llvm.org GIT mirror llvm / 731becc
[ThinLTO] Re-commit of dot dumper after test fix git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@323116 91177308-0d34-0410-b5e6-96231b3b80d8 Eugene Leviant 2 years ago
14 changed file(s) with 440 addition(s) and 35 deletion(s). Raw diff Collapse all Expand all
6868 using GlobalValueSummaryList = std::vector>;
6969
7070 struct GlobalValueSummaryInfo {
71 /// The GlobalValue corresponding to this summary. This is only used in
72 /// per-module summaries.
73 const GlobalValue *GV = nullptr;
71 union NameOrGV {
72 NameOrGV(bool IsAnalysis) {
73 if (IsAnalysis)
74 GV = nullptr;
75 else
76 Name = "";
77 }
78
79 /// The GlobalValue corresponding to this summary. This is only used in
80 /// per-module summaries, when module analysis is being run.
81 const GlobalValue *GV;
82
83 /// Summary string representation. This StringRef points to BC module
84 /// string table and is valid until module data is stored in memory.
85 /// This is guaranteed to happen until runThinLTOBackend function is
86 /// called, so it is safe to use this field during thin link. This field
87 /// is only valid if summary index was loaded from BC file.
88 StringRef Name;
89 } U;
90
91 GlobalValueSummaryInfo(bool IsAnalysis) : U(IsAnalysis) {}
7492
7593 /// List of global value summary structures for a particular value held
7694 /// in the GlobalValueMap. Requires a vector in the case of multiple
90108 /// Struct that holds a reference to a particular GUID in a global value
91109 /// summary.
92110 struct ValueInfo {
93 const GlobalValueSummaryMapTy::value_type *Ref = nullptr;
111 PointerIntPair
112 RefAndFlag;
94113
95114 ValueInfo() = default;
96 ValueInfo(const GlobalValueSummaryMapTy::value_type *Ref) : Ref(Ref) {}
97
98 operator bool() const { return Ref; }
99
100 GlobalValue::GUID getGUID() const { return Ref->first; }
101 const GlobalValue *getValue() const { return Ref->second.GV; }
115 ValueInfo(bool IsAnalysis, const GlobalValueSummaryMapTy::value_type *R) {
116 RefAndFlag.setPointer(R);
117 RefAndFlag.setInt(IsAnalysis);
118 }
119
120 operator bool() const { return getRef(); }
121
122 GlobalValue::GUID getGUID() const { return getRef()->first; }
123 const GlobalValue *getValue() const {
124 assert(isFromAnalysis());
125 return getRef()->second.U.GV;
126 }
102127
103128 ArrayRef> getSummaryList() const {
104 return Ref->second.SummaryList;
129 return getRef()->second.SummaryList;
130 }
131
132 StringRef name() const {
133 return isFromAnalysis() ? getRef()->second.U.GV->getName()
134 : getRef()->second.U.Name;
135 }
136
137 bool isFromAnalysis() const { return RefAndFlag.getInt(); }
138
139 const GlobalValueSummaryMapTy::value_type *getRef() const {
140 return RefAndFlag.getPointer();
105141 }
106142 };
107143
108144 template <> struct DenseMapInfo {
109145 static inline ValueInfo getEmptyKey() {
110 return ValueInfo((GlobalValueSummaryMapTy::value_type *)-1);
146 return ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-8);
111147 }
112148
113149 static inline ValueInfo getTombstoneKey() {
114 return ValueInfo((GlobalValueSummaryMapTy::value_type *)-2);
115 }
116
117 static bool isEqual(ValueInfo L, ValueInfo R) { return L.Ref == R.Ref; }
118 static unsigned getHashValue(ValueInfo I) { return (uintptr_t)I.Ref; }
150 return ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-16);
151 }
152
153 static inline bool isSpecialKey(ValueInfo V) {
154 return V == getTombstoneKey() || V == getEmptyKey();
155 }
156
157 static bool isEqual(ValueInfo L, ValueInfo R) {
158 // We are not supposed to mix ValueInfo(s) with different analysis flag
159 // in a same container.
160 assert(isSpecialKey(L) || isSpecialKey(R) ||
161 (L.isFromAnalysis() == R.isFromAnalysis()));
162 return L.getRef() == R.getRef();
163 }
164 static unsigned getHashValue(ValueInfo I) { return (uintptr_t)I.getRef(); }
119165 };
120166
121167 /// \brief Function and variable summary information to aid decisions and
618664 /// considered live.
619665 bool WithGlobalValueDeadStripping = false;
620666
667 /// If true then we're performing analysis of IR module, filling summary
668 /// accordingly. The value of 'false' means we're reading summary from
669 /// BC or YAML source. Affects the type of value stored in NameOrGV union
670 bool IsAnalysis;
671
621672 std::set CfiFunctionDefs;
622673 std::set CfiFunctionDecls;
623674
626677
627678 GlobalValueSummaryMapTy::value_type *
628679 getOrInsertValuePtr(GlobalValue::GUID GUID) {
629 return &*GlobalValueMap.emplace(GUID, GlobalValueSummaryInfo{}).first;
680 return &*GlobalValueMap.emplace(GUID, GlobalValueSummaryInfo(IsAnalysis)).first;
630681 }
631682
632683 public:
684 // See IsAnalysis variable comment.
685 ModuleSummaryIndex(bool IsPerformingAnalysis)
686 : IsAnalysis(IsPerformingAnalysis) {}
687
688 bool isPerformingAnalysis() const { return IsAnalysis; }
689
633690 gvsummary_iterator begin() { return GlobalValueMap.begin(); }
634691 const_gvsummary_iterator begin() const { return GlobalValueMap.begin(); }
635692 gvsummary_iterator end() { return GlobalValueMap.end(); }
651708 /// Return a ValueInfo for GUID if it exists, otherwise return ValueInfo().
652709 ValueInfo getValueInfo(GlobalValue::GUID GUID) const {
653710 auto I = GlobalValueMap.find(GUID);
654 return ValueInfo(I == GlobalValueMap.end() ? nullptr : &*I);
711 return ValueInfo(IsAnalysis, I == GlobalValueMap.end() ? nullptr : &*I);
655712 }
656713
657714 /// Return a ValueInfo for \p GUID.
658715 ValueInfo getOrInsertValueInfo(GlobalValue::GUID GUID) {
659 return ValueInfo(getOrInsertValuePtr(GUID));
716 return ValueInfo(IsAnalysis, getOrInsertValuePtr(GUID));
717 }
718
719 /// Return a ValueInfo for \p GUID setting value \p Name.
720 ValueInfo getOrInsertValueInfo(GlobalValue::GUID GUID, StringRef Name) {
721 assert(!IsAnalysis);
722 auto VP = getOrInsertValuePtr(GUID);
723 VP->second.U.Name = Name;
724 return ValueInfo(IsAnalysis, VP);
660725 }
661726
662727 /// Return a ValueInfo for \p GV and mark it as belonging to GV.
663728 ValueInfo getOrInsertValueInfo(const GlobalValue *GV) {
729 assert(IsAnalysis);
664730 auto VP = getOrInsertValuePtr(GV->getGUID());
665 VP->second.GV = GV;
666 return ValueInfo(VP);
731 VP->second.U.GV = GV;
732 return ValueInfo(IsAnalysis, VP);
667733 }
668734
669735 /// Return the GUID for \p OriginalId in the OidGuidMap.
691757 addOriginalName(VI.getGUID(), Summary->getOriginalName());
692758 // Here we have a notionally const VI, but the value it points to is owned
693759 // by the non-const *this.
694 const_cast(VI.Ref)
760 const_cast(VI.getRef())
695761 ->second.SummaryList.push_back(std::move(Summary));
696762 }
697763
822888 /// Summary).
823889 void collectDefinedGVSummariesPerModule(
824890 StringMap &ModuleToDefinedGVSummaries) const;
891
892 /// Export summary to dot file for GraphViz.
893 void exportToDot(raw_ostream& OS) const;
825894 };
826895
827896 } // end namespace llvm
206206 io.setError("key not an integer");
207207 return;
208208 }
209 auto &Elem = V[KeyInt];
209 auto P = V.emplace(KeyInt, /*IsAnalysis=*/false);
210 auto &Elem = (*P.first).second;
210211 for (auto &FSum : FSums) {
211212 Elem.SummaryList.push_back(llvm::make_unique(
212213 GlobalValueSummary::GVFlags(
371371 std::function GetBFICallback,
372372 ProfileSummaryInfo *PSI) {
373373 assert(PSI);
374 ModuleSummaryIndex Index;
374 ModuleSummaryIndex Index(/*IsPerformingAnalysis=*/true);
375375
376376 // Identify the local values in the llvm.used and llvm.compiler.used sets,
377377 // which should not be exported as they would then require renaming and
48124812 if (PrintSummaryGUIDs)
48134813 dbgs() << "GUID " << ValueGUID << "(" << OriginalNameID << ") is "
48144814 << ValueName << "\n";
4815 ValueIdToValueInfoMap[ValueID] =
4816 std::make_pair(TheIndex.getOrInsertValueInfo(ValueGUID), OriginalNameID);
4815
4816 // UseStrtab is false for legacy summary formats and value names are
4817 // created on stack. We can't use them outside of parseValueSymbolTable.
4818 ValueIdToValueInfoMap[ValueID] = std::make_pair(
4819 TheIndex.getOrInsertValueInfo(ValueGUID, UseStrtab ? ValueName : ""),
4820 OriginalNameID);
48174821 }
48184822
48194823 // Specialized value symbol table parser used when reading module index
56785682 BitstreamCursor Stream(Buffer);
56795683 Stream.JumpToBit(ModuleBit);
56805684
5681 auto Index = llvm::make_unique();
5685 auto Index =
5686 llvm::make_unique(/*IsPerformingAnalysis=*/false);
56825687 ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, *Index,
56835688 ModuleIdentifier, 0);
56845689
1313
1414 #include "llvm/IR/ModuleSummaryIndex.h"
1515 #include "llvm/ADT/StringMap.h"
16 #include "llvm/Support/Path.h"
1617 using namespace llvm;
1718
1819 // Collect for the given module the list of function it defines
6869 return true;
6970 return false;
7071 }
72
73 namespace {
74 struct Attributes {
75 void add(const Twine &Name, const Twine &Value,
76 const Twine &Comment = Twine());
77 std::string getAsString() const;
78
79 std::vector Attrs;
80 std::string Comments;
81 };
82
83 struct Edge {
84 uint64_t SrcMod;
85 int Hotness;
86 GlobalValue::GUID Src;
87 GlobalValue::GUID Dst;
88 };
89 }
90
91 void Attributes::add(const Twine &Name, const Twine &Value,
92 const Twine &Comment) {
93 std::string A = Name.str();
94 A += "=\"";
95 A += Value.str();
96 A += "\"";
97 Attrs.push_back(A);
98 if (!Comment.isTriviallyEmpty()) {
99 if (Comments.empty())
100 Comments = " // ";
101 else
102 Comments += ", ";
103 Comments += Comment.str();
104 }
105 }
106
107 std::string Attributes::getAsString() const {
108 if (Attrs.empty())
109 return "";
110
111 std::string Ret = "[";
112 for (auto &A : Attrs)
113 Ret += A + ",";
114 Ret.pop_back();
115 Ret += "];";
116 Ret += Comments;
117 return Ret;
118 }
119
120 static std::string linkageToString(GlobalValue::LinkageTypes LT) {
121 switch (LT) {
122 case GlobalValue::ExternalLinkage:
123 return "extern";
124 case GlobalValue::AvailableExternallyLinkage:
125 return "av_ext";
126 case GlobalValue::LinkOnceAnyLinkage:
127 return "linkonce";
128 case GlobalValue::LinkOnceODRLinkage:
129 return "linkonce_odr";
130 case GlobalValue::WeakAnyLinkage:
131 return "weak";
132 case GlobalValue::WeakODRLinkage:
133 return "weak_odr";
134 case GlobalValue::AppendingLinkage:
135 return "appending";
136 case GlobalValue::InternalLinkage:
137 return "internal";
138 case GlobalValue::PrivateLinkage:
139 return "private";
140 case GlobalValue::ExternalWeakLinkage:
141 return "extern_weak";
142 case GlobalValue::CommonLinkage:
143 return "common";
144 }
145
146 return "";
147 }
148
149 static std::string fflagsToString(FunctionSummary::FFlags F) {
150 auto FlagValue = [](unsigned V) { return V ? '1' : '0'; };
151 char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly),
152 FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias), 0};
153
154 return FlagRep;
155 }
156
157 // Get string representation of function instruction count and flags.
158 static std::string getSummaryAttributes(GlobalValueSummary* GVS) {
159 auto *FS = dyn_cast_or_null(GVS);
160 if (!FS)
161 return "";
162
163 return std::string("inst: ") + std::to_string(FS->instCount()) +
164 ", ffl: " + fflagsToString(FS->fflags());
165 }
166
167 static std::string getNodeVisualName(const ValueInfo &VI) {
168 return VI.name().empty() ? std::string("@") + std::to_string(VI.getGUID())
169 : VI.name().str();
170 }
171
172 static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) {
173 if (isa(GVS))
174 return getNodeVisualName(VI);
175
176 std::string Attrs = getSummaryAttributes(GVS);
177 std::string Label =
178 getNodeVisualName(VI) + "|" + linkageToString(GVS->linkage());
179 if (!Attrs.empty())
180 Label += std::string(" (") + Attrs + ")";
181 Label += "}";
182
183 return Label;
184 }
185
186 // Write definition of external node, which doesn't have any
187 // specific module associated with it. Typically this is function
188 // or variable defined in native object or library.
189 static void defineExternalNode(raw_ostream &OS, const char *Pfx,
190 const ValueInfo &VI) {
191 auto StrId = std::to_string(VI.getGUID());
192 OS << " " << StrId << " [label=\"" << getNodeVisualName(VI)
193 << "\"]; // defined externally\n";
194 }
195
196 void ModuleSummaryIndex::exportToDot(raw_ostream& OS) const {
197 std::vector CrossModuleEdges;
198 DenseMap> NodeMap;
199 StringMap ModuleToDefinedGVS;
200 collectDefinedGVSummariesPerModule(ModuleToDefinedGVS);
201
202 // Get node identifier in form MXXX_. The MXXX prefix is required,
203 // because we may have multiple linkonce functions summaries.
204 auto NodeId = [](uint64_t ModId, GlobalValue::GUID Id) {
205 return ModId == (uint64_t)-1 ? std::to_string(Id)
206 : std::string("M") + std::to_string(ModId) +
207 "_" + std::to_string(Id);
208 };
209
210 auto DrawEdge = [&](const char *Pfx, int SrcMod, GlobalValue::GUID SrcId,
211 int DstMod, GlobalValue::GUID DstId, int TypeOrHotness) {
212 // 0 corresponds to alias edge, 1 to ref edge, 2 to call with unknown
213 // hotness, ...
214 TypeOrHotness += 2;
215 static const char *EdgeAttrs[] = {
216 " [style=dotted]; // alias",
217 " [style=dashed]; // ref",
218 " // call (hotness : Unknown)",
219 " [color=blue]; // call (hotness : Cold)",
220 " // call (hotness : None)",
221 " [color=brown]; // call (hotness : Hot)",
222 " [style=bold,color=red]; // call (hotness : Critical)"};
223
224 assert(static_cast(TypeOrHotness) <
225 sizeof(EdgeAttrs) / sizeof(EdgeAttrs[0]));
226 OS << Pfx << NodeId(SrcMod, SrcId) << " -> " << NodeId(DstMod, DstId)
227 << EdgeAttrs[TypeOrHotness] << "\n";
228 };
229
230 OS << "digraph Summary {\n";
231 for (auto &ModIt : ModuleToDefinedGVS) {
232 auto ModId = getModuleId(ModIt.first());
233 OS << " // Module: " << ModIt.first() << "\n";
234 OS << " subgraph cluster_" << std::to_string(ModId) << " {\n";
235 OS << " style = filled;\n";
236 OS << " color = lightgrey;\n";
237 OS << " label = \"" << sys::path::filename(ModIt.first()) << "\";\n";
238 OS << " node [style=filled,fillcolor=lightblue];\n";
239
240 auto &GVSMap = ModIt.second;
241 auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) {
242 if (!GVSMap.count(IdTo)) {
243 CrossModuleEdges.push_back({ModId, Hotness, IdFrom, IdTo});
244 return;
245 }
246 DrawEdge(" ", ModId, IdFrom, ModId, IdTo, Hotness);
247 };
248
249 for (auto &SummaryIt : GVSMap) {
250 NodeMap[SummaryIt.first].push_back(ModId);
251 auto Flags = SummaryIt.second->flags();
252 Attributes A;
253 if (isa(SummaryIt.second)) {
254 A.add("shape", "record", "function");
255 } else if (isa(SummaryIt.second)) {
256 A.add("style", "dotted,filled", "alias");
257 A.add("shape", "box");
258 } else {
259 A.add("shape", "Mrecord", "variable");
260 }
261
262 auto VI = getValueInfo(SummaryIt.first);
263 A.add("label", getNodeLabel(VI, SummaryIt.second));
264 if (!Flags.Live)
265 A.add("fillcolor", "red", "dead");
266 else if (Flags.NotEligibleToImport)
267 A.add("fillcolor", "yellow", "not eligible to import");
268
269 OS << " " << NodeId(ModId, SummaryIt.first) << " " << A.getAsString()
270 << "\n";
271 }
272 OS << " // Edges:\n";
273
274 for (auto &SummaryIt : GVSMap) {
275 auto *GVS = SummaryIt.second;
276 for (auto &R : GVS->refs())
277 Draw(SummaryIt.first, R.getGUID(), -1);
278
279 if (auto *AS = dyn_cast_or_null(SummaryIt.second)) {
280 auto AliaseeOrigId = AS->getAliasee().getOriginalName();
281 auto AliaseeId = getGUIDFromOriginalID(AliaseeOrigId);
282
283 Draw(SummaryIt.first, AliaseeId ? AliaseeId : AliaseeOrigId, -2);
284 continue;
285 }
286
287 if (auto *FS = dyn_cast_or_null(SummaryIt.second))
288 for (auto &CGEdge : FS->calls())
289 Draw(SummaryIt.first, CGEdge.first.getGUID(),
290 static_cast(CGEdge.second.Hotness));
291 }
292 OS << " }\n";
293 }
294
295 OS << " // Cross-module edges:\n";
296 for (auto &E : CrossModuleEdges) {
297 auto &ModList = NodeMap[E.Dst];
298 if (ModList.empty()) {
299 defineExternalNode(OS, " ", getValueInfo(E.Dst));
300 // Add fake module to the list to draw an edge to an external node
301 // in the loop below.
302 ModList.push_back(-1);
303 }
304 for (auto DstMod : ModList)
305 // The edge representing call or ref is drawn to every module where target
306 // symbol is defined. When target is a linkonce symbol there can be
307 // multiple edges representing a single call or ref, both intra-module and
308 // cross-module. As we've already drawn all intra-module edges before we
309 // skip it here.
310 if (DstMod != E.SrcMod)
311 DrawEdge(" ", E.SrcMod, E.Src, DstMod, E.Dst, E.Hotness);
312 }
313
314 OS << "}";
315 }
387387 Ctx(Conf), CombinedModule(llvm::make_unique("ld-temp.o", Ctx)),
388388 Mover(llvm::make_unique(*CombinedModule)) {}
389389
390 LTO::ThinLTOState::ThinLTOState(ThinBackend Backend) : Backend(Backend) {
390 LTO::ThinLTOState::ThinLTOState(ThinBackend Backend)
391 : Backend(Backend), CombinedIndex(/*IsPeformingAnalysis*/ false) {
391392 if (!Backend)
392393 this->Backend =
393394 createInProcessThinBackend(llvm::heavyweight_hardware_concurrency());
102102 if (EC)
103103 reportOpenError(Path, EC.message());
104104 WriteIndexToFile(Index, OS);
105
106 Path = OutputFileName + "index.dot";
107 raw_fd_ostream OSDot(Path, EC, sys::fs::OpenFlags::F_None);
108 if (EC)
109 reportOpenError(Path, EC.message());
110 Index.exportToDot(OSDot);
105111 return true;
106112 };
107113
591591 */
592592 std::unique_ptr ThinLTOCodeGenerator::linkCombinedIndex() {
593593 std::unique_ptr CombinedIndex =
594 llvm::make_unique();
594 llvm::make_unique(/*IsPeformingAnalysis=*/false);
595595 uint64_t NextModuleId = 0;
596596 for (auto &ModuleBuffer : Modules) {
597597 if (Error Err = readModuleSummaryIndex(ModuleBuffer.getMemBuffer(),
230230 // it, rather than needing to perform this mapping on each walk.
231231 auto GUID = Index.getGUIDFromOriginalID(VI.getGUID());
232232 if (GUID == 0)
233 return nullptr;
233 return ValueInfo();
234234 return Index.getValueInfo(GUID);
235235 }
236236
516516 for (auto &S : Entry.second.SummaryList)
517517 if (S->isLive()) {
518518 DEBUG(dbgs() << "Live root: " << Entry.first << "\n");
519 Worklist.push_back(ValueInfo(&Entry));
519 Worklist.push_back(ValueInfo(/*IsAnalysis=*/false, &Entry));
520520 ++LiveSymbols;
521521 break;
522522 }
15281528 }
15291529
15301530 bool LowerTypeTestsModule::runForTesting(Module &M) {
1531 ModuleSummaryIndex Summary;
1531 ModuleSummaryIndex Summary(/*IsPerformingAnalysis=*/false);
15321532
15331533 // Handle the command-line summary arguments. This code is for testing
15341534 // purposes only, so we handle errors directly.
583583 bool DevirtModule::runForTesting(
584584 Module &M, function_ref AARGetter,
585585 function_ref OREGetter) {
586 ModuleSummaryIndex Summary;
586 ModuleSummaryIndex Summary(/*IsPerformingAnalysis=*/false);
587587
588588 // Handle the command-line summary arguments. This code is for testing
589589 // purposes only, so we handle errors directly.
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 @A = local_unnamed_addr global i32 10, align 4
4 @B = local_unnamed_addr global i32 20, align 4
5
6 ; Function Attrs: norecurse nounwind readonly uwtable
7 define i32 @foo() local_unnamed_addr #0 {
8 %1 = load i32, i32* @B, align 4
9 %2 = load i32, i32* @A, align 4
10 %3 = add nsw i32 %2, %1
11 ret i32 %3
12 }
13
14 ; Function Attrs: norecurse nounwind readnone uwtable
15 define i32 @bar() local_unnamed_addr {
16 ret i32 42
17 }
18
19 attributes #0 = { noinline }
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/dot-dumper.ll -o %t2.bc
2 ; RUN: llvm-lto2 run -save-temps %t1.bc %t2.bc -o %t3 \
3 ; RUN: -r=%t1.bc,main,px \
4 ; RUN: -r=%t1.bc,main_alias,p \
5 ; RUN: -r=%t1.bc,foo, \
6 ; RUN: -r=%t1.bc,A, \
7 ; RUN: -r=%t2.bc,foo,p \
8 ; RUN: -r=%t2.bc,bar,p \
9 ; RUN: -r=%t2.bc,A,p \
10 ; RUN: -r=%t2.bc,B,p
11
12 ; Never assume specific order of clusters, nodes or edges
13 ; RUN: cat %t3.index.dot | FileCheck --check-prefix=STRUCTURE %s
14 ; RUN: cat %t3.index.dot | FileCheck --check-prefix=CLUSTER0 %s
15 ; RUN: cat %t3.index.dot | FileCheck --check-prefix=CLUSTER1 %s
16
17 ; STRUCTURE: digraph Summary {
18 ; STRUCTURE-DAG: subgraph cluster_0
19 ; STRUCTURE-DAG: subgraph cluster_1
20 ; STRUCTURE: // Cross-module edges:
21 ; STRUCTURE-DAG: M0_{{[0-9]+}} -> M1_{{[0-9]+}} // call
22 ; STRUCTURE-DAG: M0_{{[0-9]+}} -> M1_{{[0-9]+}} [{{.*}}]; // ref
23 ; STRUCTURE-NEXT: }
24
25 ; CLUSTER0: // Module: {{.*}}1.bc
26 ; CLUSTER0-NEXT: subgraph cluster_0 {
27 ; CLUSTER0-DAG: M0_[[MAIN_ALIAS:[0-9]+]] [{{.*}}main_alias{{.*}}]; // alias, dead
28 ; CLUSTER0-DAG: M0_[[MAIN:[0-9]+]] [{{.*}}main|extern{{.*}}]; // function
29 ; CLUSTER0-NEXT: // Edges:
30 ; CLUSTER0-NEXT: M0_[[MAIN_ALIAS]] -> M0_[[MAIN]] [{{.*}}]; // alias
31 ; CLUSTER0-NEXT: }
32
33 ; CLUSTER1: // Module: {{.*}}2.bc
34 ; CLUSTER1-NEXT: subgraph cluster_1 {
35 ; CLUSTER1-DAG: M1_[[A:[0-9]+]] [{{.*}}A|extern{{.*}}]; // variable
36 ; CLUSTER1-DAG: M1_[[FOO:[0-9]+]] [{{.*}}foo|extern{{.*}}]; // function, not eligible to import
37 ; CLUSTER1-DAG: M1_[[B:[0-9]+]] [{{.*}}B|extern{{.*}}]; // variable
38 ; CLUSTER1-DAG: M1_[[BAR:[0-9]+]] [{{.*}}bar|extern{{.*}}]; // function, dead
39 ; CLUSTER1-NEXT: // Edges:
40 ; CLUSTER1-DAG: M1_[[FOO]] -> M1_[[B]] [{{.*}}]; // ref
41 ; CLUSTER1-DAG: M1_[[FOO]] -> M1_[[A]] [{{.*}}]; // ref
42 ; CLUSTER1-DAG: }
43
44 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
45 target triple = "x86_64-unknown-linux-gnu"
46
47 @A = external local_unnamed_addr global i32, align 4
48
49 ; Function Attrs: nounwind uwtable
50 define i32 @main() local_unnamed_addr {
51 %1 = tail call i32 (...) @foo()
52 %2 = load i32, i32* @A, align 4
53 %3 = add nsw i32 %2, %1
54 ret i32 %3
55 }
56 @main_alias = weak_odr alias i32 (), i32 ()* @main
57 declare i32 @foo(...) local_unnamed_addr
366366 /// This is meant to enable testing of ThinLTO combined index generation,
367367 /// currently available via the gold plugin via -thinlto.
368368 static void createCombinedModuleSummaryIndex() {
369 ModuleSummaryIndex CombinedIndex;
369 ModuleSummaryIndex CombinedIndex(/*IsPerformingAnalysis=*/false);
370370 uint64_t NextModuleId = 0;
371371 for (auto &Filename : InputFilenames) {
372372 ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");