diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
commit | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch) | |
tree | 64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp | |
parent | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff) | |
download | ydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp')
-rw-r--r-- | contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp | 788 |
1 files changed, 394 insertions, 394 deletions
diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp index 2d52317d0d..527644a69d 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -13,17 +13,17 @@ // //===----------------------------------------------------------------------===// -#include "CFGMST.h" +#include "CFGMST.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Sequence.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" -#include "llvm/Analysis/BlockFrequencyInfo.h" -#include "llvm/Analysis/BranchProbabilityInfo.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/CFG.h" @@ -36,7 +36,7 @@ #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" -#include "llvm/Support/CRC.h" +#include "llvm/Support/CRC.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" @@ -57,8 +57,8 @@ namespace endian = llvm::support::endian; #define DEBUG_TYPE "insert-gcov-profiling" enum : uint32_t { - GCOV_ARC_ON_TREE = 1 << 0, - + GCOV_ARC_ON_TREE = 1 << 0, + GCOV_TAG_FUNCTION = 0x01000000, GCOV_TAG_BLOCKS = 0x01410000, GCOV_TAG_ARCS = 0x01430000, @@ -69,9 +69,9 @@ static cl::opt<std::string> DefaultGCOVVersion("default-gcov-version", cl::init("408*"), cl::Hidden, cl::ValueRequired); -static cl::opt<bool> AtomicCounter("gcov-atomic-counter", cl::Hidden, - cl::desc("Make counter updates atomic")); - +static cl::opt<bool> AtomicCounter("gcov-atomic-counter", cl::Hidden, + cl::desc("Make counter updates atomic")); + // Returns the number of words which will be used to represent this string. static unsigned wordsOfString(StringRef s) { // Length + NUL-terminated string + 0~3 padding NULs. @@ -83,7 +83,7 @@ GCOVOptions GCOVOptions::getDefault() { Options.EmitNotes = true; Options.EmitData = true; Options.NoRedZone = false; - Options.Atomic = AtomicCounter; + Options.Atomic = AtomicCounter; if (DefaultGCOVVersion.size() != 4) { llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") + @@ -101,8 +101,8 @@ public: GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {} GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {} bool - runOnModule(Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, - function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, + runOnModule(Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, + function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, std::function<const TargetLibraryInfo &(Function &F)> GetTLI); void write(uint32_t i) { @@ -119,14 +119,14 @@ public: private: // Create the .gcno files for the Module based on DebugInfo. - bool - emitProfileNotes(NamedMDNode *CUNode, bool HasExecOrFork, - function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, - function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, - function_ref<const TargetLibraryInfo &(Function &F)> GetTLI); + bool + emitProfileNotes(NamedMDNode *CUNode, bool HasExecOrFork, + function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, + function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, + function_ref<const TargetLibraryInfo &(Function &F)> GetTLI); - void emitGlobalConstructor( - SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP); + void emitGlobalConstructor( + SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP); bool isFunctionInstrumented(const Function &F); std::vector<Regex> createRegexesFromString(StringRef RegexesStr); @@ -164,7 +164,7 @@ private: SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs; std::vector<Regex> FilterRe; std::vector<Regex> ExcludeRe; - DenseSet<const BasicBlock *> ExecBlocks; + DenseSet<const BasicBlock *> ExecBlocks; StringMap<bool> InstrumentedFiles; }; @@ -180,68 +180,68 @@ public: StringRef getPassName() const override { return "GCOV Profiler"; } bool runOnModule(Module &M) override { - auto GetBFI = [this](Function &F) { - return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI(); - }; - auto GetBPI = [this](Function &F) { - return &this->getAnalysis<BranchProbabilityInfoWrapperPass>(F).getBPI(); - }; - auto GetTLI = [this](Function &F) -> const TargetLibraryInfo & { - return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); - }; - return Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI); + auto GetBFI = [this](Function &F) { + return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI(); + }; + auto GetBPI = [this](Function &F) { + return &this->getAnalysis<BranchProbabilityInfoWrapperPass>(F).getBPI(); + }; + auto GetTLI = [this](Function &F) -> const TargetLibraryInfo & { + return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); + }; + return Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI); } void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired<BlockFrequencyInfoWrapperPass>(); + AU.addRequired<BlockFrequencyInfoWrapperPass>(); AU.addRequired<TargetLibraryInfoWrapperPass>(); } private: GCOVProfiler Profiler; }; - -struct BBInfo { - BBInfo *Group; - uint32_t Index; - uint32_t Rank = 0; - - BBInfo(unsigned Index) : Group(this), Index(Index) {} - const std::string infoString() const { - return (Twine("Index=") + Twine(Index)).str(); - } -}; - -struct Edge { - // This class implements the CFG edges. Note the CFG can be a multi-graph. - // So there might be multiple edges with same SrcBB and DestBB. - const BasicBlock *SrcBB; - const BasicBlock *DestBB; - uint64_t Weight; - BasicBlock *Place = nullptr; - uint32_t SrcNumber, DstNumber; - bool InMST = false; - bool Removed = false; - bool IsCritical = false; - - Edge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W = 1) - : SrcBB(Src), DestBB(Dest), Weight(W) {} - - // Return the information string of an edge. - const std::string infoString() const { - return (Twine(Removed ? "-" : " ") + (InMST ? " " : "*") + - (IsCritical ? "c" : " ") + " W=" + Twine(Weight)) - .str(); - } -}; + +struct BBInfo { + BBInfo *Group; + uint32_t Index; + uint32_t Rank = 0; + + BBInfo(unsigned Index) : Group(this), Index(Index) {} + const std::string infoString() const { + return (Twine("Index=") + Twine(Index)).str(); + } +}; + +struct Edge { + // This class implements the CFG edges. Note the CFG can be a multi-graph. + // So there might be multiple edges with same SrcBB and DestBB. + const BasicBlock *SrcBB; + const BasicBlock *DestBB; + uint64_t Weight; + BasicBlock *Place = nullptr; + uint32_t SrcNumber, DstNumber; + bool InMST = false; + bool Removed = false; + bool IsCritical = false; + + Edge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W = 1) + : SrcBB(Src), DestBB(Dest), Weight(W) {} + + // Return the information string of an edge. + const std::string infoString() const { + return (Twine(Removed ? "-" : " ") + (InMST ? " " : "*") + + (IsCritical ? "c" : " ") + " W=" + Twine(Weight)) + .str(); + } +}; } char GCOVProfilerLegacyPass::ID = 0; INITIALIZE_PASS_BEGIN( GCOVProfilerLegacyPass, "insert-gcov-profiling", "Insert instrumentation for GCOV profiling", false, false) -INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) -INITIALIZE_PASS_DEPENDENCY(BranchProbabilityInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(BranchProbabilityInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_END( GCOVProfilerLegacyPass, "insert-gcov-profiling", @@ -326,8 +326,8 @@ namespace { return LinesByFile.try_emplace(Filename, P, Filename).first->second; } - void addEdge(GCOVBlock &Successor, uint32_t Flags) { - OutEdges.emplace_back(&Successor, Flags); + void addEdge(GCOVBlock &Successor, uint32_t Flags) { + OutEdges.emplace_back(&Successor, Flags); } void writeOut() { @@ -360,10 +360,10 @@ namespace { assert(OutEdges.empty()); } - uint32_t Number; - SmallVector<std::pair<GCOVBlock *, uint32_t>, 4> OutEdges; - - private: + uint32_t Number; + SmallVector<std::pair<GCOVBlock *, uint32_t>, 4> OutEdges; + + private: friend class GCOVFunction; GCOVBlock(GCOVProfiler *P, uint32_t Number) @@ -380,11 +380,11 @@ namespace { GCOVFunction(GCOVProfiler *P, Function *F, const DISubprogram *SP, unsigned EndLine, uint32_t Ident, int Version) : GCOVRecord(P), SP(SP), EndLine(EndLine), Ident(Ident), - Version(Version), EntryBlock(P, 0), ReturnBlock(P, 1) { + Version(Version), EntryBlock(P, 0), ReturnBlock(P, 1) { LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n"); bool ExitBlockBeforeBody = Version >= 48; - uint32_t i = ExitBlockBeforeBody ? 2 : 1; - for (BasicBlock &BB : *F) + uint32_t i = ExitBlockBeforeBody ? 2 : 1; + for (BasicBlock &BB : *F) Blocks.insert(std::make_pair(&BB, GCOVBlock(P, i++))); if (!ExitBlockBeforeBody) ReturnBlock.Number = i; @@ -396,11 +396,11 @@ namespace { FuncChecksum = hash_value(FunctionNameAndLine); } - GCOVBlock &getBlock(const BasicBlock *BB) { - return Blocks.find(const_cast<BasicBlock *>(BB))->second; + GCOVBlock &getBlock(const BasicBlock *BB) { + return Blocks.find(const_cast<BasicBlock *>(BB))->second; } - GCOVBlock &getEntryBlock() { return EntryBlock; } + GCOVBlock &getEntryBlock() { return EntryBlock; } GCOVBlock &getReturnBlock() { return ReturnBlock; } @@ -443,52 +443,52 @@ namespace { // Emit count of blocks. write(GCOV_TAG_BLOCKS); if (Version < 80) { - write(Blocks.size() + 2); - for (int i = Blocks.size() + 2; i; --i) + write(Blocks.size() + 2); + for (int i = Blocks.size() + 2; i; --i) write(0); } else { write(1); - write(Blocks.size() + 2); + write(Blocks.size() + 2); } LLVM_DEBUG(dbgs() << (Blocks.size() + 1) << " blocks\n"); // Emit edges between blocks. - const uint32_t Outgoing = EntryBlock.OutEdges.size(); - if (Outgoing) { - write(GCOV_TAG_ARCS); - write(Outgoing * 2 + 1); - write(EntryBlock.Number); - for (const auto &E : EntryBlock.OutEdges) { - write(E.first->Number); - write(E.second); - } - } - for (auto &It : Blocks) { - const GCOVBlock &Block = It.second; + const uint32_t Outgoing = EntryBlock.OutEdges.size(); + if (Outgoing) { + write(GCOV_TAG_ARCS); + write(Outgoing * 2 + 1); + write(EntryBlock.Number); + for (const auto &E : EntryBlock.OutEdges) { + write(E.first->Number); + write(E.second); + } + } + for (auto &It : Blocks) { + const GCOVBlock &Block = It.second; if (Block.OutEdges.empty()) continue; write(GCOV_TAG_ARCS); write(Block.OutEdges.size() * 2 + 1); write(Block.Number); - for (const auto &E : Block.OutEdges) { - write(E.first->Number); - write(E.second); + for (const auto &E : Block.OutEdges) { + write(E.first->Number); + write(E.second); } } // Emit lines for each block. - for (auto &It : Blocks) - It.second.writeOut(); + for (auto &It : Blocks) + It.second.writeOut(); } - public: + public: const DISubprogram *SP; unsigned EndLine; uint32_t Ident; uint32_t FuncChecksum; int Version; - MapVector<BasicBlock *, GCOVBlock> Blocks; - GCOVBlock EntryBlock; + MapVector<BasicBlock *, GCOVBlock> Blocks; + GCOVBlock EntryBlock; GCOVBlock ReturnBlock; }; } @@ -602,23 +602,23 @@ std::string GCOVProfiler::mangleName(const DICompileUnit *CU, } bool GCOVProfiler::runOnModule( - Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, - function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, - std::function<const TargetLibraryInfo &(Function &F)> GetTLI) { + Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, + function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, + std::function<const TargetLibraryInfo &(Function &F)> GetTLI) { this->M = &M; this->GetTLI = std::move(GetTLI); Ctx = &M.getContext(); - NamedMDNode *CUNode = M.getNamedMetadata("llvm.dbg.cu"); - if (!CUNode || (!Options.EmitNotes && !Options.EmitData)) - return false; + NamedMDNode *CUNode = M.getNamedMetadata("llvm.dbg.cu"); + if (!CUNode || (!Options.EmitNotes && !Options.EmitData)) + return false; + + bool HasExecOrFork = AddFlushBeforeForkAndExec(); - bool HasExecOrFork = AddFlushBeforeForkAndExec(); - FilterRe = createRegexesFromString(Options.Filter); ExcludeRe = createRegexesFromString(Options.Exclude); - emitProfileNotes(CUNode, HasExecOrFork, GetBFI, GetBPI, this->GetTLI); - return true; + emitProfileNotes(CUNode, HasExecOrFork, GetBFI, GetBPI, this->GetTLI); + return true; } PreservedAnalyses GCOVProfilerPass::run(Module &M, @@ -628,17 +628,17 @@ PreservedAnalyses GCOVProfilerPass::run(Module &M, FunctionAnalysisManager &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); - auto GetBFI = [&FAM](Function &F) { - return &FAM.getResult<BlockFrequencyAnalysis>(F); - }; - auto GetBPI = [&FAM](Function &F) { - return &FAM.getResult<BranchProbabilityAnalysis>(F); - }; - auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & { - return FAM.getResult<TargetLibraryAnalysis>(F); - }; - - if (!Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI)) + auto GetBFI = [&FAM](Function &F) { + return &FAM.getResult<BlockFrequencyAnalysis>(F); + }; + auto GetBPI = [&FAM](Function &F) { + return &FAM.getResult<BranchProbabilityAnalysis>(F); + }; + auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & { + return FAM.getResult<TargetLibraryAnalysis>(F); + }; + + if (!Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI)) return PreservedAnalyses::all(); return PreservedAnalyses::none(); @@ -744,7 +744,7 @@ bool GCOVProfiler::AddFlushBeforeForkAndExec() { // dumped FunctionCallee ResetF = M->getOrInsertFunction("llvm_reset_counters", FTy); Builder.CreateCall(ResetF)->setDebugLoc(Loc); - ExecBlocks.insert(Parent); + ExecBlocks.insert(Parent); Parent->splitBasicBlock(NextInst); Parent->back().setDebugLoc(Loc); } @@ -752,67 +752,67 @@ bool GCOVProfiler::AddFlushBeforeForkAndExec() { return !Forks.empty() || !Execs.empty(); } -static BasicBlock *getInstrBB(CFGMST<Edge, BBInfo> &MST, Edge &E, - const DenseSet<const BasicBlock *> &ExecBlocks) { - if (E.InMST || E.Removed) - return nullptr; - - BasicBlock *SrcBB = const_cast<BasicBlock *>(E.SrcBB); - BasicBlock *DestBB = const_cast<BasicBlock *>(E.DestBB); - // For a fake edge, instrument the real BB. - if (SrcBB == nullptr) - return DestBB; - if (DestBB == nullptr) - return SrcBB; - - auto CanInstrument = [](BasicBlock *BB) -> BasicBlock * { - // There are basic blocks (such as catchswitch) cannot be instrumented. - // If the returned first insertion point is the end of BB, skip this BB. - if (BB->getFirstInsertionPt() == BB->end()) - return nullptr; - return BB; - }; - - // Instrument the SrcBB if it has a single successor, - // otherwise, the DestBB if this is not a critical edge. - Instruction *TI = SrcBB->getTerminator(); - if (TI->getNumSuccessors() <= 1 && !ExecBlocks.count(SrcBB)) - return CanInstrument(SrcBB); - if (!E.IsCritical) - return CanInstrument(DestBB); - - // Some IndirectBr critical edges cannot be split by the previous - // SplitIndirectBrCriticalEdges call. Bail out. - const unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB); - BasicBlock *InstrBB = - isa<IndirectBrInst>(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum); - if (!InstrBB) - return nullptr; - - MST.addEdge(SrcBB, InstrBB, 0); - MST.addEdge(InstrBB, DestBB, 0).InMST = true; - E.Removed = true; - - return CanInstrument(InstrBB); -} - -#ifndef NDEBUG -static void dumpEdges(CFGMST<Edge, BBInfo> &MST, GCOVFunction &GF) { - size_t ID = 0; - for (auto &E : make_pointee_range(MST.AllEdges)) { - GCOVBlock &Src = E.SrcBB ? GF.getBlock(E.SrcBB) : GF.getEntryBlock(); - GCOVBlock &Dst = E.DestBB ? GF.getBlock(E.DestBB) : GF.getReturnBlock(); - dbgs() << " Edge " << ID++ << ": " << Src.Number << "->" << Dst.Number - << E.infoString() << "\n"; - } -} -#endif - -bool GCOVProfiler::emitProfileNotes( - NamedMDNode *CUNode, bool HasExecOrFork, - function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, - function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, - function_ref<const TargetLibraryInfo &(Function &F)> GetTLI) { +static BasicBlock *getInstrBB(CFGMST<Edge, BBInfo> &MST, Edge &E, + const DenseSet<const BasicBlock *> &ExecBlocks) { + if (E.InMST || E.Removed) + return nullptr; + + BasicBlock *SrcBB = const_cast<BasicBlock *>(E.SrcBB); + BasicBlock *DestBB = const_cast<BasicBlock *>(E.DestBB); + // For a fake edge, instrument the real BB. + if (SrcBB == nullptr) + return DestBB; + if (DestBB == nullptr) + return SrcBB; + + auto CanInstrument = [](BasicBlock *BB) -> BasicBlock * { + // There are basic blocks (such as catchswitch) cannot be instrumented. + // If the returned first insertion point is the end of BB, skip this BB. + if (BB->getFirstInsertionPt() == BB->end()) + return nullptr; + return BB; + }; + + // Instrument the SrcBB if it has a single successor, + // otherwise, the DestBB if this is not a critical edge. + Instruction *TI = SrcBB->getTerminator(); + if (TI->getNumSuccessors() <= 1 && !ExecBlocks.count(SrcBB)) + return CanInstrument(SrcBB); + if (!E.IsCritical) + return CanInstrument(DestBB); + + // Some IndirectBr critical edges cannot be split by the previous + // SplitIndirectBrCriticalEdges call. Bail out. + const unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB); + BasicBlock *InstrBB = + isa<IndirectBrInst>(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum); + if (!InstrBB) + return nullptr; + + MST.addEdge(SrcBB, InstrBB, 0); + MST.addEdge(InstrBB, DestBB, 0).InMST = true; + E.Removed = true; + + return CanInstrument(InstrBB); +} + +#ifndef NDEBUG +static void dumpEdges(CFGMST<Edge, BBInfo> &MST, GCOVFunction &GF) { + size_t ID = 0; + for (auto &E : make_pointee_range(MST.AllEdges)) { + GCOVBlock &Src = E.SrcBB ? GF.getBlock(E.SrcBB) : GF.getEntryBlock(); + GCOVBlock &Dst = E.DestBB ? GF.getBlock(E.DestBB) : GF.getReturnBlock(); + dbgs() << " Edge " << ID++ << ": " << Src.Number << "->" << Dst.Number + << E.infoString() << "\n"; + } +} +#endif + +bool GCOVProfiler::emitProfileNotes( + NamedMDNode *CUNode, bool HasExecOrFork, + function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, + function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, + function_ref<const TargetLibraryInfo &(Function &F)> GetTLI) { int Version; { uint8_t c3 = Options.Version[0]; @@ -822,20 +822,20 @@ bool GCOVProfiler::emitProfileNotes( : (c3 - '0') * 10 + c1 - '0'; } - bool EmitGCDA = Options.EmitData; - for (unsigned i = 0, e = CUNode->getNumOperands(); i != e; ++i) { + bool EmitGCDA = Options.EmitData; + for (unsigned i = 0, e = CUNode->getNumOperands(); i != e; ++i) { // Each compile unit gets its own .gcno file. This means that whether we run // this pass over the original .o's as they're produced, or run it after // LTO, we'll generate the same .gcno files. - auto *CU = cast<DICompileUnit>(CUNode->getOperand(i)); + auto *CU = cast<DICompileUnit>(CUNode->getOperand(i)); // Skip module skeleton (and module) CUs. if (CU->getDWOId()) continue; - std::vector<uint8_t> EdgeDestinations; - SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; + std::vector<uint8_t> EdgeDestinations; + SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; Endian = M->getDataLayout().isLittleEndian() ? support::endianness::little : support::endianness::big; @@ -849,82 +849,82 @@ bool GCOVProfiler::emitProfileNotes( // TODO: Functions using scope-based EH are currently not supported. if (isUsingScopeBasedEH(F)) continue; - // Add the function line number to the lines of the entry block - // to have a counter for the function definition. - uint32_t Line = SP->getLine(); - auto Filename = getFilename(SP); - - BranchProbabilityInfo *BPI = GetBPI(F); - BlockFrequencyInfo *BFI = GetBFI(F); - - // Split indirectbr critical edges here before computing the MST rather - // than later in getInstrBB() to avoid invalidating it. - SplitIndirectBrCriticalEdges(F, BPI, BFI); - - CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry_=*/false, BPI, BFI); - - // getInstrBB can split basic blocks and push elements to AllEdges. - for (size_t I : llvm::seq<size_t>(0, MST.AllEdges.size())) { - auto &E = *MST.AllEdges[I]; - // For now, disable spanning tree optimization when fork or exec* is - // used. - if (HasExecOrFork) - E.InMST = false; - E.Place = getInstrBB(MST, E, ExecBlocks); - } - // Basic blocks in F are finalized at this point. + // Add the function line number to the lines of the entry block + // to have a counter for the function definition. + uint32_t Line = SP->getLine(); + auto Filename = getFilename(SP); + + BranchProbabilityInfo *BPI = GetBPI(F); + BlockFrequencyInfo *BFI = GetBFI(F); + + // Split indirectbr critical edges here before computing the MST rather + // than later in getInstrBB() to avoid invalidating it. + SplitIndirectBrCriticalEdges(F, BPI, BFI); + + CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry_=*/false, BPI, BFI); + + // getInstrBB can split basic blocks and push elements to AllEdges. + for (size_t I : llvm::seq<size_t>(0, MST.AllEdges.size())) { + auto &E = *MST.AllEdges[I]; + // For now, disable spanning tree optimization when fork or exec* is + // used. + if (HasExecOrFork) + E.InMST = false; + E.Place = getInstrBB(MST, E, ExecBlocks); + } + // Basic blocks in F are finalized at this point. BasicBlock &EntryBlock = F.getEntryBlock(); Funcs.push_back(std::make_unique<GCOVFunction>(this, &F, SP, EndLine, FunctionIdent++, Version)); GCOVFunction &Func = *Funcs.back(); - // Some non-tree edges are IndirectBr which cannot be split. Ignore them - // as well. - llvm::erase_if(MST.AllEdges, [](std::unique_ptr<Edge> &E) { - return E->Removed || (!E->InMST && !E->Place); - }); - const size_t Measured = - std::stable_partition( - MST.AllEdges.begin(), MST.AllEdges.end(), - [](std::unique_ptr<Edge> &E) { return E->Place; }) - - MST.AllEdges.begin(); - for (size_t I : llvm::seq<size_t>(0, Measured)) { - Edge &E = *MST.AllEdges[I]; - GCOVBlock &Src = - E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); - GCOVBlock &Dst = - E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); - E.SrcNumber = Src.Number; - E.DstNumber = Dst.Number; - } - std::stable_sort( - MST.AllEdges.begin(), MST.AllEdges.begin() + Measured, - [](const std::unique_ptr<Edge> &L, const std::unique_ptr<Edge> &R) { - return L->SrcNumber != R->SrcNumber ? L->SrcNumber < R->SrcNumber - : L->DstNumber < R->DstNumber; - }); - - for (const Edge &E : make_pointee_range(MST.AllEdges)) { - GCOVBlock &Src = - E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); - GCOVBlock &Dst = - E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); - Src.addEdge(Dst, E.Place ? 0 : uint32_t(GCOV_ARC_ON_TREE)); - } - + // Some non-tree edges are IndirectBr which cannot be split. Ignore them + // as well. + llvm::erase_if(MST.AllEdges, [](std::unique_ptr<Edge> &E) { + return E->Removed || (!E->InMST && !E->Place); + }); + const size_t Measured = + std::stable_partition( + MST.AllEdges.begin(), MST.AllEdges.end(), + [](std::unique_ptr<Edge> &E) { return E->Place; }) - + MST.AllEdges.begin(); + for (size_t I : llvm::seq<size_t>(0, Measured)) { + Edge &E = *MST.AllEdges[I]; + GCOVBlock &Src = + E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); + GCOVBlock &Dst = + E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); + E.SrcNumber = Src.Number; + E.DstNumber = Dst.Number; + } + std::stable_sort( + MST.AllEdges.begin(), MST.AllEdges.begin() + Measured, + [](const std::unique_ptr<Edge> &L, const std::unique_ptr<Edge> &R) { + return L->SrcNumber != R->SrcNumber ? L->SrcNumber < R->SrcNumber + : L->DstNumber < R->DstNumber; + }); + + for (const Edge &E : make_pointee_range(MST.AllEdges)) { + GCOVBlock &Src = + E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); + GCOVBlock &Dst = + E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); + Src.addEdge(Dst, E.Place ? 0 : uint32_t(GCOV_ARC_ON_TREE)); + } + // Artificial functions such as global initializers if (!SP->isArtificial()) Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line); - LLVM_DEBUG(dumpEdges(MST, Func)); - - for (auto &GB : Func.Blocks) { - const BasicBlock &BB = *GB.first; - auto &Block = GB.second; - for (auto Succ : Block.OutEdges) { - uint32_t Idx = Succ.first->Number; - do EdgeDestinations.push_back(Idx & 255); - while ((Idx >>= 8) > 0); + LLVM_DEBUG(dumpEdges(MST, Func)); + + for (auto &GB : Func.Blocks) { + const BasicBlock &BB = *GB.first; + auto &Block = GB.second; + for (auto Succ : Block.OutEdges) { + uint32_t Idx = Succ.first->Number; + do EdgeDestinations.push_back(Idx & 255); + while ((Idx >>= 8) > 0); } for (auto &I : BB) { @@ -950,110 +950,110 @@ bool GCOVProfiler::emitProfileNotes( } Line = 0; } - if (EmitGCDA) { - DISubprogram *SP = F.getSubprogram(); - ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Measured); - GlobalVariable *Counters = new GlobalVariable( - *M, CounterTy, false, GlobalValue::InternalLinkage, - Constant::getNullValue(CounterTy), "__llvm_gcov_ctr"); - CountersBySP.emplace_back(Counters, SP); - - for (size_t I : llvm::seq<size_t>(0, Measured)) { - const Edge &E = *MST.AllEdges[I]; - IRBuilder<> Builder(E.Place, E.Place->getFirstInsertionPt()); - Value *V = Builder.CreateConstInBoundsGEP2_64( - Counters->getValueType(), Counters, 0, I); - if (Options.Atomic) { - Builder.CreateAtomicRMW(AtomicRMWInst::Add, V, Builder.getInt64(1), - AtomicOrdering::Monotonic); - } else { - Value *Count = - Builder.CreateLoad(Builder.getInt64Ty(), V, "gcov_ctr"); - Count = Builder.CreateAdd(Count, Builder.getInt64(1)); - Builder.CreateStore(Count, V); - } - } - } + if (EmitGCDA) { + DISubprogram *SP = F.getSubprogram(); + ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Measured); + GlobalVariable *Counters = new GlobalVariable( + *M, CounterTy, false, GlobalValue::InternalLinkage, + Constant::getNullValue(CounterTy), "__llvm_gcov_ctr"); + CountersBySP.emplace_back(Counters, SP); + + for (size_t I : llvm::seq<size_t>(0, Measured)) { + const Edge &E = *MST.AllEdges[I]; + IRBuilder<> Builder(E.Place, E.Place->getFirstInsertionPt()); + Value *V = Builder.CreateConstInBoundsGEP2_64( + Counters->getValueType(), Counters, 0, I); + if (Options.Atomic) { + Builder.CreateAtomicRMW(AtomicRMWInst::Add, V, Builder.getInt64(1), + AtomicOrdering::Monotonic); + } else { + Value *Count = + Builder.CreateLoad(Builder.getInt64Ty(), V, "gcov_ctr"); + Count = Builder.CreateAdd(Count, Builder.getInt64(1)); + Builder.CreateStore(Count, V); + } + } + } } char Tmp[4]; - JamCRC JC; - JC.update(EdgeDestinations); - uint32_t Stamp = JC.getCRC(); + JamCRC JC; + JC.update(EdgeDestinations); + uint32_t Stamp = JC.getCRC(); FileChecksums.push_back(Stamp); - if (Options.EmitNotes) { - std::error_code EC; - raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, - sys::fs::OF_None); - if (EC) { - Ctx->emitError( - Twine("failed to open coverage notes file for writing: ") + - EC.message()); + if (Options.EmitNotes) { + std::error_code EC; + raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, + sys::fs::OF_None); + if (EC) { + Ctx->emitError( + Twine("failed to open coverage notes file for writing: ") + + EC.message()); continue; } - os = &out; - if (Endian == support::endianness::big) { - out.write("gcno", 4); - out.write(Options.Version, 4); - } else { - out.write("oncg", 4); - std::reverse_copy(Options.Version, Options.Version + 4, Tmp); - out.write(Tmp, 4); - } - write(Stamp); - if (Version >= 90) - writeString(""); // unuseful current_working_directory - if (Version >= 80) - write(0); // unuseful has_unexecuted_blocks - - for (auto &Func : Funcs) - Func->writeOut(Stamp); - - write(0); - write(0); - out.close(); - } - - if (EmitGCDA) { - emitGlobalConstructor(CountersBySP); - EmitGCDA = false; + os = &out; + if (Endian == support::endianness::big) { + out.write("gcno", 4); + out.write(Options.Version, 4); + } else { + out.write("oncg", 4); + std::reverse_copy(Options.Version, Options.Version + 4, Tmp); + out.write(Tmp, 4); + } + write(Stamp); + if (Version >= 90) + writeString(""); // unuseful current_working_directory + if (Version >= 80) + write(0); // unuseful has_unexecuted_blocks + + for (auto &Func : Funcs) + Func->writeOut(Stamp); + + write(0); + write(0); + out.close(); + } + + if (EmitGCDA) { + emitGlobalConstructor(CountersBySP); + EmitGCDA = false; } - } - return true; -} - -void GCOVProfiler::emitGlobalConstructor( - SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) { - Function *WriteoutF = insertCounterWriteout(CountersBySP); - Function *ResetF = insertReset(CountersBySP); - - // Create a small bit of code that registers the "__llvm_gcov_writeout" to - // be executed at exit and the "__llvm_gcov_flush" function to be executed - // when "__gcov_flush" is called. - FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, - "__llvm_gcov_init", M); - F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - F->setLinkage(GlobalValue::InternalLinkage); - F->addFnAttr(Attribute::NoInline); - if (Options.NoRedZone) - F->addFnAttr(Attribute::NoRedZone); - - BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); - IRBuilder<> Builder(BB); - - FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - auto *PFTy = PointerType::get(FTy, 0); - FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false); - - // Initialize the environment and register the local writeout, flush and - // reset functions. - FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); - Builder.CreateCall(GCOVInit, {WriteoutF, ResetF}); - Builder.CreateRetVoid(); - - appendToGlobalCtors(*M, F, 0); + } + return true; +} + +void GCOVProfiler::emitGlobalConstructor( + SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) { + Function *WriteoutF = insertCounterWriteout(CountersBySP); + Function *ResetF = insertReset(CountersBySP); + + // Create a small bit of code that registers the "__llvm_gcov_writeout" to + // be executed at exit and the "__llvm_gcov_flush" function to be executed + // when "__gcov_flush" is called. + FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); + Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, + "__llvm_gcov_init", M); + F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + F->setLinkage(GlobalValue::InternalLinkage); + F->addFnAttr(Attribute::NoInline); + if (Options.NoRedZone) + F->addFnAttr(Attribute::NoRedZone); + + BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); + IRBuilder<> Builder(BB); + + FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); + auto *PFTy = PointerType::get(FTy, 0); + FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false); + + // Initialize the environment and register the local writeout, flush and + // reset functions. + FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); + Builder.CreateCall(GCOVInit, {WriteoutF, ResetF}); + Builder.CreateRetVoid(); + + appendToGlobalCtors(*M, F, 0); } FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) { @@ -1140,19 +1140,19 @@ Function *GCOVProfiler::insertCounterWriteout( // Collect the relevant data into a large constant data structure that we can // walk to write out everything. StructType *StartFileCallArgsTy = StructType::create( - {Builder.getInt8PtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()}, - "start_file_args_ty"); + {Builder.getInt8PtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()}, + "start_file_args_ty"); StructType *EmitFunctionCallArgsTy = StructType::create( - {Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()}, - "emit_function_args_ty"); + {Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()}, + "emit_function_args_ty"); StructType *EmitArcsCallArgsTy = StructType::create( - {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}, - "emit_arcs_args_ty"); + {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}, + "emit_arcs_args_ty"); StructType *FileInfoTy = StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(), EmitFunctionCallArgsTy->getPointerTo(), - EmitArcsCallArgsTy->getPointerTo()}, - "file_info"); + EmitArcsCallArgsTy->getPointerTo()}, + "file_info"); Constant *Zero32 = Builder.getInt32(0); // Build an explicit array of two zeros for use in ConstantExpr GEP building. @@ -1262,46 +1262,46 @@ Function *GCOVProfiler::insertCounterWriteout( // The index into the files structure is our loop induction variable. Builder.SetInsertPoint(FileLoopHeader); - PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, - "file_idx"); + PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, + "file_idx"); IV->addIncoming(Builder.getInt32(0), BB); auto *FileInfoPtr = Builder.CreateInBoundsGEP( FileInfoArrayTy, FileInfoArrayGV, {Builder.getInt32(0), IV}); auto *StartFileCallArgsPtr = - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0, "start_file_args"); + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0, "start_file_args"); auto *StartFileCall = Builder.CreateCall( StartFile, {Builder.CreateLoad(StartFileCallArgsTy->getElementType(0), Builder.CreateStructGEP(StartFileCallArgsTy, - StartFileCallArgsPtr, 0), - "filename"), + StartFileCallArgsPtr, 0), + "filename"), Builder.CreateLoad(StartFileCallArgsTy->getElementType(1), Builder.CreateStructGEP(StartFileCallArgsTy, - StartFileCallArgsPtr, 1), - "version"), + StartFileCallArgsPtr, 1), + "version"), Builder.CreateLoad(StartFileCallArgsTy->getElementType(2), Builder.CreateStructGEP(StartFileCallArgsTy, - StartFileCallArgsPtr, 2), - "stamp")}); + StartFileCallArgsPtr, 2), + "stamp")}); if (auto AK = TLI->getExtAttrForI32Param(false)) StartFileCall->addParamAttr(2, AK); - auto *NumCounters = Builder.CreateLoad( - FileInfoTy->getElementType(1), - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1), "num_ctrs"); + auto *NumCounters = Builder.CreateLoad( + FileInfoTy->getElementType(1), + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1), "num_ctrs"); auto *EmitFunctionCallArgsArray = Builder.CreateLoad(FileInfoTy->getElementType(2), - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2), - "emit_function_args"); - auto *EmitArcsCallArgsArray = Builder.CreateLoad( - FileInfoTy->getElementType(3), - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3), "emit_arcs_args"); + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2), + "emit_function_args"); + auto *EmitArcsCallArgsArray = Builder.CreateLoad( + FileInfoTy->getElementType(3), + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3), "emit_arcs_args"); auto *EnterCounterLoopCond = Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters); Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch); Builder.SetInsertPoint(CounterLoopHeader); - auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, - "ctr_idx"); + auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, + "ctr_idx"); JV->addIncoming(Builder.getInt32(0), FileLoopHeader); auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP( EmitFunctionCallArgsTy, EmitFunctionCallArgsArray, JV); @@ -1309,16 +1309,16 @@ Function *GCOVProfiler::insertCounterWriteout( EmitFunction, {Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(0), Builder.CreateStructGEP(EmitFunctionCallArgsTy, - EmitFunctionCallArgsPtr, 0), - "ident"), + EmitFunctionCallArgsPtr, 0), + "ident"), Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(1), Builder.CreateStructGEP(EmitFunctionCallArgsTy, - EmitFunctionCallArgsPtr, 1), - "func_checkssum"), + EmitFunctionCallArgsPtr, 1), + "func_checkssum"), Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(2), Builder.CreateStructGEP(EmitFunctionCallArgsTy, - EmitFunctionCallArgsPtr, 2), - "cfg_checksum")}); + EmitFunctionCallArgsPtr, 2), + "cfg_checksum")}); if (auto AK = TLI->getExtAttrForI32Param(false)) { EmitFunctionCall->addParamAttr(0, AK); EmitFunctionCall->addParamAttr(1, AK); @@ -1330,12 +1330,12 @@ Function *GCOVProfiler::insertCounterWriteout( EmitArcs, {Builder.CreateLoad( EmitArcsCallArgsTy->getElementType(0), - Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0), - "num_counters"), - Builder.CreateLoad( - EmitArcsCallArgsTy->getElementType(1), - Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 1), - "counters")}); + Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0), + "num_counters"), + Builder.CreateLoad( + EmitArcsCallArgsTy->getElementType(1), + Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 1), + "counters")}); if (auto AK = TLI->getExtAttrForI32Param(false)) EmitArcsCall->addParamAttr(0, AK); auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1)); @@ -1346,7 +1346,7 @@ Function *GCOVProfiler::insertCounterWriteout( Builder.SetInsertPoint(FileLoopLatch); Builder.CreateCall(SummaryInfo, {}); Builder.CreateCall(EndFile, {}); - auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1), "next_file_idx"); + auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1), "next_file_idx"); auto *FileLoopCond = Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size())); Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB); |