X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTransforms%2FInstrumentation%2FGCOVProfiling.cpp;h=0baa1c494e5b739487c87c2154c3d3e3fe447bf0;hb=7cc4447ccfa69e76cb8e3e3cc76984895421dba5;hp=61c53b49f78e8cf0a387f515e4e6e1c1b91c3150;hpb=f675b3c6444af3e2f547b050eedb8a12584110ef;p=oota-llvm.git diff --git a/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/lib/Transforms/Instrumentation/GCOVProfiling.cpp index 61c53b49f78..0baa1c494e5 100644 --- a/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -14,34 +14,36 @@ // //===----------------------------------------------------------------------===// -#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); @@ -63,20 +65,25 @@ 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()); + init(); } GCOVProfiler(const GCOVOptions &Options) : ModulePass(ID), Options(Options){ assert((Options.EmitNotes || Options.EmitData) && "GCOVProfiler asked to do nothing?"); + init(); + } + const char *getPassName() const override { + return "GCOV Profiler"; + } + + private: + void init() { ReversedVersion[0] = Options.Version[3]; ReversedVersion[1] = Options.Version[2]; ReversedVersion[2] = Options.Version[1]; @@ -84,12 +91,7 @@ namespace { ReversedVersion[4] = '\0'; initializeGCOVProfilerPass(*PassRegistry::getPassRegistry()); } - virtual const char *getPassName() const { - 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(); @@ -103,6 +105,7 @@ namespace { Constant *getIncrementIndirectCounterFunc(); Constant *getEmitFunctionFunc(); Constant *getEmitArcsFunc(); + Constant *getSummaryInfoFunc(); Constant *getDeleteWriteoutFunctionListFunc(); Constant *getDeleteFlushFunctionListFunc(); Constant *getEndFileFunc(); @@ -130,10 +133,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; }; } @@ -145,7 +151,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(); @@ -205,6 +211,7 @@ 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); } @@ -220,7 +227,7 @@ namespace { write(Lines[i]); } - GCOVLines(StringRef F, raw_ostream *os) + GCOVLines(StringRef F, raw_ostream *os) : Filename(F) { this->os = os; } @@ -231,14 +238,6 @@ namespace { }; - // Sorting function for deterministic behaviour in GCOVBlock::writeOut. - struct StringKeySort { - bool operator()(StringMapEntry *LHS, - StringMapEntry *RHS) const { - return LHS->getKey() < RHS->getKey(); - } - }; - // 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. @@ -269,11 +268,14 @@ namespace { write(Len); write(Number); - StringKeySort Sorter; - std::sort(SortedLinesByFile.begin(), SortedLinesByFile.end(), Sorter); + 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 != E; ++I) (*I)->getValue()->writeOut(); write(0); write(0); @@ -302,30 +304,23 @@ namespace { class GCOVFunction : public GCOVRecord { public: GCOVFunction(DISubprogram SP, raw_ostream *os, uint32_t Ident, - bool UseCfgChecksum) { + bool UseCfgChecksum) : + SP(SP), Ident(Ident), UseCfgChecksum(UseCfgChecksum), CfgChecksum(0) { 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); } ReturnBlock = new GCOVBlock(i++, os); - writeBytes(FunctionTag, 4); - uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) + - 1 + lengthOfGCOVString(SP.getFilename()) + 1; - if (UseCfgChecksum) - ++BlockLen; - write(BlockLen); - write(Ident); - write(0); // lineno checksum - if (UseCfgChecksum) - write(0); // cfg checksum - writeGCOVString(getFunctionName(SP)); - writeGCOVString(SP.getFilename()); - write(SP.getLineNumber()); + std::string FunctionNameAndLine; + raw_string_ostream FNLOS(FunctionNameAndLine); + FNLOS << getFunctionName(SP) << SP.getLineNumber(); + FNLOS.flush(); + FuncChecksum = hash_value(FunctionNameAndLine); } ~GCOVFunction() { @@ -341,7 +336,41 @@ namespace { 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 = *Blocks[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; + if (UseCfgChecksum) + ++BlockLen; + write(BlockLen); + write(Ident); + write(FuncChecksum); + if (UseCfgChecksum) + write(CfgChecksum); + writeGCOVString(getFunctionName(SP)); + writeGCOVString(SP.getFilename()); + write(SP.getLineNumber()); + // Emit count of blocks. writeBytes(BlockTag, 4); write(Blocks.size() + 1); @@ -375,6 +404,11 @@ namespace { } private: + DISubprogram SP; + uint32_t Ident; + uint32_t FuncChecksum; + bool UseCfgChecksum; + uint32_t CfgChecksum; DenseMap Blocks; GCOVBlock *ReturnBlock; }; @@ -414,6 +448,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; @@ -424,12 +480,9 @@ 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, - sys::fs::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(); for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) { @@ -441,7 +494,19 @@ void GCOVProfiler::emitProfileNotes() { 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, i, Options.UseCfgChecksum)); + GCOVFunction &Func = *Funcs.back(); for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { GCOVBlock &Block = Func.getBlock(BB); @@ -457,8 +522,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; @@ -467,8 +540,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(); } @@ -478,7 +562,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)); @@ -492,6 +576,7 @@ bool GCOVProfiler::emitProfileArcs() { 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) { @@ -501,7 +586,7 @@ bool GCOVProfiler::emitProfileArcs() { else Edges += TI->getNumSuccessors(); } - + ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Edges); GlobalVariable *Counters = @@ -510,10 +595,10 @@ 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(); @@ -547,13 +632,13 @@ bool GCOVProfiler::emitProfileArcs() { 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]->getFirstInsertionPt()); Builder.CreateStore(Builder.getInt32(i), EdgeState); @@ -599,7 +684,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); @@ -630,7 +715,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; @@ -652,11 +737,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; @@ -666,6 +751,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); @@ -683,10 +769,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); @@ -701,6 +789,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); @@ -747,6 +840,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"); @@ -754,17 +848,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 = @@ -773,6 +872,7 @@ Function *GCOVProfiler::insertCounterWriteout( Builder.getInt32(Arcs), Builder.CreateConstGEP2_64(GV, 0, 0)); } + Builder.CreateCall(SummaryInfo); Builder.CreateCall(EndFile); } } @@ -811,7 +911,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");