46 #define DEBUG_TYPE "insert-gcov-profiling"
76 GCOVProfiler() : GCOVProfiler(
GCOVOptions::getDefault()) {}
77 GCOVProfiler(
const GCOVOptions &Opts) : Options(Opts) {
78 assert((Options.EmitNotes || Options.EmitData) &&
79 "GCOVProfiler asked to do nothing?");
80 ReversedVersion[0] = Options.Version[3];
81 ReversedVersion[1] = Options.Version[2];
82 ReversedVersion[2] = Options.Version[1];
83 ReversedVersion[3] = Options.Version[0];
84 ReversedVersion[4] =
'\0';
86 bool runOnModule(
Module &M);
90 void emitProfileNotes();
94 bool emitProfileArcs();
98 Constant *getIncrementIndirectCounterFunc();
117 insertCounterWriteout(
ArrayRef<std::pair<GlobalVariable *, MDNode *>>);
119 void insertIndirectCounterIncrement();
121 enum class GCovFileType { GCNO, GCDA };
127 char ReversedVersion[5];
136 class GCOVProfilerLegacyPass :
public ModulePass {
139 GCOVProfilerLegacyPass()
140 : GCOVProfilerLegacyPass(
GCOVOptions::getDefault()) {}
145 StringRef getPassName()
const override {
return "GCOV Profiler"; }
147 bool runOnModule(
Module &M)
override {
return Profiler.runOnModule(M); }
150 GCOVProfiler Profiler;
156 "Insert instrumentation for GCOV profiling",
false,
false)
159 return new GCOVProfilerLegacyPass(Options);
163 if (!SP->getLinkageName().empty())
164 return SP->getLinkageName();
171 static const char *
const LinesTag;
172 static const char *
const FunctionTag;
173 static const char *
const BlockTag;
174 static const char *
const EdgeTag;
176 GCOVRecord() =
default;
178 void writeBytes(
const char *Bytes,
int Size) {
179 os->write(Bytes, Size);
183 writeBytes(reinterpret_cast<char*>(&i), 4);
188 static unsigned lengthOfGCOVString(
StringRef s) {
192 return (s.
size() / 4) + 1;
196 uint32_t Len = lengthOfGCOVString(s);
203 writeBytes(
"\0\0\0\0", 4 - (s.
size() % 4));
208 const char *
const GCOVRecord::LinesTag =
"\0\0\x45\x01";
209 const char *
const GCOVRecord::FunctionTag =
"\0\0\0\1";
210 const char *
const GCOVRecord::BlockTag =
"\0\0\x41\x01";
211 const char *
const GCOVRecord::EdgeTag =
"\0\0\x43\x01";
219 class GCOVLines :
public GCOVRecord {
222 assert(Line != 0 &&
"Line zero is not a valid real line number.");
223 Lines.push_back(Line);
228 return lengthOfGCOVString(Filename) + 2 +
Lines.size();
233 writeGCOVString(Filename);
234 for (
int i = 0, e =
Lines.size(); i != e; ++
i)
255 return LinesByFile.try_emplace(Filename, Filename, os).first->second;
259 OutEdges.push_back(&Successor);
265 for (
auto &
I : LinesByFile) {
266 Len +=
I.second.length();
270 writeBytes(LinesTag, 4);
275 SortedLinesByFile.
begin(), SortedLinesByFile.
end(),
277 return LHS->
getKey() < RHS->getKey();
279 for (
auto &
I : SortedLinesByFile)
280 I->getValue().writeOut();
289 assert(LinesByFile.empty());
312 uint32_t Ident,
bool UseCfgChecksum,
bool ExitBlockBeforeBody)
313 : SP(SP), Ident(Ident), UseCfgChecksum(UseCfgChecksum), CfgChecksum(0),
320 for (
auto &BB : *F) {
322 if (i == 1 && ExitBlockBeforeBody)
324 Blocks.insert(std::make_pair(&BB,
GCOVBlock(i++, os)));
326 if (!ExitBlockBeforeBody)
327 ReturnBlock.Number =
i;
329 std::string FunctionNameAndLine;
333 FuncChecksum =
hash_value(FunctionNameAndLine);
337 return Blocks.find(BB)->second;
344 std::string getEdgeDestinations() {
345 std::string EdgeDestinations;
347 Function *F = Blocks.begin()->first->getParent();
350 for (
int i = 0, e = Block.OutEdges.size(); i != e; ++
i)
351 EDOS << Block.OutEdges[i]->Number;
353 return EdgeDestinations;
360 void setCfgChecksum(
uint32_t Checksum) {
361 CfgChecksum = Checksum;
365 writeBytes(FunctionTag, 4);
377 write(SP->getLine());
380 writeBytes(BlockTag, 4);
381 write(Blocks.size() + 1);
382 for (
int i = 0, e = Blocks.size() + 1; i != e; ++
i) {
385 DEBUG(
dbgs() << Blocks.size() <<
" blocks.\n");
388 if (Blocks.empty())
return;
389 Function *F = Blocks.begin()->first->getParent();
392 if (Block.OutEdges.empty())
continue;
394 writeBytes(EdgeTag, 4);
395 write(Block.OutEdges.size() * 2 + 1);
397 for (
int i = 0, e = Block.OutEdges.size(); i != e; ++
i) {
398 DEBUG(
dbgs() << Block.Number <<
" -> " << Block.OutEdges[i]->Number
400 write(Block.OutEdges[i]->Number);
407 getBlock(&
I).writeOut();
421 std::string GCOVProfiler::mangleName(
const DICompileUnit *CU,
422 GCovFileType OutputType) {
423 bool Notes = OutputType == GCovFileType::GCNO;
425 if (
NamedMDNode *GCov = M->getNamedMetadata(
"llvm.gcov")) {
426 for (
int i = 0, e = GCov->getNumOperands(); i != e; ++
i) {
427 MDNode *
N = GCov->getOperand(i);
431 if (dyn_cast<MDNode>(N->
getOperand(ThreeElement ? 2 : 1)) != CU)
439 if (!NotesFile || !DataFile)
441 return Notes ? NotesFile->
getString() : DataFile->getString();
450 return Filename.
str();
460 return CurPath.
str();
463 bool GCOVProfiler::runOnModule(
Module &M) {
467 if (Options.EmitNotes) emitProfileNotes();
468 if (Options.EmitData)
return emitProfileArcs();
475 GCOVProfiler Profiler(GCOVOpts);
477 if (!Profiler.runOnModule(M))
490 if (isa<DbgInfoIntrinsic>(&
I))
continue;
497 if (Loc.
getLine() == 0)
continue;
505 void GCOVProfiler::emitProfileNotes() {
507 if (!CU_Nodes)
return;
514 auto *CU = cast<DICompileUnit>(CU_Nodes->
getOperand(i));
522 std::string EdgeDestinations;
524 unsigned FunctionIdent = 0;
534 while (isa<AllocaInst>(*It) || isa<DbgInfoIntrinsic>(*It))
538 Funcs.push_back(make_unique<GCOVFunction>(SP, &F, &out, FunctionIdent++,
539 Options.UseCfgChecksum,
540 Options.ExitBlockBeforeBody));
550 }
else if (isa<ReturnInst>(TI)) {
551 Block.addEdge(Func.getReturnBlock());
558 if (isa<DbgInfoIntrinsic>(&
I))
continue;
565 if (Loc.
getLine() == 0)
continue;
567 if (Line == Loc.
getLine())
continue;
576 EdgeDestinations += Func.getEdgeDestinations();
580 out.write(
"oncg", 4);
581 out.write(ReversedVersion, 4);
582 out.write(reinterpret_cast<char*>(&
FileChecksums.back()), 4);
584 for (
auto &Func : Funcs) {
589 out.write(
"\0\0\0\0\0\0\0\0", 8);
594 bool GCOVProfiler::emitProfileArcs() {
596 if (!CU_Nodes)
return false;
599 bool InsertIndCounterIncrCode =
false;
606 if (!Result) Result =
true;
610 if (isa<ReturnInst>(TI))
623 CountersBySP.
push_back(std::make_pair(Counters, SP));
633 if (Successors == 1) {
635 Value *
Counter = Builder.CreateConstInBoundsGEP2_64(Counters, 0,
637 Value *Count = Builder.CreateLoad(Counter);
638 Count = Builder.CreateAdd(Count, Builder.getInt64(1));
639 Builder.CreateStore(Count, Counter);
640 }
else if (
BranchInst *BI = dyn_cast<BranchInst>(TI)) {
642 Value *Sel = Builder.CreateSelect(BI->getCondition(),
643 Builder.getInt64(Edge),
644 Builder.getInt64(Edge + 1));
646 Counters->
getValueType(), Counters, {Builder.getInt64(0), Sel});
647 Value *Count = Builder.CreateLoad(Counter);
648 Count = Builder.CreateAdd(Count, Builder.getInt64(1));
649 Builder.CreateStore(Count, Counter);
651 ComplexEdgePreds.
insert(&BB);
652 for (
int i = 0; i != Successors; ++
i)
660 if (!ComplexEdgePreds.
empty()) {
662 buildEdgeLookupTable(&F, Counters,
663 ComplexEdgePreds, ComplexEdgeSuccs);
666 for (
int i = 0, e = ComplexEdgePreds.
size(); i != e; ++
i) {
667 IRBuilder<> Builder(&*ComplexEdgePreds[i + 1]->getFirstInsertionPt());
668 Builder.CreateStore(Builder.getInt32(i), EdgeState);
671 for (
int i = 0, e = ComplexEdgeSuccs.
size(); i != e; ++
i) {
673 IRBuilder<> Builder(&*ComplexEdgeSuccs[i + 1]->getFirstInsertionPt());
674 Value *CounterPtrArray =
675 Builder.CreateConstInBoundsGEP2_64(EdgeTable, 0,
676 i * ComplexEdgePreds.
size());
679 InsertIndCounterIncrCode =
true;
680 Builder.CreateCall(getIncrementIndirectCounterFunc(),
681 {EdgeState, CounterPtrArray});
686 Function *WriteoutF = insertCounterWriteout(CountersBySP);
687 Function *FlushF = insertFlush(CountersBySP);
694 "__llvm_gcov_init", M);
698 if (Options.NoRedZone)
714 Builder.CreateCall(GCOVInit, {WriteoutF, FlushF});
715 Builder.CreateRetVoid();
720 if (InsertIndCounterIncrCode)
721 insertIndirectCounterIncrement();
738 size_t TableSize = Succs.
size() * Preds.
size();
742 std::unique_ptr<Constant * []> EdgeTable(
new Constant *[TableSize]);
744 for (
size_t i = 0; i != TableSize; ++
i)
745 EdgeTable[i] = NullValue;
751 if (Successors > 1 && !isa<BranchInst>(TI) && !isa<ReturnInst>(TI)) {
752 for (
int i = 0; i != Successors; ++
i) {
755 Value *Counter = Builder.CreateConstInBoundsGEP2_64(Counters, 0,
757 EdgeTable[((Succs.
idFor(Succ) - 1) * Preds.
size()) +
758 (Preds.
idFor(&BB) - 1)] = cast<Constant>(Counter);
769 "__llvm_gcda_edge_table");
774 Constant *GCOVProfiler::getStartFileFunc() {
784 Constant *GCOVProfiler::getIncrementIndirectCounterFunc() {
795 Constant *GCOVProfiler::getEmitFunctionFunc() {
807 Constant *GCOVProfiler::getEmitArcsFunc() {
816 Constant *GCOVProfiler::getSummaryInfoFunc() {
821 Constant *GCOVProfiler::getEndFileFunc() {
833 "__llvm_gcov_global_state_pred");
839 Function *GCOVProfiler::insertCounterWriteout(
840 ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) {
845 "__llvm_gcov_writeout", M);
847 WriteoutF->
addFnAttr(Attribute::NoInline);
848 if (Options.NoRedZone)
849 WriteoutF->
addFnAttr(Attribute::NoRedZone);
854 Constant *StartFile = getStartFileFunc();
855 Constant *EmitFunction = getEmitFunctionFunc();
856 Constant *EmitArcs = getEmitArcsFunc();
857 Constant *SummaryInfo = getSummaryInfoFunc();
858 Constant *EndFile = getEndFileFunc();
863 auto *CU = cast<DICompileUnit>(CU_Nodes->
getOperand(i));
869 std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA);
871 Builder.CreateCall(StartFile,
872 {Builder.CreateGlobalStringPtr(FilenameGcda),
873 Builder.CreateGlobalStringPtr(ReversedVersion),
874 Builder.getInt32(CfgChecksum)});
875 for (
unsigned j = 0, e = CountersBySP.
size(); j != e; ++j) {
876 auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second);
877 uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum();
880 {Builder.getInt32(j),
881 Options.FunctionNamesInData
884 Builder.getInt32(FuncChecksum),
885 Builder.getInt8(Options.UseCfgChecksum),
886 Builder.getInt32(CfgChecksum)});
891 Builder.CreateCall(EmitArcs, {Builder.getInt32(Arcs),
892 Builder.CreateConstGEP2_64(GV, 0, 0)});
894 Builder.CreateCall(SummaryInfo, {});
895 Builder.CreateCall(EndFile, {});
899 Builder.CreateRetVoid();
903 void GCOVProfiler::insertIndirectCounterIncrement() {
905 cast<Function>(GCOVProfiler::getIncrementIndirectCounterFunc());
909 if (Options.NoRedZone)
924 Value *Pred = Builder.CreateLoad(Arg,
"pred");
925 Value *Cond = Builder.CreateICmpEQ(Pred, Builder.getInt32(0xffffffff));
928 Builder.SetInsertPoint(PredNotNegOne);
932 Value *ZExtPred = Builder.CreateZExt(Pred, Builder.getInt64Ty());
936 Value *Counter = Builder.CreateLoad(GEP,
"counter");
937 Cond = Builder.CreateICmpEQ(Counter,
939 Builder.getInt64Ty()->getPointerTo()));
940 Builder.CreateCondBr(Cond, Exit, CounterEnd);
943 Builder.SetInsertPoint(CounterEnd);
944 Value *
Add = Builder.CreateAdd(Builder.CreateLoad(Counter),
945 Builder.getInt64(1));
946 Builder.CreateStore(Add, Counter);
947 Builder.CreateBr(Exit);
950 Builder.SetInsertPoint(Exit);
951 Builder.CreateRetVoid();
955 insertFlush(
ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) {
960 "__llvm_gcov_flush", M);
965 if (Options.NoRedZone)
972 assert(WriteoutF &&
"Need to create the writeout function first!");
975 Builder.CreateCall(WriteoutF, {});
978 for (
const auto &
I : CountersBySP) {
981 Builder.CreateStore(Null, GV);
986 Builder.CreateRetVoid();
static StringRef getFunctionName(TargetLowering::CallLoweringInfo &CLI)
void push_back(const T &Elt)
GCOVBlock(GCOVFunction &P, uint32_t N)
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
LLVM Argument representation.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
MDNode * getScope() const
StringMapEntry - This is used to represent one value that is inserted into a StringMap.
static cl::opt< bool > DefaultExitBlockBeforeBody("gcov-exit-block-before-body", cl::init(false), cl::Hidden)
A Module instance is used to store all the information related to an LLVM module. ...
INITIALIZE_PASS(GCOVProfilerLegacyPass,"insert-gcov-profiling","Insert instrumentation for GCOV profiling", false, false) ModulePass *llvm
static GCOVOptions getDefault()
ModulePass * createGCOVProfilerPass(const GCOVOptions &Options=GCOVOptions::getDefault())
unsigned getNumOperands() const
Return number of MDNode operands.
Type * getValueType() const
static void addEdge(SmallVectorImpl< LazyCallGraph::Edge > &Edges, DenseMap< Function *, int > &EdgeIndexMap, Function &F, LazyCallGraph::Edge::Kind EK)
static PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space...
void replace_extension(SmallVectorImpl< char > &path, const Twine &extension)
Replace the file extension of path with extension.
std::error_code current_path(SmallVectorImpl< char > &result)
Get the current path.
Type * getReturnType() const
Returns the type of the ret val.
static IntegerType * getInt64Ty(LLVMContext &C)
static PointerType * getInt64PtrTy(LLVMContext &C, unsigned AS=0)
uint64_t getDWOId() const
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
iterator begin()
Instruction iterator methods.
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
StringRef getFilename() const
void setName(const Twine &Name)
Change the name of the value.
DISubprogram * getDISubprogram(const MDNode *Scope)
Find subprogram that is enclosing this scope.
unsigned idFor(const T &Entry) const
idFor - return the ID for an existing entry.
Class to represent function types.
This file provides the interface for the GCOV style profiler pass.
Class to represent array types.
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
GCOVBlock - Collects block information.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
GCOVFunction(GCOVFile &P)
hash_code hash_value(const APFloat &Arg)
See friend declarations above.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t size() const
size - Get the string size.
Value * CreateInBoundsGEP(Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
unsigned getNumSuccessors() const
Return the number of successors that this terminator has.
StringRef filename(StringRef path)
Get filename.
initializer< Ty > init(const Ty &Val)
Subclasses of this class are all able to terminate a basic block.
A set of analyses that are preserved following a run of a transformation pass.
iterator_range< iterator > functions()
StringRef getName() const
bool empty() const
empty - Returns true if the vector is empty.
Constant * getOrInsertFunction(StringRef Name, FunctionType *T, AttributeSet AttributeList)
Look up the specified function in the module symbol table.
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
BasicBlock * getSuccessor(unsigned idx) const
Return the specified successor.
This is an important class for using LLVM in a threaded context.
Conditional or Unconditional Branch instruction.
This is an important base class in LLVM.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
static Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static Type * getVoidTy(LLVMContext &C)
MDNode * getOperand(unsigned i) const
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
cl::opt< TargetMachine::CodeGenFileType > FileType("filetype", cl::init(TargetMachine::CGFT_AssemblyFile), cl::desc("Choose a file type (not all types are supported by all targets):"), cl::values(clEnumValN(TargetMachine::CGFT_AssemblyFile,"asm","Emit an assembly ('.s') file"), clEnumValN(TargetMachine::CGFT_ObjectFile,"obj","Emit a native object ('.o') file"), clEnumValN(TargetMachine::CGFT_Null,"null","Emit nothing, for performance testing")))
static void write(bool isBE, void *P, T V)
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
StringRef getString() const
const MDOperand & getOperand(unsigned I) const
Iterator for intrusive lists based on ilist_node.
static bool functionHasLines(Function &F)
Module.h This file contains the declarations for the Module class.
void initializeGCOVProfilerLegacyPassPass(PassRegistry &)
static Constant * get(Type *Ty, uint64_t V, bool isSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
static BranchInst * Create(BasicBlock *IfTrue, Instruction *InsertBefore=nullptr)
void appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data=nullptr)
Append F to the list of global ctors of module M with the given Priority.
void setLinkage(LinkageTypes LT)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
StringRef str() const
Explicit conversion to StringRef.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static cl::opt< std::string > DefaultGCOVVersion("default-gcov-version", cl::init("402*"), cl::Hidden, cl::ValueRequired)
NamedMDNode * getNamedMetadata(const Twine &Name) const
Return the first NamedMDNode in the module with the specified name.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
GCOVFunction - Collects function information.
A raw_ostream that writes to a file descriptor.
void setUnnamedAddr(UnnamedAddr Val)
static IntegerType * getInt32Ty(LLVMContext &C)
unsigned insert(const T &Entry)
insert - Append entry to the vector if it doesn't already exist.
size_t size() const
size - Returns the number of entries in the vector.
TerminatorInst * getTerminator()
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
LLVM_ATTRIBUTE_ALWAYS_INLINE size_type size() const
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
static ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Rename collisions when linking (static functions).
BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="")
Split the basic block into two basic blocks at the specified instruction.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
LLVM Value Representation.
succ_range successors(BasicBlock *BB)
unsigned getNumOperands() const
This class implements an extremely fast bulk output stream that can only output to a stream...
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
StringRef - Represent a constant reference to a string, i.e.
A container for analyses that lazily runs them and caches their results.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, const Twine &N="", Module *M=nullptr)
DISubprogram * getSubprogram() const
Get the subprogram for this scope.
static IntegerType * getInt8Ty(LLVMContext &C)
UniqueVector - This class produces a sequential ID number (base 1) for each unique entry that is adde...
GlobalVariable * getGlobalVariable(StringRef Name) const
Look up the specified global variable in the module symbol table.
LLVMContext & getContext() const
Get the global data context.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)