[llvm] 6e60330 - [SampleFDO] Read call-graph matching recovered top-level function profile (#101053)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 4 11:08:43 PDT 2024
Author: Lei Wang
Date: 2024-09-04T11:08:40-07:00
New Revision: 6e60330af55bfdf5b34aed4c9197cd3afbf00498
URL: https://github.com/llvm/llvm-project/commit/6e60330af55bfdf5b34aed4c9197cd3afbf00498
DIFF: https://github.com/llvm/llvm-project/commit/6e60330af55bfdf5b34aed4c9197cd3afbf00498.diff
LOG: [SampleFDO] Read call-graph matching recovered top-level function profile (#101053)
With extbinary profile format, initial profile loading only reads
profile based on current function names in the module. However, if a
function is renamed, sample loader skips to load its original
profile(which has a different name), we will miss this case. To address
this, we load the top-level profile candidate explicitly for the
matching. If a match is found later, the function profile will be
further preserved for use by the sample loader.
Added:
llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-toplev-func.prof
llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-toplev-func.ll
Modified:
llvm/include/llvm/ProfileData/SampleProfReader.h
llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h
index 0fd86600de21f0..5301f23def3f37 100644
--- a/llvm/include/llvm/ProfileData/SampleProfReader.h
+++ b/llvm/include/llvm/ProfileData/SampleProfReader.h
@@ -424,6 +424,16 @@ class SampleProfileReader {
if (It != Profiles.end())
return &It->second;
+ if (FuncNameToProfNameMap && !FuncNameToProfNameMap->empty()) {
+ auto R = FuncNameToProfNameMap->find(FunctionId(Fname));
+ if (R != FuncNameToProfNameMap->end()) {
+ Fname = R->second.stringRef();
+ auto It = Profiles.find(FunctionId(Fname));
+ if (It != Profiles.end())
+ return &It->second;
+ }
+ }
+
if (Remapper) {
if (auto NameInProfile = Remapper->lookUpNameInProfile(Fname)) {
auto It = Profiles.find(FunctionId(*NameInProfile));
@@ -505,6 +515,11 @@ class SampleProfileReader {
void setModule(const Module *Mod) { M = Mod; }
+ void setFuncNameToProfNameMap(
+ const HashKeyMap<std::unordered_map, FunctionId, FunctionId> &FPMap) {
+ FuncNameToProfNameMap = &FPMap;
+ }
+
protected:
/// Map every function to its associated profile.
///
@@ -541,6 +556,12 @@ class SampleProfileReader {
std::unique_ptr<SampleProfileReaderItaniumRemapper> Remapper;
+ // A map pointer to the FuncNameToProfNameMap in SampleProfileLoader,
+ // which maps the function name to the matched profile name. This is used
+ // for sample loader to look up profile using the new name.
+ const HashKeyMap<std::unordered_map, FunctionId, FunctionId>
+ *FuncNameToProfNameMap = nullptr;
+
// A map from a function's context hash to its meta data section range, used
// for on-demand read function profile metadata.
std::unordered_map<uint64_t, std::pair<const uint8_t *, const uint8_t *>>
diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
index a67f158433391c..076d91adfd1dea 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
@@ -198,6 +198,7 @@ class SampleProfileMatcher {
// function and all inlinees.
void countMismatchedCallsiteSamples(const FunctionSamples &FS);
void computeAndReportProfileStaleness();
+ void UpdateWithSalvagedProfiles();
LocToLocMap &getIRToProfileLocationMap(const Function &F) {
auto Ret = FuncMappings.try_emplace(
diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 312672e56b0170..0c676e8fb95fdb 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -36,6 +36,13 @@ static cl::opt<unsigned> MinCallCountForCGMatching(
cl::desc("The minimum number of call anchors required for a function to "
"run stale profile call graph matching."));
+static cl::opt<bool> LoadFuncProfileforCGMatching(
+ "load-func-profile-for-cg-matching", cl::Hidden, cl::init(false),
+ cl::desc(
+ "Load top-level profiles that the sample reader initially skipped for "
+ "the call-graph matching (only meaningful for extended binary "
+ "format)"));
+
extern cl::opt<bool> SalvageStaleProfile;
extern cl::opt<bool> SalvageUnusedProfile;
extern cl::opt<bool> PersistProfileStaleness;
@@ -410,18 +417,19 @@ void SampleProfileMatcher::runOnFunction(Function &F) {
// callsites in one context may
diff er from those in another context. To get
// the maximum number of callsites, we merge the function profiles from all
// contexts, aka, the flattened profile to find profile anchors.
- const auto *FSFlattened = getFlattenedSamplesFor(F);
- if (SalvageUnusedProfile && !FSFlattened) {
+ const auto *FSForMatching = getFlattenedSamplesFor(F);
+ if (SalvageUnusedProfile && !FSForMatching) {
// Apply the matching in place to find the new function's matched profile.
- // TODO: For extended profile format, if a function profile is unused and
- // it's top-level, even if the profile is matched, it's not found in the
- // profile. This is because sample reader only read the used profile at the
- // beginning, we need to support loading the profile on-demand in future.
auto R = FuncToProfileNameMap.find(&F);
- if (R != FuncToProfileNameMap.end())
- FSFlattened = getFlattenedSamplesFor(R->second);
+ if (R != FuncToProfileNameMap.end()) {
+ FSForMatching = getFlattenedSamplesFor(R->second);
+ // Try to find the salvaged top-level profiles that are explicitly loaded
+ // for the matching, see "functionMatchesProfileHelper" for the details.
+ if (!FSForMatching && LoadFuncProfileforCGMatching)
+ FSForMatching = Reader.getSamplesFor(R->second.stringRef());
+ }
}
- if (!FSFlattened)
+ if (!FSForMatching)
return;
// Anchors for IR. It's a map from IR location to callee name, callee name is
@@ -432,7 +440,7 @@ void SampleProfileMatcher::runOnFunction(Function &F) {
// Anchors for profile. It's a map from callsite location to a set of callee
// name.
AnchorMap ProfileAnchors;
- findProfileAnchors(*FSFlattened, ProfileAnchors);
+ findProfileAnchors(*FSForMatching, ProfileAnchors);
// Compute the callsite match states for profile staleness report.
if (ReportProfileStaleness || PersistProfileStaleness)
@@ -443,7 +451,7 @@ void SampleProfileMatcher::runOnFunction(Function &F) {
// For probe-based profiles, run matching only when profile checksum is
// mismatched.
bool ChecksumMismatch = FunctionSamples::ProfileIsProbeBased &&
- !ProbeManager->profileIsValid(F, *FSFlattened);
+ !ProbeManager->profileIsValid(F, *FSForMatching);
bool RunCFGMatching =
!FunctionSamples::ProfileIsProbeBased || ChecksumMismatch;
bool RunCGMatching = SalvageUnusedProfile;
@@ -781,14 +789,30 @@ bool SampleProfileMatcher::functionMatchesProfileHelper(
// two sequences are.
float Similarity = 0.0;
- const auto *FSFlattened = getFlattenedSamplesFor(ProfFunc);
- if (!FSFlattened)
+ const auto *FSForMatching = getFlattenedSamplesFor(ProfFunc);
+ // With extbinary profile format, initial profile loading only reads profile
+ // based on current function names in the module.
+ // However, if a function is renamed, sample loader skips to load its original
+ // profile(which has a
diff erent name), we will miss this case. To address
+ // this, we load the top-level profile candidate explicitly for the matching.
+ if (!FSForMatching && LoadFuncProfileforCGMatching) {
+ DenseSet<StringRef> TopLevelFunc({ProfFunc.stringRef()});
+ if (std::error_code EC = Reader.read(TopLevelFunc))
+ return false;
+ FSForMatching = Reader.getSamplesFor(ProfFunc.stringRef());
+ LLVM_DEBUG({
+ if (FSForMatching)
+ dbgs() << "Read top-level function " << ProfFunc
+ << " for call-graph matching\n";
+ });
+ }
+ if (!FSForMatching)
return false;
// The check for similarity or checksum may not be reliable if the function is
// tiny, we use the number of basic block as a proxy for the function
// complexity and skip the matching if it's too small.
if (IRFunc.size() < MinFuncCountForCGMatching ||
- FSFlattened->getBodySamples().size() < MinFuncCountForCGMatching)
+ FSForMatching->getBodySamples().size() < MinFuncCountForCGMatching)
return false;
// For probe-based function, we first trust the checksum info. If the checksum
@@ -796,7 +820,7 @@ bool SampleProfileMatcher::functionMatchesProfileHelper(
if (FunctionSamples::ProfileIsProbeBased) {
const auto *FuncDesc = ProbeManager->getDesc(IRFunc);
if (FuncDesc &&
- !ProbeManager->profileIsHashMismatched(*FuncDesc, *FSFlattened)) {
+ !ProbeManager->profileIsHashMismatched(*FuncDesc, *FSForMatching)) {
LLVM_DEBUG(dbgs() << "The checksums for " << IRFunc.getName()
<< "(IR) and " << ProfFunc << "(Profile) match.\n");
@@ -807,7 +831,7 @@ bool SampleProfileMatcher::functionMatchesProfileHelper(
AnchorMap IRAnchors;
findIRAnchors(IRFunc, IRAnchors);
AnchorMap ProfileAnchors;
- findProfileAnchors(*FSFlattened, ProfileAnchors);
+ findProfileAnchors(*FSForMatching, ProfileAnchors);
AnchorList FilteredIRAnchorsList;
AnchorList FilteredProfileAnchorList;
@@ -863,6 +887,29 @@ bool SampleProfileMatcher::functionMatchesProfile(Function &IRFunc,
return Matched;
}
+void SampleProfileMatcher::UpdateWithSalvagedProfiles() {
+ DenseSet<StringRef> ProfileSalvagedFuncs;
+ // Update FuncNameToProfNameMap and SymbolMap.
+ for (auto &I : FuncToProfileNameMap) {
+ assert(I.first && "New function is null");
+ FunctionId FuncName(I.first->getName());
+ ProfileSalvagedFuncs.insert(I.second.stringRef());
+ FuncNameToProfNameMap->emplace(FuncName, I.second);
+
+ // We need to remove the old entry to avoid duplicating the function
+ // processing.
+ SymbolMap->erase(FuncName);
+ SymbolMap->emplace(I.second, I.first);
+ }
+
+ // With extbinary profile format, initial profile loading only reads profile
+ // based on current function names in the module, so we need to load top-level
+ // profiles for functions with
diff erent profile name explicitly after
+ // function-profile name map is established with stale profile matching.
+ Reader.read(ProfileSalvagedFuncs);
+ Reader.setFuncNameToProfNameMap(*FuncNameToProfNameMap);
+}
+
void SampleProfileMatcher::runOnModule() {
ProfileConverter::flattenProfile(Reader.getProfiles(), FlattenedProfiles,
FunctionSamples::ProfileIsCS);
@@ -880,17 +927,8 @@ void SampleProfileMatcher::runOnModule() {
runOnFunction(*F);
}
- // Update the data in SampleLoader.
if (SalvageUnusedProfile)
- for (auto &I : FuncToProfileNameMap) {
- assert(I.first && "New function is null");
- FunctionId FuncName(I.first->getName());
- FuncNameToProfNameMap->emplace(FuncName, I.second);
- // We need to remove the old entry to avoid duplicating the function
- // processing.
- SymbolMap->erase(FuncName);
- SymbolMap->emplace(I.second, I.first);
- }
+ UpdateWithSalvagedProfiles();
if (SalvageStaleProfile)
distributeIRToProfileLocationMap();
diff --git a/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-toplev-func.prof b/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-toplev-func.prof
new file mode 100644
index 00000000000000..86c8cb3285afe2
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-toplev-func.prof
@@ -0,0 +1,23 @@
+foo:2724522:51
+ 1: 51
+ 2: 452674
+ 3: 47
+ 4: 497875
+ 6: 415959
+ 10: 452623
+ 11: 452687 bar:452687
+ 12: 452623
+ 13: 47
+ !CFGChecksum: 281479271677951
+bar:452687:452687
+ 1: 452687
+ !CFGChecksum: 4294967295
+main:204:0
+ 1: 0
+ 2: 51
+ 3: 0
+ 4: 51
+ 5: 51 foo:51
+ 6: 51
+ 7: 0
+ !CFGChecksum: 281582264815352
diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-toplev-func.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-toplev-func.ll
new file mode 100644
index 00000000000000..c839364f235536
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-toplev-func.ll
@@ -0,0 +1,169 @@
+; REQUIRES: x86_64-linux
+; REQUIRES: asserts
+; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/pseudo-probe-stale-profile-toplev-func.prof --salvage-stale-profile --salvage-unused-profile -report-profile-staleness -S --debug-only=sample-profile,sample-profile-matcher,sample-profile-impl -pass-remarks=inline --min-call-count-for-cg-matching=0 --min-func-count-for-cg-matching=0 --load-func-profile-for-cg-matching 2>&1 | FileCheck %s -check-prefix=CHECK-TEXT
+; RUN: llvm-profdata merge --sample %S/Inputs/pseudo-probe-stale-profile-toplev-func.prof -extbinary -o %t.extbinary
+; RUN: opt < %s -passes=sample-profile -sample-profile-file=%t.extbinary --salvage-stale-profile --salvage-unused-profile -report-profile-staleness -S --debug-only=sample-profile,sample-profile-matcher,sample-profile-impl -pass-remarks=inline --min-call-count-for-cg-matching=0 --min-func-count-for-cg-matching=0 --load-func-profile-for-cg-matching 2>&1 | FileCheck %s -check-prefix=CHECK-EXTBIN
+
+; CHECK-TEXT: Run stale profile matching for main
+; CHECK-TEXT-NOT: Read top-level function foo for call-graph matching
+; CHECK-TEXT: The checksums for foo_rename(IR) and foo(Profile) match.
+; CHECK-TEXT: Function:foo_rename matches profile:foo
+; CHECK-TEXT: Run stale profile matching for foo_rename
+; CHECK-TEXT: (1/3) of functions' profile are matched and (2724522/3177413) of samples are reused by call graph matching.
+
+; CHECK-TEXT: Processing Function main
+; CHECK-TEXT: 5: call void @foo_rename(), !dbg ![[#]] - weight: 51
+; CHECK-TEXT: Processing Function foo_rename
+; CHECK-TEXT: 2: %call = call i32 @bar(i32 noundef %0), !dbg ![[#]] - weight: 452674
+
+
+; CHECK-EXTBIN: Run stale profile matching for main
+; CHECK-EXTBIN: Read top-level function foo for call-graph matching
+; CHECK-EXTBIN: The checksums for foo_rename(IR) and foo(Profile) match.
+; CHECK-EXTBIN: Function:foo_rename matches profile:foo
+; CHECK-EXTBIN: Run stale profile matching for foo_rename
+; CHECK-EXTBIN: (1/3) of functions' profile are matched and (2724522/3177413) of samples are reused by call graph matching.
+
+; CHECK-EXTBIN: Processing Function main
+; CHECK-EXTBIN: 5: call void @foo_rename(), !dbg ![[#]] - weight: 51
+; CHECK-EXTBIN: Processing Function foo_rename
+; CHECK-EXTBIN: 2: %call = call i32 @bar(i32 noundef %0), !dbg ![[#]] - weight: 452674
+
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at x = dso_local global i32 0, align 4, !dbg !0
+
+; Function Attrs: noinline nounwind uwtable
+define dso_local i32 @bar(i32 noundef %x) #0 !dbg !18 {
+entry:
+ #dbg_value(i32 %x, !22, !DIExpression(), !23)
+ call void @llvm.pseudoprobe(i64 -2012135647395072713, i64 1, i32 0, i64 -1), !dbg !24
+ %add = add nsw i32 %x, 1, !dbg !25
+ ret i32 %add, !dbg !26
+}
+
+; Function Attrs: noinline nounwind uwtable
+define dso_local void @foo_rename() #0 !dbg !27 {
+entry:
+ call void @llvm.pseudoprobe(i64 -2115950948644264162, i64 1, i32 0, i64 -1), !dbg !30
+ %0 = load volatile i32, ptr @x, align 4, !dbg !30, !tbaa !31
+ %call = call i32 @bar(i32 noundef %0), !dbg !35
+ %1 = load volatile i32, ptr @x, align 4, !dbg !37, !tbaa !31
+ %add = add nsw i32 %1, %call, !dbg !37
+ store volatile i32 %add, ptr @x, align 4, !dbg !37, !tbaa !31
+ ret void, !dbg !38
+}
+
+; Function Attrs: nounwind uwtable
+define dso_local i32 @main() #1 !dbg !39 {
+entry:
+ call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 1, i32 0, i64 -1), !dbg !45
+ #dbg_value(i32 0, !43, !DIExpression(), !46)
+ br label %for.cond, !dbg !47
+
+for.cond: ; preds = %for.body, %entry
+ %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ], !dbg !48
+ #dbg_value(i32 %i.0, !43, !DIExpression(), !46)
+ call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 2, i32 0, i64 -1), !dbg !49
+ %cmp = icmp slt i32 %i.0, 100000, !dbg !51
+ br i1 %cmp, label %for.body, label %for.cond.cleanup, !dbg !52
+
+for.cond.cleanup: ; preds = %for.cond
+ call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 3, i32 0, i64 -1), !dbg !53
+ call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 7, i32 0, i64 -1), !dbg !54
+ ret i32 0, !dbg !54
+
+for.body: ; preds = %for.cond
+ call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 4, i32 0, i64 -1), !dbg !55
+ call void @foo_rename(), !dbg !57
+ call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 6, i32 0, i64 -1), !dbg !59
+ %inc = add nsw i32 %i.0, 1, !dbg !59
+ #dbg_value(i32 %inc, !43, !DIExpression(), !46)
+ br label %for.cond, !dbg !60, !llvm.loop !61
+}
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite)
+declare void @llvm.pseudoprobe(i64, i64, i32, i64) #3
+
+attributes #0 = { noinline nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "use-sample-profile" }
+attributes #1 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "use-sample-profile" }
+attributes #2 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+attributes #3 = { mustprogress nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!7, !8, !9, !10, !11, !12, !13}
+!llvm.ident = !{!14}
+!llvm.pseudo_probe_desc = !{!15, !16, !17}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 20.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "test_rename.c", directory: "/home", checksumkind: CSK_MD5, checksum: "11a33a83e4d190ebda0792d0610f0c67")
+!4 = !{!0}
+!5 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !6)
+!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = !{i32 7, !"Dwarf Version", i32 5}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{i32 8, !"PIC Level", i32 2}
+!11 = !{i32 7, !"PIE Level", i32 2}
+!12 = !{i32 7, !"uwtable", i32 2}
+!13 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+!14 = !{!"clang version 20.0.0"}
+!15 = !{i64 -2012135647395072713, i64 4294967295, !"bar"}
+!16 = !{i64 -2115950948644264162, i64 281479271677951, !"foo_rename"}
+!17 = !{i64 -2624081020897602054, i64 281582264815352, !"main"}
+!18 = distinct !DISubprogram(name: "bar", scope: !3, file: !3, line: 3, type: !19, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !21)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!6, !6}
+!21 = !{!22}
+!22 = !DILocalVariable(name: "x", arg: 1, scope: !18, file: !3, line: 3, type: !6)
+!23 = !DILocation(line: 0, scope: !18)
+!24 = !DILocation(line: 4, column: 10, scope: !18)
+!25 = !DILocation(line: 4, column: 12, scope: !18)
+!26 = !DILocation(line: 4, column: 3, scope: !18)
+!27 = distinct !DISubprogram(name: "foo_rename", scope: !3, file: !3, line: 7, type: !28, scopeLine: 7, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!28 = !DISubroutineType(types: !29)
+!29 = !{null}
+!30 = !DILocation(line: 8, column: 15, scope: !27)
+!31 = !{!32, !32, i64 0}
+!32 = !{!"int", !33, i64 0}
+!33 = !{!"omnipotent char", !34, i64 0}
+!34 = !{!"Simple C/C++ TBAA"}
+!35 = !DILocation(line: 8, column: 11, scope: !36)
+!36 = !DILexicalBlockFile(scope: !27, file: !3, discriminator: 455082007)
+!37 = !DILocation(line: 8, column: 8, scope: !27)
+!38 = !DILocation(line: 9, column: 1, scope: !27)
+!39 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 11, type: !40, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !42)
+!40 = !DISubroutineType(types: !41)
+!41 = !{!6}
+!42 = !{!43}
+!43 = !DILocalVariable(name: "i", scope: !44, file: !3, line: 12, type: !6)
+!44 = distinct !DILexicalBlock(scope: !39, file: !3, line: 12, column: 3)
+!45 = !DILocation(line: 12, column: 12, scope: !44)
+!46 = !DILocation(line: 0, scope: !44)
+!47 = !DILocation(line: 12, column: 8, scope: !44)
+!48 = !DILocation(line: 12, scope: !44)
+!49 = !DILocation(line: 12, column: 19, scope: !50)
+!50 = distinct !DILexicalBlock(scope: !44, file: !3, line: 12, column: 3)
+!51 = !DILocation(line: 12, column: 21, scope: !50)
+!52 = !DILocation(line: 12, column: 3, scope: !44)
+!53 = !DILocation(line: 0, scope: !39)
+!54 = !DILocation(line: 15, column: 1, scope: !39)
+!55 = !DILocation(line: 13, column: 7, scope: !56)
+!56 = distinct !DILexicalBlock(scope: !50, file: !3, line: 12, column: 40)
+!57 = !DILocation(line: 13, column: 7, scope: !58)
+!58 = !DILexicalBlockFile(scope: !56, file: !3, discriminator: 455082031)
+!59 = !DILocation(line: 12, column: 36, scope: !50)
+!60 = !DILocation(line: 12, column: 3, scope: !50)
+!61 = distinct !{!61, !52, !62, !63}
+!62 = !DILocation(line: 14, column: 3, scope: !44)
+!63 = !{!"llvm.loop.mustprogress"}
More information about the llvm-commits
mailing list