X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTransforms%2FInstrumentation%2FGCOVProfiling.cpp;h=8882dea5e0420e6e2c8a250a5a78593e3f74a73e;hp=3ce9cf6c3a46dbad4fa6b539be4f550dec6b1b2e;hb=2a9bbcbbadd5ba2eac950e1717c456298ec12bb6;hpb=a11c3e25015a62c817e60ec4f955a7f3f3bb6c67 diff --git a/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/lib/Transforms/Instrumentation/GCOVProfiling.cpp index 3ce9cf6c3a4..8882dea5e04 100644 --- a/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -14,36 +14,41 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "insert-gcov-profiling" - #include "llvm/Transforms/Instrumentation.h" -#include "ProfilingUtils.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/UniqueVector.h" -#include "llvm/DebugInfo.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DebugLoc.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/DebugLoc.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/InstIterator.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include +#include #include #include using namespace llvm; +#define DEBUG_TYPE "insert-gcov-profiling" + static cl::opt DefaultGCOVVersion("default-gcov-version", cl::init("402*"), cl::Hidden, cl::ValueRequired); +static cl::opt DefaultExitBlockBeforeBody("gcov-exit-block-before-body", + cl::init(false), cl::Hidden); GCOVOptions GCOVOptions::getDefault() { GCOVOptions Options; @@ -52,6 +57,7 @@ GCOVOptions GCOVOptions::getDefault() { Options.UseCfgChecksum = false; Options.NoRedZone = false; Options.FunctionNamesInData = true; + Options.ExitBlockBeforeBody = DefaultExitBlockBeforeBody; if (DefaultGCOVVersion.size() != 4) { llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") + @@ -62,18 +68,13 @@ GCOVOptions GCOVOptions::getDefault() { } namespace { + class GCOVFunction; + class GCOVProfiler : public ModulePass { public: static char ID; - GCOVProfiler() : ModulePass(ID), Options(GCOVOptions::getDefault()) { - ReversedVersion[0] = Options.Version[3]; - ReversedVersion[1] = Options.Version[2]; - ReversedVersion[2] = Options.Version[1]; - ReversedVersion[3] = Options.Version[0]; - ReversedVersion[4] = '\0'; - initializeGCOVProfilerPass(*PassRegistry::getPassRegistry()); - } - GCOVProfiler(const GCOVOptions &Options) : ModulePass(ID), Options(Options){ + GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {} + GCOVProfiler(const GCOVOptions &Opts) : ModulePass(ID), Options(Opts) { assert((Options.EmitNotes || Options.EmitData) && "GCOVProfiler asked to do nothing?"); ReversedVersion[0] = Options.Version[3]; @@ -83,12 +84,12 @@ namespace { ReversedVersion[4] = '\0'; initializeGCOVProfilerPass(*PassRegistry::getPassRegistry()); } - virtual const char *getPassName() const { + const char *getPassName() const override { return "GCOV Profiler"; } private: - bool runOnModule(Module &M); + bool runOnModule(Module &M) override; // Create the .gcno files for the Module based on DebugInfo. void emitProfileNotes(); @@ -102,6 +103,7 @@ namespace { Constant *getIncrementIndirectCounterFunc(); Constant *getEmitFunctionFunc(); Constant *getEmitArcsFunc(); + Constant *getSummaryInfoFunc(); Constant *getDeleteWriteoutFunctionListFunc(); Constant *getDeleteFlushFunctionListFunc(); Constant *getEndFileFunc(); @@ -129,10 +131,13 @@ namespace { GCOVOptions Options; // Reversed, NUL-terminated copy of Options.Version. - char ReversedVersion[5]; + char ReversedVersion[5]; + // Checksum, produced by hash of EdgeDestinations + SmallVector FileChecksums; Module *M; LLVMContext *Ctx; + SmallVector, 16> Funcs; }; } @@ -144,7 +149,7 @@ ModulePass *llvm::createGCOVProfilerPass(const GCOVOptions &Options) { return new GCOVProfiler(Options); } -static std::string getFunctionName(DISubprogram SP) { +static StringRef getFunctionName(DISubprogram SP) { if (!SP.getLinkageName().empty()) return SP.getLinkageName(); return SP.getName(); @@ -153,10 +158,10 @@ static std::string getFunctionName(DISubprogram SP) { namespace { class GCOVRecord { protected: - static const char *LinesTag; - static const char *FunctionTag; - static const char *BlockTag; - static const char *EdgeTag; + static const char *const LinesTag; + static const char *const FunctionTag; + static const char *const BlockTag; + static const char *const EdgeTag; GCOVRecord() {} @@ -170,7 +175,7 @@ namespace { // Returns the length measured in 4-byte blocks that will be used to // represent this string in a GCOV file - unsigned lengthOfGCOVString(StringRef s) { + static unsigned lengthOfGCOVString(StringRef s) { // A GCOV string is a length, followed by a NUL, then between 0 and 3 NULs // padding out to the next 4-byte word. The length is measured in 4-byte // words including padding, not bytes of actual string. @@ -190,10 +195,10 @@ namespace { raw_ostream *os; }; - const char *GCOVRecord::LinesTag = "\0\0\x45\x01"; - const char *GCOVRecord::FunctionTag = "\0\0\0\1"; - const char *GCOVRecord::BlockTag = "\0\0\x41\x01"; - const char *GCOVRecord::EdgeTag = "\0\0\x43\x01"; + const char *const GCOVRecord::LinesTag = "\0\0\x45\x01"; + const char *const GCOVRecord::FunctionTag = "\0\0\0\1"; + const char *const GCOVRecord::BlockTag = "\0\0\x41\x01"; + const char *const GCOVRecord::EdgeTag = "\0\0\x43\x01"; class GCOVFunction; class GCOVBlock; @@ -204,10 +209,11 @@ namespace { class GCOVLines : public GCOVRecord { public: void addLine(uint32_t Line) { + assert(Line != 0 && "Line zero is not a valid real line number."); Lines.push_back(Line); } - uint32_t length() { + uint32_t length() const { // Here 2 = 1 for string length + 1 for '0' id#. return lengthOfGCOVString(Filename) + 2 + Lines.size(); } @@ -219,7 +225,7 @@ namespace { write(Lines[i]); } - GCOVLines(StringRef F, raw_ostream *os) + GCOVLines(StringRef F, raw_ostream *os) : Filename(F) { this->os = os; } @@ -229,6 +235,7 @@ namespace { SmallVector Lines; }; + // Represent a basic block in GCOV. Each block has a unique number in the // function, number of lines belonging to each block, and a set of edges to // other blocks. @@ -248,17 +255,26 @@ namespace { void writeOut() { uint32_t Len = 3; + SmallVector *, 32> SortedLinesByFile; for (StringMap::iterator I = LinesByFile.begin(), E = LinesByFile.end(); I != E; ++I) { Len += I->second->length(); + SortedLinesByFile.push_back(&*I); } writeBytes(LinesTag, 4); write(Len); write(Number); - for (StringMap::iterator I = LinesByFile.begin(), - E = LinesByFile.end(); I != E; ++I) - I->second->writeOut(); + + std::sort(SortedLinesByFile.begin(), SortedLinesByFile.end(), + [](StringMapEntry *LHS, + StringMapEntry *RHS) { + return LHS->getKey() < RHS->getKey(); + }); + for (SmallVectorImpl *>::iterator + I = SortedLinesByFile.begin(), E = SortedLinesByFile.end(); + I != E; ++I) + (*I)->getValue()->writeOut(); write(0); write(0); } @@ -267,6 +283,14 @@ namespace { DeleteContainerSeconds(LinesByFile); } + GCOVBlock(const GCOVBlock &RHS) : GCOVRecord(RHS), Number(RHS.Number) { + // Only allow copy before edges and lines have been added. After that, + // there are inter-block pointers (eg: edges) that won't take kindly to + // blocks being copied or moved around. + assert(LinesByFile.empty()); + assert(OutEdges.empty()); + } + private: friend class GCOVFunction; @@ -285,18 +309,61 @@ namespace { // object users can construct, the blocks and lines will be rooted here. class GCOVFunction : public GCOVRecord { public: - GCOVFunction(DISubprogram SP, raw_ostream *os, uint32_t Ident, - bool UseCfgChecksum) { + GCOVFunction(DISubprogram SP, raw_ostream *os, uint32_t Ident, + bool UseCfgChecksum, bool ExitBlockBeforeBody) + : SP(SP), Ident(Ident), UseCfgChecksum(UseCfgChecksum), CfgChecksum(0), + ReturnBlock(1, os) { this->os = os; Function *F = SP.getFunction(); - DEBUG(dbgs() << "Function: " << F->getName() << "\n"); + DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n"); + uint32_t i = 0; - for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { - Blocks[BB] = new GCOVBlock(i++, os); + for (auto &BB : *F) { + // Skip index 1 if it's assigned to the ReturnBlock. + if (i == 1 && ExitBlockBeforeBody) + ++i; + Blocks.insert(std::make_pair(&BB, GCOVBlock(i++, os))); } - ReturnBlock = new GCOVBlock(i++, os); + if (!ExitBlockBeforeBody) + ReturnBlock.Number = i; + + std::string FunctionNameAndLine; + raw_string_ostream FNLOS(FunctionNameAndLine); + FNLOS << getFunctionName(SP) << SP.getLineNumber(); + FNLOS.flush(); + FuncChecksum = hash_value(FunctionNameAndLine); + } + + GCOVBlock &getBlock(BasicBlock *BB) { + return Blocks.find(BB)->second; + } + + GCOVBlock &getReturnBlock() { + return ReturnBlock; + } + + std::string getEdgeDestinations() { + std::string EdgeDestinations; + raw_string_ostream EDOS(EdgeDestinations); + Function *F = Blocks.begin()->first->getParent(); + for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) { + GCOVBlock &Block = getBlock(I); + for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) + EDOS << Block.OutEdges[i]->Number; + } + return EdgeDestinations; + } + uint32_t getFuncChecksum() { + return FuncChecksum; + } + + void setCfgChecksum(uint32_t Checksum) { + CfgChecksum = Checksum; + } + + void writeOut() { writeBytes(FunctionTag, 4); uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) + 1 + lengthOfGCOVString(SP.getFilename()) + 1; @@ -304,28 +371,13 @@ namespace { ++BlockLen; write(BlockLen); write(Ident); - write(0); // lineno checksum + write(FuncChecksum); if (UseCfgChecksum) - write(0); // cfg checksum + write(CfgChecksum); writeGCOVString(getFunctionName(SP)); writeGCOVString(SP.getFilename()); write(SP.getLineNumber()); - } - - ~GCOVFunction() { - DeleteContainerSeconds(Blocks); - delete ReturnBlock; - } - - GCOVBlock &getBlock(BasicBlock *BB) { - return *Blocks[BB]; - } - - GCOVBlock &getReturnBlock() { - return *ReturnBlock; - } - void writeOut() { // Emit count of blocks. writeBytes(BlockTag, 4); write(Blocks.size() + 1); @@ -335,9 +387,10 @@ namespace { DEBUG(dbgs() << Blocks.size() << " blocks.\n"); // Emit edges between blocks. - for (DenseMap::iterator I = Blocks.begin(), - E = Blocks.end(); I != E; ++I) { - GCOVBlock &Block = *I->second; + if (Blocks.empty()) return; + Function *F = Blocks.begin()->first->getParent(); + for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) { + GCOVBlock &Block = getBlock(I); if (Block.OutEdges.empty()) continue; writeBytes(EdgeTag, 4); @@ -352,15 +405,19 @@ namespace { } // Emit lines for each block. - for (DenseMap::iterator I = Blocks.begin(), - E = Blocks.end(); I != E; ++I) { - I->second->writeOut(); + for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) { + getBlock(I).writeOut(); } } private: - DenseMap Blocks; - GCOVBlock *ReturnBlock; + DISubprogram SP; + uint32_t Ident; + uint32_t FuncChecksum; + bool UseCfgChecksum; + uint32_t CfgChecksum; + DenseMap Blocks; + GCOVBlock ReturnBlock; }; } @@ -385,7 +442,7 @@ std::string GCOVProfiler::mangleName(DICompileUnit CU, const char *NewStem) { StringRef FName = sys::path::filename(Filename); SmallString<128> CurPath; if (sys::fs::current_path(CurPath)) return FName; - sys::path::append(CurPath, FName.str()); + sys::path::append(CurPath, FName); return CurPath.str(); } @@ -398,6 +455,28 @@ bool GCOVProfiler::runOnModule(Module &M) { return false; } +static bool functionHasLines(Function *F) { + // Check whether this function actually has any source lines. Not only + // do these waste space, they also can crash gcov. + for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { + for (BasicBlock::iterator I = BB->begin(), IE = BB->end(); + I != IE; ++I) { + // Debug intrinsic locations correspond to the location of the + // declaration, not necessarily any statements or expressions. + if (isa(I)) continue; + + const DebugLoc &Loc = I->getDebugLoc(); + if (Loc.isUnknown()) continue; + + // Artificial lines such as calls to the global constructors. + if (Loc.getLine() == 0) continue; + + return true; + } + } + return false; +} + void GCOVProfiler::emitProfileNotes() { NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); if (!CU_Nodes) return; @@ -408,21 +487,35 @@ void GCOVProfiler::emitProfileNotes() { // LTO, we'll generate the same .gcno files. DICompileUnit CU(CU_Nodes->getOperand(i)); - std::string ErrorInfo; - raw_fd_ostream out(mangleName(CU, "gcno").c_str(), ErrorInfo, - raw_fd_ostream::F_Binary); - out.write("oncg", 4); - out.write(ReversedVersion, 4); - out.write("MVLL", 4); + std::error_code EC; + raw_fd_ostream out(mangleName(CU, "gcno"), EC, sys::fs::F_None); + std::string EdgeDestinations; DIArray SPs = CU.getSubprograms(); + unsigned FunctionIdent = 0; for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) { DISubprogram SP(SPs.getElement(i)); - if (!SP.Verify()) continue; + assert((!SP || SP.isSubprogram()) && + "A MDNode in subprograms of a CU should be null or a DISubprogram."); + if (!SP) + continue; Function *F = SP.getFunction(); if (!F) continue; - GCOVFunction Func(SP, &out, i, Options.UseCfgChecksum); + if (!functionHasLines(F)) continue; + + // gcov expects every function to start with an entry block that has a + // single successor, so split the entry block to make sure of that. + BasicBlock &EntryBlock = F->getEntryBlock(); + BasicBlock::iterator It = EntryBlock.begin(); + while (isa(*It) || isa(*It)) + ++It; + EntryBlock.splitBasicBlock(It); + + Funcs.push_back(make_unique(SP, &out, FunctionIdent++, + Options.UseCfgChecksum, + Options.ExitBlockBeforeBody)); + GCOVFunction &Func = *Funcs.back(); for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { GCOVBlock &Block = Func.getBlock(BB); @@ -438,8 +531,16 @@ void GCOVProfiler::emitProfileNotes() { uint32_t Line = 0; for (BasicBlock::iterator I = BB->begin(), IE = BB->end(); I != IE; ++I) { + // Debug intrinsic locations correspond to the location of the + // declaration, not necessarily any statements or expressions. + if (isa(I)) continue; + const DebugLoc &Loc = I->getDebugLoc(); if (Loc.isUnknown()) continue; + + // Artificial lines such as calls to the global constructors. + if (Loc.getLine() == 0) continue; + if (Line == Loc.getLine()) continue; Line = Loc.getLine(); if (SP != getDISubprogram(Loc.getScope(*Ctx))) continue; @@ -448,8 +549,19 @@ void GCOVProfiler::emitProfileNotes() { Lines.addLine(Loc.getLine()); } } - Func.writeOut(); + EdgeDestinations += Func.getEdgeDestinations(); + } + + FileChecksums.push_back(hash_value(EdgeDestinations)); + out.write("oncg", 4); + out.write(ReversedVersion, 4); + out.write(reinterpret_cast(&FileChecksums.back()), 4); + + for (auto &Func : Funcs) { + Func->setCfgChecksum(FileChecksums.back()); + Func->writeOut(); } + out.write("\0\0\0\0\0\0\0\0", 8); // EOF out.close(); } @@ -459,7 +571,7 @@ bool GCOVProfiler::emitProfileArcs() { NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); if (!CU_Nodes) return false; - bool Result = false; + bool Result = false; bool InsertIndCounterIncrCode = false; for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { DICompileUnit CU(CU_Nodes->getOperand(i)); @@ -467,9 +579,13 @@ bool GCOVProfiler::emitProfileArcs() { SmallVector, 8> CountersBySP; for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) { DISubprogram SP(SPs.getElement(i)); - if (!SP.Verify()) continue; + assert((!SP || SP.isSubprogram()) && + "A MDNode in subprograms of a CU should be null or a DISubprogram."); + if (!SP) + continue; Function *F = SP.getFunction(); if (!F) continue; + if (!functionHasLines(F)) continue; if (!Result) Result = true; unsigned Edges = 0; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { @@ -479,7 +595,7 @@ bool GCOVProfiler::emitProfileArcs() { else Edges += TI->getNumSuccessors(); } - + ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Edges); GlobalVariable *Counters = @@ -488,24 +604,24 @@ bool GCOVProfiler::emitProfileArcs() { Constant::getNullValue(CounterTy), "__llvm_gcov_ctr"); CountersBySP.push_back(std::make_pair(Counters, (MDNode*)SP)); - + UniqueVector ComplexEdgePreds; UniqueVector ComplexEdgeSuccs; - + unsigned Edge = 0; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { TerminatorInst *TI = BB->getTerminator(); int Successors = isa(TI) ? 1 : TI->getNumSuccessors(); if (Successors) { - IRBuilder<> Builder(TI); - if (Successors == 1) { + IRBuilder<> Builder(BB->getFirstInsertionPt()); Value *Counter = Builder.CreateConstInBoundsGEP2_64(Counters, 0, Edge); Value *Count = Builder.CreateLoad(Counter); Count = Builder.CreateAdd(Count, Builder.getInt64(1)); Builder.CreateStore(Count, Counter); } else if (BranchInst *BI = dyn_cast(TI)) { + IRBuilder<> Builder(BI); Value *Sel = Builder.CreateSelect(BI->getCondition(), Builder.getInt64(Edge), Builder.getInt64(Edge + 1)); @@ -521,25 +637,25 @@ bool GCOVProfiler::emitProfileArcs() { for (int i = 0; i != Successors; ++i) ComplexEdgeSuccs.insert(TI->getSuccessor(i)); } + Edge += Successors; } } - + if (!ComplexEdgePreds.empty()) { GlobalVariable *EdgeTable = buildEdgeLookupTable(F, Counters, ComplexEdgePreds, ComplexEdgeSuccs); GlobalVariable *EdgeState = getEdgeStateValue(); - + for (int i = 0, e = ComplexEdgePreds.size(); i != e; ++i) { - IRBuilder<> Builder(ComplexEdgePreds[i+1]->getTerminator()); + IRBuilder<> Builder(ComplexEdgePreds[i + 1]->getFirstInsertionPt()); Builder.CreateStore(Builder.getInt32(i), EdgeState); } + for (int i = 0, e = ComplexEdgeSuccs.size(); i != e; ++i) { - // call runtime to perform increment - BasicBlock::iterator InsertPt = - ComplexEdgeSuccs[i+1]->getFirstInsertionPt(); - IRBuilder<> Builder(InsertPt); + // Call runtime to perform increment. + IRBuilder<> Builder(ComplexEdgeSuccs[i+1]->getFirstInsertionPt()); Value *CounterPtrArray = Builder.CreateConstInBoundsGEP2_64(EdgeTable, 0, i * ComplexEdgePreds.size()); @@ -577,7 +693,7 @@ bool GCOVProfiler::emitProfileArcs() { }; FTy = FunctionType::get(Builder.getVoidTy(), Params, false); - // Inialize the environment and register the local writeout and flush + // Initialize the environment and register the local writeout and flush // functions. Constant *GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); Builder.CreateCall2(GCOVInit, WriteoutF, FlushF); @@ -608,7 +724,7 @@ GlobalVariable *GCOVProfiler::buildEdgeLookupTable( Type *Int64PtrTy = Type::getInt64PtrTy(*Ctx); ArrayType *EdgeTableTy = ArrayType::get(Int64PtrTy, TableSize); - OwningArrayPtr EdgeTable(new Constant*[TableSize]); + std::unique_ptr EdgeTable(new Constant *[TableSize]); Constant *NullValue = Constant::getNullValue(Int64PtrTy); for (size_t i = 0; i != TableSize; ++i) EdgeTable[i] = NullValue; @@ -630,11 +746,11 @@ GlobalVariable *GCOVProfiler::buildEdgeLookupTable( Edge += Successors; } - ArrayRef V(&EdgeTable[0], TableSize); GlobalVariable *EdgeTableGV = new GlobalVariable( *M, EdgeTableTy, true, GlobalValue::InternalLinkage, - ConstantArray::get(EdgeTableTy, V), + ConstantArray::get(EdgeTableTy, + makeArrayRef(&EdgeTable[0],TableSize)), "__llvm_gcda_edge_table"); EdgeTableGV->setUnnamedAddr(true); return EdgeTableGV; @@ -644,6 +760,7 @@ Constant *GCOVProfiler::getStartFileFunc() { Type *Args[] = { Type::getInt8PtrTy(*Ctx), // const char *orig_filename Type::getInt8PtrTy(*Ctx), // const char version[4] + Type::getInt32Ty(*Ctx), // uint32_t checksum }; FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); return M->getOrInsertFunction("llvm_gcda_start_file", FTy); @@ -661,10 +778,12 @@ Constant *GCOVProfiler::getIncrementIndirectCounterFunc() { } Constant *GCOVProfiler::getEmitFunctionFunc() { - Type *Args[3] = { + Type *Args[] = { Type::getInt32Ty(*Ctx), // uint32_t ident Type::getInt8PtrTy(*Ctx), // const char *function_name + Type::getInt32Ty(*Ctx), // uint32_t func_checksum Type::getInt8Ty(*Ctx), // uint8_t use_extra_checksum + Type::getInt32Ty(*Ctx), // uint32_t cfg_checksum }; FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); return M->getOrInsertFunction("llvm_gcda_emit_function", FTy); @@ -679,6 +798,11 @@ Constant *GCOVProfiler::getEmitArcsFunc() { return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy); } +Constant *GCOVProfiler::getSummaryInfoFunc() { + FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); + return M->getOrInsertFunction("llvm_gcda_summary_info", FTy); +} + Constant *GCOVProfiler::getDeleteWriteoutFunctionListFunc() { FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); return M->getOrInsertFunction("llvm_delete_writeout_function_list", FTy); @@ -725,6 +849,7 @@ Function *GCOVProfiler::insertCounterWriteout( Constant *StartFile = getStartFileFunc(); Constant *EmitFunction = getEmitFunctionFunc(); Constant *EmitArcs = getEmitArcsFunc(); + Constant *SummaryInfo = getSummaryInfoFunc(); Constant *EndFile = getEndFileFunc(); NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); @@ -732,17 +857,22 @@ Function *GCOVProfiler::insertCounterWriteout( for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { DICompileUnit CU(CU_Nodes->getOperand(i)); std::string FilenameGcda = mangleName(CU, "gcda"); - Builder.CreateCall2(StartFile, + uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i]; + Builder.CreateCall3(StartFile, Builder.CreateGlobalStringPtr(FilenameGcda), - Builder.CreateGlobalStringPtr(ReversedVersion)); + Builder.CreateGlobalStringPtr(ReversedVersion), + Builder.getInt32(CfgChecksum)); for (unsigned j = 0, e = CountersBySP.size(); j != e; ++j) { DISubprogram SP(CountersBySP[j].second); - Builder.CreateCall3( + uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum(); + Builder.CreateCall5( EmitFunction, Builder.getInt32(j), Options.FunctionNamesInData ? Builder.CreateGlobalStringPtr(getFunctionName(SP)) : Constant::getNullValue(Builder.getInt8PtrTy()), - Builder.getInt8(Options.UseCfgChecksum)); + Builder.getInt32(FuncChecksum), + Builder.getInt8(Options.UseCfgChecksum), + Builder.getInt32(CfgChecksum)); GlobalVariable *GV = CountersBySP[j].first; unsigned Arcs = @@ -751,6 +881,7 @@ Function *GCOVProfiler::insertCounterWriteout( Builder.getInt32(Arcs), Builder.CreateConstGEP2_64(GV, 0, 0)); } + Builder.CreateCall(SummaryInfo); Builder.CreateCall(EndFile); } } @@ -789,7 +920,7 @@ void GCOVProfiler::insertIndirectCounterIncrement() { // uint64_t *counter = counters[pred]; // if (!counter) return; Value *ZExtPred = Builder.CreateZExt(Pred, Builder.getInt64Ty()); - Arg = llvm::next(Fn->arg_begin()); + Arg = std::next(Fn->arg_begin()); Arg->setName("counters"); Value *GEP = Builder.CreateGEP(Arg, ZExtPred); Value *Counter = Builder.CreateLoad(GEP, "counter");