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