diff options
-rw-r--r-- | llvm/include/llvm/ProfileData/SampleProf.h | 3 | ||||
-rw-r--r-- | llvm/include/llvm/ProfileData/SampleProfReader.h | 85 | ||||
-rw-r--r-- | llvm/include/llvm/Support/GCOV.h | 7 | ||||
-rw-r--r-- | llvm/lib/ProfileData/SampleProf.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/ProfileData/SampleProfReader.cpp | 278 | ||||
-rw-r--r-- | llvm/test/Transforms/SampleProfile/Inputs/gcc-simple.afdo | bin | 0 -> 1972 bytes | |||
-rw-r--r-- | llvm/test/Transforms/SampleProfile/gcc-simple.ll | 218 |
7 files changed, 580 insertions, 13 deletions
diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h index 1b82e55aa77..1eea95d61ac 100644 --- a/llvm/include/llvm/ProfileData/SampleProf.h +++ b/llvm/include/llvm/ProfileData/SampleProf.h @@ -32,7 +32,8 @@ enum class sampleprof_error { too_large, truncated, malformed, - unrecognized_format + unrecognized_format, + not_implemented }; inline std::error_code make_error_code(sampleprof_error E) { diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h index c082a1abe95..770d25ea52a 100644 --- a/llvm/include/llvm/ProfileData/SampleProfReader.h +++ b/llvm/include/llvm/ProfileData/SampleProfReader.h @@ -24,6 +24,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/GCOV.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" @@ -57,7 +58,7 @@ namespace sampleprof { /// /// The reader supports two file formats: text and binary. The text format /// is useful for debugging and testing, while the binary format is more -/// compact. They can both be used interchangeably. +/// compact and I/O efficient. They can both be used interchangeably. class SampleProfileReader { public: SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) @@ -86,7 +87,7 @@ public: StringMap<FunctionSamples> &getProfiles() { return Profiles; } /// \brief Report a parse error message. - void reportParseError(int64_t LineNumber, Twine Msg) const { + void reportError(int64_t LineNumber, Twine Msg) const { Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(), LineNumber, Msg)); } @@ -163,6 +164,86 @@ protected: const uint8_t *End; }; +// Represents the source position in GCC sample profiles. +struct SourceInfo { + SourceInfo() + : FuncName(), DirName(), FileName(), StartLine(0), Line(0), + Discriminator(0) {} + + SourceInfo(StringRef FuncName, StringRef DirName, StringRef FileName, + uint32_t StartLine, uint32_t Line, uint32_t Discriminator) + : FuncName(FuncName), DirName(DirName), FileName(FileName), + StartLine(StartLine), Line(Line), Discriminator(Discriminator) {} + + bool operator<(const SourceInfo &p) const; + + uint32_t Offset() const { return ((Line - StartLine) << 16) | Discriminator; } + + bool Malformed() const { return Line < StartLine; } + + StringRef FuncName; + StringRef DirName; + StringRef FileName; + uint32_t StartLine; + uint32_t Line; + uint32_t Discriminator; +}; + +typedef std::vector<SourceInfo> SourceStack; + +// Supported histogram types in GCC. Currently, we only need support for +// call target histograms. +enum HistType { + HIST_TYPE_INTERVAL, + HIST_TYPE_POW2, + HIST_TYPE_SINGLE_VALUE, + HIST_TYPE_CONST_DELTA, + HIST_TYPE_INDIR_CALL, + HIST_TYPE_AVERAGE, + HIST_TYPE_IOR, + HIST_TYPE_INDIR_CALL_TOPN +}; + +class SampleProfileReaderGCC : public SampleProfileReader { +public: + SampleProfileReaderGCC(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) + : SampleProfileReader(std::move(B), C), GcovBuffer(Buffer.get()) {} + + /// \brief Read and validate the file header. + std::error_code readHeader() override; + + /// \brief Read sample profiles from the associated file. + std::error_code read() override; + + /// \brief Return true if \p Buffer is in the format supported by this class. + static bool hasFormat(const MemoryBuffer &Buffer); + +protected: + std::error_code readNameTable(); + std::error_code addSourceCount(StringRef Name, const SourceStack &Src, + uint64_t Count); + std::error_code readOneFunctionProfile(const SourceStack &Stack, bool Update); + std::error_code readFunctionProfiles(); + std::error_code readModuleGroup(); + std::error_code readWorkingSet(); + std::error_code skipNextWord(); + template <typename T> ErrorOr<T> readNumber(); + ErrorOr<StringRef> readString(); + + /// \brief Read the section tag and check that it's the same as \p Expected. + std::error_code readSectionTag(uint32_t Expected); + + /// GCOV buffer containing the profile. + GCOVBuffer GcovBuffer; + + /// Function names in this profile. + std::vector<std::string> Names; + + /// GCOV tags used to separate sections in the profile file. + static const uint32_t GCOVTagAFDOFileNames = 0xaa000000; + static const uint32_t GCOVTagAFDOFunction = 0xac000000; +}; + } // End namespace sampleprof } // End namespace llvm diff --git a/llvm/include/llvm/Support/GCOV.h b/llvm/include/llvm/Support/GCOV.h index c2e34bd3eae..4c35128deca 100644 --- a/llvm/include/llvm/Support/GCOV.h +++ b/llvm/include/llvm/Support/GCOV.h @@ -30,7 +30,7 @@ class GCOVBlock; class FileInfo; namespace GCOV { -enum GCOVVersion { V402, V404 }; +enum GCOVVersion { V402, V404, V704 }; } // end GCOV namespace /// GCOVOptions - A struct for passing gcov options between functions. @@ -90,6 +90,11 @@ public: Version = GCOV::V404; return true; } + if (VersionStr == "*704") { + Cursor += 4; + Version = GCOV::V704; + return true; + } errs() << "Unexpected version: " << VersionStr << ".\n"; return false; } diff --git a/llvm/lib/ProfileData/SampleProf.cpp b/llvm/lib/ProfileData/SampleProf.cpp index 920c48a2464..027fa81790b 100644 --- a/llvm/lib/ProfileData/SampleProf.cpp +++ b/llvm/lib/ProfileData/SampleProf.cpp @@ -38,6 +38,8 @@ class SampleProfErrorCategoryType : public std::error_category { return "Malformed profile data"; case sampleprof_error::unrecognized_format: return "Unrecognized profile encoding format"; + case sampleprof_error::not_implemented: + return "Unimplemented feature"; } llvm_unreachable("A value of sampleprof_error has no message."); } diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp index b39bfd6e2ec..70964cb27e1 100644 --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -173,8 +173,8 @@ std::error_code SampleProfileReaderText::read() { // should not begin with a number. SmallVector<StringRef, 4> Matches; if (!HeadRE.match(*LineIt, &Matches)) { - reportParseError(LineIt.line_number(), - "Expected 'mangled_name:NUM:NUM', found " + *LineIt); + reportError(LineIt.line_number(), + "Expected 'mangled_name:NUM:NUM', found " + *LineIt); return sampleprof_error::malformed; } assert(Matches.size() == 4); @@ -192,9 +192,9 @@ std::error_code SampleProfileReaderText::read() { // EOF or when we see the start of the next function. while (!LineIt.is_at_eof() && isdigit((*LineIt)[0])) { if (!LineSampleRE.match(*LineIt, &Matches)) { - reportParseError( - LineIt.line_number(), - "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " + *LineIt); + reportError(LineIt.line_number(), + "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " + + *LineIt); return sampleprof_error::malformed; } assert(Matches.size() == 5); @@ -210,8 +210,8 @@ std::error_code SampleProfileReaderText::read() { while (CallsLine != "") { SmallVector<StringRef, 3> CallSample; if (!CallSampleRE.match(CallsLine, &CallSample)) { - reportParseError(LineIt.line_number(), - "Expected 'mangled_name:NUM', found " + CallsLine); + reportError(LineIt.line_number(), + "Expected 'mangled_name:NUM', found " + CallsLine); return sampleprof_error::malformed; } StringRef CalledFunction = CallSample[1]; @@ -243,7 +243,7 @@ template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() { EC = sampleprof_error::success; if (EC) { - reportParseError(0, EC.message()); + reportError(0, EC.message()); return EC; } @@ -256,7 +256,7 @@ ErrorOr<StringRef> SampleProfileReaderBinary::readString() { StringRef Str(reinterpret_cast<const char *>(Data)); if (Data + Str.size() + 1 > End) { EC = sampleprof_error::truncated; - reportParseError(0, EC.message()); + reportError(0, EC.message()); return EC; } @@ -353,6 +353,264 @@ bool SampleProfileReaderBinary::hasFormat(const MemoryBuffer &Buffer) { return Magic == SPMagic(); } +bool SourceInfo::operator<(const SourceInfo &P) const { + if (Line != P.Line) + return Line < P.Line; + if (StartLine != P.StartLine) + return StartLine < P.StartLine; + if (Discriminator != P.Discriminator) + return Discriminator < P.Discriminator; + return FuncName < P.FuncName; +} + +std::error_code SampleProfileReaderGCC::skipNextWord() { + uint32_t dummy; + if (!GcovBuffer.readInt(dummy)) + return sampleprof_error::truncated; + return sampleprof_error::success; +} + +template <typename T> ErrorOr<T> SampleProfileReaderGCC::readNumber() { + if (sizeof(T) <= sizeof(uint32_t)) { + uint32_t Val; + if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max()) + return static_cast<T>(Val); + } else if (sizeof(T) <= sizeof(uint64_t)) { + uint64_t Val; + if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max()) + return static_cast<T>(Val); + } + + std::error_code EC = sampleprof_error::malformed; + reportError(0, EC.message()); + return EC; +} + +ErrorOr<StringRef> SampleProfileReaderGCC::readString() { + StringRef Str; + if (!GcovBuffer.readString(Str)) + return sampleprof_error::truncated; + return Str; +} + +std::error_code SampleProfileReaderGCC::readHeader() { + // Read the magic identifier. + if (!GcovBuffer.readGCDAFormat()) + return sampleprof_error::unrecognized_format; + + // Read the version number. Note - the GCC reader does not validate this + // version, but the profile creator generates v704. + GCOV::GCOVVersion version; + if (!GcovBuffer.readGCOVVersion(version)) + return sampleprof_error::unrecognized_format; + + if (version != GCOV::V704) + return sampleprof_error::unsupported_version; + + // Skip the empty integer. + if (std::error_code EC = skipNextWord()) + return EC; + + return sampleprof_error::success; +} + +std::error_code SampleProfileReaderGCC::readSectionTag(uint32_t Expected) { + uint32_t Tag; + if (!GcovBuffer.readInt(Tag)) + return sampleprof_error::truncated; + + if (Tag != Expected) + return sampleprof_error::malformed; + + if (std::error_code EC = skipNextWord()) + return EC; + + return sampleprof_error::success; +} + +std::error_code SampleProfileReaderGCC::readNameTable() { + if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames)) + return EC; + + uint32_t Size; + if (!GcovBuffer.readInt(Size)) + return sampleprof_error::truncated; + + for (uint32_t I = 0; I < Size; ++I) { + StringRef Str; + if (!GcovBuffer.readString(Str)) + return sampleprof_error::truncated; + Names.push_back(Str); + } + + return sampleprof_error::success; +} + +std::error_code SampleProfileReaderGCC::readFunctionProfiles() { + if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction)) + return EC; + + uint32_t NumFunctions; + if (!GcovBuffer.readInt(NumFunctions)) + return sampleprof_error::truncated; + + SourceStack Stack; + for (uint32_t I = 0; I < NumFunctions; ++I) + if (std::error_code EC = readOneFunctionProfile(Stack, true)) + return EC; + + return sampleprof_error::success; +} + +std::error_code SampleProfileReaderGCC::addSourceCount(StringRef Name, + const SourceStack &Src, + uint64_t Count) { + if (Src.size() == 0 || Src[0].Malformed()) + return sampleprof_error::malformed; + FunctionSamples &FProfile = Profiles[Name]; + FProfile.addTotalSamples(Count); + // FIXME(dnovillo) - Properly update inline stack for FnName. + FProfile.addBodySamples(Src[0].Line, Src[0].Discriminator, Count); + return sampleprof_error::success; +} + + +std::error_code +SampleProfileReaderGCC::readOneFunctionProfile(const SourceStack &Stack, + bool Update) { + uint64_t HeadCount = 0; + if (Stack.size() == 0) + if (!GcovBuffer.readInt64(HeadCount)) + return sampleprof_error::truncated; + + uint32_t NameIdx; + if (!GcovBuffer.readInt(NameIdx)) + return sampleprof_error::truncated; + + StringRef Name(Names[NameIdx]); + + uint32_t NumPosCounts; + if (!GcovBuffer.readInt(NumPosCounts)) + return sampleprof_error::truncated; + + uint32_t NumCallSites; + if (!GcovBuffer.readInt(NumCallSites)) + return sampleprof_error::truncated; + + if (Stack.size() == 0) { + FunctionSamples &FProfile = Profiles[Name]; + FProfile.addHeadSamples(HeadCount); + if (FProfile.getTotalSamples() > 0) + Update = false; + } + + for (uint32_t I = 0; I < NumPosCounts; ++I) { + uint32_t Offset; + if (!GcovBuffer.readInt(Offset)) + return sampleprof_error::truncated; + + uint32_t NumTargets; + if (!GcovBuffer.readInt(NumTargets)) + return sampleprof_error::truncated; + + uint64_t Count; + if (!GcovBuffer.readInt64(Count)) + return sampleprof_error::truncated; + + SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff); + SourceStack NewStack; + NewStack.push_back(Info); + NewStack.insert(NewStack.end(), Stack.begin(), Stack.end()); + if (Update) + addSourceCount(NewStack[NewStack.size() - 1].FuncName, NewStack, Count); + + for (uint32_t J = 0; J < NumTargets; J++) { + uint32_t HistVal; + if (!GcovBuffer.readInt(HistVal)) + return sampleprof_error::truncated; + + if (HistVal != HIST_TYPE_INDIR_CALL_TOPN) + return sampleprof_error::malformed; + + uint64_t TargetIdx; + if (!GcovBuffer.readInt64(TargetIdx)) + return sampleprof_error::truncated; + StringRef TargetName(Names[TargetIdx]); + + uint64_t TargetCount; + if (!GcovBuffer.readInt64(TargetCount)) + return sampleprof_error::truncated; + + if (Update) { + FunctionSamples &TargetProfile = Profiles[TargetName]; + TargetProfile.addBodySamples(NewStack[0].Line, + NewStack[0].Discriminator, TargetCount); + } + } + } + + for (uint32_t I = 0; I < NumCallSites; I++) { + // The offset is encoded as: + // high 16 bits: line offset to the start of the function. + // low 16 bits: discriminator. + uint32_t Offset; + if (!GcovBuffer.readInt(Offset)) + return sampleprof_error::truncated; + SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff); + SourceStack NewStack; + NewStack.push_back(Info); + NewStack.insert(NewStack.end(), Stack.begin(), Stack.end()); + if (std::error_code EC = readOneFunctionProfile(NewStack, Update)) + return EC; + } + + return sampleprof_error::success; +} + +std::error_code SampleProfileReaderGCC::readModuleGroup() { + // FIXME(dnovillo) - Module support still not implemented. + return sampleprof_error::not_implemented; +} + +std::error_code SampleProfileReaderGCC::readWorkingSet() { + // FIXME(dnovillo) - Working sets still not implemented. + return sampleprof_error::not_implemented; +} + + +/// \brief Read a GCC AutoFDO profile. +/// +/// This format is generated by the Linux Perf conversion tool at +/// https://github.com/google/autofdo. +std::error_code SampleProfileReaderGCC::read() { + // Read the string table. + if (std::error_code EC = readNameTable()) + return EC; + + // Read the source profile. + if (std::error_code EC = readFunctionProfiles()) + return EC; + + // FIXME(dnovillo) - Module groups and working set support are not + // yet implemented. +#if 0 + // Read the module group file. + if (std::error_code EC = readModuleGroup()) + return EC; + + // Read the working set. + if (std::error_code EC = readWorkingSet()) + return EC; +#endif + + return sampleprof_error::success; +} + +bool SampleProfileReaderGCC::hasFormat(const MemoryBuffer &Buffer) { + StringRef Magic(reinterpret_cast<const char *>(Buffer.getBufferStart())); + return Magic == "adcg*704"; +} + /// \brief Prepare a memory buffer for the contents of \p Filename. /// /// \returns an error code indicating the status of the buffer. @@ -389,6 +647,8 @@ SampleProfileReader::create(StringRef Filename, LLVMContext &C) { std::unique_ptr<SampleProfileReader> Reader; if (SampleProfileReaderBinary::hasFormat(*Buffer)) Reader.reset(new SampleProfileReaderBinary(std::move(Buffer), C)); + else if (SampleProfileReaderGCC::hasFormat(*Buffer)) + Reader.reset(new SampleProfileReaderGCC(std::move(Buffer), C)); else Reader.reset(new SampleProfileReaderText(std::move(Buffer), C)); diff --git a/llvm/test/Transforms/SampleProfile/Inputs/gcc-simple.afdo b/llvm/test/Transforms/SampleProfile/Inputs/gcc-simple.afdo Binary files differnew file mode 100644 index 00000000000..93f22ce3053 --- /dev/null +++ b/llvm/test/Transforms/SampleProfile/Inputs/gcc-simple.afdo diff --git a/llvm/test/Transforms/SampleProfile/gcc-simple.ll b/llvm/test/Transforms/SampleProfile/gcc-simple.ll new file mode 100644 index 00000000000..9a22eb2749a --- /dev/null +++ b/llvm/test/Transforms/SampleProfile/gcc-simple.ll @@ -0,0 +1,218 @@ +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/gcc-simple.afdo -S | FileCheck %s +; +; Original code: +; +; #include <stdlib.h> +; +; long long int foo(long i) { +; if (rand() < 500) return 2; else if (rand() > 5000) return 10; else return 90; +; } +; +; int main() { +; long long int sum = 0; +; for (int k = 0; k < 3000; k++) +; for (int i = 0; i < 200000; i++) sum += foo(i); +; return sum > 0 ? 0 : 1; +; } +; +; This test was compiled down to bytecode at -O0 to avoid inlining foo() into +; main(). The profile was generated using a GCC-generated binary (also compiled +; at -O0). The conversion from the Linux Perf profile to the GCC autofdo +; profile used the converter at https://github.com/google/autofdo +; +; $ gcc -g -O0 gcc-simple.cc -o gcc-simple +; $ perf record -b ./gcc-simple +; $ create_gcov --binary=gcc-simple --gcov=gcc-simple.afdo + +define i64 @_Z3fool(i64 %i) #0 { +; CHECK: !prof ![[EC1:[0-9]+]] +entry: + %retval = alloca i64, align 8 + %i.addr = alloca i64, align 8 + store i64 %i, i64* %i.addr, align 8 + call void @llvm.dbg.declare(metadata i64* %i.addr, metadata !16, metadata !17), !dbg !18 + %call = call i32 @rand() #3, !dbg !19 + %cmp = icmp slt i32 %call, 500, !dbg !21 + br i1 %cmp, label %if.then, label %if.else, !dbg !22 +; CHECK: !prof ![[PROF1:[0-9]+]] + +if.then: ; preds = %entry + store i64 2, i64* %retval, align 8, !dbg !23 + br label %return, !dbg !23 + +if.else: ; preds = %entry + %call1 = call i32 @rand() #3, !dbg !25 + %cmp2 = icmp sgt i32 %call1, 5000, !dbg !28 + br i1 %cmp2, label %if.then.3, label %if.else.4, !dbg !29 +; CHECK: !prof ![[PROF2:[0-9]+]] + +if.then.3: ; preds = %if.else + store i64 10, i64* %retval, align 8, !dbg !30 + br label %return, !dbg !30 + +if.else.4: ; preds = %if.else + store i64 90, i64* %retval, align 8, !dbg !32 + br label %return, !dbg !32 + +return: ; preds = %if.else.4, %if.then.3, %if.then + %0 = load i64, i64* %retval, align 8, !dbg !34 + ret i64 %0, !dbg !34 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind +declare i32 @rand() #2 + +; Function Attrs: nounwind uwtable +define i32 @main() #0 { +; CHECK: !prof ![[EC2:[0-9]+]] +entry: + %retval = alloca i32, align 4 + %sum = alloca i64, align 8 + %k = alloca i32, align 4 + %i = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + call void @llvm.dbg.declare(metadata i64* %sum, metadata !35, metadata !17), !dbg !36 + store i64 0, i64* %sum, align 8, !dbg !36 + call void @llvm.dbg.declare(metadata i32* %k, metadata !37, metadata !17), !dbg !39 + store i32 0, i32* %k, align 4, !dbg !39 + br label %for.cond, !dbg !40 + +for.cond: ; preds = %for.inc.4, %entry + %0 = load i32, i32* %k, align 4, !dbg !41 + %cmp = icmp slt i32 %0, 3000, !dbg !45 + br i1 %cmp, label %for.body, label %for.end.6, !dbg !46 +; CHECK: !prof ![[PROF3:[0-9]+]] + +for.body: ; preds = %for.cond + call void @llvm.dbg.declare(metadata i32* %i, metadata !47, metadata !17), !dbg !49 + store i32 0, i32* %i, align 4, !dbg !49 + br label %for.cond.1, !dbg !50 + +for.cond.1: ; preds = %for.inc, %for.body + %1 = load i32, i32* %i, align 4, !dbg !51 + %cmp2 = icmp slt i32 %1, 200000, !dbg !55 + br i1 %cmp2, label %for.body.3, label %for.end, !dbg !56 +; CHECK: !prof ![[PROF4:[0-9]+]] + +for.body.3: ; preds = %for.cond.1 + %2 = load i32, i32* %i, align 4, !dbg !57 + %conv = sext i32 %2 to i64, !dbg !57 + %call = call i64 @_Z3fool(i64 %conv), !dbg !59 + %3 = load i64, i64* %sum, align 8, !dbg !60 + %add = add nsw i64 %3, %call, !dbg !60 + store i64 %add, i64* %sum, align 8, !dbg !60 + br label %for.inc, !dbg !61 + +for.inc: ; preds = %for.body.3 + %4 = load i32, i32* %i, align 4, !dbg !62 + %inc = add nsw i32 %4, 1, !dbg !62 + store i32 %inc, i32* %i, align 4, !dbg !62 + br label %for.cond.1, !dbg !64 + +for.end: ; preds = %for.cond.1 + br label %for.inc.4, !dbg !65 + +for.inc.4: ; preds = %for.end + %5 = load i32, i32* %k, align 4, !dbg !67 + %inc5 = add nsw i32 %5, 1, !dbg !67 + store i32 %inc5, i32* %k, align 4, !dbg !67 + br label %for.cond, !dbg !68 + +for.end.6: ; preds = %for.cond + %6 = load i64, i64* %sum, align 8, !dbg !69 + %cmp7 = icmp sgt i64 %6, 0, !dbg !70 + %cond = select i1 %cmp7, i32 0, i32 1, !dbg !69 + ret i32 %cond, !dbg !71 +} + +; CHECK ![[EC1]] = !{!"function_entry_count", i64 24108} +; CHECK ![[PROF1]] = !{!"branch_weights", i32 1, i32 30124} +; CHECK ![[PROF2]] = !{!"branch_weights", i32 30177, i32 29579} +; CHECK ![[EC2]] = !{!"function_entry_count", i64 0} +; CHECK ![[PROF3]] = !{!"branch_weights", i32 1, i32 1} +; CHECK ![[PROF4]] = !{!"branch_weights", i32 1, i32 20238} + +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" } +attributes #1 = { nounwind readnone } +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" } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!13, !14} +!llvm.ident = !{!15} + +!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) +!1 = !DIFile(filename: "discriminator.cc", directory: "/usr/local/google/home/dnovillo/llvm/test/autofdo") +!2 = !{} +!3 = !{!4, !9} +!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) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !8} +!7 = !DIBasicType(name: "long long int", size: 64, align: 64, encoding: DW_ATE_signed) +!8 = !DIBasicType(name: "long int", size: 64, align: 64, encoding: DW_ATE_signed) +!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) +!10 = !DISubroutineType(types: !11) +!11 = !{!12} +!12 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!13 = !{i32 2, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{!"clang version 3.8.0 (trunk 247554) (llvm/trunk 247557)"} +!16 = !DILocalVariable(name: "i", arg: 1, scope: !4, file: !1, line: 3, type: !8) +!17 = !DIExpression() +!18 = !DILocation(line: 3, column: 24, scope: !4) +!19 = !DILocation(line: 4, column: 7, scope: !20) +!20 = distinct !DILexicalBlock(scope: !4, file: !1, line: 4, column: 7) +!21 = !DILocation(line: 4, column: 14, scope: !20) +!22 = !DILocation(line: 4, column: 7, scope: !4) +!23 = !DILocation(line: 4, column: 21, scope: !24) +!24 = !DILexicalBlockFile(scope: !20, file: !1, discriminator: 1) +!25 = !DILocation(line: 4, column: 40, scope: !26) +!26 = !DILexicalBlockFile(scope: !27, file: !1, discriminator: 2) +!27 = distinct !DILexicalBlock(scope: !20, file: !1, line: 4, column: 40) +!28 = !DILocation(line: 4, column: 47, scope: !27) +!29 = !DILocation(line: 4, column: 40, scope: !20) +!30 = !DILocation(line: 4, column: 55, scope: !31) +!31 = !DILexicalBlockFile(scope: !27, file: !1, discriminator: 3) +!32 = !DILocation(line: 4, column: 71, scope: !33) +!33 = !DILexicalBlockFile(scope: !27, file: !1, discriminator: 4) +!34 = !DILocation(line: 5, column: 1, scope: !4) +!35 = !DILocalVariable(name: "sum", scope: !9, file: !1, line: 8, type: !7) +!36 = !DILocation(line: 8, column: 17, scope: !9) +!37 = !DILocalVariable(name: "k", scope: !38, file: !1, line: 9, type: !12) +!38 = distinct !DILexicalBlock(scope: !9, file: !1, line: 9, column: 3) +!39 = !DILocation(line: 9, column: 12, scope: !38) +!40 = !DILocation(line: 9, column: 8, scope: !38) +!41 = !DILocation(line: 9, column: 19, scope: !42) +!42 = !DILexicalBlockFile(scope: !43, file: !1, discriminator: 2) +!43 = !DILexicalBlockFile(scope: !44, file: !1, discriminator: 1) +!44 = distinct !DILexicalBlock(scope: !38, file: !1, line: 9, column: 3) +!45 = !DILocation(line: 9, column: 21, scope: !44) +!46 = !DILocation(line: 9, column: 3, scope: !38) +!47 = !DILocalVariable(name: "i", scope: !48, file: !1, line: 10, type: !12) +!48 = distinct !DILexicalBlock(scope: !44, file: !1, line: 10, column: 5) +!49 = !DILocation(line: 10, column: 14, scope: !48) +!50 = !DILocation(line: 10, column: 10, scope: !48) +!51 = !DILocation(line: 10, column: 21, scope: !52) +!52 = !DILexicalBlockFile(scope: !53, file: !1, discriminator: 5) +!53 = !DILexicalBlockFile(scope: !54, file: !1, discriminator: 1) +!54 = distinct !DILexicalBlock(scope: !48, file: !1, line: 10, column: 5) +!55 = !DILocation(line: 10, column: 23, scope: !54) +!56 = !DILocation(line: 10, column: 5, scope: !48) +!57 = !DILocation(line: 10, column: 49, scope: !58) +!58 = !DILexicalBlockFile(scope: !54, file: !1, discriminator: 2) +!59 = !DILocation(line: 10, column: 45, scope: !54) +!60 = !DILocation(line: 10, column: 42, scope: !54) +!61 = !DILocation(line: 10, column: 38, scope: !54) +!62 = !DILocation(line: 10, column: 34, scope: !63) +!63 = !DILexicalBlockFile(scope: !54, file: !1, discriminator: 4) +!64 = !DILocation(line: 10, column: 5, scope: !54) +!65 = !DILocation(line: 10, column: 50, scope: !66) +!66 = !DILexicalBlockFile(scope: !48, file: !1, discriminator: 3) +!67 = !DILocation(line: 9, column: 30, scope: !44) +!68 = !DILocation(line: 9, column: 3, scope: !44) +!69 = !DILocation(line: 11, column: 10, scope: !9) +!70 = !DILocation(line: 11, column: 14, scope: !9) +!71 = !DILocation(line: 11, column: 3, scope: !9) |