diff options
Diffstat (limited to 'lib/Transforms/Instrumentation/GCOVProfiling.cpp')
-rw-r--r-- | lib/Transforms/Instrumentation/GCOVProfiling.cpp | 404 |
1 files changed, 193 insertions, 211 deletions
diff --git a/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/lib/Transforms/Instrumentation/GCOVProfiling.cpp index 132e8089fe3b..9af64ed332cd 100644 --- a/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -21,9 +21,9 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/UniqueVector.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/CFG.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/IRBuilder.h" @@ -36,6 +36,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" @@ -96,30 +97,25 @@ private: // profiling runtime to emit .gcda files when run. bool emitProfileArcs(); + bool isFunctionInstrumented(const Function &F); + std::vector<Regex> createRegexesFromString(StringRef RegexesStr); + static bool doesFilenameMatchARegex(StringRef Filename, + std::vector<Regex> &Regexes); + // Get pointers to the functions in the runtime library. Constant *getStartFileFunc(); - Constant *getIncrementIndirectCounterFunc(); Constant *getEmitFunctionFunc(); Constant *getEmitArcsFunc(); Constant *getSummaryInfoFunc(); Constant *getEndFileFunc(); - // Create or retrieve an i32 state value that is used to represent the - // pred block number for certain non-trivial edges. - GlobalVariable *getEdgeStateValue(); - - // Produce a table of pointers to counters, by predecessor and successor - // block number. - GlobalVariable *buildEdgeLookupTable(Function *F, GlobalVariable *Counter, - const UniqueVector<BasicBlock *> &Preds, - const UniqueVector<BasicBlock *> &Succs); - // Add the function to write out all our counters to the global destructor // list. Function * insertCounterWriteout(ArrayRef<std::pair<GlobalVariable *, MDNode *>>); Function *insertFlush(ArrayRef<std::pair<GlobalVariable *, MDNode *>>); - void insertIndirectCounterIncrement(); + + void AddFlushBeforeForkAndExec(); enum class GCovFileType { GCNO, GCDA }; std::string mangleName(const DICompileUnit *CU, GCovFileType FileType); @@ -135,6 +131,9 @@ private: const TargetLibraryInfo *TLI; LLVMContext *Ctx; SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs; + std::vector<Regex> FilterRe; + std::vector<Regex> ExcludeRe; + StringMap<bool> InstrumentedFiles; }; class GCOVProfilerLegacyPass : public ModulePass { @@ -181,6 +180,21 @@ static StringRef getFunctionName(const DISubprogram *SP) { return SP->getName(); } +/// Extract a filename for a DISubprogram. +/// +/// Prefer relative paths in the coverage notes. Clang also may split +/// up absolute paths into a directory and filename component. When +/// the relative path doesn't exist, reconstruct the absolute path. +static SmallString<128> getFilename(const DISubprogram *SP) { + SmallString<128> Path; + StringRef RelPath = SP->getFilename(); + if (sys::fs::exists(RelPath)) + Path = RelPath; + else + sys::path::append(Path, SP->getDirectory(), SP->getFilename()); + return Path; +} + namespace { class GCOVRecord { protected: @@ -257,7 +271,7 @@ namespace { } private: - StringRef Filename; + std::string Filename; SmallVector<uint32_t, 32> Lines; }; @@ -287,11 +301,10 @@ namespace { write(Len); write(Number); - llvm::sort( - SortedLinesByFile.begin(), SortedLinesByFile.end(), - [](StringMapEntry<GCOVLines> *LHS, StringMapEntry<GCOVLines> *RHS) { - return LHS->getKey() < RHS->getKey(); - }); + llvm::sort(SortedLinesByFile, [](StringMapEntry<GCOVLines> *LHS, + StringMapEntry<GCOVLines> *RHS) { + return LHS->getKey() < RHS->getKey(); + }); for (auto &I : SortedLinesByFile) I->getValue().writeOut(); write(0); @@ -379,8 +392,9 @@ namespace { void writeOut() { writeBytes(FunctionTag, 4); + SmallString<128> Filename = getFilename(SP); uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) + - 1 + lengthOfGCOVString(SP->getFilename()) + 1; + 1 + lengthOfGCOVString(Filename) + 1; if (UseCfgChecksum) ++BlockLen; write(BlockLen); @@ -389,7 +403,7 @@ namespace { if (UseCfgChecksum) write(CfgChecksum); writeGCOVString(getFunctionName(SP)); - writeGCOVString(SP->getFilename()); + writeGCOVString(Filename); write(SP->getLine()); // Emit count of blocks. @@ -434,6 +448,72 @@ namespace { }; } +// RegexesStr is a string containing differents regex separated by a semi-colon. +// For example "foo\..*$;bar\..*$". +std::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) { + std::vector<Regex> Regexes; + while (!RegexesStr.empty()) { + std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(';'); + if (!HeadTail.first.empty()) { + Regex Re(HeadTail.first); + std::string Err; + if (!Re.isValid(Err)) { + Ctx->emitError(Twine("Regex ") + HeadTail.first + + " is not valid: " + Err); + } + Regexes.emplace_back(std::move(Re)); + } + RegexesStr = HeadTail.second; + } + return Regexes; +} + +bool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename, + std::vector<Regex> &Regexes) { + for (Regex &Re : Regexes) { + if (Re.match(Filename)) { + return true; + } + } + return false; +} + +bool GCOVProfiler::isFunctionInstrumented(const Function &F) { + if (FilterRe.empty() && ExcludeRe.empty()) { + return true; + } + SmallString<128> Filename = getFilename(F.getSubprogram()); + auto It = InstrumentedFiles.find(Filename); + if (It != InstrumentedFiles.end()) { + return It->second; + } + + SmallString<256> RealPath; + StringRef RealFilename; + + // Path can be + // /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for + // such a case we must get the real_path. + if (sys::fs::real_path(Filename, RealPath)) { + // real_path can fail with path like "foo.c". + RealFilename = Filename; + } else { + RealFilename = RealPath; + } + + bool ShouldInstrument; + if (FilterRe.empty()) { + ShouldInstrument = !doesFilenameMatchARegex(RealFilename, ExcludeRe); + } else if (ExcludeRe.empty()) { + ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe); + } else { + ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe) && + !doesFilenameMatchARegex(RealFilename, ExcludeRe); + } + InstrumentedFiles[Filename] = ShouldInstrument; + return ShouldInstrument; +} + std::string GCOVProfiler::mangleName(const DICompileUnit *CU, GCovFileType OutputType) { bool Notes = OutputType == GCovFileType::GCNO; @@ -481,6 +561,11 @@ bool GCOVProfiler::runOnModule(Module &M, const TargetLibraryInfo &TLI) { this->TLI = &TLI; Ctx = &M.getContext(); + AddFlushBeforeForkAndExec(); + + FilterRe = createRegexesFromString(Options.Filter); + ExcludeRe = createRegexesFromString(Options.Exclude); + if (Options.EmitNotes) emitProfileNotes(); if (Options.EmitData) return emitProfileArcs(); return false; @@ -537,6 +622,38 @@ static bool shouldKeepInEntry(BasicBlock::iterator It) { return false; } +void GCOVProfiler::AddFlushBeforeForkAndExec() { + SmallVector<Instruction *, 2> ForkAndExecs; + for (auto &F : M->functions()) { + for (auto &I : instructions(F)) { + if (CallInst *CI = dyn_cast<CallInst>(&I)) { + if (Function *Callee = CI->getCalledFunction()) { + LibFunc LF; + if (TLI->getLibFunc(*Callee, LF) && + (LF == LibFunc_fork || LF == LibFunc_execl || + LF == LibFunc_execle || LF == LibFunc_execlp || + LF == LibFunc_execv || LF == LibFunc_execvp || + LF == LibFunc_execve || LF == LibFunc_execvpe || + LF == LibFunc_execvP)) { + ForkAndExecs.push_back(&I); + } + } + } + } + } + + // We need to split the block after the fork/exec call + // because else the counters for the lines after will be + // the same as before the call. + for (auto I : ForkAndExecs) { + IRBuilder<> Builder(I); + FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); + Constant *GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy); + Builder.CreateCall(GCOVFlush); + I->getParent()->splitBasicBlock(I); + } +} + void GCOVProfiler::emitProfileNotes() { NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); if (!CU_Nodes) return; @@ -566,7 +683,8 @@ void GCOVProfiler::emitProfileNotes() { for (auto &F : M->functions()) { DISubprogram *SP = F.getSubprogram(); if (!SP) continue; - if (!functionHasLines(F)) continue; + if (!functionHasLines(F) || !isFunctionInstrumented(F)) + continue; // TODO: Functions using scope-based EH are currently not supported. if (isUsingScopeBasedEH(F)) continue; @@ -583,9 +701,15 @@ void GCOVProfiler::emitProfileNotes() { Options.ExitBlockBeforeBody)); GCOVFunction &Func = *Funcs.back(); + // Add the function line number to the lines of the entry block + // to have a counter for the function definition. + uint32_t Line = SP->getLine(); + auto Filename = getFilename(SP); + Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line); + for (auto &BB : F) { GCOVBlock &Block = Func.getBlock(&BB); - TerminatorInst *TI = BB.getTerminator(); + Instruction *TI = BB.getTerminator(); if (int successors = TI->getNumSuccessors()) { for (int i = 0; i != successors; ++i) { Block.addEdge(Func.getBlock(TI->getSuccessor(i))); @@ -594,7 +718,6 @@ void GCOVProfiler::emitProfileNotes() { Block.addEdge(Func.getReturnBlock()); } - uint32_t Line = 0; for (auto &I : BB) { // Debug intrinsic locations correspond to the location of the // declaration, not necessarily any statements or expressions. @@ -605,16 +728,18 @@ void GCOVProfiler::emitProfileNotes() { continue; // Artificial lines such as calls to the global constructors. - if (Loc.getLine() == 0) continue; + if (Loc.getLine() == 0 || Loc.isImplicitCode()) + continue; if (Line == Loc.getLine()) continue; Line = Loc.getLine(); if (SP != getDISubprogram(Loc.getScope())) continue; - GCOVLines &Lines = Block.getFile(SP->getFilename()); + GCOVLines &Lines = Block.getFile(Filename); Lines.addLine(Loc.getLine()); } + Line = 0; } EdgeDestinations += Func.getEdgeDestinations(); } @@ -639,24 +764,28 @@ bool GCOVProfiler::emitProfileArcs() { if (!CU_Nodes) return false; bool Result = false; - bool InsertIndCounterIncrCode = false; for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; for (auto &F : M->functions()) { DISubprogram *SP = F.getSubprogram(); if (!SP) continue; - if (!functionHasLines(F)) continue; + if (!functionHasLines(F) || !isFunctionInstrumented(F)) + continue; // TODO: Functions using scope-based EH are currently not supported. if (isUsingScopeBasedEH(F)) continue; if (!Result) Result = true; + DenseMap<std::pair<BasicBlock *, BasicBlock *>, unsigned> EdgeToCounter; unsigned Edges = 0; for (auto &BB : F) { - TerminatorInst *TI = BB.getTerminator(); - if (isa<ReturnInst>(TI)) - ++Edges; - else - Edges += TI->getNumSuccessors(); + Instruction *TI = BB.getTerminator(); + if (isa<ReturnInst>(TI)) { + EdgeToCounter[{&BB, nullptr}] = Edges++; + } else { + for (BasicBlock *Succ : successors(TI)) { + EdgeToCounter[{&BB, Succ}] = Edges++; + } + } } ArrayType *CounterTy = @@ -668,63 +797,42 @@ bool GCOVProfiler::emitProfileArcs() { "__llvm_gcov_ctr"); CountersBySP.push_back(std::make_pair(Counters, SP)); - UniqueVector<BasicBlock *> ComplexEdgePreds; - UniqueVector<BasicBlock *> ComplexEdgeSuccs; - - unsigned Edge = 0; + // If a BB has several predecessors, use a PHINode to select + // the correct counter. for (auto &BB : F) { - TerminatorInst *TI = BB.getTerminator(); - int Successors = isa<ReturnInst>(TI) ? 1 : TI->getNumSuccessors(); - if (Successors) { - 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<BranchInst>(TI)) { - IRBuilder<> Builder(BI); - Value *Sel = Builder.CreateSelect(BI->getCondition(), - Builder.getInt64(Edge), - Builder.getInt64(Edge + 1)); - Value *Counter = Builder.CreateInBoundsGEP( - Counters->getValueType(), Counters, {Builder.getInt64(0), Sel}); + const unsigned EdgeCount = + std::distance(pred_begin(&BB), pred_end(&BB)); + if (EdgeCount) { + // The phi node must be at the begin of the BB. + IRBuilder<> BuilderForPhi(&*BB.begin()); + Type *Int64PtrTy = Type::getInt64PtrTy(*Ctx); + PHINode *Phi = BuilderForPhi.CreatePHI(Int64PtrTy, EdgeCount); + for (BasicBlock *Pred : predecessors(&BB)) { + auto It = EdgeToCounter.find({Pred, &BB}); + assert(It != EdgeToCounter.end()); + const unsigned Edge = It->second; + Value *EdgeCounter = + BuilderForPhi.CreateConstInBoundsGEP2_64(Counters, 0, Edge); + Phi->addIncoming(EdgeCounter, Pred); + } + + // Skip phis, landingpads. + IRBuilder<> Builder(&*BB.getFirstInsertionPt()); + Value *Count = Builder.CreateLoad(Phi); + Count = Builder.CreateAdd(Count, Builder.getInt64(1)); + Builder.CreateStore(Count, Phi); + + Instruction *TI = BB.getTerminator(); + if (isa<ReturnInst>(TI)) { + auto It = EdgeToCounter.find({&BB, nullptr}); + assert(It != EdgeToCounter.end()); + const unsigned Edge = It->second; + 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 { - ComplexEdgePreds.insert(&BB); - 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]->getFirstInsertionPt()); - Builder.CreateStore(Builder.getInt32(i), EdgeState); - } - - for (int i = 0, e = ComplexEdgeSuccs.size(); i != e; ++i) { - // Call runtime to perform increment. - IRBuilder<> Builder(&*ComplexEdgeSuccs[i + 1]->getFirstInsertionPt()); - Value *CounterPtrArray = - Builder.CreateConstInBoundsGEP2_64(EdgeTable, 0, - i * ComplexEdgePreds.size()); - - // Build code to increment the counter. - InsertIndCounterIncrCode = true; - Builder.CreateCall(getIncrementIndirectCounterFunc(), - {EdgeState, CounterPtrArray}); } } } @@ -763,60 +871,9 @@ bool GCOVProfiler::emitProfileArcs() { appendToGlobalCtors(*M, F, 0); } - if (InsertIndCounterIncrCode) - insertIndirectCounterIncrement(); - return Result; } -// All edges with successors that aren't branches are "complex", because it -// requires complex logic to pick which counter to update. -GlobalVariable *GCOVProfiler::buildEdgeLookupTable( - Function *F, - GlobalVariable *Counters, - const UniqueVector<BasicBlock *> &Preds, - const UniqueVector<BasicBlock *> &Succs) { - // TODO: support invoke, threads. We rely on the fact that nothing can modify - // the whole-Module pred edge# between the time we set it and the time we next - // read it. Threads and invoke make this untrue. - - // emit [(succs * preds) x i64*], logically [succ x [pred x i64*]]. - size_t TableSize = Succs.size() * Preds.size(); - Type *Int64PtrTy = Type::getInt64PtrTy(*Ctx); - ArrayType *EdgeTableTy = ArrayType::get(Int64PtrTy, TableSize); - - std::unique_ptr<Constant * []> EdgeTable(new Constant *[TableSize]); - Constant *NullValue = Constant::getNullValue(Int64PtrTy); - for (size_t i = 0; i != TableSize; ++i) - EdgeTable[i] = NullValue; - - unsigned Edge = 0; - for (BasicBlock &BB : *F) { - TerminatorInst *TI = BB.getTerminator(); - int Successors = isa<ReturnInst>(TI) ? 1 : TI->getNumSuccessors(); - if (Successors > 1 && !isa<BranchInst>(TI) && !isa<ReturnInst>(TI)) { - for (int i = 0; i != Successors; ++i) { - BasicBlock *Succ = TI->getSuccessor(i); - IRBuilder<> Builder(Succ); - Value *Counter = Builder.CreateConstInBoundsGEP2_64(Counters, 0, - Edge + i); - EdgeTable[((Succs.idFor(Succ) - 1) * Preds.size()) + - (Preds.idFor(&BB) - 1)] = cast<Constant>(Counter); - } - } - Edge += Successors; - } - - GlobalVariable *EdgeTableGV = - new GlobalVariable( - *M, EdgeTableTy, true, GlobalValue::InternalLinkage, - ConstantArray::get(EdgeTableTy, - makeArrayRef(&EdgeTable[0],TableSize)), - "__llvm_gcda_edge_table"); - EdgeTableGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - return EdgeTableGV; -} - Constant *GCOVProfiler::getStartFileFunc() { Type *Args[] = { Type::getInt8PtrTy(*Ctx), // const char *orig_filename @@ -832,17 +889,6 @@ Constant *GCOVProfiler::getStartFileFunc() { } -Constant *GCOVProfiler::getIncrementIndirectCounterFunc() { - Type *Int32Ty = Type::getInt32Ty(*Ctx); - Type *Int64Ty = Type::getInt64Ty(*Ctx); - Type *Args[] = { - Int32Ty->getPointerTo(), // uint32_t *predecessor - Int64Ty->getPointerTo()->getPointerTo() // uint64_t **counters - }; - FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); - return M->getOrInsertFunction("__llvm_gcov_indirect_counter_increment", FTy); -} - Constant *GCOVProfiler::getEmitFunctionFunc() { Type *Args[] = { Type::getInt32Ty(*Ctx), // uint32_t ident @@ -886,19 +932,6 @@ Constant *GCOVProfiler::getEndFileFunc() { return M->getOrInsertFunction("llvm_gcda_end_file", FTy); } -GlobalVariable *GCOVProfiler::getEdgeStateValue() { - GlobalVariable *GV = M->getGlobalVariable("__llvm_gcov_global_state_pred"); - if (!GV) { - GV = new GlobalVariable(*M, Type::getInt32Ty(*Ctx), false, - GlobalValue::InternalLinkage, - ConstantInt::get(Type::getInt32Ty(*Ctx), - 0xffffffff), - "__llvm_gcov_global_state_pred"); - GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - } - return GV; -} - Function *GCOVProfiler::insertCounterWriteout( ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) { FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false); @@ -1122,57 +1155,6 @@ Function *GCOVProfiler::insertCounterWriteout( return WriteoutF; } -void GCOVProfiler::insertIndirectCounterIncrement() { - Function *Fn = - cast<Function>(GCOVProfiler::getIncrementIndirectCounterFunc()); - Fn->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - Fn->setLinkage(GlobalValue::InternalLinkage); - Fn->addFnAttr(Attribute::NoInline); - if (Options.NoRedZone) - Fn->addFnAttr(Attribute::NoRedZone); - - // Create basic blocks for function. - BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", Fn); - IRBuilder<> Builder(BB); - - BasicBlock *PredNotNegOne = BasicBlock::Create(*Ctx, "", Fn); - BasicBlock *CounterEnd = BasicBlock::Create(*Ctx, "", Fn); - BasicBlock *Exit = BasicBlock::Create(*Ctx, "exit", Fn); - - // uint32_t pred = *predecessor; - // if (pred == 0xffffffff) return; - Argument *Arg = &*Fn->arg_begin(); - Arg->setName("predecessor"); - Value *Pred = Builder.CreateLoad(Arg, "pred"); - Value *Cond = Builder.CreateICmpEQ(Pred, Builder.getInt32(0xffffffff)); - BranchInst::Create(Exit, PredNotNegOne, Cond, BB); - - Builder.SetInsertPoint(PredNotNegOne); - - // uint64_t *counter = counters[pred]; - // if (!counter) return; - Value *ZExtPred = Builder.CreateZExt(Pred, Builder.getInt64Ty()); - Arg = &*std::next(Fn->arg_begin()); - Arg->setName("counters"); - Value *GEP = Builder.CreateGEP(Type::getInt64PtrTy(*Ctx), Arg, ZExtPred); - Value *Counter = Builder.CreateLoad(GEP, "counter"); - Cond = Builder.CreateICmpEQ(Counter, - Constant::getNullValue( - Builder.getInt64Ty()->getPointerTo())); - Builder.CreateCondBr(Cond, Exit, CounterEnd); - - // ++*counter; - Builder.SetInsertPoint(CounterEnd); - Value *Add = Builder.CreateAdd(Builder.CreateLoad(Counter), - Builder.getInt64(1)); - Builder.CreateStore(Add, Counter); - Builder.CreateBr(Exit); - - // Fill in the exit block. - Builder.SetInsertPoint(Exit); - Builder.CreateRetVoid(); -} - Function *GCOVProfiler:: insertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) { FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); |