Skip to content

Commit 3376a78

Browse files
author
Diego Novillo
committedSep 17, 2015
GCC AutoFDO profile reader - Initial support.
This adds enough machinery to support reading simple GCC AutoFDO profiles. It now supports reading flat profiles (no function calls). Subsequent patches will add support for: - Inlined calls (in particular, the inline call stack is not traversed to accumulate samples). - Working sets and modules. These are used mostly for GCC's LIPO optimizations, so they're not needed in LLVM atm. I'm not sure that we will ever need them. For now, I've if0'd around the calls. The patch also adds support in GCOV.h for gcov version V704 (generated by GCC's profile conversion tool). llvm-svn: 247874
1 parent c6d032a commit 3376a78

File tree

7 files changed

+580
-13
lines changed

7 files changed

+580
-13
lines changed
 

‎llvm/include/llvm/ProfileData/SampleProf.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ enum class sampleprof_error {
3232
too_large,
3333
truncated,
3434
malformed,
35-
unrecognized_format
35+
unrecognized_format,
36+
not_implemented
3637
};
3738

3839
inline std::error_code make_error_code(sampleprof_error E) {

‎llvm/include/llvm/ProfileData/SampleProfReader.h

+83-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/Support/Debug.h"
2525
#include "llvm/Support/ErrorHandling.h"
2626
#include "llvm/Support/ErrorOr.h"
27+
#include "llvm/Support/GCOV.h"
2728
#include "llvm/Support/MemoryBuffer.h"
2829
#include "llvm/Support/raw_ostream.h"
2930

@@ -57,7 +58,7 @@ namespace sampleprof {
5758
///
5859
/// The reader supports two file formats: text and binary. The text format
5960
/// is useful for debugging and testing, while the binary format is more
60-
/// compact. They can both be used interchangeably.
61+
/// compact and I/O efficient. They can both be used interchangeably.
6162
class SampleProfileReader {
6263
public:
6364
SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
@@ -86,7 +87,7 @@ class SampleProfileReader {
8687
StringMap<FunctionSamples> &getProfiles() { return Profiles; }
8788

8889
/// \brief Report a parse error message.
89-
void reportParseError(int64_t LineNumber, Twine Msg) const {
90+
void reportError(int64_t LineNumber, Twine Msg) const {
9091
Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(),
9192
LineNumber, Msg));
9293
}
@@ -163,6 +164,86 @@ class SampleProfileReaderBinary : public SampleProfileReader {
163164
const uint8_t *End;
164165
};
165166

167+
// Represents the source position in GCC sample profiles.
168+
struct SourceInfo {
169+
SourceInfo()
170+
: FuncName(), DirName(), FileName(), StartLine(0), Line(0),
171+
Discriminator(0) {}
172+
173+
SourceInfo(StringRef FuncName, StringRef DirName, StringRef FileName,
174+
uint32_t StartLine, uint32_t Line, uint32_t Discriminator)
175+
: FuncName(FuncName), DirName(DirName), FileName(FileName),
176+
StartLine(StartLine), Line(Line), Discriminator(Discriminator) {}
177+
178+
bool operator<(const SourceInfo &p) const;
179+
180+
uint32_t Offset() const { return ((Line - StartLine) << 16) | Discriminator; }
181+
182+
bool Malformed() const { return Line < StartLine; }
183+
184+
StringRef FuncName;
185+
StringRef DirName;
186+
StringRef FileName;
187+
uint32_t StartLine;
188+
uint32_t Line;
189+
uint32_t Discriminator;
190+
};
191+
192+
typedef std::vector<SourceInfo> SourceStack;
193+
194+
// Supported histogram types in GCC. Currently, we only need support for
195+
// call target histograms.
196+
enum HistType {
197+
HIST_TYPE_INTERVAL,
198+
HIST_TYPE_POW2,
199+
HIST_TYPE_SINGLE_VALUE,
200+
HIST_TYPE_CONST_DELTA,
201+
HIST_TYPE_INDIR_CALL,
202+
HIST_TYPE_AVERAGE,
203+
HIST_TYPE_IOR,
204+
HIST_TYPE_INDIR_CALL_TOPN
205+
};
206+
207+
class SampleProfileReaderGCC : public SampleProfileReader {
208+
public:
209+
SampleProfileReaderGCC(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
210+
: SampleProfileReader(std::move(B), C), GcovBuffer(Buffer.get()) {}
211+
212+
/// \brief Read and validate the file header.
213+
std::error_code readHeader() override;
214+
215+
/// \brief Read sample profiles from the associated file.
216+
std::error_code read() override;
217+
218+
/// \brief Return true if \p Buffer is in the format supported by this class.
219+
static bool hasFormat(const MemoryBuffer &Buffer);
220+
221+
protected:
222+
std::error_code readNameTable();
223+
std::error_code addSourceCount(StringRef Name, const SourceStack &Src,
224+
uint64_t Count);
225+
std::error_code readOneFunctionProfile(const SourceStack &Stack, bool Update);
226+
std::error_code readFunctionProfiles();
227+
std::error_code readModuleGroup();
228+
std::error_code readWorkingSet();
229+
std::error_code skipNextWord();
230+
template <typename T> ErrorOr<T> readNumber();
231+
ErrorOr<StringRef> readString();
232+
233+
/// \brief Read the section tag and check that it's the same as \p Expected.
234+
std::error_code readSectionTag(uint32_t Expected);
235+
236+
/// GCOV buffer containing the profile.
237+
GCOVBuffer GcovBuffer;
238+
239+
/// Function names in this profile.
240+
std::vector<std::string> Names;
241+
242+
/// GCOV tags used to separate sections in the profile file.
243+
static const uint32_t GCOVTagAFDOFileNames = 0xaa000000;
244+
static const uint32_t GCOVTagAFDOFunction = 0xac000000;
245+
};
246+
166247
} // End namespace sampleprof
167248

168249
} // End namespace llvm

‎llvm/include/llvm/Support/GCOV.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class GCOVBlock;
3030
class FileInfo;
3131

3232
namespace GCOV {
33-
enum GCOVVersion { V402, V404 };
33+
enum GCOVVersion { V402, V404, V704 };
3434
} // end GCOV namespace
3535

3636
/// GCOVOptions - A struct for passing gcov options between functions.
@@ -90,6 +90,11 @@ class GCOVBuffer {
9090
Version = GCOV::V404;
9191
return true;
9292
}
93+
if (VersionStr == "*704") {
94+
Cursor += 4;
95+
Version = GCOV::V704;
96+
return true;
97+
}
9398
errs() << "Unexpected version: " << VersionStr << ".\n";
9499
return false;
95100
}

‎llvm/lib/ProfileData/SampleProf.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class SampleProfErrorCategoryType : public std::error_category {
3838
return "Malformed profile data";
3939
case sampleprof_error::unrecognized_format:
4040
return "Unrecognized profile encoding format";
41+
case sampleprof_error::not_implemented:
42+
return "Unimplemented feature";
4143
}
4244
llvm_unreachable("A value of sampleprof_error has no message.");
4345
}

‎llvm/lib/ProfileData/SampleProfReader.cpp

+269-9
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ std::error_code SampleProfileReaderText::read() {
173173
// should not begin with a number.
174174
SmallVector<StringRef, 4> Matches;
175175
if (!HeadRE.match(*LineIt, &Matches)) {
176-
reportParseError(LineIt.line_number(),
177-
"Expected 'mangled_name:NUM:NUM', found " + *LineIt);
176+
reportError(LineIt.line_number(),
177+
"Expected 'mangled_name:NUM:NUM', found " + *LineIt);
178178
return sampleprof_error::malformed;
179179
}
180180
assert(Matches.size() == 4);
@@ -192,9 +192,9 @@ std::error_code SampleProfileReaderText::read() {
192192
// EOF or when we see the start of the next function.
193193
while (!LineIt.is_at_eof() && isdigit((*LineIt)[0])) {
194194
if (!LineSampleRE.match(*LineIt, &Matches)) {
195-
reportParseError(
196-
LineIt.line_number(),
197-
"Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " + *LineIt);
195+
reportError(LineIt.line_number(),
196+
"Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
197+
*LineIt);
198198
return sampleprof_error::malformed;
199199
}
200200
assert(Matches.size() == 5);
@@ -210,8 +210,8 @@ std::error_code SampleProfileReaderText::read() {
210210
while (CallsLine != "") {
211211
SmallVector<StringRef, 3> CallSample;
212212
if (!CallSampleRE.match(CallsLine, &CallSample)) {
213-
reportParseError(LineIt.line_number(),
214-
"Expected 'mangled_name:NUM', found " + CallsLine);
213+
reportError(LineIt.line_number(),
214+
"Expected 'mangled_name:NUM', found " + CallsLine);
215215
return sampleprof_error::malformed;
216216
}
217217
StringRef CalledFunction = CallSample[1];
@@ -243,7 +243,7 @@ template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() {
243243
EC = sampleprof_error::success;
244244

245245
if (EC) {
246-
reportParseError(0, EC.message());
246+
reportError(0, EC.message());
247247
return EC;
248248
}
249249

@@ -256,7 +256,7 @@ ErrorOr<StringRef> SampleProfileReaderBinary::readString() {
256256
StringRef Str(reinterpret_cast<const char *>(Data));
257257
if (Data + Str.size() + 1 > End) {
258258
EC = sampleprof_error::truncated;
259-
reportParseError(0, EC.message());
259+
reportError(0, EC.message());
260260
return EC;
261261
}
262262

@@ -353,6 +353,264 @@ bool SampleProfileReaderBinary::hasFormat(const MemoryBuffer &Buffer) {
353353
return Magic == SPMagic();
354354
}
355355

356+
bool SourceInfo::operator<(const SourceInfo &P) const {
357+
if (Line != P.Line)
358+
return Line < P.Line;
359+
if (StartLine != P.StartLine)
360+
return StartLine < P.StartLine;
361+
if (Discriminator != P.Discriminator)
362+
return Discriminator < P.Discriminator;
363+
return FuncName < P.FuncName;
364+
}
365+
366+
std::error_code SampleProfileReaderGCC::skipNextWord() {
367+
uint32_t dummy;
368+
if (!GcovBuffer.readInt(dummy))
369+
return sampleprof_error::truncated;
370+
return sampleprof_error::success;
371+
}
372+
373+
template <typename T> ErrorOr<T> SampleProfileReaderGCC::readNumber() {
374+
if (sizeof(T) <= sizeof(uint32_t)) {
375+
uint32_t Val;
376+
if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max())
377+
return static_cast<T>(Val);
378+
} else if (sizeof(T) <= sizeof(uint64_t)) {
379+
uint64_t Val;
380+
if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max())
381+
return static_cast<T>(Val);
382+
}
383+
384+
std::error_code EC = sampleprof_error::malformed;
385+
reportError(0, EC.message());
386+
return EC;
387+
}
388+
389+
ErrorOr<StringRef> SampleProfileReaderGCC::readString() {
390+
StringRef Str;
391+
if (!GcovBuffer.readString(Str))
392+
return sampleprof_error::truncated;
393+
return Str;
394+
}
395+
396+
std::error_code SampleProfileReaderGCC::readHeader() {
397+
// Read the magic identifier.
398+
if (!GcovBuffer.readGCDAFormat())
399+
return sampleprof_error::unrecognized_format;
400+
401+
// Read the version number. Note - the GCC reader does not validate this
402+
// version, but the profile creator generates v704.
403+
GCOV::GCOVVersion version;
404+
if (!GcovBuffer.readGCOVVersion(version))
405+
return sampleprof_error::unrecognized_format;
406+
407+
if (version != GCOV::V704)
408+
return sampleprof_error::unsupported_version;
409+
410+
// Skip the empty integer.
411+
if (std::error_code EC = skipNextWord())
412+
return EC;
413+
414+
return sampleprof_error::success;
415+
}
416+
417+
std::error_code SampleProfileReaderGCC::readSectionTag(uint32_t Expected) {
418+
uint32_t Tag;
419+
if (!GcovBuffer.readInt(Tag))
420+
return sampleprof_error::truncated;
421+
422+
if (Tag != Expected)
423+
return sampleprof_error::malformed;
424+
425+
if (std::error_code EC = skipNextWord())
426+
return EC;
427+
428+
return sampleprof_error::success;
429+
}
430+
431+
std::error_code SampleProfileReaderGCC::readNameTable() {
432+
if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames))
433+
return EC;
434+
435+
uint32_t Size;
436+
if (!GcovBuffer.readInt(Size))
437+
return sampleprof_error::truncated;
438+
439+
for (uint32_t I = 0; I < Size; ++I) {
440+
StringRef Str;
441+
if (!GcovBuffer.readString(Str))
442+
return sampleprof_error::truncated;
443+
Names.push_back(Str);
444+
}
445+
446+
return sampleprof_error::success;
447+
}
448+
449+
std::error_code SampleProfileReaderGCC::readFunctionProfiles() {
450+
if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction))
451+
return EC;
452+
453+
uint32_t NumFunctions;
454+
if (!GcovBuffer.readInt(NumFunctions))
455+
return sampleprof_error::truncated;
456+
457+
SourceStack Stack;
458+
for (uint32_t I = 0; I < NumFunctions; ++I)
459+
if (std::error_code EC = readOneFunctionProfile(Stack, true))
460+
return EC;
461+
462+
return sampleprof_error::success;
463+
}
464+
465+
std::error_code SampleProfileReaderGCC::addSourceCount(StringRef Name,
466+
const SourceStack &Src,
467+
uint64_t Count) {
468+
if (Src.size() == 0 || Src[0].Malformed())
469+
return sampleprof_error::malformed;
470+
FunctionSamples &FProfile = Profiles[Name];
471+
FProfile.addTotalSamples(Count);
472+
// FIXME(dnovillo) - Properly update inline stack for FnName.
473+
FProfile.addBodySamples(Src[0].Line, Src[0].Discriminator, Count);
474+
return sampleprof_error::success;
475+
}
476+
477+
478+
std::error_code
479+
SampleProfileReaderGCC::readOneFunctionProfile(const SourceStack &Stack,
480+
bool Update) {
481+
uint64_t HeadCount = 0;
482+
if (Stack.size() == 0)
483+
if (!GcovBuffer.readInt64(HeadCount))
484+
return sampleprof_error::truncated;
485+
486+
uint32_t NameIdx;
487+
if (!GcovBuffer.readInt(NameIdx))
488+
return sampleprof_error::truncated;
489+
490+
StringRef Name(Names[NameIdx]);
491+
492+
uint32_t NumPosCounts;
493+
if (!GcovBuffer.readInt(NumPosCounts))
494+
return sampleprof_error::truncated;
495+
496+
uint32_t NumCallSites;
497+
if (!GcovBuffer.readInt(NumCallSites))
498+
return sampleprof_error::truncated;
499+
500+
if (Stack.size() == 0) {
501+
FunctionSamples &FProfile = Profiles[Name];
502+
FProfile.addHeadSamples(HeadCount);
503+
if (FProfile.getTotalSamples() > 0)
504+
Update = false;
505+
}
506+
507+
for (uint32_t I = 0; I < NumPosCounts; ++I) {
508+
uint32_t Offset;
509+
if (!GcovBuffer.readInt(Offset))
510+
return sampleprof_error::truncated;
511+
512+
uint32_t NumTargets;
513+
if (!GcovBuffer.readInt(NumTargets))
514+
return sampleprof_error::truncated;
515+
516+
uint64_t Count;
517+
if (!GcovBuffer.readInt64(Count))
518+
return sampleprof_error::truncated;
519+
520+
SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff);
521+
SourceStack NewStack;
522+
NewStack.push_back(Info);
523+
NewStack.insert(NewStack.end(), Stack.begin(), Stack.end());
524+
if (Update)
525+
addSourceCount(NewStack[NewStack.size() - 1].FuncName, NewStack, Count);
526+
527+
for (uint32_t J = 0; J < NumTargets; J++) {
528+
uint32_t HistVal;
529+
if (!GcovBuffer.readInt(HistVal))
530+
return sampleprof_error::truncated;
531+
532+
if (HistVal != HIST_TYPE_INDIR_CALL_TOPN)
533+
return sampleprof_error::malformed;
534+
535+
uint64_t TargetIdx;
536+
if (!GcovBuffer.readInt64(TargetIdx))
537+
return sampleprof_error::truncated;
538+
StringRef TargetName(Names[TargetIdx]);
539+
540+
uint64_t TargetCount;
541+
if (!GcovBuffer.readInt64(TargetCount))
542+
return sampleprof_error::truncated;
543+
544+
if (Update) {
545+
FunctionSamples &TargetProfile = Profiles[TargetName];
546+
TargetProfile.addBodySamples(NewStack[0].Line,
547+
NewStack[0].Discriminator, TargetCount);
548+
}
549+
}
550+
}
551+
552+
for (uint32_t I = 0; I < NumCallSites; I++) {
553+
// The offset is encoded as:
554+
// high 16 bits: line offset to the start of the function.
555+
// low 16 bits: discriminator.
556+
uint32_t Offset;
557+
if (!GcovBuffer.readInt(Offset))
558+
return sampleprof_error::truncated;
559+
SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff);
560+
SourceStack NewStack;
561+
NewStack.push_back(Info);
562+
NewStack.insert(NewStack.end(), Stack.begin(), Stack.end());
563+
if (std::error_code EC = readOneFunctionProfile(NewStack, Update))
564+
return EC;
565+
}
566+
567+
return sampleprof_error::success;
568+
}
569+
570+
std::error_code SampleProfileReaderGCC::readModuleGroup() {
571+
// FIXME(dnovillo) - Module support still not implemented.
572+
return sampleprof_error::not_implemented;
573+
}
574+
575+
std::error_code SampleProfileReaderGCC::readWorkingSet() {
576+
// FIXME(dnovillo) - Working sets still not implemented.
577+
return sampleprof_error::not_implemented;
578+
}
579+
580+
581+
/// \brief Read a GCC AutoFDO profile.
582+
///
583+
/// This format is generated by the Linux Perf conversion tool at
584+
/// https://github.com/google/autofdo.
585+
std::error_code SampleProfileReaderGCC::read() {
586+
// Read the string table.
587+
if (std::error_code EC = readNameTable())
588+
return EC;
589+
590+
// Read the source profile.
591+
if (std::error_code EC = readFunctionProfiles())
592+
return EC;
593+
594+
// FIXME(dnovillo) - Module groups and working set support are not
595+
// yet implemented.
596+
#if 0
597+
// Read the module group file.
598+
if (std::error_code EC = readModuleGroup())
599+
return EC;
600+
601+
// Read the working set.
602+
if (std::error_code EC = readWorkingSet())
603+
return EC;
604+
#endif
605+
606+
return sampleprof_error::success;
607+
}
608+
609+
bool SampleProfileReaderGCC::hasFormat(const MemoryBuffer &Buffer) {
610+
StringRef Magic(reinterpret_cast<const char *>(Buffer.getBufferStart()));
611+
return Magic == "adcg*704";
612+
}
613+
356614
/// \brief Prepare a memory buffer for the contents of \p Filename.
357615
///
358616
/// \returns an error code indicating the status of the buffer.
@@ -389,6 +647,8 @@ SampleProfileReader::create(StringRef Filename, LLVMContext &C) {
389647
std::unique_ptr<SampleProfileReader> Reader;
390648
if (SampleProfileReaderBinary::hasFormat(*Buffer))
391649
Reader.reset(new SampleProfileReaderBinary(std::move(Buffer), C));
650+
else if (SampleProfileReaderGCC::hasFormat(*Buffer))
651+
Reader.reset(new SampleProfileReaderGCC(std::move(Buffer), C));
392652
else
393653
Reader.reset(new SampleProfileReaderText(std::move(Buffer), C));
394654

Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/gcc-simple.afdo -S | FileCheck %s
2+
;
3+
; Original code:
4+
;
5+
; #include <stdlib.h>
6+
;
7+
; long long int foo(long i) {
8+
; if (rand() < 500) return 2; else if (rand() > 5000) return 10; else return 90;
9+
; }
10+
;
11+
; int main() {
12+
; long long int sum = 0;
13+
; for (int k = 0; k < 3000; k++)
14+
; for (int i = 0; i < 200000; i++) sum += foo(i);
15+
; return sum > 0 ? 0 : 1;
16+
; }
17+
;
18+
; This test was compiled down to bytecode at -O0 to avoid inlining foo() into
19+
; main(). The profile was generated using a GCC-generated binary (also compiled
20+
; at -O0). The conversion from the Linux Perf profile to the GCC autofdo
21+
; profile used the converter at https://github.com/google/autofdo
22+
;
23+
; $ gcc -g -O0 gcc-simple.cc -o gcc-simple
24+
; $ perf record -b ./gcc-simple
25+
; $ create_gcov --binary=gcc-simple --gcov=gcc-simple.afdo
26+
27+
define i64 @_Z3fool(i64 %i) #0 {
28+
; CHECK: !prof ![[EC1:[0-9]+]]
29+
entry:
30+
%retval = alloca i64, align 8
31+
%i.addr = alloca i64, align 8
32+
store i64 %i, i64* %i.addr, align 8
33+
call void @llvm.dbg.declare(metadata i64* %i.addr, metadata !16, metadata !17), !dbg !18
34+
%call = call i32 @rand() #3, !dbg !19
35+
%cmp = icmp slt i32 %call, 500, !dbg !21
36+
br i1 %cmp, label %if.then, label %if.else, !dbg !22
37+
; CHECK: !prof ![[PROF1:[0-9]+]]
38+
39+
if.then: ; preds = %entry
40+
store i64 2, i64* %retval, align 8, !dbg !23
41+
br label %return, !dbg !23
42+
43+
if.else: ; preds = %entry
44+
%call1 = call i32 @rand() #3, !dbg !25
45+
%cmp2 = icmp sgt i32 %call1, 5000, !dbg !28
46+
br i1 %cmp2, label %if.then.3, label %if.else.4, !dbg !29
47+
; CHECK: !prof ![[PROF2:[0-9]+]]
48+
49+
if.then.3: ; preds = %if.else
50+
store i64 10, i64* %retval, align 8, !dbg !30
51+
br label %return, !dbg !30
52+
53+
if.else.4: ; preds = %if.else
54+
store i64 90, i64* %retval, align 8, !dbg !32
55+
br label %return, !dbg !32
56+
57+
return: ; preds = %if.else.4, %if.then.3, %if.then
58+
%0 = load i64, i64* %retval, align 8, !dbg !34
59+
ret i64 %0, !dbg !34
60+
}
61+
62+
; Function Attrs: nounwind readnone
63+
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
64+
65+
; Function Attrs: nounwind
66+
declare i32 @rand() #2
67+
68+
; Function Attrs: nounwind uwtable
69+
define i32 @main() #0 {
70+
; CHECK: !prof ![[EC2:[0-9]+]]
71+
entry:
72+
%retval = alloca i32, align 4
73+
%sum = alloca i64, align 8
74+
%k = alloca i32, align 4
75+
%i = alloca i32, align 4
76+
store i32 0, i32* %retval, align 4
77+
call void @llvm.dbg.declare(metadata i64* %sum, metadata !35, metadata !17), !dbg !36
78+
store i64 0, i64* %sum, align 8, !dbg !36
79+
call void @llvm.dbg.declare(metadata i32* %k, metadata !37, metadata !17), !dbg !39
80+
store i32 0, i32* %k, align 4, !dbg !39
81+
br label %for.cond, !dbg !40
82+
83+
for.cond: ; preds = %for.inc.4, %entry
84+
%0 = load i32, i32* %k, align 4, !dbg !41
85+
%cmp = icmp slt i32 %0, 3000, !dbg !45
86+
br i1 %cmp, label %for.body, label %for.end.6, !dbg !46
87+
; CHECK: !prof ![[PROF3:[0-9]+]]
88+
89+
for.body: ; preds = %for.cond
90+
call void @llvm.dbg.declare(metadata i32* %i, metadata !47, metadata !17), !dbg !49
91+
store i32 0, i32* %i, align 4, !dbg !49
92+
br label %for.cond.1, !dbg !50
93+
94+
for.cond.1: ; preds = %for.inc, %for.body
95+
%1 = load i32, i32* %i, align 4, !dbg !51
96+
%cmp2 = icmp slt i32 %1, 200000, !dbg !55
97+
br i1 %cmp2, label %for.body.3, label %for.end, !dbg !56
98+
; CHECK: !prof ![[PROF4:[0-9]+]]
99+
100+
for.body.3: ; preds = %for.cond.1
101+
%2 = load i32, i32* %i, align 4, !dbg !57
102+
%conv = sext i32 %2 to i64, !dbg !57
103+
%call = call i64 @_Z3fool(i64 %conv), !dbg !59
104+
%3 = load i64, i64* %sum, align 8, !dbg !60
105+
%add = add nsw i64 %3, %call, !dbg !60
106+
store i64 %add, i64* %sum, align 8, !dbg !60
107+
br label %for.inc, !dbg !61
108+
109+
for.inc: ; preds = %for.body.3
110+
%4 = load i32, i32* %i, align 4, !dbg !62
111+
%inc = add nsw i32 %4, 1, !dbg !62
112+
store i32 %inc, i32* %i, align 4, !dbg !62
113+
br label %for.cond.1, !dbg !64
114+
115+
for.end: ; preds = %for.cond.1
116+
br label %for.inc.4, !dbg !65
117+
118+
for.inc.4: ; preds = %for.end
119+
%5 = load i32, i32* %k, align 4, !dbg !67
120+
%inc5 = add nsw i32 %5, 1, !dbg !67
121+
store i32 %inc5, i32* %k, align 4, !dbg !67
122+
br label %for.cond, !dbg !68
123+
124+
for.end.6: ; preds = %for.cond
125+
%6 = load i64, i64* %sum, align 8, !dbg !69
126+
%cmp7 = icmp sgt i64 %6, 0, !dbg !70
127+
%cond = select i1 %cmp7, i32 0, i32 1, !dbg !69
128+
ret i32 %cond, !dbg !71
129+
}
130+
131+
; CHECK ![[EC1]] = !{!"function_entry_count", i64 24108}
132+
; CHECK ![[PROF1]] = !{!"branch_weights", i32 1, i32 30124}
133+
; CHECK ![[PROF2]] = !{!"branch_weights", i32 30177, i32 29579}
134+
; CHECK ![[EC2]] = !{!"function_entry_count", i64 0}
135+
; CHECK ![[PROF3]] = !{!"branch_weights", i32 1, i32 1}
136+
; CHECK ![[PROF4]] = !{!"branch_weights", i32 1, i32 20238}
137+
138+
attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
139+
attributes #1 = { nounwind readnone }
140+
attributes #2 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
141+
attributes #3 = { nounwind }
142+
143+
!llvm.dbg.cu = !{!0}
144+
!llvm.module.flags = !{!13, !14}
145+
!llvm.ident = !{!15}
146+
147+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 247554) (llvm/trunk 247557)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3)
148+
!1 = !DIFile(filename: "discriminator.cc", directory: "/usr/local/google/home/dnovillo/llvm/test/autofdo")
149+
!2 = !{}
150+
!3 = !{!4, !9}
151+
!4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fool", scope: !1, file: !1, line: 3, type: !5, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i64 (i64)* @_Z3fool, variables: !2)
152+
!5 = !DISubroutineType(types: !6)
153+
!6 = !{!7, !8}
154+
!7 = !DIBasicType(name: "long long int", size: 64, align: 64, encoding: DW_ATE_signed)
155+
!8 = !DIBasicType(name: "long int", size: 64, align: 64, encoding: DW_ATE_signed)
156+
!9 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !10, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @main, variables: !2)
157+
!10 = !DISubroutineType(types: !11)
158+
!11 = !{!12}
159+
!12 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
160+
!13 = !{i32 2, !"Dwarf Version", i32 4}
161+
!14 = !{i32 2, !"Debug Info Version", i32 3}
162+
!15 = !{!"clang version 3.8.0 (trunk 247554) (llvm/trunk 247557)"}
163+
!16 = !DILocalVariable(name: "i", arg: 1, scope: !4, file: !1, line: 3, type: !8)
164+
!17 = !DIExpression()
165+
!18 = !DILocation(line: 3, column: 24, scope: !4)
166+
!19 = !DILocation(line: 4, column: 7, scope: !20)
167+
!20 = distinct !DILexicalBlock(scope: !4, file: !1, line: 4, column: 7)
168+
!21 = !DILocation(line: 4, column: 14, scope: !20)
169+
!22 = !DILocation(line: 4, column: 7, scope: !4)
170+
!23 = !DILocation(line: 4, column: 21, scope: !24)
171+
!24 = !DILexicalBlockFile(scope: !20, file: !1, discriminator: 1)
172+
!25 = !DILocation(line: 4, column: 40, scope: !26)
173+
!26 = !DILexicalBlockFile(scope: !27, file: !1, discriminator: 2)
174+
!27 = distinct !DILexicalBlock(scope: !20, file: !1, line: 4, column: 40)
175+
!28 = !DILocation(line: 4, column: 47, scope: !27)
176+
!29 = !DILocation(line: 4, column: 40, scope: !20)
177+
!30 = !DILocation(line: 4, column: 55, scope: !31)
178+
!31 = !DILexicalBlockFile(scope: !27, file: !1, discriminator: 3)
179+
!32 = !DILocation(line: 4, column: 71, scope: !33)
180+
!33 = !DILexicalBlockFile(scope: !27, file: !1, discriminator: 4)
181+
!34 = !DILocation(line: 5, column: 1, scope: !4)
182+
!35 = !DILocalVariable(name: "sum", scope: !9, file: !1, line: 8, type: !7)
183+
!36 = !DILocation(line: 8, column: 17, scope: !9)
184+
!37 = !DILocalVariable(name: "k", scope: !38, file: !1, line: 9, type: !12)
185+
!38 = distinct !DILexicalBlock(scope: !9, file: !1, line: 9, column: 3)
186+
!39 = !DILocation(line: 9, column: 12, scope: !38)
187+
!40 = !DILocation(line: 9, column: 8, scope: !38)
188+
!41 = !DILocation(line: 9, column: 19, scope: !42)
189+
!42 = !DILexicalBlockFile(scope: !43, file: !1, discriminator: 2)
190+
!43 = !DILexicalBlockFile(scope: !44, file: !1, discriminator: 1)
191+
!44 = distinct !DILexicalBlock(scope: !38, file: !1, line: 9, column: 3)
192+
!45 = !DILocation(line: 9, column: 21, scope: !44)
193+
!46 = !DILocation(line: 9, column: 3, scope: !38)
194+
!47 = !DILocalVariable(name: "i", scope: !48, file: !1, line: 10, type: !12)
195+
!48 = distinct !DILexicalBlock(scope: !44, file: !1, line: 10, column: 5)
196+
!49 = !DILocation(line: 10, column: 14, scope: !48)
197+
!50 = !DILocation(line: 10, column: 10, scope: !48)
198+
!51 = !DILocation(line: 10, column: 21, scope: !52)
199+
!52 = !DILexicalBlockFile(scope: !53, file: !1, discriminator: 5)
200+
!53 = !DILexicalBlockFile(scope: !54, file: !1, discriminator: 1)
201+
!54 = distinct !DILexicalBlock(scope: !48, file: !1, line: 10, column: 5)
202+
!55 = !DILocation(line: 10, column: 23, scope: !54)
203+
!56 = !DILocation(line: 10, column: 5, scope: !48)
204+
!57 = !DILocation(line: 10, column: 49, scope: !58)
205+
!58 = !DILexicalBlockFile(scope: !54, file: !1, discriminator: 2)
206+
!59 = !DILocation(line: 10, column: 45, scope: !54)
207+
!60 = !DILocation(line: 10, column: 42, scope: !54)
208+
!61 = !DILocation(line: 10, column: 38, scope: !54)
209+
!62 = !DILocation(line: 10, column: 34, scope: !63)
210+
!63 = !DILexicalBlockFile(scope: !54, file: !1, discriminator: 4)
211+
!64 = !DILocation(line: 10, column: 5, scope: !54)
212+
!65 = !DILocation(line: 10, column: 50, scope: !66)
213+
!66 = !DILexicalBlockFile(scope: !48, file: !1, discriminator: 3)
214+
!67 = !DILocation(line: 9, column: 30, scope: !44)
215+
!68 = !DILocation(line: 9, column: 3, scope: !44)
216+
!69 = !DILocation(line: 11, column: 10, scope: !9)
217+
!70 = !DILocation(line: 11, column: 14, scope: !9)
218+
!71 = !DILocation(line: 11, column: 3, scope: !9)

0 commit comments

Comments
 (0)
Please sign in to comment.