[PATCH] Add profile writing capabilities for sampling profiles.

Justin Bogner mail at justinbogner.com
Thu Oct 30 10:18:03 PDT 2014


Diego Novillo <dnovillo at google.com> writes:
>> +       SI != SE; ++SI) {
>> +    LineLocation Loc = SI->first;
>> +    SampleRecord Sample = SI->second;
>> +    OS << "\tline offset: " << Loc.LineOffset
>> +       << ", discriminator: " << Loc.Discriminator
>> +       << ", number of samples: " << Sample.getSamples();
>> +    if (Sample.hasCalls()) {
>> The handling of calls seems like a separate change from adding the
>> binary format. Can you break it out into its own commit?
>
> Yeah, but if it's OK with you, it would be a bit more convenient if I
> can leave this in.  This affects the tests that I added for the binary
> writer. I'd have to remove it, only to add it immediately after.

Sure, that should be fine.

>   - Fix comment.

And with this, LGTM.

> http://reviews.llvm.org/D6000
>
> Files:
>   include/llvm/ProfileData/SampleProf.h
>   include/llvm/ProfileData/SampleProfReader.h
>   include/llvm/ProfileData/SampleProfWriter.h
>   lib/ProfileData/CMakeLists.txt
>   lib/ProfileData/SampleProf.cpp
>   lib/ProfileData/SampleProfReader.cpp
>   lib/ProfileData/SampleProfWriter.cpp
>   lib/Transforms/Scalar/SampleProfile.cpp
>   test/Transforms/SampleProfile/Inputs/fnptr.binprof
>   test/Transforms/SampleProfile/Inputs/fnptr.prof
>   test/Transforms/SampleProfile/fnptr.ll
>   test/Transforms/SampleProfile/syntax.ll
>
> Index: include/llvm/ProfileData/SampleProf.h
> ===================================================================
> --- /dev/null
> +++ include/llvm/ProfileData/SampleProf.h
> @@ -0,0 +1,206 @@
> +//=-- SampleProf.h - Sampling profiling format support --------------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file contains common definitions used in the reading and writing of
> +// sample profile data.
> +//
> +//===----------------------------------------------------------------------===//
> +#ifndef LLVM_PROFILEDATA_SAMPLEPROF_H_
> +#define LLVM_PROFILEDATA_SAMPLEPROF_H_
> +
> +#include "llvm/ADT/DenseMap.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +#include <system_error>
> +
> +namespace llvm {
> +
> +const std::error_category &sampleprof_category();
> +
> +enum class sampleprof_error {
> +  success = 0,
> +  bad_magic,
> +  unsupported_version,
> +  too_large,
> +  truncated,
> +  malformed
> +};
> +
> +inline std::error_code make_error_code(sampleprof_error E) {
> +  return std::error_code(static_cast<int>(E), sampleprof_category());
> +}
> +
> +} // end namespace llvm
> +
> +namespace std {
> +template <>
> +struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {};
> +}
> +
> +namespace llvm {
> +
> +namespace sampleprof {
> +
> +static inline uint64_t SPMagic() {
> +  return uint64_t('S') << (64 - 8) | uint64_t('P') << (64 - 16) |
> +         uint64_t('R') << (64 - 24) | uint64_t('O') << (64 - 32) |
> +         uint64_t('F') << (64 - 40) | uint64_t('4') << (64 - 48) |
> +         uint64_t('2') << (64 - 56) | uint64_t(0xff);
> +}
> +
> +static inline uint64_t SPVersion() { return 100; }
> +
> +/// \brief Represents the relative location of an instruction.
> +///
> +/// Instruction locations are specified by the line offset from the
> +/// beginning of the function (marked by the line where the function
> +/// header is) and the discriminator value within that line.
> +///
> +/// The discriminator value is useful to distinguish instructions
> +/// that are on the same line but belong to different basic blocks
> +/// (e.g., the two post-increment instructions in "if (p) x++; else y++;").
> +struct LineLocation {
> +  LineLocation(int L, unsigned D) : LineOffset(L), Discriminator(D) {}
> +  int LineOffset;
> +  unsigned Discriminator;
> +};
> +
> +} // End namespace sampleprof
> +
> +template <> struct DenseMapInfo<sampleprof::LineLocation> {
> +  typedef DenseMapInfo<int> OffsetInfo;
> +  typedef DenseMapInfo<unsigned> DiscriminatorInfo;
> +  static inline sampleprof::LineLocation getEmptyKey() {
> +    return sampleprof::LineLocation(OffsetInfo::getEmptyKey(),
> +                                    DiscriminatorInfo::getEmptyKey());
> +  }
> +  static inline sampleprof::LineLocation getTombstoneKey() {
> +    return sampleprof::LineLocation(OffsetInfo::getTombstoneKey(),
> +                                    DiscriminatorInfo::getTombstoneKey());
> +  }
> +  static inline unsigned getHashValue(sampleprof::LineLocation Val) {
> +    return DenseMapInfo<std::pair<int, unsigned>>::getHashValue(
> +        std::pair<int, unsigned>(Val.LineOffset, Val.Discriminator));
> +  }
> +  static inline bool isEqual(sampleprof::LineLocation LHS,
> +                             sampleprof::LineLocation RHS) {
> +    return LHS.LineOffset == RHS.LineOffset &&
> +           LHS.Discriminator == RHS.Discriminator;
> +  }
> +};
> +
> +namespace sampleprof {
> +
> +/// \brief Representation of a single sample record.
> +///
> +/// A sample record is represented by a positive integer value, which
> +/// indicates how frequently was the associated line location executed.
> +///
> +/// Additionally, if the associated location contains a function call,
> +/// the record will hold a list of all the possible called targets. For
> +/// direct calls, this will be the exact function being invoked. For
> +/// indirect calls (function pointers, virtual table dispatch), this
> +/// will be a list of one or more functions.
> +class SampleRecord {
> +public:
> +  typedef SmallVector<std::pair<std::string, unsigned>, 8> CallTargetList;
> +
> +  SampleRecord() : NumSamples(0), CallTargets() {}
> +
> +  /// \brief Increment the number of samples for this record by \p S.
> +  void addSamples(unsigned S) { NumSamples += S; }
> +
> +  /// \brief Add called function \p F with samples \p S.
> +  void addCalledTarget(std::string F, unsigned S) {
> +    CallTargets.push_back(std::make_pair(F, S));
> +  }
> +
> +  /// \brief Return true if this sample record contains function calls.
> +  bool hasCalls() const { return CallTargets.size() > 0; }
> +
> +  unsigned getSamples() const { return NumSamples; }
> +  const CallTargetList &getCallTargets() const { return CallTargets; }
> +
> +private:
> +  unsigned NumSamples;
> +  CallTargetList CallTargets;
> +};
> +
> +typedef DenseMap<LineLocation, SampleRecord> BodySampleMap;
> +
> +/// \brief Representation of the samples collected for a function.
> +///
> +/// This data structure contains all the collected samples for the body
> +/// of a function. Each sample corresponds to a LineLocation instance
> +/// within the body of the function.
> +class FunctionSamples {
> +public:
> +  FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
> +  void print(raw_ostream &OS);
> +  void addTotalSamples(unsigned Num) { TotalSamples += Num; }
> +  void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; }
> +  void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) {
> +    assert(LineOffset >= 0);
> +    // When dealing with instruction weights, we use the value
> +    // zero to indicate the absence of a sample. If we read an
> +    // actual zero from the profile file, use the value 1 to
> +    // avoid the confusion later on.
> +    if (Num == 0)
> +      Num = 1;
> +    BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num);
> +  }
> +  void addCalledTargetSamples(int LineOffset, unsigned Discriminator,
> +                              std::string FName, unsigned Num) {
> +    assert(LineOffset >= 0);
> +    BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(FName,
> +                                                                         Num);
> +  }
> +
> +  /// \brief Return the number of samples collected at the given location.
> +  /// Each location is specified by \p LineOffset and \p Discriminator.
> +  unsigned samplesAt(int LineOffset, unsigned Discriminator) {
> +    return BodySamples[LineLocation(LineOffset, Discriminator)].getSamples();
> +  }
> +
> +  bool empty() const { return BodySamples.empty(); }
> +
> +  /// \brief Return the total number of samples collected inside the function.
> +  unsigned getTotalSamples() const { return TotalSamples; }
> +
> +  /// \brief Return the total number of samples collected at the head of the
> +  /// function.
> +  unsigned getHeadSamples() const { return TotalHeadSamples; }
> +
> +  /// \brief Return all the samples collected in the body of the function.
> +  const BodySampleMap &getBodySamples() const { return BodySamples; }
> +
> +private:
> +  /// \brief Total number of samples collected inside this function.
> +  ///
> +  /// Samples are cumulative, they include all the samples collected
> +  /// inside this function and all its inlined callees.
> +  unsigned TotalSamples;
> +
> +  /// \brief Total number of samples collected at the head of the function.
> +  unsigned TotalHeadSamples;
> +
> +  /// \brief Map instruction locations to collected samples.
> +  ///
> +  /// Each entry in this map contains the number of samples
> +  /// collected at the corresponding line offset. All line locations
> +  /// are an offset from the start of the function.
> +  BodySampleMap BodySamples;
> +};
> +
> +} // End namespace sampleprof
> +
> +} // End namespace llvm
> +
> +#endif // LLVM_PROFILEDATA_SAMPLEPROF_H_
> Index: include/llvm/ProfileData/SampleProfReader.h
> ===================================================================
> --- include/llvm/ProfileData/SampleProfReader.h
> +++ include/llvm/ProfileData/SampleProfReader.h
> @@ -17,104 +17,19 @@
>  #include "llvm/IR/DiagnosticInfo.h"
>  #include "llvm/IR/Function.h"
>  #include "llvm/IR/LLVMContext.h"
> -#include "llvm/IR/Module.h"
>  #include "llvm/ADT/StringMap.h"
>  #include "llvm/ADT/StringRef.h"
>  #include "llvm/ADT/Twine.h"
> +#include "llvm/ProfileData/SampleProf.h"
>  #include "llvm/Support/ErrorHandling.h"
> +#include "llvm/Support/ErrorOr.h"
> +#include "llvm/Support/MemoryBuffer.h"
>  #include "llvm/Support/raw_ostream.h"
>  
> -using namespace llvm;
> -
> -namespace sampleprof {
> -
> -/// \brief Represents the relative location of an instruction.
> -///
> -/// Instruction locations are specified by the line offset from the
> -/// beginning of the function (marked by the line where the function
> -/// header is) and the discriminator value within that line.
> -///
> -/// The discriminator value is useful to distinguish instructions
> -/// that are on the same line but belong to different basic blocks
> -/// (e.g., the two post-increment instructions in "if (p) x++; else y++;").
> -struct LineLocation {
> -  LineLocation(int L, unsigned D) : LineOffset(L), Discriminator(D) {}
> -  int LineOffset;
> -  unsigned Discriminator;
> -};
> -} // End namespace sampleprof
> -
>  namespace llvm {
> -template <> struct DenseMapInfo<sampleprof::LineLocation> {
> -  typedef DenseMapInfo<int> OffsetInfo;
> -  typedef DenseMapInfo<unsigned> DiscriminatorInfo;
> -  static inline sampleprof::LineLocation getEmptyKey() {
> -    return sampleprof::LineLocation(OffsetInfo::getEmptyKey(),
> -                                    DiscriminatorInfo::getEmptyKey());
> -  }
> -  static inline sampleprof::LineLocation getTombstoneKey() {
> -    return sampleprof::LineLocation(OffsetInfo::getTombstoneKey(),
> -                                    DiscriminatorInfo::getTombstoneKey());
> -  }
> -  static inline unsigned getHashValue(sampleprof::LineLocation Val) {
> -    return DenseMapInfo<std::pair<int, unsigned>>::getHashValue(
> -        std::pair<int, unsigned>(Val.LineOffset, Val.Discriminator));
> -  }
> -  static inline bool isEqual(sampleprof::LineLocation LHS,
> -                             sampleprof::LineLocation RHS) {
> -    return LHS.LineOffset == RHS.LineOffset &&
> -           LHS.Discriminator == RHS.Discriminator;
> -  }
> -};
> -}
>  
>  namespace sampleprof {
>  
> -typedef DenseMap<LineLocation, unsigned> BodySampleMap;
> -
> -/// \brief Representation of the samples collected for a function.
> -///
> -/// This data structure contains all the collected samples for the body
> -/// of a function. Each sample corresponds to a LineLocation instance
> -/// within the body of the function.
> -class FunctionSamples {
> -public:
> -  FunctionSamples()
> -      : TotalSamples(0), TotalHeadSamples(0) {}
> -  void print(raw_ostream & OS);
> -  void addTotalSamples(unsigned Num) { TotalSamples += Num; }
> -  void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; }
> -  void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) {
> -    assert(LineOffset >= 0);
> -    BodySamples[LineLocation(LineOffset, Discriminator)] += Num;
> -  }
> -
> -  /// \brief Return the number of samples collected at the given location.
> -  /// Each location is specified by \p LineOffset and \p Discriminator.
> -  unsigned samplesAt(int LineOffset, unsigned Discriminator) {
> -    return BodySamples.lookup(LineLocation(LineOffset, Discriminator));
> -  }
> -
> -  bool empty() { return BodySamples.empty(); }
> -
> -private:
> -  /// \brief Total number of samples collected inside this function.
> -  ///
> -  /// Samples are cumulative, they include all the samples collected
> -  /// inside this function and all its inlined callees.
> -  unsigned TotalSamples;
> -
> -  /// \brief Total number of samples collected at the head of the function.
> -  unsigned TotalHeadSamples;
> -
> -  /// \brief Map instruction locations to collected samples.
> -  ///
> -  /// Each entry in this map contains the number of samples
> -  /// collected at the corresponding line offset. All line locations
> -  /// are an offset from the start of the function.
> -  BodySampleMap BodySamples;
> -};
> -
>  /// \brief Sample-based profile reader.
>  ///
>  /// Each profile contains sample counts for all the functions
> @@ -139,19 +54,24 @@
>  ///      protection against source code shuffling, line numbers should
>  ///      be relative to the start of the function.
>  ///
> -/// The reader supports two file formats: text and bitcode. The text format
> -/// is useful for debugging and testing, while the bitcode format is more
> +/// 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.
>  class SampleProfileReader {
>  public:
> -  SampleProfileReader(const Module &M, StringRef F)
> -      : Profiles(0), Filename(F), M(M) {}
> +  SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
> +      : Profiles(0), Ctx(C), Buffer(std::move(B)) {}
> +
> +  virtual ~SampleProfileReader() {}
>  
>    /// \brief Print all the profiles to dbgs().
>    void dump();
>  
> -  /// \brief Load sample profiles from the associated file.
> -  bool load();
> +  /// \brief Read and validate the file header.
> +  virtual std::error_code readHeader() = 0;
> +
> +  /// \brief Read sample profiles from the associated file.
> +  virtual std::error_code read() = 0;
>  
>    /// \brief Print the profile for \p FName on stream \p OS.
>    void printFunctionProfile(raw_ostream &OS, StringRef FName);
> @@ -166,29 +86,86 @@
>  
>    /// \brief Report a parse error message.
>    void reportParseError(int64_t LineNumber, Twine Msg) const {
> -    DiagnosticInfoSampleProfile Diag(Filename.data(), LineNumber, Msg);
> -    M.getContext().diagnose(Diag);
> +    DiagnosticInfoSampleProfile Diag(Buffer->getBufferIdentifier(), LineNumber,
> +                                     Msg);
> +    Ctx.diagnose(Diag);
>    }
>  
> -protected:
> -  bool loadText();
> -  bool loadBitcode() { llvm_unreachable("not implemented"); }
> +  /// \brief Create a sample profile reader appropriate to the file format.
> +  static std::error_code create(std::string Filename,
> +                                std::unique_ptr<SampleProfileReader> &Reader,
> +                                LLVMContext &C);
>  
> +protected:
>    /// \brief Map every function to its associated profile.
>    ///
>    /// The profile of every function executed at runtime is collected
>    /// in the structure FunctionSamples. This maps function objects
>    /// to their corresponding profiles.
>    StringMap<FunctionSamples> Profiles;
>  
> -  /// \brief Path name to the file holding the profile data.
> -  StringRef Filename;
> +  /// \brief LLVM context used to emit diagnostics.
> +  LLVMContext &Ctx;
> +
> +  /// \brief Memory buffer holding the profile file.
> +  std::unique_ptr<MemoryBuffer> Buffer;
> +};
> +
> +class SampleProfileReaderText : public SampleProfileReader {
> +public:
> +  SampleProfileReaderText(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
> +      : SampleProfileReader(std::move(B), C) {}
> +
> +  /// \brief Read and validate the file header.
> +  std::error_code readHeader() override { return sampleprof_error::success; }
> +
> +  /// \brief Read sample profiles from the associated file.
> +  std::error_code read() override;
> +};
> +
> +class SampleProfileReaderBinary : public SampleProfileReader {
> +public:
> +  SampleProfileReaderBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
> +      : SampleProfileReader(std::move(B), C), Data(nullptr), End(nullptr) {}
> +
> +  /// \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:
> +  /// \brief Read a numeric value of type T from the profile.
> +  ///
> +  /// If an error occurs during decoding, a diagnostic message is emitted and
> +  /// EC is set.
> +  ///
> +  /// \returns the read value.
> +  template <typename T> ErrorOr<T> readNumber();
>  
> -  /// \brief Module being compiled. Used to access the current
> -  /// LLVM context for diagnostics.
> -  const Module &M;
> +  /// \brief Read a string from the profile.
> +  ///
> +  /// If an error occurs during decoding, a diagnostic message is emitted and
> +  /// EC is set.
> +  ///
> +  /// \returns the read value.
> +  ErrorOr<StringRef> readString();
> +
> +  /// \brief Return true if we've reached the end of file.
> +  bool at_eof() const { return Data >= End; }
> +
> +  /// \brief Points to the current location in the buffer.
> +  const uint8_t *Data;
> +
> +  /// \brief Points to the end of the buffer.
> +  const uint8_t *End;
>  };
>  
>  } // End namespace sampleprof
>  
> +} // End namespace llvm
> +
>  #endif // LLVM_PROFILEDATA_SAMPLEPROFREADER_H
> Index: include/llvm/ProfileData/SampleProfWriter.h
> ===================================================================
> --- /dev/null
> +++ include/llvm/ProfileData/SampleProfWriter.h
> @@ -0,0 +1,82 @@
> +//===- SampleProfWriter.h - Write LLVM sample profile data ----------------===//
> +//
> +//                      The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file contains definitions needed for writing sample profiles.
> +//
> +//===----------------------------------------------------------------------===//
> +#ifndef LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
> +#define LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
> +
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/IR/Function.h"
> +#include "llvm/IR/Module.h"
> +#include "llvm/ProfileData/SampleProf.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +namespace llvm {
> +
> +namespace sampleprof {
> +
> +/// \brief Sample-based profile writer. Base class.
> +class SampleProfileWriter {
> +public:
> +  SampleProfileWriter(StringRef Filename, std::error_code &EC,
> +                      sys::fs::OpenFlags Flags)
> +      : OS(Filename, EC, Flags) {}
> +  virtual ~SampleProfileWriter() {}
> +
> +  /// \brief Write sample profiles in \p S for function \p F.
> +  ///
> +  /// \returns true if the file was updated successfully. False, otherwise.
> +  virtual bool write(const Function &F, const FunctionSamples &S) = 0;
> +
> +  /// \brief Write all the sample profiles for all the functions in \p M.
> +  ///
> +  /// \returns true if the file was updated successfully. False, otherwise.
> +  bool write(const Module &M, StringMap<FunctionSamples> &P) {
> +    for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I)
> +      if (!write((*I), P[I->getName()]))
> +        return false;
> +    return true;
> +  }
> +
> +protected:
> +  /// \brief Output stream where to emit the profile to.
> +  raw_fd_ostream OS;
> +};
> +
> +/// \brief Sample-based profile writer (text format).
> +class SampleProfileWriterText : public SampleProfileWriter {
> +public:
> +  SampleProfileWriterText(StringRef F, std::error_code &EC)
> +      : SampleProfileWriter(F, EC, sys::fs::F_Text) {}
> +
> +  bool write(const Function &F, const FunctionSamples &S) override;
> +  bool write(const Module &M, StringMap<FunctionSamples> &P) {
> +    return SampleProfileWriter::write(M, P);
> +  }
> +};
> +
> +/// \brief Sample-based profile writer (binary format).
> +class SampleProfileWriterBinary : public SampleProfileWriter {
> +public:
> +  SampleProfileWriterBinary(StringRef F, std::error_code &EC);
> +
> +  bool write(const Function &F, const FunctionSamples &S) override;
> +  bool write(const Module &M, StringMap<FunctionSamples> &P) {
> +    return SampleProfileWriter::write(M, P);
> +  }
> +};
> +
> +} // End namespace sampleprof
> +
> +} // End namespace sampleprof
> +
> +#endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
> Index: lib/ProfileData/CMakeLists.txt
> ===================================================================
> --- lib/ProfileData/CMakeLists.txt
> +++ lib/ProfileData/CMakeLists.txt
> @@ -5,5 +5,7 @@
>    CoverageMapping.cpp
>    CoverageMappingWriter.cpp
>    CoverageMappingReader.cpp
> +  SampleProf.cpp
>    SampleProfReader.cpp
> +  SampleProfWriter.cpp
>    )
> Index: lib/ProfileData/SampleProf.cpp
> ===================================================================
> --- /dev/null
> +++ lib/ProfileData/SampleProf.cpp
> @@ -0,0 +1,49 @@
> +//=-- SampleProf.cpp - Sample profiling format support --------------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file contains common definitions used in the reading and writing of
> +// sample profile data.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/ProfileData/SampleProf.h"
> +#include "llvm/Support/ErrorHandling.h"
> +#include "llvm/Support/ManagedStatic.h"
> +
> +using namespace llvm;
> +
> +namespace {
> +class SampleProfErrorCategoryType : public std::error_category {
> +  const char *name() const LLVM_NOEXCEPT override { return "llvm.sampleprof"; }
> +  std::string message(int IE) const override {
> +    sampleprof_error E = static_cast<sampleprof_error>(IE);
> +    switch (E) {
> +    case sampleprof_error::success:
> +      return "Success";
> +    case sampleprof_error::bad_magic:
> +      return "Invalid file format (bad magic)";
> +    case sampleprof_error::unsupported_version:
> +      return "Unsupported format version";
> +    case sampleprof_error::too_large:
> +      return "Too much profile data";
> +    case sampleprof_error::truncated:
> +      return "Truncated profile data";
> +    case sampleprof_error::malformed:
> +      return "Malformed profile data";
> +    }
> +    llvm_unreachable("A value of sampleprof_error has no message.");
> +  }
> +};
> +}
> +
> +static ManagedStatic<SampleProfErrorCategoryType> ErrorCategory;
> +
> +const std::error_category &llvm::sampleprof_category() {
> +  return *ErrorCategory;
> +}
> Index: lib/ProfileData/SampleProfReader.cpp
> ===================================================================
> --- lib/ProfileData/SampleProfReader.cpp
> +++ lib/ProfileData/SampleProfReader.cpp
> @@ -8,8 +8,8 @@
>  //===----------------------------------------------------------------------===//
>  //
>  // This file implements the class that reads LLVM sample profiles. It
> -// supports two file formats: text and bitcode. The textual representation
> -// is useful for debugging and testing purposes. The bitcode representation
> +// supports two file formats: text and binary. The textual representation
> +// is useful for debugging and testing purposes. The binary representation
>  // is more compact, resulting in smaller file sizes. However, they can
>  // both be used interchangeably.
>  //
> @@ -95,13 +95,15 @@
>  //===----------------------------------------------------------------------===//
>  
>  #include "llvm/ProfileData/SampleProfReader.h"
> +#include "llvm/ProfileData/SampleProfWriter.h" // REMOVE
>  #include "llvm/Support/Debug.h"
>  #include "llvm/Support/ErrorOr.h"
> -#include "llvm/Support/MemoryBuffer.h"
> +#include "llvm/Support/LEB128.h"
>  #include "llvm/Support/LineIterator.h"
> +#include "llvm/Support/MemoryBuffer.h"
>  #include "llvm/Support/Regex.h"
>  
> -using namespace sampleprof;
> +using namespace llvm::sampleprof;
>  using namespace llvm;
>  
>  /// \brief Print the samples collected for a function on stream \p OS.
> @@ -112,10 +114,22 @@
>       << " sampled lines\n";
>    for (BodySampleMap::const_iterator SI = BodySamples.begin(),
>                                       SE = BodySamples.end();
> -       SI != SE; ++SI)
> -    OS << "\tline offset: " << SI->first.LineOffset
> -       << ", discriminator: " << SI->first.Discriminator
> -       << ", number of samples: " << SI->second << "\n";
> +       SI != SE; ++SI) {
> +    LineLocation Loc = SI->first;
> +    SampleRecord Sample = SI->second;
> +    OS << "\tline offset: " << Loc.LineOffset
> +       << ", discriminator: " << Loc.Discriminator
> +       << ", number of samples: " << Sample.getSamples();
> +    if (Sample.hasCalls()) {
> +      OS << ", calls:";
> +      for (SampleRecord::CallTargetList::const_iterator
> +               I = Sample.getCallTargets().begin(),
> +               E = Sample.getCallTargets().end();
> +           I != E; ++I)
> +        OS << " " << (*I).first << ":" << (*I).second;
> +    }
> +    OS << "\n";
> +  }
>    OS << "\n";
>  }
>  
> @@ -125,7 +139,7 @@
>  /// \param FName Name of the function to print.
>  void SampleProfileReader::printFunctionProfile(raw_ostream &OS,
>                                                 StringRef FName) {
> -  OS << "Function: " << FName << ":\n";
> +  OS << "Function: " << FName << ": ";
>    Profiles[FName].print(OS);
>  }
>  
> @@ -150,22 +164,15 @@
>  /// the expected format.
>  ///
>  /// \returns true if the file was loaded successfully, false otherwise.
> -bool SampleProfileReader::loadText() {
> -  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
> -      MemoryBuffer::getFile(Filename);
> -  if (std::error_code EC = BufferOrErr.getError()) {
> -    std::string Msg(EC.message());
> -    M.getContext().diagnose(DiagnosticInfoSampleProfile(Filename.data(), Msg));
> -    return false;
> -  }
> -  MemoryBuffer &Buffer = *BufferOrErr.get();
> -  line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#');
> +std::error_code SampleProfileReaderText::read() {
> +  line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#');
>  
>    // Read the profile of each function. Since each function may be
>    // mentioned more than once, and we are collecting flat profiles,
>    // accumulate samples as we parse them.
>    Regex HeadRE("^([^0-9].*):([0-9]+):([0-9]+)$");
> -  Regex LineSample("^([0-9]+)\\.?([0-9]+)?: ([0-9]+)(.*)$");
> +  Regex LineSampleRE("^([0-9]+)\\.?([0-9]+)?: ([0-9]+)(.*)$");
> +  Regex CallSampleRE(" +([^0-9 ][^ ]*):([0-9]+)");
>    while (!LineIt.is_at_eof()) {
>      // Read the header of each function.
>      //
> @@ -179,11 +186,11 @@
>      //
>      // The only requirement we place on the identifier, then, is that it
>      // should not begin with a number.
> -    SmallVector<StringRef, 3> Matches;
> +    SmallVector<StringRef, 4> Matches;
>      if (!HeadRE.match(*LineIt, &Matches)) {
>        reportParseError(LineIt.line_number(),
>                         "Expected 'mangled_name:NUM:NUM', found " + *LineIt);
> -      return false;
> +      return sampleprof_error::malformed;
>      }
>      assert(Matches.size() == 4);
>      StringRef FName = Matches[1];
> @@ -199,40 +206,207 @@
>      // Now read the body. The body of the function ends when we reach
>      // EOF or when we see the start of the next function.
>      while (!LineIt.is_at_eof() && isdigit((*LineIt)[0])) {
> -      if (!LineSample.match(*LineIt, &Matches)) {
> +      if (!LineSampleRE.match(*LineIt, &Matches)) {
>          reportParseError(
>              LineIt.line_number(),
>              "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " + *LineIt);
> -        return false;
> +        return sampleprof_error::malformed;
>        }
>        assert(Matches.size() == 5);
>        unsigned LineOffset, NumSamples, Discriminator = 0;
>        Matches[1].getAsInteger(10, LineOffset);
>        if (Matches[2] != "")
>          Matches[2].getAsInteger(10, Discriminator);
>        Matches[3].getAsInteger(10, NumSamples);
>  
> -      // FIXME: Handle called targets (in Matches[4]).
> +      // If there are function calls in this line, generate a call sample
> +      // entry for each call.
> +      std::string CallsLine(Matches[4]);
> +      while (CallsLine != "") {
> +        SmallVector<StringRef, 3> CallSample;
> +        if (!CallSampleRE.match(CallsLine, &CallSample)) {
> +          reportParseError(LineIt.line_number(),
> +                           "Expected 'mangled_name:NUM', found " + CallsLine);
> +          return sampleprof_error::malformed;
> +        }
> +        StringRef CalledFunction = CallSample[1];
> +        unsigned CalledFunctionSamples;
> +        CallSample[2].getAsInteger(10, CalledFunctionSamples);
> +        FProfile.addCalledTargetSamples(LineOffset, Discriminator,
> +                                        CalledFunction, CalledFunctionSamples);
> +        CallsLine = CallSampleRE.sub("", CallsLine);
> +      }
>  
> -      // When dealing with instruction weights, we use the value
> -      // zero to indicate the absence of a sample. If we read an
> -      // actual zero from the profile file, return it as 1 to
> -      // avoid the confusion later on.
> -      if (NumSamples == 0)
> -        NumSamples = 1;
>        FProfile.addBodySamples(LineOffset, Discriminator, NumSamples);
>        ++LineIt;
>      }
>    }
>  
> -  return true;
> +  return sampleprof_error::success;
> +}
> +
> +template <typename T>
> +ErrorOr<T> SampleProfileReaderBinary::readNumber() {
> +  unsigned NumBytesRead = 0;
> +  std::error_code EC;
> +  uint64_t Val = decodeULEB128(Data, &NumBytesRead);
> +
> +  if (Val > std::numeric_limits<T>::max())
> +    EC = sampleprof_error::malformed;
> +  else if (Data + NumBytesRead > End)
> +    EC = sampleprof_error::truncated;
> +  else
> +    EC = sampleprof_error::success;
> +
> +  if (EC) {
> +    reportParseError(0, EC.message());
> +    return EC;
> +  }
> +
> +  Data += NumBytesRead;
> +  return static_cast<T>(Val);
> +}
> +
> +ErrorOr<StringRef> SampleProfileReaderBinary::readString() {
> +  std::error_code EC;
> +  StringRef Str(reinterpret_cast<const char *>(Data));
> +  if (Data + Str.size() + 1 > End) {
> +    EC = sampleprof_error::truncated;
> +    reportParseError(0, EC.message());
> +    return EC;
> +  }
> +
> +  Data += Str.size() + 1;
> +  return Str;
> +}
> +
> +std::error_code SampleProfileReaderBinary::read() {
> +  while (!at_eof()) {
> +    auto FName(readString());
> +    if (std::error_code EC = FName.getError())
> +      return EC;
> +
> +    Profiles[*FName] = FunctionSamples();
> +    FunctionSamples &FProfile = Profiles[*FName];
> +
> +    auto Val = readNumber<unsigned>();
> +    if (std::error_code EC = Val.getError())
> +      return EC;
> +    FProfile.addTotalSamples(*Val);
> +
> +    Val = readNumber<unsigned>();
> +    if (std::error_code EC = Val.getError())
> +      return EC;
> +    FProfile.addHeadSamples(*Val);
> +
> +    // Read the samples in the body.
> +    auto NumRecords = readNumber<unsigned>();
> +    if (std::error_code EC = NumRecords.getError())
> +      return EC;
> +    for (unsigned I = 0; I < *NumRecords; ++I) {
> +      auto LineOffset = readNumber<uint64_t>();
> +      if (std::error_code EC = LineOffset.getError())
> +        return EC;
> +
> +      auto Discriminator = readNumber<uint64_t>();
> +      if (std::error_code EC = Discriminator.getError())
> +        return EC;
> +
> +      auto NumSamples = readNumber<uint64_t>();
> +      if (std::error_code EC = NumSamples.getError())
> +        return EC;
> +
> +      auto NumCalls = readNumber<unsigned>();
> +      if (std::error_code EC = NumCalls.getError())
> +        return EC;
> +
> +      for (unsigned J = 0; J < *NumCalls; ++J) {
> +        auto CalledFunction(readString());
> +        if (std::error_code EC = CalledFunction.getError())
> +          return EC;
> +
> +        auto CalledFunctionSamples = readNumber<uint64_t>();
> +        if (std::error_code EC = CalledFunctionSamples.getError())
> +          return EC;
> +
> +        FProfile.addCalledTargetSamples(*LineOffset, *Discriminator,
> +                                        *CalledFunction,
> +                                        *CalledFunctionSamples);
> +      }
> +
> +      FProfile.addBodySamples(*LineOffset, *Discriminator, *NumSamples);
> +    }
> +  }
> +
> +  return sampleprof_error::success;
> +}
> +
> +std::error_code SampleProfileReaderBinary::readHeader() {
> +  Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
> +  End = Data + Buffer->getBufferSize();
> +
> +  // Read and check the magic identifier.
> +  auto Magic = readNumber<uint64_t>();
> +  if (std::error_code EC = Magic.getError())
> +    return EC;
> +  else if (*Magic != SPMagic())
> +    return sampleprof_error::bad_magic;
> +
> +  // Read the version number.
> +  auto Version = readNumber<uint64_t>();
> +  if (std::error_code EC = Version.getError())
> +    return EC;
> +  else if (*Version != SPVersion())
> +    return sampleprof_error::unsupported_version;
> +
> +  return sampleprof_error::success;
>  }
>  
> -/// \brief Load execution samples from a file.
> +bool SampleProfileReaderBinary::hasFormat(const MemoryBuffer &Buffer) {
> +  const uint8_t *Data =
> +      reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
> +  uint64_t Magic = decodeULEB128(Data);
> +  return Magic == SPMagic();
> +}
> +
> +/// \brief Prepare a memory buffer for the contents of \p Filename.
> +///
> +/// \returns an error code indicating the status of the buffer.
> +static std::error_code
> +setupMemoryBuffer(std::string Filename, std::unique_ptr<MemoryBuffer> &Buffer) {
> +  auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(Filename);
> +  if (std::error_code EC = BufferOrErr.getError())
> +    return EC;
> +  Buffer = std::move(BufferOrErr.get());
> +
> +  // Sanity check the file.
> +  if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
> +    return sampleprof_error::too_large;
> +
> +  return sampleprof_error::success;
> +}
> +
> +/// \brief Create a sample profile reader based on the format of the input file.
> +///
> +/// \param Filename The file to open.
> +///
> +/// \param Reader The reader to instantiate according to \p Filename's format.
>  ///
> -/// This function examines the header of the given file to determine
> -/// whether to use the text or the bitcode loader.
> -bool SampleProfileReader::load() {
> -  // TODO Actually detect the file format.
> -  return loadText();
> +/// \param C The LLVM context to use to emit diagnostics.
> +///
> +/// \returns an error code indicating the status of the created reader.
> +std::error_code
> +SampleProfileReader::create(std::string Filename,
> +                            std::unique_ptr<SampleProfileReader> &Reader,
> +                            LLVMContext &C) {
> +  std::unique_ptr<MemoryBuffer> Buffer;
> +  if (std::error_code EC = setupMemoryBuffer(Filename, Buffer))
> +    return EC;
> +
> +  if (SampleProfileReaderBinary::hasFormat(*Buffer))
> +    Reader.reset(new SampleProfileReaderBinary(std::move(Buffer), C));
> +  else
> +    Reader.reset(new SampleProfileReaderText(std::move(Buffer), C));
> +
> +  return Reader->readHeader();
>  }
> Index: lib/ProfileData/SampleProfWriter.cpp
> ===================================================================
> --- /dev/null
> +++ lib/ProfileData/SampleProfWriter.cpp
> @@ -0,0 +1,110 @@
> +//===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
> +//
> +//                      The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file implements the class that writes LLVM sample profiles. It
> +// supports two file formats: text and binary. The textual representation
> +// is useful for debugging and testing purposes. The binary representation
> +// is more compact, resulting in smaller file sizes. However, they can
> +// both be used interchangeably.
> +//
> +// See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
> +// supported formats.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/ProfileData/SampleProfWriter.h"
> +#include "llvm/Support/Debug.h"
> +#include "llvm/Support/ErrorOr.h"
> +#include "llvm/Support/MemoryBuffer.h"
> +#include "llvm/Support/LEB128.h"
> +#include "llvm/Support/LineIterator.h"
> +#include "llvm/Support/Regex.h"
> +
> +using namespace llvm::sampleprof;
> +using namespace llvm;
> +
> +/// \brief Write samples to a text file.
> +bool SampleProfileWriterText::write(const Function &F,
> +                                    const FunctionSamples &S) {
> +  if (S.empty())
> +    return true;
> +
> +  OS << F.getName() << ":" << S.getTotalSamples() << ":" << S.getHeadSamples()
> +     << "\n";
> +
> +  for (BodySampleMap::const_iterator I = S.getBodySamples().begin(),
> +                                     E = S.getBodySamples().end();
> +       I != E; ++I) {
> +    LineLocation Loc = I->first;
> +    SampleRecord Sample = I->second;
> +    if (Loc.Discriminator == 0)
> +      OS << Loc.LineOffset << ": ";
> +    else
> +      OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
> +
> +    OS << Sample.getSamples();
> +
> +    for (SampleRecord::CallTargetList::const_iterator
> +             I = Sample.getCallTargets().begin(),
> +             E = Sample.getCallTargets().end();
> +         I != E; ++I)
> +      OS << " " << (*I).first << ":" << (*I).second;
> +    OS << "\n";
> +  }
> +
> +  return true;
> +}
> +
> +SampleProfileWriterBinary::SampleProfileWriterBinary(StringRef F,
> +                                                     std::error_code &EC)
> +    : SampleProfileWriter(F, EC, sys::fs::F_None) {
> +  if (EC)
> +    return;
> +
> +  // Write the file header.
> +  encodeULEB128(SPMagic(), OS);
> +  encodeULEB128(SPVersion(), OS);
> +}
> +
> +/// \brief Write samples to a binary file.
> +///
> +/// \returns true if the samples were written successfully, false otherwise.
> +bool SampleProfileWriterBinary::write(const Function &F,
> +                                      const FunctionSamples &S) {
> +  if (S.empty())
> +    return true;
> +
> +  OS << F.getName();
> +  encodeULEB128(0, OS);
> +  encodeULEB128(S.getTotalSamples(), OS);
> +  encodeULEB128(S.getHeadSamples(), OS);
> +  encodeULEB128(S.getBodySamples().size(), OS);
> +  for (BodySampleMap::const_iterator I = S.getBodySamples().begin(),
> +                                     E = S.getBodySamples().end();
> +       I != E; ++I) {
> +    LineLocation Loc = I->first;
> +    SampleRecord Sample = I->second;
> +    encodeULEB128(Loc.LineOffset, OS);
> +    encodeULEB128(Loc.Discriminator, OS);
> +    encodeULEB128(Sample.getSamples(), OS);
> +    encodeULEB128(Sample.getCallTargets().size(), OS);
> +    for (SampleRecord::CallTargetList::const_iterator
> +             I = Sample.getCallTargets().begin(),
> +             E = Sample.getCallTargets().end();
> +         I != E; ++I) {
> +      std::string Callee = (*I).first;
> +      unsigned CalleeSamples = (*I).second;
> +      OS << Callee;
> +      encodeULEB128(0, OS);
> +      encodeULEB128(CalleeSamples, OS);
> +    }
> +  }
> +
> +  return true;
> +}
> Index: lib/Transforms/Scalar/SampleProfile.cpp
> ===================================================================
> --- lib/Transforms/Scalar/SampleProfile.cpp
> +++ lib/Transforms/Scalar/SampleProfile.cpp
> @@ -737,8 +737,14 @@
>                      "Sample Profile loader", false, false)
>  
>  bool SampleProfileLoader::doInitialization(Module &M) {
> -  Reader.reset(new SampleProfileReader(M, Filename));
> -  ProfileIsValid = Reader->load();
> +  if (std::error_code EC =
> +          SampleProfileReader::create(Filename, Reader, M.getContext())) {
> +    std::string Msg = "Could not open profile: " + EC.message();
> +    DiagnosticInfoSampleProfile Diag(Filename.data(), Msg);
> +    M.getContext().diagnose(Diag);
> +    return false;
> +  }
> +  ProfileIsValid = (Reader->read() == sampleprof_error::success);
>    return true;
>  }
>  
> Index: test/Transforms/SampleProfile/Inputs/fnptr.prof
> ===================================================================
> --- /dev/null
> +++ test/Transforms/SampleProfile/Inputs/fnptr.prof
> @@ -0,0 +1,12 @@
> +_Z3fooi:7711:610
> +1: 610
> +_Z3bari:20301:1437
> +1: 1437
> +main:184019:0
> +4: 534
> +6: 2080
> +9: 2064 _Z3bari:1471 _Z3fooi:631
> +5.1: 1075
> +5: 1075
> +7: 534
> +4.2: 534
> Index: test/Transforms/SampleProfile/fnptr.ll
> ===================================================================
> --- /dev/null
> +++ test/Transforms/SampleProfile/fnptr.ll
> @@ -0,0 +1,155 @@
> +; The two profiles used in this test are the same but encoded in different
> +; formats. This checks that we produce the same profile annotations regardless
> +; of the profile format.
> +;
> +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/fnptr.prof | opt -analyze -branch-prob | FileCheck %s
> +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/fnptr.binprof | opt -analyze -branch-prob | FileCheck %s
> +
> +; CHECK:   edge for.body3 -> if.then probability is 534 / 2598 = 20.5543%
> +; CHECK:   edge for.body3 -> if.else probability is 2064 / 2598 = 79.4457%
> +; CHECK:   edge for.inc -> for.inc12 probability is 1052 / 2598 = 40.4927%
> +; CHECK:   edge for.inc -> for.body3 probability is 1546 / 2598 = 59.5073%
> +; CHECK:   edge for.inc12 -> for.end14 probability is 518 / 1052 = 49.2395%
> +; CHECK:   edge for.inc12 -> for.cond1.preheader probability is 534 / 1052 = 50.7605%
> +
> +; Original C++ test case.
> +;
> +; #include <stdlib.h>
> +; #include <math.h>
> +; #include <stdio.h>
> +;
> +; #define N 10000
> +; #define M 6000
> +;
> +; double foo(int x) {
> +;   return x * sin((double)x);
> +; }
> +;
> +; double bar(int x) {
> +;   return x - cos((double)x);
> +; }
> +;
> +; int main() {
> +;   double (*fptr)(int);
> +;   double S = 0;
> +;   for (int i = 0; i < N; i++)
> +;     for (int j = 0; j < M; j++) {
> +;       fptr = (rand() % 100 < 30) ? foo : bar;
> +;       if (rand() % 100 < 10)
> +;         S += (*fptr)(i + j * 300);
> +;       else
> +;         S += (*fptr)(i - j / 840);
> +;     }
> +;   printf("S = %lf\n", S);
> +;   return 0;
> +; }
> +
> + at .str = private unnamed_addr constant [9 x i8] c"S = %lf\0A\00", align 1
> +
> +define double @_Z3fooi(i32 %x) #0 {
> +entry:
> +  %conv = sitofp i32 %x to double, !dbg !2
> +  %call = tail call double @sin(double %conv) #3, !dbg !8
> +  %mul = fmul double %conv, %call, !dbg !8
> +  ret double %mul, !dbg !8
> +}
> +
> +declare double @sin(double) #1
> +
> +define double @_Z3bari(i32 %x) #0 {
> +entry:
> +  %conv = sitofp i32 %x to double, !dbg !9
> +  %call = tail call double @cos(double %conv) #3, !dbg !11
> +  %sub = fsub double %conv, %call, !dbg !11
> +  ret double %sub, !dbg !11
> +}
> +
> +declare double @cos(double) #1
> +
> +define i32 @main() #2 {
> +entry:
> +  br label %for.cond1.preheader, !dbg !12
> +
> +for.cond1.preheader:                              ; preds = %for.inc12, %entry
> +  %i.025 = phi i32 [ 0, %entry ], [ %inc13, %for.inc12 ]
> +  %S.024 = phi double [ 0.000000e+00, %entry ], [ %S.2.lcssa, %for.inc12 ]
> +  br label %for.body3, !dbg !14
> +
> +for.body3:                                        ; preds = %for.inc, %for.cond1.preheader
> +  %j.023 = phi i32 [ 0, %for.cond1.preheader ], [ %inc, %for.inc ]
> +  %S.122 = phi double [ %S.024, %for.cond1.preheader ], [ %S.2, %for.inc ]
> +  %call = tail call i32 @rand() #3, !dbg !15
> +  %rem = srem i32 %call, 100, !dbg !15
> +  %cmp4 = icmp slt i32 %rem, 30, !dbg !15
> +  %_Z3fooi._Z3bari = select i1 %cmp4, double (i32)* @_Z3fooi, double (i32)* @_Z3bari, !dbg !15
> +  %call5 = tail call i32 @rand() #3, !dbg !16
> +  %rem6 = srem i32 %call5, 100, !dbg !16
> +  %cmp7 = icmp slt i32 %rem6, 10, !dbg !16
> +  br i1 %cmp7, label %if.then, label %if.else, !dbg !16, !prof !17
> +
> +if.then:                                          ; preds = %for.body3
> +  %mul = mul nsw i32 %j.023, 300, !dbg !18
> +  %add = add nsw i32 %mul, %i.025, !dbg !18
> +  %call8 = tail call double %_Z3fooi._Z3bari(i32 %add), !dbg !18
> +  br label %for.inc, !dbg !18
> +
> +if.else:                                          ; preds = %for.body3
> +  %div = sdiv i32 %j.023, 840, !dbg !19
> +  %sub = sub nsw i32 %i.025, %div, !dbg !19
> +  %call10 = tail call double %_Z3fooi._Z3bari(i32 %sub), !dbg !19
> +  br label %for.inc
> +
> +for.inc:                                          ; preds = %if.then, %if.else
> +  %call8.pn = phi double [ %call8, %if.then ], [ %call10, %if.else ]
> +  %S.2 = fadd double %S.122, %call8.pn, !dbg !18
> +  %inc = add nsw i32 %j.023, 1, !dbg !20
> +  %exitcond = icmp eq i32 %j.023, 5999, !dbg !14
> +  br i1 %exitcond, label %for.inc12, label %for.body3, !dbg !14, !prof !21
> +
> +for.inc12:                                        ; preds = %for.inc
> +  %S.2.lcssa = phi double [ %S.2, %for.inc ]
> +  %inc13 = add nsw i32 %i.025, 1, !dbg !22
> +  %exitcond26 = icmp eq i32 %i.025, 9999, !dbg !12
> +  br i1 %exitcond26, label %for.end14, label %for.cond1.preheader, !dbg !12, !prof !23
> +
> +for.end14:                                        ; preds = %for.inc12
> +  %S.2.lcssa.lcssa = phi double [ %S.2.lcssa, %for.inc12 ]
> +  %call15 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @.str, i64 0, i64 0), double %S.2.lcssa.lcssa), !dbg !24
> +  ret i32 0, !dbg !25
> +}
> +
> +; Function Attrs: nounwind
> +declare i32 @rand() #1
> +
> +; Function Attrs: nounwind
> +declare i32 @printf(i8* nocapture readonly, ...) #1
> +
> +!llvm.module.flags = !{!0}
> +!llvm.ident = !{!1}
> +
> +!0 = metadata !{i32 2, metadata !"Debug Info Version", i32 2}
> +!1 = metadata !{metadata !"clang version 3.6.0 "}
> +!2 = metadata !{i32 9, i32 3, metadata !3, null}
> +!3 = metadata !{metadata !"0x2e\00foo\00foo\00\008\000\001\000\000\00256\001\008", metadata !4, metadata !5, metadata !6, null, double (i32)* @_Z3fooi, null, null, metadata !7} ; [ DW_TAG_subprogram ] [line 8] [def] [foo]
> +!4 = metadata !{metadata !"fnptr.cc", metadata !"."}
> +!5 = metadata !{metadata !"0x29", metadata !4}    ; [ DW_TAG_file_type ] [./fnptr.cc]
> +!6 = metadata !{metadata !"0x15\00\000\000\000\000\000\000", null, null, null, metadata !7, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
> +!7 = metadata !{}
> +!8 = metadata !{i32 9, i32 14, metadata !3, null}
> +!9 = metadata !{i32 13, i32 3, metadata !10, null}
> +!10 = metadata !{metadata !"0x2e\00bar\00bar\00\0012\000\001\000\000\00256\001\0012", metadata !4, metadata !5, metadata !6, null, double (i32)* @_Z3bari, null, null, metadata !7} ; [ DW_TAG_subprogram ] [line 12] [def] [bar]
> +!11 = metadata !{i32 13, i32 14, metadata !10, null}
> +!12 = metadata !{i32 19, i32 3, metadata !13, null}
> +!13 = metadata !{metadata !"0x2e\00main\00main\00\0016\000\001\000\000\00256\001\0016", metadata !4, metadata !5, metadata !6, null, i32 ()* @main, null, null, metadata !7} ; [ DW_TAG_subprogram ] [line 16] [def] [main]
> +!14 = metadata !{i32 20, i32 5, metadata !13, null}
> +!15 = metadata !{i32 21, i32 15, metadata !13, null}
> +!16 = metadata !{i32 22, i32 11, metadata !13, null}
> +!17 = metadata !{metadata !"branch_weights", i32 534, i32 2064}
> +!18 = metadata !{i32 23, i32 14, metadata !13, null}
> +!19 = metadata !{i32 25, i32 14, metadata !13, null}
> +!20 = metadata !{i32 20, i32 28, metadata !13, null}
> +!21 = metadata !{metadata !"branch_weights", i32 0, i32 1075}
> +!22 = metadata !{i32 19, i32 26, metadata !13, null}
> +!23 = metadata !{metadata !"branch_weights", i32 0, i32 534}
> +!24 = metadata !{i32 27, i32 3, metadata !13, null}
> +!25 = metadata !{i32 28, i32 3, metadata !13, null}
> Index: test/Transforms/SampleProfile/syntax.ll
> ===================================================================
> --- test/Transforms/SampleProfile/syntax.ll
> +++ test/Transforms/SampleProfile/syntax.ll
> @@ -12,7 +12,7 @@
>    ret void
>  }
>  ; NO-DEBUG: warning: No debug information found in function empty: Function profile not used
> -; MISSING-FILE: error: missing.prof:
> +; MISSING-FILE: missing.prof: Could not open profile: No such file or directory
>  ; BAD-FN-HEADER: error: {{.*}}bad_fn_header.prof:1: Expected 'mangled_name:NUM:NUM', found 3empty:100:BAD
>  ; BAD-SAMPLE-LINE: error: {{.*}}bad_sample_line.prof:3: Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found 1: BAD
>  ; BAD-LINE-VALUES: error: {{.*}}bad_line_values.prof:2: Expected 'mangled_name:NUM:NUM', found -1: 10



More information about the llvm-commits mailing list