Refactor GCOV's six constructor arguments into a struct with a getter that

constructs default arguments. It can now take default arguments from
cl::opt'ions. Add a new -default-gcov-version=... option, and actually test it!

Sink the reverse-order of the version into GCOVProfiling, hiding it from our
users.

llvm-svn: 177002
This commit is contained in:
Nick Lewycky 2013-03-14 05:13:26 +00:00
parent 59852367b4
commit fdfed3e9c9
4 changed files with 113 additions and 49 deletions

View File

@ -31,12 +31,32 @@ ModulePass *createOptimalEdgeProfilerPass();
ModulePass *createPathProfilerPass(); ModulePass *createPathProfilerPass();
// Insert GCOV profiling instrumentation // Insert GCOV profiling instrumentation
static const char DefaultGCovVersion[4] = {'*', '2', '0', '4'}; struct GCOVOptions {
ModulePass *createGCOVProfilerPass(bool EmitNotes = true, bool EmitData = true, static GCOVOptions getDefault();
const char (&Version)[4] =DefaultGCovVersion,
bool UseExtraChecksum = false, // Specify whether to emit .gcno files.
bool NoRedZone = false, bool EmitNotes;
bool NoFunctionNamesInData = false);
// Specify whether to modify the program to emit .gcda files when run.
bool EmitData;
// A four-byte version string. The meaning of a version string is described in
// gcc's gcov-io.h
char Version[4];
// Emit a "cfg checksum" that follows the "line number checksum" of a
// function. This affects both .gcno and .gcda files.
bool UseCfgChecksum;
// Add the 'noredzone' attribute to added runtime library calls.
bool NoRedZone;
// Emit the name of the function in the .gcda files. This is redundant, as
// the function identifier can be used to find the name from the .gcno file.
bool FunctionNamesInData;
};
ModulePass *createGCOVProfilerPass(const GCOVOptions &Options =
GCOVOptions::getDefault());
// Insert AddressSanitizer (address sanity checking) instrumentation // Insert AddressSanitizer (address sanity checking) instrumentation
FunctionPass *createAddressSanitizerFunctionPass( FunctionPass *createAddressSanitizerFunctionPass(
@ -54,7 +74,6 @@ FunctionPass *createMemorySanitizerPass(bool TrackOrigins = false,
// Insert ThreadSanitizer (race detection) instrumentation // Insert ThreadSanitizer (race detection) instrumentation
FunctionPass *createThreadSanitizerPass(StringRef BlacklistFile = StringRef()); FunctionPass *createThreadSanitizerPass(StringRef BlacklistFile = StringRef());
// BoundsChecking - This pass instruments the code to perform run-time bounds // BoundsChecking - This pass instruments the code to perform run-time bounds
// checking on loads, stores, and other memory intrinsics. // checking on loads, stores, and other memory intrinsics.
FunctionPass *createBoundsCheckingPass(); FunctionPass *createBoundsCheckingPass();

View File

@ -29,6 +29,7 @@
#include "llvm/IR/Instructions.h" #include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/Pass.h" #include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/DebugLoc.h" #include "llvm/Support/DebugLoc.h"
#include "llvm/Support/InstIterator.h" #include "llvm/Support/InstIterator.h"
@ -39,30 +40,52 @@
#include <utility> #include <utility>
using namespace llvm; using namespace llvm;
static cl::opt<std::string>
DefaultGCOVVersion("default-gcov-version", cl::init("402*"), cl::Hidden,
cl::ValueRequired);
GCOVOptions GCOVOptions::getDefault() {
GCOVOptions Options;
Options.EmitNotes = true;
Options.EmitData = true;
Options.UseCfgChecksum = false;
Options.NoRedZone = false;
Options.FunctionNamesInData = true;
if (DefaultGCOVVersion.size() != 4) {
llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") +
DefaultGCOVVersion);
}
memcpy(Options.Version, DefaultGCOVVersion.c_str(), 4);
return Options;
}
namespace { namespace {
class GCOVProfiler : public ModulePass { class GCOVProfiler : public ModulePass {
public: public:
static char ID; static char ID;
GCOVProfiler() GCOVProfiler() : ModulePass(ID), Options(GCOVOptions::getDefault()) {
: ModulePass(ID), EmitNotes(true), EmitData(true), ReversedVersion[0] = Options.Version[3];
UseExtraChecksum(false), NoRedZone(false), ReversedVersion[1] = Options.Version[2];
NoFunctionNamesInData(false) { ReversedVersion[2] = Options.Version[1];
memcpy(Version, DefaultGCovVersion, 4); ReversedVersion[3] = Options.Version[0];
ReversedVersion[4] = '\0';
initializeGCOVProfilerPass(*PassRegistry::getPassRegistry()); initializeGCOVProfilerPass(*PassRegistry::getPassRegistry());
} }
GCOVProfiler(bool EmitNotes, bool EmitData, const char (&Version)[4], GCOVProfiler(const GCOVOptions &Options) : ModulePass(ID), Options(Options){
bool UseExtraChecksum, bool NoRedZone, assert((Options.EmitNotes || Options.EmitData) &&
bool NoFunctionNamesInData) "GCOVProfiler asked to do nothing?");
: ModulePass(ID), EmitNotes(EmitNotes), EmitData(EmitData), ReversedVersion[0] = Options.Version[3];
UseExtraChecksum(UseExtraChecksum), NoRedZone(NoRedZone), ReversedVersion[1] = Options.Version[2];
NoFunctionNamesInData(NoFunctionNamesInData) { ReversedVersion[2] = Options.Version[1];
memcpy(this->Version, Version, 4); ReversedVersion[3] = Options.Version[0];
assert((EmitNotes || EmitData) && "GCOVProfiler asked to do nothing?"); ReversedVersion[4] = '\0';
initializeGCOVProfilerPass(*PassRegistry::getPassRegistry()); initializeGCOVProfilerPass(*PassRegistry::getPassRegistry());
} }
virtual const char *getPassName() const { virtual const char *getPassName() const {
return "GCOV Profiler"; return "GCOV Profiler";
} }
private: private:
bool runOnModule(Module &M); bool runOnModule(Module &M);
@ -99,12 +122,10 @@ namespace {
std::string mangleName(DICompileUnit CU, const char *NewStem); std::string mangleName(DICompileUnit CU, const char *NewStem);
bool EmitNotes; GCOVOptions Options;
bool EmitData;
char Version[4]; // This is stored in reverse order for direct emission. // Reversed, NUL-terminated copy of Options.Version.
bool UseExtraChecksum; char ReversedVersion[5];
bool NoRedZone;
bool NoFunctionNamesInData;
Module *M; Module *M;
LLVMContext *Ctx; LLVMContext *Ctx;
@ -115,13 +136,8 @@ char GCOVProfiler::ID = 0;
INITIALIZE_PASS(GCOVProfiler, "insert-gcov-profiling", INITIALIZE_PASS(GCOVProfiler, "insert-gcov-profiling",
"Insert instrumentation for GCOV profiling", false, false) "Insert instrumentation for GCOV profiling", false, false)
ModulePass *llvm::createGCOVProfilerPass(bool EmitNotes, bool EmitData, ModulePass *llvm::createGCOVProfilerPass(const GCOVOptions &Options) {
const char (&Version)[4], return new GCOVProfiler(Options);
bool UseExtraChecksum,
bool NoRedZone,
bool NoFunctionNamesInData) {
return new GCOVProfiler(EmitNotes, EmitData, Version, UseExtraChecksum,
NoRedZone, NoFunctionNamesInData);
} }
namespace { namespace {
@ -260,7 +276,7 @@ namespace {
class GCOVFunction : public GCOVRecord { class GCOVFunction : public GCOVRecord {
public: public:
GCOVFunction(DISubprogram SP, raw_ostream *os, uint32_t Ident, GCOVFunction(DISubprogram SP, raw_ostream *os, uint32_t Ident,
bool UseExtraChecksum) { bool UseCfgChecksum) {
this->os = os; this->os = os;
Function *F = SP.getFunction(); Function *F = SP.getFunction();
@ -274,12 +290,12 @@ namespace {
writeBytes(FunctionTag, 4); writeBytes(FunctionTag, 4);
uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(SP.getName()) + uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(SP.getName()) +
1 + lengthOfGCOVString(SP.getFilename()) + 1; 1 + lengthOfGCOVString(SP.getFilename()) + 1;
if (UseExtraChecksum) if (UseCfgChecksum)
++BlockLen; ++BlockLen;
write(BlockLen); write(BlockLen);
write(Ident); write(Ident);
write(0); // lineno checksum write(0); // lineno checksum
if (UseExtraChecksum) if (UseCfgChecksum)
write(0); // cfg checksum write(0); // cfg checksum
writeGCOVString(SP.getName()); writeGCOVString(SP.getName());
writeGCOVString(SP.getFilename()); writeGCOVString(SP.getFilename());
@ -363,8 +379,8 @@ bool GCOVProfiler::runOnModule(Module &M) {
this->M = &M; this->M = &M;
Ctx = &M.getContext(); Ctx = &M.getContext();
if (EmitNotes) emitProfileNotes(); if (Options.EmitNotes) emitProfileNotes();
if (EmitData) return emitProfileArcs(); if (Options.EmitData) return emitProfileArcs();
return false; return false;
} }
@ -379,10 +395,11 @@ void GCOVProfiler::emitProfileNotes() {
DICompileUnit CU(CU_Nodes->getOperand(i)); DICompileUnit CU(CU_Nodes->getOperand(i));
std::string ErrorInfo; std::string ErrorInfo;
outs() << "outputting gcno to: " << mangleName(CU, "gcno") << "\n";
raw_fd_ostream out(mangleName(CU, "gcno").c_str(), ErrorInfo, raw_fd_ostream out(mangleName(CU, "gcno").c_str(), ErrorInfo,
raw_fd_ostream::F_Binary); raw_fd_ostream::F_Binary);
out.write("oncg", 4); out.write("oncg", 4);
out.write(Version, 4); out.write(ReversedVersion, 4);
out.write("MVLL", 4); out.write("MVLL", 4);
DIArray SPs = CU.getSubprograms(); DIArray SPs = CU.getSubprograms();
@ -392,7 +409,7 @@ void GCOVProfiler::emitProfileNotes() {
Function *F = SP.getFunction(); Function *F = SP.getFunction();
if (!F) continue; if (!F) continue;
GCOVFunction Func(SP, &out, i, UseExtraChecksum); GCOVFunction Func(SP, &out, i, Options.UseCfgChecksum);
for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
GCOVBlock &Block = Func.getBlock(BB); GCOVBlock &Block = Func.getBlock(BB);
@ -646,7 +663,7 @@ void GCOVProfiler::insertCounterWriteout(
"__llvm_gcov_writeout", M); "__llvm_gcov_writeout", M);
WriteoutF->setUnnamedAddr(true); WriteoutF->setUnnamedAddr(true);
WriteoutF->addFnAttr(Attribute::NoInline); WriteoutF->addFnAttr(Attribute::NoInline);
if (NoRedZone) if (Options.NoRedZone)
WriteoutF->addFnAttr(Attribute::NoRedZone); WriteoutF->addFnAttr(Attribute::NoRedZone);
BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF); BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF);
@ -664,15 +681,15 @@ void GCOVProfiler::insertCounterWriteout(
std::string FilenameGcda = mangleName(CU, "gcda"); std::string FilenameGcda = mangleName(CU, "gcda");
Builder.CreateCall2(StartFile, Builder.CreateCall2(StartFile,
Builder.CreateGlobalStringPtr(FilenameGcda), Builder.CreateGlobalStringPtr(FilenameGcda),
Builder.CreateGlobalStringPtr(Version)); Builder.CreateGlobalStringPtr(ReversedVersion));
for (unsigned j = 0, e = CountersBySP.size(); j != e; ++j) { for (unsigned j = 0, e = CountersBySP.size(); j != e; ++j) {
DISubprogram SP(CountersBySP[j].second); DISubprogram SP(CountersBySP[j].second);
Builder.CreateCall3(EmitFunction, Builder.CreateCall3(EmitFunction,
Builder.getInt32(j), Builder.getInt32(j),
NoFunctionNamesInData ? Options.FunctionNamesInData ?
Constant::getNullValue(Builder.getInt8PtrTy()) : Builder.CreateGlobalStringPtr(SP.getName()) :
Builder.CreateGlobalStringPtr(SP.getName()), Constant::getNullValue(Builder.getInt8PtrTy()),
Builder.getInt8(UseExtraChecksum)); Builder.getInt8(Options.UseCfgChecksum));
GlobalVariable *GV = CountersBySP[j].first; GlobalVariable *GV = CountersBySP[j].first;
unsigned Arcs = unsigned Arcs =
@ -694,7 +711,7 @@ void GCOVProfiler::insertCounterWriteout(
F->setUnnamedAddr(true); F->setUnnamedAddr(true);
F->setLinkage(GlobalValue::InternalLinkage); F->setLinkage(GlobalValue::InternalLinkage);
F->addFnAttr(Attribute::NoInline); F->addFnAttr(Attribute::NoInline);
if (NoRedZone) if (Options.NoRedZone)
F->addFnAttr(Attribute::NoRedZone); F->addFnAttr(Attribute::NoRedZone);
BB = BasicBlock::Create(*Ctx, "entry", F); BB = BasicBlock::Create(*Ctx, "entry", F);
@ -715,7 +732,7 @@ void GCOVProfiler::insertIndirectCounterIncrement() {
Fn->setUnnamedAddr(true); Fn->setUnnamedAddr(true);
Fn->setLinkage(GlobalValue::InternalLinkage); Fn->setLinkage(GlobalValue::InternalLinkage);
Fn->addFnAttr(Attribute::NoInline); Fn->addFnAttr(Attribute::NoInline);
if (NoRedZone) if (Options.NoRedZone)
Fn->addFnAttr(Attribute::NoRedZone); Fn->addFnAttr(Attribute::NoRedZone);
// Create basic blocks for function. // Create basic blocks for function.
@ -771,7 +788,7 @@ insertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) {
FlushF->setLinkage(GlobalValue::InternalLinkage); FlushF->setLinkage(GlobalValue::InternalLinkage);
FlushF->setUnnamedAddr(true); FlushF->setUnnamedAddr(true);
FlushF->addFnAttr(Attribute::NoInline); FlushF->addFnAttr(Attribute::NoInline);
if (NoRedZone) if (Options.NoRedZone)
FlushF->addFnAttr(Attribute::NoRedZone); FlushF->addFnAttr(Attribute::NoRedZone);
BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF); BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF);

View File

@ -0,0 +1 @@
config.suffixes = ['.ll', '.c', '.cpp']

View File

@ -0,0 +1,27 @@
; RUN: echo '!9 = metadata !{metadata !"%s", metadata !0}' > %t1
; RUN: cat %s %t1 > %t2
; RUN: opt -insert-gcov-profiling -disable-output < %t2
; RUN: head -c12 version.gcno | grep '^oncg\*204MVLL$'
; RUN: rm version.gcno
; RUN: not opt -insert-gcov-profiling -default-gcov-version=asdfasdf -disable-output < %t2
; RUN: opt -insert-gcov-profiling -default-gcov-version=407* -disable-output < %t2
; RUN: head -c12 version.gcno | grep '^oncg\*704MVLL$'
; RUN: rm version.gcno
define void @test() {
ret void, !dbg !8
}
!llvm.gcov = !{!9}
!llvm.dbg.cu = !{!0}
!0 = metadata !{metadata !"%s/version", metadata !1}
!1 = metadata !{i32 786449, i32 0, i32 4, metadata !2, metadata !"clang version 3.3 (trunk 176994)", i1 false, metadata !"", i32 0, metadata !3, metadata !3, metadata !4, metadata !3, metadata !""} ; [ DW_TAG_compile_unit ] [./version] [DW_LANG_C_plus_plus]
!2 = metadata !{i32 786473, metadata !"version", metadata !"/usr/local/google/home/nlewycky"} ; [ DW_TAG_file_type ]
!3 = metadata !{i32 0}
!4 = metadata !{metadata !5}
!5 = metadata !{i32 786478, i32 0, metadata !6, metadata !"test", metadata !"test", metadata !"", metadata !6, i32 1, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @test, null, null, metadata !3, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [test]
!6 = metadata !{i32 786473, metadata !"<stdin>", metadata !"."} ; [ DW_TAG_file_type ]
!7 = metadata !{i32 786453, i32 0, metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !3, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
!8= metadata !{i32 1, i32 0, metadata !5, null}
;; !9 is added through the echo line at the top.