Introduce the __llvm_gcov_flush function.

This function writes out the current values of the counters and then resets
them. This can be used similarly to the __gcov_flush function to sync the
counters when need be. For instance, in a situation where the application
doesn't exit.
<rdar://problem/12185886>

llvm-svn: 163757
This commit is contained in:
Bill Wendling 2012-09-13 00:09:55 +00:00
parent b261a50b40
commit 2e6e86606a
1 changed files with 56 additions and 6 deletions

View File

@ -34,6 +34,7 @@
#include "llvm/Support/InstIterator.h" #include "llvm/Support/InstIterator.h"
#include "llvm/Support/PathV2.h" #include "llvm/Support/PathV2.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/Utils/ModuleUtils.h" #include "llvm/Transforms/Utils/ModuleUtils.h"
#include <string> #include <string>
#include <utility> #include <utility>
@ -90,6 +91,7 @@ namespace {
// list. // list.
void insertCounterWriteout(ArrayRef<std::pair<GlobalVariable*, MDNode*> >); void insertCounterWriteout(ArrayRef<std::pair<GlobalVariable*, MDNode*> >);
void insertIndirectCounterIncrement(); void insertIndirectCounterIncrement();
void insertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> >);
std::string mangleName(DICompileUnit CU, const char *NewStem); std::string mangleName(DICompileUnit CU, const char *NewStem);
@ -100,6 +102,7 @@ namespace {
Module *M; Module *M;
LLVMContext *Ctx; LLVMContext *Ctx;
const TargetData *TD;
}; };
} }
@ -351,6 +354,7 @@ std::string GCOVProfiler::mangleName(DICompileUnit CU, const char *NewStem) {
bool GCOVProfiler::runOnModule(Module &M) { bool GCOVProfiler::runOnModule(Module &M) {
this->M = &M; this->M = &M;
TD = getAnalysisIfAvailable<TargetData>();
Ctx = &M.getContext(); Ctx = &M.getContext();
if (EmitNotes) emitGCNO(); if (EmitNotes) emitGCNO();
@ -518,6 +522,7 @@ bool GCOVProfiler::emitProfileArcs() {
} }
insertCounterWriteout(CountersBySP); insertCounterWriteout(CountersBySP);
insertFlush(CountersBySP);
} }
if (InsertIndCounterIncrCode) if (InsertIndCounterIncrCode)
@ -630,13 +635,14 @@ GlobalVariable *GCOVProfiler::getEdgeStateValue() {
void GCOVProfiler::insertCounterWriteout( void GCOVProfiler::insertCounterWriteout(
ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) { ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) {
FunctionType *WriteoutFTy = FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
FunctionType::get(Type::getVoidTy(*Ctx), false); Function *WriteoutF = M->getFunction("__llvm_gcov_writeout");
Function *WriteoutF = Function::Create(WriteoutFTy, if (!WriteoutF)
GlobalValue::InternalLinkage, WriteoutF = Function::Create(WriteoutFTy, GlobalValue::InternalLinkage,
"__llvm_gcov_writeout", M); "__llvm_gcov_writeout", M);
WriteoutF->setUnnamedAddr(true); WriteoutF->setUnnamedAddr(true);
BasicBlock *BB = BasicBlock::Create(*Ctx, "", WriteoutF);
BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF);
IRBuilder<> Builder(BB); IRBuilder<> Builder(BB);
Constant *StartFile = getStartFileFunc(); Constant *StartFile = getStartFileFunc();
@ -744,3 +750,47 @@ void GCOVProfiler::insertIndirectCounterIncrement() {
Builder.SetInsertPoint(Exit); Builder.SetInsertPoint(Exit);
Builder.CreateRetVoid(); Builder.CreateRetVoid();
} }
void GCOVProfiler::
insertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) {
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
Function *FlushF = M->getFunction("__llvm_gcov_flush");
if (!FlushF)
FlushF = Function::Create(FTy, GlobalValue::InternalLinkage,
"__llvm_gcov_flush", M);
else
FlushF->setLinkage(GlobalValue::InternalLinkage);
FlushF->setUnnamedAddr(true);
Type *Int8Ty = Type::getInt8Ty(*Ctx);
Type *Int64Ty = Type::getInt64Ty(*Ctx);
BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF);
// Write out the current counters.
Constant *WriteoutF = M->getFunction("__llvm_gcov_writeout");
assert(WriteoutF && "Need to create the writeout function first!");
IRBuilder<> Builder(Entry);
Builder.CreateCall(WriteoutF);
if (TD)
// Zero out the counters.
for (ArrayRef<std::pair<GlobalVariable *, MDNode *> >::iterator
I = CountersBySP.begin(), E = CountersBySP.end();
I != E; ++I) {
GlobalVariable *GV = I->first;
uint64_t NumBytes = TD->getTypeAllocSize(GV->getType()->getElementType());
Builder.CreateMemSet(Builder.CreateConstGEP2_64(GV, 0, 0),
ConstantInt::get(Int8Ty, 0),
ConstantInt::get(Int64Ty, NumBytes), false);
}
Type *RetTy = FlushF->getReturnType();
if (RetTy == Type::getVoidTy(*Ctx))
Builder.CreateRetVoid();
else if (RetTy->isIntegerTy())
// Used if __llvm_gcov_flush was implicitly declared.
Builder.CreateRet(ConstantInt::get(RetTy, 0));
else
report_fatal_error("invalid return type for __llvm_gcov_flush");
}