10b57cec5SDimitry Andric //===- GCOVProfiling.cpp - Insert edge counters for gcov profiling --------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass implements GCOV-style profiling. When this pass is run it emits 100b57cec5SDimitry Andric // "gcno" files next to the existing source, and instruments the code that runs 110b57cec5SDimitry Andric // to records the edges between blocks that run and emit a complementary "gcda" 120b57cec5SDimitry Andric // file on exit. 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "llvm/ADT/Hashing.h" 17e8d8bef9SDimitry Andric #include "llvm/ADT/MapVector.h" 180b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 190b57cec5SDimitry Andric #include "llvm/ADT/Sequence.h" 200b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h" 21e8d8bef9SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h" 22e8d8bef9SDimitry Andric #include "llvm/Analysis/BranchProbabilityInfo.h" 230b57cec5SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 240b57cec5SDimitry Andric #include "llvm/IR/DebugInfo.h" 250b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 2606c3fb27SDimitry Andric #include "llvm/IR/EHPersonalities.h" 270b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 280b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h" 290b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 300b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 310b57cec5SDimitry Andric #include "llvm/IR/Module.h" 32e8d8bef9SDimitry Andric #include "llvm/Support/CRC.h" 330b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 340b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 350b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 360b57cec5SDimitry Andric #include "llvm/Support/Path.h" 370b57cec5SDimitry Andric #include "llvm/Support/Regex.h" 380b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 390b57cec5SDimitry Andric #include "llvm/Transforms/Instrumentation.h" 4006c3fb27SDimitry Andric #include "llvm/Transforms/Instrumentation/CFGMST.h" 410b57cec5SDimitry Andric #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" 420b57cec5SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h" 430b57cec5SDimitry Andric #include <algorithm> 440b57cec5SDimitry Andric #include <memory> 450b57cec5SDimitry Andric #include <string> 460b57cec5SDimitry Andric #include <utility> 475ffd83dbSDimitry Andric 480b57cec5SDimitry Andric using namespace llvm; 495ffd83dbSDimitry Andric namespace endian = llvm::support::endian; 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric #define DEBUG_TYPE "insert-gcov-profiling" 520b57cec5SDimitry Andric 535ffd83dbSDimitry Andric enum : uint32_t { 54e8d8bef9SDimitry Andric GCOV_ARC_ON_TREE = 1 << 0, 55e8d8bef9SDimitry Andric 565ffd83dbSDimitry Andric GCOV_TAG_FUNCTION = 0x01000000, 575ffd83dbSDimitry Andric GCOV_TAG_BLOCKS = 0x01410000, 585ffd83dbSDimitry Andric GCOV_TAG_ARCS = 0x01430000, 595ffd83dbSDimitry Andric GCOV_TAG_LINES = 0x01450000, 605ffd83dbSDimitry Andric }; 615ffd83dbSDimitry Andric 625ffd83dbSDimitry Andric static cl::opt<std::string> DefaultGCOVVersion("default-gcov-version", 635ffd83dbSDimitry Andric cl::init("408*"), cl::Hidden, 640b57cec5SDimitry Andric cl::ValueRequired); 655ffd83dbSDimitry Andric 66e8d8bef9SDimitry Andric static cl::opt<bool> AtomicCounter("gcov-atomic-counter", cl::Hidden, 67e8d8bef9SDimitry Andric cl::desc("Make counter updates atomic")); 68e8d8bef9SDimitry Andric 695ffd83dbSDimitry Andric // Returns the number of words which will be used to represent this string. 705ffd83dbSDimitry Andric static unsigned wordsOfString(StringRef s) { 715ffd83dbSDimitry Andric // Length + NUL-terminated string + 0~3 padding NULs. 725ffd83dbSDimitry Andric return (s.size() / 4) + 2; 735ffd83dbSDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric GCOVOptions GCOVOptions::getDefault() { 760b57cec5SDimitry Andric GCOVOptions Options; 770b57cec5SDimitry Andric Options.EmitNotes = true; 780b57cec5SDimitry Andric Options.EmitData = true; 790b57cec5SDimitry Andric Options.NoRedZone = false; 80e8d8bef9SDimitry Andric Options.Atomic = AtomicCounter; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric if (DefaultGCOVVersion.size() != 4) { 83349cc55cSDimitry Andric llvm::report_fatal_error(Twine("Invalid -default-gcov-version: ") + 8481ad6265SDimitry Andric DefaultGCOVVersion, /*GenCrashDiag=*/false); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric memcpy(Options.Version, DefaultGCOVVersion.c_str(), 4); 870b57cec5SDimitry Andric return Options; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric namespace { 910b57cec5SDimitry Andric class GCOVFunction; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric class GCOVProfiler { 940b57cec5SDimitry Andric public: 950b57cec5SDimitry Andric GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {} 965ffd83dbSDimitry Andric GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {} 978bcb0991SDimitry Andric bool 98e8d8bef9SDimitry Andric runOnModule(Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, 99e8d8bef9SDimitry Andric function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, 1008bcb0991SDimitry Andric std::function<const TargetLibraryInfo &(Function &F)> GetTLI); 1010b57cec5SDimitry Andric 1025ffd83dbSDimitry Andric void write(uint32_t i) { 1035ffd83dbSDimitry Andric char Bytes[4]; 1045ffd83dbSDimitry Andric endian::write32(Bytes, i, Endian); 1055ffd83dbSDimitry Andric os->write(Bytes, 4); 1065ffd83dbSDimitry Andric } 1075ffd83dbSDimitry Andric void writeString(StringRef s) { 1085ffd83dbSDimitry Andric write(wordsOfString(s) - 1); 1095ffd83dbSDimitry Andric os->write(s.data(), s.size()); 1105ffd83dbSDimitry Andric os->write_zeros(4 - s.size() % 4); 1115ffd83dbSDimitry Andric } 1125ffd83dbSDimitry Andric void writeBytes(const char *Bytes, int Size) { os->write(Bytes, Size); } 1135ffd83dbSDimitry Andric 1140b57cec5SDimitry Andric private: 1150b57cec5SDimitry Andric // Create the .gcno files for the Module based on DebugInfo. 116e8d8bef9SDimitry Andric bool 117e8d8bef9SDimitry Andric emitProfileNotes(NamedMDNode *CUNode, bool HasExecOrFork, 118e8d8bef9SDimitry Andric function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, 119e8d8bef9SDimitry Andric function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, 120e8d8bef9SDimitry Andric function_ref<const TargetLibraryInfo &(Function &F)> GetTLI); 1210b57cec5SDimitry Andric 122bdd1243dSDimitry Andric Function *createInternalFunction(FunctionType *FTy, StringRef Name, 123bdd1243dSDimitry Andric StringRef MangledType = ""); 124e8d8bef9SDimitry Andric void emitGlobalConstructor( 125e8d8bef9SDimitry Andric SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric bool isFunctionInstrumented(const Function &F); 1280b57cec5SDimitry Andric std::vector<Regex> createRegexesFromString(StringRef RegexesStr); 1290b57cec5SDimitry Andric static bool doesFilenameMatchARegex(StringRef Filename, 1300b57cec5SDimitry Andric std::vector<Regex> &Regexes); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric // Get pointers to the functions in the runtime library. 1338bcb0991SDimitry Andric FunctionCallee getStartFileFunc(const TargetLibraryInfo *TLI); 1348bcb0991SDimitry Andric FunctionCallee getEmitFunctionFunc(const TargetLibraryInfo *TLI); 1358bcb0991SDimitry Andric FunctionCallee getEmitArcsFunc(const TargetLibraryInfo *TLI); 1360b57cec5SDimitry Andric FunctionCallee getSummaryInfoFunc(); 1370b57cec5SDimitry Andric FunctionCallee getEndFileFunc(); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // Add the function to write out all our counters to the global destructor 1400b57cec5SDimitry Andric // list. 1410b57cec5SDimitry Andric Function * 1420b57cec5SDimitry Andric insertCounterWriteout(ArrayRef<std::pair<GlobalVariable *, MDNode *>>); 143d65cd7a5SDimitry Andric Function *insertReset(ArrayRef<std::pair<GlobalVariable *, MDNode *>>); 1440b57cec5SDimitry Andric 1455ffd83dbSDimitry Andric bool AddFlushBeforeForkAndExec(); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric enum class GCovFileType { GCNO, GCDA }; 1480b57cec5SDimitry Andric std::string mangleName(const DICompileUnit *CU, GCovFileType FileType); 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric GCOVOptions Options; 1515f757f3fSDimitry Andric llvm::endianness Endian; 1525ffd83dbSDimitry Andric raw_ostream *os; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric // Checksum, produced by hash of EdgeDestinations 1550b57cec5SDimitry Andric SmallVector<uint32_t, 4> FileChecksums; 1560b57cec5SDimitry Andric 157480093f4SDimitry Andric Module *M = nullptr; 1588bcb0991SDimitry Andric std::function<const TargetLibraryInfo &(Function &F)> GetTLI; 159480093f4SDimitry Andric LLVMContext *Ctx = nullptr; 1600b57cec5SDimitry Andric SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs; 1610b57cec5SDimitry Andric std::vector<Regex> FilterRe; 1620b57cec5SDimitry Andric std::vector<Regex> ExcludeRe; 163e8d8bef9SDimitry Andric DenseSet<const BasicBlock *> ExecBlocks; 1640b57cec5SDimitry Andric StringMap<bool> InstrumentedFiles; 1650b57cec5SDimitry Andric }; 1660b57cec5SDimitry Andric 167e8d8bef9SDimitry Andric struct BBInfo { 168e8d8bef9SDimitry Andric BBInfo *Group; 169e8d8bef9SDimitry Andric uint32_t Index; 170e8d8bef9SDimitry Andric uint32_t Rank = 0; 171e8d8bef9SDimitry Andric 172e8d8bef9SDimitry Andric BBInfo(unsigned Index) : Group(this), Index(Index) {} 173fe6060f1SDimitry Andric std::string infoString() const { 174e8d8bef9SDimitry Andric return (Twine("Index=") + Twine(Index)).str(); 175e8d8bef9SDimitry Andric } 176e8d8bef9SDimitry Andric }; 177e8d8bef9SDimitry Andric 178e8d8bef9SDimitry Andric struct Edge { 179e8d8bef9SDimitry Andric // This class implements the CFG edges. Note the CFG can be a multi-graph. 180e8d8bef9SDimitry Andric // So there might be multiple edges with same SrcBB and DestBB. 181e8d8bef9SDimitry Andric const BasicBlock *SrcBB; 182e8d8bef9SDimitry Andric const BasicBlock *DestBB; 183e8d8bef9SDimitry Andric uint64_t Weight; 184e8d8bef9SDimitry Andric BasicBlock *Place = nullptr; 185e8d8bef9SDimitry Andric uint32_t SrcNumber, DstNumber; 186e8d8bef9SDimitry Andric bool InMST = false; 187e8d8bef9SDimitry Andric bool Removed = false; 188e8d8bef9SDimitry Andric bool IsCritical = false; 189e8d8bef9SDimitry Andric 190e8d8bef9SDimitry Andric Edge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W = 1) 191e8d8bef9SDimitry Andric : SrcBB(Src), DestBB(Dest), Weight(W) {} 192e8d8bef9SDimitry Andric 193e8d8bef9SDimitry Andric // Return the information string of an edge. 194fe6060f1SDimitry Andric std::string infoString() const { 195e8d8bef9SDimitry Andric return (Twine(Removed ? "-" : " ") + (InMST ? " " : "*") + 196e8d8bef9SDimitry Andric (IsCritical ? "c" : " ") + " W=" + Twine(Weight)) 197e8d8bef9SDimitry Andric .str(); 198e8d8bef9SDimitry Andric } 199e8d8bef9SDimitry Andric }; 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric static StringRef getFunctionName(const DISubprogram *SP) { 2030b57cec5SDimitry Andric if (!SP->getLinkageName().empty()) 2040b57cec5SDimitry Andric return SP->getLinkageName(); 2050b57cec5SDimitry Andric return SP->getName(); 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric /// Extract a filename for a DISubprogram. 2090b57cec5SDimitry Andric /// 2100b57cec5SDimitry Andric /// Prefer relative paths in the coverage notes. Clang also may split 2110b57cec5SDimitry Andric /// up absolute paths into a directory and filename component. When 2120b57cec5SDimitry Andric /// the relative path doesn't exist, reconstruct the absolute path. 2130b57cec5SDimitry Andric static SmallString<128> getFilename(const DISubprogram *SP) { 2140b57cec5SDimitry Andric SmallString<128> Path; 2150b57cec5SDimitry Andric StringRef RelPath = SP->getFilename(); 2160b57cec5SDimitry Andric if (sys::fs::exists(RelPath)) 2170b57cec5SDimitry Andric Path = RelPath; 2180b57cec5SDimitry Andric else 2190b57cec5SDimitry Andric sys::path::append(Path, SP->getDirectory(), SP->getFilename()); 2200b57cec5SDimitry Andric return Path; 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric namespace { 2240b57cec5SDimitry Andric class GCOVRecord { 2250b57cec5SDimitry Andric protected: 2265ffd83dbSDimitry Andric GCOVProfiler *P; 2270b57cec5SDimitry Andric 2285ffd83dbSDimitry Andric GCOVRecord(GCOVProfiler *P) : P(P) {} 2290b57cec5SDimitry Andric 2305ffd83dbSDimitry Andric void write(uint32_t i) { P->write(i); } 2315ffd83dbSDimitry Andric void writeString(StringRef s) { P->writeString(s); } 2325ffd83dbSDimitry Andric void writeBytes(const char *Bytes, int Size) { P->writeBytes(Bytes, Size); } 2330b57cec5SDimitry Andric }; 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric class GCOVFunction; 2360b57cec5SDimitry Andric class GCOVBlock; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric // Constructed only by requesting it from a GCOVBlock, this object stores a 2390b57cec5SDimitry Andric // list of line numbers and a single filename, representing lines that belong 2400b57cec5SDimitry Andric // to the block. 2410b57cec5SDimitry Andric class GCOVLines : public GCOVRecord { 2420b57cec5SDimitry Andric public: 2430b57cec5SDimitry Andric void addLine(uint32_t Line) { 2440b57cec5SDimitry Andric assert(Line != 0 && "Line zero is not a valid real line number."); 2450b57cec5SDimitry Andric Lines.push_back(Line); 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric uint32_t length() const { 2495ffd83dbSDimitry Andric return 1 + wordsOfString(Filename) + Lines.size(); 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric void writeOut() { 2530b57cec5SDimitry Andric write(0); 2545ffd83dbSDimitry Andric writeString(Filename); 255bdd1243dSDimitry Andric for (uint32_t L : Lines) 256bdd1243dSDimitry Andric write(L); 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric 2595ffd83dbSDimitry Andric GCOVLines(GCOVProfiler *P, StringRef F) 2605ffd83dbSDimitry Andric : GCOVRecord(P), Filename(std::string(F)) {} 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric private: 2630b57cec5SDimitry Andric std::string Filename; 2640b57cec5SDimitry Andric SmallVector<uint32_t, 32> Lines; 2650b57cec5SDimitry Andric }; 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric // Represent a basic block in GCOV. Each block has a unique number in the 2690b57cec5SDimitry Andric // function, number of lines belonging to each block, and a set of edges to 2700b57cec5SDimitry Andric // other blocks. 2710b57cec5SDimitry Andric class GCOVBlock : public GCOVRecord { 2720b57cec5SDimitry Andric public: 2730b57cec5SDimitry Andric GCOVLines &getFile(StringRef Filename) { 2745ffd83dbSDimitry Andric return LinesByFile.try_emplace(Filename, P, Filename).first->second; 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 277e8d8bef9SDimitry Andric void addEdge(GCOVBlock &Successor, uint32_t Flags) { 278e8d8bef9SDimitry Andric OutEdges.emplace_back(&Successor, Flags); 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric void writeOut() { 2820b57cec5SDimitry Andric uint32_t Len = 3; 2830b57cec5SDimitry Andric SmallVector<StringMapEntry<GCOVLines> *, 32> SortedLinesByFile; 2840b57cec5SDimitry Andric for (auto &I : LinesByFile) { 2850b57cec5SDimitry Andric Len += I.second.length(); 2860b57cec5SDimitry Andric SortedLinesByFile.push_back(&I); 2870b57cec5SDimitry Andric } 2880b57cec5SDimitry Andric 2895ffd83dbSDimitry Andric write(GCOV_TAG_LINES); 2900b57cec5SDimitry Andric write(Len); 2910b57cec5SDimitry Andric write(Number); 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric llvm::sort(SortedLinesByFile, [](StringMapEntry<GCOVLines> *LHS, 2940b57cec5SDimitry Andric StringMapEntry<GCOVLines> *RHS) { 2950b57cec5SDimitry Andric return LHS->getKey() < RHS->getKey(); 2960b57cec5SDimitry Andric }); 2970b57cec5SDimitry Andric for (auto &I : SortedLinesByFile) 2980b57cec5SDimitry Andric I->getValue().writeOut(); 2990b57cec5SDimitry Andric write(0); 3000b57cec5SDimitry Andric write(0); 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric GCOVBlock(const GCOVBlock &RHS) : GCOVRecord(RHS), Number(RHS.Number) { 3040b57cec5SDimitry Andric // Only allow copy before edges and lines have been added. After that, 3050b57cec5SDimitry Andric // there are inter-block pointers (eg: edges) that won't take kindly to 3060b57cec5SDimitry Andric // blocks being copied or moved around. 3070b57cec5SDimitry Andric assert(LinesByFile.empty()); 3080b57cec5SDimitry Andric assert(OutEdges.empty()); 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric 311e8d8bef9SDimitry Andric uint32_t Number; 312e8d8bef9SDimitry Andric SmallVector<std::pair<GCOVBlock *, uint32_t>, 4> OutEdges; 313e8d8bef9SDimitry Andric 3140b57cec5SDimitry Andric private: 3150b57cec5SDimitry Andric friend class GCOVFunction; 3160b57cec5SDimitry Andric 3175ffd83dbSDimitry Andric GCOVBlock(GCOVProfiler *P, uint32_t Number) 3185ffd83dbSDimitry Andric : GCOVRecord(P), Number(Number) {} 3190b57cec5SDimitry Andric 3200b57cec5SDimitry Andric StringMap<GCOVLines> LinesByFile; 3210b57cec5SDimitry Andric }; 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric // A function has a unique identifier, a checksum (we leave as zero) and a 3240b57cec5SDimitry Andric // set of blocks and a map of edges between blocks. This is the only GCOV 3250b57cec5SDimitry Andric // object users can construct, the blocks and lines will be rooted here. 3260b57cec5SDimitry Andric class GCOVFunction : public GCOVRecord { 3270b57cec5SDimitry Andric public: 3285ffd83dbSDimitry Andric GCOVFunction(GCOVProfiler *P, Function *F, const DISubprogram *SP, 3295ffd83dbSDimitry Andric unsigned EndLine, uint32_t Ident, int Version) 3305ffd83dbSDimitry Andric : GCOVRecord(P), SP(SP), EndLine(EndLine), Ident(Ident), 331e8d8bef9SDimitry Andric Version(Version), EntryBlock(P, 0), ReturnBlock(P, 1) { 3320b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n"); 3335ffd83dbSDimitry Andric bool ExitBlockBeforeBody = Version >= 48; 334e8d8bef9SDimitry Andric uint32_t i = ExitBlockBeforeBody ? 2 : 1; 335e8d8bef9SDimitry Andric for (BasicBlock &BB : *F) 3365ffd83dbSDimitry Andric Blocks.insert(std::make_pair(&BB, GCOVBlock(P, i++))); 3370b57cec5SDimitry Andric if (!ExitBlockBeforeBody) 3380b57cec5SDimitry Andric ReturnBlock.Number = i; 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric std::string FunctionNameAndLine; 3410b57cec5SDimitry Andric raw_string_ostream FNLOS(FunctionNameAndLine); 3420b57cec5SDimitry Andric FNLOS << getFunctionName(SP) << SP->getLine(); 3430b57cec5SDimitry Andric FNLOS.flush(); 3440b57cec5SDimitry Andric FuncChecksum = hash_value(FunctionNameAndLine); 3450b57cec5SDimitry Andric } 3460b57cec5SDimitry Andric 347e8d8bef9SDimitry Andric GCOVBlock &getBlock(const BasicBlock *BB) { 348e8d8bef9SDimitry Andric return Blocks.find(const_cast<BasicBlock *>(BB))->second; 3490b57cec5SDimitry Andric } 3500b57cec5SDimitry Andric 351e8d8bef9SDimitry Andric GCOVBlock &getEntryBlock() { return EntryBlock; } 3520b57cec5SDimitry Andric GCOVBlock &getReturnBlock() { 3530b57cec5SDimitry Andric return ReturnBlock; 3540b57cec5SDimitry Andric } 3550b57cec5SDimitry Andric 356480093f4SDimitry Andric uint32_t getFuncChecksum() const { 3570b57cec5SDimitry Andric return FuncChecksum; 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 3605ffd83dbSDimitry Andric void writeOut(uint32_t CfgChecksum) { 3615ffd83dbSDimitry Andric write(GCOV_TAG_FUNCTION); 3620b57cec5SDimitry Andric SmallString<128> Filename = getFilename(SP); 3635ffd83dbSDimitry Andric uint32_t BlockLen = 3645ffd83dbSDimitry Andric 2 + (Version >= 47) + wordsOfString(getFunctionName(SP)); 3655ffd83dbSDimitry Andric if (Version < 80) 3665ffd83dbSDimitry Andric BlockLen += wordsOfString(Filename) + 1; 3675ffd83dbSDimitry Andric else 3685ffd83dbSDimitry Andric BlockLen += 1 + wordsOfString(Filename) + 3 + (Version >= 90); 3695ffd83dbSDimitry Andric 3700b57cec5SDimitry Andric write(BlockLen); 3710b57cec5SDimitry Andric write(Ident); 3720b57cec5SDimitry Andric write(FuncChecksum); 3735ffd83dbSDimitry Andric if (Version >= 47) 3740b57cec5SDimitry Andric write(CfgChecksum); 3755ffd83dbSDimitry Andric writeString(getFunctionName(SP)); 3765ffd83dbSDimitry Andric if (Version < 80) { 3775ffd83dbSDimitry Andric writeString(Filename); 3780b57cec5SDimitry Andric write(SP->getLine()); 3795ffd83dbSDimitry Andric } else { 3805ffd83dbSDimitry Andric write(SP->isArtificial()); // artificial 3815ffd83dbSDimitry Andric writeString(Filename); 3825ffd83dbSDimitry Andric write(SP->getLine()); // start_line 3835ffd83dbSDimitry Andric write(0); // start_column 3845ffd83dbSDimitry Andric // EndLine is the last line with !dbg. It is not the } line as in GCC, 3855ffd83dbSDimitry Andric // but good enough. 3865ffd83dbSDimitry Andric write(EndLine); 3875ffd83dbSDimitry Andric if (Version >= 90) 3885ffd83dbSDimitry Andric write(0); // end_column 3895ffd83dbSDimitry Andric } 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric // Emit count of blocks. 3925ffd83dbSDimitry Andric write(GCOV_TAG_BLOCKS); 3935ffd83dbSDimitry Andric if (Version < 80) { 394e8d8bef9SDimitry Andric write(Blocks.size() + 2); 395e8d8bef9SDimitry Andric for (int i = Blocks.size() + 2; i; --i) 3965ffd83dbSDimitry Andric write(0); 3975ffd83dbSDimitry Andric } else { 3985ffd83dbSDimitry Andric write(1); 399e8d8bef9SDimitry Andric write(Blocks.size() + 2); 4000b57cec5SDimitry Andric } 4015ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << (Blocks.size() + 1) << " blocks\n"); 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric // Emit edges between blocks. 404e8d8bef9SDimitry Andric const uint32_t Outgoing = EntryBlock.OutEdges.size(); 405e8d8bef9SDimitry Andric if (Outgoing) { 406e8d8bef9SDimitry Andric write(GCOV_TAG_ARCS); 407e8d8bef9SDimitry Andric write(Outgoing * 2 + 1); 408e8d8bef9SDimitry Andric write(EntryBlock.Number); 409e8d8bef9SDimitry Andric for (const auto &E : EntryBlock.OutEdges) { 410e8d8bef9SDimitry Andric write(E.first->Number); 411e8d8bef9SDimitry Andric write(E.second); 412e8d8bef9SDimitry Andric } 413e8d8bef9SDimitry Andric } 414e8d8bef9SDimitry Andric for (auto &It : Blocks) { 415e8d8bef9SDimitry Andric const GCOVBlock &Block = It.second; 4160b57cec5SDimitry Andric if (Block.OutEdges.empty()) continue; 4170b57cec5SDimitry Andric 4185ffd83dbSDimitry Andric write(GCOV_TAG_ARCS); 4190b57cec5SDimitry Andric write(Block.OutEdges.size() * 2 + 1); 4200b57cec5SDimitry Andric write(Block.Number); 421e8d8bef9SDimitry Andric for (const auto &E : Block.OutEdges) { 422e8d8bef9SDimitry Andric write(E.first->Number); 423e8d8bef9SDimitry Andric write(E.second); 4240b57cec5SDimitry Andric } 4250b57cec5SDimitry Andric } 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric // Emit lines for each block. 428e8d8bef9SDimitry Andric for (auto &It : Blocks) 429e8d8bef9SDimitry Andric It.second.writeOut(); 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric 432e8d8bef9SDimitry Andric public: 4330b57cec5SDimitry Andric const DISubprogram *SP; 4345ffd83dbSDimitry Andric unsigned EndLine; 4350b57cec5SDimitry Andric uint32_t Ident; 4360b57cec5SDimitry Andric uint32_t FuncChecksum; 4375ffd83dbSDimitry Andric int Version; 438e8d8bef9SDimitry Andric MapVector<BasicBlock *, GCOVBlock> Blocks; 439e8d8bef9SDimitry Andric GCOVBlock EntryBlock; 4400b57cec5SDimitry Andric GCOVBlock ReturnBlock; 4410b57cec5SDimitry Andric }; 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric // RegexesStr is a string containing differents regex separated by a semi-colon. 4450b57cec5SDimitry Andric // For example "foo\..*$;bar\..*$". 4460b57cec5SDimitry Andric std::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) { 4470b57cec5SDimitry Andric std::vector<Regex> Regexes; 4480b57cec5SDimitry Andric while (!RegexesStr.empty()) { 4490b57cec5SDimitry Andric std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(';'); 4500b57cec5SDimitry Andric if (!HeadTail.first.empty()) { 4510b57cec5SDimitry Andric Regex Re(HeadTail.first); 4520b57cec5SDimitry Andric std::string Err; 4530b57cec5SDimitry Andric if (!Re.isValid(Err)) { 4540b57cec5SDimitry Andric Ctx->emitError(Twine("Regex ") + HeadTail.first + 4550b57cec5SDimitry Andric " is not valid: " + Err); 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric Regexes.emplace_back(std::move(Re)); 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric RegexesStr = HeadTail.second; 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric return Regexes; 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric bool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename, 4650b57cec5SDimitry Andric std::vector<Regex> &Regexes) { 4665ffd83dbSDimitry Andric for (Regex &Re : Regexes) 4675ffd83dbSDimitry Andric if (Re.match(Filename)) 4680b57cec5SDimitry Andric return true; 4690b57cec5SDimitry Andric return false; 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric bool GCOVProfiler::isFunctionInstrumented(const Function &F) { 4730b57cec5SDimitry Andric if (FilterRe.empty() && ExcludeRe.empty()) { 4740b57cec5SDimitry Andric return true; 4750b57cec5SDimitry Andric } 4760b57cec5SDimitry Andric SmallString<128> Filename = getFilename(F.getSubprogram()); 4770b57cec5SDimitry Andric auto It = InstrumentedFiles.find(Filename); 4780b57cec5SDimitry Andric if (It != InstrumentedFiles.end()) { 4790b57cec5SDimitry Andric return It->second; 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric SmallString<256> RealPath; 4830b57cec5SDimitry Andric StringRef RealFilename; 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric // Path can be 4860b57cec5SDimitry Andric // /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for 4870b57cec5SDimitry Andric // such a case we must get the real_path. 4880b57cec5SDimitry Andric if (sys::fs::real_path(Filename, RealPath)) { 4890b57cec5SDimitry Andric // real_path can fail with path like "foo.c". 4900b57cec5SDimitry Andric RealFilename = Filename; 4910b57cec5SDimitry Andric } else { 4920b57cec5SDimitry Andric RealFilename = RealPath; 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric 4950b57cec5SDimitry Andric bool ShouldInstrument; 4960b57cec5SDimitry Andric if (FilterRe.empty()) { 4970b57cec5SDimitry Andric ShouldInstrument = !doesFilenameMatchARegex(RealFilename, ExcludeRe); 4980b57cec5SDimitry Andric } else if (ExcludeRe.empty()) { 4990b57cec5SDimitry Andric ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe); 5000b57cec5SDimitry Andric } else { 5010b57cec5SDimitry Andric ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe) && 5020b57cec5SDimitry Andric !doesFilenameMatchARegex(RealFilename, ExcludeRe); 5030b57cec5SDimitry Andric } 5040b57cec5SDimitry Andric InstrumentedFiles[Filename] = ShouldInstrument; 5050b57cec5SDimitry Andric return ShouldInstrument; 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric std::string GCOVProfiler::mangleName(const DICompileUnit *CU, 5090b57cec5SDimitry Andric GCovFileType OutputType) { 5100b57cec5SDimitry Andric bool Notes = OutputType == GCovFileType::GCNO; 5110b57cec5SDimitry Andric 5120b57cec5SDimitry Andric if (NamedMDNode *GCov = M->getNamedMetadata("llvm.gcov")) { 5130b57cec5SDimitry Andric for (int i = 0, e = GCov->getNumOperands(); i != e; ++i) { 5140b57cec5SDimitry Andric MDNode *N = GCov->getOperand(i); 5150b57cec5SDimitry Andric bool ThreeElement = N->getNumOperands() == 3; 5160b57cec5SDimitry Andric if (!ThreeElement && N->getNumOperands() != 2) 5170b57cec5SDimitry Andric continue; 5180b57cec5SDimitry Andric if (dyn_cast<MDNode>(N->getOperand(ThreeElement ? 2 : 1)) != CU) 5190b57cec5SDimitry Andric continue; 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric if (ThreeElement) { 5220b57cec5SDimitry Andric // These nodes have no mangling to apply, it's stored mangled in the 5230b57cec5SDimitry Andric // bitcode. 5240b57cec5SDimitry Andric MDString *NotesFile = dyn_cast<MDString>(N->getOperand(0)); 5250b57cec5SDimitry Andric MDString *DataFile = dyn_cast<MDString>(N->getOperand(1)); 5260b57cec5SDimitry Andric if (!NotesFile || !DataFile) 5270b57cec5SDimitry Andric continue; 5285ffd83dbSDimitry Andric return std::string(Notes ? NotesFile->getString() 5295ffd83dbSDimitry Andric : DataFile->getString()); 5300b57cec5SDimitry Andric } 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric MDString *GCovFile = dyn_cast<MDString>(N->getOperand(0)); 5330b57cec5SDimitry Andric if (!GCovFile) 5340b57cec5SDimitry Andric continue; 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric SmallString<128> Filename = GCovFile->getString(); 5370b57cec5SDimitry Andric sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda"); 538*7a6dacacSDimitry Andric return std::string(Filename); 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric SmallString<128> Filename = CU->getFilename(); 5430b57cec5SDimitry Andric sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda"); 5440b57cec5SDimitry Andric StringRef FName = sys::path::filename(Filename); 5450b57cec5SDimitry Andric SmallString<128> CurPath; 5465ffd83dbSDimitry Andric if (sys::fs::current_path(CurPath)) 5475ffd83dbSDimitry Andric return std::string(FName); 5480b57cec5SDimitry Andric sys::path::append(CurPath, FName); 549*7a6dacacSDimitry Andric return std::string(CurPath); 5500b57cec5SDimitry Andric } 5510b57cec5SDimitry Andric 5528bcb0991SDimitry Andric bool GCOVProfiler::runOnModule( 553e8d8bef9SDimitry Andric Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, 554e8d8bef9SDimitry Andric function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, 555e8d8bef9SDimitry Andric std::function<const TargetLibraryInfo &(Function &F)> GetTLI) { 5560b57cec5SDimitry Andric this->M = &M; 5578bcb0991SDimitry Andric this->GetTLI = std::move(GetTLI); 5580b57cec5SDimitry Andric Ctx = &M.getContext(); 5590b57cec5SDimitry Andric 560e8d8bef9SDimitry Andric NamedMDNode *CUNode = M.getNamedMetadata("llvm.dbg.cu"); 561e8d8bef9SDimitry Andric if (!CUNode || (!Options.EmitNotes && !Options.EmitData)) 562e8d8bef9SDimitry Andric return false; 563e8d8bef9SDimitry Andric 564e8d8bef9SDimitry Andric bool HasExecOrFork = AddFlushBeforeForkAndExec(); 5650b57cec5SDimitry Andric 5660b57cec5SDimitry Andric FilterRe = createRegexesFromString(Options.Filter); 5670b57cec5SDimitry Andric ExcludeRe = createRegexesFromString(Options.Exclude); 568e8d8bef9SDimitry Andric emitProfileNotes(CUNode, HasExecOrFork, GetBFI, GetBPI, this->GetTLI); 569e8d8bef9SDimitry Andric return true; 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric PreservedAnalyses GCOVProfilerPass::run(Module &M, 5730b57cec5SDimitry Andric ModuleAnalysisManager &AM) { 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric GCOVProfiler Profiler(GCOVOpts); 5768bcb0991SDimitry Andric FunctionAnalysisManager &FAM = 5778bcb0991SDimitry Andric AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 5780b57cec5SDimitry Andric 579e8d8bef9SDimitry Andric auto GetBFI = [&FAM](Function &F) { 580e8d8bef9SDimitry Andric return &FAM.getResult<BlockFrequencyAnalysis>(F); 581e8d8bef9SDimitry Andric }; 582e8d8bef9SDimitry Andric auto GetBPI = [&FAM](Function &F) { 583e8d8bef9SDimitry Andric return &FAM.getResult<BranchProbabilityAnalysis>(F); 584e8d8bef9SDimitry Andric }; 585e8d8bef9SDimitry Andric auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & { 5868bcb0991SDimitry Andric return FAM.getResult<TargetLibraryAnalysis>(F); 587e8d8bef9SDimitry Andric }; 588e8d8bef9SDimitry Andric 589e8d8bef9SDimitry Andric if (!Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI)) 5900b57cec5SDimitry Andric return PreservedAnalyses::all(); 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric return PreservedAnalyses::none(); 5930b57cec5SDimitry Andric } 5940b57cec5SDimitry Andric 5955ffd83dbSDimitry Andric static bool functionHasLines(const Function &F, unsigned &EndLine) { 5960b57cec5SDimitry Andric // Check whether this function actually has any source lines. Not only 5970b57cec5SDimitry Andric // do these waste space, they also can crash gcov. 5985ffd83dbSDimitry Andric EndLine = 0; 599bdd1243dSDimitry Andric for (const auto &BB : F) { 600bdd1243dSDimitry Andric for (const auto &I : BB) { 6010b57cec5SDimitry Andric // Debug intrinsic locations correspond to the location of the 6020b57cec5SDimitry Andric // declaration, not necessarily any statements or expressions. 6030b57cec5SDimitry Andric if (isa<DbgInfoIntrinsic>(&I)) continue; 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric const DebugLoc &Loc = I.getDebugLoc(); 6060b57cec5SDimitry Andric if (!Loc) 6070b57cec5SDimitry Andric continue; 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric // Artificial lines such as calls to the global constructors. 6100b57cec5SDimitry Andric if (Loc.getLine() == 0) continue; 6115ffd83dbSDimitry Andric EndLine = std::max(EndLine, Loc.getLine()); 6120b57cec5SDimitry Andric 6130b57cec5SDimitry Andric return true; 6140b57cec5SDimitry Andric } 6150b57cec5SDimitry Andric } 6160b57cec5SDimitry Andric return false; 6170b57cec5SDimitry Andric } 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric static bool isUsingScopeBasedEH(Function &F) { 6200b57cec5SDimitry Andric if (!F.hasPersonalityFn()) return false; 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric EHPersonality Personality = classifyEHPersonality(F.getPersonalityFn()); 6230b57cec5SDimitry Andric return isScopedEHPersonality(Personality); 6240b57cec5SDimitry Andric } 6250b57cec5SDimitry Andric 6265ffd83dbSDimitry Andric bool GCOVProfiler::AddFlushBeforeForkAndExec() { 627bdd1243dSDimitry Andric const TargetLibraryInfo *TLI = nullptr; 628d65cd7a5SDimitry Andric SmallVector<CallInst *, 2> Forks; 629d65cd7a5SDimitry Andric SmallVector<CallInst *, 2> Execs; 6300b57cec5SDimitry Andric for (auto &F : M->functions()) { 631bdd1243dSDimitry Andric TLI = TLI == nullptr ? &GetTLI(F) : TLI; 6320b57cec5SDimitry Andric for (auto &I : instructions(F)) { 6330b57cec5SDimitry Andric if (CallInst *CI = dyn_cast<CallInst>(&I)) { 6340b57cec5SDimitry Andric if (Function *Callee = CI->getCalledFunction()) { 6350b57cec5SDimitry Andric LibFunc LF; 636d65cd7a5SDimitry Andric if (TLI->getLibFunc(*Callee, LF)) { 637d65cd7a5SDimitry Andric if (LF == LibFunc_fork) { 638d65cd7a5SDimitry Andric #if !defined(_WIN32) 639d65cd7a5SDimitry Andric Forks.push_back(CI); 640d65cd7a5SDimitry Andric #endif 641d65cd7a5SDimitry Andric } else if (LF == LibFunc_execl || LF == LibFunc_execle || 642d65cd7a5SDimitry Andric LF == LibFunc_execlp || LF == LibFunc_execv || 643d65cd7a5SDimitry Andric LF == LibFunc_execvp || LF == LibFunc_execve || 644d65cd7a5SDimitry Andric LF == LibFunc_execvpe || LF == LibFunc_execvP) { 645d65cd7a5SDimitry Andric Execs.push_back(CI); 646d65cd7a5SDimitry Andric } 6470b57cec5SDimitry Andric } 6480b57cec5SDimitry Andric } 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric } 6510b57cec5SDimitry Andric } 6520b57cec5SDimitry Andric 653bdd1243dSDimitry Andric for (auto *F : Forks) { 654d65cd7a5SDimitry Andric IRBuilder<> Builder(F); 655d65cd7a5SDimitry Andric BasicBlock *Parent = F->getParent(); 656d65cd7a5SDimitry Andric auto NextInst = ++F->getIterator(); 657d65cd7a5SDimitry Andric 658d65cd7a5SDimitry Andric // We've a fork so just reset the counters in the child process 659d65cd7a5SDimitry Andric FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false); 660bdd1243dSDimitry Andric FunctionCallee GCOVFork = M->getOrInsertFunction( 661bdd1243dSDimitry Andric "__gcov_fork", FTy, 662bdd1243dSDimitry Andric TLI->getAttrList(Ctx, {}, /*Signed=*/true, /*Ret=*/true)); 663d65cd7a5SDimitry Andric F->setCalledFunction(GCOVFork); 664d65cd7a5SDimitry Andric 665d65cd7a5SDimitry Andric // We split just after the fork to have a counter for the lines after 666d65cd7a5SDimitry Andric // Anyway there's a bug: 667d65cd7a5SDimitry Andric // void foo() { fork(); } 668d65cd7a5SDimitry Andric // void bar() { foo(); blah(); } 669d65cd7a5SDimitry Andric // then "blah();" will be called 2 times but showed as 1 670d65cd7a5SDimitry Andric // because "blah()" belongs to the same block as "foo();" 671d65cd7a5SDimitry Andric Parent->splitBasicBlock(NextInst); 672d65cd7a5SDimitry Andric 673d65cd7a5SDimitry Andric // back() is a br instruction with a debug location 674d65cd7a5SDimitry Andric // equals to the one from NextAfterFork 675d65cd7a5SDimitry Andric // So to avoid to have two debug locs on two blocks just change it 676d65cd7a5SDimitry Andric DebugLoc Loc = F->getDebugLoc(); 677d65cd7a5SDimitry Andric Parent->back().setDebugLoc(Loc); 678d65cd7a5SDimitry Andric } 679d65cd7a5SDimitry Andric 680bdd1243dSDimitry Andric for (auto *E : Execs) { 681d65cd7a5SDimitry Andric IRBuilder<> Builder(E); 682d65cd7a5SDimitry Andric BasicBlock *Parent = E->getParent(); 683d65cd7a5SDimitry Andric auto NextInst = ++E->getIterator(); 684d65cd7a5SDimitry Andric 685d65cd7a5SDimitry Andric // Since the process is replaced by a new one we need to write out gcdas 686d65cd7a5SDimitry Andric // No need to reset the counters since they'll be lost after the exec** 6870b57cec5SDimitry Andric FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); 688d65cd7a5SDimitry Andric FunctionCallee WriteoutF = 689d65cd7a5SDimitry Andric M->getOrInsertFunction("llvm_writeout_files", FTy); 690d65cd7a5SDimitry Andric Builder.CreateCall(WriteoutF); 691d65cd7a5SDimitry Andric 692d65cd7a5SDimitry Andric DebugLoc Loc = E->getDebugLoc(); 693d65cd7a5SDimitry Andric Builder.SetInsertPoint(&*NextInst); 694d65cd7a5SDimitry Andric // If the exec** fails we must reset the counters since they've been 695d65cd7a5SDimitry Andric // dumped 696d65cd7a5SDimitry Andric FunctionCallee ResetF = M->getOrInsertFunction("llvm_reset_counters", FTy); 697d65cd7a5SDimitry Andric Builder.CreateCall(ResetF)->setDebugLoc(Loc); 698e8d8bef9SDimitry Andric ExecBlocks.insert(Parent); 699d65cd7a5SDimitry Andric Parent->splitBasicBlock(NextInst); 700d65cd7a5SDimitry Andric Parent->back().setDebugLoc(Loc); 7010b57cec5SDimitry Andric } 7025ffd83dbSDimitry Andric 7035ffd83dbSDimitry Andric return !Forks.empty() || !Execs.empty(); 7040b57cec5SDimitry Andric } 7050b57cec5SDimitry Andric 706e8d8bef9SDimitry Andric static BasicBlock *getInstrBB(CFGMST<Edge, BBInfo> &MST, Edge &E, 707e8d8bef9SDimitry Andric const DenseSet<const BasicBlock *> &ExecBlocks) { 708e8d8bef9SDimitry Andric if (E.InMST || E.Removed) 709e8d8bef9SDimitry Andric return nullptr; 7100b57cec5SDimitry Andric 711e8d8bef9SDimitry Andric BasicBlock *SrcBB = const_cast<BasicBlock *>(E.SrcBB); 712e8d8bef9SDimitry Andric BasicBlock *DestBB = const_cast<BasicBlock *>(E.DestBB); 713e8d8bef9SDimitry Andric // For a fake edge, instrument the real BB. 714e8d8bef9SDimitry Andric if (SrcBB == nullptr) 715e8d8bef9SDimitry Andric return DestBB; 716e8d8bef9SDimitry Andric if (DestBB == nullptr) 717e8d8bef9SDimitry Andric return SrcBB; 718e8d8bef9SDimitry Andric 719e8d8bef9SDimitry Andric auto CanInstrument = [](BasicBlock *BB) -> BasicBlock * { 720e8d8bef9SDimitry Andric // There are basic blocks (such as catchswitch) cannot be instrumented. 721e8d8bef9SDimitry Andric // If the returned first insertion point is the end of BB, skip this BB. 722e8d8bef9SDimitry Andric if (BB->getFirstInsertionPt() == BB->end()) 723e8d8bef9SDimitry Andric return nullptr; 724e8d8bef9SDimitry Andric return BB; 725e8d8bef9SDimitry Andric }; 726e8d8bef9SDimitry Andric 727e8d8bef9SDimitry Andric // Instrument the SrcBB if it has a single successor, 728e8d8bef9SDimitry Andric // otherwise, the DestBB if this is not a critical edge. 729e8d8bef9SDimitry Andric Instruction *TI = SrcBB->getTerminator(); 730e8d8bef9SDimitry Andric if (TI->getNumSuccessors() <= 1 && !ExecBlocks.count(SrcBB)) 731e8d8bef9SDimitry Andric return CanInstrument(SrcBB); 732e8d8bef9SDimitry Andric if (!E.IsCritical) 733e8d8bef9SDimitry Andric return CanInstrument(DestBB); 734e8d8bef9SDimitry Andric 735e8d8bef9SDimitry Andric // Some IndirectBr critical edges cannot be split by the previous 736e8d8bef9SDimitry Andric // SplitIndirectBrCriticalEdges call. Bail out. 737e8d8bef9SDimitry Andric const unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB); 738e8d8bef9SDimitry Andric BasicBlock *InstrBB = 739e8d8bef9SDimitry Andric isa<IndirectBrInst>(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum); 740e8d8bef9SDimitry Andric if (!InstrBB) 741e8d8bef9SDimitry Andric return nullptr; 742e8d8bef9SDimitry Andric 743e8d8bef9SDimitry Andric MST.addEdge(SrcBB, InstrBB, 0); 744e8d8bef9SDimitry Andric MST.addEdge(InstrBB, DestBB, 0).InMST = true; 745e8d8bef9SDimitry Andric E.Removed = true; 746e8d8bef9SDimitry Andric 747e8d8bef9SDimitry Andric return CanInstrument(InstrBB); 748e8d8bef9SDimitry Andric } 749e8d8bef9SDimitry Andric 750e8d8bef9SDimitry Andric #ifndef NDEBUG 751e8d8bef9SDimitry Andric static void dumpEdges(CFGMST<Edge, BBInfo> &MST, GCOVFunction &GF) { 752e8d8bef9SDimitry Andric size_t ID = 0; 7535f757f3fSDimitry Andric for (const auto &E : make_pointee_range(MST.allEdges())) { 754e8d8bef9SDimitry Andric GCOVBlock &Src = E.SrcBB ? GF.getBlock(E.SrcBB) : GF.getEntryBlock(); 755e8d8bef9SDimitry Andric GCOVBlock &Dst = E.DestBB ? GF.getBlock(E.DestBB) : GF.getReturnBlock(); 756e8d8bef9SDimitry Andric dbgs() << " Edge " << ID++ << ": " << Src.Number << "->" << Dst.Number 757e8d8bef9SDimitry Andric << E.infoString() << "\n"; 758e8d8bef9SDimitry Andric } 759e8d8bef9SDimitry Andric } 760e8d8bef9SDimitry Andric #endif 761e8d8bef9SDimitry Andric 762e8d8bef9SDimitry Andric bool GCOVProfiler::emitProfileNotes( 763e8d8bef9SDimitry Andric NamedMDNode *CUNode, bool HasExecOrFork, 764e8d8bef9SDimitry Andric function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, 765e8d8bef9SDimitry Andric function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, 766e8d8bef9SDimitry Andric function_ref<const TargetLibraryInfo &(Function &F)> GetTLI) { 7675ffd83dbSDimitry Andric int Version; 7685ffd83dbSDimitry Andric { 7695ffd83dbSDimitry Andric uint8_t c3 = Options.Version[0]; 7705ffd83dbSDimitry Andric uint8_t c2 = Options.Version[1]; 7715ffd83dbSDimitry Andric uint8_t c1 = Options.Version[2]; 7725ffd83dbSDimitry Andric Version = c3 >= 'A' ? (c3 - 'A') * 100 + (c2 - '0') * 10 + c1 - '0' 7735ffd83dbSDimitry Andric : (c3 - '0') * 10 + c1 - '0'; 7745ffd83dbSDimitry Andric } 7755ffd83dbSDimitry Andric 776e8d8bef9SDimitry Andric bool EmitGCDA = Options.EmitData; 777e8d8bef9SDimitry Andric for (unsigned i = 0, e = CUNode->getNumOperands(); i != e; ++i) { 7780b57cec5SDimitry Andric // Each compile unit gets its own .gcno file. This means that whether we run 7790b57cec5SDimitry Andric // this pass over the original .o's as they're produced, or run it after 7800b57cec5SDimitry Andric // LTO, we'll generate the same .gcno files. 7810b57cec5SDimitry Andric 782e8d8bef9SDimitry Andric auto *CU = cast<DICompileUnit>(CUNode->getOperand(i)); 7830b57cec5SDimitry Andric 7840b57cec5SDimitry Andric // Skip module skeleton (and module) CUs. 7850b57cec5SDimitry Andric if (CU->getDWOId()) 7860b57cec5SDimitry Andric continue; 7870b57cec5SDimitry Andric 788e8d8bef9SDimitry Andric std::vector<uint8_t> EdgeDestinations; 789e8d8bef9SDimitry Andric SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; 7900b57cec5SDimitry Andric 7915f757f3fSDimitry Andric Endian = M->getDataLayout().isLittleEndian() ? llvm::endianness::little 7925f757f3fSDimitry Andric : llvm::endianness::big; 7930b57cec5SDimitry Andric unsigned FunctionIdent = 0; 7940b57cec5SDimitry Andric for (auto &F : M->functions()) { 7950b57cec5SDimitry Andric DISubprogram *SP = F.getSubprogram(); 7965ffd83dbSDimitry Andric unsigned EndLine; 7970b57cec5SDimitry Andric if (!SP) continue; 7985ffd83dbSDimitry Andric if (!functionHasLines(F, EndLine) || !isFunctionInstrumented(F)) 7990b57cec5SDimitry Andric continue; 8000b57cec5SDimitry Andric // TODO: Functions using scope-based EH are currently not supported. 8010b57cec5SDimitry Andric if (isUsingScopeBasedEH(F)) continue; 802fe6060f1SDimitry Andric if (F.hasFnAttribute(llvm::Attribute::NoProfile)) 803fe6060f1SDimitry Andric continue; 804bdd1243dSDimitry Andric if (F.hasFnAttribute(llvm::Attribute::SkipProfile)) 805bdd1243dSDimitry Andric continue; 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric // Add the function line number to the lines of the entry block 8080b57cec5SDimitry Andric // to have a counter for the function definition. 8090b57cec5SDimitry Andric uint32_t Line = SP->getLine(); 8100b57cec5SDimitry Andric auto Filename = getFilename(SP); 811480093f4SDimitry Andric 812e8d8bef9SDimitry Andric BranchProbabilityInfo *BPI = GetBPI(F); 813e8d8bef9SDimitry Andric BlockFrequencyInfo *BFI = GetBFI(F); 814e8d8bef9SDimitry Andric 815e8d8bef9SDimitry Andric // Split indirectbr critical edges here before computing the MST rather 816e8d8bef9SDimitry Andric // than later in getInstrBB() to avoid invalidating it. 81781ad6265SDimitry Andric SplitIndirectBrCriticalEdges(F, /*IgnoreBlocksWithoutPHI=*/false, BPI, 81881ad6265SDimitry Andric BFI); 819e8d8bef9SDimitry Andric 820e8d8bef9SDimitry Andric CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry_=*/false, BPI, BFI); 821e8d8bef9SDimitry Andric 822e8d8bef9SDimitry Andric // getInstrBB can split basic blocks and push elements to AllEdges. 8235f757f3fSDimitry Andric for (size_t I : llvm::seq<size_t>(0, MST.numEdges())) { 8245f757f3fSDimitry Andric auto &E = *MST.allEdges()[I]; 825e8d8bef9SDimitry Andric // For now, disable spanning tree optimization when fork or exec* is 826e8d8bef9SDimitry Andric // used. 827e8d8bef9SDimitry Andric if (HasExecOrFork) 828e8d8bef9SDimitry Andric E.InMST = false; 829e8d8bef9SDimitry Andric E.Place = getInstrBB(MST, E, ExecBlocks); 830e8d8bef9SDimitry Andric } 831e8d8bef9SDimitry Andric // Basic blocks in F are finalized at this point. 832e8d8bef9SDimitry Andric BasicBlock &EntryBlock = F.getEntryBlock(); 833e8d8bef9SDimitry Andric Funcs.push_back(std::make_unique<GCOVFunction>(this, &F, SP, EndLine, 834e8d8bef9SDimitry Andric FunctionIdent++, Version)); 835e8d8bef9SDimitry Andric GCOVFunction &Func = *Funcs.back(); 836e8d8bef9SDimitry Andric 837e8d8bef9SDimitry Andric // Some non-tree edges are IndirectBr which cannot be split. Ignore them 838e8d8bef9SDimitry Andric // as well. 8395f757f3fSDimitry Andric llvm::erase_if(MST.allEdges(), [](std::unique_ptr<Edge> &E) { 840e8d8bef9SDimitry Andric return E->Removed || (!E->InMST && !E->Place); 841e8d8bef9SDimitry Andric }); 842e8d8bef9SDimitry Andric const size_t Measured = 843e8d8bef9SDimitry Andric std::stable_partition( 8445f757f3fSDimitry Andric MST.allEdges().begin(), MST.allEdges().end(), 845e8d8bef9SDimitry Andric [](std::unique_ptr<Edge> &E) { return E->Place; }) - 8465f757f3fSDimitry Andric MST.allEdges().begin(); 847e8d8bef9SDimitry Andric for (size_t I : llvm::seq<size_t>(0, Measured)) { 8485f757f3fSDimitry Andric Edge &E = *MST.allEdges()[I]; 849e8d8bef9SDimitry Andric GCOVBlock &Src = 850e8d8bef9SDimitry Andric E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); 851e8d8bef9SDimitry Andric GCOVBlock &Dst = 852e8d8bef9SDimitry Andric E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); 853e8d8bef9SDimitry Andric E.SrcNumber = Src.Number; 854e8d8bef9SDimitry Andric E.DstNumber = Dst.Number; 855e8d8bef9SDimitry Andric } 856e8d8bef9SDimitry Andric std::stable_sort( 8575f757f3fSDimitry Andric MST.allEdges().begin(), MST.allEdges().begin() + Measured, 858e8d8bef9SDimitry Andric [](const std::unique_ptr<Edge> &L, const std::unique_ptr<Edge> &R) { 859e8d8bef9SDimitry Andric return L->SrcNumber != R->SrcNumber ? L->SrcNumber < R->SrcNumber 860e8d8bef9SDimitry Andric : L->DstNumber < R->DstNumber; 861e8d8bef9SDimitry Andric }); 862e8d8bef9SDimitry Andric 8635f757f3fSDimitry Andric for (const Edge &E : make_pointee_range(MST.allEdges())) { 864e8d8bef9SDimitry Andric GCOVBlock &Src = 865e8d8bef9SDimitry Andric E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); 866e8d8bef9SDimitry Andric GCOVBlock &Dst = 867e8d8bef9SDimitry Andric E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); 868e8d8bef9SDimitry Andric Src.addEdge(Dst, E.Place ? 0 : uint32_t(GCOV_ARC_ON_TREE)); 869e8d8bef9SDimitry Andric } 870e8d8bef9SDimitry Andric 871480093f4SDimitry Andric // Artificial functions such as global initializers 872480093f4SDimitry Andric if (!SP->isArtificial()) 8730b57cec5SDimitry Andric Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line); 8740b57cec5SDimitry Andric 875e8d8bef9SDimitry Andric LLVM_DEBUG(dumpEdges(MST, Func)); 876e8d8bef9SDimitry Andric 877e8d8bef9SDimitry Andric for (auto &GB : Func.Blocks) { 878e8d8bef9SDimitry Andric const BasicBlock &BB = *GB.first; 879e8d8bef9SDimitry Andric auto &Block = GB.second; 880e8d8bef9SDimitry Andric for (auto Succ : Block.OutEdges) { 881e8d8bef9SDimitry Andric uint32_t Idx = Succ.first->Number; 882e8d8bef9SDimitry Andric do EdgeDestinations.push_back(Idx & 255); 883e8d8bef9SDimitry Andric while ((Idx >>= 8) > 0); 8840b57cec5SDimitry Andric } 8850b57cec5SDimitry Andric 886bdd1243dSDimitry Andric for (const auto &I : BB) { 8870b57cec5SDimitry Andric // Debug intrinsic locations correspond to the location of the 8880b57cec5SDimitry Andric // declaration, not necessarily any statements or expressions. 8890b57cec5SDimitry Andric if (isa<DbgInfoIntrinsic>(&I)) continue; 8900b57cec5SDimitry Andric 8910b57cec5SDimitry Andric const DebugLoc &Loc = I.getDebugLoc(); 8920b57cec5SDimitry Andric if (!Loc) 8930b57cec5SDimitry Andric continue; 8940b57cec5SDimitry Andric 8950b57cec5SDimitry Andric // Artificial lines such as calls to the global constructors. 8960b57cec5SDimitry Andric if (Loc.getLine() == 0 || Loc.isImplicitCode()) 8970b57cec5SDimitry Andric continue; 8980b57cec5SDimitry Andric 8990b57cec5SDimitry Andric if (Line == Loc.getLine()) continue; 9000b57cec5SDimitry Andric Line = Loc.getLine(); 9018a4dda33SDimitry Andric MDNode *Scope = Loc.getScope(); 9028a4dda33SDimitry Andric // TODO: Handle blocks from another file due to #line, #include, etc. 9038a4dda33SDimitry Andric if (isa<DILexicalBlockFile>(Scope) || SP != getDISubprogram(Scope)) 9040b57cec5SDimitry Andric continue; 9050b57cec5SDimitry Andric 9060b57cec5SDimitry Andric GCOVLines &Lines = Block.getFile(Filename); 9070b57cec5SDimitry Andric Lines.addLine(Loc.getLine()); 9080b57cec5SDimitry Andric } 9090b57cec5SDimitry Andric Line = 0; 9100b57cec5SDimitry Andric } 911e8d8bef9SDimitry Andric if (EmitGCDA) { 912e8d8bef9SDimitry Andric DISubprogram *SP = F.getSubprogram(); 913e8d8bef9SDimitry Andric ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Measured); 914e8d8bef9SDimitry Andric GlobalVariable *Counters = new GlobalVariable( 915e8d8bef9SDimitry Andric *M, CounterTy, false, GlobalValue::InternalLinkage, 916e8d8bef9SDimitry Andric Constant::getNullValue(CounterTy), "__llvm_gcov_ctr"); 917e8d8bef9SDimitry Andric CountersBySP.emplace_back(Counters, SP); 918e8d8bef9SDimitry Andric 919e8d8bef9SDimitry Andric for (size_t I : llvm::seq<size_t>(0, Measured)) { 9205f757f3fSDimitry Andric const Edge &E = *MST.allEdges()[I]; 921e8d8bef9SDimitry Andric IRBuilder<> Builder(E.Place, E.Place->getFirstInsertionPt()); 922e8d8bef9SDimitry Andric Value *V = Builder.CreateConstInBoundsGEP2_64( 923e8d8bef9SDimitry Andric Counters->getValueType(), Counters, 0, I); 92406c3fb27SDimitry Andric // Disable sanitizers to decrease size bloat. We don't expect 92506c3fb27SDimitry Andric // sanitizers to catch interesting issues. 92606c3fb27SDimitry Andric Instruction *Inst; 927e8d8bef9SDimitry Andric if (Options.Atomic) { 92806c3fb27SDimitry Andric Inst = Builder.CreateAtomicRMW(AtomicRMWInst::Add, V, 92906c3fb27SDimitry Andric Builder.getInt64(1), MaybeAlign(), 93006c3fb27SDimitry Andric AtomicOrdering::Monotonic); 931e8d8bef9SDimitry Andric } else { 93206c3fb27SDimitry Andric LoadInst *OldCount = 933e8d8bef9SDimitry Andric Builder.CreateLoad(Builder.getInt64Ty(), V, "gcov_ctr"); 93406c3fb27SDimitry Andric OldCount->setNoSanitizeMetadata(); 93506c3fb27SDimitry Andric Value *NewCount = Builder.CreateAdd(OldCount, Builder.getInt64(1)); 93606c3fb27SDimitry Andric Inst = Builder.CreateStore(NewCount, V); 937e8d8bef9SDimitry Andric } 93806c3fb27SDimitry Andric Inst->setNoSanitizeMetadata(); 939e8d8bef9SDimitry Andric } 940e8d8bef9SDimitry Andric } 9410b57cec5SDimitry Andric } 9420b57cec5SDimitry Andric 9435ffd83dbSDimitry Andric char Tmp[4]; 944e8d8bef9SDimitry Andric JamCRC JC; 945e8d8bef9SDimitry Andric JC.update(EdgeDestinations); 946e8d8bef9SDimitry Andric uint32_t Stamp = JC.getCRC(); 9475ffd83dbSDimitry Andric FileChecksums.push_back(Stamp); 948e8d8bef9SDimitry Andric 949e8d8bef9SDimitry Andric if (Options.EmitNotes) { 950e8d8bef9SDimitry Andric std::error_code EC; 951e8d8bef9SDimitry Andric raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, 952e8d8bef9SDimitry Andric sys::fs::OF_None); 953e8d8bef9SDimitry Andric if (EC) { 954e8d8bef9SDimitry Andric Ctx->emitError( 955e8d8bef9SDimitry Andric Twine("failed to open coverage notes file for writing: ") + 956e8d8bef9SDimitry Andric EC.message()); 957e8d8bef9SDimitry Andric continue; 958e8d8bef9SDimitry Andric } 959e8d8bef9SDimitry Andric os = &out; 9605f757f3fSDimitry Andric if (Endian == llvm::endianness::big) { 9615ffd83dbSDimitry Andric out.write("gcno", 4); 9625ffd83dbSDimitry Andric out.write(Options.Version, 4); 9635ffd83dbSDimitry Andric } else { 9640b57cec5SDimitry Andric out.write("oncg", 4); 9655ffd83dbSDimitry Andric std::reverse_copy(Options.Version, Options.Version + 4, Tmp); 9665ffd83dbSDimitry Andric out.write(Tmp, 4); 9670b57cec5SDimitry Andric } 9685ffd83dbSDimitry Andric write(Stamp); 9695ffd83dbSDimitry Andric if (Version >= 90) 9705ffd83dbSDimitry Andric writeString(""); // unuseful current_working_directory 9715ffd83dbSDimitry Andric if (Version >= 80) 9725ffd83dbSDimitry Andric write(0); // unuseful has_unexecuted_blocks 9730b57cec5SDimitry Andric 9745ffd83dbSDimitry Andric for (auto &Func : Funcs) 9755ffd83dbSDimitry Andric Func->writeOut(Stamp); 9765ffd83dbSDimitry Andric 9775ffd83dbSDimitry Andric write(0); 9785ffd83dbSDimitry Andric write(0); 9790b57cec5SDimitry Andric out.close(); 9800b57cec5SDimitry Andric } 981e8d8bef9SDimitry Andric 982e8d8bef9SDimitry Andric if (EmitGCDA) { 983e8d8bef9SDimitry Andric emitGlobalConstructor(CountersBySP); 984e8d8bef9SDimitry Andric EmitGCDA = false; 985e8d8bef9SDimitry Andric } 986e8d8bef9SDimitry Andric } 987e8d8bef9SDimitry Andric return true; 9880b57cec5SDimitry Andric } 9890b57cec5SDimitry Andric 990fe6060f1SDimitry Andric Function *GCOVProfiler::createInternalFunction(FunctionType *FTy, 991bdd1243dSDimitry Andric StringRef Name, 992bdd1243dSDimitry Andric StringRef MangledType /*=""*/) { 993fe6060f1SDimitry Andric Function *F = Function::createWithDefaultAttr( 994fe6060f1SDimitry Andric FTy, GlobalValue::InternalLinkage, 0, Name, M); 995fe6060f1SDimitry Andric F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 996fe6060f1SDimitry Andric F->addFnAttr(Attribute::NoUnwind); 997fe6060f1SDimitry Andric if (Options.NoRedZone) 998fe6060f1SDimitry Andric F->addFnAttr(Attribute::NoRedZone); 999bdd1243dSDimitry Andric if (!MangledType.empty()) 1000bdd1243dSDimitry Andric setKCFIType(*M, *F, MangledType); 1001fe6060f1SDimitry Andric return F; 1002fe6060f1SDimitry Andric } 1003fe6060f1SDimitry Andric 1004e8d8bef9SDimitry Andric void GCOVProfiler::emitGlobalConstructor( 1005e8d8bef9SDimitry Andric SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) { 10060b57cec5SDimitry Andric Function *WriteoutF = insertCounterWriteout(CountersBySP); 1007d65cd7a5SDimitry Andric Function *ResetF = insertReset(CountersBySP); 10080b57cec5SDimitry Andric 10090b57cec5SDimitry Andric // Create a small bit of code that registers the "__llvm_gcov_writeout" to 1010fe6060f1SDimitry Andric // be executed at exit and the "__llvm_gcov_reset" function to be executed 10110b57cec5SDimitry Andric // when "__gcov_flush" is called. 10120b57cec5SDimitry Andric FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 1013bdd1243dSDimitry Andric Function *F = createInternalFunction(FTy, "__llvm_gcov_init", "_ZTSFvvE"); 10140b57cec5SDimitry Andric F->addFnAttr(Attribute::NoInline); 10150b57cec5SDimitry Andric 10160b57cec5SDimitry Andric BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); 10170b57cec5SDimitry Andric IRBuilder<> Builder(BB); 10180b57cec5SDimitry Andric 10190b57cec5SDimitry Andric FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 1020e8d8bef9SDimitry Andric auto *PFTy = PointerType::get(FTy, 0); 1021e8d8bef9SDimitry Andric FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false); 10220b57cec5SDimitry Andric 1023d65cd7a5SDimitry Andric // Initialize the environment and register the local writeout, flush and 1024d65cd7a5SDimitry Andric // reset functions. 10250b57cec5SDimitry Andric FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); 1026e8d8bef9SDimitry Andric Builder.CreateCall(GCOVInit, {WriteoutF, ResetF}); 10270b57cec5SDimitry Andric Builder.CreateRetVoid(); 10280b57cec5SDimitry Andric 10290b57cec5SDimitry Andric appendToGlobalCtors(*M, F, 0); 10300b57cec5SDimitry Andric } 10310b57cec5SDimitry Andric 10328bcb0991SDimitry Andric FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) { 10330b57cec5SDimitry Andric Type *Args[] = { 10345f757f3fSDimitry Andric PointerType::getUnqual(*Ctx), // const char *orig_filename 10355ffd83dbSDimitry Andric Type::getInt32Ty(*Ctx), // uint32_t version 10360b57cec5SDimitry Andric Type::getInt32Ty(*Ctx), // uint32_t checksum 10370b57cec5SDimitry Andric }; 10380b57cec5SDimitry Andric FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 1039bdd1243dSDimitry Andric return M->getOrInsertFunction("llvm_gcda_start_file", FTy, 1040bdd1243dSDimitry Andric TLI->getAttrList(Ctx, {1, 2}, /*Signed=*/false)); 10410b57cec5SDimitry Andric } 10420b57cec5SDimitry Andric 10438bcb0991SDimitry Andric FunctionCallee GCOVProfiler::getEmitFunctionFunc(const TargetLibraryInfo *TLI) { 10440b57cec5SDimitry Andric Type *Args[] = { 10450b57cec5SDimitry Andric Type::getInt32Ty(*Ctx), // uint32_t ident 10460b57cec5SDimitry Andric Type::getInt32Ty(*Ctx), // uint32_t func_checksum 10470b57cec5SDimitry Andric Type::getInt32Ty(*Ctx), // uint32_t cfg_checksum 10480b57cec5SDimitry Andric }; 10490b57cec5SDimitry Andric FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 1050bdd1243dSDimitry Andric return M->getOrInsertFunction("llvm_gcda_emit_function", FTy, 1051bdd1243dSDimitry Andric TLI->getAttrList(Ctx, {0, 1, 2}, /*Signed=*/false)); 10520b57cec5SDimitry Andric } 10530b57cec5SDimitry Andric 10548bcb0991SDimitry Andric FunctionCallee GCOVProfiler::getEmitArcsFunc(const TargetLibraryInfo *TLI) { 10550b57cec5SDimitry Andric Type *Args[] = { 10560b57cec5SDimitry Andric Type::getInt32Ty(*Ctx), // uint32_t num_counters 10575f757f3fSDimitry Andric PointerType::getUnqual(*Ctx), // uint64_t *counters 10580b57cec5SDimitry Andric }; 10590b57cec5SDimitry Andric FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 1060bdd1243dSDimitry Andric return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy, 1061bdd1243dSDimitry Andric TLI->getAttrList(Ctx, {0}, /*Signed=*/false)); 10620b57cec5SDimitry Andric } 10630b57cec5SDimitry Andric 10640b57cec5SDimitry Andric FunctionCallee GCOVProfiler::getSummaryInfoFunc() { 10650b57cec5SDimitry Andric FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 10660b57cec5SDimitry Andric return M->getOrInsertFunction("llvm_gcda_summary_info", FTy); 10670b57cec5SDimitry Andric } 10680b57cec5SDimitry Andric 10690b57cec5SDimitry Andric FunctionCallee GCOVProfiler::getEndFileFunc() { 10700b57cec5SDimitry Andric FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 10710b57cec5SDimitry Andric return M->getOrInsertFunction("llvm_gcda_end_file", FTy); 10720b57cec5SDimitry Andric } 10730b57cec5SDimitry Andric 10740b57cec5SDimitry Andric Function *GCOVProfiler::insertCounterWriteout( 10750b57cec5SDimitry Andric ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) { 10760b57cec5SDimitry Andric FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 10770b57cec5SDimitry Andric Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); 10780b57cec5SDimitry Andric if (!WriteoutF) 1079bdd1243dSDimitry Andric WriteoutF = 1080bdd1243dSDimitry Andric createInternalFunction(WriteoutFTy, "__llvm_gcov_writeout", "_ZTSFvvE"); 10810b57cec5SDimitry Andric WriteoutF->addFnAttr(Attribute::NoInline); 10820b57cec5SDimitry Andric 10830b57cec5SDimitry Andric BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF); 10840b57cec5SDimitry Andric IRBuilder<> Builder(BB); 10850b57cec5SDimitry Andric 10868bcb0991SDimitry Andric auto *TLI = &GetTLI(*WriteoutF); 10878bcb0991SDimitry Andric 10888bcb0991SDimitry Andric FunctionCallee StartFile = getStartFileFunc(TLI); 10898bcb0991SDimitry Andric FunctionCallee EmitFunction = getEmitFunctionFunc(TLI); 10908bcb0991SDimitry Andric FunctionCallee EmitArcs = getEmitArcsFunc(TLI); 10910b57cec5SDimitry Andric FunctionCallee SummaryInfo = getSummaryInfoFunc(); 10920b57cec5SDimitry Andric FunctionCallee EndFile = getEndFileFunc(); 10930b57cec5SDimitry Andric 10940b57cec5SDimitry Andric NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu"); 10950b57cec5SDimitry Andric if (!CUNodes) { 10960b57cec5SDimitry Andric Builder.CreateRetVoid(); 10970b57cec5SDimitry Andric return WriteoutF; 10980b57cec5SDimitry Andric } 10990b57cec5SDimitry Andric 11000b57cec5SDimitry Andric // Collect the relevant data into a large constant data structure that we can 11010b57cec5SDimitry Andric // walk to write out everything. 11020b57cec5SDimitry Andric StructType *StartFileCallArgsTy = StructType::create( 11035f757f3fSDimitry Andric {Builder.getPtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()}, 1104e8d8bef9SDimitry Andric "start_file_args_ty"); 11050b57cec5SDimitry Andric StructType *EmitFunctionCallArgsTy = StructType::create( 1106e8d8bef9SDimitry Andric {Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()}, 1107e8d8bef9SDimitry Andric "emit_function_args_ty"); 11085f757f3fSDimitry Andric auto *PtrTy = Builder.getPtrTy(); 11095f757f3fSDimitry Andric StructType *EmitArcsCallArgsTy = 11105f757f3fSDimitry Andric StructType::create({Builder.getInt32Ty(), PtrTy}, "emit_arcs_args_ty"); 11115f757f3fSDimitry Andric StructType *FileInfoTy = StructType::create( 11125f757f3fSDimitry Andric {StartFileCallArgsTy, Builder.getInt32Ty(), PtrTy, PtrTy}, "file_info"); 11130b57cec5SDimitry Andric 11140b57cec5SDimitry Andric Constant *Zero32 = Builder.getInt32(0); 11150b57cec5SDimitry Andric // Build an explicit array of two zeros for use in ConstantExpr GEP building. 11160b57cec5SDimitry Andric Constant *TwoZero32s[] = {Zero32, Zero32}; 11170b57cec5SDimitry Andric 11180b57cec5SDimitry Andric SmallVector<Constant *, 8> FileInfos; 11190b57cec5SDimitry Andric for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) { 11200b57cec5SDimitry Andric auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i)); 11210b57cec5SDimitry Andric 11220b57cec5SDimitry Andric // Skip module skeleton (and module) CUs. 11230b57cec5SDimitry Andric if (CU->getDWOId()) 11240b57cec5SDimitry Andric continue; 11250b57cec5SDimitry Andric 11260b57cec5SDimitry Andric std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA); 11270b57cec5SDimitry Andric uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i]; 11280b57cec5SDimitry Andric auto *StartFileCallArgs = ConstantStruct::get( 11295ffd83dbSDimitry Andric StartFileCallArgsTy, 11305ffd83dbSDimitry Andric {Builder.CreateGlobalStringPtr(FilenameGcda), 11315ffd83dbSDimitry Andric Builder.getInt32(endian::read32be(Options.Version)), 11320b57cec5SDimitry Andric Builder.getInt32(CfgChecksum)}); 11330b57cec5SDimitry Andric 11340b57cec5SDimitry Andric SmallVector<Constant *, 8> EmitFunctionCallArgsArray; 11350b57cec5SDimitry Andric SmallVector<Constant *, 8> EmitArcsCallArgsArray; 11360b57cec5SDimitry Andric for (int j : llvm::seq<int>(0, CountersBySP.size())) { 11370b57cec5SDimitry Andric uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum(); 11380b57cec5SDimitry Andric EmitFunctionCallArgsArray.push_back(ConstantStruct::get( 11390b57cec5SDimitry Andric EmitFunctionCallArgsTy, 11400b57cec5SDimitry Andric {Builder.getInt32(j), 11410b57cec5SDimitry Andric Builder.getInt32(FuncChecksum), 11420b57cec5SDimitry Andric Builder.getInt32(CfgChecksum)})); 11430b57cec5SDimitry Andric 11440b57cec5SDimitry Andric GlobalVariable *GV = CountersBySP[j].first; 11450b57cec5SDimitry Andric unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements(); 11460b57cec5SDimitry Andric EmitArcsCallArgsArray.push_back(ConstantStruct::get( 11470b57cec5SDimitry Andric EmitArcsCallArgsTy, 11480b57cec5SDimitry Andric {Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr( 11490b57cec5SDimitry Andric GV->getValueType(), GV, TwoZero32s)})); 11500b57cec5SDimitry Andric } 11510b57cec5SDimitry Andric // Create global arrays for the two emit calls. 11520b57cec5SDimitry Andric int CountersSize = CountersBySP.size(); 11530b57cec5SDimitry Andric assert(CountersSize == (int)EmitFunctionCallArgsArray.size() && 11540b57cec5SDimitry Andric "Mismatched array size!"); 11550b57cec5SDimitry Andric assert(CountersSize == (int)EmitArcsCallArgsArray.size() && 11560b57cec5SDimitry Andric "Mismatched array size!"); 11570b57cec5SDimitry Andric auto *EmitFunctionCallArgsArrayTy = 11580b57cec5SDimitry Andric ArrayType::get(EmitFunctionCallArgsTy, CountersSize); 11590b57cec5SDimitry Andric auto *EmitFunctionCallArgsArrayGV = new GlobalVariable( 11600b57cec5SDimitry Andric *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true, 11610b57cec5SDimitry Andric GlobalValue::InternalLinkage, 11620b57cec5SDimitry Andric ConstantArray::get(EmitFunctionCallArgsArrayTy, 11630b57cec5SDimitry Andric EmitFunctionCallArgsArray), 11640b57cec5SDimitry Andric Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i)); 11650b57cec5SDimitry Andric auto *EmitArcsCallArgsArrayTy = 11660b57cec5SDimitry Andric ArrayType::get(EmitArcsCallArgsTy, CountersSize); 11670b57cec5SDimitry Andric EmitFunctionCallArgsArrayGV->setUnnamedAddr( 11680b57cec5SDimitry Andric GlobalValue::UnnamedAddr::Global); 11690b57cec5SDimitry Andric auto *EmitArcsCallArgsArrayGV = new GlobalVariable( 11700b57cec5SDimitry Andric *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true, 11710b57cec5SDimitry Andric GlobalValue::InternalLinkage, 11720b57cec5SDimitry Andric ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray), 11730b57cec5SDimitry Andric Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i)); 11740b57cec5SDimitry Andric EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 11750b57cec5SDimitry Andric 11760b57cec5SDimitry Andric FileInfos.push_back(ConstantStruct::get( 11770b57cec5SDimitry Andric FileInfoTy, 11780b57cec5SDimitry Andric {StartFileCallArgs, Builder.getInt32(CountersSize), 11790b57cec5SDimitry Andric ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy, 11800b57cec5SDimitry Andric EmitFunctionCallArgsArrayGV, 11810b57cec5SDimitry Andric TwoZero32s), 11820b57cec5SDimitry Andric ConstantExpr::getInBoundsGetElementPtr( 11830b57cec5SDimitry Andric EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)})); 11840b57cec5SDimitry Andric } 11850b57cec5SDimitry Andric 11860b57cec5SDimitry Andric // If we didn't find anything to actually emit, bail on out. 11870b57cec5SDimitry Andric if (FileInfos.empty()) { 11880b57cec5SDimitry Andric Builder.CreateRetVoid(); 11890b57cec5SDimitry Andric return WriteoutF; 11900b57cec5SDimitry Andric } 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric // To simplify code, we cap the number of file infos we write out to fit 11930b57cec5SDimitry Andric // easily in a 32-bit signed integer. This gives consistent behavior between 11940b57cec5SDimitry Andric // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit 11950b57cec5SDimitry Andric // operations on 32-bit systems. It also seems unreasonable to try to handle 11960b57cec5SDimitry Andric // more than 2 billion files. 11970b57cec5SDimitry Andric if ((int64_t)FileInfos.size() > (int64_t)INT_MAX) 11980b57cec5SDimitry Andric FileInfos.resize(INT_MAX); 11990b57cec5SDimitry Andric 12000b57cec5SDimitry Andric // Create a global for the entire data structure so we can walk it more 12010b57cec5SDimitry Andric // easily. 12020b57cec5SDimitry Andric auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size()); 12030b57cec5SDimitry Andric auto *FileInfoArrayGV = new GlobalVariable( 12040b57cec5SDimitry Andric *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, 12050b57cec5SDimitry Andric ConstantArray::get(FileInfoArrayTy, FileInfos), 12060b57cec5SDimitry Andric "__llvm_internal_gcov_emit_file_info"); 12070b57cec5SDimitry Andric FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 12080b57cec5SDimitry Andric 12090b57cec5SDimitry Andric // Create the CFG for walking this data structure. 12100b57cec5SDimitry Andric auto *FileLoopHeader = 12110b57cec5SDimitry Andric BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF); 12120b57cec5SDimitry Andric auto *CounterLoopHeader = 12130b57cec5SDimitry Andric BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF); 12140b57cec5SDimitry Andric auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF); 12150b57cec5SDimitry Andric auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF); 12160b57cec5SDimitry Andric 12170b57cec5SDimitry Andric // We always have at least one file, so just branch to the header. 12180b57cec5SDimitry Andric Builder.CreateBr(FileLoopHeader); 12190b57cec5SDimitry Andric 12200b57cec5SDimitry Andric // The index into the files structure is our loop induction variable. 12210b57cec5SDimitry Andric Builder.SetInsertPoint(FileLoopHeader); 1222e8d8bef9SDimitry Andric PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, 1223e8d8bef9SDimitry Andric "file_idx"); 12240b57cec5SDimitry Andric IV->addIncoming(Builder.getInt32(0), BB); 12250b57cec5SDimitry Andric auto *FileInfoPtr = Builder.CreateInBoundsGEP( 12260b57cec5SDimitry Andric FileInfoArrayTy, FileInfoArrayGV, {Builder.getInt32(0), IV}); 12270b57cec5SDimitry Andric auto *StartFileCallArgsPtr = 1228e8d8bef9SDimitry Andric Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0, "start_file_args"); 12290b57cec5SDimitry Andric auto *StartFileCall = Builder.CreateCall( 12300b57cec5SDimitry Andric StartFile, 12310b57cec5SDimitry Andric {Builder.CreateLoad(StartFileCallArgsTy->getElementType(0), 12320b57cec5SDimitry Andric Builder.CreateStructGEP(StartFileCallArgsTy, 1233e8d8bef9SDimitry Andric StartFileCallArgsPtr, 0), 1234e8d8bef9SDimitry Andric "filename"), 12350b57cec5SDimitry Andric Builder.CreateLoad(StartFileCallArgsTy->getElementType(1), 12360b57cec5SDimitry Andric Builder.CreateStructGEP(StartFileCallArgsTy, 1237e8d8bef9SDimitry Andric StartFileCallArgsPtr, 1), 1238e8d8bef9SDimitry Andric "version"), 12390b57cec5SDimitry Andric Builder.CreateLoad(StartFileCallArgsTy->getElementType(2), 12400b57cec5SDimitry Andric Builder.CreateStructGEP(StartFileCallArgsTy, 1241e8d8bef9SDimitry Andric StartFileCallArgsPtr, 2), 1242e8d8bef9SDimitry Andric "stamp")}); 12430b57cec5SDimitry Andric if (auto AK = TLI->getExtAttrForI32Param(false)) 12440b57cec5SDimitry Andric StartFileCall->addParamAttr(2, AK); 1245e8d8bef9SDimitry Andric auto *NumCounters = Builder.CreateLoad( 1246e8d8bef9SDimitry Andric FileInfoTy->getElementType(1), 1247e8d8bef9SDimitry Andric Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1), "num_ctrs"); 12480b57cec5SDimitry Andric auto *EmitFunctionCallArgsArray = 12490b57cec5SDimitry Andric Builder.CreateLoad(FileInfoTy->getElementType(2), 1250e8d8bef9SDimitry Andric Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2), 1251e8d8bef9SDimitry Andric "emit_function_args"); 1252e8d8bef9SDimitry Andric auto *EmitArcsCallArgsArray = Builder.CreateLoad( 1253e8d8bef9SDimitry Andric FileInfoTy->getElementType(3), 1254e8d8bef9SDimitry Andric Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3), "emit_arcs_args"); 12550b57cec5SDimitry Andric auto *EnterCounterLoopCond = 12560b57cec5SDimitry Andric Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters); 12570b57cec5SDimitry Andric Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch); 12580b57cec5SDimitry Andric 12590b57cec5SDimitry Andric Builder.SetInsertPoint(CounterLoopHeader); 1260e8d8bef9SDimitry Andric auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, 1261e8d8bef9SDimitry Andric "ctr_idx"); 12620b57cec5SDimitry Andric JV->addIncoming(Builder.getInt32(0), FileLoopHeader); 12630b57cec5SDimitry Andric auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP( 12640b57cec5SDimitry Andric EmitFunctionCallArgsTy, EmitFunctionCallArgsArray, JV); 12650b57cec5SDimitry Andric auto *EmitFunctionCall = Builder.CreateCall( 12660b57cec5SDimitry Andric EmitFunction, 12670b57cec5SDimitry Andric {Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(0), 12680b57cec5SDimitry Andric Builder.CreateStructGEP(EmitFunctionCallArgsTy, 1269e8d8bef9SDimitry Andric EmitFunctionCallArgsPtr, 0), 1270e8d8bef9SDimitry Andric "ident"), 12710b57cec5SDimitry Andric Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(1), 12720b57cec5SDimitry Andric Builder.CreateStructGEP(EmitFunctionCallArgsTy, 1273e8d8bef9SDimitry Andric EmitFunctionCallArgsPtr, 1), 1274e8d8bef9SDimitry Andric "func_checkssum"), 12750b57cec5SDimitry Andric Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(2), 12760b57cec5SDimitry Andric Builder.CreateStructGEP(EmitFunctionCallArgsTy, 1277e8d8bef9SDimitry Andric EmitFunctionCallArgsPtr, 2), 1278e8d8bef9SDimitry Andric "cfg_checksum")}); 12790b57cec5SDimitry Andric if (auto AK = TLI->getExtAttrForI32Param(false)) { 12800b57cec5SDimitry Andric EmitFunctionCall->addParamAttr(0, AK); 12815ffd83dbSDimitry Andric EmitFunctionCall->addParamAttr(1, AK); 12820b57cec5SDimitry Andric EmitFunctionCall->addParamAttr(2, AK); 12830b57cec5SDimitry Andric } 12840b57cec5SDimitry Andric auto *EmitArcsCallArgsPtr = 12850b57cec5SDimitry Andric Builder.CreateInBoundsGEP(EmitArcsCallArgsTy, EmitArcsCallArgsArray, JV); 12860b57cec5SDimitry Andric auto *EmitArcsCall = Builder.CreateCall( 12870b57cec5SDimitry Andric EmitArcs, 12880b57cec5SDimitry Andric {Builder.CreateLoad( 12890b57cec5SDimitry Andric EmitArcsCallArgsTy->getElementType(0), 1290e8d8bef9SDimitry Andric Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0), 1291e8d8bef9SDimitry Andric "num_counters"), 1292e8d8bef9SDimitry Andric Builder.CreateLoad( 1293e8d8bef9SDimitry Andric EmitArcsCallArgsTy->getElementType(1), 1294e8d8bef9SDimitry Andric Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 1), 1295e8d8bef9SDimitry Andric "counters")}); 12960b57cec5SDimitry Andric if (auto AK = TLI->getExtAttrForI32Param(false)) 12970b57cec5SDimitry Andric EmitArcsCall->addParamAttr(0, AK); 12980b57cec5SDimitry Andric auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1)); 12990b57cec5SDimitry Andric auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters); 13000b57cec5SDimitry Andric Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch); 13010b57cec5SDimitry Andric JV->addIncoming(NextJV, CounterLoopHeader); 13020b57cec5SDimitry Andric 13030b57cec5SDimitry Andric Builder.SetInsertPoint(FileLoopLatch); 13040b57cec5SDimitry Andric Builder.CreateCall(SummaryInfo, {}); 13050b57cec5SDimitry Andric Builder.CreateCall(EndFile, {}); 1306e8d8bef9SDimitry Andric auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1), "next_file_idx"); 13070b57cec5SDimitry Andric auto *FileLoopCond = 13080b57cec5SDimitry Andric Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size())); 13090b57cec5SDimitry Andric Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB); 13100b57cec5SDimitry Andric IV->addIncoming(NextIV, FileLoopLatch); 13110b57cec5SDimitry Andric 13120b57cec5SDimitry Andric Builder.SetInsertPoint(ExitBB); 13130b57cec5SDimitry Andric Builder.CreateRetVoid(); 13140b57cec5SDimitry Andric 13150b57cec5SDimitry Andric return WriteoutF; 13160b57cec5SDimitry Andric } 13170b57cec5SDimitry Andric 1318d65cd7a5SDimitry Andric Function *GCOVProfiler::insertReset( 1319d65cd7a5SDimitry Andric ArrayRef<std::pair<GlobalVariable *, MDNode *>> CountersBySP) { 1320d65cd7a5SDimitry Andric FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 1321d65cd7a5SDimitry Andric Function *ResetF = M->getFunction("__llvm_gcov_reset"); 1322d65cd7a5SDimitry Andric if (!ResetF) 1323bdd1243dSDimitry Andric ResetF = createInternalFunction(FTy, "__llvm_gcov_reset", "_ZTSFvvE"); 1324d65cd7a5SDimitry Andric ResetF->addFnAttr(Attribute::NoInline); 1325d65cd7a5SDimitry Andric 1326d65cd7a5SDimitry Andric BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", ResetF); 1327d65cd7a5SDimitry Andric IRBuilder<> Builder(Entry); 1328349cc55cSDimitry Andric LLVMContext &C = Entry->getContext(); 1329d65cd7a5SDimitry Andric 1330d65cd7a5SDimitry Andric // Zero out the counters. 1331d65cd7a5SDimitry Andric for (const auto &I : CountersBySP) { 1332d65cd7a5SDimitry Andric GlobalVariable *GV = I.first; 1333349cc55cSDimitry Andric auto *GVTy = cast<ArrayType>(GV->getValueType()); 1334349cc55cSDimitry Andric Builder.CreateMemSet(GV, Constant::getNullValue(Type::getInt8Ty(C)), 1335349cc55cSDimitry Andric GVTy->getNumElements() * 1336349cc55cSDimitry Andric GVTy->getElementType()->getScalarSizeInBits() / 8, 1337349cc55cSDimitry Andric GV->getAlign()); 1338d65cd7a5SDimitry Andric } 1339d65cd7a5SDimitry Andric 1340d65cd7a5SDimitry Andric Type *RetTy = ResetF->getReturnType(); 1341d65cd7a5SDimitry Andric if (RetTy->isVoidTy()) 1342d65cd7a5SDimitry Andric Builder.CreateRetVoid(); 1343d65cd7a5SDimitry Andric else if (RetTy->isIntegerTy()) 1344d65cd7a5SDimitry Andric // Used if __llvm_gcov_reset was implicitly declared. 1345d65cd7a5SDimitry Andric Builder.CreateRet(ConstantInt::get(RetTy, 0)); 1346d65cd7a5SDimitry Andric else 1347d65cd7a5SDimitry Andric report_fatal_error("invalid return type for __llvm_gcov_reset"); 1348d65cd7a5SDimitry Andric 1349d65cd7a5SDimitry Andric return ResetF; 1350d65cd7a5SDimitry Andric } 1351