llvm.org GIT mirror llvm / a3f1de9
[ThinLTO] Internalize readonly globals An attempt to recommit r346584 after failure on OSX build bot. Fixed cache key computation in ThinLTOCodeGenerator and added test case git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@347033 91177308-0d34-0410-b5e6-96231b3b80d8 Eugene Leviant 10 months ago
46 changed file(s) with 866 addition(s) and 93 deletion(s). Raw diff Collapse all Expand all
162162 /// Struct that holds a reference to a particular GUID in a global value
163163 /// summary.
164164 struct ValueInfo {
165 PointerIntPair
166 RefAndFlag;
165 PointerIntPair
166 RefAndFlags;
167167
168168 ValueInfo() = default;
169169 ValueInfo(bool HaveGVs, const GlobalValueSummaryMapTy::value_type *R) {
170 RefAndFlag.setPointer(R);
171 RefAndFlag.setInt(HaveGVs);
170 RefAndFlags.setPointer(R);
171 RefAndFlags.setInt(HaveGVs);
172172 }
173173
174174 operator bool() const { return getRef(); }
188188 : getRef()->second.U.Name;
189189 }
190190
191 bool haveGVs() const { return RefAndFlag.getInt(); }
191 bool haveGVs() const { return RefAndFlags.getInt() & 0x1; }
192 bool isReadOnly() const { return RefAndFlags.getInt() & 0x2; }
193 void setReadOnly() { RefAndFlags.setInt(RefAndFlags.getInt() | 0x2); }
192194
193195 const GlobalValueSummaryMapTy::value_type *getRef() const {
194 return RefAndFlag.getPointer();
196 return RefAndFlags.getPointer();
195197 }
196198
197199 bool isDSOLocal() const;
542544 std::move(TypeTestAssumeConstVCalls),
543545 std::move(TypeCheckedLoadConstVCalls)});
544546 }
547 // Gets the number of immutable refs in RefEdgeList
548 unsigned immutableRefCount() const;
545549
546550 /// Check if this is a function summary.
547551 static bool classof(const GlobalValueSummary *GVS) {
651655 /// Global variable summary information to aid decisions and
652656 /// implementation of importing.
653657 ///
654 /// Currently this doesn't add anything to the base \p GlobalValueSummary,
655 /// but is a placeholder as additional info may be added to the summary
656 /// for variables.
658 /// Global variable summary has extra flag, telling if it is
659 /// modified during the program run or not. This affects ThinLTO
660 /// internalization
657661 class GlobalVarSummary : public GlobalValueSummary {
658
659662 public:
660 GlobalVarSummary(GVFlags Flags, std::vector Refs)
661 : GlobalValueSummary(GlobalVarKind, Flags, std::move(Refs)) {}
663 struct GVarFlags {
664 GVarFlags(bool ReadOnly = false) : ReadOnly(ReadOnly) {}
665
666 unsigned ReadOnly : 1;
667 } VarFlags;
668
669 GlobalVarSummary(GVFlags Flags, GVarFlags VarFlags,
670 std::vector Refs)
671 : GlobalValueSummary(GlobalVarKind, Flags, std::move(Refs)),
672 VarFlags(VarFlags) {}
662673
663674 /// Check if this is a global variable summary.
664675 static bool classof(const GlobalValueSummary *GVS) {
665676 return GVS->getSummaryKind() == GlobalVarKind;
666677 }
678
679 GVarFlags varflags() const { return VarFlags; }
680 void setReadOnly(bool RO) { VarFlags.ReadOnly = RO; }
681 bool isReadOnly() const { return VarFlags.ReadOnly; }
667682 };
668683
669684 struct TypeTestResolution {
11341149
11351150 /// Print out strongly connected components for debugging.
11361151 void dumpSCCs(raw_ostream &OS);
1152
1153 /// Analyze index and detect unmodified globals
1154 void propagateConstants(const DenseSet &PreservedSymbols);
11371155 };
11381156
11391157 /// GraphTraits definition to build SCC for the index
11831201 }
11841202 };
11851203
1204 static inline bool canImportGlobalVar(GlobalValueSummary *S) {
1205 assert(isa(S->getBaseObject()));
1206
1207 // We don't import GV with references, because it can result
1208 // in promotion of local variables in the source module.
1209 return !GlobalValue::isInterposableLinkage(S->linkage()) &&
1210 !S->notEligibleToImport() && S->refs().empty();
1211 }
11861212 } // end namespace llvm
11871213
11881214 #endif // LLVM_IR_MODULESUMMARYINDEX_H
175175 const DenseSet &GUIDPreservedSymbols,
176176 function_ref isPrevailing);
177177
178 /// Compute dead symbols and run constant propagation in combined index
179 /// after that.
180 void computeDeadSymbolsWithConstProp(
181 ModuleSummaryIndex &Index,
182 const DenseSet &GUIDPreservedSymbols,
183 function_ref isPrevailing,
184 bool ImportEnabled);
185
178186 /// Converts value \p GV to declaration, or replaces with a declaration if
179187 /// it is an alias. Returns true if converted, false if replaced.
180188 bool convertToDeclaration(GlobalValue &GV);
112112 bool renameModuleForThinLTO(
113113 Module &M, const ModuleSummaryIndex &Index,
114114 SetVector *GlobalsToImport = nullptr);
115
116115 } // End llvm namespace
117116
118117 #endif
219219 }
220220 }
221221
222 static void computeFunctionSummary(
223 ModuleSummaryIndex &Index, const Module &M, const Function &F,
224 BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, DominatorTree &DT,
225 bool HasLocalsInUsedOrAsm, DenseSet &CantBePromoted) {
222 static bool isNonVolatileLoad(const Instruction *I) {
223 if (const auto *LI = dyn_cast(I))
224 return !LI->isVolatile();
225
226 return false;
227 }
228
229 static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
230 const Function &F, BlockFrequencyInfo *BFI,
231 ProfileSummaryInfo *PSI, DominatorTree &DT,
232 bool HasLocalsInUsedOrAsm,
233 DenseSet &CantBePromoted,
234 bool IsThinLTO) {
226235 // Summary not currently supported for anonymous functions, they should
227236 // have been named.
228237 assert(F.hasName());
243252 // Add personality function, prefix data and prologue data to function's ref
244253 // list.
245254 findRefEdges(Index, &F, RefEdges, Visited);
255 std::vector NonVolatileLoads;
246256
247257 bool HasInlineAsmMaybeReferencingInternal = false;
248258 bool InitsVarArgs = false;
255265 InitsVarArgs = true;
256266 }
257267 ++NumInsts;
268 if (isNonVolatileLoad(&I)) {
269 // Postpone processing of non-volatile load instructions
270 // See comments below
271 Visited.insert(&I);
272 NonVolatileLoads.push_back(&I);
273 continue;
274 }
258275 findRefEdges(Index, &I, RefEdges, Visited);
259276 auto CS = ImmutableCallSite(&I);
260277 if (!CS)
344361 }
345362 }
346363
364 // By now we processed all instructions in a function, except
365 // non-volatile loads. All new refs we add in a loop below
366 // are obviously constant. All constant refs are grouped in the
367 // end of RefEdges vector, so we can use a single integer value
368 // to identify them.
369 unsigned RefCnt = RefEdges.size();
370 for (const Instruction *I : NonVolatileLoads) {
371 Visited.erase(I);
372 findRefEdges(Index, I, RefEdges, Visited);
373 }
374 std::vector Refs = RefEdges.takeVector();
375 // Regular LTO module doesn't participate in ThinLTO import,
376 // so no reference from it can be readonly, since this would
377 // require importing variable as local copy
378 if (IsThinLTO)
379 for (; RefCnt < Refs.size(); ++RefCnt)
380 Refs[RefCnt].setReadOnly();
381
347382 // Explicit add hot edges to enforce importing for designated GUIDs for
348383 // sample PGO, to enable the same inlines as the profiled optimized binary.
349384 for (auto &I : F.getImportGUIDs())
367402 // Don't try to import functions with noinline attribute.
368403 F.getAttributes().hasFnAttribute(Attribute::NoInline)};
369404 auto FuncSummary = llvm::make_unique(
370 Flags, NumInsts, FunFlags, RefEdges.takeVector(),
371 CallGraphEdges.takeVector(), TypeTests.takeVector(),
372 TypeTestAssumeVCalls.takeVector(), TypeCheckedLoadVCalls.takeVector(),
405 Flags, NumInsts, FunFlags, std::move(Refs), CallGraphEdges.takeVector(),
406 TypeTests.takeVector(), TypeTestAssumeVCalls.takeVector(),
407 TypeCheckedLoadVCalls.takeVector(),
373408 TypeTestAssumeConstVCalls.takeVector(),
374409 TypeCheckedLoadConstVCalls.takeVector());
375410 if (NonRenamableLocal)
386421 bool NonRenamableLocal = isNonRenamableLocal(V);
387422 GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,
388423 /* Live = */ false, V.isDSOLocal());
389 auto GVarSummary =
390 llvm::make_unique(Flags, RefEdges.takeVector());
424
425 // Don't mark variables we won't be able to internalize as read-only.
426 GlobalVarSummary::GVarFlags VarFlags(
427 !V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() &&
428 !V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass());
429 auto GVarSummary = llvm::make_unique(Flags, VarFlags,
430 RefEdges.takeVector());
391431 if (NonRenamableLocal)
392432 CantBePromoted.insert(V.getGUID());
393433 if (HasBlockAddress)
491531 Index.addGlobalValueSummary(*GV, std::move(Summary));
492532 } else {
493533 std::unique_ptr Summary =
494 llvm::make_unique(GVFlags,
495 ArrayRef{});
534 llvm::make_unique(
535 GVFlags, GlobalVarSummary::GVarFlags(),
536 ArrayRef{});
496537 Index.addGlobalValueSummary(*GV, std::move(Summary));
497538 }
498539 });
499540 }
541
542 bool IsThinLTO = true;
543 if (auto *MD =
544 mdconst::extract_or_null(M.getModuleFlag("ThinLTO")))
545 IsThinLTO = MD->getZExtValue();
500546
501547 // Compute summaries for all functions defined in module, and save in the
502548 // index.
518564
519565 computeFunctionSummary(Index, M, F, BFI, PSI, DT,
520566 !LocalsUsed.empty() || HasLocalInlineAsmSymbol,
521 CantBePromoted);
567 CantBePromoted, IsThinLTO);
522568 }
523569
524570 // Compute summaries for all variables defined in module, and save in the
548594 setLiveRoot(Index, "llvm.global_ctors");
549595 setLiveRoot(Index, "llvm.global_dtors");
550596 setLiveRoot(Index, "llvm.global.annotations");
551
552 bool IsThinLTO = true;
553 if (auto *MD =
554 mdconst::extract_or_null(M.getModuleFlag("ThinLTO")))
555 IsThinLTO = MD->getZExtValue();
556597
557598 for (auto &GlobalList : Index) {
558599 // Ignore entries for references that are undefined in the current module.
77147714 if (ParseToken(lltok::rparen, "expected ')' here"))
77157715 return true;
77167716
7717 auto GS = llvm::make_unique(GVFlags, std::move(Refs));
7717 auto GS = llvm::make_unique(
7718 GVFlags, GlobalVarSummary::GVarFlags(), std::move(Refs));
77187719
77197720 GS->setModulePath(ModulePath);
77207721
895895 bool Local = (RawFlags & 0x4);
896896
897897 return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, Live, Local);
898 }
899
900 // Decode the flags for GlobalVariable in the summary
901 static GlobalVarSummary::GVarFlags getDecodedGVarFlags(uint64_t RawFlags) {
902 return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false);
898903 }
899904
900905 static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) {
52185223 parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId);
52195224 }
52205225
5226 static void setImmutableRefs(std::vector &Refs, unsigned Count) {
5227 // Read-only refs are in the end of the refs list.
5228 for (unsigned RefNo = Refs.size() - Count; RefNo < Refs.size(); ++RefNo)
5229 Refs[RefNo].setReadOnly();
5230 }
5231
52215232 // Eagerly parse the entire summary block. This populates the GlobalValueSummary
52225233 // objects in the index.
52235234 Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
52355246 }
52365247 const uint64_t Version = Record[0];
52375248 const bool IsOldProfileFormat = Version == 1;
5238 if (Version < 1 || Version > 4)
5249 if (Version < 1 || Version > 5)
52395250 return error("Invalid summary version " + Twine(Version) +
5240 ", 1, 2, 3 or 4 expected");
5251 ", 1, 2, 3, 4 or 5 expected");
52415252 Record.clear();
52425253
52435254 // Keep around the last seen summary to be used when we see an optional
53165327 unsigned InstCount = Record[2];
53175328 uint64_t RawFunFlags = 0;
53185329 unsigned NumRefs = Record[3];
5330 unsigned NumImmutableRefs = 0;
53195331 int RefListStartIndex = 4;
53205332 if (Version >= 4) {
53215333 RawFunFlags = Record[3];
53225334 NumRefs = Record[4];
53235335 RefListStartIndex = 5;
5336 if (Version >= 5) {
5337 NumImmutableRefs = Record[5];
5338 RefListStartIndex = 6;
5339 }
53245340 }
53255341
53265342 auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
53395355 std::vector Calls = makeCallList(
53405356 ArrayRef(Record).slice(CallGraphEdgeStartIndex),
53415357 IsOldProfileFormat, HasProfile, HasRelBF);
5358 setImmutableRefs(Refs, NumImmutableRefs);
53425359 auto FS = llvm::make_unique(
53435360 Flags, InstCount, getDecodedFFlags(RawFunFlags), std::move(Refs),
53445361 std::move(Calls), std::move(PendingTypeTests),
53875404 TheIndex.addGlobalValueSummary(GUID.first, std::move(AS));
53885405 break;
53895406 }
5390 // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, n x valueid]
5407 // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags, n x valueid]
53915408 case bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS: {
53925409 unsigned ValueID = Record[0];
53935410 uint64_t RawFlags = Record[1];
5411 unsigned RefArrayStart = 2;
5412 GlobalVarSummary::GVarFlags GVF;
53945413 auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
5414 if (Version >= 5) {
5415 GVF = getDecodedGVarFlags(Record[2]);
5416 RefArrayStart = 3;
5417 }
53955418 std::vector Refs =
5396 makeRefList(ArrayRef(Record).slice(2));
5397 auto FS = llvm::make_unique(Flags, std::move(Refs));
5419 makeRefList(ArrayRef(Record).slice(RefArrayStart));
5420 auto FS =
5421 llvm::make_unique(Flags, GVF, std::move(Refs));
53985422 FS->setModulePath(getThisModule()->first());
53995423 auto GUID = getValueInfoFromValueId(ValueID);
54005424 FS->setOriginalName(GUID.second);
54135437 unsigned InstCount = Record[3];
54145438 uint64_t RawFunFlags = 0;
54155439 unsigned NumRefs = Record[4];
5440 unsigned NumImmutableRefs = 0;
54165441 int RefListStartIndex = 5;
54175442
54185443 if (Version >= 4) {
54195444 RawFunFlags = Record[4];
54205445 NumRefs = Record[5];
54215446 RefListStartIndex = 6;
5447 if (Version >= 5) {
5448 NumImmutableRefs = Record[6];
5449 RefListStartIndex = 7;
5450 }
54225451 }
54235452
54245453 auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
54325461 ArrayRef(Record).slice(CallGraphEdgeStartIndex),
54335462 IsOldProfileFormat, HasProfile, false);
54345463 ValueInfo VI = getValueInfoFromValueId(ValueID).first;
5464 setImmutableRefs(Refs, NumImmutableRefs);
54355465 auto FS = llvm::make_unique(
54365466 Flags, InstCount, getDecodedFFlags(RawFunFlags), std::move(Refs),
54375467 std::move(Edges), std::move(PendingTypeTests),
54805510 unsigned ValueID = Record[0];
54815511 uint64_t ModuleId = Record[1];
54825512 uint64_t RawFlags = Record[2];
5513 unsigned RefArrayStart = 3;
5514 GlobalVarSummary::GVarFlags GVF;
54835515 auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
5516 if (Version >= 5) {
5517 GVF = getDecodedGVarFlags(Record[3]);
5518 RefArrayStart = 4;
5519 }
54845520 std::vector Refs =
5485 makeRefList(ArrayRef(Record).slice(3));
5486 auto FS = llvm::make_unique(Flags, std::move(Refs));
5521 makeRefList(ArrayRef(Record).slice(RefArrayStart));
5522 auto FS =
5523 llvm::make_unique(Flags, GVF, std::move(Refs));
54875524 LastSeenSummary = FS.get();
54885525 FS->setModulePath(ModuleIdMap[ModuleId]);
54895526 ValueInfo VI = getValueInfoFromValueId(ValueID).first;
999999 return RawFlags;
10001000 }
10011001
1002 static uint64_t getEncodedGVarFlags(GlobalVarSummary::GVarFlags Flags) {
1003 uint64_t RawFlags = Flags.ReadOnly;
1004 return RawFlags;
1005 }
1006
10021007 static unsigned getEncodedVisibility(const GlobalValue &GV) {
10031008 switch (GV.getVisibility()) {
10041009 case GlobalValue::DefaultVisibility: return 0;
35383543 NameVals.push_back(FS->instCount());
35393544 NameVals.push_back(getEncodedFFlags(FS->fflags()));
35403545 NameVals.push_back(FS->refs().size());
3546 NameVals.push_back(FS->immutableRefCount());
35413547
35423548 for (auto &RI : FS->refs())
35433549 NameVals.push_back(VE.getValueID(RI.getValue()));
35793585 NameVals.push_back(VE.getValueID(&V));
35803586 GlobalVarSummary *VS = cast(Summary);
35813587 NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
3588 NameVals.push_back(getEncodedGVarFlags(VS->varflags()));
35823589
35833590 unsigned SizeBeforeRefs = NameVals.size();
35843591 for (auto &RI : VS->refs())
35953602 // Current version for the summary.
35963603 // This is bumped whenever we introduce changes in the way some record are
35973604 // interpreted, like flags for instance.
3598 static const uint64_t INDEX_VERSION = 4;
3605 static const uint64_t INDEX_VERSION = 5;
35993606
36003607 /// Emit the per-module summary section alongside the rest of
36013608 /// the module's bitcode.
36303637 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
36313638 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags
36323639 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
3640 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt
36333641 // numrefs x valueid, n x (valueid, hotness)
36343642 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
36353643 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
36463654 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
36473655 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags
36483656 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
3657 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt
36493658 // numrefs x valueid, n x (valueid [, rel_block_freq])
36503659 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
36513660 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
37403749 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
37413750 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags
37423751 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
3752 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt
37433753 // numrefs x valueid, n x (valueid)
37443754 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
37453755 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
37543764 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
37553765 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags
37563766 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
3767 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt
37573768 // numrefs x valueid, n x (valueid, hotness)
37583769 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
37593770 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
38263837 NameVals.push_back(*ValueId);
38273838 NameVals.push_back(Index.getModuleId(VS->modulePath()));
38283839 NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
3840 NameVals.push_back(getEncodedGVarFlags(VS->varflags()));
38293841 for (auto &RI : VS->refs()) {
38303842 auto RefValueId = getValueId(RI.getGUID());
38313843 if (!RefValueId)
38513863 NameVals.push_back(FS->instCount());
38523864 NameVals.push_back(getEncodedFFlags(FS->fflags()));
38533865 // Fill in below
3854 NameVals.push_back(0);
3855
3856 unsigned Count = 0;
3866 NameVals.push_back(0); // numrefs
3867 NameVals.push_back(0); // immutablerefcnt
3868
3869 unsigned Count = 0, ImmutableRefCnt = 0;
38573870 for (auto &RI : FS->refs()) {
38583871 auto RefValueId = getValueId(RI.getGUID());
38593872 if (!RefValueId)
38603873 continue;
38613874 NameVals.push_back(*RefValueId);
3875 if (RI.isReadOnly())
3876 ImmutableRefCnt++;
38623877 Count++;
38633878 }
38643879 NameVals[5] = Count;
3880 NameVals[6] = ImmutableRefCnt;
38653881
38663882 bool HasProfileData = false;
38673883 for (auto &EI : FS->calls()) {
2727 [](const std::unique_ptr &Summary) {
2828 return Summary->isDSOLocal();
2929 });
30 }
31
32 // Gets the number of immutable refs in RefEdgeList
33 unsigned FunctionSummary::immutableRefCount() const {
34 // Here we take advantage of having all readonly references
35 // located in the end of the RefEdgeList.
36 auto Refs = refs();
37 unsigned ImmutableRefCnt = 0;
38 for (int I = Refs.size() - 1; I >= 0 && Refs[I].isReadOnly(); --I)
39 ImmutableRefCnt++;
40 return ImmutableRefCnt;
3041 }
3142
3243 // Collect for the given module the list of function it defines
8394 return false;
8495 }
8596
97 static void propagateConstantsToRefs(GlobalValueSummary *S) {
98 // If reference is not readonly then referenced summary is not
99 // readonly either. Note that:
100 // - All references from GlobalVarSummary are conservatively considered as
101 // not readonly. Tracking them properly requires more complex analysis
102 // then we have now.
103 //
104 // - AliasSummary objects have no refs at all so this function is a no-op
105 // for them.
106 for (auto &VI : S->refs()) {
107 if (VI.isReadOnly()) {
108 // We only mark refs as readonly when computing function summaries on
109 // analysis phase.
110 assert(isa(S));
111 continue;
112 }
113 for (auto &Ref : VI.getSummaryList())
114 // If references to alias is not readonly then aliasee is not readonly
115 if (auto *GVS = dyn_cast(Ref->getBaseObject()))
116 GVS->setReadOnly(false);
117 }
118 }
119
120 // Do the constant propagation in combined index.
121 // The goal of constant propagation is internalization of readonly
122 // variables. To determine which variables are readonly and which
123 // are not we take following steps:
124 // - During analysis we speculatively assign readonly attribute to
125 // all variables which can be internalized. When computing function
126 // summary we also assign readonly attribute to a reference if
127 // function doesn't modify referenced variable.
128 //
129 // - After computing dead symbols in combined index we do the constant
130 // propagation. During this step we clear readonly attribute from
131 // all variables which:
132 // a. are dead, preserved or can't be imported
133 // b. referenced by any global variable initializer
134 // c. referenced by a function and reference is not readonly
135 //
136 // Internalization itself happens in the backend after import is finished
137 // See internalizeImmutableGVs.
138 void ModuleSummaryIndex::propagateConstants(
139 const DenseSet &GUIDPreservedSymbols) {
140 for (auto &P : *this)
141 for (auto &S : P.second.SummaryList) {
142 if (!isGlobalValueLive(S.get()))
143 // We don't examine references from dead objects
144 continue;
145
146 // Global variable can't be marked read only if it is not eligible
147 // to import since we need to ensure that all external references
148 // get a local (imported) copy. It also can't be marked read only
149 // if it or any alias (since alias points to the same memory) are
150 // preserved or notEligibleToImport, since either of those means
151 // there could be writes that are not visible (because preserved
152 // means it could have external to DSO writes, and notEligibleToImport
153 // means it could have writes via inline assembly leading it to be
154 // in the @llvm.*used).
155 if (auto *GVS = dyn_cast(S->getBaseObject()))
156 // Here we intentionally pass S.get() not GVS, because S could be
157 // an alias.
158 if (!canImportGlobalVar(S.get()) || GUIDPreservedSymbols.count(P.first))
159 GVS->setReadOnly(false);
160 propagateConstantsToRefs(S.get());
161 }
162 }
163
86164 // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
87165 // then delete this function and update its tests
88166 LLVM_DUMP_METHOD
107185 struct Attributes {
108186 void add(const Twine &Name, const Twine &Value,
109187 const Twine &Comment = Twine());
188 void addComment(const Twine &Comment);
110189 std::string getAsString() const;
111190
112191 std::vector Attrs;
128207 A += Value.str();
129208 A += "\"";
130209 Attrs.push_back(A);
210 addComment(Comment);
211 }
212
213 void Attributes::addComment(const Twine &Comment) {
131214 if (!Comment.isTriviallyEmpty()) {
132215 if (Comments.empty())
133216 Comments = " // ";
236319 OS << "\"]; // defined externally\n";
237320 }
238321
322 static bool hasReadOnlyFlag(const GlobalValueSummary *S) {
323 if (auto *GVS = dyn_cast(S))
324 return GVS->isReadOnly();
325 return false;
326 }
327
239328 void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const {
240329 std::vector CrossModuleEdges;
241330 DenseMap> NodeMap;
251340 };
252341
253342 auto DrawEdge = [&](const char *Pfx, uint64_t SrcMod, GlobalValue::GUID SrcId,
254 uint64_t DstMod, GlobalValue::GUID DstId, int TypeOrHotness) {
255 // 0 corresponds to alias edge, 1 to ref edge, 2 to call with unknown
256 // hotness, ...
257 TypeOrHotness += 2;
343 uint64_t DstMod, GlobalValue::GUID DstId,
344 int TypeOrHotness) {
345 // 0 - alias
346 // 1 - reference
347 // 2 - constant reference
348 // Other value: (hotness - 3).
349 TypeOrHotness += 3;
258350 static const char *EdgeAttrs[] = {
259351 " [style=dotted]; // alias",
260352 " [style=dashed]; // ref",
353 " [style=dashed,color=forestgreen]; // const-ref",
261354 " // call (hotness : Unknown)",
262355 " [color=blue]; // call (hotness : Cold)",
263356 " // call (hotness : None)",
300393 A.add("shape", "box");
301394 } else {
302395 A.add("shape", "Mrecord", "variable");
396 if (Flags.Live && hasReadOnlyFlag(SummaryIt.second))
397 A.addComment("immutable");
303398 }
304399
305400 auto VI = getValueInfo(SummaryIt.first);
317412 for (auto &SummaryIt : GVSMap) {
318413 auto *GVS = SummaryIt.second;
319414 for (auto &R : GVS->refs())
320 Draw(SummaryIt.first, R.getGUID(), -1);
415 Draw(SummaryIt.first, R.getGUID(), R.isReadOnly() ? -1 : -2);
321416
322417 if (auto *AS = dyn_cast_or_null(SummaryIt.second)) {
323418 GlobalValue::GUID AliaseeId;
330425 AliaseeId = AliaseeOrigId;
331426 }
332427
333 Draw(SummaryIt.first, AliaseeId, -2);
428 Draw(SummaryIt.first, AliaseeId, -3);
334429 continue;
335430 }
336431
186186 AddUnsigned(VI.isDSOLocal());
187187 AddUsedCfiGlobal(VI.getGUID());
188188 }
189 if (auto *GVS = dyn_cast(GS))
190 AddUnsigned(GVS->isReadOnly());
189191 if (auto *FS = dyn_cast(GS)) {
190192 for (auto &TT : FS->type_tests())
191193 UsedTypeIds.insert(TT);
808810 return PrevailingType::Unknown;
809811 return It->second;
810812 };
811 computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols, isPrevailing);
813 computeDeadSymbolsWithConstProp(ThinLTO.CombinedIndex, GUIDPreservedSymbols,
814 isPrevailing, Conf.OptLevel > 0);
812815
813816 // Setup output file to emit statistics.
814817 std::unique_ptr StatsFile = nullptr;
297297 const FunctionImporter::ImportMapTy &ImportList,
298298 const FunctionImporter::ExportSetTy &ExportList,
299299 const std::map &ResolvedODR,
300 const GVSummaryMapTy &DefinedFunctions,
300 const GVSummaryMapTy &DefinedGVSummaries,
301301 const DenseSet &PreservedSymbols, unsigned OptLevel,
302302 bool Freestanding, const TargetMachineBuilder &TMBuilder) {
303303 if (CachePath.empty())
367367 for (auto &Entry : ImportList) {
368368 auto ModHash = Index.getModuleHash(Entry.first());
369369 Hasher.update(ArrayRef((uint8_t *)&ModHash[0], sizeof(ModHash)));
370 for (auto Guid : Entry.second)
371 if (auto *GVS = dyn_cast(
372 Index.getGlobalValueSummary(Guid, false)))
373 AddUnsigned(GVS->isReadOnly());
370374 }
371375
372376 // Include the hash for the resolved ODR.
379383
380384 // Include the hash for the preserved symbols.
381385 for (auto &Entry : PreservedSymbols) {
382 if (DefinedFunctions.count(Entry))
386 if (DefinedGVSummaries.count(Entry))
383387 Hasher.update(
384388 ArrayRef((const uint8_t *)&Entry, sizeof(GlobalValue::GUID)));
385389 }
390
391 for (auto &Entry : DefinedGVSummaries)
392 if (auto *GVS = dyn_cast(Entry.second))
393 AddUnsigned(GVS->isReadOnly());
386394
387395 // This choice of file name allows the cache to be pruned (see pruneCache()
388396 // in include/llvm/Support/CachePruning.h).
645653 auto isPrevailing = [&](GlobalValue::GUID G) {
646654 return PrevailingType::Unknown;
647655 };
648 computeDeadSymbols(Index, GUIDPreservedSymbols, isPrevailing);
656 computeDeadSymbolsWithConstProp(Index, GUIDPreservedSymbols, isPrevailing,
657 /* ImportEnabled = */ true);
649658 }
650659
651660 /**
982991 auto ModuleIdentifier = ModuleBuffer.getBufferIdentifier();
983992 auto &ExportList = ExportLists[ModuleIdentifier];
984993
985 auto &DefinedFunctions = ModuleToDefinedGVSummaries[ModuleIdentifier];
994 auto &DefinedGVSummaries = ModuleToDefinedGVSummaries[ModuleIdentifier];
986995
987996 // The module may be cached, this helps handling it.
988997 ModuleCacheEntry CacheEntry(CacheOptions.Path, *Index, ModuleIdentifier,
989998 ImportLists[ModuleIdentifier], ExportList,
990999 ResolvedODR[ModuleIdentifier],
991 DefinedFunctions, GUIDPreservedSymbols,
1000 DefinedGVSummaries, GUIDPreservedSymbols,
9921001 OptLevel, Freestanding, TMBuilder);
9931002 auto CacheEntryPath = CacheEntry.getEntryPath();
9941003
10611061 ValueMap.MD()[CU->getRawEnumTypes()].reset(nullptr);
10621062 ValueMap.MD()[CU->getRawMacros()].reset(nullptr);
10631063 ValueMap.MD()[CU->getRawRetainedTypes()].reset(nullptr);
1064 // We import global variables only temporarily in order for instcombine
1065 // and globalopt to perform constant folding and static constructor
1066 // evaluation. After that elim-avail-extern will covert imported globals
1067 // back to declarations, so we don't need debug info for them.
1068 ValueMap.MD()[CU->getRawGlobalVariables()].reset(nullptr);
10691064
10701065 // Imported entities only need to be mapped in if they have local
10711066 // scope, as those might correspond to an imported entity inside a
293293 LLVM_DEBUG(dbgs() << " ref -> " << VI << "\n");
294294
295295 for (auto &RefSummary : VI.getSummaryList())
296 if (RefSummary->getSummaryKind() == GlobalValueSummary::GlobalVarKind &&
297 !RefSummary->notEligibleToImport() &&
298 !GlobalValue::isInterposableLinkage(RefSummary->linkage()) &&
299 RefSummary->refs().empty()) {
296 if (isa(RefSummary.get()) &&
297 canImportGlobalVar(RefSummary.get())) {
300298 auto ILI = ImportList[RefSummary->modulePath()].insert(VI.getGUID());
301299 // Only update stat if we haven't already imported this variable.
302300 if (ILI.second)
823821 NumLiveSymbols += LiveSymbols;
824822 }
825823
824 // Compute dead symbols and propagate constants in combined index.
825 void llvm::computeDeadSymbolsWithConstProp(
826 ModuleSummaryIndex &Index,
827 const DenseSet &GUIDPreservedSymbols,
828 function_ref isPrevailing,
829 bool ImportEnabled) {
830 computeDeadSymbols(Index, GUIDPreservedSymbols, isPrevailing);
831 if (ImportEnabled) {
832 Index.propagateConstants(GUIDPreservedSymbols);
833 } else {
834 // If import is disabled we should drop read-only attribute
835 // from all summaries to prevent internalization.
836 for (auto &P : Index)
837 for (auto &S : P.second.SummaryList)
838 if (auto *GVS = dyn_cast(S.get()))
839 GVS->setReadOnly(false);
840 }
841 }
842
826843 /// Compute the set of summaries needed for a ThinLTO backend compilation of
827844 /// \p ModulePath.
828845 void llvm::gatherImportedSummariesForModule(
10191036 return NewFn;
10201037 }
10211038
1039 // Internalize values that we marked with specific attribute
1040 // in processGlobalForThinLTO.
1041 static void internalizeImmutableGVs(Module &M) {
1042 for (auto &GV : M.globals())
1043 // Skip GVs which have been converted to declarations
1044 // by dropDeadSymbols.
1045 if (!GV.isDeclaration() && GV.hasAttribute("thinlto-internalize")) {
1046 GV.setLinkage(GlobalValue::InternalLinkage);
1047 GV.setVisibility(GlobalValue::DefaultVisibility);
1048 }
1049 }
1050
10221051 // Automatically import functions in Module \p DestModule based on the summaries
10231052 // index.
10241053 Expected FunctionImporter::importFunctions(
11421171 NumImportedModules++;
11431172 }
11441173
1174 internalizeImmutableGVs(DestModule);
1175
11451176 NumImportedFunctions += (ImportedCount - ImportedGVCount);
11461177 NumImportedGlobalVars += ImportedGVCount;
11471178
203203
204204 // Check the summaries to see if the symbol gets resolved to a known local
205205 // definition.
206 ValueInfo VI;
206207 if (GV.hasName()) {
207 ValueInfo VI = ImportIndex.getValueInfo(GV.getGUID());
208 VI = ImportIndex.getValueInfo(GV.getGUID());
208209 if (VI && VI.isDSOLocal()) {
209210 GV.setDSOLocal(true);
210211 if (GV.hasDLLImportStorageClass())
211212 GV.setDLLStorageClass(GlobalValue::DefaultStorageClass);
212213 }
214 }
215
216 // Mark read-only variables which can be imported with specific attribute.
217 // We can't internalize them now because IRMover will fail to link variable
218 // definitions to their external declarations during ThinLTO import. We'll
219 // internalize read-only variables later, after import is finished.
220 // See internalizeImmutableGVs.
221 //
222 // If global value dead stripping is not enabled in summary then
223 // propagateConstants hasn't been run. We can't internalize GV
224 // in such case.
225 if (!GV.isDeclaration() && VI && ImportIndex.withGlobalValueDeadStripping()) {
226 const auto &SL = VI.getSummaryList();
227 auto *GVS = SL.empty() ? nullptr : dyn_cast(SL[0].get());
228 if (GVS && GVS->isReadOnly())
229 cast(&GV)->addAttribute("thinlto-internalize");
213230 }
214231
215232 bool DoPromote = false;
229246 // Remove functions imported as available externally defs from comdats,
230247 // as this is a declaration for the linker, and will be dropped eventually.
231248 // It is illegal for comdats to contain declarations.
232 auto *GO = dyn_cast_or_null(&GV);
249 auto *GO = dyn_cast(&GV);
233250 if (GO && GO->isDeclarationForLinker() && GO->hasComdat()) {
234251 // The IRMover should not have placed any imported declarations in
235252 // a comdat, so the only declaration that should be in a comdat
11 ; RUN: opt -module-summary %s -o - | llvm-bcanalyzer -dump | FileCheck %s
22
33 ; CHECK:
4 ; CHECK: 4/>
4 ; CHECK: 5/>
55
66
77
1919 ; CHECK-NEXT:
2020 ; See if the call to func is registered.
2121 ; The value id 1 matches the second FUNCTION record above.
22 ; CHECK-NEXT: 5=1/>
22 ; CHECK-NEXT: 6=1/>
2323 ; CHECK-NEXT:
2424
2525 ; CHECK:
3232 ; COMBINED-NEXT:
3333 ; COMBINED-NEXT:
3434 ; COMBINED-NEXT:
35 ; COMBINED-NEXT: 6=[[ALIASID]]/>
35 ; COMBINED-NEXT: 7=[[ALIASID]]/>
3636 ; COMBINED-NEXT:
3737 ; COMBINED-NEXT:
3838 ; COMBINED-NEXT:
33
44 ; CHECK:
55 ; CHECK-NEXT:
6 ; CHECK-NEXT: [[ALIASID:[0-9]+]]/>
6 ; CHECK-NEXT: 0 op6=[[ALIASID:[0-9]+]]/>
77 ; CHECK-NEXT:
88 ; CHECK-NEXT:
99 ; CHECK-NEXT:
55 ; CHECK:
66 ; CHECK-NEXT:
77 ; "op7" is a call to "callee" function.
8 ; CHECK-NEXT: 7=3 op8=[[ALIASID:[0-9]+]]/>
8 ; CHECK-NEXT: 8=3 op9=[[ALIASID:[0-9]+]]/>
99 ; "another_caller" has only references but no calls.
10 ; CHECK-NEXT: 7={{[0-9]+}}/>
10 ; CHECK-NEXT: 8={{[0-9]+}}/>
1111 ; CHECK-NEXT:
1212 ; CHECK-NEXT:
1313 ; CHECK-NEXT:
1616 ; CHECK:
1717 ; CHECK-NEXT:
1818 ; See if the call to func is registered, using the expected hotness type.
19 ; CHECK-NEXT: 5=1 op6=2/>
19 ; CHECK-NEXT: 6=1 op7=2/>
2020 ; CHECK-NEXT:
2121 ; CHECK:
2222 ; CHECK-NEXT: blob data = 'mainfunc{{.*}}'
2929 ; COMBINED-NEXT:
3030 ; See if the call to func is registered, using the expected hotness type.
3131 ; op6=2 which is hotnessType::None.
32 ; COMBINED-NEXT: 6=[[FUNCID]] op7=2/>
32 ; COMBINED-NEXT: 7=[[FUNCID]] op8=2/>
3333 ; COMBINED-NEXT:
3434
3535 ; ModuleID = 'thinlto-function-summary-callgraph.ll'
4747 ; CHECK-NEXT:
4848 ; CHECK-NEXT:
4949 ; op4=hot1 op6=cold op8=hot2 op10=hot4 op12=none1 op14=hot3 op16=none2 op18=none3 op20=123
50 ; CHECK-NEXT: 5=1 op6=3 op7=5 op8=1 op9=2 op10=3 op11=4 op12=1 op13=6 op14=2 op15=3 op16=3 op17=7 op18=2 op19=8 op20=2 op21=25 op22=4/>
50 ; CHECK-NEXT: 6=1 op7=3 op8=5 op9=1 op10=2 op11=3 op12=4 op13=1 op14=6 op15=2 op16=3 op17=3 op18=7 op19=2 op20=8 op21=2 op22=25 op23=4/>
5151 ; CHECK-NEXT:
5252
5353 ; CHECK:
7070 ; COMBINED-NEXT:
7171 ; COMBINED-NEXT:
7272 ; COMBINED-NEXT:
73 ; COMBINED-NEXT: 6=[[HOT1:.*]] op7=3 op8=[[COLD:.*]] op9=1 op10=[[HOT2:.*]] op11=3 op12=[[NONE1:.*]] op13=2 op14=[[HOT3:.*]] op15=3 op16=[[NONE2:.*]] op17=2 op18=[[NONE3:.*]] op19=2/>
73 ; COMBINED-NEXT: 7=[[HOT1:.*]] op8=3 op9=[[COLD:.*]] op10=1 op11=[[HOT2:.*]] op12=3 op13=[[NONE1:.*]] op14=2 op15=[[HOT3:.*]] op16=3 op17=[[NONE2:.*]] op18=2 op19=[[NONE3:.*]] op20=2/>
7474 ; COMBINED_NEXT:
7575 ; COMBINED_NEXT:
7676
1212 ; CHECK:
1313 ; CHECK-NEXT:
1414 ; See if the call to func is registered.
15 ; CHECK-NEXT: 7=256
15 ; CHECK-NEXT: 8=256
1616 ; CHECK-NEXT:
1717 ; CHECK:
1818 ; CHECK-NEXT: blob data = 'undefinedglobmainfunc{{.*}}'
3030 ; CHECK-NEXT:
3131 ; CHECK-NEXT:
3232 ; op4=none1 op6=hot1 op8=cold1 op10=none2 op12=hot2 op14=cold2 op16=none3 op18=hot3 op20=cold3 op22=123
33 ; CHECK-NEXT: 5=7 op6=0 op7=1 op8=3 op9=4 op10=1 op11=8 op12=0 op13=2 op14=3 op15=5 op16=1 op17=9 op18=0 op19=3 op20=3 op21=6 op22=1 op23=26 op24=4/>
33 ; CHECK-NEXT: 6=7 op7=0 op8=1 op9=3 op10=4 op11=1 op12=8 op13=0 op14=2 op15=3 op16=5 op17=1 op18=9 op19=0 op20=3 op21=3 op22=6 op23=1 op24=26 op25=4/>
3434 ; CHECK-NEXT:
3535
3636 ; CHECK:
5757 ; COMBINED-NEXT:
5858 ; COMBINED-NEXT:
5959 ; COMBINED-NEXT:
60 ; COMBINED-NEXT: 6=[[NONE1:.*]] op7=0 op8=[[HOT1:.*]] op9=3 op10=[[COLD1:.*]] op11=1 op12=[[NONE2:.*]] op13=0 op14=[[HOT2:.*]] op15=3 op16=[[COLD2:.*]] op17=1 op18=[[NONE3:.*]] op19=0 op20=[[HOT3:.*]] op21=3 op22=[[COLD3:.*]] op23=1/>
60 ; COMBINED-NEXT: 7=[[NONE1:.*]] op8=0 op9=[[HOT1:.*]] op10=3 op11=[[COLD1:.*]] op12=1 op13=[[NONE2:.*]] op14=0 op15=[[HOT2:.*]] op16=3 op17=[[COLD2:.*]] op18=1 op19=[[NONE3:.*]] op20=0 op21=[[HOT3:.*]] op22=3 op23=[[COLD3:.*]] op24=1/>
6161 ; COMBINED_NEXT:
6262 ; COMBINED_NEXT:
6363
1616 ; CHECK-NEXT:
1717 ; CHECK:
1818 ; CHECK-NEXT:
19 ; See if the call to func is registered.
19 ; See if the call to func is registered
2020 ; CHECK-NEXT:
2121 ; CHECK-NEXT:
2222 ; CHECK:
3232 ; COMBINED-NEXT:
3333 ; COMBINED-NEXT:
3434 ; See if the call to func is registered.
35 ; COMBINED-NEXT: 6=[[FUNCID]]/>
35 ; COMBINED-NEXT: 7=[[FUNCID]]/>
3636 ; COMBINED-NEXT:
3737
3838 ; ModuleID = 'thinlto-function-summary-callgraph.ll'
4040 ; CHECK:
4141 ; Function main contains call to func, as well as address reference to func:
4242 ; op0=main op4=func op5=func
43 ; CHECK-DAG: 2 op6=2/>
43 ; CHECK-DAG: 0 op6=2 op7=2/>
4444 ; Function W contains a call to func3 as well as a reference to globalvar:
4545 ; op0=W op4=globalvar op5=func3
46 ; CHECK-DAG: 1 op6=5/>
46 ; CHECK-DAG: 0 op6=1 op7=5/>
4747 ; Function X contains call to foo, as well as address reference to foo
4848 ; which is in the same instruction as the call:
4949 ; op0=X op4=foo op5=foo
50 ; CHECK-DAG: 4 op6=4/>
50 ; CHECK-DAG: 0 op6=4 op7=4/>
5151 ; Function Y contains call to func2, and ensures we don't incorrectly add
5252 ; a reference to it when reached while earlier analyzing the phi using its
5353 ; return value:
5454 ; op0=Y op4=func2
55 ; CHECK-DAG: 3/>
55 ; CHECK-DAG: 0 op6=3/>
5656 ; Function Z contains call to func2, and ensures we don't incorrectly add
5757 ; a reference to it when reached while analyzing subsequent use of its return
5858 ; value:
5959 ; op0=Z op4=func2
60 ; CHECK-DAG: 3/>
60 ; CHECK-DAG: 0 op6=3/>
6161 ; Variable bar initialization contains address reference to func:
6262 ; op0=bar op2=func
63 ; CHECK-DAG: 2/>
63 ; CHECK-DAG: 1 op3=2/>
6464 ; CHECK:
6565
6666 ; CHECK:
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 @g = global i32 42, align 4
4 @g.alias = weak alias i32, i32* @g
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 @gFoo = internal unnamed_addr global i32 1, align 4
4
5 ; Function Attrs: norecurse nounwind readonly ssp uwtable
6 define i32 @foo() local_unnamed_addr {
7 %1 = load i32, i32* @gFoo, align 4
8 ret i32 %1
9 }
10
11 ; Function Attrs: nounwind ssp uwtable
12 define void @bar() local_unnamed_addr {
13 %1 = tail call i32 @rand()
14 store i32 %1, i32* @gFoo, align 4
15 ret void
16 }
17
18 declare i32 @rand() local_unnamed_addr
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 ; Function Attrs: nounwind ssp uwtable
4 define i32 @test() local_unnamed_addr {
5 %1 = tail call i32 (...) @foo()
6 ret i32 %1
7 }
8
9 declare i32 @foo(...) local_unnamed_addr
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 ; Function Attrs: nounwind ssp uwtable
4 define i32 @test() local_unnamed_addr {
5 %1 = tail call i32 (...) @foo()
6 %2 = tail call i32 (...) @bar()
7 %3 = add nsw i32 %2, %1
8 ret i32 %3
9 }
10
11 declare i32 @foo(...) local_unnamed_addr
12
13 declare i32 @bar(...) local_unnamed_addr
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 $comdat.any = comdat any
4 @g = global i32 42, comdat($comdat.any)
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 @g = global i32 42, align 4
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 @g = external global i32
4
5 define i32 @foo() {
6 %v = load i32, i32* @g
7 ret i32 %v
8 }
9
10 !0 = !{i32 1, !"ThinLTO", i32 0}
11 !llvm.module.flags = !{ !0 }
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 @b = global i32* @a, align 8
4 @a = global i32 42, align 4
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 @g1 = common global i32 0, align 4
4 @g2 = global i32 42, align 4
5 @g3 = available_externally global i32 42, align 4
6
7 define i32 @foo() {
8 %v1 = load i32, i32* @g1
9 %v2 = load i32, i32* @g2
10 %v3 = load i32, i32* @g3
11 %s1 = add i32 %v1, %v2
12 %s2 = add i32 %s1, %v3
13 ret i32 %s2
14 }
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-pc-linux-gnu"
2
3 @gBar = local_unnamed_addr global i32 2, align 4, !dbg !0
4 @gFoo = internal unnamed_addr global i32 1, align 4, !dbg !6
5
6 ; Function Attrs: norecurse nounwind readonly
7 define i32 @foo() local_unnamed_addr #0 !dbg !14 {
8 %1 = load i32, i32* @gFoo, align 4, !dbg !17
9 ret i32 %1, !dbg !18
10 }
11
12 ; Function Attrs: norecurse nounwind readonly
13 define i32 @bar() local_unnamed_addr #0 !dbg !19 {
14 %1 = load i32, i32* @gBar, align 4, !dbg !20
15 ret i32 %1, !dbg !21
16 }
17
18 define void @baz() local_unnamed_addr !dbg !22 {
19 %1 = tail call i32 @rand(), !dbg !25
20 store i32 %1, i32* @gFoo, align 4, !dbg !26
21 %2 = tail call i32 @rand(), !dbg !27
22 store i32 %2, i32* @gBar, align 4, !dbg !28
23 ret void, !dbg !29
24 }
25
26 declare i32 @rand() local_unnamed_addr
27
28 attributes #0 = { norecurse nounwind readonly }
29
30 !llvm.dbg.cu = !{!2}
31 !llvm.module.flags = !{!9, !10, !11, !12}
32 !llvm.ident = !{!13}
33
34 !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
35 !1 = distinct !DIGlobalVariable(name: "gBar", scope: !2, file: !3, line: 4, type: !8, isLocal: false, isDefinition: true)
36 !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 7.0.0 (trunk 332246)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
37 !3 = !DIFile(filename: "foo.c", directory: "/data/work/lto/roref/test")
38 !4 = !{}
39 !5 = !{!0, !6}
40 !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
41 !7 = distinct !DIGlobalVariable(name: "gFoo", scope: !2, file: !3, line: 3, type: !8, isLocal: true, isDefinition: true)
42 !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
43 !9 = !{i32 2, !"Dwarf Version", i32 4}
44 !10 = !{i32 2, !"Debug Info Version", i32 3}
45 !11 = !{i32 1, !"wchar_size", i32 4}
46 !12 = !{i32 7, !"PIC Level", i32 2}
47 !13 = !{!"clang version 7.0.0 (trunk 332246)"}
48 !14 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 6, type: !15, isLocal: false, isDefinition: true, scopeLine: 6, isOptimized: true, unit: !2, retainedNodes: !4)
49 !15 = !DISubroutineType(types: !16)
50 !16 = !{!8}
51 !17 = !DILocation(line: 7, column: 10, scope: !14)
52 !18 = !DILocation(line: 7, column: 3, scope: !14)
53 !19 = distinct !DISubprogram(name: "bar", scope: !3, file: !3, line: 10, type: !15, isLocal: false, isDefinition: true, scopeLine: 10, isOptimized: true, unit: !2, retainedNodes: !4)
54 !20 = !DILocation(line: 11, column: 10, scope: !19)
55 !21 = !DILocation(line: 11, column: 3, scope: !19)
56 !22 = distinct !DISubprogram(name: "baz", scope: !3, file: !3, line: 14, type: !23, isLocal: false, isDefinition: true, scopeLine: 14, isOptimized: true, unit: !2, retainedNodes: !4)
57 !23 = !DISubroutineType(types: !24)
58 !24 = !{null}
59 !25 = !DILocation(line: 15, column: 10, scope: !22)
60 !26 = !DILocation(line: 15, column: 8, scope: !22)
61 !27 = !DILocation(line: 16, column: 10, scope: !22)
62 !28 = !DILocation(line: 16, column: 8, scope: !22)
63 !29 = !DILocation(line: 17, column: 1, scope: !22)
1919 ; STRUCTURE-DAG: subgraph cluster_1
2020 ; STRUCTURE: // Cross-module edges:
2121 ; STRUCTURE-DAG: M0_{{[0-9]+}} -> M1_{{[0-9]+}} // call
22 ; STRUCTURE-DAG: M0_{{[0-9]+}} -> M1_{{[0-9]+}} [{{.*}}]; // ref
22 ; STRUCTURE-DAG: M0_{{[0-9]+}} -> M1_{{[0-9]+}} [{{.*}}]; // const-ref
2323 ; STRUCTURE-NEXT: }
2424
2525 ; CLUSTER0: // Module: {{.*}}1.bc
3232
3333 ; CLUSTER1: // Module: {{.*}}2.bc
3434 ; CLUSTER1-NEXT: subgraph cluster_1 {
35 ; CLUSTER1-DAG: M1_[[A:[0-9]+]] [{{.*}}A|extern{{.*}}]; // variable
35 ; CLUSTER1-DAG: M1_[[A:[0-9]+]] [{{.*}}A|extern{{.*}}]; // variable, immutable
3636 ; CLUSTER1-DAG: M1_[[FOO:[0-9]+]] [{{.*}}foo|extern{{.*}} ffl: 00001{{.*}}]; // function
37 ; CLUSTER1-DAG: M1_[[B:[0-9]+]] [{{.*}}B|extern{{.*}}]; // variable
37 ; CLUSTER1-DAG: M1_[[B:[0-9]+]] [{{.*}}B|extern{{.*}}]; // variable, immutable
3838 ; CLUSTER1-DAG: M1_[[BAR:[0-9]+]] [{{.*}}bar|extern{{.*}}]; // function, dead
3939 ; CLUSTER1-NEXT: // Edges:
40 ; CLUSTER1-DAG: M1_[[FOO]] -> M1_[[B]] [{{.*}}]; // ref
41 ; CLUSTER1-DAG: M1_[[FOO]] -> M1_[[A]] [{{.*}}]; // ref
40 ; CLUSTER1-DAG: M1_[[FOO]] -> M1_[[B]] [{{.*}}]; // const-ref
41 ; CLUSTER1-DAG: M1_[[FOO]] -> M1_[[A]] [{{.*}}]; // const-ref
4242 ; CLUSTER1-DAG: }
4343
4444 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
11 ; RUN: opt -module-summary %p/Inputs/globals-import-cf-baz.ll -o %t2.bc
22 ; RUN: llvm-lto -thinlto-action=thinlink %t1.bc %t2.bc -o %t3.index.bc
33
4 ; RUN: llvm-lto -thinlto-action=import %t1.bc %t2.bc -thinlto-index=%t3.index.bc
4 ; RUN: llvm-lto -thinlto-action=import -exported-symbol=main %t1.bc -thinlto-index=%t3.index.bc
55 ; RUN: llvm-dis %t1.bc.thinlto.imported.bc -o - | FileCheck --check-prefix=IMPORT %s
66 ; RUN: llvm-lto -thinlto-action=optimize %t1.bc.thinlto.imported.bc -o %t1.bc.thinlto.opt.bc
77 ; RUN: llvm-dis %t1.bc.thinlto.opt.bc -o - | FileCheck --check-prefix=OPTIMIZE %s
88
9 ; IMPORT: @baz = available_externally local_unnamed_addr constant i32 10
9 ; IMPORT: @baz = internal local_unnamed_addr constant i32 10
1010
1111 ; OPTIMIZE: define i32 @main()
1212 ; OPTIMIZE-NEXT: ret i32 10
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/index-const-prop-define-g.ll -o %t2.bc
2 ; RUN: llvm-lto2 run -O0 -save-temps %t2.bc -r=%t2.bc,g,pl %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,g, -o %t3
3 ; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s
4
5 ; With -O0 import is disabled so we must not internalize
6 ; read-only globals
7 ; CHECK: @g = dso_local global i32 42
8
9 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
10 target triple = "x86_64-unknown-linux-gnu"
11
12 @g = external global i32
13
14 define i32 @main() {
15 %v = load i32, i32* @g
16 ret i32 %v
17 }
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/index-const-prop-alias.ll -o %t2.bc
2 ; RUN: llvm-lto2 run %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,ret_ptr,pl -r=%t1.bc,g.alias,l -r=%t1.bc,g,l \
3 ; RUN: %t2.bc -r=%t2.bc,g,pl -r=%t2.bc,g.alias,pl -save-temps -o %t3
4 ; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT
5 ; RUN: llvm-dis %t3.1.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN
6
7 ; When ret_ptr is preserved we return pointer to alias, so we can't internalize aliasee
8 ; RUN: llvm-lto2 run %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,ret_ptr,plx -r=%t1.bc,g.alias,l -r=%t1.bc,g,l \
9 ; RUN: %t2.bc -r=%t2.bc,g,pl -r=%t2.bc,g.alias,pl -save-temps -o %t4
10 ; RUN: llvm-dis %t4.1.3.import.bc -o - | FileCheck %s --check-prefix=PRESERVED
11
12 ; When g.alias is preserved we can't internalize aliasee either
13 ; RUN: llvm-lto2 run %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,ret_ptr,pl -r=%t1.bc,g.alias,l -r=%t1.bc,g,l \
14 ; RUN: %t2.bc -r=%t2.bc,g,pl -r=%t2.bc,g.alias,plx -save-temps -o %t5
15 ; RUN: llvm-dis %t5.1.3.import.bc -o - | FileCheck %s --check-prefix=PRESERVED
16
17 ; We currently don't support importing aliases
18 ; IMPORT: @g.alias = external dso_local global i32
19 ; IMPORT-NEXT: @g = internal global i32 42, align 4 #0
20 ; IMPORT: attributes #0 = { "thinlto-internalize" }
21
22 ; CODEGEN: define dso_local i32 @main
23 ; CODEGEN-NEXT: ret i32 42
24
25 ; PRESERVED: @g.alias = external dso_local global i32
26 ; PRESERVED-NEXT: @g = available_externally dso_local global i32 42, align 4
27
28 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
29 target triple = "x86_64-unknown-linux-gnu"
30
31 @g.alias = external global i32
32 @g = external global i32
33
34 define i32 @main() {
35 %v = load i32, i32* @g
36 ret i32 %v
37 }
38
39 define i32* @ret_ptr() {
40 ret i32* @g.alias
41 }
0 ; Check that we correctly handle 'ReadOnly' attribute when computing cache key
1 ; RUN: opt -module-summary -module-hash %s -o %t1.bc
2 ; RUN: opt -module-summary -module-hash %p/Inputs/index-const-prop-cache-foo.ll -o %t2.bc
3 ; RUN: opt -module-summary -module-hash %p/Inputs/index-const-prop-cache-test1.ll -o %t3.bc
4 ; RUN: opt -module-summary -module-hash %p/Inputs/index-const-prop-cache-test2.ll -o %t4.bc
5 ; RUN: rm -Rf %t.cache && mkdir %t.cache
6
7 ; Here @gFoo variable is writeable
8 ; RUN: llvm-lto -thinlto-action=run %t1.bc %t4.bc %t2.bc \
9 ; RUN: -exported-symbol=main -exported-symbol=test -thinlto-cache-dir=%t.cache
10 ; RUN: ls %t.cache/llvmcache-* | count 3
11
12 ; Now gFoo is read-only and all modules should get different cache keys.
13 ; RUN: llvm-lto -thinlto-action=run %t1.bc %t3.bc %t2.bc \
14 ; RUN: -exported-symbol=main -exported-symbol=test -thinlto-cache-dir=%t.cache
15 ; RUN: ls %t.cache/llvmcache-* | count 6
16
17 ; Do the same but with llvm-lto2
18 ; RUN: rm -Rf %t.cache && mkdir %t.cache
19 ; RUN: llvm-lto2 run %t1.bc %t4.bc %t2.bc -cache-dir=%t.cache -o %t5 \
20 ; RUN: -r=%t1.bc,main,plx -r=%t1.bc,foo,l \
21 ; RUN: -r=%t4.bc,test,plx -r=%t4.bc,foo,l -r=%t4.bc,bar,l \
22 ; RUN: -r=%t2.bc,foo,pl -r=%t2.bc,bar,pl -r=%t2.bc,rand,
23 ; RUN: ls %t.cache/llvmcache-* | count 3
24
25 ; RUN: llvm-lto2 run %t1.bc %t3.bc %t2.bc -cache-dir %t.cache -o %t6 \
26 ; RUN: -r=%t1.bc,main,plx -r=%t1.bc,foo,l \
27 ; RUN: -r=%t3.bc,test,plx -r=%t3.bc,foo,l \
28 ; RUN: -r=%t2.bc,foo,pl -r=%t2.bc,bar,pl -r=%t2.bc,rand,
29 ; RUN: ls %t.cache/llvmcache-* | count 6
30
31 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
32 target triple = "x86_64-unknown-linux-gnu"
33
34 ; Function Attrs: nounwind ssp uwtable
35 define i32 @main() local_unnamed_addr {
36 %1 = tail call i32 (...) @foo()
37 ret i32 %1
38 }
39
40 declare i32 @foo(...) local_unnamed_addr
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/index-const-prop-comdat.ll -o %t2.bc
2 ; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,g,pl %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,g, -o %t3
3 ; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s
4
5 ; Comdats are not internalized even if they are read only.
6 ; CHECK: @g = available_externally dso_local global i32 42
7
8 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
9 target triple = "x86_64-unknown-linux-gnu"
10
11 @g = external global i32
12
13 define i32 @main() {
14 %v = load i32, i32* @g
15 ret i32 %v
16 }
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/index-const-prop-define-g.ll -o %t2.bc
2 ; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,g,pl \
3 ; RUN: %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,foo,pl -r=%t1.bc,g, -o %t3
4 ; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s
5
6 ; Dead globals are converted to declarations by ThinLTO in dropDeadSymbols
7 ; If we try to internalize such we'll get a broken module.
8 ; CHECK: @g = external dso_local global i32
9
10 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
11 target triple = "x86_64-unknown-linux-gnu"
12
13 @g = external global i32
14
15 ; We need at least one live symbol to enable dead stripping
16 ; Otherwise ModuleSummaryIndex::isGlobalValueLive will always
17 ; return true.
18 define i32 @main() {
19 ret i32 42
20 }
21
22 define i32 @foo() {
23 %v = load i32, i32* @g
24 ret i32 %v
25 }
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/index-const-prop-define-g.ll -o %t2.bc
2 ; RUN: opt -module-summary %p/Inputs/index-const-prop-full-lto.ll -o %t3.bc
3 ; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,g,pl \
4 ; RUN: %t1.bc -r=%t1.bc,foo,l -r=%t1.bc,main,plx -r=%t1.bc,g, \
5 ; RUN: %t3.bc -r=%t3.bc,foo,pl -r=%t3.bc,g, -o %t4
6 ; RUN: llvm-dis %t4.2.3.import.bc -o - | FileCheck %s
7
8 ; All references from functions in full LTO module are not constant.
9 ; We cannot internalize @g
10 ; CHECK: @g = available_externally dso_local global i32 42
11
12 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
13 target triple = "x86_64-unknown-linux-gnu"
14
15 declare i32 @foo()
16 @g = external global i32
17
18 define i32 @main() {
19 %v = call i32 @foo()
20 %v2 = load i32, i32* @g
21 %v3 = add i32 %v, %v2
22 ret i32 %v3
23 }
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/index-const-prop-gvref.ll -o %t2.bc
2 ; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,b,pl -r=%t2.bc,a,pl \
3 ; RUN: %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,a, -r=%t1.bc,b, -o %t3
4 ; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=SRC
5 ; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s --check-prefix=DEST
6
7 ; No variable in the source module should have been internalized
8 ; SRC: @b = dso_local global i32* @a
9 ; SRC-NEXT: @a = dso_local global i32 42
10
11 ; We can't internalize globals referenced by other live globals
12 ; DEST: @b = external dso_local global i32*
13 ; DEST-NEXT: @a = available_externally dso_local global i32 42, align 4
14
15 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
16 target triple = "x86_64-unknown-linux-gnu"
17
18 @a = external global i32
19 @b = external global i32*
20
21 define i32 @main() {
22 %p = load i32*, i32** @b, align 8
23 store i32 33, i32* %p, align 4
24 %v = load i32, i32* @a, align 4
25 ret i32 %v
26 }
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/index-const-prop-define-g.ll -o %t2.bc
2 ; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,g,pl %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,g, -o %t3
3 ; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s
4
5 ; The 'store' instruction in @main should prevent internalization
6 ; even when there is 'load' instruction before it.
7 ; CHECK: @g = available_externally dso_local global i32 42
8
9 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
10 target triple = "x86_64-unknown-linux-gnu"
11
12 @g = external global i32
13
14 define i32 @main() {
15 %v = load i32, i32* @g
16 %q = add i32 %v, 1
17 store i32 %q, i32* @g
18
19 ret i32 %v
20 }
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/index-const-prop-linkage.ll -o %t2.bc
2 ; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,foo,pl -r=%t2.bc,g1,pl -r=%t2.bc,g2,pl -r=%t2.bc,g3, \
3 ; RUN: %t1.bc -r=%t1.bc,foo, -r=%t1.bc,main,plx -r=%t1.bc,g2, -o %t3
4 ; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s
5
6 ; Check that we never internalize anything with:
7 ; - appending linkage
8 ; - common linkage
9 ; - available_externally linkage
10 ; - reference from @llvm.used
11 ; CHECK: @llvm.used = appending global [1 x i32*] [i32* @g2]
12 ; CHECK-NEXT: @g1 = external dso_local global i32, align 4
13 ; CHECK-NEXT: @g2 = available_externally dso_local global i32 42, align 4
14 ; CHECK-NEXT: @g3 = available_externally global i32 42, align 4
15
16 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
17 target triple = "x86_64-unknown-linux-gnu"
18
19 declare i32 @foo()
20 @g2 = external global i32
21 @llvm.used = appending global [1 x i32*] [i32* @g2]
22
23 define i32 @main() {
24 %v = call i32 @foo()
25 ret i32 %v
26 }
0 ; Check constant propagation in thinlto combined summary. This allows us to do 2 things:
1 ; 1. Internalize global definition which is not used externally if all accesses to it are read-only
2 ; 2. Make a local copy of internal definition if all accesses to it are readonly. This allows constant
3 ; folding it during optimziation phase.
4
5 ; RUN: opt -module-summary %s -o %t1.bc
6 ; RUN: opt -module-summary %p/Inputs/index-const-prop.ll -o %t2.bc
7 ; RUN: llvm-lto -thinlto-action=thinlink -o %t3.index.bc %t1.bc %t2.bc
8 ; RUN: llvm-lto -thinlto-action=import -exported-symbol=main %t1.bc -thinlto-index=%t3.index.bc -o %t1.imported.bc
9 ; RUN: llvm-dis %t1.imported.bc -o - | FileCheck %s --check-prefix=IMPORT
10 ; RUN: llvm-lto -thinlto-action=optimize %t1.imported.bc -o - | llvm-dis - -o - | FileCheck %s --check-prefix=OPTIMIZE
11
12 ; Check that we don't internalize gBar when it is exported
13 ; RUN: llvm-lto -thinlto-action=import -exported-symbol main -exported-symbol gBar %t1.bc -thinlto-index=%t3.index.bc -o %t1.imported2.bc
14 ; RUN: llvm-dis %t1.imported2.bc -o - | FileCheck %s --check-prefix=IMPORT2
15
16 ; IMPORT: @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4, !dbg !0
17 ; IMPORT-NEXT: @gBar = internal local_unnamed_addr global i32 2, align 4, !dbg !5
18 ; IMPORT: !DICompileUnit({{.*}}, globals: !{{[0-9]+}})
19
20 ; OPTIMIZE: define i32 @main
21 ; OPTIMIZE-NEXT: ret i32 3
22
23 ; IMPORT2: @gBar = available_externally local_unnamed_addr global i32 2, align 4, !dbg !5
24
25 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
26 target triple = "x86_64-pc-linux-gnu"
27
28 @gBar = external global i32
29
30 define i32 @main() local_unnamed_addr {
31 %call = tail call i32 bitcast (i32 (...)* @foo to i32 ()*)()
32 %call1 = tail call i32 bitcast (i32 (...)* @bar to i32 ()*)()
33 %add = add nsw i32 %call1, %call
34 ret i32 %add
35 }
36
37 declare i32 @foo(...) local_unnamed_addr
38
39 declare i32 @bar(...) local_unnamed_addr
0 ; Check constant propagation in thinlto combined summary. This allows us to do 2 things:
1 ; 1. Internalize global definition which is not used externally if all accesses to it are read-only
2 ; 2. Make a local copy of internal definition if all accesses to it are readonly. This allows constant
3 ; folding it during optimziation phase.
4 ; RUN: opt -module-summary %s -o %t1.bc
5 ; RUN: opt -module-summary %p/Inputs/index-const-prop.ll -o %t2.bc
6 ; RUN: llvm-lto2 run %t1.bc %t2.bc -save-temps \
7 ; RUN: -r=%t2.bc,foo,pl \
8 ; RUN: -r=%t2.bc,bar,pl \
9 ; RUN: -r=%t2.bc,baz,pl \
10 ; RUN: -r=%t2.bc,rand, \
11 ; RUN: -r=%t2.bc,gBar,pl \
12 ; RUN: -r=%t1.bc,main,plx \
13 ; RUN: -r=%t1.bc,foo, \
14 ; RUN: -r=%t1.bc,bar, \
15 ; RUN: -r=%t1.bc,gBar, \
16 ; RUN: -o %t3
17 ; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT
18 ; RUN: llvm-dis %t3.1.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN
19
20 ; Now check that we won't internalize global (gBar) if it's externally referenced
21 ; RUN: llvm-lto2 run %t1.bc %t2.bc -save-temps \
22 ; RUN: -r=%t2.bc,foo,pl \
23 ; RUN: -r=%t2.bc,bar,pl \
24 ; RUN: -r=%t2.bc,baz,pl \
25 ; RUN: -r=%t2.bc,rand, \
26 ; RUN: -r=%t2.bc,gBar,plx \
27 ; RUN: -r=%t1.bc,main,plx \
28 ; RUN: -r=%t1.bc,foo, \
29 ; RUN: -r=%t1.bc,bar, \
30 ; RUN: -r=%t1.bc,gBar, \
31 ; RUN: -o %t3
32 ; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT2
33
34 ; IMPORT: @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4
35 ; IMPORT-NEXT: @gBar = internal local_unnamed_addr global i32 2, align 4
36 ; IMPORT: !DICompileUnit({{.*}}, globals: !{{[0-9]+}})
37
38 ; CODEGEN: i32 @main()
39 ; CODEGEN-NEXT: ret i32 3
40
41 ; IMPORT2: @gBar = available_externally dso_local local_unnamed_addr global i32 2, align 4
42
43 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
44 target triple = "x86_64-pc-linux-gnu"
45
46 ; We should be able to link external definition of gBar to its declaration
47 @gBar = external global i32
48
49 define i32 @main() local_unnamed_addr {
50 %call = tail call i32 bitcast (i32 (...)* @foo to i32 ()*)()
51 %call1 = tail call i32 bitcast (i32 (...)* @bar to i32 ()*)()
52 %add = add nsw i32 %call1, %call
53 ret i32 %add
54 }
55
56 declare i32 @foo(...) local_unnamed_addr
57
58 declare i32 @bar(...) local_unnamed_addr