xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
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