@@ -115,7 +115,8 @@ class GCOVProfiler {
115
115
// list.
116
116
Function *
117
117
insertCounterWriteout (ArrayRef<std::pair<GlobalVariable *, MDNode *>>);
118
- Function *insertFlush (ArrayRef<std::pair<GlobalVariable *, MDNode *>>);
118
+ Function *insertReset (ArrayRef<std::pair<GlobalVariable *, MDNode *>>);
119
+ Function *insertFlush (Function *ResetF);
119
120
120
121
void AddFlushBeforeForkAndExec ();
121
122
@@ -630,35 +631,76 @@ static bool shouldKeepInEntry(BasicBlock::iterator It) {
630
631
}
631
632
632
633
void GCOVProfiler::AddFlushBeforeForkAndExec () {
633
- SmallVector<Instruction *, 2 > ForkAndExecs;
634
+ SmallVector<CallInst *, 2 > Forks;
635
+ SmallVector<CallInst *, 2 > Execs;
634
636
for (auto &F : M->functions ()) {
635
637
auto *TLI = &GetTLI (F);
636
638
for (auto &I : instructions (F)) {
637
639
if (CallInst *CI = dyn_cast<CallInst>(&I)) {
638
640
if (Function *Callee = CI->getCalledFunction ()) {
639
641
LibFunc LF;
640
- if (TLI->getLibFunc (*Callee, LF) &&
641
- (LF == LibFunc_fork || LF == LibFunc_execl ||
642
- LF == LibFunc_execle || LF == LibFunc_execlp ||
643
- LF == LibFunc_execv || LF == LibFunc_execvp ||
644
- LF == LibFunc_execve || LF == LibFunc_execvpe ||
645
- LF == LibFunc_execvP)) {
646
- ForkAndExecs.push_back (&I);
642
+ if (TLI->getLibFunc (*Callee, LF)) {
643
+ if (LF == LibFunc_fork) {
644
+ #if !defined(_WIN32)
645
+ Forks.push_back (CI);
646
+ #endif
647
+ } else if (LF == LibFunc_execl || LF == LibFunc_execle ||
648
+ LF == LibFunc_execlp || LF == LibFunc_execv ||
649
+ LF == LibFunc_execvp || LF == LibFunc_execve ||
650
+ LF == LibFunc_execvpe || LF == LibFunc_execvP) {
651
+ Execs.push_back (CI);
652
+ }
647
653
}
648
654
}
649
655
}
650
656
}
651
657
}
652
658
653
- // We need to split the block after the fork/exec call
654
- // because else the counters for the lines after will be
655
- // the same as before the call.
656
- for (auto I : ForkAndExecs) {
657
- IRBuilder<> Builder (I);
659
+ for (auto F : Forks) {
660
+ IRBuilder<> Builder (F);
661
+ BasicBlock *Parent = F->getParent ();
662
+ auto NextInst = ++F->getIterator ();
663
+
664
+ // We've a fork so just reset the counters in the child process
665
+ FunctionType *FTy = FunctionType::get (Builder.getInt32Ty (), {}, false );
666
+ FunctionCallee GCOVFork = M->getOrInsertFunction (" __gcov_fork" , FTy);
667
+ F->setCalledFunction (GCOVFork);
668
+
669
+ // We split just after the fork to have a counter for the lines after
670
+ // Anyway there's a bug:
671
+ // void foo() { fork(); }
672
+ // void bar() { foo(); blah(); }
673
+ // then "blah();" will be called 2 times but showed as 1
674
+ // because "blah()" belongs to the same block as "foo();"
675
+ Parent->splitBasicBlock (NextInst);
676
+
677
+ // back() is a br instruction with a debug location
678
+ // equals to the one from NextAfterFork
679
+ // So to avoid to have two debug locs on two blocks just change it
680
+ DebugLoc Loc = F->getDebugLoc ();
681
+ Parent->back ().setDebugLoc (Loc);
682
+ }
683
+
684
+ for (auto E : Execs) {
685
+ IRBuilder<> Builder (E);
686
+ BasicBlock *Parent = E->getParent ();
687
+ auto NextInst = ++E->getIterator ();
688
+
689
+ // Since the process is replaced by a new one we need to write out gcdas
690
+ // No need to reset the counters since they'll be lost after the exec**
658
691
FunctionType *FTy = FunctionType::get (Builder.getVoidTy (), {}, false );
659
- FunctionCallee GCOVFlush = M->getOrInsertFunction (" __gcov_flush" , FTy);
660
- Builder.CreateCall (GCOVFlush);
661
- I->getParent ()->splitBasicBlock (I);
692
+ FunctionCallee WriteoutF =
693
+ M->getOrInsertFunction (" llvm_writeout_files" , FTy);
694
+ Builder.CreateCall (WriteoutF);
695
+
696
+ DebugLoc Loc = E->getDebugLoc ();
697
+ Builder.SetInsertPoint (&*NextInst);
698
+ // If the exec** fails we must reset the counters since they've been
699
+ // dumped
700
+ FunctionCallee ResetF = M->getOrInsertFunction (" llvm_reset_counters" , FTy);
701
+ Builder.CreateCall (ResetF)->setDebugLoc (Loc);
702
+ Parent->splitBasicBlock (NextInst);
703
+ Parent->back ().setDebugLoc (Loc);
662
704
}
663
705
}
664
706
@@ -850,7 +892,8 @@ bool GCOVProfiler::emitProfileArcs() {
850
892
}
851
893
852
894
Function *WriteoutF = insertCounterWriteout (CountersBySP);
853
- Function *FlushF = insertFlush (CountersBySP);
895
+ Function *ResetF = insertReset (CountersBySP);
896
+ Function *FlushF = insertFlush (ResetF);
854
897
855
898
// Create a small bit of code that registers the "__llvm_gcov_writeout" to
856
899
// be executed at exit and the "__llvm_gcov_flush" function to be executed
@@ -868,16 +911,14 @@ bool GCOVProfiler::emitProfileArcs() {
868
911
IRBuilder<> Builder (BB);
869
912
870
913
FTy = FunctionType::get (Type::getVoidTy (*Ctx), false );
871
- Type *Params[] = {
872
- PointerType::get (FTy, 0 ),
873
- PointerType::get (FTy, 0 )
874
- };
914
+ Type *Params[] = {PointerType::get (FTy, 0 ), PointerType::get (FTy, 0 ),
915
+ PointerType::get (FTy, 0 )};
875
916
FTy = FunctionType::get (Builder.getVoidTy (), Params, false );
876
917
877
- // Initialize the environment and register the local writeout and flush
878
- // functions.
918
+ // Initialize the environment and register the local writeout, flush and
919
+ // reset functions.
879
920
FunctionCallee GCOVInit = M->getOrInsertFunction (" llvm_gcov_init" , FTy);
880
- Builder.CreateCall (GCOVInit, {WriteoutF, FlushF});
921
+ Builder.CreateCall (GCOVInit, {WriteoutF, FlushF, ResetF });
881
922
Builder.CreateRetVoid ();
882
923
883
924
appendToGlobalCtors (*M, F, 0 );
@@ -1190,8 +1231,43 @@ Function *GCOVProfiler::insertCounterWriteout(
1190
1231
return WriteoutF;
1191
1232
}
1192
1233
1193
- Function *GCOVProfiler::
1194
- insertFlush (ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) {
1234
+ Function *GCOVProfiler::insertReset (
1235
+ ArrayRef<std::pair<GlobalVariable *, MDNode *>> CountersBySP) {
1236
+ FunctionType *FTy = FunctionType::get (Type::getVoidTy (*Ctx), false );
1237
+ Function *ResetF = M->getFunction (" __llvm_gcov_reset" );
1238
+ if (!ResetF)
1239
+ ResetF = Function::Create (FTy, GlobalValue::InternalLinkage,
1240
+ " __llvm_gcov_reset" , M);
1241
+ else
1242
+ ResetF->setLinkage (GlobalValue::InternalLinkage);
1243
+ ResetF->setUnnamedAddr (GlobalValue::UnnamedAddr::Global);
1244
+ ResetF->addFnAttr (Attribute::NoInline);
1245
+ if (Options.NoRedZone )
1246
+ ResetF->addFnAttr (Attribute::NoRedZone);
1247
+
1248
+ BasicBlock *Entry = BasicBlock::Create (*Ctx, " entry" , ResetF);
1249
+ IRBuilder<> Builder (Entry);
1250
+
1251
+ // Zero out the counters.
1252
+ for (const auto &I : CountersBySP) {
1253
+ GlobalVariable *GV = I.first ;
1254
+ Constant *Null = Constant::getNullValue (GV->getValueType ());
1255
+ Builder.CreateStore (Null, GV);
1256
+ }
1257
+
1258
+ Type *RetTy = ResetF->getReturnType ();
1259
+ if (RetTy->isVoidTy ())
1260
+ Builder.CreateRetVoid ();
1261
+ else if (RetTy->isIntegerTy ())
1262
+ // Used if __llvm_gcov_reset was implicitly declared.
1263
+ Builder.CreateRet (ConstantInt::get (RetTy, 0 ));
1264
+ else
1265
+ report_fatal_error (" invalid return type for __llvm_gcov_reset" );
1266
+
1267
+ return ResetF;
1268
+ }
1269
+
1270
+ Function *GCOVProfiler::insertFlush (Function *ResetF) {
1195
1271
FunctionType *FTy = FunctionType::get (Type::getVoidTy (*Ctx), false );
1196
1272
Function *FlushF = M->getFunction (" __llvm_gcov_flush" );
1197
1273
if (!FlushF)
@@ -1212,16 +1288,10 @@ insertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) {
1212
1288
1213
1289
IRBuilder<> Builder (Entry);
1214
1290
Builder.CreateCall (WriteoutF, {});
1215
-
1216
- // Zero out the counters.
1217
- for (const auto &I : CountersBySP) {
1218
- GlobalVariable *GV = I.first ;
1219
- Constant *Null = Constant::getNullValue (GV->getValueType ());
1220
- Builder.CreateStore (Null, GV);
1221
- }
1291
+ Builder.CreateCall (ResetF, {});
1222
1292
1223
1293
Type *RetTy = FlushF->getReturnType ();
1224
- if (RetTy == Type::getVoidTy (*Ctx ))
1294
+ if (RetTy-> isVoidTy ( ))
1225
1295
Builder.CreateRetVoid ();
1226
1296
else if (RetTy->isIntegerTy ())
1227
1297
// Used if __llvm_gcov_flush was implicitly declared.
0 commit comments