1221337Sdim//===- GCOVProfiling.cpp - Insert edge counters for gcov profiling --------===// 2221337Sdim// 3221337Sdim// The LLVM Compiler Infrastructure 4221337Sdim// 5221337Sdim// This file is distributed under the University of Illinois Open Source 6221337Sdim// License. See LICENSE.TXT for details. 7221337Sdim// 8221337Sdim//===----------------------------------------------------------------------===// 9221337Sdim// 10221337Sdim// This pass implements GCOV-style profiling. When this pass is run it emits 11221337Sdim// "gcno" files next to the existing source, and instruments the code that runs 12221337Sdim// to records the edges between blocks that run and emit a complementary "gcda" 13221337Sdim// file on exit. 14221337Sdim// 15221337Sdim//===----------------------------------------------------------------------===// 16221337Sdim 17221337Sdim#define DEBUG_TYPE "insert-gcov-profiling" 18221337Sdim 19252723Sdim#include "llvm/Transforms/Instrumentation.h" 20221337Sdim#include "llvm/ADT/DenseMap.h" 21245431Sdim#include "llvm/ADT/STLExtras.h" 22221337Sdim#include "llvm/ADT/Statistic.h" 23221337Sdim#include "llvm/ADT/StringExtras.h" 24221337Sdim#include "llvm/ADT/StringMap.h" 25221337Sdim#include "llvm/ADT/UniqueVector.h" 26252723Sdim#include "llvm/DebugInfo.h" 27252723Sdim#include "llvm/IR/IRBuilder.h" 28252723Sdim#include "llvm/IR/Instructions.h" 29252723Sdim#include "llvm/IR/Module.h" 30252723Sdim#include "llvm/Pass.h" 31252723Sdim#include "llvm/Support/CommandLine.h" 32245431Sdim#include "llvm/Support/Debug.h" 33245431Sdim#include "llvm/Support/DebugLoc.h" 34252723Sdim#include "llvm/Support/FileSystem.h" 35245431Sdim#include "llvm/Support/InstIterator.h" 36263509Sdim#include "llvm/Support/Path.h" 37245431Sdim#include "llvm/Support/raw_ostream.h" 38245431Sdim#include "llvm/Transforms/Utils/ModuleUtils.h" 39263509Sdim#include <algorithm> 40221337Sdim#include <string> 41221337Sdim#include <utility> 42221337Sdimusing namespace llvm; 43221337Sdim 44252723Sdimstatic cl::opt<std::string> 45252723SdimDefaultGCOVVersion("default-gcov-version", cl::init("402*"), cl::Hidden, 46252723Sdim cl::ValueRequired); 47252723Sdim 48252723SdimGCOVOptions GCOVOptions::getDefault() { 49252723Sdim GCOVOptions Options; 50252723Sdim Options.EmitNotes = true; 51252723Sdim Options.EmitData = true; 52252723Sdim Options.UseCfgChecksum = false; 53252723Sdim Options.NoRedZone = false; 54252723Sdim Options.FunctionNamesInData = true; 55252723Sdim 56252723Sdim if (DefaultGCOVVersion.size() != 4) { 57252723Sdim llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") + 58252723Sdim DefaultGCOVVersion); 59252723Sdim } 60252723Sdim memcpy(Options.Version, DefaultGCOVVersion.c_str(), 4); 61252723Sdim return Options; 62252723Sdim} 63252723Sdim 64221337Sdimnamespace { 65221337Sdim class GCOVProfiler : public ModulePass { 66221337Sdim public: 67221337Sdim static char ID; 68252723Sdim GCOVProfiler() : ModulePass(ID), Options(GCOVOptions::getDefault()) { 69252723Sdim ReversedVersion[0] = Options.Version[3]; 70252723Sdim ReversedVersion[1] = Options.Version[2]; 71252723Sdim ReversedVersion[2] = Options.Version[1]; 72252723Sdim ReversedVersion[3] = Options.Version[0]; 73252723Sdim ReversedVersion[4] = '\0'; 74221337Sdim initializeGCOVProfilerPass(*PassRegistry::getPassRegistry()); 75221337Sdim } 76252723Sdim GCOVProfiler(const GCOVOptions &Options) : ModulePass(ID), Options(Options){ 77252723Sdim assert((Options.EmitNotes || Options.EmitData) && 78252723Sdim "GCOVProfiler asked to do nothing?"); 79252723Sdim ReversedVersion[0] = Options.Version[3]; 80252723Sdim ReversedVersion[1] = Options.Version[2]; 81252723Sdim ReversedVersion[2] = Options.Version[1]; 82252723Sdim ReversedVersion[3] = Options.Version[0]; 83252723Sdim ReversedVersion[4] = '\0'; 84221337Sdim initializeGCOVProfilerPass(*PassRegistry::getPassRegistry()); 85221337Sdim } 86221337Sdim virtual const char *getPassName() const { 87221337Sdim return "GCOV Profiler"; 88221337Sdim } 89252723Sdim 90221337Sdim private: 91223017Sdim bool runOnModule(Module &M); 92223017Sdim 93252723Sdim // Create the .gcno files for the Module based on DebugInfo. 94252723Sdim void emitProfileNotes(); 95221337Sdim 96221337Sdim // Modify the program to track transitions along edges and call into the 97221337Sdim // profiling runtime to emit .gcda files when run. 98226890Sdim bool emitProfileArcs(); 99221337Sdim 100221337Sdim // Get pointers to the functions in the runtime library. 101221337Sdim Constant *getStartFileFunc(); 102221337Sdim Constant *getIncrementIndirectCounterFunc(); 103221337Sdim Constant *getEmitFunctionFunc(); 104221337Sdim Constant *getEmitArcsFunc(); 105263509Sdim Constant *getSummaryInfoFunc(); 106252723Sdim Constant *getDeleteWriteoutFunctionListFunc(); 107252723Sdim Constant *getDeleteFlushFunctionListFunc(); 108221337Sdim Constant *getEndFileFunc(); 109221337Sdim 110221337Sdim // Create or retrieve an i32 state value that is used to represent the 111221337Sdim // pred block number for certain non-trivial edges. 112221337Sdim GlobalVariable *getEdgeStateValue(); 113221337Sdim 114221337Sdim // Produce a table of pointers to counters, by predecessor and successor 115221337Sdim // block number. 116221337Sdim GlobalVariable *buildEdgeLookupTable(Function *F, 117221337Sdim GlobalVariable *Counter, 118252723Sdim const UniqueVector<BasicBlock *>&Preds, 119252723Sdim const UniqueVector<BasicBlock*>&Succs); 120221337Sdim 121221337Sdim // Add the function to write out all our counters to the global destructor 122221337Sdim // list. 123252723Sdim Function *insertCounterWriteout(ArrayRef<std::pair<GlobalVariable*, 124252723Sdim MDNode*> >); 125252723Sdim Function *insertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> >); 126245431Sdim void insertIndirectCounterIncrement(); 127221337Sdim 128245431Sdim std::string mangleName(DICompileUnit CU, const char *NewStem); 129223017Sdim 130252723Sdim GCOVOptions Options; 131221337Sdim 132252723Sdim // Reversed, NUL-terminated copy of Options.Version. 133252723Sdim char ReversedVersion[5]; 134252723Sdim 135221337Sdim Module *M; 136221337Sdim LLVMContext *Ctx; 137221337Sdim }; 138221337Sdim} 139221337Sdim 140221337Sdimchar GCOVProfiler::ID = 0; 141221337SdimINITIALIZE_PASS(GCOVProfiler, "insert-gcov-profiling", 142221337Sdim "Insert instrumentation for GCOV profiling", false, false) 143221337Sdim 144252723SdimModulePass *llvm::createGCOVProfilerPass(const GCOVOptions &Options) { 145252723Sdim return new GCOVProfiler(Options); 146221337Sdim} 147221337Sdim 148252723Sdimstatic std::string getFunctionName(DISubprogram SP) { 149252723Sdim if (!SP.getLinkageName().empty()) 150252723Sdim return SP.getLinkageName(); 151252723Sdim return SP.getName(); 152252723Sdim} 153252723Sdim 154221337Sdimnamespace { 155221337Sdim class GCOVRecord { 156221337Sdim protected: 157263509Sdim static const char *const LinesTag; 158263509Sdim static const char *const FunctionTag; 159263509Sdim static const char *const BlockTag; 160263509Sdim static const char *const EdgeTag; 161221337Sdim 162221337Sdim GCOVRecord() {} 163221337Sdim 164221337Sdim void writeBytes(const char *Bytes, int Size) { 165221337Sdim os->write(Bytes, Size); 166221337Sdim } 167221337Sdim 168221337Sdim void write(uint32_t i) { 169221337Sdim writeBytes(reinterpret_cast<char*>(&i), 4); 170221337Sdim } 171221337Sdim 172221337Sdim // Returns the length measured in 4-byte blocks that will be used to 173221337Sdim // represent this string in a GCOV file 174263509Sdim static unsigned lengthOfGCOVString(StringRef s) { 175221337Sdim // A GCOV string is a length, followed by a NUL, then between 0 and 3 NULs 176221337Sdim // padding out to the next 4-byte word. The length is measured in 4-byte 177221337Sdim // words including padding, not bytes of actual string. 178223017Sdim return (s.size() / 4) + 1; 179221337Sdim } 180221337Sdim 181221337Sdim void writeGCOVString(StringRef s) { 182221337Sdim uint32_t Len = lengthOfGCOVString(s); 183221337Sdim write(Len); 184221337Sdim writeBytes(s.data(), s.size()); 185221337Sdim 186221337Sdim // Write 1 to 4 bytes of NUL padding. 187221337Sdim assert((unsigned)(4 - (s.size() % 4)) > 0); 188221337Sdim assert((unsigned)(4 - (s.size() % 4)) <= 4); 189221337Sdim writeBytes("\0\0\0\0", 4 - (s.size() % 4)); 190221337Sdim } 191221337Sdim 192221337Sdim raw_ostream *os; 193221337Sdim }; 194263509Sdim const char *const GCOVRecord::LinesTag = "\0\0\x45\x01"; 195263509Sdim const char *const GCOVRecord::FunctionTag = "\0\0\0\1"; 196263509Sdim const char *const GCOVRecord::BlockTag = "\0\0\x41\x01"; 197263509Sdim const char *const GCOVRecord::EdgeTag = "\0\0\x43\x01"; 198221337Sdim 199221337Sdim class GCOVFunction; 200221337Sdim class GCOVBlock; 201221337Sdim 202221337Sdim // Constructed only by requesting it from a GCOVBlock, this object stores a 203221337Sdim // list of line numbers and a single filename, representing lines that belong 204221337Sdim // to the block. 205221337Sdim class GCOVLines : public GCOVRecord { 206221337Sdim public: 207221337Sdim void addLine(uint32_t Line) { 208221337Sdim Lines.push_back(Line); 209221337Sdim } 210221337Sdim 211263509Sdim uint32_t length() const { 212235633Sdim // Here 2 = 1 for string length + 1 for '0' id#. 213221337Sdim return lengthOfGCOVString(Filename) + 2 + Lines.size(); 214221337Sdim } 215221337Sdim 216226890Sdim void writeOut() { 217226890Sdim write(0); 218226890Sdim writeGCOVString(Filename); 219226890Sdim for (int i = 0, e = Lines.size(); i != e; ++i) 220226890Sdim write(Lines[i]); 221226890Sdim } 222221337Sdim 223226890Sdim GCOVLines(StringRef F, raw_ostream *os) 224226890Sdim : Filename(F) { 225221337Sdim this->os = os; 226221337Sdim } 227221337Sdim 228226890Sdim private: 229226890Sdim StringRef Filename; 230221337Sdim SmallVector<uint32_t, 32> Lines; 231221337Sdim }; 232221337Sdim 233263509Sdim 234263509Sdim // Sorting function for deterministic behaviour in GCOVBlock::writeOut. 235263509Sdim struct StringKeySort { 236263509Sdim bool operator()(StringMapEntry<GCOVLines *> *LHS, 237263509Sdim StringMapEntry<GCOVLines *> *RHS) const { 238263509Sdim return LHS->getKey() < RHS->getKey(); 239263509Sdim } 240263509Sdim }; 241263509Sdim 242221337Sdim // Represent a basic block in GCOV. Each block has a unique number in the 243221337Sdim // function, number of lines belonging to each block, and a set of edges to 244221337Sdim // other blocks. 245221337Sdim class GCOVBlock : public GCOVRecord { 246221337Sdim public: 247226890Sdim GCOVLines &getFile(StringRef Filename) { 248221337Sdim GCOVLines *&Lines = LinesByFile[Filename]; 249221337Sdim if (!Lines) { 250221337Sdim Lines = new GCOVLines(Filename, os); 251221337Sdim } 252221337Sdim return *Lines; 253221337Sdim } 254221337Sdim 255221337Sdim void addEdge(GCOVBlock &Successor) { 256221337Sdim OutEdges.push_back(&Successor); 257221337Sdim } 258221337Sdim 259221337Sdim void writeOut() { 260221337Sdim uint32_t Len = 3; 261263509Sdim SmallVector<StringMapEntry<GCOVLines *> *, 32> SortedLinesByFile; 262221337Sdim for (StringMap<GCOVLines *>::iterator I = LinesByFile.begin(), 263221337Sdim E = LinesByFile.end(); I != E; ++I) { 264221337Sdim Len += I->second->length(); 265263509Sdim SortedLinesByFile.push_back(&*I); 266221337Sdim } 267221337Sdim 268221337Sdim writeBytes(LinesTag, 4); 269221337Sdim write(Len); 270221337Sdim write(Number); 271263509Sdim 272263509Sdim StringKeySort Sorter; 273263509Sdim std::sort(SortedLinesByFile.begin(), SortedLinesByFile.end(), Sorter); 274263509Sdim for (SmallVectorImpl<StringMapEntry<GCOVLines *> *>::iterator 275263509Sdim I = SortedLinesByFile.begin(), E = SortedLinesByFile.end(); 276263509Sdim I != E; ++I) 277263509Sdim (*I)->getValue()->writeOut(); 278221337Sdim write(0); 279221337Sdim write(0); 280221337Sdim } 281221337Sdim 282221337Sdim ~GCOVBlock() { 283221337Sdim DeleteContainerSeconds(LinesByFile); 284221337Sdim } 285221337Sdim 286221337Sdim private: 287221337Sdim friend class GCOVFunction; 288221337Sdim 289221337Sdim GCOVBlock(uint32_t Number, raw_ostream *os) 290221337Sdim : Number(Number) { 291221337Sdim this->os = os; 292221337Sdim } 293221337Sdim 294221337Sdim uint32_t Number; 295221337Sdim StringMap<GCOVLines *> LinesByFile; 296221337Sdim SmallVector<GCOVBlock *, 4> OutEdges; 297221337Sdim }; 298221337Sdim 299221337Sdim // A function has a unique identifier, a checksum (we leave as zero) and a 300221337Sdim // set of blocks and a map of edges between blocks. This is the only GCOV 301221337Sdim // object users can construct, the blocks and lines will be rooted here. 302221337Sdim class GCOVFunction : public GCOVRecord { 303221337Sdim public: 304252723Sdim GCOVFunction(DISubprogram SP, raw_ostream *os, uint32_t Ident, 305252723Sdim bool UseCfgChecksum) { 306221337Sdim this->os = os; 307221337Sdim 308221337Sdim Function *F = SP.getFunction(); 309235633Sdim DEBUG(dbgs() << "Function: " << F->getName() << "\n"); 310221337Sdim uint32_t i = 0; 311221337Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 312221337Sdim Blocks[BB] = new GCOVBlock(i++, os); 313221337Sdim } 314221337Sdim ReturnBlock = new GCOVBlock(i++, os); 315221337Sdim 316221337Sdim writeBytes(FunctionTag, 4); 317252723Sdim uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) + 318221337Sdim 1 + lengthOfGCOVString(SP.getFilename()) + 1; 319252723Sdim if (UseCfgChecksum) 320235633Sdim ++BlockLen; 321221337Sdim write(BlockLen); 322221337Sdim write(Ident); 323235633Sdim write(0); // lineno checksum 324252723Sdim if (UseCfgChecksum) 325235633Sdim write(0); // cfg checksum 326252723Sdim writeGCOVString(getFunctionName(SP)); 327221337Sdim writeGCOVString(SP.getFilename()); 328221337Sdim write(SP.getLineNumber()); 329221337Sdim } 330221337Sdim 331221337Sdim ~GCOVFunction() { 332221337Sdim DeleteContainerSeconds(Blocks); 333221337Sdim delete ReturnBlock; 334221337Sdim } 335221337Sdim 336221337Sdim GCOVBlock &getBlock(BasicBlock *BB) { 337221337Sdim return *Blocks[BB]; 338221337Sdim } 339221337Sdim 340221337Sdim GCOVBlock &getReturnBlock() { 341221337Sdim return *ReturnBlock; 342221337Sdim } 343221337Sdim 344221337Sdim void writeOut() { 345221337Sdim // Emit count of blocks. 346221337Sdim writeBytes(BlockTag, 4); 347221337Sdim write(Blocks.size() + 1); 348221337Sdim for (int i = 0, e = Blocks.size() + 1; i != e; ++i) { 349221337Sdim write(0); // No flags on our blocks. 350221337Sdim } 351235633Sdim DEBUG(dbgs() << Blocks.size() << " blocks.\n"); 352221337Sdim 353221337Sdim // Emit edges between blocks. 354263509Sdim if (Blocks.empty()) return; 355263509Sdim Function *F = Blocks.begin()->first->getParent(); 356263509Sdim for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) { 357263509Sdim GCOVBlock &Block = *Blocks[I]; 358221337Sdim if (Block.OutEdges.empty()) continue; 359221337Sdim 360221337Sdim writeBytes(EdgeTag, 4); 361221337Sdim write(Block.OutEdges.size() * 2 + 1); 362221337Sdim write(Block.Number); 363221337Sdim for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) { 364235633Sdim DEBUG(dbgs() << Block.Number << " -> " << Block.OutEdges[i]->Number 365235633Sdim << "\n"); 366221337Sdim write(Block.OutEdges[i]->Number); 367221337Sdim write(0); // no flags 368221337Sdim } 369221337Sdim } 370221337Sdim 371221337Sdim // Emit lines for each block. 372263509Sdim for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) { 373263509Sdim Blocks[I]->writeOut(); 374221337Sdim } 375221337Sdim } 376221337Sdim 377221337Sdim private: 378221337Sdim DenseMap<BasicBlock *, GCOVBlock *> Blocks; 379221337Sdim GCOVBlock *ReturnBlock; 380221337Sdim }; 381221337Sdim} 382221337Sdim 383245431Sdimstd::string GCOVProfiler::mangleName(DICompileUnit CU, const char *NewStem) { 384223017Sdim if (NamedMDNode *GCov = M->getNamedMetadata("llvm.gcov")) { 385223017Sdim for (int i = 0, e = GCov->getNumOperands(); i != e; ++i) { 386223017Sdim MDNode *N = GCov->getOperand(i); 387223017Sdim if (N->getNumOperands() != 2) continue; 388223017Sdim MDString *GCovFile = dyn_cast<MDString>(N->getOperand(0)); 389223017Sdim MDNode *CompileUnit = dyn_cast<MDNode>(N->getOperand(1)); 390223017Sdim if (!GCovFile || !CompileUnit) continue; 391223017Sdim if (CompileUnit == CU) { 392223017Sdim SmallString<128> Filename = GCovFile->getString(); 393223017Sdim sys::path::replace_extension(Filename, NewStem); 394223017Sdim return Filename.str(); 395223017Sdim } 396223017Sdim } 397223017Sdim } 398223017Sdim 399223017Sdim SmallString<128> Filename = CU.getFilename(); 400223017Sdim sys::path::replace_extension(Filename, NewStem); 401252723Sdim StringRef FName = sys::path::filename(Filename); 402252723Sdim SmallString<128> CurPath; 403252723Sdim if (sys::fs::current_path(CurPath)) return FName; 404252723Sdim sys::path::append(CurPath, FName.str()); 405252723Sdim return CurPath.str(); 406221337Sdim} 407221337Sdim 408221337Sdimbool GCOVProfiler::runOnModule(Module &M) { 409221337Sdim this->M = &M; 410221337Sdim Ctx = &M.getContext(); 411221337Sdim 412252723Sdim if (Options.EmitNotes) emitProfileNotes(); 413252723Sdim if (Options.EmitData) return emitProfileArcs(); 414221337Sdim return false; 415221337Sdim} 416221337Sdim 417252723Sdimvoid GCOVProfiler::emitProfileNotes() { 418226890Sdim NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); 419235633Sdim if (!CU_Nodes) return; 420235633Sdim 421235633Sdim for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { 422235633Sdim // Each compile unit gets its own .gcno file. This means that whether we run 423235633Sdim // this pass over the original .o's as they're produced, or run it after 424235633Sdim // LTO, we'll generate the same .gcno files. 425235633Sdim 426235633Sdim DICompileUnit CU(CU_Nodes->getOperand(i)); 427235633Sdim std::string ErrorInfo; 428235633Sdim raw_fd_ostream out(mangleName(CU, "gcno").c_str(), ErrorInfo, 429263509Sdim sys::fs::F_Binary); 430252723Sdim out.write("oncg", 4); 431252723Sdim out.write(ReversedVersion, 4); 432252723Sdim out.write("MVLL", 4); 433235633Sdim 434235633Sdim DIArray SPs = CU.getSubprograms(); 435235633Sdim for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) { 436235633Sdim DISubprogram SP(SPs.getElement(i)); 437263509Sdim assert((!SP || SP.isSubprogram()) && 438263509Sdim "A MDNode in subprograms of a CU should be null or a DISubprogram."); 439263509Sdim if (!SP) 440263509Sdim continue; 441235633Sdim 442235633Sdim Function *F = SP.getFunction(); 443235633Sdim if (!F) continue; 444252723Sdim GCOVFunction Func(SP, &out, i, Options.UseCfgChecksum); 445235633Sdim 446235633Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 447235633Sdim GCOVBlock &Block = Func.getBlock(BB); 448235633Sdim TerminatorInst *TI = BB->getTerminator(); 449235633Sdim if (int successors = TI->getNumSuccessors()) { 450235633Sdim for (int i = 0; i != successors; ++i) { 451235633Sdim Block.addEdge(Func.getBlock(TI->getSuccessor(i))); 452226890Sdim } 453235633Sdim } else if (isa<ReturnInst>(TI)) { 454235633Sdim Block.addEdge(Func.getReturnBlock()); 455221337Sdim } 456235633Sdim 457235633Sdim uint32_t Line = 0; 458235633Sdim for (BasicBlock::iterator I = BB->begin(), IE = BB->end(); 459235633Sdim I != IE; ++I) { 460235633Sdim const DebugLoc &Loc = I->getDebugLoc(); 461235633Sdim if (Loc.isUnknown()) continue; 462235633Sdim if (Line == Loc.getLine()) continue; 463235633Sdim Line = Loc.getLine(); 464235633Sdim if (SP != getDISubprogram(Loc.getScope(*Ctx))) continue; 465235633Sdim 466235633Sdim GCOVLines &Lines = Block.getFile(SP.getFilename()); 467235633Sdim Lines.addLine(Loc.getLine()); 468235633Sdim } 469221337Sdim } 470235633Sdim Func.writeOut(); 471221337Sdim } 472235633Sdim out.write("\0\0\0\0\0\0\0\0", 8); // EOF 473235633Sdim out.close(); 474221337Sdim } 475221337Sdim} 476221337Sdim 477226890Sdimbool GCOVProfiler::emitProfileArcs() { 478226890Sdim NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); 479226890Sdim if (!CU_Nodes) return false; 480221337Sdim 481226890Sdim bool Result = false; 482245431Sdim bool InsertIndCounterIncrCode = false; 483226890Sdim for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { 484226890Sdim DICompileUnit CU(CU_Nodes->getOperand(i)); 485226890Sdim DIArray SPs = CU.getSubprograms(); 486226890Sdim SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; 487226890Sdim for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) { 488226890Sdim DISubprogram SP(SPs.getElement(i)); 489263509Sdim assert((!SP || SP.isSubprogram()) && 490263509Sdim "A MDNode in subprograms of a CU should be null or a DISubprogram."); 491263509Sdim if (!SP) 492263509Sdim continue; 493226890Sdim Function *F = SP.getFunction(); 494226890Sdim if (!F) continue; 495226890Sdim if (!Result) Result = true; 496226890Sdim unsigned Edges = 0; 497226890Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 498226890Sdim TerminatorInst *TI = BB->getTerminator(); 499226890Sdim if (isa<ReturnInst>(TI)) 500226890Sdim ++Edges; 501226890Sdim else 502226890Sdim Edges += TI->getNumSuccessors(); 503226890Sdim } 504226890Sdim 505226890Sdim ArrayType *CounterTy = 506221337Sdim ArrayType::get(Type::getInt64Ty(*Ctx), Edges); 507226890Sdim GlobalVariable *Counters = 508221337Sdim new GlobalVariable(*M, CounterTy, false, 509221337Sdim GlobalValue::InternalLinkage, 510221337Sdim Constant::getNullValue(CounterTy), 511245431Sdim "__llvm_gcov_ctr"); 512226890Sdim CountersBySP.push_back(std::make_pair(Counters, (MDNode*)SP)); 513226890Sdim 514226890Sdim UniqueVector<BasicBlock *> ComplexEdgePreds; 515226890Sdim UniqueVector<BasicBlock *> ComplexEdgeSuccs; 516226890Sdim 517226890Sdim unsigned Edge = 0; 518226890Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 519226890Sdim TerminatorInst *TI = BB->getTerminator(); 520226890Sdim int Successors = isa<ReturnInst>(TI) ? 1 : TI->getNumSuccessors(); 521226890Sdim if (Successors) { 522226890Sdim if (Successors == 1) { 523263509Sdim IRBuilder<> Builder(BB->getFirstInsertionPt()); 524226890Sdim Value *Counter = Builder.CreateConstInBoundsGEP2_64(Counters, 0, 525226890Sdim Edge); 526226890Sdim Value *Count = Builder.CreateLoad(Counter); 527252723Sdim Count = Builder.CreateAdd(Count, Builder.getInt64(1)); 528226890Sdim Builder.CreateStore(Count, Counter); 529226890Sdim } else if (BranchInst *BI = dyn_cast<BranchInst>(TI)) { 530263509Sdim IRBuilder<> Builder(BI); 531252723Sdim Value *Sel = Builder.CreateSelect(BI->getCondition(), 532252723Sdim Builder.getInt64(Edge), 533252723Sdim Builder.getInt64(Edge + 1)); 534226890Sdim SmallVector<Value *, 2> Idx; 535252723Sdim Idx.push_back(Builder.getInt64(0)); 536226890Sdim Idx.push_back(Sel); 537226890Sdim Value *Counter = Builder.CreateInBoundsGEP(Counters, Idx); 538226890Sdim Value *Count = Builder.CreateLoad(Counter); 539252723Sdim Count = Builder.CreateAdd(Count, Builder.getInt64(1)); 540226890Sdim Builder.CreateStore(Count, Counter); 541226890Sdim } else { 542226890Sdim ComplexEdgePreds.insert(BB); 543226890Sdim for (int i = 0; i != Successors; ++i) 544226890Sdim ComplexEdgeSuccs.insert(TI->getSuccessor(i)); 545226890Sdim } 546263509Sdim 547226890Sdim Edge += Successors; 548221337Sdim } 549221337Sdim } 550226890Sdim 551226890Sdim if (!ComplexEdgePreds.empty()) { 552226890Sdim GlobalVariable *EdgeTable = 553221337Sdim buildEdgeLookupTable(F, Counters, 554221337Sdim ComplexEdgePreds, ComplexEdgeSuccs); 555226890Sdim GlobalVariable *EdgeState = getEdgeStateValue(); 556226890Sdim 557226890Sdim for (int i = 0, e = ComplexEdgePreds.size(); i != e; ++i) { 558263509Sdim IRBuilder<> Builder(ComplexEdgePreds[i + 1]->getFirstInsertionPt()); 559252723Sdim Builder.CreateStore(Builder.getInt32(i), EdgeState); 560226890Sdim } 561263509Sdim 562226890Sdim for (int i = 0, e = ComplexEdgeSuccs.size(); i != e; ++i) { 563263509Sdim // Call runtime to perform increment. 564263509Sdim IRBuilder<> Builder(ComplexEdgeSuccs[i+1]->getFirstInsertionPt()); 565226890Sdim Value *CounterPtrArray = 566221337Sdim Builder.CreateConstInBoundsGEP2_64(EdgeTable, 0, 567221337Sdim i * ComplexEdgePreds.size()); 568245431Sdim 569245431Sdim // Build code to increment the counter. 570245431Sdim InsertIndCounterIncrCode = true; 571226890Sdim Builder.CreateCall2(getIncrementIndirectCounterFunc(), 572226890Sdim EdgeState, CounterPtrArray); 573226890Sdim } 574221337Sdim } 575221337Sdim } 576245431Sdim 577252723Sdim Function *WriteoutF = insertCounterWriteout(CountersBySP); 578252723Sdim Function *FlushF = insertFlush(CountersBySP); 579252723Sdim 580252723Sdim // Create a small bit of code that registers the "__llvm_gcov_writeout" to 581252723Sdim // be executed at exit and the "__llvm_gcov_flush" function to be executed 582252723Sdim // when "__gcov_flush" is called. 583252723Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 584252723Sdim Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, 585252723Sdim "__llvm_gcov_init", M); 586252723Sdim F->setUnnamedAddr(true); 587252723Sdim F->setLinkage(GlobalValue::InternalLinkage); 588252723Sdim F->addFnAttr(Attribute::NoInline); 589252723Sdim if (Options.NoRedZone) 590252723Sdim F->addFnAttr(Attribute::NoRedZone); 591252723Sdim 592252723Sdim BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); 593252723Sdim IRBuilder<> Builder(BB); 594252723Sdim 595252723Sdim FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 596252723Sdim Type *Params[] = { 597252723Sdim PointerType::get(FTy, 0), 598252723Sdim PointerType::get(FTy, 0) 599252723Sdim }; 600252723Sdim FTy = FunctionType::get(Builder.getVoidTy(), Params, false); 601252723Sdim 602263509Sdim // Initialize the environment and register the local writeout and flush 603252723Sdim // functions. 604252723Sdim Constant *GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); 605252723Sdim Builder.CreateCall2(GCOVInit, WriteoutF, FlushF); 606252723Sdim Builder.CreateRetVoid(); 607252723Sdim 608252723Sdim appendToGlobalCtors(*M, F, 0); 609221337Sdim } 610245431Sdim 611245431Sdim if (InsertIndCounterIncrCode) 612245431Sdim insertIndirectCounterIncrement(); 613245431Sdim 614226890Sdim return Result; 615221337Sdim} 616221337Sdim 617221337Sdim// All edges with successors that aren't branches are "complex", because it 618221337Sdim// requires complex logic to pick which counter to update. 619221337SdimGlobalVariable *GCOVProfiler::buildEdgeLookupTable( 620221337Sdim Function *F, 621221337Sdim GlobalVariable *Counters, 622221337Sdim const UniqueVector<BasicBlock *> &Preds, 623221337Sdim const UniqueVector<BasicBlock *> &Succs) { 624221337Sdim // TODO: support invoke, threads. We rely on the fact that nothing can modify 625221337Sdim // the whole-Module pred edge# between the time we set it and the time we next 626221337Sdim // read it. Threads and invoke make this untrue. 627221337Sdim 628221337Sdim // emit [(succs * preds) x i64*], logically [succ x [pred x i64*]]. 629252723Sdim size_t TableSize = Succs.size() * Preds.size(); 630226890Sdim Type *Int64PtrTy = Type::getInt64PtrTy(*Ctx); 631252723Sdim ArrayType *EdgeTableTy = ArrayType::get(Int64PtrTy, TableSize); 632221337Sdim 633252723Sdim OwningArrayPtr<Constant *> EdgeTable(new Constant*[TableSize]); 634221337Sdim Constant *NullValue = Constant::getNullValue(Int64PtrTy); 635252723Sdim for (size_t i = 0; i != TableSize; ++i) 636221337Sdim EdgeTable[i] = NullValue; 637221337Sdim 638221337Sdim unsigned Edge = 0; 639221337Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 640221337Sdim TerminatorInst *TI = BB->getTerminator(); 641221337Sdim int Successors = isa<ReturnInst>(TI) ? 1 : TI->getNumSuccessors(); 642221337Sdim if (Successors > 1 && !isa<BranchInst>(TI) && !isa<ReturnInst>(TI)) { 643221337Sdim for (int i = 0; i != Successors; ++i) { 644221337Sdim BasicBlock *Succ = TI->getSuccessor(i); 645252723Sdim IRBuilder<> Builder(Succ); 646252723Sdim Value *Counter = Builder.CreateConstInBoundsGEP2_64(Counters, 0, 647221337Sdim Edge + i); 648221337Sdim EdgeTable[((Succs.idFor(Succ)-1) * Preds.size()) + 649221337Sdim (Preds.idFor(BB)-1)] = cast<Constant>(Counter); 650221337Sdim } 651221337Sdim } 652221337Sdim Edge += Successors; 653221337Sdim } 654221337Sdim 655252723Sdim ArrayRef<Constant*> V(&EdgeTable[0], TableSize); 656221337Sdim GlobalVariable *EdgeTableGV = 657221337Sdim new GlobalVariable( 658221337Sdim *M, EdgeTableTy, true, GlobalValue::InternalLinkage, 659224145Sdim ConstantArray::get(EdgeTableTy, V), 660221337Sdim "__llvm_gcda_edge_table"); 661221337Sdim EdgeTableGV->setUnnamedAddr(true); 662221337Sdim return EdgeTableGV; 663221337Sdim} 664221337Sdim 665221337SdimConstant *GCOVProfiler::getStartFileFunc() { 666252723Sdim Type *Args[] = { 667252723Sdim Type::getInt8PtrTy(*Ctx), // const char *orig_filename 668252723Sdim Type::getInt8PtrTy(*Ctx), // const char version[4] 669252723Sdim }; 670252723Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 671221337Sdim return M->getOrInsertFunction("llvm_gcda_start_file", FTy); 672221337Sdim} 673221337Sdim 674221337SdimConstant *GCOVProfiler::getIncrementIndirectCounterFunc() { 675245431Sdim Type *Int32Ty = Type::getInt32Ty(*Ctx); 676245431Sdim Type *Int64Ty = Type::getInt64Ty(*Ctx); 677224145Sdim Type *Args[] = { 678245431Sdim Int32Ty->getPointerTo(), // uint32_t *predecessor 679245431Sdim Int64Ty->getPointerTo()->getPointerTo() // uint64_t **counters 680221337Sdim }; 681245431Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 682245431Sdim return M->getOrInsertFunction("__llvm_gcov_indirect_counter_increment", FTy); 683221337Sdim} 684221337Sdim 685221337SdimConstant *GCOVProfiler::getEmitFunctionFunc() { 686252723Sdim Type *Args[3] = { 687223017Sdim Type::getInt32Ty(*Ctx), // uint32_t ident 688223017Sdim Type::getInt8PtrTy(*Ctx), // const char *function_name 689252723Sdim Type::getInt8Ty(*Ctx), // uint8_t use_extra_checksum 690223017Sdim }; 691245431Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 692221337Sdim return M->getOrInsertFunction("llvm_gcda_emit_function", FTy); 693221337Sdim} 694221337Sdim 695221337SdimConstant *GCOVProfiler::getEmitArcsFunc() { 696224145Sdim Type *Args[] = { 697221337Sdim Type::getInt32Ty(*Ctx), // uint32_t num_counters 698221337Sdim Type::getInt64PtrTy(*Ctx), // uint64_t *counters 699221337Sdim }; 700252723Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); 701221337Sdim return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy); 702221337Sdim} 703221337Sdim 704263509SdimConstant *GCOVProfiler::getSummaryInfoFunc() { 705263509Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 706263509Sdim return M->getOrInsertFunction("llvm_gcda_summary_info", FTy); 707263509Sdim} 708263509Sdim 709252723SdimConstant *GCOVProfiler::getDeleteWriteoutFunctionListFunc() { 710252723Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 711252723Sdim return M->getOrInsertFunction("llvm_delete_writeout_function_list", FTy); 712252723Sdim} 713252723Sdim 714252723SdimConstant *GCOVProfiler::getDeleteFlushFunctionListFunc() { 715252723Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 716252723Sdim return M->getOrInsertFunction("llvm_delete_flush_function_list", FTy); 717252723Sdim} 718252723Sdim 719221337SdimConstant *GCOVProfiler::getEndFileFunc() { 720226890Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 721221337Sdim return M->getOrInsertFunction("llvm_gcda_end_file", FTy); 722221337Sdim} 723221337Sdim 724221337SdimGlobalVariable *GCOVProfiler::getEdgeStateValue() { 725221337Sdim GlobalVariable *GV = M->getGlobalVariable("__llvm_gcov_global_state_pred"); 726221337Sdim if (!GV) { 727221337Sdim GV = new GlobalVariable(*M, Type::getInt32Ty(*Ctx), false, 728221337Sdim GlobalValue::InternalLinkage, 729221337Sdim ConstantInt::get(Type::getInt32Ty(*Ctx), 730221337Sdim 0xffffffff), 731221337Sdim "__llvm_gcov_global_state_pred"); 732221337Sdim GV->setUnnamedAddr(true); 733221337Sdim } 734221337Sdim return GV; 735221337Sdim} 736221337Sdim 737252723SdimFunction *GCOVProfiler::insertCounterWriteout( 738245431Sdim ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) { 739245431Sdim FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 740245431Sdim Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); 741245431Sdim if (!WriteoutF) 742245431Sdim WriteoutF = Function::Create(WriteoutFTy, GlobalValue::InternalLinkage, 743245431Sdim "__llvm_gcov_writeout", M); 744221337Sdim WriteoutF->setUnnamedAddr(true); 745252723Sdim WriteoutF->addFnAttr(Attribute::NoInline); 746252723Sdim if (Options.NoRedZone) 747252723Sdim WriteoutF->addFnAttr(Attribute::NoRedZone); 748245431Sdim 749245431Sdim BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF); 750221337Sdim IRBuilder<> Builder(BB); 751221337Sdim 752221337Sdim Constant *StartFile = getStartFileFunc(); 753221337Sdim Constant *EmitFunction = getEmitFunctionFunc(); 754221337Sdim Constant *EmitArcs = getEmitArcsFunc(); 755263509Sdim Constant *SummaryInfo = getSummaryInfoFunc(); 756221337Sdim Constant *EndFile = getEndFileFunc(); 757221337Sdim 758226890Sdim NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); 759226890Sdim if (CU_Nodes) { 760226890Sdim for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { 761245431Sdim DICompileUnit CU(CU_Nodes->getOperand(i)); 762245431Sdim std::string FilenameGcda = mangleName(CU, "gcda"); 763252723Sdim Builder.CreateCall2(StartFile, 764252723Sdim Builder.CreateGlobalStringPtr(FilenameGcda), 765252723Sdim Builder.CreateGlobalStringPtr(ReversedVersion)); 766252723Sdim for (unsigned j = 0, e = CountersBySP.size(); j != e; ++j) { 767252723Sdim DISubprogram SP(CountersBySP[j].second); 768252723Sdim Builder.CreateCall3( 769252723Sdim EmitFunction, Builder.getInt32(j), 770252723Sdim Options.FunctionNamesInData ? 771252723Sdim Builder.CreateGlobalStringPtr(getFunctionName(SP)) : 772252723Sdim Constant::getNullValue(Builder.getInt8PtrTy()), 773252723Sdim Builder.getInt8(Options.UseCfgChecksum)); 774252723Sdim 775252723Sdim GlobalVariable *GV = CountersBySP[j].first; 776226890Sdim unsigned Arcs = 777221337Sdim cast<ArrayType>(GV->getType()->getElementType())->getNumElements(); 778226890Sdim Builder.CreateCall2(EmitArcs, 779252723Sdim Builder.getInt32(Arcs), 780226890Sdim Builder.CreateConstGEP2_64(GV, 0, 0)); 781226890Sdim } 782263509Sdim Builder.CreateCall(SummaryInfo); 783226890Sdim Builder.CreateCall(EndFile); 784221337Sdim } 785221337Sdim } 786221337Sdim 787245431Sdim Builder.CreateRetVoid(); 788252723Sdim return WriteoutF; 789221337Sdim} 790245431Sdim 791245431Sdimvoid GCOVProfiler::insertIndirectCounterIncrement() { 792245431Sdim Function *Fn = 793245431Sdim cast<Function>(GCOVProfiler::getIncrementIndirectCounterFunc()); 794245431Sdim Fn->setUnnamedAddr(true); 795245431Sdim Fn->setLinkage(GlobalValue::InternalLinkage); 796252723Sdim Fn->addFnAttr(Attribute::NoInline); 797252723Sdim if (Options.NoRedZone) 798252723Sdim Fn->addFnAttr(Attribute::NoRedZone); 799245431Sdim 800245431Sdim // Create basic blocks for function. 801245431Sdim BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", Fn); 802245431Sdim IRBuilder<> Builder(BB); 803245431Sdim 804245431Sdim BasicBlock *PredNotNegOne = BasicBlock::Create(*Ctx, "", Fn); 805245431Sdim BasicBlock *CounterEnd = BasicBlock::Create(*Ctx, "", Fn); 806245431Sdim BasicBlock *Exit = BasicBlock::Create(*Ctx, "exit", Fn); 807245431Sdim 808245431Sdim // uint32_t pred = *predecessor; 809245431Sdim // if (pred == 0xffffffff) return; 810245431Sdim Argument *Arg = Fn->arg_begin(); 811245431Sdim Arg->setName("predecessor"); 812245431Sdim Value *Pred = Builder.CreateLoad(Arg, "pred"); 813252723Sdim Value *Cond = Builder.CreateICmpEQ(Pred, Builder.getInt32(0xffffffff)); 814245431Sdim BranchInst::Create(Exit, PredNotNegOne, Cond, BB); 815245431Sdim 816245431Sdim Builder.SetInsertPoint(PredNotNegOne); 817245431Sdim 818245431Sdim // uint64_t *counter = counters[pred]; 819245431Sdim // if (!counter) return; 820252723Sdim Value *ZExtPred = Builder.CreateZExt(Pred, Builder.getInt64Ty()); 821245431Sdim Arg = llvm::next(Fn->arg_begin()); 822245431Sdim Arg->setName("counters"); 823245431Sdim Value *GEP = Builder.CreateGEP(Arg, ZExtPred); 824245431Sdim Value *Counter = Builder.CreateLoad(GEP, "counter"); 825245431Sdim Cond = Builder.CreateICmpEQ(Counter, 826252723Sdim Constant::getNullValue( 827252723Sdim Builder.getInt64Ty()->getPointerTo())); 828245431Sdim Builder.CreateCondBr(Cond, Exit, CounterEnd); 829245431Sdim 830245431Sdim // ++*counter; 831245431Sdim Builder.SetInsertPoint(CounterEnd); 832245431Sdim Value *Add = Builder.CreateAdd(Builder.CreateLoad(Counter), 833252723Sdim Builder.getInt64(1)); 834245431Sdim Builder.CreateStore(Add, Counter); 835245431Sdim Builder.CreateBr(Exit); 836245431Sdim 837245431Sdim // Fill in the exit block. 838245431Sdim Builder.SetInsertPoint(Exit); 839245431Sdim Builder.CreateRetVoid(); 840245431Sdim} 841245431Sdim 842252723SdimFunction *GCOVProfiler:: 843245431SdiminsertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) { 844245431Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 845252723Sdim Function *FlushF = M->getFunction("__llvm_gcov_flush"); 846245431Sdim if (!FlushF) 847245431Sdim FlushF = Function::Create(FTy, GlobalValue::InternalLinkage, 848252723Sdim "__llvm_gcov_flush", M); 849245431Sdim else 850245431Sdim FlushF->setLinkage(GlobalValue::InternalLinkage); 851245431Sdim FlushF->setUnnamedAddr(true); 852252723Sdim FlushF->addFnAttr(Attribute::NoInline); 853252723Sdim if (Options.NoRedZone) 854252723Sdim FlushF->addFnAttr(Attribute::NoRedZone); 855245431Sdim 856245431Sdim BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF); 857245431Sdim 858245431Sdim // Write out the current counters. 859245431Sdim Constant *WriteoutF = M->getFunction("__llvm_gcov_writeout"); 860245431Sdim assert(WriteoutF && "Need to create the writeout function first!"); 861245431Sdim 862245431Sdim IRBuilder<> Builder(Entry); 863245431Sdim Builder.CreateCall(WriteoutF); 864245431Sdim 865245431Sdim // Zero out the counters. 866245431Sdim for (ArrayRef<std::pair<GlobalVariable *, MDNode *> >::iterator 867245431Sdim I = CountersBySP.begin(), E = CountersBySP.end(); 868245431Sdim I != E; ++I) { 869245431Sdim GlobalVariable *GV = I->first; 870245431Sdim Constant *Null = Constant::getNullValue(GV->getType()->getElementType()); 871245431Sdim Builder.CreateStore(Null, GV); 872245431Sdim } 873245431Sdim 874245431Sdim Type *RetTy = FlushF->getReturnType(); 875245431Sdim if (RetTy == Type::getVoidTy(*Ctx)) 876245431Sdim Builder.CreateRetVoid(); 877245431Sdim else if (RetTy->isIntegerTy()) 878252723Sdim // Used if __llvm_gcov_flush was implicitly declared. 879245431Sdim Builder.CreateRet(ConstantInt::get(RetTy, 0)); 880245431Sdim else 881252723Sdim report_fatal_error("invalid return type for __llvm_gcov_flush"); 882252723Sdim 883252723Sdim return FlushF; 884245431Sdim} 885