GCOVProfiling.cpp revision 234353
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 19221337Sdim#include "ProfilingUtils.h" 20221337Sdim#include "llvm/Transforms/Instrumentation.h" 21221337Sdim#include "llvm/Analysis/DebugInfo.h" 22221337Sdim#include "llvm/Module.h" 23221337Sdim#include "llvm/Pass.h" 24221337Sdim#include "llvm/Instructions.h" 25221337Sdim#include "llvm/Support/raw_ostream.h" 26221337Sdim#include "llvm/Support/Debug.h" 27221337Sdim#include "llvm/Support/DebugLoc.h" 28221337Sdim#include "llvm/Support/InstIterator.h" 29221337Sdim#include "llvm/Support/IRBuilder.h" 30221337Sdim#include "llvm/Support/PathV2.h" 31221337Sdim#include "llvm/ADT/DenseMap.h" 32221337Sdim#include "llvm/ADT/Statistic.h" 33221337Sdim#include "llvm/ADT/STLExtras.h" 34221337Sdim#include "llvm/ADT/StringExtras.h" 35221337Sdim#include "llvm/ADT/StringMap.h" 36221337Sdim#include "llvm/ADT/UniqueVector.h" 37221337Sdim#include <string> 38221337Sdim#include <utility> 39221337Sdimusing namespace llvm; 40221337Sdim 41221337Sdimnamespace { 42221337Sdim class GCOVProfiler : public ModulePass { 43221337Sdim public: 44221337Sdim static char ID; 45221337Sdim GCOVProfiler() 46234353Sdim : ModulePass(ID), EmitNotes(true), EmitData(true), Use402Format(false), 47234353Sdim UseExtraChecksum(false) { 48221337Sdim initializeGCOVProfilerPass(*PassRegistry::getPassRegistry()); 49221337Sdim } 50234353Sdim GCOVProfiler(bool EmitNotes, bool EmitData, bool use402Format = false, 51234353Sdim bool useExtraChecksum = false) 52223017Sdim : ModulePass(ID), EmitNotes(EmitNotes), EmitData(EmitData), 53234353Sdim Use402Format(use402Format), UseExtraChecksum(useExtraChecksum) { 54221337Sdim assert((EmitNotes || EmitData) && "GCOVProfiler asked to do nothing?"); 55221337Sdim initializeGCOVProfilerPass(*PassRegistry::getPassRegistry()); 56221337Sdim } 57221337Sdim virtual const char *getPassName() const { 58221337Sdim return "GCOV Profiler"; 59221337Sdim } 60221337Sdim 61221337Sdim private: 62223017Sdim bool runOnModule(Module &M); 63223017Sdim 64221337Sdim // Create the GCNO files for the Module based on DebugInfo. 65226633Sdim void emitGCNO(); 66221337Sdim 67221337Sdim // Modify the program to track transitions along edges and call into the 68221337Sdim // profiling runtime to emit .gcda files when run. 69226633Sdim bool emitProfileArcs(); 70221337Sdim 71221337Sdim // Get pointers to the functions in the runtime library. 72221337Sdim Constant *getStartFileFunc(); 73221337Sdim Constant *getIncrementIndirectCounterFunc(); 74221337Sdim Constant *getEmitFunctionFunc(); 75221337Sdim Constant *getEmitArcsFunc(); 76221337Sdim Constant *getEndFileFunc(); 77221337Sdim 78221337Sdim // Create or retrieve an i32 state value that is used to represent the 79221337Sdim // pred block number for certain non-trivial edges. 80221337Sdim GlobalVariable *getEdgeStateValue(); 81221337Sdim 82221337Sdim // Produce a table of pointers to counters, by predecessor and successor 83221337Sdim // block number. 84221337Sdim GlobalVariable *buildEdgeLookupTable(Function *F, 85221337Sdim GlobalVariable *Counter, 86221337Sdim const UniqueVector<BasicBlock *> &Preds, 87221337Sdim const UniqueVector<BasicBlock *> &Succs); 88221337Sdim 89221337Sdim // Add the function to write out all our counters to the global destructor 90221337Sdim // list. 91226633Sdim void insertCounterWriteout(SmallVector<std::pair<GlobalVariable *, 92223017Sdim MDNode *>, 8> &); 93221337Sdim 94223017Sdim std::string mangleName(DICompileUnit CU, std::string NewStem); 95223017Sdim 96221337Sdim bool EmitNotes; 97221337Sdim bool EmitData; 98223017Sdim bool Use402Format; 99234353Sdim bool UseExtraChecksum; 100221337Sdim 101221337Sdim Module *M; 102221337Sdim LLVMContext *Ctx; 103221337Sdim }; 104221337Sdim} 105221337Sdim 106221337Sdimchar GCOVProfiler::ID = 0; 107221337SdimINITIALIZE_PASS(GCOVProfiler, "insert-gcov-profiling", 108221337Sdim "Insert instrumentation for GCOV profiling", false, false) 109221337Sdim 110223017SdimModulePass *llvm::createGCOVProfilerPass(bool EmitNotes, bool EmitData, 111234353Sdim bool Use402Format, 112234353Sdim bool UseExtraChecksum) { 113234353Sdim return new GCOVProfiler(EmitNotes, EmitData, Use402Format, UseExtraChecksum); 114221337Sdim} 115221337Sdim 116221337Sdimnamespace { 117221337Sdim class GCOVRecord { 118221337Sdim protected: 119221337Sdim static const char *LinesTag; 120221337Sdim static const char *FunctionTag; 121221337Sdim static const char *BlockTag; 122221337Sdim static const char *EdgeTag; 123221337Sdim 124221337Sdim GCOVRecord() {} 125221337Sdim 126221337Sdim void writeBytes(const char *Bytes, int Size) { 127221337Sdim os->write(Bytes, Size); 128221337Sdim } 129221337Sdim 130221337Sdim void write(uint32_t i) { 131221337Sdim writeBytes(reinterpret_cast<char*>(&i), 4); 132221337Sdim } 133221337Sdim 134221337Sdim // Returns the length measured in 4-byte blocks that will be used to 135221337Sdim // represent this string in a GCOV file 136221337Sdim unsigned lengthOfGCOVString(StringRef s) { 137221337Sdim // A GCOV string is a length, followed by a NUL, then between 0 and 3 NULs 138221337Sdim // padding out to the next 4-byte word. The length is measured in 4-byte 139221337Sdim // words including padding, not bytes of actual string. 140223017Sdim return (s.size() / 4) + 1; 141221337Sdim } 142221337Sdim 143221337Sdim void writeGCOVString(StringRef s) { 144221337Sdim uint32_t Len = lengthOfGCOVString(s); 145221337Sdim write(Len); 146221337Sdim writeBytes(s.data(), s.size()); 147221337Sdim 148221337Sdim // Write 1 to 4 bytes of NUL padding. 149221337Sdim assert((unsigned)(4 - (s.size() % 4)) > 0); 150221337Sdim assert((unsigned)(4 - (s.size() % 4)) <= 4); 151221337Sdim writeBytes("\0\0\0\0", 4 - (s.size() % 4)); 152221337Sdim } 153221337Sdim 154221337Sdim raw_ostream *os; 155221337Sdim }; 156221337Sdim const char *GCOVRecord::LinesTag = "\0\0\x45\x01"; 157221337Sdim const char *GCOVRecord::FunctionTag = "\0\0\0\1"; 158221337Sdim const char *GCOVRecord::BlockTag = "\0\0\x41\x01"; 159221337Sdim const char *GCOVRecord::EdgeTag = "\0\0\x43\x01"; 160221337Sdim 161221337Sdim class GCOVFunction; 162221337Sdim class GCOVBlock; 163221337Sdim 164221337Sdim // Constructed only by requesting it from a GCOVBlock, this object stores a 165221337Sdim // list of line numbers and a single filename, representing lines that belong 166221337Sdim // to the block. 167221337Sdim class GCOVLines : public GCOVRecord { 168221337Sdim public: 169221337Sdim void addLine(uint32_t Line) { 170221337Sdim Lines.push_back(Line); 171221337Sdim } 172221337Sdim 173221337Sdim uint32_t length() { 174234353Sdim // Here 2 = 1 for string length + 1 for '0' id#. 175221337Sdim return lengthOfGCOVString(Filename) + 2 + Lines.size(); 176221337Sdim } 177221337Sdim 178226633Sdim void writeOut() { 179226633Sdim write(0); 180226633Sdim writeGCOVString(Filename); 181226633Sdim for (int i = 0, e = Lines.size(); i != e; ++i) 182226633Sdim write(Lines[i]); 183226633Sdim } 184221337Sdim 185226633Sdim GCOVLines(StringRef F, raw_ostream *os) 186226633Sdim : Filename(F) { 187221337Sdim this->os = os; 188221337Sdim } 189221337Sdim 190226633Sdim private: 191226633Sdim StringRef Filename; 192221337Sdim SmallVector<uint32_t, 32> Lines; 193221337Sdim }; 194221337Sdim 195221337Sdim // Represent a basic block in GCOV. Each block has a unique number in the 196221337Sdim // function, number of lines belonging to each block, and a set of edges to 197221337Sdim // other blocks. 198221337Sdim class GCOVBlock : public GCOVRecord { 199221337Sdim public: 200226633Sdim GCOVLines &getFile(StringRef Filename) { 201221337Sdim GCOVLines *&Lines = LinesByFile[Filename]; 202221337Sdim if (!Lines) { 203221337Sdim Lines = new GCOVLines(Filename, os); 204221337Sdim } 205221337Sdim return *Lines; 206221337Sdim } 207221337Sdim 208221337Sdim void addEdge(GCOVBlock &Successor) { 209221337Sdim OutEdges.push_back(&Successor); 210221337Sdim } 211221337Sdim 212221337Sdim void writeOut() { 213221337Sdim uint32_t Len = 3; 214221337Sdim for (StringMap<GCOVLines *>::iterator I = LinesByFile.begin(), 215221337Sdim E = LinesByFile.end(); I != E; ++I) { 216221337Sdim Len += I->second->length(); 217221337Sdim } 218221337Sdim 219221337Sdim writeBytes(LinesTag, 4); 220221337Sdim write(Len); 221221337Sdim write(Number); 222221337Sdim for (StringMap<GCOVLines *>::iterator I = LinesByFile.begin(), 223226633Sdim E = LinesByFile.end(); I != E; ++I) 224226633Sdim I->second->writeOut(); 225221337Sdim write(0); 226221337Sdim write(0); 227221337Sdim } 228221337Sdim 229221337Sdim ~GCOVBlock() { 230221337Sdim DeleteContainerSeconds(LinesByFile); 231221337Sdim } 232221337Sdim 233221337Sdim private: 234221337Sdim friend class GCOVFunction; 235221337Sdim 236221337Sdim GCOVBlock(uint32_t Number, raw_ostream *os) 237221337Sdim : Number(Number) { 238221337Sdim this->os = os; 239221337Sdim } 240221337Sdim 241221337Sdim uint32_t Number; 242221337Sdim StringMap<GCOVLines *> LinesByFile; 243221337Sdim SmallVector<GCOVBlock *, 4> OutEdges; 244221337Sdim }; 245221337Sdim 246221337Sdim // A function has a unique identifier, a checksum (we leave as zero) and a 247221337Sdim // set of blocks and a map of edges between blocks. This is the only GCOV 248221337Sdim // object users can construct, the blocks and lines will be rooted here. 249221337Sdim class GCOVFunction : public GCOVRecord { 250221337Sdim public: 251234353Sdim GCOVFunction(DISubprogram SP, raw_ostream *os, 252234353Sdim bool Use402Format, bool UseExtraChecksum) { 253221337Sdim this->os = os; 254221337Sdim 255221337Sdim Function *F = SP.getFunction(); 256234353Sdim DEBUG(dbgs() << "Function: " << F->getName() << "\n"); 257221337Sdim uint32_t i = 0; 258221337Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 259221337Sdim Blocks[BB] = new GCOVBlock(i++, os); 260221337Sdim } 261221337Sdim ReturnBlock = new GCOVBlock(i++, os); 262221337Sdim 263221337Sdim writeBytes(FunctionTag, 4); 264221337Sdim uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(SP.getName()) + 265221337Sdim 1 + lengthOfGCOVString(SP.getFilename()) + 1; 266234353Sdim if (UseExtraChecksum) 267234353Sdim ++BlockLen; 268221337Sdim write(BlockLen); 269221337Sdim uint32_t Ident = reinterpret_cast<intptr_t>((MDNode*)SP); 270221337Sdim write(Ident); 271234353Sdim write(0); // lineno checksum 272234353Sdim if (UseExtraChecksum) 273234353Sdim write(0); // cfg checksum 274221337Sdim writeGCOVString(SP.getName()); 275221337Sdim writeGCOVString(SP.getFilename()); 276221337Sdim write(SP.getLineNumber()); 277221337Sdim } 278221337Sdim 279221337Sdim ~GCOVFunction() { 280221337Sdim DeleteContainerSeconds(Blocks); 281221337Sdim delete ReturnBlock; 282221337Sdim } 283221337Sdim 284221337Sdim GCOVBlock &getBlock(BasicBlock *BB) { 285221337Sdim return *Blocks[BB]; 286221337Sdim } 287221337Sdim 288221337Sdim GCOVBlock &getReturnBlock() { 289221337Sdim return *ReturnBlock; 290221337Sdim } 291221337Sdim 292221337Sdim void writeOut() { 293221337Sdim // Emit count of blocks. 294221337Sdim writeBytes(BlockTag, 4); 295221337Sdim write(Blocks.size() + 1); 296221337Sdim for (int i = 0, e = Blocks.size() + 1; i != e; ++i) { 297221337Sdim write(0); // No flags on our blocks. 298221337Sdim } 299234353Sdim DEBUG(dbgs() << Blocks.size() << " blocks.\n"); 300221337Sdim 301221337Sdim // Emit edges between blocks. 302221337Sdim for (DenseMap<BasicBlock *, GCOVBlock *>::iterator I = Blocks.begin(), 303221337Sdim E = Blocks.end(); I != E; ++I) { 304221337Sdim GCOVBlock &Block = *I->second; 305221337Sdim if (Block.OutEdges.empty()) continue; 306221337Sdim 307221337Sdim writeBytes(EdgeTag, 4); 308221337Sdim write(Block.OutEdges.size() * 2 + 1); 309221337Sdim write(Block.Number); 310221337Sdim for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) { 311234353Sdim DEBUG(dbgs() << Block.Number << " -> " << Block.OutEdges[i]->Number 312234353Sdim << "\n"); 313221337Sdim write(Block.OutEdges[i]->Number); 314221337Sdim write(0); // no flags 315221337Sdim } 316221337Sdim } 317221337Sdim 318221337Sdim // Emit lines for each block. 319221337Sdim for (DenseMap<BasicBlock *, GCOVBlock *>::iterator I = Blocks.begin(), 320221337Sdim E = Blocks.end(); I != E; ++I) { 321221337Sdim I->second->writeOut(); 322221337Sdim } 323221337Sdim } 324221337Sdim 325221337Sdim private: 326221337Sdim DenseMap<BasicBlock *, GCOVBlock *> Blocks; 327221337Sdim GCOVBlock *ReturnBlock; 328221337Sdim }; 329221337Sdim} 330221337Sdim 331223017Sdimstd::string GCOVProfiler::mangleName(DICompileUnit CU, std::string NewStem) { 332223017Sdim if (NamedMDNode *GCov = M->getNamedMetadata("llvm.gcov")) { 333223017Sdim for (int i = 0, e = GCov->getNumOperands(); i != e; ++i) { 334223017Sdim MDNode *N = GCov->getOperand(i); 335223017Sdim if (N->getNumOperands() != 2) continue; 336223017Sdim MDString *GCovFile = dyn_cast<MDString>(N->getOperand(0)); 337223017Sdim MDNode *CompileUnit = dyn_cast<MDNode>(N->getOperand(1)); 338223017Sdim if (!GCovFile || !CompileUnit) continue; 339223017Sdim if (CompileUnit == CU) { 340223017Sdim SmallString<128> Filename = GCovFile->getString(); 341223017Sdim sys::path::replace_extension(Filename, NewStem); 342223017Sdim return Filename.str(); 343223017Sdim } 344223017Sdim } 345223017Sdim } 346223017Sdim 347223017Sdim SmallString<128> Filename = CU.getFilename(); 348223017Sdim sys::path::replace_extension(Filename, NewStem); 349223017Sdim return sys::path::filename(Filename.str()); 350221337Sdim} 351221337Sdim 352221337Sdimbool GCOVProfiler::runOnModule(Module &M) { 353221337Sdim this->M = &M; 354221337Sdim Ctx = &M.getContext(); 355221337Sdim 356226633Sdim if (EmitNotes) emitGCNO(); 357226633Sdim if (EmitData) return emitProfileArcs(); 358221337Sdim return false; 359221337Sdim} 360221337Sdim 361226633Sdimvoid GCOVProfiler::emitGCNO() { 362226633Sdim NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); 363234353Sdim if (!CU_Nodes) return; 364234353Sdim 365234353Sdim for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { 366234353Sdim // Each compile unit gets its own .gcno file. This means that whether we run 367234353Sdim // this pass over the original .o's as they're produced, or run it after 368234353Sdim // LTO, we'll generate the same .gcno files. 369234353Sdim 370234353Sdim DICompileUnit CU(CU_Nodes->getOperand(i)); 371234353Sdim std::string ErrorInfo; 372234353Sdim raw_fd_ostream out(mangleName(CU, "gcno").c_str(), ErrorInfo, 373234353Sdim raw_fd_ostream::F_Binary); 374234353Sdim if (!Use402Format) 375234353Sdim out.write("oncg*404MVLL", 12); 376234353Sdim else 377234353Sdim out.write("oncg*204MVLL", 12); 378234353Sdim 379234353Sdim DIArray SPs = CU.getSubprograms(); 380234353Sdim for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) { 381234353Sdim DISubprogram SP(SPs.getElement(i)); 382234353Sdim if (!SP.Verify()) continue; 383234353Sdim 384234353Sdim Function *F = SP.getFunction(); 385234353Sdim if (!F) continue; 386234353Sdim GCOVFunction Func(SP, &out, Use402Format, UseExtraChecksum); 387234353Sdim 388234353Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 389234353Sdim GCOVBlock &Block = Func.getBlock(BB); 390234353Sdim TerminatorInst *TI = BB->getTerminator(); 391234353Sdim if (int successors = TI->getNumSuccessors()) { 392234353Sdim for (int i = 0; i != successors; ++i) { 393234353Sdim Block.addEdge(Func.getBlock(TI->getSuccessor(i))); 394226633Sdim } 395234353Sdim } else if (isa<ReturnInst>(TI)) { 396234353Sdim Block.addEdge(Func.getReturnBlock()); 397221337Sdim } 398234353Sdim 399234353Sdim uint32_t Line = 0; 400234353Sdim for (BasicBlock::iterator I = BB->begin(), IE = BB->end(); 401234353Sdim I != IE; ++I) { 402234353Sdim const DebugLoc &Loc = I->getDebugLoc(); 403234353Sdim if (Loc.isUnknown()) continue; 404234353Sdim if (Line == Loc.getLine()) continue; 405234353Sdim Line = Loc.getLine(); 406234353Sdim if (SP != getDISubprogram(Loc.getScope(*Ctx))) continue; 407234353Sdim 408234353Sdim GCOVLines &Lines = Block.getFile(SP.getFilename()); 409234353Sdim Lines.addLine(Loc.getLine()); 410234353Sdim } 411221337Sdim } 412234353Sdim Func.writeOut(); 413221337Sdim } 414234353Sdim out.write("\0\0\0\0\0\0\0\0", 8); // EOF 415234353Sdim out.close(); 416221337Sdim } 417221337Sdim} 418221337Sdim 419226633Sdimbool GCOVProfiler::emitProfileArcs() { 420226633Sdim NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); 421226633Sdim if (!CU_Nodes) return false; 422221337Sdim 423226633Sdim bool Result = false; 424226633Sdim for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { 425226633Sdim DICompileUnit CU(CU_Nodes->getOperand(i)); 426226633Sdim DIArray SPs = CU.getSubprograms(); 427226633Sdim SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; 428226633Sdim for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) { 429226633Sdim DISubprogram SP(SPs.getElement(i)); 430226633Sdim if (!SP.Verify()) continue; 431226633Sdim Function *F = SP.getFunction(); 432226633Sdim if (!F) continue; 433226633Sdim if (!Result) Result = true; 434226633Sdim unsigned Edges = 0; 435226633Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 436226633Sdim TerminatorInst *TI = BB->getTerminator(); 437226633Sdim if (isa<ReturnInst>(TI)) 438226633Sdim ++Edges; 439226633Sdim else 440226633Sdim Edges += TI->getNumSuccessors(); 441226633Sdim } 442226633Sdim 443226633Sdim ArrayType *CounterTy = 444221337Sdim ArrayType::get(Type::getInt64Ty(*Ctx), Edges); 445226633Sdim GlobalVariable *Counters = 446221337Sdim new GlobalVariable(*M, CounterTy, false, 447221337Sdim GlobalValue::InternalLinkage, 448221337Sdim Constant::getNullValue(CounterTy), 449221337Sdim "__llvm_gcov_ctr", 0, false, 0); 450226633Sdim CountersBySP.push_back(std::make_pair(Counters, (MDNode*)SP)); 451226633Sdim 452226633Sdim UniqueVector<BasicBlock *> ComplexEdgePreds; 453226633Sdim UniqueVector<BasicBlock *> ComplexEdgeSuccs; 454226633Sdim 455226633Sdim unsigned Edge = 0; 456226633Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 457226633Sdim TerminatorInst *TI = BB->getTerminator(); 458226633Sdim int Successors = isa<ReturnInst>(TI) ? 1 : TI->getNumSuccessors(); 459226633Sdim if (Successors) { 460226633Sdim IRBuilder<> Builder(TI); 461226633Sdim 462226633Sdim if (Successors == 1) { 463226633Sdim Value *Counter = Builder.CreateConstInBoundsGEP2_64(Counters, 0, 464226633Sdim Edge); 465226633Sdim Value *Count = Builder.CreateLoad(Counter); 466226633Sdim Count = Builder.CreateAdd(Count, 467226633Sdim ConstantInt::get(Type::getInt64Ty(*Ctx),1)); 468226633Sdim Builder.CreateStore(Count, Counter); 469226633Sdim } else if (BranchInst *BI = dyn_cast<BranchInst>(TI)) { 470226633Sdim Value *Sel = Builder.CreateSelect( 471221337Sdim BI->getCondition(), 472221337Sdim ConstantInt::get(Type::getInt64Ty(*Ctx), Edge), 473221337Sdim ConstantInt::get(Type::getInt64Ty(*Ctx), Edge + 1)); 474226633Sdim SmallVector<Value *, 2> Idx; 475226633Sdim Idx.push_back(Constant::getNullValue(Type::getInt64Ty(*Ctx))); 476226633Sdim Idx.push_back(Sel); 477226633Sdim Value *Counter = Builder.CreateInBoundsGEP(Counters, Idx); 478226633Sdim Value *Count = Builder.CreateLoad(Counter); 479226633Sdim Count = Builder.CreateAdd(Count, 480226633Sdim ConstantInt::get(Type::getInt64Ty(*Ctx),1)); 481226633Sdim Builder.CreateStore(Count, Counter); 482226633Sdim } else { 483226633Sdim ComplexEdgePreds.insert(BB); 484226633Sdim for (int i = 0; i != Successors; ++i) 485226633Sdim ComplexEdgeSuccs.insert(TI->getSuccessor(i)); 486226633Sdim } 487226633Sdim Edge += Successors; 488221337Sdim } 489221337Sdim } 490226633Sdim 491226633Sdim if (!ComplexEdgePreds.empty()) { 492226633Sdim GlobalVariable *EdgeTable = 493221337Sdim buildEdgeLookupTable(F, Counters, 494221337Sdim ComplexEdgePreds, ComplexEdgeSuccs); 495226633Sdim GlobalVariable *EdgeState = getEdgeStateValue(); 496226633Sdim 497226633Sdim Type *Int32Ty = Type::getInt32Ty(*Ctx); 498226633Sdim for (int i = 0, e = ComplexEdgePreds.size(); i != e; ++i) { 499226633Sdim IRBuilder<> Builder(ComplexEdgePreds[i+1]->getTerminator()); 500226633Sdim Builder.CreateStore(ConstantInt::get(Int32Ty, i), EdgeState); 501226633Sdim } 502226633Sdim for (int i = 0, e = ComplexEdgeSuccs.size(); i != e; ++i) { 503226633Sdim // call runtime to perform increment 504226633Sdim BasicBlock::iterator InsertPt = 505226633Sdim ComplexEdgeSuccs[i+1]->getFirstInsertionPt(); 506226633Sdim IRBuilder<> Builder(InsertPt); 507226633Sdim Value *CounterPtrArray = 508221337Sdim Builder.CreateConstInBoundsGEP2_64(EdgeTable, 0, 509221337Sdim i * ComplexEdgePreds.size()); 510226633Sdim Builder.CreateCall2(getIncrementIndirectCounterFunc(), 511226633Sdim EdgeState, CounterPtrArray); 512226633Sdim // clear the predecessor number 513226633Sdim Builder.CreateStore(ConstantInt::get(Int32Ty, 0xffffffff), EdgeState); 514226633Sdim } 515221337Sdim } 516221337Sdim } 517226633Sdim insertCounterWriteout(CountersBySP); 518221337Sdim } 519226633Sdim return Result; 520221337Sdim} 521221337Sdim 522221337Sdim// All edges with successors that aren't branches are "complex", because it 523221337Sdim// requires complex logic to pick which counter to update. 524221337SdimGlobalVariable *GCOVProfiler::buildEdgeLookupTable( 525221337Sdim Function *F, 526221337Sdim GlobalVariable *Counters, 527221337Sdim const UniqueVector<BasicBlock *> &Preds, 528221337Sdim const UniqueVector<BasicBlock *> &Succs) { 529221337Sdim // TODO: support invoke, threads. We rely on the fact that nothing can modify 530221337Sdim // the whole-Module pred edge# between the time we set it and the time we next 531221337Sdim // read it. Threads and invoke make this untrue. 532221337Sdim 533221337Sdim // emit [(succs * preds) x i64*], logically [succ x [pred x i64*]]. 534226633Sdim Type *Int64PtrTy = Type::getInt64PtrTy(*Ctx); 535226633Sdim ArrayType *EdgeTableTy = ArrayType::get( 536221337Sdim Int64PtrTy, Succs.size() * Preds.size()); 537221337Sdim 538221337Sdim Constant **EdgeTable = new Constant*[Succs.size() * Preds.size()]; 539221337Sdim Constant *NullValue = Constant::getNullValue(Int64PtrTy); 540221337Sdim for (int i = 0, ie = Succs.size() * Preds.size(); i != ie; ++i) 541221337Sdim EdgeTable[i] = NullValue; 542221337Sdim 543221337Sdim unsigned Edge = 0; 544221337Sdim for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { 545221337Sdim TerminatorInst *TI = BB->getTerminator(); 546221337Sdim int Successors = isa<ReturnInst>(TI) ? 1 : TI->getNumSuccessors(); 547221337Sdim if (Successors > 1 && !isa<BranchInst>(TI) && !isa<ReturnInst>(TI)) { 548221337Sdim for (int i = 0; i != Successors; ++i) { 549221337Sdim BasicBlock *Succ = TI->getSuccessor(i); 550221337Sdim IRBuilder<> builder(Succ); 551221337Sdim Value *Counter = builder.CreateConstInBoundsGEP2_64(Counters, 0, 552221337Sdim Edge + i); 553221337Sdim EdgeTable[((Succs.idFor(Succ)-1) * Preds.size()) + 554221337Sdim (Preds.idFor(BB)-1)] = cast<Constant>(Counter); 555221337Sdim } 556221337Sdim } 557221337Sdim Edge += Successors; 558221337Sdim } 559221337Sdim 560224145Sdim ArrayRef<Constant*> V(&EdgeTable[0], Succs.size() * Preds.size()); 561221337Sdim GlobalVariable *EdgeTableGV = 562221337Sdim new GlobalVariable( 563221337Sdim *M, EdgeTableTy, true, GlobalValue::InternalLinkage, 564224145Sdim ConstantArray::get(EdgeTableTy, V), 565221337Sdim "__llvm_gcda_edge_table"); 566221337Sdim EdgeTableGV->setUnnamedAddr(true); 567221337Sdim return EdgeTableGV; 568221337Sdim} 569221337Sdim 570221337SdimConstant *GCOVProfiler::getStartFileFunc() { 571226633Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), 572224145Sdim Type::getInt8PtrTy(*Ctx), false); 573221337Sdim return M->getOrInsertFunction("llvm_gcda_start_file", FTy); 574221337Sdim} 575221337Sdim 576221337SdimConstant *GCOVProfiler::getIncrementIndirectCounterFunc() { 577224145Sdim Type *Args[] = { 578221337Sdim Type::getInt32PtrTy(*Ctx), // uint32_t *predecessor 579221337Sdim Type::getInt64PtrTy(*Ctx)->getPointerTo(), // uint64_t **state_table_row 580221337Sdim }; 581226633Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), 582221337Sdim Args, false); 583221337Sdim return M->getOrInsertFunction("llvm_gcda_increment_indirect_counter", FTy); 584221337Sdim} 585221337Sdim 586221337SdimConstant *GCOVProfiler::getEmitFunctionFunc() { 587224145Sdim Type *Args[2] = { 588223017Sdim Type::getInt32Ty(*Ctx), // uint32_t ident 589223017Sdim Type::getInt8PtrTy(*Ctx), // const char *function_name 590223017Sdim }; 591226633Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), 592221337Sdim Args, false); 593221337Sdim return M->getOrInsertFunction("llvm_gcda_emit_function", FTy); 594221337Sdim} 595221337Sdim 596221337SdimConstant *GCOVProfiler::getEmitArcsFunc() { 597224145Sdim Type *Args[] = { 598221337Sdim Type::getInt32Ty(*Ctx), // uint32_t num_counters 599221337Sdim Type::getInt64PtrTy(*Ctx), // uint64_t *counters 600221337Sdim }; 601226633Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), 602221337Sdim Args, false); 603221337Sdim return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy); 604221337Sdim} 605221337Sdim 606221337SdimConstant *GCOVProfiler::getEndFileFunc() { 607226633Sdim FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); 608221337Sdim return M->getOrInsertFunction("llvm_gcda_end_file", FTy); 609221337Sdim} 610221337Sdim 611221337SdimGlobalVariable *GCOVProfiler::getEdgeStateValue() { 612221337Sdim GlobalVariable *GV = M->getGlobalVariable("__llvm_gcov_global_state_pred"); 613221337Sdim if (!GV) { 614221337Sdim GV = new GlobalVariable(*M, Type::getInt32Ty(*Ctx), false, 615221337Sdim GlobalValue::InternalLinkage, 616221337Sdim ConstantInt::get(Type::getInt32Ty(*Ctx), 617221337Sdim 0xffffffff), 618221337Sdim "__llvm_gcov_global_state_pred"); 619221337Sdim GV->setUnnamedAddr(true); 620221337Sdim } 621221337Sdim return GV; 622221337Sdim} 623221337Sdim 624221337Sdimvoid GCOVProfiler::insertCounterWriteout( 625223017Sdim SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> &CountersBySP) { 626226633Sdim FunctionType *WriteoutFTy = 627221337Sdim FunctionType::get(Type::getVoidTy(*Ctx), false); 628221337Sdim Function *WriteoutF = Function::Create(WriteoutFTy, 629221337Sdim GlobalValue::InternalLinkage, 630221337Sdim "__llvm_gcov_writeout", M); 631221337Sdim WriteoutF->setUnnamedAddr(true); 632221337Sdim BasicBlock *BB = BasicBlock::Create(*Ctx, "", WriteoutF); 633221337Sdim IRBuilder<> Builder(BB); 634221337Sdim 635221337Sdim Constant *StartFile = getStartFileFunc(); 636221337Sdim Constant *EmitFunction = getEmitFunctionFunc(); 637221337Sdim Constant *EmitArcs = getEmitArcsFunc(); 638221337Sdim Constant *EndFile = getEndFileFunc(); 639221337Sdim 640226633Sdim NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); 641226633Sdim if (CU_Nodes) { 642226633Sdim for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { 643226633Sdim DICompileUnit compile_unit(CU_Nodes->getOperand(i)); 644226633Sdim std::string FilenameGcda = mangleName(compile_unit, "gcda"); 645226633Sdim Builder.CreateCall(StartFile, 646226633Sdim Builder.CreateGlobalStringPtr(FilenameGcda)); 647226633Sdim for (SmallVector<std::pair<GlobalVariable *, MDNode *>, 8>::iterator 648223017Sdim I = CountersBySP.begin(), E = CountersBySP.end(); 649226633Sdim I != E; ++I) { 650226633Sdim DISubprogram SP(I->second); 651226633Sdim intptr_t ident = reinterpret_cast<intptr_t>(I->second); 652226633Sdim Builder.CreateCall2(EmitFunction, 653226633Sdim ConstantInt::get(Type::getInt32Ty(*Ctx), ident), 654226633Sdim Builder.CreateGlobalStringPtr(SP.getName())); 655226633Sdim 656226633Sdim GlobalVariable *GV = I->first; 657226633Sdim unsigned Arcs = 658221337Sdim cast<ArrayType>(GV->getType()->getElementType())->getNumElements(); 659226633Sdim Builder.CreateCall2(EmitArcs, 660226633Sdim ConstantInt::get(Type::getInt32Ty(*Ctx), Arcs), 661226633Sdim Builder.CreateConstGEP2_64(GV, 0, 0)); 662226633Sdim } 663226633Sdim Builder.CreateCall(EndFile); 664221337Sdim } 665221337Sdim } 666221337Sdim Builder.CreateRetVoid(); 667221337Sdim 668221337Sdim InsertProfilingShutdownCall(WriteoutF, M); 669221337Sdim} 670