#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/PathV2.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
+#include <algorithm>
#include <string>
#include <utility>
using namespace llvm;
Constant *getIncrementIndirectCounterFunc();
Constant *getEmitFunctionFunc();
Constant *getEmitArcsFunc();
+ Constant *getDeleteWriteoutFunctionListFunc();
Constant *getDeleteFlushFunctionListFunc();
Constant *getEndFileFunc();
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() {}
// 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.
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;
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();
}
SmallVector<uint32_t, 32> Lines;
};
+
+ // Sorting function for deterministic behaviour in GCOVBlock::writeOut.
+ struct StringKeySort {
+ bool operator()(StringMapEntry<GCOVLines *> *LHS,
+ StringMapEntry<GCOVLines *> *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.
void writeOut() {
uint32_t Len = 3;
+ SmallVector<StringMapEntry<GCOVLines *> *, 32> SortedLinesByFile;
for (StringMap<GCOVLines *>::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<GCOVLines *>::iterator I = LinesByFile.begin(),
- E = LinesByFile.end(); I != E; ++I)
- I->second->writeOut();
+
+ StringKeySort Sorter;
+ std::sort(SortedLinesByFile.begin(), SortedLinesByFile.end(), Sorter);
+ for (SmallVectorImpl<StringMapEntry<GCOVLines *> *>::iterator
+ I = SortedLinesByFile.begin(), E = SortedLinesByFile.end();
+ I != E; ++I)
+ (*I)->getValue()->writeOut();
write(0);
write(0);
}
DEBUG(dbgs() << Blocks.size() << " blocks.\n");
// Emit edges between blocks.
- for (DenseMap<BasicBlock *, GCOVBlock *>::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 = *Blocks[I];
if (Block.OutEdges.empty()) continue;
writeBytes(EdgeTag, 4);
}
// Emit lines for each block.
- for (DenseMap<BasicBlock *, GCOVBlock *>::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) {
+ Blocks[I]->writeOut();
}
}
SmallString<128> Filename = CU.getFilename();
sys::path::replace_extension(Filename, NewStem);
- return sys::path::filename(Filename.str());
+ StringRef FName = sys::path::filename(Filename);
+ SmallString<128> CurPath;
+ if (sys::fs::current_path(CurPath)) return FName;
+ sys::path::append(CurPath, FName.str());
+ return CurPath.str();
}
bool GCOVProfiler::runOnModule(Module &M) {
DICompileUnit CU(CU_Nodes->getOperand(i));
std::string ErrorInfo;
raw_fd_ostream out(mangleName(CU, "gcno").c_str(), ErrorInfo,
- raw_fd_ostream::F_Binary);
+ sys::fs::F_Binary);
out.write("oncg", 4);
out.write(ReversedVersion, 4);
out.write("MVLL", 4);
DIArray SPs = CU.getSubprograms();
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;
SmallVector<std::pair<GlobalVariable *, MDNode *>, 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 (!Result) Result = true;
Function *FlushF = insertFlush(CountersBySP);
// Create a small bit of code that registers the "__llvm_gcov_writeout" to
- // be executed at exit and the "__llvm_gcov_flush" function to be executed
- // when "__gcov_flush" is called.
+ // be executed at exit and the "__llvm_gcov_flush" function to be executed
+ // when "__gcov_flush" is called.
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
Function *F = Function::Create(FTy, GlobalValue::InternalLinkage,
"__llvm_gcov_init", M);
BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F);
IRBuilder<> Builder(BB);
- FTy = FunctionType::get(Builder.getInt32Ty(),
- PointerType::get(FTy, 0), false);
- Constant *AtExitFn = M->getOrInsertFunction("atexit", FTy);
- Builder.CreateCall(AtExitFn, WriteoutF);
-
- // Register the local flush function.
FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
- FTy = FunctionType::get(Builder.getVoidTy(),
- PointerType::get(FTy, 0), false);
- Constant *RegFlush =
- M->getOrInsertFunction("llvm_register_flush_function", FTy);
- Builder.CreateCall(RegFlush, FlushF);
-
- // Make sure that all the flush function list is deleted.
- Builder.CreateCall(AtExitFn, getDeleteFlushFunctionListFunc());
+ Type *Params[] = {
+ PointerType::get(FTy, 0),
+ PointerType::get(FTy, 0)
+ };
+ FTy = FunctionType::get(Builder.getVoidTy(), Params, false);
+
+ // Inialize the environment and register the local writeout and flush
+ // functions.
+ Constant *GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy);
+ Builder.CreateCall2(GCOVInit, WriteoutF, FlushF);
Builder.CreateRetVoid();
appendToGlobalCtors(*M, F, 0);
return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy);
}
+Constant *GCOVProfiler::getDeleteWriteoutFunctionListFunc() {
+ FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
+ return M->getOrInsertFunction("llvm_delete_writeout_function_list", FTy);
+}
+
Constant *GCOVProfiler::getDeleteFlushFunctionListFunc() {
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
return M->getOrInsertFunction("llvm_delete_flush_function_list", FTy);