Skip to content

Commit 8b2bdfb

Browse files
committed
[Coverage][clang] Enable MC/DC Support in LLVM Source-based Code Coverage (3/3)
Part 3 of 3. This includes the MC/DC clang front-end components. Differential Revision: https://reviews.llvm.org/D138849
1 parent 85939e5 commit 8b2bdfb

29 files changed

+1700
-90
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to
209209
///< enable code coverage analysis.
210210
CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping
211211
///< regions.
212+
CODEGENOPT(MCDCCoverage , 1, 0) ///< Enable MC/DC code coverage criteria.
212213

213214
/// If -fpcc-struct-return or -freg-struct-return is specified.
214215
ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default)

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,12 @@ defm coverage_mapping : BoolFOption<"coverage-mapping",
16951695
"Generate coverage mapping to enable code coverage analysis">,
16961696
NegFlag<SetFalse, [], [ClangOption], "Disable code coverage analysis">, BothFlags<
16971697
[], [ClangOption, CLOption]>>;
1698+
defm mcdc_coverage : BoolFOption<"coverage-mcdc",
1699+
CodeGenOpts<"MCDCCoverage">, DefaultFalse,
1700+
PosFlag<SetTrue, [], [ClangOption, CC1Option],
1701+
"Enable MC/DC criteria when generating code coverage">,
1702+
NegFlag<SetFalse, [], [ClangOption], "Disable MC/DC coverage criteria">,
1703+
BothFlags<[], [ClangOption, CLOption]>>;
16981704
def fprofile_generate : Flag<["-"], "fprofile-generate">,
16991705
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
17001706
HelpText<"Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">;

clang/lib/CodeGen/CGClass.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
856856
EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);
857857

858858
incrementProfileCounter(Body);
859+
maybeCreateMCDCCondBitmap();
859860

860861
RunCleanupsScope RunCleanups(*this);
861862

@@ -1444,8 +1445,10 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14441445
}
14451446

14461447
Stmt *Body = Dtor->getBody();
1447-
if (Body)
1448+
if (Body) {
14481449
incrementProfileCounter(Body);
1450+
maybeCreateMCDCCondBitmap();
1451+
}
14491452

14501453
// The call to operator delete in a deleting destructor happens
14511454
// outside of the function-try-block, which means it's always
@@ -1548,6 +1551,7 @@ void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args)
15481551
LexicalScope Scope(*this, RootCS->getSourceRange());
15491552

15501553
incrementProfileCounter(RootCS);
1554+
maybeCreateMCDCCondBitmap();
15511555
AssignmentMemcpyizer AM(*this, AssignOp, Args);
15521556
for (auto *I : RootCS->body())
15531557
AM.emitAssignment(I);

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4564,6 +4564,12 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
45644564
if (LHSCondVal) { // If we have 1 && X, just emit X.
45654565
CGF.incrementProfileCounter(E);
45664566

4567+
// If the top of the logical operator nest, reset the MCDC temp to 0.
4568+
if (CGF.MCDCLogOpStack.empty())
4569+
CGF.maybeResetMCDCCondBitmap(E);
4570+
4571+
CGF.MCDCLogOpStack.push_back(E);
4572+
45674573
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
45684574

45694575
// If we're generating for profiling or coverage, generate a branch to a
@@ -4572,6 +4578,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
45724578
// "FalseBlock" after the increment is done.
45734579
if (InstrumentRegions &&
45744580
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
4581+
CGF.maybeUpdateMCDCCondBitmap(E->getRHS(), RHSCond);
45754582
llvm::BasicBlock *FBlock = CGF.createBasicBlock("land.end");
45764583
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("land.rhscnt");
45774584
Builder.CreateCondBr(RHSCond, RHSBlockCnt, FBlock);
@@ -4581,6 +4588,11 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
45814588
CGF.EmitBlock(FBlock);
45824589
}
45834590

4591+
CGF.MCDCLogOpStack.pop_back();
4592+
// If the top of the logical operator nest, update the MCDC bitmap.
4593+
if (CGF.MCDCLogOpStack.empty())
4594+
CGF.maybeUpdateMCDCTestVectorBitmap(E);
4595+
45844596
// ZExt result to int or bool.
45854597
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext");
45864598
}
@@ -4590,6 +4602,12 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
45904602
return llvm::Constant::getNullValue(ResTy);
45914603
}
45924604

4605+
// If the top of the logical operator nest, reset the MCDC temp to 0.
4606+
if (CGF.MCDCLogOpStack.empty())
4607+
CGF.maybeResetMCDCCondBitmap(E);
4608+
4609+
CGF.MCDCLogOpStack.push_back(E);
4610+
45934611
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end");
45944612
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("land.rhs");
45954613

@@ -4622,6 +4640,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
46224640
// condition coverage.
46234641
if (InstrumentRegions &&
46244642
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
4643+
CGF.maybeUpdateMCDCCondBitmap(E->getRHS(), RHSCond);
46254644
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("land.rhscnt");
46264645
Builder.CreateCondBr(RHSCond, RHSBlockCnt, ContBlock);
46274646
CGF.EmitBlock(RHSBlockCnt);
@@ -4639,6 +4658,11 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
46394658
// Insert an entry into the phi node for the edge with the value of RHSCond.
46404659
PN->addIncoming(RHSCond, RHSBlock);
46414660

4661+
CGF.MCDCLogOpStack.pop_back();
4662+
// If the top of the logical operator nest, update the MCDC bitmap.
4663+
if (CGF.MCDCLogOpStack.empty())
4664+
CGF.maybeUpdateMCDCTestVectorBitmap(E);
4665+
46424666
// Artificial location to preserve the scope information
46434667
{
46444668
auto NL = ApplyDebugLocation::CreateArtificial(CGF);
@@ -4680,6 +4704,12 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
46804704
if (!LHSCondVal) { // If we have 0 || X, just emit X.
46814705
CGF.incrementProfileCounter(E);
46824706

4707+
// If the top of the logical operator nest, reset the MCDC temp to 0.
4708+
if (CGF.MCDCLogOpStack.empty())
4709+
CGF.maybeResetMCDCCondBitmap(E);
4710+
4711+
CGF.MCDCLogOpStack.push_back(E);
4712+
46834713
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
46844714

46854715
// If we're generating for profiling or coverage, generate a branch to a
@@ -4688,6 +4718,7 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
46884718
// "FalseBlock" after the increment is done.
46894719
if (InstrumentRegions &&
46904720
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
4721+
CGF.maybeUpdateMCDCCondBitmap(E->getRHS(), RHSCond);
46914722
llvm::BasicBlock *FBlock = CGF.createBasicBlock("lor.end");
46924723
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("lor.rhscnt");
46934724
Builder.CreateCondBr(RHSCond, FBlock, RHSBlockCnt);
@@ -4697,6 +4728,11 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
46974728
CGF.EmitBlock(FBlock);
46984729
}
46994730

4731+
CGF.MCDCLogOpStack.pop_back();
4732+
// If the top of the logical operator nest, update the MCDC bitmap.
4733+
if (CGF.MCDCLogOpStack.empty())
4734+
CGF.maybeUpdateMCDCTestVectorBitmap(E);
4735+
47004736
// ZExt result to int or bool.
47014737
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext");
47024738
}
@@ -4706,6 +4742,12 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
47064742
return llvm::ConstantInt::get(ResTy, 1);
47074743
}
47084744

4745+
// If the top of the logical operator nest, reset the MCDC temp to 0.
4746+
if (CGF.MCDCLogOpStack.empty())
4747+
CGF.maybeResetMCDCCondBitmap(E);
4748+
4749+
CGF.MCDCLogOpStack.push_back(E);
4750+
47094751
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end");
47104752
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("lor.rhs");
47114753

@@ -4742,6 +4784,7 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
47424784
// condition coverage.
47434785
if (InstrumentRegions &&
47444786
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
4787+
CGF.maybeUpdateMCDCCondBitmap(E->getRHS(), RHSCond);
47454788
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("lor.rhscnt");
47464789
Builder.CreateCondBr(RHSCond, ContBlock, RHSBlockCnt);
47474790
CGF.EmitBlock(RHSBlockCnt);
@@ -4755,6 +4798,11 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
47554798
CGF.EmitBlock(ContBlock);
47564799
PN->addIncoming(RHSCond, RHSBlock);
47574800

4801+
CGF.MCDCLogOpStack.pop_back();
4802+
// If the top of the logical operator nest, update the MCDC bitmap.
4803+
if (CGF.MCDCLogOpStack.empty())
4804+
CGF.maybeUpdateMCDCTestVectorBitmap(E);
4805+
47584806
// ZExt result to int.
47594807
return Builder.CreateZExtOrBitCast(PN, ResTy, "lor.ext");
47604808
}
@@ -4899,6 +4947,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
48994947
return Builder.CreateSelect(CondV, LHS, RHS, "cond");
49004948
}
49014949

4950+
// If the top of the logical operator nest, reset the MCDC temp to 0.
4951+
if (CGF.MCDCLogOpStack.empty())
4952+
CGF.maybeResetMCDCCondBitmap(condExpr);
4953+
49024954
llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
49034955
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
49044956
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
@@ -4934,6 +4986,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
49344986
llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), 2, "cond");
49354987
PN->addIncoming(LHS, LHSBlock);
49364988
PN->addIncoming(RHS, RHSBlock);
4989+
4990+
// If the top of the logical operator nest, update the MCDC bitmap.
4991+
if (CGF.MCDCLogOpStack.empty())
4992+
CGF.maybeUpdateMCDCTestVectorBitmap(condExpr);
4993+
49374994
return PN;
49384995
}
49394996

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,19 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
837837
if (!ThenCount && !getCurrentProfileCount() &&
838838
CGM.getCodeGenOpts().OptimizationLevel)
839839
LH = Stmt::getLikelihood(S.getThen(), S.getElse());
840-
EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, ThenCount, LH);
840+
841+
// When measuring MC/DC, always fully evaluate the condition up front using
842+
// EvaluateExprAsBool() so that the test vector bitmap can be updated prior to
843+
// executing the body of the if.then or if.else. This is useful for when
844+
// there is a 'return' within the body, but this is particularly beneficial
845+
// when one if-stmt is nested within another if-stmt so that all of the MC/DC
846+
// updates are kept linear and consistent.
847+
if (!CGM.getCodeGenOpts().MCDCCoverage)
848+
EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, ThenCount, LH);
849+
else {
850+
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
851+
Builder.CreateCondBr(BoolCondVal, ThenBlock, ElseBlock);
852+
}
841853

842854
// Emit the 'then' code.
843855
EmitBlock(ThenBlock);

0 commit comments

Comments
 (0)