brintos

brintos / llvm-project-archived public Read only

0
0
Text · 49.6 KiB · d842275 Raw
1374 lines · cpp
1//===- GCOVProfiling.cpp - Insert edge counters for gcov profiling --------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This pass implements GCOV-style profiling. When this pass is run it emits10// "gcno" files next to the existing source, and instruments the code that runs11// to records the edges between blocks that run and emit a complementary "gcda"12// file on exit.13//14//===----------------------------------------------------------------------===//15 16#include "llvm/ADT/Hashing.h"17#include "llvm/ADT/MapVector.h"18#include "llvm/ADT/STLExtras.h"19#include "llvm/ADT/Sequence.h"20#include "llvm/ADT/StringMap.h"21#include "llvm/Analysis/BlockFrequencyInfo.h"22#include "llvm/Analysis/BranchProbabilityInfo.h"23#include "llvm/Analysis/TargetLibraryInfo.h"24#include "llvm/IR/DebugInfo.h"25#include "llvm/IR/DebugLoc.h"26#include "llvm/IR/EHPersonalities.h"27#include "llvm/IR/IRBuilder.h"28#include "llvm/IR/InstIterator.h"29#include "llvm/IR/Instructions.h"30#include "llvm/IR/Module.h"31#include "llvm/ProfileData/InstrProf.h"32#include "llvm/Support/CRC.h"33#include "llvm/Support/CommandLine.h"34#include "llvm/Support/Debug.h"35#include "llvm/Support/FileSystem.h"36#include "llvm/Support/Path.h"37#include "llvm/Support/Regex.h"38#include "llvm/Support/VirtualFileSystem.h"39#include "llvm/Support/raw_ostream.h"40#include "llvm/Transforms/Instrumentation/CFGMST.h"41#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"42#include "llvm/Transforms/Utils/Instrumentation.h"43#include "llvm/Transforms/Utils/ModuleUtils.h"44#include <algorithm>45#include <memory>46#include <string>47#include <utility>48 49using namespace llvm;50namespace endian = llvm::support::endian;51 52#define DEBUG_TYPE "insert-gcov-profiling"53 54enum : uint32_t {55  GCOV_ARC_ON_TREE = 1 << 0,56 57  GCOV_TAG_FUNCTION = 0x01000000,58  GCOV_TAG_BLOCKS = 0x01410000,59  GCOV_TAG_ARCS = 0x01430000,60  GCOV_TAG_LINES = 0x01450000,61};62 63static cl::opt<std::string> DefaultGCOVVersion("default-gcov-version",64                                               cl::init("0000"), cl::Hidden,65                                               cl::ValueRequired);66 67static cl::opt<bool> AtomicCounter("gcov-atomic-counter", cl::Hidden,68                                   cl::desc("Make counter updates atomic"));69 70// Returns the number of words which will be used to represent this string.71static unsigned wordsOfString(StringRef s) {72  // Length + NUL-terminated string + 0~3 padding NULs.73  return (s.size() / 4) + 2;74}75 76GCOVOptions GCOVOptions::getDefault() {77  GCOVOptions Options;78  Options.EmitNotes = true;79  Options.EmitData = true;80  Options.NoRedZone = false;81  Options.Atomic = AtomicCounter;82 83  if (DefaultGCOVVersion.size() != 4) {84    reportFatalUsageError(Twine("Invalid -default-gcov-version: ") +85                          DefaultGCOVVersion);86  }87  memcpy(Options.Version, DefaultGCOVVersion.c_str(), 4);88  return Options;89}90 91namespace {92class GCOVFunction;93 94class GCOVProfiler {95public:96  GCOVProfiler()97      : GCOVProfiler(GCOVOptions::getDefault(), *vfs::getRealFileSystem()) {}98  GCOVProfiler(const GCOVOptions &Opts, vfs::FileSystem &VFS)99      : Options(Opts), VFS(VFS) {}100  bool101  runOnModule(Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,102              function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,103              std::function<const TargetLibraryInfo &(Function &F)> GetTLI);104 105  void write(uint32_t i) {106    char Bytes[4];107    endian::write32(Bytes, i, Endian);108    os->write(Bytes, 4);109  }110  void writeString(StringRef s) {111    write(wordsOfString(s) - 1);112    os->write(s.data(), s.size());113    os->write_zeros(4 - s.size() % 4);114  }115  void writeBytes(const char *Bytes, int Size) { os->write(Bytes, Size); }116  vfs::FileSystem &getVirtualFileSystem() const { return VFS; }117 118private:119  // Create the .gcno files for the Module based on DebugInfo.120  bool121  emitProfileNotes(NamedMDNode *CUNode, bool HasExecOrFork,122                   function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,123                   function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,124                   function_ref<const TargetLibraryInfo &(Function &F)> GetTLI);125 126  Function *createInternalFunction(FunctionType *FTy, StringRef Name,127                                   StringRef MangledType = "");128 129  void emitGlobalConstructor(130      SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP);131  void emitModuleInitFunctionPtrs(132      SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP);133 134  bool isFunctionInstrumented(const Function &F);135  std::vector<Regex> createRegexesFromString(StringRef RegexesStr);136  static bool doesFilenameMatchARegex(StringRef Filename,137                                      std::vector<Regex> &Regexes);138 139  // Get pointers to the functions in the runtime library.140  FunctionCallee getStartFileFunc(const TargetLibraryInfo *TLI);141  FunctionCallee getEmitFunctionFunc(const TargetLibraryInfo *TLI);142  FunctionCallee getEmitArcsFunc(const TargetLibraryInfo *TLI);143  FunctionCallee getSummaryInfoFunc();144  FunctionCallee getEndFileFunc();145 146  // Add the function to write out all our counters to the global destructor147  // list.148  Function *149  insertCounterWriteout(ArrayRef<std::pair<GlobalVariable *, MDNode *>>);150  Function *insertReset(ArrayRef<std::pair<GlobalVariable *, MDNode *>>);151 152  bool AddFlushBeforeForkAndExec();153 154  enum class GCovFileType { GCNO, GCDA };155  std::string mangleName(const DICompileUnit *CU, GCovFileType FileType);156 157  GCOVOptions Options;158  llvm::endianness Endian;159  raw_ostream *os;160  int Version = 0;161 162  // Checksum, produced by hash of EdgeDestinations163  SmallVector<uint32_t, 4> FileChecksums;164 165  Module *M = nullptr;166  std::function<const TargetLibraryInfo &(Function &F)> GetTLI;167  LLVMContext *Ctx = nullptr;168  SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs;169  std::vector<Regex> FilterRe;170  std::vector<Regex> ExcludeRe;171  DenseSet<const BasicBlock *> ExecBlocks;172  StringMap<bool> InstrumentedFiles;173  vfs::FileSystem &VFS;174};175 176struct BBInfo {177  BBInfo *Group;178  uint32_t Index;179  uint32_t Rank = 0;180 181  BBInfo(unsigned Index) : Group(this), Index(Index) {}182  std::string infoString() const {183    return (Twine("Index=") + Twine(Index)).str();184  }185};186 187struct Edge {188  // This class implements the CFG edges. Note the CFG can be a multi-graph.189  // So there might be multiple edges with same SrcBB and DestBB.190  const BasicBlock *SrcBB;191  const BasicBlock *DestBB;192  uint64_t Weight;193  BasicBlock *Place = nullptr;194  uint32_t SrcNumber, DstNumber;195  bool InMST = false;196  bool Removed = false;197  bool IsCritical = false;198 199  Edge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W = 1)200      : SrcBB(Src), DestBB(Dest), Weight(W) {}201 202  // Return the information string of an edge.203  std::string infoString() const {204    return (Twine(Removed ? "-" : " ") + (InMST ? " " : "*") +205            (IsCritical ? "c" : " ") + "  W=" + Twine(Weight))206        .str();207  }208};209}210 211static StringRef getFunctionName(const DISubprogram *SP) {212  if (!SP->getLinkageName().empty())213    return SP->getLinkageName();214  return SP->getName();215}216 217/// Extract a filename for a DIScope.218///219/// Prefer relative paths in the coverage notes. Clang also may split220/// up absolute paths into a directory and filename component. When221/// the relative path doesn't exist, reconstruct the absolute path.222static SmallString<128> getFilename(const DIScope *SP, vfs::FileSystem &VFS) {223  SmallString<128> Path;224  StringRef RelPath = SP->getFilename();225  if (VFS.exists(RelPath))226    Path = RelPath;227  else228    sys::path::append(Path, SP->getDirectory(), SP->getFilename());229  return Path;230}231 232namespace {233  class GCOVRecord {234  protected:235    GCOVProfiler *P;236 237    GCOVRecord(GCOVProfiler *P) : P(P) {}238 239    void write(uint32_t i) { P->write(i); }240    void writeString(StringRef s) { P->writeString(s); }241    void writeBytes(const char *Bytes, int Size) { P->writeBytes(Bytes, Size); }242  };243 244  class GCOVFunction;245  class GCOVBlock;246 247  // Constructed only by requesting it from a GCOVBlock, this object stores a248  // list of line numbers and a single filename, representing lines that belong249  // to the block.250  class GCOVLines : public GCOVRecord {251  public:252    StringRef getFilename() { return Filename; }253 254    void addLine(uint32_t Line) {255      assert(Line != 0 && "Line zero is not a valid real line number.");256      Lines.push_back(Line);257    }258 259    uint32_t length() const {260      return 1 + wordsOfString(Filename) + Lines.size();261    }262 263    void writeOut() {264      write(0);265      writeString(Filename);266      for (uint32_t L : Lines)267        write(L);268    }269 270    GCOVLines(GCOVProfiler *P, StringRef F)271        : GCOVRecord(P), Filename(std::string(F)) {}272 273  private:274    std::string Filename;275    SmallVector<uint32_t, 32> Lines;276  };277 278 279  // Represent a basic block in GCOV. Each block has a unique number in the280  // function, number of lines belonging to each block, and a set of edges to281  // other blocks.282  class GCOVBlock : public GCOVRecord {283   public:284    GCOVLines &getFile(StringRef Filename) {285      if (Lines.empty() || Lines.back().getFilename() != Filename)286        Lines.emplace_back(P, Filename);287      return Lines.back();288    }289 290    void addEdge(GCOVBlock &Successor, uint32_t Flags) {291      OutEdges.emplace_back(&Successor, Flags);292    }293 294    void writeOut() {295      uint32_t Len = 3;296 297      for (auto &L : Lines)298        Len += L.length();299 300      write(GCOV_TAG_LINES);301      write(Len);302      write(Number);303 304      for (auto &L : Lines)305        L.writeOut();306      write(0);307      write(0);308    }309 310    GCOVBlock(const GCOVBlock &RHS) : GCOVRecord(RHS), Number(RHS.Number) {311      // Only allow copy before edges and lines have been added. After that,312      // there are inter-block pointers (eg: edges) that won't take kindly to313      // blocks being copied or moved around.314      assert(Lines.empty());315      assert(OutEdges.empty());316    }317 318    uint32_t Number;319    SmallVector<std::pair<GCOVBlock *, uint32_t>, 4> OutEdges;320 321  private:322    friend class GCOVFunction;323 324    GCOVBlock(GCOVProfiler *P, uint32_t Number)325        : GCOVRecord(P), Number(Number) {}326 327    SmallVector<GCOVLines> Lines;328  };329 330  // A function has a unique identifier, a checksum (we leave as zero) and a331  // set of blocks and a map of edges between blocks. This is the only GCOV332  // object users can construct, the blocks and lines will be rooted here.333  class GCOVFunction : public GCOVRecord {334  public:335    GCOVFunction(GCOVProfiler *P, Function *F, const DISubprogram *SP,336                 unsigned EndLine, uint32_t Ident, int Version)337        : GCOVRecord(P), SP(SP), EndLine(EndLine), Ident(Ident),338          Version(Version), EntryBlock(P, 0), ReturnBlock(P, 1) {339      LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n");340      uint32_t i = 2;341      for (BasicBlock &BB : *F)342        Blocks.insert(std::make_pair(&BB, GCOVBlock(P, i++)));343 344      std::string FunctionNameAndLine;345      raw_string_ostream FNLOS(FunctionNameAndLine);346      FNLOS << getFunctionName(SP) << SP->getLine();347      FuncChecksum = hash_value(FunctionNameAndLine);348    }349 350    GCOVBlock &getBlock(const BasicBlock *BB) {351      return Blocks.find(const_cast<BasicBlock *>(BB))->second;352    }353 354    GCOVBlock &getEntryBlock() { return EntryBlock; }355    GCOVBlock &getReturnBlock() {356      return ReturnBlock;357    }358 359    uint32_t getFuncChecksum() const {360      return FuncChecksum;361    }362 363    void writeOut(uint32_t CfgChecksum) {364      write(GCOV_TAG_FUNCTION);365      SmallString<128> Filename = getFilename(SP, P->getVirtualFileSystem());366      uint32_t BlockLen = 3 + wordsOfString(getFunctionName(SP));367      BlockLen += 1 + wordsOfString(Filename) + 4;368 369      write(BlockLen);370      write(Ident);371      write(FuncChecksum);372      write(CfgChecksum);373      writeString(getFunctionName(SP));374 375      write(SP->isArtificial()); // artificial376      writeString(Filename);377      write(SP->getLine()); // start_line378      write(0);             // start_column379      // EndLine is the last line with !dbg. It is not the } line as in GCC,380      // but good enough.381      write(EndLine);382      write(0); // end_column383 384      // Emit count of blocks.385      write(GCOV_TAG_BLOCKS);386      write(1);387      write(Blocks.size() + 2);388      LLVM_DEBUG(dbgs() << (Blocks.size() + 1) << " blocks\n");389 390      // Emit edges between blocks.391      const uint32_t Outgoing = EntryBlock.OutEdges.size();392      if (Outgoing) {393        write(GCOV_TAG_ARCS);394        write(Outgoing * 2 + 1);395        write(EntryBlock.Number);396        for (const auto &E : EntryBlock.OutEdges) {397          write(E.first->Number);398          write(E.second);399        }400      }401      for (auto &It : Blocks) {402        const GCOVBlock &Block = It.second;403        if (Block.OutEdges.empty()) continue;404 405        write(GCOV_TAG_ARCS);406        write(Block.OutEdges.size() * 2 + 1);407        write(Block.Number);408        for (const auto &E : Block.OutEdges) {409          write(E.first->Number);410          write(E.second);411        }412      }413 414      // Emit lines for each block.415      for (auto &It : Blocks)416        It.second.writeOut();417    }418 419  public:420    const DISubprogram *SP;421    unsigned EndLine;422    uint32_t Ident;423    uint32_t FuncChecksum;424    int Version;425    MapVector<BasicBlock *, GCOVBlock> Blocks;426    GCOVBlock EntryBlock;427    GCOVBlock ReturnBlock;428  };429}430 431// RegexesStr is a string containing differents regex separated by a semi-colon.432// For example "foo\..*$;bar\..*$".433std::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) {434  std::vector<Regex> Regexes;435  while (!RegexesStr.empty()) {436    std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(';');437    if (!HeadTail.first.empty()) {438      Regex Re(HeadTail.first);439      std::string Err;440      if (!Re.isValid(Err)) {441        Ctx->emitError(Twine("Regex ") + HeadTail.first +442                       " is not valid: " + Err);443      }444      Regexes.emplace_back(std::move(Re));445    }446    RegexesStr = HeadTail.second;447  }448  return Regexes;449}450 451bool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename,452                                           std::vector<Regex> &Regexes) {453  for (Regex &Re : Regexes)454    if (Re.match(Filename))455      return true;456  return false;457}458 459bool GCOVProfiler::isFunctionInstrumented(const Function &F) {460  if (FilterRe.empty() && ExcludeRe.empty()) {461    return true;462  }463  SmallString<128> Filename = getFilename(F.getSubprogram(), VFS);464  auto It = InstrumentedFiles.find(Filename);465  if (It != InstrumentedFiles.end()) {466    return It->second;467  }468 469  SmallString<256> RealPath;470  StringRef RealFilename;471 472  // Path can be473  // /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for474  // such a case we must get the real_path.475  if (VFS.getRealPath(Filename, RealPath)) {476    // real_path can fail with path like "foo.c".477    RealFilename = Filename;478  } else {479    RealFilename = RealPath;480  }481 482  bool ShouldInstrument;483  if (FilterRe.empty()) {484    ShouldInstrument = !doesFilenameMatchARegex(RealFilename, ExcludeRe);485  } else if (ExcludeRe.empty()) {486    ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe);487  } else {488    ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe) &&489                       !doesFilenameMatchARegex(RealFilename, ExcludeRe);490  }491  InstrumentedFiles[Filename] = ShouldInstrument;492  return ShouldInstrument;493}494 495std::string GCOVProfiler::mangleName(const DICompileUnit *CU,496                                     GCovFileType OutputType) {497  bool Notes = OutputType == GCovFileType::GCNO;498 499  if (NamedMDNode *GCov = M->getNamedMetadata("llvm.gcov")) {500    for (int i = 0, e = GCov->getNumOperands(); i != e; ++i) {501      MDNode *N = GCov->getOperand(i);502      bool ThreeElement = N->getNumOperands() == 3;503      if (!ThreeElement && N->getNumOperands() != 2)504        continue;505      if (dyn_cast<MDNode>(N->getOperand(ThreeElement ? 2 : 1)) != CU)506        continue;507 508      if (ThreeElement) {509        // These nodes have no mangling to apply, it's stored mangled in the510        // bitcode.511        MDString *NotesFile = dyn_cast<MDString>(N->getOperand(0));512        MDString *DataFile = dyn_cast<MDString>(N->getOperand(1));513        if (!NotesFile || !DataFile)514          continue;515        return std::string(Notes ? NotesFile->getString()516                                 : DataFile->getString());517      }518 519      MDString *GCovFile = dyn_cast<MDString>(N->getOperand(0));520      if (!GCovFile)521        continue;522 523      SmallString<128> Filename = GCovFile->getString();524      sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda");525      return std::string(Filename);526    }527  }528 529  SmallString<128> Filename = CU->getFilename();530  sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda");531  StringRef FName = sys::path::filename(Filename);532  ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();533  if (!CWD)534    return std::string(FName);535  SmallString<128> CurPath{*CWD};536  sys::path::append(CurPath, FName);537  return std::string(CurPath);538}539 540bool GCOVProfiler::runOnModule(541    Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,542    function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,543    std::function<const TargetLibraryInfo &(Function &F)> GetTLI) {544  this->M = &M;545  this->GetTLI = std::move(GetTLI);546  Ctx = &M.getContext();547 548  NamedMDNode *CUNode = M.getNamedMetadata("llvm.dbg.cu");549  if (!CUNode || (!Options.EmitNotes && !Options.EmitData))550    return false;551 552  bool HasExecOrFork = AddFlushBeforeForkAndExec();553 554  FilterRe = createRegexesFromString(Options.Filter);555  ExcludeRe = createRegexesFromString(Options.Exclude);556  emitProfileNotes(CUNode, HasExecOrFork, GetBFI, GetBPI, this->GetTLI);557  return true;558}559 560PreservedAnalyses GCOVProfilerPass::run(Module &M,561                                        ModuleAnalysisManager &AM) {562 563  GCOVProfiler Profiler(GCOVOpts, *VFS);564  FunctionAnalysisManager &FAM =565      AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();566 567  auto GetBFI = [&FAM](Function &F) {568    return &FAM.getResult<BlockFrequencyAnalysis>(F);569  };570  auto GetBPI = [&FAM](Function &F) {571    return &FAM.getResult<BranchProbabilityAnalysis>(F);572  };573  auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & {574    return FAM.getResult<TargetLibraryAnalysis>(F);575  };576 577  if (!Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI))578    return PreservedAnalyses::all();579 580  return PreservedAnalyses::none();581}582 583static bool functionHasLines(const Function &F, unsigned &EndLine) {584  // Check whether this function actually has any source lines. Not only585  // do these waste space, they also can crash gcov.586  EndLine = 0;587  for (const auto &BB : F) {588    for (const auto &I : BB) {589      const DebugLoc &Loc = I.getDebugLoc();590      if (!Loc)591        continue;592 593      // Artificial lines such as calls to the global constructors.594      if (Loc.getLine() == 0) continue;595      EndLine = std::max(EndLine, Loc.getLine());596 597      return true;598    }599  }600  return false;601}602 603static bool isUsingScopeBasedEH(Function &F) {604  if (!F.hasPersonalityFn()) return false;605 606  EHPersonality Personality = classifyEHPersonality(F.getPersonalityFn());607  return isScopedEHPersonality(Personality);608}609 610bool GCOVProfiler::AddFlushBeforeForkAndExec() {611  const TargetLibraryInfo *TLI = nullptr;612  SmallVector<CallInst *, 2> Forks;613  SmallVector<CallInst *, 2> Execs;614  for (auto &F : M->functions()) {615    TLI = TLI == nullptr ? &GetTLI(F) : TLI;616    for (auto &I : instructions(F)) {617      if (CallInst *CI = dyn_cast<CallInst>(&I)) {618        if (Function *Callee = CI->getCalledFunction()) {619          LibFunc LF;620          if (TLI->getLibFunc(*Callee, LF)) {621            if (LF == LibFunc_fork) {622#if !defined(_WIN32)623              Forks.push_back(CI);624#endif625            } else if (LF == LibFunc_execl || LF == LibFunc_execle ||626                       LF == LibFunc_execlp || LF == LibFunc_execv ||627                       LF == LibFunc_execvp || LF == LibFunc_execve ||628                       LF == LibFunc_execvpe || LF == LibFunc_execvP) {629              Execs.push_back(CI);630            }631          }632        }633      }634    }635  }636 637  for (auto *F : Forks) {638    IRBuilder<> Builder(F);639    BasicBlock *Parent = F->getParent();640    auto NextInst = ++F->getIterator();641 642    // We've a fork so just reset the counters in the child process643    FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false);644    FunctionCallee GCOVFork = M->getOrInsertFunction(645        "__gcov_fork", FTy,646        TLI->getAttrList(Ctx, {}, /*Signed=*/true, /*Ret=*/true));647    F->setCalledFunction(GCOVFork);648 649    // We split just after the fork to have a counter for the lines after650    // Anyway there's a bug:651    // void foo() { fork(); }652    // void bar() { foo(); blah(); }653    // then "blah();" will be called 2 times but showed as 1654    // because "blah()" belongs to the same block as "foo();"655    Parent->splitBasicBlock(NextInst);656 657    // back() is a br instruction with a debug location658    // equals to the one from NextAfterFork659    // So to avoid to have two debug locs on two blocks just change it660    DebugLoc Loc = F->getDebugLoc();661    Parent->back().setDebugLoc(Loc);662  }663 664  for (auto *E : Execs) {665    IRBuilder<> Builder(E);666    BasicBlock *Parent = E->getParent();667    auto NextInst = ++E->getIterator();668 669    // Since the process is replaced by a new one we need to write out gcdas670    // No need to reset the counters since they'll be lost after the exec**671    FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false);672    FunctionCallee WriteoutF =673        M->getOrInsertFunction("llvm_writeout_files", FTy);674    Builder.CreateCall(WriteoutF);675 676    DebugLoc Loc = E->getDebugLoc();677    Builder.SetInsertPoint(&*NextInst);678    // If the exec** fails we must reset the counters since they've been679    // dumped680    FunctionCallee ResetF = M->getOrInsertFunction("llvm_reset_counters", FTy);681    Builder.CreateCall(ResetF)->setDebugLoc(Loc);682    ExecBlocks.insert(Parent);683    Parent->splitBasicBlock(NextInst);684    Parent->back().setDebugLoc(Loc);685  }686 687  return !Forks.empty() || !Execs.empty();688}689 690static BasicBlock *getInstrBB(CFGMST<Edge, BBInfo> &MST, Edge &E,691                              const DenseSet<const BasicBlock *> &ExecBlocks) {692  if (E.InMST || E.Removed)693    return nullptr;694 695  BasicBlock *SrcBB = const_cast<BasicBlock *>(E.SrcBB);696  BasicBlock *DestBB = const_cast<BasicBlock *>(E.DestBB);697  // For a fake edge, instrument the real BB.698  if (SrcBB == nullptr)699    return DestBB;700  if (DestBB == nullptr)701    return SrcBB;702 703  auto CanInstrument = [](BasicBlock *BB) -> BasicBlock * {704    // There are basic blocks (such as catchswitch) cannot be instrumented.705    // If the returned first insertion point is the end of BB, skip this BB.706    if (BB->getFirstInsertionPt() == BB->end())707      return nullptr;708    return BB;709  };710 711  // Instrument the SrcBB if it has a single successor,712  // otherwise, the DestBB if this is not a critical edge.713  Instruction *TI = SrcBB->getTerminator();714  if (TI->getNumSuccessors() <= 1 && !ExecBlocks.count(SrcBB))715    return CanInstrument(SrcBB);716  if (!E.IsCritical)717    return CanInstrument(DestBB);718 719  // Some IndirectBr critical edges cannot be split by the previous720  // SplitIndirectBrCriticalEdges call. Bail out.721  const unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB);722  BasicBlock *InstrBB =723      isa<IndirectBrInst>(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum);724  if (!InstrBB)725    return nullptr;726 727  MST.addEdge(SrcBB, InstrBB, 0);728  MST.addEdge(InstrBB, DestBB, 0).InMST = true;729  E.Removed = true;730 731  return CanInstrument(InstrBB);732}733 734#ifndef NDEBUG735static void dumpEdges(CFGMST<Edge, BBInfo> &MST, GCOVFunction &GF) {736  size_t ID = 0;737  for (const auto &E : make_pointee_range(MST.allEdges())) {738    GCOVBlock &Src = E.SrcBB ? GF.getBlock(E.SrcBB) : GF.getEntryBlock();739    GCOVBlock &Dst = E.DestBB ? GF.getBlock(E.DestBB) : GF.getReturnBlock();740    dbgs() << "  Edge " << ID++ << ": " << Src.Number << "->" << Dst.Number741           << E.infoString() << "\n";742  }743}744#endif745 746bool GCOVProfiler::emitProfileNotes(747    NamedMDNode *CUNode, bool HasExecOrFork,748    function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,749    function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,750    function_ref<const TargetLibraryInfo &(Function &F)> GetTLI) {751  {752    uint8_t c3 = Options.Version[0];753    uint8_t c2 = Options.Version[1];754    uint8_t c1 = Options.Version[2];755    Version = c3 >= 'A' ? (c3 - 'A') * 100 + (c2 - '0') * 10 + c1 - '0'756                        : (c3 - '0') * 10 + c1 - '0';757  }758  // Emit .gcno files that are compatible with GCC 11.1.759  if (Version < 111) {760    Version = 111;761    memcpy(Options.Version, "B11*", 4);762  }763 764  bool EmitGCDA = Options.EmitData;765  for (unsigned i = 0, e = CUNode->getNumOperands(); i != e; ++i) {766    // Each compile unit gets its own .gcno file. This means that whether we run767    // this pass over the original .o's as they're produced, or run it after768    // LTO, we'll generate the same .gcno files.769 770    auto *CU = cast<DICompileUnit>(CUNode->getOperand(i));771 772    // Skip module skeleton (and module) CUs.773    if (CU->getDWOId())774      continue;775 776    std::vector<uint8_t> EdgeDestinations;777    SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP;778 779    Endian = M->getDataLayout().isLittleEndian() ? llvm::endianness::little780                                                 : llvm::endianness::big;781    unsigned FunctionIdent = 0;782    for (auto &F : M->functions()) {783      DISubprogram *SP = F.getSubprogram();784      unsigned EndLine;785      if (!SP) continue;786      if (!functionHasLines(F, EndLine) || !isFunctionInstrumented(F))787        continue;788      // TODO: Functions using scope-based EH are currently not supported.789      if (isUsingScopeBasedEH(F)) continue;790      if (F.hasFnAttribute(llvm::Attribute::NoProfile))791        continue;792      if (F.hasFnAttribute(llvm::Attribute::SkipProfile))793        continue;794 795      // Add the function line number to the lines of the entry block796      // to have a counter for the function definition.797      uint32_t Line = SP->getLine();798      auto Filename = getFilename(SP, VFS);799 800      BranchProbabilityInfo *BPI = GetBPI(F);801      BlockFrequencyInfo *BFI = GetBFI(F);802 803      // Split indirectbr critical edges here before computing the MST rather804      // than later in getInstrBB() to avoid invalidating it.805      SplitIndirectBrCriticalEdges(F, /*IgnoreBlocksWithoutPHI=*/false, BPI,806                                   BFI);807 808      CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry=*/false,809                               /*InstrumentLoopEntries=*/false, BPI, BFI);810 811      // getInstrBB can split basic blocks and push elements to AllEdges.812      for (size_t I : llvm::seq<size_t>(0, MST.numEdges())) {813        auto &E = *MST.allEdges()[I];814        // For now, disable spanning tree optimization when fork or exec* is815        // used.816        if (HasExecOrFork)817          E.InMST = false;818        E.Place = getInstrBB(MST, E, ExecBlocks);819      }820      // Basic blocks in F are finalized at this point.821      BasicBlock &EntryBlock = F.getEntryBlock();822      Funcs.push_back(std::make_unique<GCOVFunction>(this, &F, SP, EndLine,823                                                     FunctionIdent++, Version));824      GCOVFunction &Func = *Funcs.back();825 826      // Some non-tree edges are IndirectBr which cannot be split. Ignore them827      // as well.828      llvm::erase_if(MST.allEdges(), [](std::unique_ptr<Edge> &E) {829        return E->Removed || (!E->InMST && !E->Place);830      });831      const size_t Measured =832          std::stable_partition(833              MST.allEdges().begin(), MST.allEdges().end(),834              [](std::unique_ptr<Edge> &E) { return E->Place; }) -835          MST.allEdges().begin();836      for (size_t I : llvm::seq<size_t>(0, Measured)) {837        Edge &E = *MST.allEdges()[I];838        GCOVBlock &Src =839            E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock();840        GCOVBlock &Dst =841            E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock();842        E.SrcNumber = Src.Number;843        E.DstNumber = Dst.Number;844      }845      std::stable_sort(846          MST.allEdges().begin(), MST.allEdges().begin() + Measured,847          [](const std::unique_ptr<Edge> &L, const std::unique_ptr<Edge> &R) {848            return L->SrcNumber != R->SrcNumber ? L->SrcNumber < R->SrcNumber849                                                : L->DstNumber < R->DstNumber;850          });851 852      for (const Edge &E : make_pointee_range(MST.allEdges())) {853        GCOVBlock &Src =854            E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock();855        GCOVBlock &Dst =856            E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock();857        Src.addEdge(Dst, E.Place ? 0 : uint32_t(GCOV_ARC_ON_TREE));858      }859 860      // Artificial functions such as global initializers861      if (!SP->isArtificial())862        Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line);863 864      LLVM_DEBUG(dumpEdges(MST, Func));865 866      for (auto &GB : Func.Blocks) {867        const BasicBlock &BB = *GB.first;868        auto &Block = GB.second;869        for (auto Succ : Block.OutEdges) {870          uint32_t Idx = Succ.first->Number;871          do EdgeDestinations.push_back(Idx & 255);872          while ((Idx >>= 8) > 0);873        }874 875        for (const auto &I : BB) {876          const DebugLoc &Loc = I.getDebugLoc();877          if (!Loc)878            continue;879 880          // Artificial lines such as calls to the global constructors.881          if (Loc.getLine() == 0 || Loc.isImplicitCode())882            continue;883 884          if (Line == Loc.getLine()) continue;885          Line = Loc.getLine();886          MDNode *Scope = Loc.getScope();887          if (SP != getDISubprogram(Scope))888            continue;889 890          GCOVLines &Lines = Block.getFile(getFilename(Loc->getScope(), VFS));891          Lines.addLine(Loc.getLine());892        }893        Line = 0;894      }895      if (EmitGCDA) {896        DISubprogram *SP = F.getSubprogram();897        ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Measured);898        GlobalVariable *Counters = new GlobalVariable(899            *M, CounterTy, false, GlobalValue::InternalLinkage,900            Constant::getNullValue(CounterTy), "__llvm_gcov_ctr");901        const llvm::Triple &Triple = M->getTargetTriple();902        if (Triple.getObjectFormat() == llvm::Triple::XCOFF)903          Counters->setSection("__llvm_gcov_ctr_section");904        CountersBySP.emplace_back(Counters, SP);905 906        for (size_t I : llvm::seq<size_t>(0, Measured)) {907          const Edge &E = *MST.allEdges()[I];908          IRBuilder<> Builder(E.Place, E.Place->getFirstInsertionPt());909          Value *V = Builder.CreateConstInBoundsGEP2_64(910              Counters->getValueType(), Counters, 0, I);911          // Disable sanitizers to decrease size bloat. We don't expect912          // sanitizers to catch interesting issues.913          Instruction *Inst;914          if (Options.Atomic) {915            Inst = Builder.CreateAtomicRMW(AtomicRMWInst::Add, V,916                                           Builder.getInt64(1), MaybeAlign(),917                                           AtomicOrdering::Monotonic);918          } else {919            LoadInst *OldCount =920                Builder.CreateLoad(Builder.getInt64Ty(), V, "gcov_ctr");921            OldCount->setNoSanitizeMetadata();922            Value *NewCount = Builder.CreateAdd(OldCount, Builder.getInt64(1));923            Inst = Builder.CreateStore(NewCount, V);924          }925          Inst->setNoSanitizeMetadata();926        }927      }928    }929 930    char Tmp[4];931    JamCRC JC;932    JC.update(EdgeDestinations);933    uint32_t Stamp = JC.getCRC();934    FileChecksums.push_back(Stamp);935 936    if (Options.EmitNotes) {937      std::error_code EC;938      raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC,939                         sys::fs::OF_None);940      if (EC) {941        Ctx->emitError(942            Twine("failed to open coverage notes file for writing: ") +943            EC.message());944        continue;945      }946      os = &out;947      if (Endian == llvm::endianness::big) {948        out.write("gcno", 4);949        out.write(Options.Version, 4);950      } else {951        out.write("oncg", 4);952        std::reverse_copy(Options.Version, Options.Version + 4, Tmp);953        out.write(Tmp, 4);954      }955      write(Stamp);956      writeString("."); // unuseful current_working_directory957      write(0);         // unuseful has_unexecuted_blocks958 959      for (auto &Func : Funcs)960        Func->writeOut(Stamp);961 962      write(0);963      write(0);964      out.close();965    }966 967    if (EmitGCDA) {968      const llvm::Triple &Triple = M->getTargetTriple();969      if (Triple.getObjectFormat() == llvm::Triple::XCOFF)970        emitModuleInitFunctionPtrs(CountersBySP);971      else972        emitGlobalConstructor(CountersBySP);973      EmitGCDA = false;974    }975  }976  return true;977}978 979Function *GCOVProfiler::createInternalFunction(FunctionType *FTy,980                                               StringRef Name,981                                               StringRef MangledType /*=""*/) {982  Function *F = Function::createWithDefaultAttr(983      FTy, GlobalValue::InternalLinkage, 0, Name, M);984  F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);985  F->addFnAttr(Attribute::NoUnwind);986  if (Options.NoRedZone)987    F->addFnAttr(Attribute::NoRedZone);988  if (!MangledType.empty())989    setKCFIType(*M, *F, MangledType);990  return F;991}992 993void GCOVProfiler::emitGlobalConstructor(994    SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) {995  Function *WriteoutF = insertCounterWriteout(CountersBySP);996  Function *ResetF = insertReset(CountersBySP);997 998  // Create a small bit of code that registers the "__llvm_gcov_writeout" to999  // be executed at exit and the "__llvm_gcov_reset" function to be executed1000  // when "__gcov_flush" is called.1001  FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1002  Function *F = createInternalFunction(FTy, "__llvm_gcov_init", "_ZTSFvvE");1003  F->addFnAttr(Attribute::NoInline);1004 1005  BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F);1006  IRBuilder<> Builder(BB);1007 1008  FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1009  auto *PFTy = PointerType::get(*Ctx, 0);1010  FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false);1011 1012  // Initialize the environment and register the local writeout, flush and1013  // reset functions.1014  FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy);1015  Builder.CreateCall(GCOVInit, {WriteoutF, ResetF});1016  Builder.CreateRetVoid();1017 1018  appendToGlobalCtors(*M, F, 0);1019}1020 1021void GCOVProfiler::emitModuleInitFunctionPtrs(1022    SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) {1023  Function *WriteoutF = insertCounterWriteout(CountersBySP);1024  Function *ResetF = insertReset(CountersBySP);1025 1026  // Instead of creating a function call and add it to the constructors list,1027  // create a global variable in the __llvm_covinit section so the functions1028  // can be registered by a constructor in the runtime.1029 1030  auto &Ctx = M->getContext();1031 1032  Type *InitFuncDataTy[] = {1033#define COVINIT_FUNC(Type, LLVMType, Name, Init) LLVMType,1034#include "llvm/ProfileData/InstrProfData.inc"1035  };1036 1037  auto STy = StructType::get(Ctx, ArrayRef(InitFuncDataTy));1038 1039  Constant *InitFuncPtrs[] = {1040#define COVINIT_FUNC(Type, LLVMType, Name, Init) Init,1041#include "llvm/ProfileData/InstrProfData.inc"1042  };1043 1044  auto *CovInitGV =1045      new GlobalVariable(*M, STy, false, GlobalValue::PrivateLinkage, nullptr,1046                         "__llvm_covinit_functions");1047  CovInitGV->setInitializer(ConstantStruct::get(STy, InitFuncPtrs));1048  CovInitGV->setVisibility(GlobalValue::VisibilityTypes::DefaultVisibility);1049  CovInitGV->setSection(getInstrProfSectionName(1050      IPSK_covinit, M->getTargetTriple().getObjectFormat()));1051  CovInitGV->setAlignment(Align(INSTR_PROF_DATA_ALIGNMENT));1052  CovInitGV->setConstant(true);1053}1054 1055FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) {1056  Type *Args[] = {1057      PointerType::getUnqual(*Ctx), // const char *orig_filename1058      Type::getInt32Ty(*Ctx),       // uint32_t version1059      Type::getInt32Ty(*Ctx),       // uint32_t checksum1060  };1061  FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);1062  return M->getOrInsertFunction("llvm_gcda_start_file", FTy,1063                                TLI->getAttrList(Ctx, {1, 2}, /*Signed=*/false));1064}1065 1066FunctionCallee GCOVProfiler::getEmitFunctionFunc(const TargetLibraryInfo *TLI) {1067  Type *Args[] = {1068    Type::getInt32Ty(*Ctx),    // uint32_t ident1069    Type::getInt32Ty(*Ctx),    // uint32_t func_checksum1070    Type::getInt32Ty(*Ctx),    // uint32_t cfg_checksum1071  };1072  FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);1073  return M->getOrInsertFunction("llvm_gcda_emit_function", FTy,1074                             TLI->getAttrList(Ctx, {0, 1, 2}, /*Signed=*/false));1075}1076 1077FunctionCallee GCOVProfiler::getEmitArcsFunc(const TargetLibraryInfo *TLI) {1078  Type *Args[] = {1079      Type::getInt32Ty(*Ctx),       // uint32_t num_counters1080      PointerType::getUnqual(*Ctx), // uint64_t *counters1081  };1082  FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);1083  return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy,1084                                TLI->getAttrList(Ctx, {0}, /*Signed=*/false));1085}1086 1087FunctionCallee GCOVProfiler::getSummaryInfoFunc() {1088  FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1089  return M->getOrInsertFunction("llvm_gcda_summary_info", FTy);1090}1091 1092FunctionCallee GCOVProfiler::getEndFileFunc() {1093  FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1094  return M->getOrInsertFunction("llvm_gcda_end_file", FTy);1095}1096 1097Function *GCOVProfiler::insertCounterWriteout(1098    ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) {1099  FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1100  Function *WriteoutF = M->getFunction("__llvm_gcov_writeout");1101  if (!WriteoutF)1102    WriteoutF =1103        createInternalFunction(WriteoutFTy, "__llvm_gcov_writeout", "_ZTSFvvE");1104  WriteoutF->addFnAttr(Attribute::NoInline);1105 1106  BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF);1107  IRBuilder<> Builder(BB);1108 1109  auto *TLI = &GetTLI(*WriteoutF);1110 1111  FunctionCallee StartFile = getStartFileFunc(TLI);1112  FunctionCallee EmitFunction = getEmitFunctionFunc(TLI);1113  FunctionCallee EmitArcs = getEmitArcsFunc(TLI);1114  FunctionCallee SummaryInfo = getSummaryInfoFunc();1115  FunctionCallee EndFile = getEndFileFunc();1116 1117  NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu");1118  if (!CUNodes) {1119    Builder.CreateRetVoid();1120    return WriteoutF;1121  }1122 1123  // Collect the relevant data into a large constant data structure that we can1124  // walk to write out everything.1125  StructType *StartFileCallArgsTy = StructType::create(1126      {Builder.getPtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()},1127      "start_file_args_ty");1128  StructType *EmitFunctionCallArgsTy = StructType::create(1129      {Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()},1130      "emit_function_args_ty");1131  auto *PtrTy = Builder.getPtrTy();1132  StructType *EmitArcsCallArgsTy =1133      StructType::create({Builder.getInt32Ty(), PtrTy}, "emit_arcs_args_ty");1134  StructType *FileInfoTy = StructType::create(1135      {StartFileCallArgsTy, Builder.getInt32Ty(), PtrTy, PtrTy}, "file_info");1136 1137  Constant *Zero32 = Builder.getInt32(0);1138  // Build an explicit array of two zeros for use in ConstantExpr GEP building.1139  Constant *TwoZero32s[] = {Zero32, Zero32};1140 1141  SmallVector<Constant *, 8> FileInfos;1142  for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) {1143    auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i));1144 1145    // Skip module skeleton (and module) CUs.1146    if (CU->getDWOId())1147      continue;1148 1149    std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA);1150    uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i];1151    auto *StartFileCallArgs = ConstantStruct::get(1152        StartFileCallArgsTy,1153        {Builder.CreateGlobalString(FilenameGcda),1154         Builder.getInt32(endian::read32be(Options.Version)),1155         Builder.getInt32(CfgChecksum)});1156 1157    SmallVector<Constant *, 8> EmitFunctionCallArgsArray;1158    SmallVector<Constant *, 8> EmitArcsCallArgsArray;1159    for (int j : llvm::seq<int>(0, CountersBySP.size())) {1160      uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum();1161      EmitFunctionCallArgsArray.push_back(ConstantStruct::get(1162          EmitFunctionCallArgsTy,1163          {Builder.getInt32(j),1164           Builder.getInt32(FuncChecksum),1165           Builder.getInt32(CfgChecksum)}));1166 1167      GlobalVariable *GV = CountersBySP[j].first;1168      unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements();1169      EmitArcsCallArgsArray.push_back(ConstantStruct::get(1170          EmitArcsCallArgsTy,1171          {Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr(1172                                       GV->getValueType(), GV, TwoZero32s)}));1173    }1174    // Create global arrays for the two emit calls.1175    int CountersSize = CountersBySP.size();1176    assert(CountersSize == (int)EmitFunctionCallArgsArray.size() &&1177           "Mismatched array size!");1178    assert(CountersSize == (int)EmitArcsCallArgsArray.size() &&1179           "Mismatched array size!");1180    auto *EmitFunctionCallArgsArrayTy =1181        ArrayType::get(EmitFunctionCallArgsTy, CountersSize);1182    auto *EmitFunctionCallArgsArrayGV = new GlobalVariable(1183        *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true,1184        GlobalValue::InternalLinkage,1185        ConstantArray::get(EmitFunctionCallArgsArrayTy,1186                           EmitFunctionCallArgsArray),1187        Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i));1188    auto *EmitArcsCallArgsArrayTy =1189        ArrayType::get(EmitArcsCallArgsTy, CountersSize);1190    EmitFunctionCallArgsArrayGV->setUnnamedAddr(1191        GlobalValue::UnnamedAddr::Global);1192    auto *EmitArcsCallArgsArrayGV = new GlobalVariable(1193        *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true,1194        GlobalValue::InternalLinkage,1195        ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray),1196        Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i));1197    EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);1198 1199    FileInfos.push_back(ConstantStruct::get(1200        FileInfoTy,1201        {StartFileCallArgs, Builder.getInt32(CountersSize),1202         ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy,1203                                                EmitFunctionCallArgsArrayGV,1204                                                TwoZero32s),1205         ConstantExpr::getInBoundsGetElementPtr(1206             EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)}));1207  }1208 1209  // If we didn't find anything to actually emit, bail on out.1210  if (FileInfos.empty()) {1211    Builder.CreateRetVoid();1212    return WriteoutF;1213  }1214 1215  // To simplify code, we cap the number of file infos we write out to fit1216  // easily in a 32-bit signed integer. This gives consistent behavior between1217  // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit1218  // operations on 32-bit systems. It also seems unreasonable to try to handle1219  // more than 2 billion files.1220  if ((int64_t)FileInfos.size() > (int64_t)INT_MAX)1221    FileInfos.resize(INT_MAX);1222 1223  // Create a global for the entire data structure so we can walk it more1224  // easily.1225  auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size());1226  auto *FileInfoArrayGV = new GlobalVariable(1227      *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage,1228      ConstantArray::get(FileInfoArrayTy, FileInfos),1229      "__llvm_internal_gcov_emit_file_info");1230  FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);1231 1232  // Create the CFG for walking this data structure.1233  auto *FileLoopHeader =1234      BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF);1235  auto *CounterLoopHeader =1236      BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF);1237  auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF);1238  auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF);1239 1240  // We always have at least one file, so just branch to the header.1241  Builder.CreateBr(FileLoopHeader);1242 1243  // The index into the files structure is our loop induction variable.1244  Builder.SetInsertPoint(FileLoopHeader);1245  PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2,1246                                  "file_idx");1247  IV->addIncoming(Builder.getInt32(0), BB);1248  auto *FileInfoPtr = Builder.CreateInBoundsGEP(1249      FileInfoArrayTy, FileInfoArrayGV, {Builder.getInt32(0), IV});1250  auto *StartFileCallArgsPtr =1251      Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0, "start_file_args");1252  auto *StartFileCall = Builder.CreateCall(1253      StartFile,1254      {Builder.CreateLoad(StartFileCallArgsTy->getElementType(0),1255                          Builder.CreateStructGEP(StartFileCallArgsTy,1256                                                  StartFileCallArgsPtr, 0),1257                          "filename"),1258       Builder.CreateLoad(StartFileCallArgsTy->getElementType(1),1259                          Builder.CreateStructGEP(StartFileCallArgsTy,1260                                                  StartFileCallArgsPtr, 1),1261                          "version"),1262       Builder.CreateLoad(StartFileCallArgsTy->getElementType(2),1263                          Builder.CreateStructGEP(StartFileCallArgsTy,1264                                                  StartFileCallArgsPtr, 2),1265                          "stamp")});1266  if (auto AK = TLI->getExtAttrForI32Param(false))1267    StartFileCall->addParamAttr(2, AK);1268  auto *NumCounters = Builder.CreateLoad(1269      FileInfoTy->getElementType(1),1270      Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1), "num_ctrs");1271  auto *EmitFunctionCallArgsArray =1272      Builder.CreateLoad(FileInfoTy->getElementType(2),1273                         Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2),1274                         "emit_function_args");1275  auto *EmitArcsCallArgsArray = Builder.CreateLoad(1276      FileInfoTy->getElementType(3),1277      Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3), "emit_arcs_args");1278  auto *EnterCounterLoopCond =1279      Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters);1280  Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch);1281 1282  Builder.SetInsertPoint(CounterLoopHeader);1283  auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2,1284                               "ctr_idx");1285  JV->addIncoming(Builder.getInt32(0), FileLoopHeader);1286  auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP(1287      EmitFunctionCallArgsTy, EmitFunctionCallArgsArray, JV);1288  auto *EmitFunctionCall = Builder.CreateCall(1289      EmitFunction,1290      {Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(0),1291                          Builder.CreateStructGEP(EmitFunctionCallArgsTy,1292                                                  EmitFunctionCallArgsPtr, 0),1293                          "ident"),1294       Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(1),1295                          Builder.CreateStructGEP(EmitFunctionCallArgsTy,1296                                                  EmitFunctionCallArgsPtr, 1),1297                          "func_checkssum"),1298       Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(2),1299                          Builder.CreateStructGEP(EmitFunctionCallArgsTy,1300                                                  EmitFunctionCallArgsPtr, 2),1301                          "cfg_checksum")});1302  if (auto AK = TLI->getExtAttrForI32Param(false)) {1303    EmitFunctionCall->addParamAttr(0, AK);1304    EmitFunctionCall->addParamAttr(1, AK);1305    EmitFunctionCall->addParamAttr(2, AK);1306  }1307  auto *EmitArcsCallArgsPtr =1308      Builder.CreateInBoundsGEP(EmitArcsCallArgsTy, EmitArcsCallArgsArray, JV);1309  auto *EmitArcsCall = Builder.CreateCall(1310      EmitArcs,1311      {Builder.CreateLoad(1312           EmitArcsCallArgsTy->getElementType(0),1313           Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0),1314           "num_counters"),1315       Builder.CreateLoad(1316           EmitArcsCallArgsTy->getElementType(1),1317           Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 1),1318           "counters")});1319  if (auto AK = TLI->getExtAttrForI32Param(false))1320    EmitArcsCall->addParamAttr(0, AK);1321  auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1));1322  auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters);1323  Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch);1324  JV->addIncoming(NextJV, CounterLoopHeader);1325 1326  Builder.SetInsertPoint(FileLoopLatch);1327  Builder.CreateCall(SummaryInfo, {});1328  Builder.CreateCall(EndFile, {});1329  auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1), "next_file_idx");1330  auto *FileLoopCond =1331      Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size()));1332  Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB);1333  IV->addIncoming(NextIV, FileLoopLatch);1334 1335  Builder.SetInsertPoint(ExitBB);1336  Builder.CreateRetVoid();1337 1338  return WriteoutF;1339}1340 1341Function *GCOVProfiler::insertReset(1342    ArrayRef<std::pair<GlobalVariable *, MDNode *>> CountersBySP) {1343  FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1344  Function *ResetF = M->getFunction("__llvm_gcov_reset");1345  if (!ResetF)1346    ResetF = createInternalFunction(FTy, "__llvm_gcov_reset", "_ZTSFvvE");1347  ResetF->addFnAttr(Attribute::NoInline);1348 1349  BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", ResetF);1350  IRBuilder<> Builder(Entry);1351  LLVMContext &C = Entry->getContext();1352 1353  // Zero out the counters.1354  for (const auto &I : CountersBySP) {1355    GlobalVariable *GV = I.first;1356    auto *GVTy = cast<ArrayType>(GV->getValueType());1357    Builder.CreateMemSet(GV, Constant::getNullValue(Type::getInt8Ty(C)),1358                         GVTy->getNumElements() *1359                             GVTy->getElementType()->getScalarSizeInBits() / 8,1360                         GV->getAlign());1361  }1362 1363  Type *RetTy = ResetF->getReturnType();1364  if (RetTy->isVoidTy())1365    Builder.CreateRetVoid();1366  else if (RetTy->isIntegerTy())1367    // Used if __llvm_gcov_reset was implicitly declared.1368    Builder.CreateRet(ConstantInt::get(RetTy, 0));1369  else1370    report_fatal_error("invalid return type for __llvm_gcov_reset");1371 1372  return ResetF;1373}1374