llvm.org GIT mirror llvm / 4697389
Reverted r365188 due to alignment problems on i686-android git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365206 91177308-0d34-0410-b5e6-96231b3b80d8 Eugene Leviant a month ago
28 changed file(s) with 201 addition(s) and 604 deletion(s). Raw diff Collapse all Expand all
161161 /// Struct that holds a reference to a particular GUID in a global value
162162 /// summary.
163163 struct ValueInfo {
164 enum Flags { HaveGV = 1, ReadOnly = 2, WriteOnly = 4 };
165 PointerIntPair3, int>
164 PointerIntPair2, int>
166165 RefAndFlags;
167166
168167 ValueInfo() = default;
188187 : getRef()->second.U.Name;
189188 }
190189
191 bool haveGVs() const { return RefAndFlags.getInt() & HaveGV; }
192 bool isReadOnly() const {
193 assert(isValidAccessSpecifier());
194 return RefAndFlags.getInt() & ReadOnly;
195 }
196 bool isWriteOnly() const {
197 assert(isValidAccessSpecifier());
198 return RefAndFlags.getInt() & WriteOnly;
199 }
200 unsigned getAccessSpecifier() const {
201 assert(isValidAccessSpecifier());
202 return RefAndFlags.getInt() & (ReadOnly | WriteOnly);
203 }
204 bool isValidAccessSpecifier() const {
205 unsigned BadAccessMask = ReadOnly | WriteOnly;
206 return (RefAndFlags.getInt() & BadAccessMask) != BadAccessMask;
207 }
208 void setReadOnly() {
209 // We expect ro/wo attribute to set only once during
210 // ValueInfo lifetime.
211 assert(getAccessSpecifier() == 0);
212 RefAndFlags.setInt(RefAndFlags.getInt() | ReadOnly);
213 }
214 void setWriteOnly() {
215 assert(getAccessSpecifier() == 0);
216 RefAndFlags.setInt(RefAndFlags.getInt() | WriteOnly);
217 }
190 bool haveGVs() const { return RefAndFlags.getInt() & 0x1; }
191 bool isReadOnly() const { return RefAndFlags.getInt() & 0x2; }
192 void setReadOnly() { RefAndFlags.setInt(RefAndFlags.getInt() | 0x2); }
218193
219194 const GlobalValueSummaryMapTy::value_type *getRef() const {
220195 return RefAndFlags.getPointer();
608583 std::move(TypeTestAssumeConstVCalls),
609584 std::move(TypeCheckedLoadConstVCalls)});
610585 }
611 // Gets the number of readonly and writeonly refs in RefEdgeList
612 std::pair specialRefCounts() const;
586 // Gets the number of immutable refs in RefEdgeList
587 unsigned immutableRefCount() const;
613588
614589 /// Check if this is a function summary.
615590 static bool classof(const GlobalValueSummary *GVS) {
737712 /// Global variable summary information to aid decisions and
738713 /// implementation of importing.
739714 ///
740 /// Global variable summary has two extra flag, telling if it is
741 /// readonly or writeonly. Both readonly and writeonly variables
742 /// can be optimized in the backed: readonly variables can be
743 /// const-folded, while writeonly vars can be completely eliminated
744 /// together with corresponding stores. We let both things happen
745 /// by means of internalizing such variables after ThinLTO import.
715 /// Global variable summary has extra flag, telling if it is
716 /// modified during the program run or not. This affects ThinLTO
717 /// internalization
746718 class GlobalVarSummary : public GlobalValueSummary {
747719 private:
748720 /// For vtable definitions this holds the list of functions and
751723
752724 public:
753725 struct GVarFlags {
754 GVarFlags(bool ReadOnly, bool WriteOnly)
755 : MaybeReadOnly(ReadOnly), MaybeWriteOnly(WriteOnly) {}
756
757 // In permodule summaries both MaybeReadOnly and MaybeWriteOnly
758 // bits are set, because attribute propagation occurs later on
759 // thin link phase.
760 unsigned MaybeReadOnly : 1;
761 unsigned MaybeWriteOnly : 1;
726 GVarFlags(bool ReadOnly = false) : ReadOnly(ReadOnly) {}
727
728 unsigned ReadOnly : 1;
762729 } VarFlags;
763730
764731 GlobalVarSummary(GVFlags Flags, GVarFlags VarFlags,
772739 }
773740
774741 GVarFlags varflags() const { return VarFlags; }
775 void setReadOnly(bool RO) { VarFlags.MaybeReadOnly = RO; }
776 void setWriteOnly(bool WO) { VarFlags.MaybeWriteOnly = WO; }
777 bool maybeReadOnly() const { return VarFlags.MaybeReadOnly; }
778 bool maybeWriteOnly() const { return VarFlags.MaybeWriteOnly; }
742 void setReadOnly(bool RO) { VarFlags.ReadOnly = RO; }
743 bool isReadOnly() const { return VarFlags.ReadOnly; }
779744
780745 void setVTableFuncs(VTableFuncList Funcs) {
781746 assert(!VTableFuncs);
13461311 void dumpSCCs(raw_ostream &OS);
13471312
13481313 /// Analyze index and detect unmodified globals
1349 void propagateAttributes(const DenseSet &PreservedSymbols);
1314 void propagateConstants(const DenseSet &PreservedSymbols);
13501315 };
13511316
13521317 /// GraphTraits definition to build SCC for the index
230230 return false;
231231 }
232232
233 static bool isNonVolatileStore(const Instruction *I) {
234 if (const auto *SI = dyn_cast(I))
235 return !SI->isVolatile();
236
237 return false;
238 }
239
240233 static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
241234 const Function &F, BlockFrequencyInfo *BFI,
242235 ProfileSummaryInfo *PSI, DominatorTree &DT,
251244 // Map from callee ValueId to profile count. Used to accumulate profile
252245 // counts for all static calls to a given callee.
253246 MapVector CallGraphEdges;
254 SetVector RefEdges, LoadRefEdges, StoreRefEdges;
247 SetVector RefEdges;
255248 SetVector TypeTests;
256249 SetVector TypeTestAssumeVCalls,
257250 TypeCheckedLoadVCalls;
264257 // list.
265258 findRefEdges(Index, &F, RefEdges, Visited);
266259 std::vector NonVolatileLoads;
267 std::vector NonVolatileStores;
268260
269261 bool HasInlineAsmMaybeReferencingInternal = false;
270262 for (const BasicBlock &BB : F)
272264 if (isa(I))
273265 continue;
274266 ++NumInsts;
275 // Regular LTO module doesn't participate in ThinLTO import,
276 // so no reference from it can be read/writeonly, since this
277 // would require importing variable as local copy
278 if (IsThinLTO) {
279 if (isNonVolatileLoad(&I)) {
280 // Postpone processing of non-volatile load instructions
281 // See comments below
282 Visited.insert(&I);
283 NonVolatileLoads.push_back(&I);
284 continue;
285 } else if (isNonVolatileStore(&I)) {
286 Visited.insert(&I);
287 NonVolatileStores.push_back(&I);
288 // All references from second operand of store (destination address)
289 // can be considered write-only if they're not referenced by any
290 // non-store instruction. References from first operand of store
291 // (stored value) can't be treated either as read- or as write-only
292 // so we add them to RefEdges as we do with all other instructions
293 // except non-volatile load.
294 Value *Stored = I.getOperand(0);
295 if (auto *GV = dyn_cast(Stored))
296 // findRefEdges will try to examine GV operands, so instead
297 // of calling it we should add GV to RefEdges directly.
298 RefEdges.insert(Index.getOrInsertValueInfo(GV));
299 else if (auto *U = dyn_cast(Stored))
300 findRefEdges(Index, U, RefEdges, Visited);
301 continue;
302 }
267 if (isNonVolatileLoad(&I)) {
268 // Postpone processing of non-volatile load instructions
269 // See comments below
270 Visited.insert(&I);
271 NonVolatileLoads.push_back(&I);
272 continue;
303273 }
304274 findRefEdges(Index, &I, RefEdges, Visited);
305275 auto CS = ImmutableCallSite(&I);
390360 }
391361 }
392362
393 std::vector Refs;
394 if (IsThinLTO) {
395 auto AddRefEdges = [&](const std::vector &Instrs,
396 SetVector &Edges,
397 SmallPtrSet &Cache) {
398 for (const auto *I : Instrs) {
399 Cache.erase(I);
400 findRefEdges(Index, I, Edges, Cache);
401 }
402 };
403
404 // By now we processed all instructions in a function, except
405 // non-volatile loads and non-volatile value stores. Let's find
406 // ref edges for both of instruction sets
407 AddRefEdges(NonVolatileLoads, LoadRefEdges, Visited);
408 // We can add some values to the Visited set when processing load
409 // instructions which are also used by stores in NonVolatileStores.
410 // For example this can happen if we have following code:
411 //
412 // store %Derived* @foo, %Derived** bitcast (%Base** @bar to %Derived**)
413 // %42 = load %Derived*, %Derived** bitcast (%Base** @bar to %Derived**)
414 //
415 // After processing loads we'll add bitcast to the Visited set, and if
416 // we use the same set while processing stores, we'll never see store
417 // to @bar and @bar will be mistakenly treated as readonly.
418 SmallPtrSet StoreCache;
419 AddRefEdges(NonVolatileStores, StoreRefEdges, StoreCache);
420
421 // If both load and store instruction reference the same variable
422 // we won't be able to optimize it. Add all such reference edges
423 // to RefEdges set.
424 for (auto &VI : StoreRefEdges)
425 if (LoadRefEdges.remove(VI))
426 RefEdges.insert(VI);
427
428 unsigned RefCnt = RefEdges.size();
429 // All new reference edges inserted in two loops below are either
430 // read or write only. They will be grouped in the end of RefEdges
431 // vector, so we can use a single integer value to identify them.
432 for (auto &VI : LoadRefEdges)
433 RefEdges.insert(VI);
434
435 unsigned FirstWORef = RefEdges.size();
436 for (auto &VI : StoreRefEdges)
437 RefEdges.insert(VI);
438
439 Refs = RefEdges.takeVector();
440 for (; RefCnt < FirstWORef; ++RefCnt)
363 // By now we processed all instructions in a function, except
364 // non-volatile loads. All new refs we add in a loop below
365 // are obviously constant. All constant refs are grouped in the
366 // end of RefEdges vector, so we can use a single integer value
367 // to identify them.
368 unsigned RefCnt = RefEdges.size();
369 for (const Instruction *I : NonVolatileLoads) {
370 Visited.erase(I);
371 findRefEdges(Index, I, RefEdges, Visited);
372 }
373 std::vector Refs = RefEdges.takeVector();
374 // Regular LTO module doesn't participate in ThinLTO import,
375 // so no reference from it can be readonly, since this would
376 // require importing variable as local copy
377 if (IsThinLTO)
378 for (; RefCnt < Refs.size(); ++RefCnt)
441379 Refs[RefCnt].setReadOnly();
442380
443 for (; RefCnt < Refs.size(); ++RefCnt)
444 Refs[RefCnt].setWriteOnly();
445 } else {
446 Refs = RefEdges.takeVector();
447 }
448381 // Explicit add hot edges to enforce importing for designated GUIDs for
449382 // sample PGO, to enable the same inlines as the profiled optimized binary.
450383 for (auto &I : F.getImportGUIDs())
592525 }
593526 }
594527
595 // Don't mark variables we won't be able to internalize as read/write-only.
596 bool CanBeInternalized =
528 // Don't mark variables we won't be able to internalize as read-only.
529 GlobalVarSummary::GVarFlags VarFlags(
597530 !V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() &&
598 !V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass();
599 GlobalVarSummary::GVarFlags VarFlags(CanBeInternalized, CanBeInternalized);
531 !V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass());
600532 auto GVarSummary = llvm::make_unique(Flags, VarFlags,
601533 RefEdges.takeVector());
602534 if (NonRenamableLocal)
714646 } else {
715647 std::unique_ptr Summary =
716648 llvm::make_unique(
717 GVFlags, GlobalVarSummary::GVarFlags(false, false),
649 GVFlags, GlobalVarSummary::GVarFlags(),
718650 ArrayRef{});
719651 Index.addGlobalValueSummary(*GV, std::move(Summary));
720652 }
78597859
78607860 static void resolveFwdRef(ValueInfo *Fwd, ValueInfo &Resolved) {
78617861 bool ReadOnly = Fwd->isReadOnly();
7862 bool WriteOnly = Fwd->isWriteOnly();
7863 assert(!(ReadOnly && WriteOnly));
78647862 *Fwd = Resolved;
78657863 if (ReadOnly)
78667864 Fwd->setReadOnly();
7867 if (WriteOnly)
7868 Fwd->setWriteOnly();
78697865 }
78707866
78717867 /// Stores the given Name/GUID and associated summary into the Index.
80958091 GlobalValueSummary::GVFlags GVFlags = GlobalValueSummary::GVFlags(
80968092 /*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false,
80978093 /*Live=*/false, /*IsLocal=*/false, /*CanAutoHide=*/false);
8098 GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false,
8099 /* WriteOnly */ false);
8094 GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false);
81008095 std::vector Refs;
81018096 VTableFuncList VTableFuncs;
81028097 if (ParseToken(lltok::colon, "expected ':' here") ||
84378432 VContexts.push_back(VC);
84388433 } while (EatIfPresent(lltok::comma));
84398434
8440 // Sort value contexts so that ones with writeonly
8441 // and readonly ValueInfo are at the end of VContexts vector.
8442 // See FunctionSummary::specialRefCounts()
8435 // Sort value contexts so that ones with readonly ValueInfo are at the end
8436 // of VContexts vector. This is needed to match immutableRefCount() behavior.
84438437 llvm::sort(VContexts, [](const ValueContext &VC1, const ValueContext &VC2) {
8444 return VC1.VI.getAccessSpecifier() < VC2.VI.getAccessSpecifier();
8438 return VC1.VI.isReadOnly() < VC2.VI.isReadOnly();
84458439 });
84468440
84478441 IdToIndexMapType IdToIndexMap;
87598753 }
87608754
87618755 /// GVarFlags
8762 /// ::= 'varFlags' ':' '(' 'readonly' ':' Flag
8763 /// ',' 'writeonly' ':' Flag ')'
8756 /// ::= 'varFlags' ':' '(' 'readonly' ':' Flag ')'
87648757 bool LLParser::ParseGVarFlags(GlobalVarSummary::GVarFlags &GVarFlags) {
87658758 assert(Lex.getKind() == lltok::kw_varFlags);
87668759 Lex.Lex();
87678760
8761 unsigned Flag = 0;
87688762 if (ParseToken(lltok::colon, "expected ':' here") ||
8769 ParseToken(lltok::lparen, "expected '(' here"))
8770 return true;
8771
8772 auto ParseRest = [this](unsigned int &Val) {
8773 Lex.Lex();
8774 if (ParseToken(lltok::colon, "expected ':'"))
8775 return true;
8776 return ParseFlag(Val);
8777 };
8778
8779 do {
8780 unsigned Flag = 0;
8781 switch (Lex.getKind()) {
8782 case lltok::kw_readonly:
8783 if (ParseRest(Flag))
8784 return true;
8785 GVarFlags.MaybeReadOnly = Flag;
8786 break;
8787 case lltok::kw_writeonly:
8788 if (ParseRest(Flag))
8789 return true;
8790 GVarFlags.MaybeWriteOnly = Flag;
8791 break;
8792 default:
8793 return Error(Lex.getLoc(), "expected gvar flag type");
8794 }
8795 } while (EatIfPresent(lltok::comma));
8796 return ParseToken(lltok::rparen, "expected ')' here");
8763 ParseToken(lltok::lparen, "expected '(' here") ||
8764 ParseToken(lltok::kw_readonly, "expected 'readonly' here") ||
8765 ParseToken(lltok::colon, "expected ':' here"))
8766 return true;
8767
8768 ParseFlag(Flag);
8769 GVarFlags.ReadOnly = Flag;
8770
8771 if (ParseToken(lltok::rparen, "expected ')' here"))
8772 return true;
8773 return false;
87978774 }
87988775
87998776 /// ModuleReference
88168793 /// GVReference
88178794 /// ::= SummaryID
88188795 bool LLParser::ParseGVReference(ValueInfo &VI, unsigned &GVId) {
8819 bool WriteOnly = false, ReadOnly = EatIfPresent(lltok::kw_readonly);
8820 if (!ReadOnly)
8821 WriteOnly = EatIfPresent(lltok::kw_writeonly);
8796 bool ReadOnly = EatIfPresent(lltok::kw_readonly);
88228797 if (ParseToken(lltok::SummaryID, "expected GV ID"))
88238798 return true;
88248799
88338808
88348809 if (ReadOnly)
88358810 VI.setReadOnly();
8836 if (WriteOnly)
8837 VI.setWriteOnly();
8838 return false;
8839 }
8811 return false;
8812 }
983983
984984 // Decode the flags for GlobalVariable in the summary
985985 static GlobalVarSummary::GVarFlags getDecodedGVarFlags(uint64_t RawFlags) {
986 return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false,
987 (RawFlags & 0x2) ? true : false);
986 return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false);
988987 }
989988
990989 static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) {
56835682 parseTypeIdCompatibleVtableInfo(Record, Slot, TypeId);
56845683 }
56855684
5686 static void setSpecialRefs(std::vector &Refs, unsigned ROCnt,
5687 unsigned WOCnt) {
5688 // Readonly and writeonly refs are in the end of the refs list.
5689 assert(ROCnt + WOCnt <= Refs.size());
5690 unsigned FirstWORef = Refs.size() - WOCnt;
5691 unsigned RefNo = FirstWORef - ROCnt;
5692 for (; RefNo < FirstWORef; ++RefNo)
5685 static void setImmutableRefs(std::vector &Refs, unsigned Count) {
5686 // Read-only refs are in the end of the refs list.
5687 for (unsigned RefNo = Refs.size() - Count; RefNo < Refs.size(); ++RefNo)
56935688 Refs[RefNo].setReadOnly();
5694 for (; RefNo < Refs.size(); ++RefNo)
5695 Refs[RefNo].setWriteOnly();
56965689 }
56975690
56985691 // Eagerly parse the entire summary block. This populates the GlobalValueSummary
57195712 }
57205713 const uint64_t Version = Record[0];
57215714 const bool IsOldProfileFormat = Version == 1;
5722 if (Version < 1 || Version > 7)
5715 if (Version < 1 || Version > 6)
57235716 return error("Invalid summary version " + Twine(Version) +
5724 ". Version should be in the range [1-7].");
5717 ". Version should be in the range [1-6].");
57255718 Record.clear();
57265719
57275720 // Keep around the last seen summary to be used when we see an optional
58205813 unsigned InstCount = Record[2];
58215814 uint64_t RawFunFlags = 0;
58225815 unsigned NumRefs = Record[3];
5823 unsigned NumRORefs = 0, NumWORefs = 0;
5816 unsigned NumImmutableRefs = 0;
58245817 int RefListStartIndex = 4;
58255818 if (Version >= 4) {
58265819 RawFunFlags = Record[3];
58275820 NumRefs = Record[4];
58285821 RefListStartIndex = 5;
58295822 if (Version >= 5) {
5830 NumRORefs = Record[5];
5823 NumImmutableRefs = Record[5];
58315824 RefListStartIndex = 6;
5832 if (Version >= 7) {
5833 NumWORefs = Record[6];
5834 RefListStartIndex = 7;
5835 }
58365825 }
58375826 }
58385827
58525841 std::vector Calls = makeCallList(
58535842 ArrayRef(Record).slice(CallGraphEdgeStartIndex),
58545843 IsOldProfileFormat, HasProfile, HasRelBF);
5855 setSpecialRefs(Refs, NumRORefs, NumWORefs);
5844 setImmutableRefs(Refs, NumImmutableRefs);
58565845 auto FS = llvm::make_unique(
58575846 Flags, InstCount, getDecodedFFlags(RawFunFlags), /*EntryCount=*/0,
58585847 std::move(Refs), std::move(Calls), std::move(PendingTypeTests),
59035892 unsigned ValueID = Record[0];
59045893 uint64_t RawFlags = Record[1];
59055894 unsigned RefArrayStart = 2;
5906 GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false,
5907 /* WriteOnly */ false);
5895 GlobalVarSummary::GVarFlags GVF;
59085896 auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
59095897 if (Version >= 5) {
59105898 GVF = getDecodedGVarFlags(Record[2]);
59615949 uint64_t RawFunFlags = 0;
59625950 uint64_t EntryCount = 0;
59635951 unsigned NumRefs = Record[4];
5964 unsigned NumRORefs = 0, NumWORefs = 0;
5952 unsigned NumImmutableRefs = 0;
59655953 int RefListStartIndex = 5;
59665954
59675955 if (Version >= 4) {
59695957 RefListStartIndex = 6;
59705958 size_t NumRefsIndex = 5;
59715959 if (Version >= 5) {
5972 unsigned NumRORefsOffset = 1;
59735960 RefListStartIndex = 7;
59745961 if (Version >= 6) {
59755962 NumRefsIndex = 6;
59765963 EntryCount = Record[5];
59775964 RefListStartIndex = 8;
5978 if (Version >= 7) {
5979 RefListStartIndex = 9;
5980 NumWORefs = Record[8];
5981 NumRORefsOffset = 2;
5982 }
59835965 }
5984 NumRORefs = Record[RefListStartIndex - NumRORefsOffset];
5966 NumImmutableRefs = Record[RefListStartIndex - 1];
59855967 }
59865968 NumRefs = Record[NumRefsIndex];
59875969 }
59975979 ArrayRef(Record).slice(CallGraphEdgeStartIndex),
59985980 IsOldProfileFormat, HasProfile, false);
59995981 ValueInfo VI = getValueInfoFromValueId(ValueID).first;
6000 setSpecialRefs(Refs, NumRORefs, NumWORefs);
5982 setImmutableRefs(Refs, NumImmutableRefs);
60015983 auto FS = llvm::make_unique(
60025984 Flags, InstCount, getDecodedFFlags(RawFunFlags), EntryCount,
60035985 std::move(Refs), std::move(Edges), std::move(PendingTypeTests),
60446026 uint64_t ModuleId = Record[1];
60456027 uint64_t RawFlags = Record[2];
60466028 unsigned RefArrayStart = 3;
6047 GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false,
6048 /* WriteOnly */ false);
6029 GlobalVarSummary::GVarFlags GVF;
60496030 auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
60506031 if (Version >= 5) {
60516032 GVF = getDecodedGVarFlags(Record[3]);
10191019 }
10201020
10211021 static uint64_t getEncodedGVarFlags(GlobalVarSummary::GVarFlags Flags) {
1022 uint64_t RawFlags = Flags.MaybeReadOnly | (Flags.MaybeWriteOnly << 1);
1022 uint64_t RawFlags = Flags.ReadOnly;
10231023 return RawFlags;
10241024 }
10251025
36313631 FunctionSummary *FS = cast(Summary);
36323632 writeFunctionTypeMetadataRecords(Stream, FS);
36333633
3634 auto SpecialRefCnts = FS->specialRefCounts();
36353634 NameVals.push_back(getEncodedGVSummaryFlags(FS->flags()));
36363635 NameVals.push_back(FS->instCount());
36373636 NameVals.push_back(getEncodedFFlags(FS->fflags()));
36383637 NameVals.push_back(FS->refs().size());
3639 NameVals.push_back(SpecialRefCnts.first); // rorefcnt
3640 NameVals.push_back(SpecialRefCnts.second); // worefcnt
3638 NameVals.push_back(FS->immutableRefCount());
36413639
36423640 for (auto &RI : FS->refs())
36433641 NameVals.push_back(VE.getValueID(RI.getValue()));
37113709 // Current version for the summary.
37123710 // This is bumped whenever we introduce changes in the way some record are
37133711 // interpreted, like flags for instance.
3714 static const uint64_t INDEX_VERSION = 7;
3712 static const uint64_t INDEX_VERSION = 6;
37153713
37163714 /// Emit the per-module summary section alongside the rest of
37173715 /// the module's bitcode.
37533751 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
37543752 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags
37553753 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
3756 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // rorefcnt
3757 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // worefcnt
3754 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt
37583755 // numrefs x valueid, n x (valueid, hotness)
37593756 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
37603757 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
37713768 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
37723769 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags
37733770 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
3774 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // rorefcnt
3775 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // worefcnt
3771 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt
37763772 // numrefs x valueid, n x (valueid [, rel_block_freq])
37773773 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
37783774 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
39043900 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags
39053901 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // entrycount
39063902 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
3907 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // rorefcnt
3908 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // worefcnt
3903 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt
39093904 // numrefs x valueid, n x (valueid)
39103905 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
39113906 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
39213916 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags
39223917 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // entrycount
39233918 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
3924 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // rorefcnt
3925 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // worefcnt
3919 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt
39263920 // numrefs x valueid, n x (valueid, hotness)
39273921 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
39283922 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
40244018
40254019 // Fill in below
40264020 NameVals.push_back(0); // numrefs
4027 NameVals.push_back(0); // rorefcnt
4028 NameVals.push_back(0); // worefcnt
4029
4030 unsigned Count = 0, RORefCnt = 0, WORefCnt = 0;
4021 NameVals.push_back(0); // immutablerefcnt
4022
4023 unsigned Count = 0, ImmutableRefCnt = 0;
40314024 for (auto &RI : FS->refs()) {
40324025 auto RefValueId = getValueId(RI.getGUID());
40334026 if (!RefValueId)
40344027 continue;
40354028 NameVals.push_back(*RefValueId);
40364029 if (RI.isReadOnly())
4037 RORefCnt++;
4038 else if (RI.isWriteOnly())
4039 WORefCnt++;
4030 ImmutableRefCnt++;
40404031 Count++;
40414032 }
40424033 NameVals[6] = Count;
4043 NameVals[7] = RORefCnt;
4044 NameVals[8] = WORefCnt;
4034 NameVals[7] = ImmutableRefCnt;
40454035
40464036 bool HasProfileData = false;
40474037 for (auto &EI : FS->calls()) {
28902890 }
28912891
28922892 void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) {
2893 Out << ", varFlags: (readonly: " << GS->VarFlags.MaybeReadOnly << ", "
2894 << "writeonly: " << GS->VarFlags.MaybeWriteOnly << ")";
2893 Out << ", varFlags: (readonly: " << GS->VarFlags.ReadOnly << ")";
28952894
28962895 auto VTableFuncs = GS->vTableFuncs();
28972896 if (!VTableFuncs.empty()) {
31013100 Out << FS;
31023101 if (Ref.isReadOnly())
31033102 Out << "readonly ";
3104 else if (Ref.isWriteOnly())
3105 Out << "writeonly ";
31063103 Out << "^" << Machine.getGUIDSlot(Ref.getGUID());
31073104 }
31083105 Out << ")";
2222
2323 STATISTIC(ReadOnlyLiveGVars,
2424 "Number of live global variables marked read only");
25 STATISTIC(WriteOnlyLiveGVars,
26 "Number of live global variables marked write only");
2725
2826 FunctionSummary FunctionSummary::ExternalNode =
2927 FunctionSummary::makeDummyFunctionSummary({});
4644 });
4745 }
4846
49 // Gets the number of readonly and writeonly refs in RefEdgeList
50 std::pair FunctionSummary::specialRefCounts() const {
51 // Here we take advantage of having all readonly and writeonly references
47 // Gets the number of immutable refs in RefEdgeList
48 unsigned FunctionSummary::immutableRefCount() const {
49 // Here we take advantage of having all readonly references
5250 // located in the end of the RefEdgeList.
5351 auto Refs = refs();
54 unsigned RORefCnt = 0, WORefCnt = 0;
55 int I;
56 for (I = Refs.size() - 1; I >= 0 && Refs[I].isWriteOnly(); --I)
57 WORefCnt++;
58 for (; I >= 0 && Refs[I].isReadOnly(); --I)
59 RORefCnt++;
60 return {RORefCnt, WORefCnt};
52 unsigned ImmutableRefCnt = 0;
53 for (int I = Refs.size() - 1; I >= 0 && Refs[I].isReadOnly(); --I)
54 ImmutableRefCnt++;
55 return ImmutableRefCnt;
6156 }
6257
6358 // Collect for the given module the list of function it defines
10398 return false;
10499 }
105100
106 static void propagateAttributesToRefs(GlobalValueSummary *S) {
107 // If reference is not readonly or writeonly then referenced summary is not
108 // read/writeonly either. Note that:
101 static void propagateConstantsToRefs(GlobalValueSummary *S) {
102 // If reference is not readonly then referenced summary is not
103 // readonly either. Note that:
109104 // - All references from GlobalVarSummary are conservatively considered as
110 // not readonly or writeonly. Tracking them properly requires more complex
111 // analysis then we have now.
105 // not readonly. Tracking them properly requires more complex analysis
106 // then we have now.
112107 //
113108 // - AliasSummary objects have no refs at all so this function is a no-op
114109 // for them.
115110 for (auto &VI : S->refs()) {
116 assert(VI.getAccessSpecifier() == 0 || isa(S));
111 if (VI.isReadOnly()) {
112 // We only mark refs as readonly when computing function summaries on
113 // analysis phase.
114 assert(isa(S));
115 continue;
116 }
117117 for (auto &Ref : VI.getSummaryList())
118 // If references to alias is not read/writeonly then aliasee
119 // is not read/writeonly
120 if (auto *GVS = dyn_cast(Ref->getBaseObject())) {
121 if (!VI.isReadOnly())
122 GVS->setReadOnly(false);
123 if (!VI.isWriteOnly())
124 GVS->setWriteOnly(false);
125 }
126 }
127 }
128
129 // Do the access attribute propagation in combined index.
130 // The goal of attribute propagation is internalization of readonly (RO)
131 // or writeonly (WO) variables. To determine which variables are RO or WO
132 // and which are not we take following steps:
133 // - During analysis we speculatively assign readonly and writeonly
134 // attribute to all variables which can be internalized. When computing
135 // function summary we also assign readonly or writeonly attribute to a
136 // reference if function doesn't modify referenced variable (readonly)
137 // or doesn't read it (writeonly).
138 //
139 // - After computing dead symbols in combined index we do the attribute
140 // propagation. During this step we:
141 // a. clear RO and WO attributes from variables which are preserved or
142 // can't be imported
143 // b. clear RO and WO attributes from variables referenced by any global
144 // variable initializer
145 // c. clear RO attribute from variable referenced by a function when
146 // reference is not readonly
147 // d. clear WO attribute from variable referenced by a function when
148 // reference is not writeonly
149 //
150 // Because of (c, d) we don't internalize variables read by function A
151 // and modified by function B.
118 // If references to alias is not readonly then aliasee is not readonly
119 if (auto *GVS = dyn_cast(Ref->getBaseObject()))
120 GVS->setReadOnly(false);
121 }
122 }
123
124 // Do the constant propagation in combined index.
125 // The goal of constant propagation is internalization of readonly
126 // variables. To determine which variables are readonly and which
127 // are not we take following steps:
128 // - During analysis we speculatively assign readonly attribute to
129 // all variables which can be internalized. When computing function
130 // summary we also assign readonly attribute to a reference if
131 // function doesn't modify referenced variable.
132 //
133 // - After computing dead symbols in combined index we do the constant
134 // propagation. During this step we clear readonly attribute from
135 // all variables which:
136 // a. are preserved or can't be imported
137 // b. referenced by any global variable initializer
138 // c. referenced by a function and reference is not readonly
152139 //
153140 // Internalization itself happens in the backend after import is finished
154 // See internalizeGVsAfterImport.
155 void ModuleSummaryIndex::propagateAttributes(
141 // See internalizeImmutableGVs.
142 void ModuleSummaryIndex::propagateConstants(
156143 const DenseSet &GUIDPreservedSymbols) {
157144 for (auto &P : *this)
158145 for (auto &S : P.second.SummaryList) {
160147 // We don't examine references from dead objects
161148 continue;
162149
163 // Global variable can't be marked read/writeonly if it is not eligible
164 // to import since we need to ensure that all external references get
165 // a local (imported) copy. It also can't be marked read/writeonly if
166 // it or any alias (since alias points to the same memory) are preserved
167 // or notEligibleToImport, since either of those means there could be
168 // writes (or reads in case of writeonly) that are not visible (because
169 // preserved means it could have external to DSO writes or reads, and
170 // notEligibleToImport means it could have writes or reads via inline
171 // assembly leading it to be in the @llvm.*used).
150 // Global variable can't be marked read only if it is not eligible
151 // to import since we need to ensure that all external references
152 // get a local (imported) copy. It also can't be marked read only
153 // if it or any alias (since alias points to the same memory) are
154 // preserved or notEligibleToImport, since either of those means
155 // there could be writes that are not visible (because preserved
156 // means it could have external to DSO writes, and notEligibleToImport
157 // means it could have writes via inline assembly leading it to be
158 // in the @llvm.*used).
172159 if (auto *GVS = dyn_cast(S->getBaseObject()))
173160 // Here we intentionally pass S.get() not GVS, because S could be
174161 // an alias.
175 if (!canImportGlobalVar(S.get()) ||
176 GUIDPreservedSymbols.count(P.first)) {
162 if (!canImportGlobalVar(S.get()) || GUIDPreservedSymbols.count(P.first))
177163 GVS->setReadOnly(false);
178 GVS->setWriteOnly(false);
179 }
180 propagateAttributesToRefs(S.get());
164 propagateConstantsToRefs(S.get());
181165 }
182166 if (llvm::AreStatisticsEnabled())
183167 for (auto &P : *this)
184168 if (P.second.SummaryList.size())
185169 if (auto *GVS = dyn_cast(
186170 P.second.SummaryList[0]->getBaseObject()))
187 if (isGlobalValueLive(GVS)) {
188 if (GVS->maybeReadOnly())
189 ReadOnlyLiveGVars++;
190 if (GVS->maybeWriteOnly())
191 WriteOnlyLiveGVars++;
192 }
171 if (isGlobalValueLive(GVS) && GVS->isReadOnly())
172 ReadOnlyLiveGVars++;
193173 }
194174
195175 // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
352332
353333 static bool hasReadOnlyFlag(const GlobalValueSummary *S) {
354334 if (auto *GVS = dyn_cast(S))
355 return GVS->maybeReadOnly();
356 return false;
357 }
358
359 static bool hasWriteOnlyFlag(const GlobalValueSummary *S) {
360 if (auto *GVS = dyn_cast(S))
361 return GVS->maybeWriteOnly();
335 return GVS->isReadOnly();
362336 return false;
363337 }
364338
383357 // 0 - alias
384358 // 1 - reference
385359 // 2 - constant reference
386 // 3 - writeonly reference
387 // Other value: (hotness - 4).
388 TypeOrHotness += 4;
360 // Other value: (hotness - 3).
361 TypeOrHotness += 3;
389362 static const char *EdgeAttrs[] = {
390363 " [style=dotted]; // alias",
391364 " [style=dashed]; // ref",
392365 " [style=dashed,color=forestgreen]; // const-ref",
393 " [style=dashed,color=violetred]; // writeOnly-ref",
394366 " // call (hotness : Unknown)",
395367 " [color=blue]; // call (hotness : Cold)",
396368 " // call (hotness : None)",
435407 A.add("shape", "Mrecord", "variable");
436408 if (Flags.Live && hasReadOnlyFlag(SummaryIt.second))
437409 A.addComment("immutable");
438 if (Flags.Live && hasWriteOnlyFlag(SummaryIt.second))
439 A.addComment("writeOnly");
440410 }
441411 if (Flags.DSOLocal)
442412 A.addComment("dsoLocal");
458428 for (auto &SummaryIt : GVSMap) {
459429 auto *GVS = SummaryIt.second;
460430 for (auto &R : GVS->refs())
461 Draw(SummaryIt.first, R.getGUID(),
462 R.isWriteOnly() ? -1 : (R.isReadOnly() ? -2 : -3));
431 Draw(SummaryIt.first, R.getGUID(), R.isReadOnly() ? -1 : -2);
463432
464433 if (auto *AS = dyn_cast_or_null(SummaryIt.second)) {
465 Draw(SummaryIt.first, AS->getAliaseeGUID(), -4);
434 Draw(SummaryIt.first, AS->getAliaseeGUID(), -3);
466435 continue;
467436 }
468437
191191 AddUnsigned(VI.isDSOLocal());
192192 AddUsedCfiGlobal(VI.getGUID());
193193 }
194 if (auto *GVS = dyn_cast(GS)) {
195 AddUnsigned(GVS->maybeReadOnly());
196 AddUnsigned(GVS->maybeWriteOnly());
197 }
194 if (auto *GVS = dyn_cast(GS))
195 AddUnsigned(GVS->isReadOnly());
198196 if (auto *FS = dyn_cast(GS)) {
199197 for (auto &TT : FS->type_tests())
200198 UsedTypeIds.insert(TT);
372370 GUIDPreservedSymbols);
373371 }
374372
375 static bool isWeakObjectWithRWAccess(GlobalValueSummary *GVS) {
373 static bool isWeakWriteableObject(GlobalValueSummary *GVS) {
376374 if (auto *VarSummary = dyn_cast(GVS->getBaseObject()))
377 return !VarSummary->maybeReadOnly() && !VarSummary->maybeWriteOnly() &&
375 return !VarSummary->isReadOnly() &&
378376 (VarSummary->linkage() == GlobalValue::WeakODRLinkage ||
379377 VarSummary->linkage() == GlobalValue::LinkOnceODRLinkage);
380378 return false;
395393 // We can't internalize available_externally globals because this
396394 // can break function pointer equality.
397395 S->linkage() != GlobalValue::AvailableExternallyLinkage &&
398 // Functions and read-only variables with linkonce_odr and
399 // weak_odr linkage can be internalized. We can't internalize
400 // linkonce_odr and weak_odr variables which are both modified
401 // and read somewhere in the program because reads and writes
402 // will become inconsistent.
403 !isWeakObjectWithRWAccess(S.get()))
396 // Functions and read-only variables with linkonce_odr and weak_odr
397 // linkage can be internalized. We can't internalize linkonce_odr
398 // and weak_odr variables which are modified somewhere in the
399 // program because reads and writes will become inconsistent.
400 !isWeakWriteableObject(S.get()))
404401 S->setLinkage(GlobalValue::InternalLinkage);
405402 }
406403 }
849849 bool ImportEnabled) {
850850 computeDeadSymbols(Index, GUIDPreservedSymbols, isPrevailing);
851851 if (ImportEnabled) {
852 Index.propagateAttributes(GUIDPreservedSymbols);
852 Index.propagateConstants(GUIDPreservedSymbols);
853853 } else {
854 // If import is disabled we should drop read/write-only attribute
854 // If import is disabled we should drop read-only attribute
855855 // from all summaries to prevent internalization.
856856 for (auto &P : Index)
857857 for (auto &S : P.second.SummaryList)
858 if (auto *GVS = dyn_cast(S.get())) {
858 if (auto *GVS = dyn_cast(S.get()))
859859 GVS->setReadOnly(false);
860 GVS->setWriteOnly(false);
861 }
862860 }
863861 }
864862
10651063
10661064 // Internalize values that we marked with specific attribute
10671065 // in processGlobalForThinLTO.
1068 static void internalizeGVsAfterImport(Module &M) {
1066 static void internalizeImmutableGVs(Module &M) {
10691067 for (auto &GV : M.globals())
10701068 // Skip GVs which have been converted to declarations
10711069 // by dropDeadSymbols.
11981196 NumImportedModules++;
11991197 }
12001198
1201 internalizeGVsAfterImport(DestModule);
1199 internalizeImmutableGVs(DestModule);
12021200
12031201 NumImportedFunctions += (ImportedCount - ImportedGVCount);
12041202 NumImportedGlobalVars += ImportedGVCount;
228228 }
229229 }
230230
231 // Mark read/write-only variables which can be imported with specific
232 // attribute. We can't internalize them now because IRMover will fail
233 // to link variable definitions to their external declarations during
234 // ThinLTO import. We'll internalize read-only variables later, after
235 // import is finished. See internalizeGVsAfterImport.
231 // Mark read-only variables which can be imported with specific attribute.
232 // We can't internalize them now because IRMover will fail to link variable
233 // definitions to their external declarations during ThinLTO import. We'll
234 // internalize read-only variables later, after import is finished.
235 // See internalizeImmutableGVs.
236236 //
237237 // If global value dead stripping is not enabled in summary then
238238 // propagateConstants hasn't been run. We can't internalize GV
240240 if (!GV.isDeclaration() && VI && ImportIndex.withGlobalValueDeadStripping()) {
241241 const auto &SL = VI.getSummaryList();
242242 auto *GVS = SL.empty() ? nullptr : dyn_cast(SL[0].get());
243 // At this stage "maybe" is "definitely"
244 if (GVS && (GVS->maybeReadOnly() || GVS->maybeWriteOnly()))
243 if (GVS && GVS->isReadOnly())
245244 cast(&GV)->addAttribute("thinlto-internalize");
246245 }
247246
88 ; Check a function that makes several calls with various profile hotness, and a
99 ; reference (also tests forward references to function and variables in calls
1010 ; and refs).
11 ^2 = gv: (guid: 1, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 10, calls: ((callee: ^15, hotness: hot), (callee: ^17, hotness: cold), (callee: ^16, hotness: none)), refs: (writeonly ^14, readonly ^13, ^11))))
11 ^2 = gv: (guid: 1, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 10, calls: ((callee: ^15, hotness: hot), (callee: ^17, hotness: cold), (callee: ^16, hotness: none)), refs: (readonly ^13, ^14))))
1212
1313 ; Function with a call that has relative block frequency instead of profile
1414 ; hotness.
3232 ^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 1))))
3333
3434 ; Test a dsoLocal variable.
35 ^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1), varFlags: (writeonly: 0))))
35 ^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1), varFlags: (readonly: 0))))
3636
3737 ; Functions with various flag combinations (notEligibleToImport, Live,
3838 ; combinations of optional function flags).
6666 ; Make sure we get back from llvm-dis essentially what we put in via llvm-as.
6767 ; CHECK: ^0 = module: (path: "thinlto-summary1.o", hash: (1369602428, 2747878711, 259090915, 2507395659, 1141468049))
6868 ; CHECK: ^1 = module: (path: "thinlto-summary2.o", hash: (2998369023, 4283347029, 1195487472, 2757298015, 1852134156))
69 ; CHECK: ^2 = gv: (guid: 1, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 10, calls: ((callee: ^15, hotness: hot), (callee: ^17, hotness: cold), (callee: ^16, hotness: none)), refs: (^11, readonly ^13, writeonly ^14))))
69 ; CHECK: ^2 = gv: (guid: 1, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 10, calls: ((callee: ^15, hotness: hot), (callee: ^17, hotness: cold), (callee: ^16, hotness: none)), refs: (^14, readonly ^13))))
7070 ; CHECK: ^3 = gv: (guid: 2, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 10, calls: ((callee: ^15)))))
7171 ; CHECK: ^4 = gv: (guid: 3, summaries: (function: (module: ^0, flags: (linkage: internal, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 1)))
7272 ; CHECK: ^5 = gv: (guid: 4, summaries: (alias: (module: ^0, flags: (linkage: private, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), aliasee: ^14)))
7575 ; CHECK: ^8 = gv: (guid: 7, summaries: (function: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1)))
7676 ; CHECK: ^9 = gv: (guid: 8, summaries: (function: (module: ^0, flags: (linkage: weak_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 1), insts: 1)))
7777 ; CHECK: ^10 = gv: (guid: 9, summaries: (function: (module: ^0, flags: (linkage: weak, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1)))
78 ; CHECK: ^11 = gv: (guid: 10, summaries: (variable: (module: ^0, flags: (linkage: common, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0))))
79 ; CHECK: ^12 = gv: (guid: 11, summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^4))))
80 ; CHECK: ^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 0))))
81 ; CHECK: ^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0))))
78 ; CHECK: ^11 = gv: (guid: 10, summaries: (variable: (module: ^0, flags: (linkage: common, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0))))
79 ; CHECK: ^12 = gv: (guid: 11, summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0), refs: (^4))))
80 ; CHECK: ^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1))))
81 ; CHECK: ^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0))))
8282 ; CHECK: ^15 = gv: (guid: 14, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 1, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 1)))
8383 ; CHECK: ^16 = gv: (guid: 15, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 1, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0))))
8484 ; CHECK: ^17 = gv: (guid: 16, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 1, noRecurse: 0, returnDoesNotAlias: 1, noInline: 0), calls: ((callee: ^15)))))
2828
2929 ^0 = module: (path: "", hash: (0, 0, 0, 0, 0))
3030 ^1 = gv: (name: "_ZN1A1nEi") ; guid = 1621563287929432257
31 ^2 = gv: (name: "_ZTV1B", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), vTableFuncs: ((virtFunc: ^3, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^3, ^1)))) ; guid = 5283576821522790367
31 ^2 = gv: (name: "_ZTV1B", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0), vTableFuncs: ((virtFunc: ^3, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^3, ^1)))) ; guid = 5283576821522790367
3232 ^3 = gv: (name: "_ZN1B1fEi") ; guid = 7162046368816414394
33 ^4 = gv: (name: "_ZTV1C", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), vTableFuncs: ((virtFunc: ^5, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^1, ^5)))) ; guid = 13624023785555846296
33 ^4 = gv: (name: "_ZTV1C", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0), vTableFuncs: ((virtFunc: ^5, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^1, ^5)))) ; guid = 13624023785555846296
3434 ^5 = gv: (name: "_ZN1C1fEi") ; guid = 14876272565662207556
3535 ^6 = typeidCompatibleVTable: (name: "_ZTS1A", summary: ((offset: 16, ^2), (offset: 16, ^4))) ; guid = 7004155349499253778
3636 ^7 = typeidCompatibleVTable: (name: "_ZTS1B", summary: ((offset: 16, ^2))) ; guid = 6203814149063363976
11 ; RUN: opt -module-summary %s -o - | llvm-bcanalyzer -dump | FileCheck %s
22
33 ; CHECK:
4 ; CHECK: 7/>
4 ; CHECK: 6/>
55
66
77
2020 ; CHECK-NEXT:
2121 ; See if the call to func is registered.
2222 ; The value id 1 matches the second FUNCTION record above.
23 ; CHECK-NEXT: 7=1/>
23 ; CHECK-NEXT: 6=1/>
2424 ; CHECK-NEXT:
2525
2626 ; CHECK:
3333 ; COMBINED-NEXT:
3434 ; COMBINED-NEXT:
3535 ; COMBINED-NEXT:
36 ; COMBINED-NEXT: 9=[[ALIASID]]/>
36 ; COMBINED-NEXT: 8=[[ALIASID]]/>
3737 ; COMBINED-NEXT:
3838 ; COMBINED-NEXT:
3939 ; COMBINED-NEXT:
44 ; CHECK:
55 ; CHECK-NEXT:
66 ; CHECK-NEXT:
7 ; CHECK-NEXT: 0 op7=[[ALIASID:[0-9]+]]/>
7 ; CHECK-NEXT: [[ALIASID:[0-9]+]]/>
88 ; CHECK-NEXT:
99 ; CHECK-NEXT:
1010 ; CHECK-NEXT:
66 ; CHECK-NEXT:
77 ; CHECK-NEXT:
88 ; "op7" is a call to "callee" function.
9 ; CHECK-NEXT: 9=3 op10=[[ALIASID:[0-9]+]]/>
9 ; CHECK-NEXT: 8=3 op9=[[ALIASID:[0-9]+]]/>
1010 ; "another_caller" has only references but no calls.
11 ; CHECK-NEXT: 9={{[0-9]+}}/>
11 ; CHECK-NEXT: 8={{[0-9]+}}/>
1212 ; CHECK-NEXT:
1313 ; CHECK-NEXT:
1414 ; CHECK-NEXT:
1717 ; CHECK-NEXT:
1818 ; CHECK-NEXT:
1919 ; See if the call to func is registered, using the expected hotness type.
20 ; CHECK-NEXT: 7=1 op8=2/>
20 ; CHECK-NEXT: 6=1 op7=2/>
2121 ; CHECK-NEXT:
2222 ; CHECK:
2323 ; CHECK-NEXT: blob data = 'mainfunc{{.*}}'
3030 ; COMBINED-NEXT:
3131 ; See if the call to func is registered, using the expected hotness type.
3232 ; op6=2 which is hotnessType::None.
33 ; COMBINED-NEXT: 9=[[FUNCID]] op10=2/>
33 ; COMBINED-NEXT: 8=[[FUNCID]] op9=2/>
3434 ; COMBINED-NEXT:
3535
3636 ; ModuleID = 'thinlto-function-summary-callgraph.ll'
4848 ; CHECK-NEXT:
4949 ; CHECK-NEXT:
5050 ; op4=hot1 op6=cold op8=hot2 op10=hot4 op12=none1 op14=hot3 op16=none2 op18=none3 op20=123
51 ; CHECK-NEXT: 7=1 op8=3 op9=5 op10=1 op11=2 op12=3 op13=4 op14=1 op15=6 op16=2 op17=3 op18=3 op19=7 op20=2 op21=8 op22=2 op23=25 op24=4/>
51 ; 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/>
5252 ; CHECK-NEXT:
5353
5454 ; CHECK:
7171 ; COMBINED-NEXT:
7272 ; COMBINED-NEXT:
7373 ; COMBINED-NEXT:
74 ; COMBINED-NEXT: 9=[[HOT1:.*]] op10=3 op11=[[COLD:.*]] op12=1 op13=[[HOT2:.*]] op14=3 op15=[[NONE1:.*]] op16=2 op17=[[HOT3:.*]] op18=3 op19=[[NONE2:.*]] op20=2 op21=[[NONE3:.*]] op22=2/>
74 ; COMBINED-NEXT: 8=[[HOT1:.*]] op9=3 op10=[[COLD:.*]] op11=1 op12=[[HOT2:.*]] op13=3 op14=[[NONE1:.*]] op15=2 op16=[[HOT3:.*]] op17=3 op18=[[NONE2:.*]] op19=2 op20=[[NONE3:.*]] op21=2/>
7575 ; COMBINED_NEXT:
7676 ; COMBINED_NEXT:
7777
1313 ; CHECK-NEXT:
1414 ; CHECK-NEXT:
1515 ; See if the call to func is registered.
16 ; CHECK-NEXT: 9=256
16 ; CHECK-NEXT: 8=256
1717 ; CHECK-NEXT:
1818 ; CHECK:
1919 ; CHECK-NEXT: blob data = 'undefinedglobmainfunc{{.*}}'
3131 ; CHECK-NEXT:
3232 ; CHECK-NEXT:
3333 ; op4=none1 op6=hot1 op8=cold1 op10=none2 op12=hot2 op14=cold2 op16=none3 op18=hot3 op20=cold3 op22=123
34 ; CHECK-NEXT: 7=7 op8=0 op9=1 op10=3 op11=4 op12=1 op13=8 op14=0 op15=2 op16=3 op17=5 op18=1 op19=9 op20=0 op21=3 op22=3 op23=6 op24=1 op25=26 op26=4/>
34 ; 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/>
3535 ; CHECK-NEXT:
3636
3737 ; CHECK:
5858 ; COMBINED-NEXT:
5959 ; COMBINED-NEXT:
6060 ; COMBINED-NEXT:
61 ; COMBINED-NEXT: 9=[[NONE1:.*]] op10=0 op11=[[HOT1:.*]] op12=3 op13=[[COLD1:.*]] op14=1 op15=[[NONE2:.*]] op16=0 op17=[[HOT2:.*]] op18=3 op19=[[COLD2:.*]] op20=1 op21=[[NONE3:.*]] op22=0 op23=[[HOT3:.*]] op24=3 op25=[[COLD3:.*]] op26=1/>
61 ; COMBINED-NEXT: 8=[[NONE1:.*]] op9=0 op10=[[HOT1:.*]] op11=3 op12=[[COLD1:.*]] op13=1 op14=[[NONE2:.*]] op15=0 op16=[[HOT2:.*]] op17=3 op18=[[COLD2:.*]] op19=1 op20=[[NONE3:.*]] op21=0 op22=[[HOT3:.*]] op23=3 op24=[[COLD3:.*]] op25=1/>
6262 ; COMBINED_NEXT:
6363 ; COMBINED_NEXT:
6464
3333 ; COMBINED-NEXT:
3434 ; COMBINED-NEXT:
3535 ; See if the call to func is registered.
36 ; COMBINED-NEXT: 9=[[FUNCID]]/>
36 ; COMBINED-NEXT: 8=[[FUNCID]]/>
3737 ; COMBINED-NEXT:
3838
3939 ; 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: 0 op7=2 op8=2/>
43 ; CHECK-DAG: 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: 0 op7=1 op8=5/>
46 ; CHECK-DAG: 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: 0 op7=4 op8=4/>
50 ; CHECK-DAG: 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: 0 op7=3/>
55 ; CHECK-DAG: 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: 0 op7=3/>
60 ; CHECK-DAG: 3/>
6161 ; Variable bar initialization contains address reference to func:
6262 ; op0=bar op2=func
63 ; CHECK-DAG: 3 op3=2/>
63 ; CHECK-DAG: 1 op3=2/>
6464 ; CHECK:
6565
6666 ; CHECK:
153153 ; DIS-DAG: = gv: (name: "foo") ; guid = 6699318081062747564
154154 ; DIS-DAG: = gv: (name: "func") ; guid = 7289175272376759421
155155 ; DIS-DAG: = gv: (name: "func3") ; guid = 11517462787082255043
156 ; DIS-DAG: = gv: (name: "globalvar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1)))) ; guid = 12887606300320728018
156 ; DIS-DAG: = gv: (name: "globalvar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1)))) ; guid = 12887606300320728018
157157 ; DIS-DAG: = gv: (name: "func2") ; guid = 14069196320850861797
158158 ; DIS-DAG: = gv: (name: "llvm.ctpop.i8") ; guid = 15254915475081819833
159159 ; DIS-DAG: = gv: (name: "main", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 9, calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) ; guid = 15822663052811949562
160 ; DIS-DAG: = gv: (name: "bar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1), refs: (^{{.*}})))) ; guid = 16434608426314478903
160 ; DIS-DAG: = gv: (name: "bar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1), refs: (^{{.*}})))) ; guid = 16434608426314478903
161161 ; Don't try to match the exact GUID. Since it is private, the file path
162162 ; will get hashed, and that will be test dependent.
163163 ; DIS-DAG: = gv: (name: "Y", summaries: (function: (module: ^0, flags: (linkage: private, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 14, calls: ((callee: ^{{.*}}))))) ; guid =
+0
-4
test/ThinLTO/X86/Inputs/dot-dumper2.ll less more
None target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 @A = local_unnamed_addr global i32 10, align 4
+0
-43
test/ThinLTO/X86/dot-dumper2.ll less more
None ; Test writeOnly attribute
1 ; RUN: opt -module-summary %s -o %t1.bc
2 ; RUN: opt -module-summary %p/Inputs/dot-dumper2.ll -o %t2.bc
3 ; RUN: llvm-lto2 run -save-temps %t1.bc %t2.bc -o %t3 \
4 ; RUN: -r=%t1.bc,main,px \
5 ; RUN: -r=%t1.bc,A, \
6 ; RUN: -r=%t2.bc,A,p
7
8 ; RUN: cat %t3.index.dot | FileCheck --check-prefix=COMBINED %s
9
10 ; COMBINED: digraph Summary {
11 ; COMBINED-NEXT: // Module:
12 ; COMBINED-NEXT: subgraph cluster_0 {
13 ; COMBINED-NEXT: style = filled;
14 ; COMBINED-NEXT: color = lightgrey;
15 ; COMBINED-NEXT: label =
16 ; COMBINED-NEXT: node [style=filled,fillcolor=lightblue];
17 ; COMBINED-NEXT: M0_[[MAIN:[0-9]+]] [shape="record",label="main|extern (inst: 2, ffl: 00000)}"]; // function
18 ; COMBINED-NEXT: // Edges:
19 ; COMBINED-NEXT: }
20 ; COMBINED-NEXT: // Module:
21 ; COMBINED-NEXT: subgraph cluster_1 {
22 ; COMBINED-NEXT: style = filled;
23 ; COMBINED-NEXT: color = lightgrey;
24 ; COMBINED-NEXT: label =
25 ; COMBINED-NEXT: node [style=filled,fillcolor=lightblue];
26 ; COMBINED-NEXT: M1_[[A:[0-9]+]] [shape="Mrecord",label="A|extern}"]; // variable, writeOnly
27 ; COMBINED-NEXT: // Edges:
28 ; COMBINED-NEXT: }
29 ; COMBINED-NEXT: // Cross-module edges:
30 ; COMBINED-NEXT: M0_[[MAIN]] -> M1_[[A]] [style=dashed,color=violetred]; // writeOnly-ref
31 ; COMBINED-NEXT: }
32
33 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
34 target triple = "x86_64-unknown-linux-gnu"
35
36 @A = external local_unnamed_addr global i32, align 4
37
38 ; Function Attrs: nounwind uwtable
39 define i32 @main() local_unnamed_addr {
40 store i32 42, i32* @A, align 4
41 ret i32 0
42 }
1010 ; RUN: -r=%t2.bc,rand, \
1111 ; RUN: -r=%t2.bc,gBar,pl \
1212 ; RUN: -r=%t1.bc,main,plx \
13 ; RUN: -r=%t1.bc,main2,pl \
1413 ; RUN: -r=%t1.bc,foo, \
1514 ; RUN: -r=%t1.bc,bar, \
16 ; RUN: -r=%t1.bc,baz, \
1715 ; RUN: -r=%t1.bc,gBar, \
1816 ; RUN: -o %t3
1917 ; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT
2725 ; RUN: -r=%t2.bc,rand, \
2826 ; RUN: -r=%t2.bc,gBar,plx \
2927 ; RUN: -r=%t1.bc,main,plx \
30 ; RUN: -r=%t1.bc,main2,pl \
3128 ; RUN: -r=%t1.bc,foo, \
3229 ; RUN: -r=%t1.bc,bar, \
33 ; RUN: -r=%t1.bc,baz, \
3430 ; RUN: -r=%t1.bc,gBar, \
35 ; RUN: -o %t4
36 ; RUN: llvm-dis %t4.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT2
37
38 ; RUN: llvm-lto2 run %t1.bc %t2.bc -save-temps \
39 ; RUN: -r=%t2.bc,foo,pl \
40 ; RUN: -r=%t2.bc,bar,pl \
41 ; RUN: -r=%t2.bc,baz,pl \
42 ; RUN: -r=%t2.bc,rand, \
43 ; RUN: -r=%t2.bc,gBar,pl \
44 ; RUN: -r=%t1.bc,main,pl \
45 ; RUN: -r=%t1.bc,main2,plx \
46 ; RUN: -r=%t1.bc,foo, \
47 ; RUN: -r=%t1.bc,bar, \
48 ; RUN: -r=%t1.bc,baz, \
49 ; RUN: -r=%t1.bc,gBar, \
50 ; RUN: -o %t5
51 ; RUN: llvm-dis %t5.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT
52 ; RUN: llvm-dis %t5.1.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN2
53 ; Check that gFoo and gBar were eliminated from source module together
54 ; with corresponsing stores
55 ; RUN: llvm-dis %t5.2.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN2-SRC
31 ; RUN: -o %t3
32 ; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT2
5633
5734 ; IMPORT: @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4
5835 ; IMPORT-NEXT: @gBar = internal local_unnamed_addr global i32 2, align 4
6239 ; CODEGEN-NEXT: ret i32 3
6340
6441 ; IMPORT2: @gBar = available_externally dso_local local_unnamed_addr global i32 2, align 4
65
66 ; CODEGEN2: i32 @main2
67 ; CODEGEN2-NEXT: %1 = tail call i32 @rand()
68 ; CODEGEN2-NEXT: %2 = tail call i32 @rand()
69 ; CODEGEN2-NEXT: ret i32 0
70
71 ; CODEGEN2-SRC: void @baz()
72 ; CODEGEN2-SRC-NEXT: %1 = tail call i32 @rand()
73 ; CODEGEN2-SRC-NEXT: %2 = tail call i32 @rand()
74 ; CODEGEN2-SRC-NEXT: ret void
7542
7643 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7744 target triple = "x86_64-pc-linux-gnu"
8653 ret i32 %add
8754 }
8855
89 define i32 @main2() local_unnamed_addr {
90 tail call void @baz()
91 ret i32 0
92 }
93
9456 declare i32 @foo(...) local_unnamed_addr
9557
9658 declare i32 @bar(...) local_unnamed_addr
97
98 declare void @baz() local_unnamed_addr
+0
-26
test/ThinLTO/X86/load-store-caching.ll less more
None ; Test that instruction operands from loads are not cached when
1 ; processing stores. Reference from @foo to @obj should not be
2 ; readonly or writeonly
3
4 ; RUN: opt -module-summary %s -o %t.bc
5 ; RUN: llvm-dis %t.bc -o - | FileCheck %s
6
7 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
8 target triple = "x86_64-unknown-linux-gnu"
9
10 %struct.S = type { %struct.Derived* }
11 %struct.Derived = type { i32 }
12 %struct.Base = type { i32 }
13
14 @obj = dso_local local_unnamed_addr global %struct.S zeroinitializer, align 8
15
16 define dso_local %struct.Base* @foo() local_unnamed_addr {
17 entry:
18 %0 = load %struct.Base*, %struct.Base** bitcast (%struct.S* @obj to %struct.Base**), align 8
19 store %struct.Base* null, %struct.Base** bitcast (%struct.S* @obj to %struct.Base**), align 8
20 ret %struct.Base* %0
21 }
22
23 ; CHECK: ^0 = module:
24 ; CHECK-NEXT: ^1 = gv: (name: "obj", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1)))) ; guid =
25 ; CHECK-NEXT: ^2 = gv: (name: "foo", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 3, refs: (^1)))) ; guid =
+0
-41
test/ThinLTO/X86/writeonly.ll less more
None ; Checks that we optimize writeonly variables and corresponding stores using llvm-lto
1 ; -stats requires asserts
2 ; REQUIRES: asserts
3
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-lto -thinlto-action=thinlink -o %t3.index.bc %t1.bc %t2.bc
7
8 ; Check that we optimize write-only variables
9 ; RUN: llvm-lto -thinlto-action=import -exported-symbol=main %t1.bc -thinlto-index=%t3.index.bc -o %t1.imported.bc -stats 2>&1 | FileCheck %s --check-prefix=STATS
10 ; RUN: llvm-dis %t1.imported.bc -o - | FileCheck %s --check-prefix=IMPORT
11 ; RUN: llvm-lto -thinlto-action=optimize %t1.imported.bc -o - | llvm-dis - -o - | FileCheck %s --check-prefix=OPTIMIZE
12
13 ; IMPORT: @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4, !dbg !0
14 ; IMPORT-NEXT: @gBar = internal local_unnamed_addr global i32 2, align 4, !dbg !5
15 ; IMPORT: !DICompileUnit({{.*}})
16
17 ; STATS: 2 module-summary-index - Number of live global variables marked write only
18
19 ; Check that we've optimized out variables and corresponding stores
20 ; OPTIMIZE-NOT: gFoo
21 ; OPTIMIZE-NOT: gBar
22 ; OPTIMIZE: i32 @main
23 ; OPTIMIZE-NEXT: %1 = tail call i32 @rand()
24 ; OPTIMIZE-NEXT: %2 = tail call i32 @rand()
25 ; OPTIMIZE-NEXT: ret i32 0
26
27 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
28 target triple = "x86_64-pc-linux-gnu"
29
30 @gBar = external global i32
31
32 ; Should not be counted in the stats of live write only variables since it is
33 ; dead and will be dropped anyway.
34 @gDead = internal unnamed_addr global i32 1, align 4
35
36 define i32 @main() local_unnamed_addr {
37 tail call void @baz()
38 ret i32 0
39 }
40 declare void @baz() local_unnamed_addr
+0
-50
test/ThinLTO/X86/writeonly2.ll less more
None ; Check that we optimize out writeonly variables and corresponding stores.
1 ; This test uses llvm-lto2
2
3 ; RUN: opt -module-summary %s -o %t1.bc
4 ; RUN: opt -module-summary %p/Inputs/index-const-prop.ll -o %t2.bc
5 ; RUN: llvm-lto2 run %t1.bc %t2.bc -save-temps \
6 ; RUN: -r=%t2.bc,foo,pl \
7 ; RUN: -r=%t2.bc,bar,pl \
8 ; RUN: -r=%t2.bc,baz,pl \
9 ; RUN: -r=%t2.bc,rand, \
10 ; RUN: -r=%t2.bc,gBar,pl \
11 ; RUN: -r=%t1.bc,main,plx \
12 ; RUN: -r=%t1.bc,baz, \
13 ; RUN: -r=%t1.bc,gBar, \
14 ; RUN: -o %t3
15 ; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT
16 ; RUN: llvm-dis %t3.1.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN
17 ; Check that gFoo and gBar were eliminated from source module together
18 ; with corresponsing stores
19 ; RUN: llvm-dis %t3.2.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN-SRC
20
21 ; IMPORT: @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4
22 ; IMPORT-NEXT: @gBar = internal local_unnamed_addr global i32 2, align 4
23 ; IMPORT: !DICompileUnit({{.*}})
24
25 ; CODEGEN-NOT: gFoo
26 ; CODEGEN-NOT: gBar
27 ; CODEGEN: i32 @main
28 ; CODEGEN-NEXT: %1 = tail call i32 @rand()
29 ; CODEGEN-NEXT: %2 = tail call i32 @rand()
30 ; CODEGEN-NEXT: ret i32 0
31
32 ; CODEGEN-SRC-NOT: gFoo
33 ; CODEGEN-SRC-NOT: gBar
34 ; CODEGEN-SRC: void @baz()
35 ; CODEGEN-SRC-NEXT: %1 = tail call i32 @rand()
36 ; CODEGEN-SRC-NEXT: %2 = tail call i32 @rand()
37 ; CODEGEN-SRC-NEXT: ret void
38
39 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
40 target triple = "x86_64-pc-linux-gnu"
41
42 ; We should be able to link external definition of gBar to its declaration
43 @gBar = external global i32
44
45 define i32 @main() local_unnamed_addr {
46 tail call void @baz()
47 ret i32 0
48 }
49 declare void @baz() local_unnamed_addr