1221337Sdim//===- GCOVProfiling.cpp - Insert edge counters for gcov profiling --------===// 2221337Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6221337Sdim// 7221337Sdim//===----------------------------------------------------------------------===// 8221337Sdim// 9221337Sdim// This pass implements GCOV-style profiling. When this pass is run it emits 10221337Sdim// "gcno" files next to the existing source, and instruments the code that runs 11221337Sdim// to records the edges between blocks that run and emit a complementary "gcda" 12221337Sdim// file on exit. 13221337Sdim// 14221337Sdim//===----------------------------------------------------------------------===// 15221337Sdim 16221337Sdim#include "llvm/ADT/DenseMap.h" 17276479Sdim#include "llvm/ADT/Hashing.h" 18239462Sdim#include "llvm/ADT/STLExtras.h" 19341825Sdim#include "llvm/ADT/Sequence.h" 20221337Sdim#include "llvm/ADT/Statistic.h" 21221337Sdim#include "llvm/ADT/StringExtras.h" 22221337Sdim#include "llvm/ADT/StringMap.h" 23327952Sdim#include "llvm/Analysis/EHPersonalities.h" 24341825Sdim#include "llvm/Analysis/TargetLibraryInfo.h" 25344779Sdim#include "llvm/IR/CFG.h" 26276479Sdim#include "llvm/IR/DebugInfo.h" 27276479Sdim#include "llvm/IR/DebugLoc.h" 28249423Sdim#include "llvm/IR/IRBuilder.h" 29276479Sdim#include "llvm/IR/InstIterator.h" 30249423Sdim#include "llvm/IR/Instructions.h" 31276479Sdim#include "llvm/IR/IntrinsicInst.h" 32249423Sdim#include "llvm/IR/Module.h" 33360784Sdim#include "llvm/InitializePasses.h" 34249423Sdim#include "llvm/Pass.h" 35249423Sdim#include "llvm/Support/CommandLine.h" 36239462Sdim#include "llvm/Support/Debug.h" 37249423Sdim#include "llvm/Support/FileSystem.h" 38261991Sdim#include "llvm/Support/Path.h" 39344779Sdim#include "llvm/Support/Regex.h" 40239462Sdim#include "llvm/Support/raw_ostream.h" 41309124Sdim#include "llvm/Transforms/Instrumentation.h" 42341825Sdim#include "llvm/Transforms/Instrumentation/GCOVProfiler.h" 43239462Sdim#include "llvm/Transforms/Utils/ModuleUtils.h" 44261991Sdim#include <algorithm> 45276479Sdim#include <memory> 46221337Sdim#include <string> 47221337Sdim#include <utility> 48221337Sdimusing namespace llvm; 49221337Sdim 50276479Sdim#define DEBUG_TYPE "insert-gcov-profiling" 51276479Sdim 52249423Sdimstatic cl::opt<std::string> 53249423SdimDefaultGCOVVersion("default-gcov-version", cl::init("402*"), cl::Hidden, 54249423Sdim cl::ValueRequired); 55283526Sdimstatic cl::opt<bool> DefaultExitBlockBeforeBody("gcov-exit-block-before-body", 56283526Sdim cl::init(false), cl::Hidden); 57249423Sdim 58249423SdimGCOVOptions GCOVOptions::getDefault() { 59249423Sdim GCOVOptions Options; 60249423Sdim Options.EmitNotes = true; 61249423Sdim Options.EmitData = true; 62249423Sdim Options.UseCfgChecksum = false; 63249423Sdim Options.NoRedZone = false; 64249423Sdim Options.FunctionNamesInData = true; 65288943Sdim Options.ExitBlockBeforeBody = DefaultExitBlockBeforeBody; 66249423Sdim 67249423Sdim if (DefaultGCOVVersion.size() != 4) { 68249423Sdim llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") + 69249423Sdim DefaultGCOVVersion); 70249423Sdim } 71249423Sdim memcpy(Options.Version, DefaultGCOVVersion.c_str(), 4); 72249423Sdim return Options; 73249423Sdim} 74249423Sdim 75221337Sdimnamespace { 76309124Sdimclass GCOVFunction; 77276479Sdim 78309124Sdimclass GCOVProfiler { 79309124Sdimpublic: 80309124Sdim GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {} 81309124Sdim GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) { 82309124Sdim assert((Options.EmitNotes || Options.EmitData) && 83309124Sdim "GCOVProfiler asked to do nothing?"); 84309124Sdim ReversedVersion[0] = Options.Version[3]; 85309124Sdim ReversedVersion[1] = Options.Version[2]; 86309124Sdim ReversedVersion[2] = Options.Version[1]; 87309124Sdim ReversedVersion[3] = Options.Version[0]; 88309124Sdim ReversedVersion[4] = '\0'; 89309124Sdim } 90360784Sdim bool 91360784Sdim runOnModule(Module &M, 92360784Sdim std::function<const TargetLibraryInfo &(Function &F)> GetTLI); 93288943Sdim 94309124Sdimprivate: 95309124Sdim // Create the .gcno files for the Module based on DebugInfo. 96309124Sdim void emitProfileNotes(); 97249423Sdim 98309124Sdim // Modify the program to track transitions along edges and call into the 99309124Sdim // profiling runtime to emit .gcda files when run. 100309124Sdim bool emitProfileArcs(); 101221337Sdim 102344779Sdim bool isFunctionInstrumented(const Function &F); 103344779Sdim std::vector<Regex> createRegexesFromString(StringRef RegexesStr); 104344779Sdim static bool doesFilenameMatchARegex(StringRef Filename, 105344779Sdim std::vector<Regex> &Regexes); 106344779Sdim 107309124Sdim // Get pointers to the functions in the runtime library. 108360784Sdim FunctionCallee getStartFileFunc(const TargetLibraryInfo *TLI); 109360784Sdim FunctionCallee getEmitFunctionFunc(const TargetLibraryInfo *TLI); 110360784Sdim FunctionCallee getEmitArcsFunc(const TargetLibraryInfo *TLI); 111353358Sdim FunctionCallee getSummaryInfoFunc(); 112353358Sdim FunctionCallee getEndFileFunc(); 113221337Sdim 114309124Sdim // Add the function to write out all our counters to the global destructor 115309124Sdim // list. 116309124Sdim Function * 117309124Sdim insertCounterWriteout(ArrayRef<std::pair<GlobalVariable *, MDNode *>>); 118363496Sdim Function *insertReset(ArrayRef<std::pair<GlobalVariable *, MDNode *>>); 119363496Sdim Function *insertFlush(Function *ResetF); 120221337Sdim 121344779Sdim void AddFlushBeforeForkAndExec(); 122344779Sdim 123314564Sdim enum class GCovFileType { GCNO, GCDA }; 124314564Sdim std::string mangleName(const DICompileUnit *CU, GCovFileType FileType); 125221337Sdim 126309124Sdim GCOVOptions Options; 127223017Sdim 128309124Sdim // Reversed, NUL-terminated copy of Options.Version. 129309124Sdim char ReversedVersion[5]; 130309124Sdim // Checksum, produced by hash of EdgeDestinations 131309124Sdim SmallVector<uint32_t, 4> FileChecksums; 132221337Sdim 133360784Sdim Module *M = nullptr; 134360784Sdim std::function<const TargetLibraryInfo &(Function &F)> GetTLI; 135360784Sdim LLVMContext *Ctx = nullptr; 136309124Sdim SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs; 137344779Sdim std::vector<Regex> FilterRe; 138344779Sdim std::vector<Regex> ExcludeRe; 139344779Sdim StringMap<bool> InstrumentedFiles; 140309124Sdim}; 141249423Sdim 142309124Sdimclass GCOVProfilerLegacyPass : public ModulePass { 143309124Sdimpublic: 144309124Sdim static char ID; 145309124Sdim GCOVProfilerLegacyPass() 146309124Sdim : GCOVProfilerLegacyPass(GCOVOptions::getDefault()) {} 147309124Sdim GCOVProfilerLegacyPass(const GCOVOptions &Opts) 148309124Sdim : ModulePass(ID), Profiler(Opts) { 149309124Sdim initializeGCOVProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); 150309124Sdim } 151314564Sdim StringRef getPassName() const override { return "GCOV Profiler"; } 152309124Sdim 153341825Sdim bool runOnModule(Module &M) override { 154360784Sdim return Profiler.runOnModule(M, [this](Function &F) -> TargetLibraryInfo & { 155360784Sdim return getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); 156360784Sdim }); 157341825Sdim } 158309124Sdim 159341825Sdim void getAnalysisUsage(AnalysisUsage &AU) const override { 160341825Sdim AU.addRequired<TargetLibraryInfoWrapperPass>(); 161341825Sdim } 162341825Sdim 163309124Sdimprivate: 164309124Sdim GCOVProfiler Profiler; 165309124Sdim}; 166221337Sdim} 167221337Sdim 168309124Sdimchar GCOVProfilerLegacyPass::ID = 0; 169341825SdimINITIALIZE_PASS_BEGIN( 170341825Sdim GCOVProfilerLegacyPass, "insert-gcov-profiling", 171341825Sdim "Insert instrumentation for GCOV profiling", false, false) 172341825SdimINITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) 173341825SdimINITIALIZE_PASS_END( 174341825Sdim GCOVProfilerLegacyPass, "insert-gcov-profiling", 175341825Sdim "Insert instrumentation for GCOV profiling", false, false) 176221337Sdim 177249423SdimModulePass *llvm::createGCOVProfilerPass(const GCOVOptions &Options) { 178309124Sdim return new GCOVProfilerLegacyPass(Options); 179221337Sdim} 180221337Sdim 181288943Sdimstatic StringRef getFunctionName(const DISubprogram *SP) { 182288943Sdim if (!SP->getLinkageName().empty()) 183288943Sdim return SP->getLinkageName(); 184288943Sdim return SP->getName(); 185249423Sdim} 186249423Sdim 187344779Sdim/// Extract a filename for a DISubprogram. 188344779Sdim/// 189344779Sdim/// Prefer relative paths in the coverage notes. Clang also may split 190344779Sdim/// up absolute paths into a directory and filename component. When 191344779Sdim/// the relative path doesn't exist, reconstruct the absolute path. 192344779Sdimstatic SmallString<128> getFilename(const DISubprogram *SP) { 193344779Sdim SmallString<128> Path; 194344779Sdim StringRef RelPath = SP->getFilename(); 195344779Sdim if (sys::fs::exists(RelPath)) 196344779Sdim Path = RelPath; 197344779Sdim else 198344779Sdim sys::path::append(Path, SP->getDirectory(), SP->getFilename()); 199344779Sdim return Path; 200344779Sdim} 201344779Sdim 202221337Sdimnamespace { 203221337Sdim class GCOVRecord { 204221337Sdim protected: 205261991Sdim static const char *const LinesTag; 206261991Sdim static const char *const FunctionTag; 207261991Sdim static const char *const BlockTag; 208261991Sdim static const char *const EdgeTag; 209221337Sdim 210288943Sdim GCOVRecord() = default; 211221337Sdim 212221337Sdim void writeBytes(const char *Bytes, int Size) { 213221337Sdim os->write(Bytes, Size); 214221337Sdim } 215221337Sdim 216221337Sdim void write(uint32_t i) { 217221337Sdim writeBytes(reinterpret_cast<char*>(&i), 4); 218221337Sdim } 219221337Sdim 220221337Sdim // Returns the length measured in 4-byte blocks that will be used to 221221337Sdim // represent this string in a GCOV file 222261991Sdim static unsigned lengthOfGCOVString(StringRef s) { 223221337Sdim // A GCOV string is a length, followed by a NUL, then between 0 and 3 NULs 224221337Sdim // padding out to the next 4-byte word. The length is measured in 4-byte 225221337Sdim // words including padding, not bytes of actual string. 226223017Sdim return (s.size() / 4) + 1; 227221337Sdim } 228221337Sdim 229221337Sdim void writeGCOVString(StringRef s) { 230221337Sdim uint32_t Len = lengthOfGCOVString(s); 231221337Sdim write(Len); 232221337Sdim writeBytes(s.data(), s.size()); 233221337Sdim 234221337Sdim // Write 1 to 4 bytes of NUL padding. 235221337Sdim assert((unsigned)(4 - (s.size() % 4)) > 0); 236221337Sdim assert((unsigned)(4 - (s.size() % 4)) <= 4); 237221337Sdim writeBytes("\0\0\0\0", 4 - (s.size() % 4)); 238221337Sdim } 239221337Sdim 240221337Sdim raw_ostream *os; 241221337Sdim }; 242261991Sdim const char *const GCOVRecord::LinesTag = "\0\0\x45\x01"; 243261991Sdim const char *const GCOVRecord::FunctionTag = "\0\0\0\1"; 244261991Sdim const char *const GCOVRecord::BlockTag = "\0\0\x41\x01"; 245261991Sdim const char *const GCOVRecord::EdgeTag = "\0\0\x43\x01"; 246221337Sdim 247221337Sdim class GCOVFunction; 248221337Sdim class GCOVBlock; 249221337Sdim 250221337Sdim // Constructed only by requesting it from a GCOVBlock, this object stores a 251221337Sdim // list of line numbers and a single filename, representing lines that belong 252221337Sdim // to the block. 253221337Sdim class GCOVLines : public GCOVRecord { 254221337Sdim public: 255221337Sdim void addLine(uint32_t Line) { 256276479Sdim assert(Line != 0 && "Line zero is not a valid real line number."); 257221337Sdim Lines.push_back(Line); 258221337Sdim } 259221337Sdim 260261991Sdim uint32_t length() const { 261234353Sdim // Here 2 = 1 for string length + 1 for '0' id#. 262221337Sdim return lengthOfGCOVString(Filename) + 2 + Lines.size(); 263221337Sdim } 264221337Sdim 265226633Sdim void writeOut() { 266226633Sdim write(0); 267226633Sdim writeGCOVString(Filename); 268226633Sdim for (int i = 0, e = Lines.size(); i != e; ++i) 269226633Sdim write(Lines[i]); 270226633Sdim } 271221337Sdim 272276479Sdim GCOVLines(StringRef F, raw_ostream *os) 273226633Sdim : Filename(F) { 274221337Sdim this->os = os; 275221337Sdim } 276221337Sdim 277226633Sdim private: 278344779Sdim std::string Filename; 279221337Sdim SmallVector<uint32_t, 32> Lines; 280221337Sdim }; 281221337Sdim 282261991Sdim 283221337Sdim // Represent a basic block in GCOV. Each block has a unique number in the 284221337Sdim // function, number of lines belonging to each block, and a set of edges to 285221337Sdim // other blocks. 286221337Sdim class GCOVBlock : public GCOVRecord { 287221337Sdim public: 288226633Sdim GCOVLines &getFile(StringRef Filename) { 289314564Sdim return LinesByFile.try_emplace(Filename, Filename, os).first->second; 290221337Sdim } 291221337Sdim 292221337Sdim void addEdge(GCOVBlock &Successor) { 293221337Sdim OutEdges.push_back(&Successor); 294221337Sdim } 295221337Sdim 296221337Sdim void writeOut() { 297221337Sdim uint32_t Len = 3; 298314564Sdim SmallVector<StringMapEntry<GCOVLines> *, 32> SortedLinesByFile; 299309124Sdim for (auto &I : LinesByFile) { 300314564Sdim Len += I.second.length(); 301309124Sdim SortedLinesByFile.push_back(&I); 302221337Sdim } 303221337Sdim 304221337Sdim writeBytes(LinesTag, 4); 305221337Sdim write(Len); 306221337Sdim write(Number); 307261991Sdim 308344779Sdim llvm::sort(SortedLinesByFile, [](StringMapEntry<GCOVLines> *LHS, 309344779Sdim StringMapEntry<GCOVLines> *RHS) { 310344779Sdim return LHS->getKey() < RHS->getKey(); 311344779Sdim }); 312309124Sdim for (auto &I : SortedLinesByFile) 313314564Sdim I->getValue().writeOut(); 314221337Sdim write(0); 315221337Sdim write(0); 316221337Sdim } 317221337Sdim 318280031Sdim GCOVBlock(const GCOVBlock &RHS) : GCOVRecord(RHS), Number(RHS.Number) { 319280031Sdim // Only allow copy before edges and lines have been added. After that, 320280031Sdim // there are inter-block pointers (eg: edges) that won't take kindly to 321280031Sdim // blocks being copied or moved around. 322280031Sdim assert(LinesByFile.empty()); 323280031Sdim assert(OutEdges.empty()); 324280031Sdim } 325280031Sdim 326221337Sdim private: 327221337Sdim friend class GCOVFunction; 328221337Sdim 329221337Sdim GCOVBlock(uint32_t Number, raw_ostream *os) 330221337Sdim : Number(Number) { 331221337Sdim this->os = os; 332221337Sdim } 333221337Sdim 334221337Sdim uint32_t Number; 335314564Sdim StringMap<GCOVLines> LinesByFile; 336221337Sdim SmallVector<GCOVBlock *, 4> OutEdges; 337221337Sdim }; 338221337Sdim 339221337Sdim // A function has a unique identifier, a checksum (we leave as zero) and a 340221337Sdim // set of blocks and a map of edges between blocks. This is the only GCOV 341221337Sdim // object users can construct, the blocks and lines will be rooted here. 342221337Sdim class GCOVFunction : public GCOVRecord { 343221337Sdim public: 344296417Sdim GCOVFunction(const DISubprogram *SP, Function *F, raw_ostream *os, 345296417Sdim uint32_t Ident, bool UseCfgChecksum, bool ExitBlockBeforeBody) 346280031Sdim : SP(SP), Ident(Ident), UseCfgChecksum(UseCfgChecksum), CfgChecksum(0), 347280031Sdim ReturnBlock(1, os) { 348221337Sdim this->os = os; 349221337Sdim 350341825Sdim LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n"); 351280031Sdim 352221337Sdim uint32_t i = 0; 353280031Sdim for (auto &BB : *F) { 354283526Sdim // Skip index 1 if it's assigned to the ReturnBlock. 355283526Sdim if (i == 1 && ExitBlockBeforeBody) 356283526Sdim ++i; 357283526Sdim Blocks.insert(std::make_pair(&BB, GCOVBlock(i++, os))); 358221337Sdim } 359283526Sdim if (!ExitBlockBeforeBody) 360283526Sdim ReturnBlock.Number = i; 361221337Sdim 362276479Sdim std::string FunctionNameAndLine; 363276479Sdim raw_string_ostream FNLOS(FunctionNameAndLine); 364288943Sdim FNLOS << getFunctionName(SP) << SP->getLine(); 365276479Sdim FNLOS.flush(); 366276479Sdim FuncChecksum = hash_value(FunctionNameAndLine); 367221337Sdim } 368221337Sdim 369221337Sdim GCOVBlock &getBlock(BasicBlock *BB) { 370280031Sdim return Blocks.find(BB)->second; 371221337Sdim } 372221337Sdim 373221337Sdim GCOVBlock &getReturnBlock() { 374280031Sdim return ReturnBlock; 375221337Sdim } 376221337Sdim 377276479Sdim std::string getEdgeDestinations() { 378276479Sdim std::string EdgeDestinations; 379276479Sdim raw_string_ostream EDOS(EdgeDestinations); 380276479Sdim Function *F = Blocks.begin()->first->getParent(); 381296417Sdim for (BasicBlock &I : *F) { 382296417Sdim GCOVBlock &Block = getBlock(&I); 383276479Sdim for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) 384276479Sdim EDOS << Block.OutEdges[i]->Number; 385276479Sdim } 386276479Sdim return EdgeDestinations; 387276479Sdim } 388276479Sdim 389360784Sdim uint32_t getFuncChecksum() const { 390276479Sdim return FuncChecksum; 391276479Sdim } 392276479Sdim 393276479Sdim void setCfgChecksum(uint32_t Checksum) { 394276479Sdim CfgChecksum = Checksum; 395276479Sdim } 396276479Sdim 397221337Sdim void writeOut() { 398276479Sdim writeBytes(FunctionTag, 4); 399344779Sdim SmallString<128> Filename = getFilename(SP); 400276479Sdim uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) + 401344779Sdim 1 + lengthOfGCOVString(Filename) + 1; 402276479Sdim if (UseCfgChecksum) 403276479Sdim ++BlockLen; 404276479Sdim write(BlockLen); 405276479Sdim write(Ident); 406276479Sdim write(FuncChecksum); 407276479Sdim if (UseCfgChecksum) 408276479Sdim write(CfgChecksum); 409276479Sdim writeGCOVString(getFunctionName(SP)); 410344779Sdim writeGCOVString(Filename); 411288943Sdim write(SP->getLine()); 412276479Sdim 413221337Sdim // Emit count of blocks. 414221337Sdim writeBytes(BlockTag, 4); 415221337Sdim write(Blocks.size() + 1); 416221337Sdim for (int i = 0, e = Blocks.size() + 1; i != e; ++i) { 417221337Sdim write(0); // No flags on our blocks. 418221337Sdim } 419341825Sdim LLVM_DEBUG(dbgs() << Blocks.size() << " blocks.\n"); 420221337Sdim 421221337Sdim // Emit edges between blocks. 422261991Sdim if (Blocks.empty()) return; 423261991Sdim Function *F = Blocks.begin()->first->getParent(); 424296417Sdim for (BasicBlock &I : *F) { 425296417Sdim GCOVBlock &Block = getBlock(&I); 426221337Sdim if (Block.OutEdges.empty()) continue; 427221337Sdim 428221337Sdim writeBytes(EdgeTag, 4); 429221337Sdim write(Block.OutEdges.size() * 2 + 1); 430221337Sdim write(Block.Number); 431221337Sdim for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) { 432341825Sdim LLVM_DEBUG(dbgs() << Block.Number << " -> " 433341825Sdim << Block.OutEdges[i]->Number << "\n"); 434221337Sdim write(Block.OutEdges[i]->Number); 435221337Sdim write(0); // no flags 436221337Sdim } 437221337Sdim } 438221337Sdim 439221337Sdim // Emit lines for each block. 440296417Sdim for (BasicBlock &I : *F) 441296417Sdim getBlock(&I).writeOut(); 442221337Sdim } 443221337Sdim 444221337Sdim private: 445288943Sdim const DISubprogram *SP; 446276479Sdim uint32_t Ident; 447276479Sdim uint32_t FuncChecksum; 448276479Sdim bool UseCfgChecksum; 449276479Sdim uint32_t CfgChecksum; 450280031Sdim DenseMap<BasicBlock *, GCOVBlock> Blocks; 451280031Sdim GCOVBlock ReturnBlock; 452221337Sdim }; 453221337Sdim} 454221337Sdim 455344779Sdim// RegexesStr is a string containing differents regex separated by a semi-colon. 456344779Sdim// For example "foo\..*$;bar\..*$". 457344779Sdimstd::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) { 458344779Sdim std::vector<Regex> Regexes; 459344779Sdim while (!RegexesStr.empty()) { 460344779Sdim std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(';'); 461344779Sdim if (!HeadTail.first.empty()) { 462344779Sdim Regex Re(HeadTail.first); 463344779Sdim std::string Err; 464344779Sdim if (!Re.isValid(Err)) { 465344779Sdim Ctx->emitError(Twine("Regex ") + HeadTail.first + 466344779Sdim " is not valid: " + Err); 467344779Sdim } 468344779Sdim Regexes.emplace_back(std::move(Re)); 469344779Sdim } 470344779Sdim RegexesStr = HeadTail.second; 471344779Sdim } 472344779Sdim return Regexes; 473344779Sdim} 474344779Sdim 475344779Sdimbool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename, 476344779Sdim std::vector<Regex> &Regexes) { 477344779Sdim for (Regex &Re : Regexes) { 478344779Sdim if (Re.match(Filename)) { 479344779Sdim return true; 480344779Sdim } 481344779Sdim } 482344779Sdim return false; 483344779Sdim} 484344779Sdim 485344779Sdimbool GCOVProfiler::isFunctionInstrumented(const Function &F) { 486344779Sdim if (FilterRe.empty() && ExcludeRe.empty()) { 487344779Sdim return true; 488344779Sdim } 489344779Sdim SmallString<128> Filename = getFilename(F.getSubprogram()); 490344779Sdim auto It = InstrumentedFiles.find(Filename); 491344779Sdim if (It != InstrumentedFiles.end()) { 492344779Sdim return It->second; 493344779Sdim } 494344779Sdim 495344779Sdim SmallString<256> RealPath; 496344779Sdim StringRef RealFilename; 497344779Sdim 498344779Sdim // Path can be 499344779Sdim // /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for 500344779Sdim // such a case we must get the real_path. 501344779Sdim if (sys::fs::real_path(Filename, RealPath)) { 502344779Sdim // real_path can fail with path like "foo.c". 503344779Sdim RealFilename = Filename; 504344779Sdim } else { 505344779Sdim RealFilename = RealPath; 506344779Sdim } 507344779Sdim 508344779Sdim bool ShouldInstrument; 509344779Sdim if (FilterRe.empty()) { 510344779Sdim ShouldInstrument = !doesFilenameMatchARegex(RealFilename, ExcludeRe); 511344779Sdim } else if (ExcludeRe.empty()) { 512344779Sdim ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe); 513344779Sdim } else { 514344779Sdim ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe) && 515344779Sdim !doesFilenameMatchARegex(RealFilename, ExcludeRe); 516344779Sdim } 517344779Sdim InstrumentedFiles[Filename] = ShouldInstrument; 518344779Sdim return ShouldInstrument; 519344779Sdim} 520344779Sdim 521288943Sdimstd::string GCOVProfiler::mangleName(const DICompileUnit *CU, 522314564Sdim GCovFileType OutputType) { 523314564Sdim bool Notes = OutputType == GCovFileType::GCNO; 524314564Sdim 525223017Sdim if (NamedMDNode *GCov = M->getNamedMetadata("llvm.gcov")) { 526223017Sdim for (int i = 0, e = GCov->getNumOperands(); i != e; ++i) { 527223017Sdim MDNode *N = GCov->getOperand(i); 528314564Sdim bool ThreeElement = N->getNumOperands() == 3; 529314564Sdim if (!ThreeElement && N->getNumOperands() != 2) 530314564Sdim continue; 531314564Sdim if (dyn_cast<MDNode>(N->getOperand(ThreeElement ? 2 : 1)) != CU) 532314564Sdim continue; 533314564Sdim 534314564Sdim if (ThreeElement) { 535314564Sdim // These nodes have no mangling to apply, it's stored mangled in the 536314564Sdim // bitcode. 537314564Sdim MDString *NotesFile = dyn_cast<MDString>(N->getOperand(0)); 538314564Sdim MDString *DataFile = dyn_cast<MDString>(N->getOperand(1)); 539314564Sdim if (!NotesFile || !DataFile) 540314564Sdim continue; 541314564Sdim return Notes ? NotesFile->getString() : DataFile->getString(); 542314564Sdim } 543314564Sdim 544223017Sdim MDString *GCovFile = dyn_cast<MDString>(N->getOperand(0)); 545314564Sdim if (!GCovFile) 546314564Sdim continue; 547314564Sdim 548314564Sdim SmallString<128> Filename = GCovFile->getString(); 549314564Sdim sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda"); 550314564Sdim return Filename.str(); 551223017Sdim } 552223017Sdim } 553223017Sdim 554288943Sdim SmallString<128> Filename = CU->getFilename(); 555314564Sdim sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda"); 556249423Sdim StringRef FName = sys::path::filename(Filename); 557249423Sdim SmallString<128> CurPath; 558249423Sdim if (sys::fs::current_path(CurPath)) return FName; 559288943Sdim sys::path::append(CurPath, FName); 560249423Sdim return CurPath.str(); 561221337Sdim} 562221337Sdim 563360784Sdimbool GCOVProfiler::runOnModule( 564360784Sdim Module &M, std::function<const TargetLibraryInfo &(Function &F)> GetTLI) { 565221337Sdim this->M = &M; 566360784Sdim this->GetTLI = std::move(GetTLI); 567221337Sdim Ctx = &M.getContext(); 568221337Sdim 569344779Sdim AddFlushBeforeForkAndExec(); 570344779Sdim 571344779Sdim FilterRe = createRegexesFromString(Options.Filter); 572344779Sdim ExcludeRe = createRegexesFromString(Options.Exclude); 573344779Sdim 574249423Sdim if (Options.EmitNotes) emitProfileNotes(); 575249423Sdim if (Options.EmitData) return emitProfileArcs(); 576221337Sdim return false; 577221337Sdim} 578221337Sdim 579309124SdimPreservedAnalyses GCOVProfilerPass::run(Module &M, 580314564Sdim ModuleAnalysisManager &AM) { 581309124Sdim 582309124Sdim GCOVProfiler Profiler(GCOVOpts); 583360784Sdim FunctionAnalysisManager &FAM = 584360784Sdim AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 585309124Sdim 586360784Sdim if (!Profiler.runOnModule(M, [&](Function &F) -> TargetLibraryInfo & { 587360784Sdim return FAM.getResult<TargetLibraryAnalysis>(F); 588360784Sdim })) 589309124Sdim return PreservedAnalyses::all(); 590309124Sdim 591309124Sdim return PreservedAnalyses::none(); 592309124Sdim} 593309124Sdim 594309124Sdimstatic bool functionHasLines(Function &F) { 595276479Sdim // Check whether this function actually has any source lines. Not only 596276479Sdim // do these waste space, they also can crash gcov. 597309124Sdim for (auto &BB : F) { 598309124Sdim for (auto &I : BB) { 599276479Sdim // Debug intrinsic locations correspond to the location of the 600276479Sdim // declaration, not necessarily any statements or expressions. 601309124Sdim if (isa<DbgInfoIntrinsic>(&I)) continue; 602276479Sdim 603309124Sdim const DebugLoc &Loc = I.getDebugLoc(); 604288943Sdim if (!Loc) 605288943Sdim continue; 606276479Sdim 607276479Sdim // Artificial lines such as calls to the global constructors. 608283526Sdim if (Loc.getLine() == 0) continue; 609276479Sdim 610276479Sdim return true; 611276479Sdim } 612276479Sdim } 613276479Sdim return false; 614276479Sdim} 615276479Sdim 616341825Sdimstatic bool isUsingScopeBasedEH(Function &F) { 617327952Sdim if (!F.hasPersonalityFn()) return false; 618327952Sdim 619327952Sdim EHPersonality Personality = classifyEHPersonality(F.getPersonalityFn()); 620341825Sdim return isScopedEHPersonality(Personality); 621327952Sdim} 622327952Sdim 623327952Sdimstatic bool shouldKeepInEntry(BasicBlock::iterator It) { 624327952Sdim if (isa<AllocaInst>(*It)) return true; 625327952Sdim if (isa<DbgInfoIntrinsic>(*It)) return true; 626327952Sdim if (auto *II = dyn_cast<IntrinsicInst>(It)) { 627327952Sdim if (II->getIntrinsicID() == llvm::Intrinsic::localescape) return true; 628327952Sdim } 629327952Sdim 630327952Sdim return false; 631327952Sdim} 632327952Sdim 633344779Sdimvoid GCOVProfiler::AddFlushBeforeForkAndExec() { 634363496Sdim SmallVector<CallInst *, 2> Forks; 635363496Sdim SmallVector<CallInst *, 2> Execs; 636344779Sdim for (auto &F : M->functions()) { 637360784Sdim auto *TLI = &GetTLI(F); 638344779Sdim for (auto &I : instructions(F)) { 639344779Sdim if (CallInst *CI = dyn_cast<CallInst>(&I)) { 640344779Sdim if (Function *Callee = CI->getCalledFunction()) { 641344779Sdim LibFunc LF; 642363496Sdim if (TLI->getLibFunc(*Callee, LF)) { 643363496Sdim if (LF == LibFunc_fork) { 644363496Sdim#if !defined(_WIN32) 645363496Sdim Forks.push_back(CI); 646363496Sdim#endif 647363496Sdim } else if (LF == LibFunc_execl || LF == LibFunc_execle || 648363496Sdim LF == LibFunc_execlp || LF == LibFunc_execv || 649363496Sdim LF == LibFunc_execvp || LF == LibFunc_execve || 650363496Sdim LF == LibFunc_execvpe || LF == LibFunc_execvP) { 651363496Sdim Execs.push_back(CI); 652363496Sdim } 653344779Sdim } 654344779Sdim } 655344779Sdim } 656344779Sdim } 657344779Sdim } 658344779Sdim 659363496Sdim for (auto F : Forks) { 660363496Sdim IRBuilder<> Builder(F); 661363496Sdim BasicBlock *Parent = F->getParent(); 662363496Sdim auto NextInst = ++F->getIterator(); 663363496Sdim 664363496Sdim // We've a fork so just reset the counters in the child process 665363496Sdim FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false); 666363496Sdim FunctionCallee GCOVFork = M->getOrInsertFunction("__gcov_fork", FTy); 667363496Sdim F->setCalledFunction(GCOVFork); 668363496Sdim 669363496Sdim // We split just after the fork to have a counter for the lines after 670363496Sdim // Anyway there's a bug: 671363496Sdim // void foo() { fork(); } 672363496Sdim // void bar() { foo(); blah(); } 673363496Sdim // then "blah();" will be called 2 times but showed as 1 674363496Sdim // because "blah()" belongs to the same block as "foo();" 675363496Sdim Parent->splitBasicBlock(NextInst); 676363496Sdim 677363496Sdim // back() is a br instruction with a debug location 678363496Sdim // equals to the one from NextAfterFork 679363496Sdim // So to avoid to have two debug locs on two blocks just change it 680363496Sdim DebugLoc Loc = F->getDebugLoc(); 681363496Sdim Parent->back().setDebugLoc(Loc); 682363496Sdim } 683363496Sdim 684363496Sdim for (auto E : Execs) { 685363496Sdim IRBuilder<> Builder(E); 686363496Sdim BasicBlock *Parent = E->getParent(); 687363496Sdim auto NextInst = ++E->getIterator(); 688363496Sdim 689363496Sdim // Since the process is replaced by a new one we need to write out gcdas 690363496Sdim // No need to reset the counters since they'll be lost after the exec** 691344779Sdim FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); 692363496Sdim FunctionCallee WriteoutF = 693363496Sdim M->getOrInsertFunction("llvm_writeout_files", FTy); 694363496Sdim Builder.CreateCall(WriteoutF); 695363496Sdim 696363496Sdim DebugLoc Loc = E->getDebugLoc(); 697363496Sdim Builder.SetInsertPoint(&*NextInst); 698363496Sdim // If the exec** fails we must reset the counters since they've been 699363496Sdim // dumped 700363496Sdim FunctionCallee ResetF = M->getOrInsertFunction("llvm_reset_counters", FTy); 701363496Sdim Builder.CreateCall(ResetF)->setDebugLoc(Loc); 702363496Sdim Parent->splitBasicBlock(NextInst); 703363496Sdim Parent->back().setDebugLoc(Loc); 704344779Sdim } 705344779Sdim} 706344779Sdim 707249423Sdimvoid GCOVProfiler::emitProfileNotes() { 708226633Sdim NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); 709234353Sdim if (!CU_Nodes) return; 710234353Sdim 711234353Sdim for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { 712234353Sdim // Each compile unit gets its own .gcno file. This means that whether we run 713234353Sdim // this pass over the original .o's as they're produced, or run it after 714234353Sdim // LTO, we'll generate the same .gcno files. 715234353Sdim 716288943Sdim auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i)); 717296417Sdim 718296417Sdim // Skip module skeleton (and module) CUs. 719296417Sdim if (CU->getDWOId()) 720296417Sdim continue; 721296417Sdim 722280031Sdim std::error_code EC; 723360784Sdim raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, 724360784Sdim sys::fs::OF_None); 725327952Sdim if (EC) { 726327952Sdim Ctx->emitError(Twine("failed to open coverage notes file for writing: ") + 727327952Sdim EC.message()); 728327952Sdim continue; 729327952Sdim } 730327952Sdim 731276479Sdim std::string EdgeDestinations; 732234353Sdim 733280031Sdim unsigned FunctionIdent = 0; 734309124Sdim for (auto &F : M->functions()) { 735309124Sdim DISubprogram *SP = F.getSubprogram(); 736309124Sdim if (!SP) continue; 737344779Sdim if (!functionHasLines(F) || !isFunctionInstrumented(F)) 738344779Sdim continue; 739341825Sdim // TODO: Functions using scope-based EH are currently not supported. 740341825Sdim if (isUsingScopeBasedEH(F)) continue; 741234353Sdim 742276479Sdim // gcov expects every function to start with an entry block that has a 743276479Sdim // single successor, so split the entry block to make sure of that. 744309124Sdim BasicBlock &EntryBlock = F.getEntryBlock(); 745276479Sdim BasicBlock::iterator It = EntryBlock.begin(); 746327952Sdim while (shouldKeepInEntry(It)) 747276479Sdim ++It; 748276479Sdim EntryBlock.splitBasicBlock(It); 749276479Sdim 750360784Sdim Funcs.push_back(std::make_unique<GCOVFunction>(SP, &F, &out, FunctionIdent++, 751283526Sdim Options.UseCfgChecksum, 752288943Sdim Options.ExitBlockBeforeBody)); 753276479Sdim GCOVFunction &Func = *Funcs.back(); 754276479Sdim 755344779Sdim // Add the function line number to the lines of the entry block 756344779Sdim // to have a counter for the function definition. 757344779Sdim uint32_t Line = SP->getLine(); 758344779Sdim auto Filename = getFilename(SP); 759344779Sdim 760360784Sdim // Artificial functions such as global initializers 761360784Sdim if (!SP->isArtificial()) 762360784Sdim Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line); 763360784Sdim 764309124Sdim for (auto &BB : F) { 765309124Sdim GCOVBlock &Block = Func.getBlock(&BB); 766344779Sdim Instruction *TI = BB.getTerminator(); 767234353Sdim if (int successors = TI->getNumSuccessors()) { 768234353Sdim for (int i = 0; i != successors; ++i) { 769234353Sdim Block.addEdge(Func.getBlock(TI->getSuccessor(i))); 770226633Sdim } 771234353Sdim } else if (isa<ReturnInst>(TI)) { 772234353Sdim Block.addEdge(Func.getReturnBlock()); 773221337Sdim } 774234353Sdim 775309124Sdim for (auto &I : BB) { 776276479Sdim // Debug intrinsic locations correspond to the location of the 777276479Sdim // declaration, not necessarily any statements or expressions. 778309124Sdim if (isa<DbgInfoIntrinsic>(&I)) continue; 779276479Sdim 780309124Sdim const DebugLoc &Loc = I.getDebugLoc(); 781288943Sdim if (!Loc) 782288943Sdim continue; 783276479Sdim 784276479Sdim // Artificial lines such as calls to the global constructors. 785344779Sdim if (Loc.getLine() == 0 || Loc.isImplicitCode()) 786344779Sdim continue; 787276479Sdim 788234353Sdim if (Line == Loc.getLine()) continue; 789234353Sdim Line = Loc.getLine(); 790288943Sdim if (SP != getDISubprogram(Loc.getScope())) 791288943Sdim continue; 792234353Sdim 793344779Sdim GCOVLines &Lines = Block.getFile(Filename); 794234353Sdim Lines.addLine(Loc.getLine()); 795234353Sdim } 796344779Sdim Line = 0; 797221337Sdim } 798276479Sdim EdgeDestinations += Func.getEdgeDestinations(); 799221337Sdim } 800276479Sdim 801276479Sdim FileChecksums.push_back(hash_value(EdgeDestinations)); 802276479Sdim out.write("oncg", 4); 803276479Sdim out.write(ReversedVersion, 4); 804276479Sdim out.write(reinterpret_cast<char*>(&FileChecksums.back()), 4); 805276479Sdim 806276479Sdim for (auto &Func : Funcs) { 807276479Sdim Func->setCfgChecksum(FileChecksums.back()); 808276479Sdim Func->writeOut(); 809276479Sdim } 810276479Sdim 811234353Sdim out.write("\0\0\0\0\0\0\0\0", 8); // EOF 812234353Sdim out.close(); 813221337Sdim } 814221337Sdim} 815221337Sdim 816226633Sdimbool GCOVProfiler::emitProfileArcs() { 817226633Sdim NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); 818226633Sdim if (!CU_Nodes) return false; 819221337Sdim 820276479Sdim bool Result = false; 821226633Sdim for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { 822226633Sdim SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; 823309124Sdim for (auto &F : M->functions()) { 824309124Sdim DISubprogram *SP = F.getSubprogram(); 825309124Sdim if (!SP) continue; 826344779Sdim if (!functionHasLines(F) || !isFunctionInstrumented(F)) 827344779Sdim continue; 828341825Sdim // TODO: Functions using scope-based EH are currently not supported. 829341825Sdim if (isUsingScopeBasedEH(F)) continue; 830226633Sdim if (!Result) Result = true; 831327952Sdim 832344779Sdim DenseMap<std::pair<BasicBlock *, BasicBlock *>, unsigned> EdgeToCounter; 833226633Sdim unsigned Edges = 0; 834309124Sdim for (auto &BB : F) { 835344779Sdim Instruction *TI = BB.getTerminator(); 836344779Sdim if (isa<ReturnInst>(TI)) { 837344779Sdim EdgeToCounter[{&BB, nullptr}] = Edges++; 838344779Sdim } else { 839344779Sdim for (BasicBlock *Succ : successors(TI)) { 840344779Sdim EdgeToCounter[{&BB, Succ}] = Edges++; 841344779Sdim } 842344779Sdim } 843226633Sdim } 844276479Sdim 845226633Sdim ArrayType *CounterTy = 846221337Sdim ArrayType::get(Type::getInt64Ty(*Ctx), Edges); 847226633Sdim GlobalVariable *Counters = 848221337Sdim new GlobalVariable(*M, CounterTy, false, 849221337Sdim GlobalValue::InternalLinkage, 850221337Sdim Constant::getNullValue(CounterTy), 851239462Sdim "__llvm_gcov_ctr"); 852288943Sdim CountersBySP.push_back(std::make_pair(Counters, SP)); 853276479Sdim 854344779Sdim // If a BB has several predecessors, use a PHINode to select 855344779Sdim // the correct counter. 856344779Sdim for (auto &BB : F) { 857344779Sdim const unsigned EdgeCount = 858344779Sdim std::distance(pred_begin(&BB), pred_end(&BB)); 859344779Sdim if (EdgeCount) { 860344779Sdim // The phi node must be at the begin of the BB. 861344779Sdim IRBuilder<> BuilderForPhi(&*BB.begin()); 862344779Sdim Type *Int64PtrTy = Type::getInt64PtrTy(*Ctx); 863344779Sdim PHINode *Phi = BuilderForPhi.CreatePHI(Int64PtrTy, EdgeCount); 864344779Sdim for (BasicBlock *Pred : predecessors(&BB)) { 865344779Sdim auto It = EdgeToCounter.find({Pred, &BB}); 866344779Sdim assert(It != EdgeToCounter.end()); 867344779Sdim const unsigned Edge = It->second; 868353358Sdim Value *EdgeCounter = BuilderForPhi.CreateConstInBoundsGEP2_64( 869353358Sdim Counters->getValueType(), Counters, 0, Edge); 870344779Sdim Phi->addIncoming(EdgeCounter, Pred); 871344779Sdim } 872276479Sdim 873344779Sdim // Skip phis, landingpads. 874344779Sdim IRBuilder<> Builder(&*BB.getFirstInsertionPt()); 875353358Sdim Value *Count = Builder.CreateLoad(Builder.getInt64Ty(), Phi); 876344779Sdim Count = Builder.CreateAdd(Count, Builder.getInt64(1)); 877344779Sdim Builder.CreateStore(Count, Phi); 878344779Sdim 879344779Sdim Instruction *TI = BB.getTerminator(); 880344779Sdim if (isa<ReturnInst>(TI)) { 881344779Sdim auto It = EdgeToCounter.find({&BB, nullptr}); 882344779Sdim assert(It != EdgeToCounter.end()); 883344779Sdim const unsigned Edge = It->second; 884353358Sdim Value *Counter = Builder.CreateConstInBoundsGEP2_64( 885353358Sdim Counters->getValueType(), Counters, 0, Edge); 886353358Sdim Value *Count = Builder.CreateLoad(Builder.getInt64Ty(), Counter); 887249423Sdim Count = Builder.CreateAdd(Count, Builder.getInt64(1)); 888226633Sdim Builder.CreateStore(Count, Counter); 889226633Sdim } 890221337Sdim } 891221337Sdim } 892221337Sdim } 893239462Sdim 894249423Sdim Function *WriteoutF = insertCounterWriteout(CountersBySP); 895363496Sdim Function *ResetF = insertReset(CountersBySP); 896363496Sdim Function *FlushF = insertFlush(ResetF); 897249423Sdim 898249423Sdim // Create a small bit of code that registers the "__llvm_gcov_writeout" to 899249423Sdim // be executed at exit and the "__llvm_gcov_flush" function to be executed 900249423Sdim // when "__gcov_flush" is called. 901249423Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 902249423Sdim Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, 903249423Sdim "__llvm_gcov_init", M); 904309124Sdim F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 905249423Sdim F->setLinkage(GlobalValue::InternalLinkage); 906249423Sdim F->addFnAttr(Attribute::NoInline); 907249423Sdim if (Options.NoRedZone) 908249423Sdim F->addFnAttr(Attribute::NoRedZone); 909249423Sdim 910249423Sdim BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); 911249423Sdim IRBuilder<> Builder(BB); 912249423Sdim 913249423Sdim FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 914363496Sdim Type *Params[] = {PointerType::get(FTy, 0), PointerType::get(FTy, 0), 915363496Sdim PointerType::get(FTy, 0)}; 916249423Sdim FTy = FunctionType::get(Builder.getVoidTy(), Params, false); 917249423Sdim 918363496Sdim // Initialize the environment and register the local writeout, flush and 919363496Sdim // reset functions. 920353358Sdim FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); 921363496Sdim Builder.CreateCall(GCOVInit, {WriteoutF, FlushF, ResetF}); 922249423Sdim Builder.CreateRetVoid(); 923249423Sdim 924249423Sdim appendToGlobalCtors(*M, F, 0); 925221337Sdim } 926239462Sdim 927226633Sdim return Result; 928221337Sdim} 929221337Sdim 930360784SdimFunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) { 931249423Sdim Type *Args[] = { 932249423Sdim Type::getInt8PtrTy(*Ctx), // const char *orig_filename 933249423Sdim Type::getInt8PtrTy(*Ctx), // const char version[4] 934276479Sdim Type::getInt32Ty(*Ctx), // uint32_t checksum 935249423Sdim }; 936249423Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 937353358Sdim AttributeList AL; 938353358Sdim if (auto AK = TLI->getExtAttrForI32Param(false)) 939353358Sdim AL = AL.addParamAttribute(*Ctx, 2, AK); 940353358Sdim FunctionCallee Res = M->getOrInsertFunction("llvm_gcda_start_file", FTy, AL); 941341825Sdim return Res; 942221337Sdim} 943221337Sdim 944360784SdimFunctionCallee GCOVProfiler::getEmitFunctionFunc(const TargetLibraryInfo *TLI) { 945276479Sdim Type *Args[] = { 946223017Sdim Type::getInt32Ty(*Ctx), // uint32_t ident 947223017Sdim Type::getInt8PtrTy(*Ctx), // const char *function_name 948276479Sdim Type::getInt32Ty(*Ctx), // uint32_t func_checksum 949249423Sdim Type::getInt8Ty(*Ctx), // uint8_t use_extra_checksum 950276479Sdim Type::getInt32Ty(*Ctx), // uint32_t cfg_checksum 951223017Sdim }; 952239462Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 953353358Sdim AttributeList AL; 954353358Sdim if (auto AK = TLI->getExtAttrForI32Param(false)) { 955353358Sdim AL = AL.addParamAttribute(*Ctx, 0, AK); 956353358Sdim AL = AL.addParamAttribute(*Ctx, 2, AK); 957353358Sdim AL = AL.addParamAttribute(*Ctx, 3, AK); 958353358Sdim AL = AL.addParamAttribute(*Ctx, 4, AK); 959353358Sdim } 960353358Sdim return M->getOrInsertFunction("llvm_gcda_emit_function", FTy); 961221337Sdim} 962221337Sdim 963360784SdimFunctionCallee GCOVProfiler::getEmitArcsFunc(const TargetLibraryInfo *TLI) { 964224145Sdim Type *Args[] = { 965221337Sdim Type::getInt32Ty(*Ctx), // uint32_t num_counters 966221337Sdim Type::getInt64PtrTy(*Ctx), // uint64_t *counters 967221337Sdim }; 968249423Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 969353358Sdim AttributeList AL; 970353358Sdim if (auto AK = TLI->getExtAttrForI32Param(false)) 971353358Sdim AL = AL.addParamAttribute(*Ctx, 0, AK); 972353358Sdim return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy, AL); 973221337Sdim} 974221337Sdim 975353358SdimFunctionCallee GCOVProfiler::getSummaryInfoFunc() { 976261991Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 977261991Sdim return M->getOrInsertFunction("llvm_gcda_summary_info", FTy); 978261991Sdim} 979261991Sdim 980353358SdimFunctionCallee GCOVProfiler::getEndFileFunc() { 981226633Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 982221337Sdim return M->getOrInsertFunction("llvm_gcda_end_file", FTy); 983221337Sdim} 984221337Sdim 985249423SdimFunction *GCOVProfiler::insertCounterWriteout( 986243830Sdim ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) { 987243830Sdim FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 988243830Sdim Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); 989243830Sdim if (!WriteoutF) 990243830Sdim WriteoutF = Function::Create(WriteoutFTy, GlobalValue::InternalLinkage, 991243830Sdim "__llvm_gcov_writeout", M); 992309124Sdim WriteoutF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 993249423Sdim WriteoutF->addFnAttr(Attribute::NoInline); 994249423Sdim if (Options.NoRedZone) 995249423Sdim WriteoutF->addFnAttr(Attribute::NoRedZone); 996243830Sdim 997243830Sdim BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF); 998221337Sdim IRBuilder<> Builder(BB); 999221337Sdim 1000360784Sdim auto *TLI = &GetTLI(*WriteoutF); 1001360784Sdim 1002360784Sdim FunctionCallee StartFile = getStartFileFunc(TLI); 1003360784Sdim FunctionCallee EmitFunction = getEmitFunctionFunc(TLI); 1004360784Sdim FunctionCallee EmitArcs = getEmitArcsFunc(TLI); 1005353358Sdim FunctionCallee SummaryInfo = getSummaryInfoFunc(); 1006353358Sdim FunctionCallee EndFile = getEndFileFunc(); 1007221337Sdim 1008341825Sdim NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu"); 1009341825Sdim if (!CUNodes) { 1010341825Sdim Builder.CreateRetVoid(); 1011341825Sdim return WriteoutF; 1012341825Sdim } 1013296417Sdim 1014341825Sdim // Collect the relevant data into a large constant data structure that we can 1015341825Sdim // walk to write out everything. 1016341825Sdim StructType *StartFileCallArgsTy = StructType::create( 1017341825Sdim {Builder.getInt8PtrTy(), Builder.getInt8PtrTy(), Builder.getInt32Ty()}); 1018341825Sdim StructType *EmitFunctionCallArgsTy = StructType::create( 1019341825Sdim {Builder.getInt32Ty(), Builder.getInt8PtrTy(), Builder.getInt32Ty(), 1020341825Sdim Builder.getInt8Ty(), Builder.getInt32Ty()}); 1021341825Sdim StructType *EmitArcsCallArgsTy = StructType::create( 1022341825Sdim {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}); 1023341825Sdim StructType *FileInfoTy = 1024341825Sdim StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(), 1025341825Sdim EmitFunctionCallArgsTy->getPointerTo(), 1026341825Sdim EmitArcsCallArgsTy->getPointerTo()}); 1027296417Sdim 1028341825Sdim Constant *Zero32 = Builder.getInt32(0); 1029341825Sdim // Build an explicit array of two zeros for use in ConstantExpr GEP building. 1030341825Sdim Constant *TwoZero32s[] = {Zero32, Zero32}; 1031249423Sdim 1032341825Sdim SmallVector<Constant *, 8> FileInfos; 1033341825Sdim for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) { 1034341825Sdim auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i)); 1035341825Sdim 1036341825Sdim // Skip module skeleton (and module) CUs. 1037341825Sdim if (CU->getDWOId()) 1038341825Sdim continue; 1039341825Sdim 1040341825Sdim std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA); 1041341825Sdim uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i]; 1042341825Sdim auto *StartFileCallArgs = ConstantStruct::get( 1043341825Sdim StartFileCallArgsTy, {Builder.CreateGlobalStringPtr(FilenameGcda), 1044341825Sdim Builder.CreateGlobalStringPtr(ReversedVersion), 1045341825Sdim Builder.getInt32(CfgChecksum)}); 1046341825Sdim 1047341825Sdim SmallVector<Constant *, 8> EmitFunctionCallArgsArray; 1048341825Sdim SmallVector<Constant *, 8> EmitArcsCallArgsArray; 1049341825Sdim for (int j : llvm::seq<int>(0, CountersBySP.size())) { 1050341825Sdim auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second); 1051341825Sdim uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum(); 1052341825Sdim EmitFunctionCallArgsArray.push_back(ConstantStruct::get( 1053341825Sdim EmitFunctionCallArgsTy, 1054341825Sdim {Builder.getInt32(j), 1055341825Sdim Options.FunctionNamesInData 1056341825Sdim ? Builder.CreateGlobalStringPtr(getFunctionName(SP)) 1057341825Sdim : Constant::getNullValue(Builder.getInt8PtrTy()), 1058341825Sdim Builder.getInt32(FuncChecksum), 1059341825Sdim Builder.getInt8(Options.UseCfgChecksum), 1060341825Sdim Builder.getInt32(CfgChecksum)})); 1061341825Sdim 1062341825Sdim GlobalVariable *GV = CountersBySP[j].first; 1063341825Sdim unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements(); 1064341825Sdim EmitArcsCallArgsArray.push_back(ConstantStruct::get( 1065341825Sdim EmitArcsCallArgsTy, 1066341825Sdim {Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr( 1067341825Sdim GV->getValueType(), GV, TwoZero32s)})); 1068221337Sdim } 1069341825Sdim // Create global arrays for the two emit calls. 1070341825Sdim int CountersSize = CountersBySP.size(); 1071341825Sdim assert(CountersSize == (int)EmitFunctionCallArgsArray.size() && 1072341825Sdim "Mismatched array size!"); 1073341825Sdim assert(CountersSize == (int)EmitArcsCallArgsArray.size() && 1074341825Sdim "Mismatched array size!"); 1075341825Sdim auto *EmitFunctionCallArgsArrayTy = 1076341825Sdim ArrayType::get(EmitFunctionCallArgsTy, CountersSize); 1077341825Sdim auto *EmitFunctionCallArgsArrayGV = new GlobalVariable( 1078341825Sdim *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true, 1079341825Sdim GlobalValue::InternalLinkage, 1080341825Sdim ConstantArray::get(EmitFunctionCallArgsArrayTy, 1081341825Sdim EmitFunctionCallArgsArray), 1082341825Sdim Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i)); 1083341825Sdim auto *EmitArcsCallArgsArrayTy = 1084341825Sdim ArrayType::get(EmitArcsCallArgsTy, CountersSize); 1085341825Sdim EmitFunctionCallArgsArrayGV->setUnnamedAddr( 1086341825Sdim GlobalValue::UnnamedAddr::Global); 1087341825Sdim auto *EmitArcsCallArgsArrayGV = new GlobalVariable( 1088341825Sdim *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true, 1089341825Sdim GlobalValue::InternalLinkage, 1090341825Sdim ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray), 1091341825Sdim Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i)); 1092341825Sdim EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 1093341825Sdim 1094341825Sdim FileInfos.push_back(ConstantStruct::get( 1095341825Sdim FileInfoTy, 1096341825Sdim {StartFileCallArgs, Builder.getInt32(CountersSize), 1097341825Sdim ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy, 1098341825Sdim EmitFunctionCallArgsArrayGV, 1099341825Sdim TwoZero32s), 1100341825Sdim ConstantExpr::getInBoundsGetElementPtr( 1101341825Sdim EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)})); 1102221337Sdim } 1103221337Sdim 1104341825Sdim // If we didn't find anything to actually emit, bail on out. 1105341825Sdim if (FileInfos.empty()) { 1106341825Sdim Builder.CreateRetVoid(); 1107341825Sdim return WriteoutF; 1108341825Sdim } 1109341825Sdim 1110341825Sdim // To simplify code, we cap the number of file infos we write out to fit 1111341825Sdim // easily in a 32-bit signed integer. This gives consistent behavior between 1112341825Sdim // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit 1113341825Sdim // operations on 32-bit systems. It also seems unreasonable to try to handle 1114341825Sdim // more than 2 billion files. 1115341825Sdim if ((int64_t)FileInfos.size() > (int64_t)INT_MAX) 1116341825Sdim FileInfos.resize(INT_MAX); 1117341825Sdim 1118341825Sdim // Create a global for the entire data structure so we can walk it more 1119341825Sdim // easily. 1120341825Sdim auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size()); 1121341825Sdim auto *FileInfoArrayGV = new GlobalVariable( 1122341825Sdim *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, 1123341825Sdim ConstantArray::get(FileInfoArrayTy, FileInfos), 1124341825Sdim "__llvm_internal_gcov_emit_file_info"); 1125341825Sdim FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 1126341825Sdim 1127341825Sdim // Create the CFG for walking this data structure. 1128341825Sdim auto *FileLoopHeader = 1129341825Sdim BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF); 1130341825Sdim auto *CounterLoopHeader = 1131341825Sdim BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF); 1132341825Sdim auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF); 1133341825Sdim auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF); 1134341825Sdim 1135341825Sdim // We always have at least one file, so just branch to the header. 1136341825Sdim Builder.CreateBr(FileLoopHeader); 1137341825Sdim 1138341825Sdim // The index into the files structure is our loop induction variable. 1139341825Sdim Builder.SetInsertPoint(FileLoopHeader); 1140341825Sdim PHINode *IV = 1141341825Sdim Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); 1142341825Sdim IV->addIncoming(Builder.getInt32(0), BB); 1143353358Sdim auto *FileInfoPtr = Builder.CreateInBoundsGEP( 1144353358Sdim FileInfoArrayTy, FileInfoArrayGV, {Builder.getInt32(0), IV}); 1145353358Sdim auto *StartFileCallArgsPtr = 1146353358Sdim Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0); 1147341825Sdim auto *StartFileCall = Builder.CreateCall( 1148341825Sdim StartFile, 1149353358Sdim {Builder.CreateLoad(StartFileCallArgsTy->getElementType(0), 1150353358Sdim Builder.CreateStructGEP(StartFileCallArgsTy, 1151353358Sdim StartFileCallArgsPtr, 0)), 1152353358Sdim Builder.CreateLoad(StartFileCallArgsTy->getElementType(1), 1153353358Sdim Builder.CreateStructGEP(StartFileCallArgsTy, 1154353358Sdim StartFileCallArgsPtr, 1)), 1155353358Sdim Builder.CreateLoad(StartFileCallArgsTy->getElementType(2), 1156353358Sdim Builder.CreateStructGEP(StartFileCallArgsTy, 1157353358Sdim StartFileCallArgsPtr, 2))}); 1158341825Sdim if (auto AK = TLI->getExtAttrForI32Param(false)) 1159341825Sdim StartFileCall->addParamAttr(2, AK); 1160341825Sdim auto *NumCounters = 1161353358Sdim Builder.CreateLoad(FileInfoTy->getElementType(1), 1162353358Sdim Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1)); 1163341825Sdim auto *EmitFunctionCallArgsArray = 1164353358Sdim Builder.CreateLoad(FileInfoTy->getElementType(2), 1165353358Sdim Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2)); 1166341825Sdim auto *EmitArcsCallArgsArray = 1167353358Sdim Builder.CreateLoad(FileInfoTy->getElementType(3), 1168353358Sdim Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3)); 1169341825Sdim auto *EnterCounterLoopCond = 1170341825Sdim Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters); 1171341825Sdim Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch); 1172341825Sdim 1173341825Sdim Builder.SetInsertPoint(CounterLoopHeader); 1174341825Sdim auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); 1175341825Sdim JV->addIncoming(Builder.getInt32(0), FileLoopHeader); 1176353358Sdim auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP( 1177353358Sdim EmitFunctionCallArgsTy, EmitFunctionCallArgsArray, JV); 1178341825Sdim auto *EmitFunctionCall = Builder.CreateCall( 1179341825Sdim EmitFunction, 1180353358Sdim {Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(0), 1181353358Sdim Builder.CreateStructGEP(EmitFunctionCallArgsTy, 1182353358Sdim EmitFunctionCallArgsPtr, 0)), 1183353358Sdim Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(1), 1184353358Sdim Builder.CreateStructGEP(EmitFunctionCallArgsTy, 1185353358Sdim EmitFunctionCallArgsPtr, 1)), 1186353358Sdim Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(2), 1187353358Sdim Builder.CreateStructGEP(EmitFunctionCallArgsTy, 1188353358Sdim EmitFunctionCallArgsPtr, 2)), 1189353358Sdim Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(3), 1190353358Sdim Builder.CreateStructGEP(EmitFunctionCallArgsTy, 1191353358Sdim EmitFunctionCallArgsPtr, 3)), 1192353358Sdim Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(4), 1193353358Sdim Builder.CreateStructGEP(EmitFunctionCallArgsTy, 1194353358Sdim EmitFunctionCallArgsPtr, 1195353358Sdim 4))}); 1196341825Sdim if (auto AK = TLI->getExtAttrForI32Param(false)) { 1197341825Sdim EmitFunctionCall->addParamAttr(0, AK); 1198341825Sdim EmitFunctionCall->addParamAttr(2, AK); 1199341825Sdim EmitFunctionCall->addParamAttr(3, AK); 1200341825Sdim EmitFunctionCall->addParamAttr(4, AK); 1201341825Sdim } 1202341825Sdim auto *EmitArcsCallArgsPtr = 1203353358Sdim Builder.CreateInBoundsGEP(EmitArcsCallArgsTy, EmitArcsCallArgsArray, JV); 1204341825Sdim auto *EmitArcsCall = Builder.CreateCall( 1205341825Sdim EmitArcs, 1206353358Sdim {Builder.CreateLoad( 1207353358Sdim EmitArcsCallArgsTy->getElementType(0), 1208353358Sdim Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0)), 1209353358Sdim Builder.CreateLoad(EmitArcsCallArgsTy->getElementType(1), 1210353358Sdim Builder.CreateStructGEP(EmitArcsCallArgsTy, 1211353358Sdim EmitArcsCallArgsPtr, 1))}); 1212341825Sdim if (auto AK = TLI->getExtAttrForI32Param(false)) 1213341825Sdim EmitArcsCall->addParamAttr(0, AK); 1214341825Sdim auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1)); 1215341825Sdim auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters); 1216341825Sdim Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch); 1217341825Sdim JV->addIncoming(NextJV, CounterLoopHeader); 1218341825Sdim 1219341825Sdim Builder.SetInsertPoint(FileLoopLatch); 1220341825Sdim Builder.CreateCall(SummaryInfo, {}); 1221341825Sdim Builder.CreateCall(EndFile, {}); 1222341825Sdim auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1)); 1223341825Sdim auto *FileLoopCond = 1224341825Sdim Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size())); 1225341825Sdim Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB); 1226341825Sdim IV->addIncoming(NextIV, FileLoopLatch); 1227341825Sdim 1228341825Sdim Builder.SetInsertPoint(ExitBB); 1229239462Sdim Builder.CreateRetVoid(); 1230341825Sdim 1231249423Sdim return WriteoutF; 1232221337Sdim} 1233239462Sdim 1234363496SdimFunction *GCOVProfiler::insertReset( 1235363496Sdim ArrayRef<std::pair<GlobalVariable *, MDNode *>> CountersBySP) { 1236243830Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 1237363496Sdim Function *ResetF = M->getFunction("__llvm_gcov_reset"); 1238363496Sdim if (!ResetF) 1239363496Sdim ResetF = Function::Create(FTy, GlobalValue::InternalLinkage, 1240363496Sdim "__llvm_gcov_reset", M); 1241363496Sdim else 1242363496Sdim ResetF->setLinkage(GlobalValue::InternalLinkage); 1243363496Sdim ResetF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 1244363496Sdim ResetF->addFnAttr(Attribute::NoInline); 1245363496Sdim if (Options.NoRedZone) 1246363496Sdim ResetF->addFnAttr(Attribute::NoRedZone); 1247363496Sdim 1248363496Sdim BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", ResetF); 1249363496Sdim IRBuilder<> Builder(Entry); 1250363496Sdim 1251363496Sdim // Zero out the counters. 1252363496Sdim for (const auto &I : CountersBySP) { 1253363496Sdim GlobalVariable *GV = I.first; 1254363496Sdim Constant *Null = Constant::getNullValue(GV->getValueType()); 1255363496Sdim Builder.CreateStore(Null, GV); 1256363496Sdim } 1257363496Sdim 1258363496Sdim Type *RetTy = ResetF->getReturnType(); 1259363496Sdim if (RetTy->isVoidTy()) 1260363496Sdim Builder.CreateRetVoid(); 1261363496Sdim else if (RetTy->isIntegerTy()) 1262363496Sdim // Used if __llvm_gcov_reset was implicitly declared. 1263363496Sdim Builder.CreateRet(ConstantInt::get(RetTy, 0)); 1264363496Sdim else 1265363496Sdim report_fatal_error("invalid return type for __llvm_gcov_reset"); 1266363496Sdim 1267363496Sdim return ResetF; 1268363496Sdim} 1269363496Sdim 1270363496SdimFunction *GCOVProfiler::insertFlush(Function *ResetF) { 1271363496Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 1272249423Sdim Function *FlushF = M->getFunction("__llvm_gcov_flush"); 1273243830Sdim if (!FlushF) 1274243830Sdim FlushF = Function::Create(FTy, GlobalValue::InternalLinkage, 1275249423Sdim "__llvm_gcov_flush", M); 1276243830Sdim else 1277243830Sdim FlushF->setLinkage(GlobalValue::InternalLinkage); 1278309124Sdim FlushF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 1279249423Sdim FlushF->addFnAttr(Attribute::NoInline); 1280249423Sdim if (Options.NoRedZone) 1281249423Sdim FlushF->addFnAttr(Attribute::NoRedZone); 1282243830Sdim 1283243830Sdim BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF); 1284243830Sdim 1285243830Sdim // Write out the current counters. 1286353358Sdim Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); 1287243830Sdim assert(WriteoutF && "Need to create the writeout function first!"); 1288243830Sdim 1289243830Sdim IRBuilder<> Builder(Entry); 1290288943Sdim Builder.CreateCall(WriteoutF, {}); 1291363496Sdim Builder.CreateCall(ResetF, {}); 1292243830Sdim 1293243830Sdim Type *RetTy = FlushF->getReturnType(); 1294363496Sdim if (RetTy->isVoidTy()) 1295243830Sdim Builder.CreateRetVoid(); 1296243830Sdim else if (RetTy->isIntegerTy()) 1297249423Sdim // Used if __llvm_gcov_flush was implicitly declared. 1298243830Sdim Builder.CreateRet(ConstantInt::get(RetTy, 0)); 1299243830Sdim else 1300249423Sdim report_fatal_error("invalid return type for __llvm_gcov_flush"); 1301249423Sdim 1302249423Sdim return FlushF; 1303243830Sdim} 1304