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.
wordsOfString(StringRef s)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
getDefault()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:
GCOVProfiler()950b57cec5SDimitry Andric GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {}
GCOVProfiler(const GCOVOptions & Opts)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
write(uint32_t i)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 }
writeString(StringRef s)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 }
writeBytes(const char * Bytes,int Size)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
BBInfo__anon755d56fc0211::BBInfo172e8d8bef9SDimitry Andric BBInfo(unsigned Index) : Group(this), Index(Index) {}
infoString__anon755d56fc0211::BBInfo173fe6060f1SDimitry 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
Edge__anon755d56fc0211::Edge190e8d8bef9SDimitry 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.
infoString__anon755d56fc0211::Edge194fe6060f1SDimitry 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
getFunctionName(const DISubprogram * SP)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.
getFilename(const DISubprogram * SP)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
GCOVRecord(GCOVProfiler * P)2285ffd83dbSDimitry Andric GCOVRecord(GCOVProfiler *P) : P(P) {}
2290b57cec5SDimitry Andric
write(uint32_t i)2305ffd83dbSDimitry Andric void write(uint32_t i) { P->write(i); }
writeString(StringRef s)2315ffd83dbSDimitry Andric void writeString(StringRef s) { P->writeString(s); }
writeBytes(const char * Bytes,int Size)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:
addLine(uint32_t Line)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
length() const2480b57cec5SDimitry Andric uint32_t length() const {
2495ffd83dbSDimitry Andric return 1 + wordsOfString(Filename) + Lines.size();
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric
writeOut()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
GCOVLines(GCOVProfiler * P,StringRef F)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:
getFile(StringRef Filename)2730b57cec5SDimitry Andric GCOVLines &getFile(StringRef Filename) {
2745ffd83dbSDimitry Andric return LinesByFile.try_emplace(Filename, P, Filename).first->second;
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric
addEdge(GCOVBlock & Successor,uint32_t Flags)277e8d8bef9SDimitry Andric void addEdge(GCOVBlock &Successor, uint32_t Flags) {
278e8d8bef9SDimitry Andric OutEdges.emplace_back(&Successor, Flags);
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric
writeOut()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
GCOVBlock(const GCOVBlock & RHS)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
GCOVBlock(GCOVProfiler * P,uint32_t Number)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:
GCOVFunction(GCOVProfiler * P,Function * F,const DISubprogram * SP,unsigned EndLine,uint32_t Ident,int Version)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
getBlock(const BasicBlock * BB)347e8d8bef9SDimitry Andric GCOVBlock &getBlock(const BasicBlock *BB) {
348e8d8bef9SDimitry Andric return Blocks.find(const_cast<BasicBlock *>(BB))->second;
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric
getEntryBlock()351e8d8bef9SDimitry Andric GCOVBlock &getEntryBlock() { return EntryBlock; }
getReturnBlock()3520b57cec5SDimitry Andric GCOVBlock &getReturnBlock() {
3530b57cec5SDimitry Andric return ReturnBlock;
3540b57cec5SDimitry Andric }
3550b57cec5SDimitry Andric
getFuncChecksum() const356480093f4SDimitry Andric uint32_t getFuncChecksum() const {
3570b57cec5SDimitry Andric return FuncChecksum;
3580b57cec5SDimitry Andric }
3590b57cec5SDimitry Andric
writeOut(uint32_t CfgChecksum)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\..*$".
createRegexesFromString(StringRef RegexesStr)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
doesFilenameMatchARegex(StringRef Filename,std::vector<Regex> & Regexes)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
isFunctionInstrumented(const Function & F)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
mangleName(const DICompileUnit * CU,GCovFileType OutputType)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
runOnModule(Module & M,function_ref<BlockFrequencyInfo * (Function & F)> GetBFI,function_ref<BranchProbabilityInfo * (Function & F)> GetBPI,std::function<const TargetLibraryInfo & (Function & F)> GetTLI)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
run(Module & M,ModuleAnalysisManager & AM)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
functionHasLines(const Function & F,unsigned & EndLine)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
isUsingScopeBasedEH(Function & F)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
AddFlushBeforeForkAndExec()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
getInstrBB(CFGMST<Edge,BBInfo> & MST,Edge & E,const DenseSet<const BasicBlock * > & ExecBlocks)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
dumpEdges(CFGMST<Edge,BBInfo> & MST,GCOVFunction & GF)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
emitProfileNotes(NamedMDNode * CUNode,bool HasExecOrFork,function_ref<BlockFrequencyInfo * (Function & F)> GetBFI,function_ref<BranchProbabilityInfo * (Function & F)> GetBPI,function_ref<const TargetLibraryInfo & (Function & F)> GetTLI)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
createInternalFunction(FunctionType * FTy,StringRef Name,StringRef MangledType)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
emitGlobalConstructor(SmallVectorImpl<std::pair<GlobalVariable *,MDNode * >> & CountersBySP)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
getStartFileFunc(const TargetLibraryInfo * TLI)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
getEmitFunctionFunc(const TargetLibraryInfo * TLI)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
getEmitArcsFunc(const TargetLibraryInfo * TLI)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
getSummaryInfoFunc()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
getEndFileFunc()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
insertCounterWriteout(ArrayRef<std::pair<GlobalVariable *,MDNode * >> CountersBySP)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
insertReset(ArrayRef<std::pair<GlobalVariable *,MDNode * >> CountersBySP)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