comparison lib/IR/ModuleSummaryIndex.cpp @ 148:63bd29f05246

merged
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Wed, 14 Aug 2019 19:46:37 +0900
parents c2174574ed3a
children
comparison
equal deleted inserted replaced
146:3fc4d5c3e21e 148:63bd29f05246
1 //===-- ModuleSummaryIndex.cpp - Module Summary Index ---------------------===// 1 //===-- ModuleSummaryIndex.cpp - Module Summary Index ---------------------===//
2 // 2 //
3 // The LLVM Compiler Infrastructure 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // 4 // See https://llvm.org/LICENSE.txt for license information.
5 // This file is distributed under the University of Illinois Open Source 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 // License. See LICENSE.TXT for details.
7 // 6 //
8 //===----------------------------------------------------------------------===// 7 //===----------------------------------------------------------------------===//
9 // 8 //
10 // This file implements the module index and summary classes for the 9 // This file implements the module index and summary classes for the
11 // IR library. 10 // IR library.
12 // 11 //
13 //===----------------------------------------------------------------------===// 12 //===----------------------------------------------------------------------===//
14 13
15 #include "llvm/IR/ModuleSummaryIndex.h" 14 #include "llvm/IR/ModuleSummaryIndex.h"
15 #include "llvm/ADT/SCCIterator.h"
16 #include "llvm/ADT/Statistic.h"
16 #include "llvm/ADT/StringMap.h" 17 #include "llvm/ADT/StringMap.h"
17 #include "llvm/Support/Path.h" 18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/raw_ostream.h"
18 using namespace llvm; 20 using namespace llvm;
21
22 #define DEBUG_TYPE "module-summary-index"
23
24 STATISTIC(ReadOnlyLiveGVars,
25 "Number of live global variables marked read only");
26 STATISTIC(WriteOnlyLiveGVars,
27 "Number of live global variables marked write only");
28
29 FunctionSummary FunctionSummary::ExternalNode =
30 FunctionSummary::makeDummyFunctionSummary({});
19 31
20 bool ValueInfo::isDSOLocal() const { 32 bool ValueInfo::isDSOLocal() const {
21 // Need to check all summaries are local in case of hash collisions. 33 // Need to check all summaries are local in case of hash collisions.
22 return getSummaryList().size() && 34 return getSummaryList().size() &&
23 llvm::all_of(getSummaryList(), 35 llvm::all_of(getSummaryList(),
24 [](const std::unique_ptr<GlobalValueSummary> &Summary) { 36 [](const std::unique_ptr<GlobalValueSummary> &Summary) {
25 return Summary->isDSOLocal(); 37 return Summary->isDSOLocal();
26 }); 38 });
39 }
40
41 bool ValueInfo::canAutoHide() const {
42 // Can only auto hide if all copies are eligible to auto hide.
43 return getSummaryList().size() &&
44 llvm::all_of(getSummaryList(),
45 [](const std::unique_ptr<GlobalValueSummary> &Summary) {
46 return Summary->canAutoHide();
47 });
48 }
49
50 // Gets the number of readonly and writeonly refs in RefEdgeList
51 std::pair<unsigned, unsigned> FunctionSummary::specialRefCounts() const {
52 // Here we take advantage of having all readonly and writeonly references
53 // located in the end of the RefEdgeList.
54 auto Refs = refs();
55 unsigned RORefCnt = 0, WORefCnt = 0;
56 int I;
57 for (I = Refs.size() - 1; I >= 0 && Refs[I].isWriteOnly(); --I)
58 WORefCnt++;
59 for (; I >= 0 && Refs[I].isReadOnly(); --I)
60 RORefCnt++;
61 return {RORefCnt, WORefCnt};
27 } 62 }
28 63
29 // Collect for the given module the list of function it defines 64 // Collect for the given module the list of function it defines
30 // (GUID -> Summary). 65 // (GUID -> Summary).
31 void ModuleSummaryIndex::collectDefinedFunctionsForModule( 66 void ModuleSummaryIndex::collectDefinedFunctionsForModule(
43 GVSummaryMap[GUID] = Summary; 78 GVSummaryMap[GUID] = Summary;
44 } 79 }
45 } 80 }
46 } 81 }
47 82
48 // Collect for each module the list of function it defines (GUID -> Summary).
49 void ModuleSummaryIndex::collectDefinedGVSummariesPerModule(
50 StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries) const {
51 for (auto &GlobalList : *this) {
52 auto GUID = GlobalList.first;
53 for (auto &Summary : GlobalList.second.SummaryList) {
54 ModuleToDefinedGVSummaries[Summary->modulePath()][GUID] = Summary.get();
55 }
56 }
57 }
58
59 GlobalValueSummary * 83 GlobalValueSummary *
60 ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID, 84 ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID,
61 bool PerModuleIndex) const { 85 bool PerModuleIndex) const {
62 auto VI = getValueInfo(ValueGUID); 86 auto VI = getValueInfo(ValueGUID);
63 assert(VI && "GlobalValue not found in index"); 87 assert(VI && "GlobalValue not found in index");
78 if (isGlobalValueLive(I.get())) 102 if (isGlobalValueLive(I.get()))
79 return true; 103 return true;
80 return false; 104 return false;
81 } 105 }
82 106
107 static void propagateAttributesToRefs(GlobalValueSummary *S) {
108 // If reference is not readonly or writeonly then referenced summary is not
109 // read/writeonly either. Note that:
110 // - All references from GlobalVarSummary are conservatively considered as
111 // not readonly or writeonly. Tracking them properly requires more complex
112 // analysis then we have now.
113 //
114 // - AliasSummary objects have no refs at all so this function is a no-op
115 // for them.
116 for (auto &VI : S->refs()) {
117 assert(VI.getAccessSpecifier() == 0 || isa<FunctionSummary>(S));
118 for (auto &Ref : VI.getSummaryList())
119 // If references to alias is not read/writeonly then aliasee
120 // is not read/writeonly
121 if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject())) {
122 if (!VI.isReadOnly())
123 GVS->setReadOnly(false);
124 if (!VI.isWriteOnly())
125 GVS->setWriteOnly(false);
126 }
127 }
128 }
129
130 // Do the access attribute propagation in combined index.
131 // The goal of attribute propagation is internalization of readonly (RO)
132 // or writeonly (WO) variables. To determine which variables are RO or WO
133 // and which are not we take following steps:
134 // - During analysis we speculatively assign readonly and writeonly
135 // attribute to all variables which can be internalized. When computing
136 // function summary we also assign readonly or writeonly attribute to a
137 // reference if function doesn't modify referenced variable (readonly)
138 // or doesn't read it (writeonly).
139 //
140 // - After computing dead symbols in combined index we do the attribute
141 // propagation. During this step we:
142 // a. clear RO and WO attributes from variables which are preserved or
143 // can't be imported
144 // b. clear RO and WO attributes from variables referenced by any global
145 // variable initializer
146 // c. clear RO attribute from variable referenced by a function when
147 // reference is not readonly
148 // d. clear WO attribute from variable referenced by a function when
149 // reference is not writeonly
150 //
151 // Because of (c, d) we don't internalize variables read by function A
152 // and modified by function B.
153 //
154 // Internalization itself happens in the backend after import is finished
155 // See internalizeGVsAfterImport.
156 void ModuleSummaryIndex::propagateAttributes(
157 const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
158 for (auto &P : *this)
159 for (auto &S : P.second.SummaryList) {
160 if (!isGlobalValueLive(S.get()))
161 // We don't examine references from dead objects
162 continue;
163
164 // Global variable can't be marked read/writeonly if it is not eligible
165 // to import since we need to ensure that all external references get
166 // a local (imported) copy. It also can't be marked read/writeonly if
167 // it or any alias (since alias points to the same memory) are preserved
168 // or notEligibleToImport, since either of those means there could be
169 // writes (or reads in case of writeonly) that are not visible (because
170 // preserved means it could have external to DSO writes or reads, and
171 // notEligibleToImport means it could have writes or reads via inline
172 // assembly leading it to be in the @llvm.*used).
173 if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject()))
174 // Here we intentionally pass S.get() not GVS, because S could be
175 // an alias.
176 if (!canImportGlobalVar(S.get()) ||
177 GUIDPreservedSymbols.count(P.first)) {
178 GVS->setReadOnly(false);
179 GVS->setWriteOnly(false);
180 }
181 propagateAttributesToRefs(S.get());
182 }
183 if (llvm::AreStatisticsEnabled())
184 for (auto &P : *this)
185 if (P.second.SummaryList.size())
186 if (auto *GVS = dyn_cast<GlobalVarSummary>(
187 P.second.SummaryList[0]->getBaseObject()))
188 if (isGlobalValueLive(GVS)) {
189 if (GVS->maybeReadOnly())
190 ReadOnlyLiveGVars++;
191 if (GVS->maybeWriteOnly())
192 WriteOnlyLiveGVars++;
193 }
194 }
195
196 // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
197 // then delete this function and update its tests
198 LLVM_DUMP_METHOD
199 void ModuleSummaryIndex::dumpSCCs(raw_ostream &O) {
200 for (scc_iterator<ModuleSummaryIndex *> I =
201 scc_begin<ModuleSummaryIndex *>(this);
202 !I.isAtEnd(); ++I) {
203 O << "SCC (" << utostr(I->size()) << " node" << (I->size() == 1 ? "" : "s")
204 << ") {\n";
205 for (const ValueInfo V : *I) {
206 FunctionSummary *F = nullptr;
207 if (V.getSummaryList().size())
208 F = cast<FunctionSummary>(V.getSummaryList().front().get());
209 O << " " << (F == nullptr ? "External" : "") << " " << utostr(V.getGUID())
210 << (I.hasLoop() ? " (has loop)" : "") << "\n";
211 }
212 O << "}\n";
213 }
214 }
215
83 namespace { 216 namespace {
84 struct Attributes { 217 struct Attributes {
85 void add(const Twine &Name, const Twine &Value, 218 void add(const Twine &Name, const Twine &Value,
86 const Twine &Comment = Twine()); 219 const Twine &Comment = Twine());
220 void addComment(const Twine &Comment);
87 std::string getAsString() const; 221 std::string getAsString() const;
88 222
89 std::vector<std::string> Attrs; 223 std::vector<std::string> Attrs;
90 std::string Comments; 224 std::string Comments;
91 }; 225 };
103 std::string A = Name.str(); 237 std::string A = Name.str();
104 A += "=\""; 238 A += "=\"";
105 A += Value.str(); 239 A += Value.str();
106 A += "\""; 240 A += "\"";
107 Attrs.push_back(A); 241 Attrs.push_back(A);
242 addComment(Comment);
243 }
244
245 void Attributes::addComment(const Twine &Comment) {
108 if (!Comment.isTriviallyEmpty()) { 246 if (!Comment.isTriviallyEmpty()) {
109 if (Comments.empty()) 247 if (Comments.empty())
110 Comments = " // "; 248 Comments = " // ";
111 else 249 else
112 Comments += ", "; 250 Comments += ", ";
156 return "<unknown>"; 294 return "<unknown>";
157 } 295 }
158 296
159 static std::string fflagsToString(FunctionSummary::FFlags F) { 297 static std::string fflagsToString(FunctionSummary::FFlags F) {
160 auto FlagValue = [](unsigned V) { return V ? '1' : '0'; }; 298 auto FlagValue = [](unsigned V) { return V ? '1' : '0'; };
161 char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly), 299 char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly),
162 FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias), 0}; 300 FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias),
301 FlagValue(F.NoInline), 0};
163 302
164 return FlagRep; 303 return FlagRep;
165 } 304 }
166 305
167 // Get string representation of function instruction count and flags. 306 // Get string representation of function instruction count and flags.
172 311
173 return std::string("inst: ") + std::to_string(FS->instCount()) + 312 return std::string("inst: ") + std::to_string(FS->instCount()) +
174 ", ffl: " + fflagsToString(FS->fflags()); 313 ", ffl: " + fflagsToString(FS->fflags());
175 } 314 }
176 315
316 static std::string getNodeVisualName(GlobalValue::GUID Id) {
317 return std::string("@") + std::to_string(Id);
318 }
319
177 static std::string getNodeVisualName(const ValueInfo &VI) { 320 static std::string getNodeVisualName(const ValueInfo &VI) {
178 return VI.name().empty() ? std::string("@") + std::to_string(VI.getGUID()) 321 return VI.name().empty() ? getNodeVisualName(VI.getGUID()) : VI.name().str();
179 : VI.name().str();
180 } 322 }
181 323
182 static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) { 324 static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) {
183 if (isa<AliasSummary>(GVS)) 325 if (isa<AliasSummary>(GVS))
184 return getNodeVisualName(VI); 326 return getNodeVisualName(VI);
195 337
196 // Write definition of external node, which doesn't have any 338 // Write definition of external node, which doesn't have any
197 // specific module associated with it. Typically this is function 339 // specific module associated with it. Typically this is function
198 // or variable defined in native object or library. 340 // or variable defined in native object or library.
199 static void defineExternalNode(raw_ostream &OS, const char *Pfx, 341 static void defineExternalNode(raw_ostream &OS, const char *Pfx,
200 const ValueInfo &VI) { 342 const ValueInfo &VI, GlobalValue::GUID Id) {
201 auto StrId = std::to_string(VI.getGUID()); 343 auto StrId = std::to_string(Id);
202 OS << " " << StrId << " [label=\"" << getNodeVisualName(VI) 344 OS << " " << StrId << " [label=\"";
203 << "\"]; // defined externally\n"; 345
204 } 346 if (VI) {
205 347 OS << getNodeVisualName(VI);
206 void ModuleSummaryIndex::exportToDot(raw_ostream& OS) const { 348 } else {
349 OS << getNodeVisualName(Id);
350 }
351 OS << "\"]; // defined externally\n";
352 }
353
354 static bool hasReadOnlyFlag(const GlobalValueSummary *S) {
355 if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
356 return GVS->maybeReadOnly();
357 return false;
358 }
359
360 static bool hasWriteOnlyFlag(const GlobalValueSummary *S) {
361 if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
362 return GVS->maybeWriteOnly();
363 return false;
364 }
365
366 void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const {
207 std::vector<Edge> CrossModuleEdges; 367 std::vector<Edge> CrossModuleEdges;
208 DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap; 368 DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap;
209 StringMap<GVSummaryMapTy> ModuleToDefinedGVS; 369 using GVSOrderedMapTy = std::map<GlobalValue::GUID, GlobalValueSummary *>;
370 std::map<StringRef, GVSOrderedMapTy> ModuleToDefinedGVS;
210 collectDefinedGVSummariesPerModule(ModuleToDefinedGVS); 371 collectDefinedGVSummariesPerModule(ModuleToDefinedGVS);
211 372
212 // Get node identifier in form MXXX_<GUID>. The MXXX prefix is required, 373 // Get node identifier in form MXXX_<GUID>. The MXXX prefix is required,
213 // because we may have multiple linkonce functions summaries. 374 // because we may have multiple linkonce functions summaries.
214 auto NodeId = [](uint64_t ModId, GlobalValue::GUID Id) { 375 auto NodeId = [](uint64_t ModId, GlobalValue::GUID Id) {
215 return ModId == (uint64_t)-1 ? std::to_string(Id) 376 return ModId == (uint64_t)-1 ? std::to_string(Id)
216 : std::string("M") + std::to_string(ModId) + 377 : std::string("M") + std::to_string(ModId) +
217 "_" + std::to_string(Id); 378 "_" + std::to_string(Id);
218 }; 379 };
219 380
220 auto DrawEdge = [&](const char *Pfx, int SrcMod, GlobalValue::GUID SrcId, 381 auto DrawEdge = [&](const char *Pfx, uint64_t SrcMod, GlobalValue::GUID SrcId,
221 int DstMod, GlobalValue::GUID DstId, int TypeOrHotness) { 382 uint64_t DstMod, GlobalValue::GUID DstId,
222 // 0 corresponds to alias edge, 1 to ref edge, 2 to call with unknown 383 int TypeOrHotness) {
223 // hotness, ... 384 // 0 - alias
224 TypeOrHotness += 2; 385 // 1 - reference
386 // 2 - constant reference
387 // 3 - writeonly reference
388 // Other value: (hotness - 4).
389 TypeOrHotness += 4;
225 static const char *EdgeAttrs[] = { 390 static const char *EdgeAttrs[] = {
226 " [style=dotted]; // alias", 391 " [style=dotted]; // alias",
227 " [style=dashed]; // ref", 392 " [style=dashed]; // ref",
393 " [style=dashed,color=forestgreen]; // const-ref",
394 " [style=dashed,color=violetred]; // writeOnly-ref",
228 " // call (hotness : Unknown)", 395 " // call (hotness : Unknown)",
229 " [color=blue]; // call (hotness : Cold)", 396 " [color=blue]; // call (hotness : Cold)",
230 " // call (hotness : None)", 397 " // call (hotness : None)",
231 " [color=brown]; // call (hotness : Hot)", 398 " [color=brown]; // call (hotness : Hot)",
232 " [style=bold,color=red]; // call (hotness : Critical)"}; 399 " [style=bold,color=red]; // call (hotness : Critical)"};
237 << EdgeAttrs[TypeOrHotness] << "\n"; 404 << EdgeAttrs[TypeOrHotness] << "\n";
238 }; 405 };
239 406
240 OS << "digraph Summary {\n"; 407 OS << "digraph Summary {\n";
241 for (auto &ModIt : ModuleToDefinedGVS) { 408 for (auto &ModIt : ModuleToDefinedGVS) {
242 auto ModId = getModuleId(ModIt.first()); 409 auto ModId = getModuleId(ModIt.first);
243 OS << " // Module: " << ModIt.first() << "\n"; 410 OS << " // Module: " << ModIt.first << "\n";
244 OS << " subgraph cluster_" << std::to_string(ModId) << " {\n"; 411 OS << " subgraph cluster_" << std::to_string(ModId) << " {\n";
245 OS << " style = filled;\n"; 412 OS << " style = filled;\n";
246 OS << " color = lightgrey;\n"; 413 OS << " color = lightgrey;\n";
247 OS << " label = \"" << sys::path::filename(ModIt.first()) << "\";\n"; 414 OS << " label = \"" << sys::path::filename(ModIt.first) << "\";\n";
248 OS << " node [style=filled,fillcolor=lightblue];\n"; 415 OS << " node [style=filled,fillcolor=lightblue];\n";
249 416
250 auto &GVSMap = ModIt.second; 417 auto &GVSMap = ModIt.second;
251 auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) { 418 auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) {
252 if (!GVSMap.count(IdTo)) { 419 if (!GVSMap.count(IdTo)) {
265 } else if (isa<AliasSummary>(SummaryIt.second)) { 432 } else if (isa<AliasSummary>(SummaryIt.second)) {
266 A.add("style", "dotted,filled", "alias"); 433 A.add("style", "dotted,filled", "alias");
267 A.add("shape", "box"); 434 A.add("shape", "box");
268 } else { 435 } else {
269 A.add("shape", "Mrecord", "variable"); 436 A.add("shape", "Mrecord", "variable");
437 if (Flags.Live && hasReadOnlyFlag(SummaryIt.second))
438 A.addComment("immutable");
439 if (Flags.Live && hasWriteOnlyFlag(SummaryIt.second))
440 A.addComment("writeOnly");
270 } 441 }
442 if (Flags.DSOLocal)
443 A.addComment("dsoLocal");
444 if (Flags.CanAutoHide)
445 A.addComment("canAutoHide");
271 446
272 auto VI = getValueInfo(SummaryIt.first); 447 auto VI = getValueInfo(SummaryIt.first);
273 A.add("label", getNodeLabel(VI, SummaryIt.second)); 448 A.add("label", getNodeLabel(VI, SummaryIt.second));
274 if (!Flags.Live) 449 if (!Flags.Live)
275 A.add("fillcolor", "red", "dead"); 450 A.add("fillcolor", "red", "dead");
282 OS << " // Edges:\n"; 457 OS << " // Edges:\n";
283 458
284 for (auto &SummaryIt : GVSMap) { 459 for (auto &SummaryIt : GVSMap) {
285 auto *GVS = SummaryIt.second; 460 auto *GVS = SummaryIt.second;
286 for (auto &R : GVS->refs()) 461 for (auto &R : GVS->refs())
287 Draw(SummaryIt.first, R.getGUID(), -1); 462 Draw(SummaryIt.first, R.getGUID(),
463 R.isWriteOnly() ? -1 : (R.isReadOnly() ? -2 : -3));
288 464
289 if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) { 465 if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) {
290 auto AliaseeOrigId = AS->getAliasee().getOriginalName(); 466 Draw(SummaryIt.first, AS->getAliaseeGUID(), -4);
291 auto AliaseeId = getGUIDFromOriginalID(AliaseeOrigId);
292
293 Draw(SummaryIt.first, AliaseeId ? AliaseeId : AliaseeOrigId, -2);
294 continue; 467 continue;
295 } 468 }
296 469
297 if (auto *FS = dyn_cast_or_null<FunctionSummary>(SummaryIt.second)) 470 if (auto *FS = dyn_cast_or_null<FunctionSummary>(SummaryIt.second))
298 for (auto &CGEdge : FS->calls()) 471 for (auto &CGEdge : FS->calls())
304 477
305 OS << " // Cross-module edges:\n"; 478 OS << " // Cross-module edges:\n";
306 for (auto &E : CrossModuleEdges) { 479 for (auto &E : CrossModuleEdges) {
307 auto &ModList = NodeMap[E.Dst]; 480 auto &ModList = NodeMap[E.Dst];
308 if (ModList.empty()) { 481 if (ModList.empty()) {
309 defineExternalNode(OS, " ", getValueInfo(E.Dst)); 482 defineExternalNode(OS, " ", getValueInfo(E.Dst), E.Dst);
310 // Add fake module to the list to draw an edge to an external node 483 // Add fake module to the list to draw an edge to an external node
311 // in the loop below. 484 // in the loop below.
312 ModList.push_back(-1); 485 ModList.push_back(-1);
313 } 486 }
314 for (auto DstMod : ModList) 487 for (auto DstMod : ModList)