Skip to content

Commit 9f2967b

Browse files
committed
[Coverage] Add support for Branch Coverage in LLVM Source-Based Code Coverage
This is an enhancement to LLVM Source-Based Code Coverage in clang to track how many times individual branch-generating conditions are taken (evaluate to TRUE) and not taken (evaluate to FALSE). Individual conditions may comprise larger boolean expressions using boolean logical operators. This functionality is very similar to what is supported by GCOV except that it is very closely anchored to the ASTs. Differential Revision: https://reviews.llvm.org/D84467
1 parent 53c3acb commit 9f2967b

File tree

79 files changed

+3009
-241
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+3009
-241
lines changed

clang/docs/SourceBasedCodeCoverage.rst

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,18 +179,43 @@ region counts (even in macro expansions):
179179
| 4| 1|}
180180
------------------
181181
182+
If ``--show-branches=count`` and ``--show-expansions`` are also enabled, the
183+
sub-views will show detailed branch coverage information in addition to the
184+
region counts:
185+
186+
.. code-block:: none
187+
188+
------------------
189+
| void foo<float>(int):
190+
| 2| 1|template <typename T> void foo(T x) {
191+
| 3| 11| for (unsigned I = 0; I < 10; ++I) { BAR(I); }
192+
| ^11 ^10 ^10^10
193+
| ------------------
194+
| | | 1| 10|#define BAR(x) ((x) || (x))
195+
| | | ^10 ^1
196+
| | | ------------------
197+
| | | | Branch (1:17): [True: 9, False: 1]
198+
| | | | Branch (1:24): [True: 0, False: 1]
199+
| | | ------------------
200+
| ------------------
201+
| | Branch (3:23): [True: 10, False: 1]
202+
| ------------------
203+
| 4| 1|}
204+
------------------
205+
206+
182207
To generate a file-level summary of coverage statistics instead of a
183208
line-oriented report, try:
184209

185210
.. code-block:: console
186211
187212
# Step 3(c): Create a coverage summary.
188213
% llvm-cov report ./foo -instr-profile=foo.profdata
189-
Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover
190-
--------------------------------------------------------------------------------------------------------------------------------------
191-
/tmp/foo.cc 13 0 100.00% 3 0 100.00% 13 0 100.00%
192-
--------------------------------------------------------------------------------------------------------------------------------------
193-
TOTAL 13 0 100.00% 3 0 100.00% 13 0 100.00%
214+
Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover
215+
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
216+
/tmp/foo.cc 13 0 100.00% 3 0 100.00% 13 0 100.00% 12 2 83.33%
217+
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
218+
TOTAL 13 0 100.00% 3 0 100.00% 13 0 100.00% 12 2 83.33%
194219
195220
The ``llvm-cov`` tool supports specifying a custom demangler, writing out
196221
reports in a directory structure, and generating html reports. For the full
@@ -246,8 +271,17 @@ There are four statistics tracked in a coverage summary:
246271
body with no control flow). However, it's also possible for a single line to
247272
contain multiple code regions (e.g in "return x || y && z").
248273

249-
Of these four statistics, function coverage is usually the least granular while
250-
region coverage is the most granular. The project-wide totals for each
274+
* Branch coverage is the percentage of "true" and "false" branches that have
275+
been taken at least once. Each branch is tied to individual conditions in the
276+
source code that may each evaluate to either "true" or "false". These
277+
conditions may comprise larger boolean expressions linked by boolean logical
278+
operators. For example, "x = (y == 2) || (z < 10)" is a boolean expression
279+
that is comprised of two individual conditions, each of which evaluates to
280+
either true or false, producing four total branch outcomes.
281+
282+
Of these five statistics, function coverage is usually the least granular while
283+
branch coverage is the most granular. 100% branch coverage for a function
284+
implies 100% region coverage for a function. The project-wide totals for each
251285
statistic are listed in the summary.
252286

253287
Format compatibility guarantees
@@ -351,6 +385,25 @@ as red "unexecuted" highlights present at the end of an otherwise covered line,
351385
or blue "executed" highlights present at the start of a line that is otherwise
352386
not executed.
353387

388+
Branch regions
389+
--------------
390+
When viewing branch coverage details in source-based file-level sub-views using
391+
``--show-branches``, it is recommended that users show all macro expansions
392+
(using option ``--show-expansions``) since macros may contain hidden branch
393+
conditions. The coverage summary report will always include these macro-based
394+
boolean expressions in the overall branch coverage count for a function or
395+
source file.
396+
397+
Branch coverage is not tracked for constant folded branch conditions since
398+
branches are not generated for these cases. In the source-based file-level
399+
sub-view, these branches will simply be shown as ``[Folded - Ignored]`` so that
400+
users are informed about what happened.
401+
402+
Branch coverage is tied directly to branch-generating conditions in the source
403+
code. Users should not see hidden branches that aren't actually tied to the
404+
source code.
405+
406+
354407
Switch statements
355408
-----------------
356409

@@ -366,3 +419,10 @@ which the switch body and the single case share a count.
366419

367420
For switches with ``CompoundStmt`` bodies, a new region is created at the start
368421
of each switch case.
422+
423+
Branch regions are also generated for each switch case, including the default
424+
case. If there is no explicitly defined default case in the source code, a
425+
branch region is generated to correspond to the implicit default case that is
426+
generated by the compiler. The implicit branch region is tied to the line and
427+
column number of the switch statement condition since no source code for the
428+
implicit case exists.

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4191,6 +4191,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
41914191
return Builder.CreateSExt(And, ConvertType(E->getType()), "sext");
41924192
}
41934193

4194+
bool InstrumentRegions = CGF.CGM.getCodeGenOpts().hasProfileClangInstr();
41944195
llvm::Type *ResTy = ConvertType(E->getType());
41954196

41964197
// If we have 0 && RHS, see if we can elide RHS, if so, just return 0.
@@ -4201,6 +4202,22 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
42014202
CGF.incrementProfileCounter(E);
42024203

42034204
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
4205+
4206+
// If we're generating for profiling or coverage, generate a branch to a
4207+
// block that increments the RHS counter needed to track branch condition
4208+
// coverage. In this case, use "FBlock" as both the final "TrueBlock" and
4209+
// "FalseBlock" after the increment is done.
4210+
if (InstrumentRegions &&
4211+
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
4212+
llvm::BasicBlock *FBlock = CGF.createBasicBlock("land.end");
4213+
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("land.rhscnt");
4214+
Builder.CreateCondBr(RHSCond, RHSBlockCnt, FBlock);
4215+
CGF.EmitBlock(RHSBlockCnt);
4216+
CGF.incrementProfileCounter(E->getRHS());
4217+
CGF.EmitBranch(FBlock);
4218+
CGF.EmitBlock(FBlock);
4219+
}
4220+
42044221
// ZExt result to int or bool.
42054222
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext");
42064223
}
@@ -4237,6 +4254,19 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
42374254
// Reaquire the RHS block, as there may be subblocks inserted.
42384255
RHSBlock = Builder.GetInsertBlock();
42394256

4257+
// If we're generating for profiling or coverage, generate a branch on the
4258+
// RHS to a block that increments the RHS true counter needed to track branch
4259+
// condition coverage.
4260+
if (InstrumentRegions &&
4261+
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
4262+
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("land.rhscnt");
4263+
Builder.CreateCondBr(RHSCond, RHSBlockCnt, ContBlock);
4264+
CGF.EmitBlock(RHSBlockCnt);
4265+
CGF.incrementProfileCounter(E->getRHS());
4266+
CGF.EmitBranch(ContBlock);
4267+
PN->addIncoming(RHSCond, RHSBlockCnt);
4268+
}
4269+
42404270
// Emit an unconditional branch from this block to ContBlock.
42414271
{
42424272
// There is no need to emit line number for unconditional branch.
@@ -4277,6 +4307,7 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
42774307
return Builder.CreateSExt(Or, ConvertType(E->getType()), "sext");
42784308
}
42794309

4310+
bool InstrumentRegions = CGF.CGM.getCodeGenOpts().hasProfileClangInstr();
42804311
llvm::Type *ResTy = ConvertType(E->getType());
42814312

42824313
// If we have 1 || RHS, see if we can elide RHS, if so, just return 1.
@@ -4287,6 +4318,22 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
42874318
CGF.incrementProfileCounter(E);
42884319

42894320
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
4321+
4322+
// If we're generating for profiling or coverage, generate a branch to a
4323+
// block that increments the RHS counter need to track branch condition
4324+
// coverage. In this case, use "FBlock" as both the final "TrueBlock" and
4325+
// "FalseBlock" after the increment is done.
4326+
if (InstrumentRegions &&
4327+
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
4328+
llvm::BasicBlock *FBlock = CGF.createBasicBlock("lor.end");
4329+
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("lor.rhscnt");
4330+
Builder.CreateCondBr(RHSCond, FBlock, RHSBlockCnt);
4331+
CGF.EmitBlock(RHSBlockCnt);
4332+
CGF.incrementProfileCounter(E->getRHS());
4333+
CGF.EmitBranch(FBlock);
4334+
CGF.EmitBlock(FBlock);
4335+
}
4336+
42904337
// ZExt result to int or bool.
42914338
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext");
42924339
}
@@ -4327,6 +4374,19 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
43274374
// Reaquire the RHS block, as there may be subblocks inserted.
43284375
RHSBlock = Builder.GetInsertBlock();
43294376

4377+
// If we're generating for profiling or coverage, generate a branch on the
4378+
// RHS to a block that increments the RHS true counter needed to track branch
4379+
// condition coverage.
4380+
if (InstrumentRegions &&
4381+
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
4382+
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("lor.rhscnt");
4383+
Builder.CreateCondBr(RHSCond, ContBlock, RHSBlockCnt);
4384+
CGF.EmitBlock(RHSBlockCnt);
4385+
CGF.incrementProfileCounter(E->getRHS());
4386+
CGF.EmitBranch(ContBlock);
4387+
PN->addIncoming(RHSCond, RHSBlockCnt);
4388+
}
4389+
43304390
// Emit an unconditional branch from this block to ContBlock. Insert an entry
43314391
// into the phi node for the edge with the value of RHSCond.
43324392
CGF.EmitBlock(ContBlock);

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,7 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S,
14411441
SwitchWeights->push_back(getProfileCount(NextCase));
14421442
if (CGM.getCodeGenOpts().hasProfileClangInstr()) {
14431443
CaseDest = createBasicBlock("sw.bb");
1444-
EmitBlockWithFallThrough(CaseDest, &S);
1444+
EmitBlockWithFallThrough(CaseDest, CurCase);
14451445
}
14461446
// Since this loop is only executed when the CaseStmt has no attributes
14471447
// use a hard-coded value.

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 96 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,90 @@ bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
15011501
return true;
15021502
}
15031503

1504+
/// Determine whether the given condition is an instrumentable condition
1505+
/// (i.e. no "&&" or "||").
1506+
bool CodeGenFunction::isInstrumentedCondition(const Expr *C) {
1507+
// Bypass simplistic logical-NOT operator before determining whether the
1508+
// condition contains any other logical operator.
1509+
if (const UnaryOperator *UnOp = dyn_cast<UnaryOperator>(C->IgnoreParens()))
1510+
if (UnOp->getOpcode() == UO_LNot)
1511+
C = UnOp->getSubExpr();
1512+
1513+
const BinaryOperator *BOp = dyn_cast<BinaryOperator>(C->IgnoreParens());
1514+
return (!BOp || !BOp->isLogicalOp());
1515+
}
1516+
1517+
/// EmitBranchToCounterBlock - Emit a conditional branch to a new block that
1518+
/// increments a profile counter based on the semantics of the given logical
1519+
/// operator opcode. This is used to instrument branch condition coverage for
1520+
/// logical operators.
1521+
void CodeGenFunction::EmitBranchToCounterBlock(
1522+
const Expr *Cond, BinaryOperator::Opcode LOp, llvm::BasicBlock *TrueBlock,
1523+
llvm::BasicBlock *FalseBlock, uint64_t TrueCount /* = 0 */,
1524+
Stmt::Likelihood LH /* =None */, const Expr *CntrIdx /* = nullptr */) {
1525+
// If not instrumenting, just emit a branch.
1526+
bool InstrumentRegions = CGM.getCodeGenOpts().hasProfileClangInstr();
1527+
if (!InstrumentRegions || !isInstrumentedCondition(Cond))
1528+
return EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount, LH);
1529+
1530+
llvm::BasicBlock *ThenBlock = NULL;
1531+
llvm::BasicBlock *ElseBlock = NULL;
1532+
llvm::BasicBlock *NextBlock = NULL;
1533+
1534+
// Create the block we'll use to increment the appropriate counter.
1535+
llvm::BasicBlock *CounterIncrBlock = createBasicBlock("lop.rhscnt");
1536+
1537+
// Set block pointers according to Logical-AND (BO_LAnd) semantics. This
1538+
// means we need to evaluate the condition and increment the counter on TRUE:
1539+
//
1540+
// if (Cond)
1541+
// goto CounterIncrBlock;
1542+
// else
1543+
// goto FalseBlock;
1544+
//
1545+
// CounterIncrBlock:
1546+
// Counter++;
1547+
// goto TrueBlock;
1548+
1549+
if (LOp == BO_LAnd) {
1550+
ThenBlock = CounterIncrBlock;
1551+
ElseBlock = FalseBlock;
1552+
NextBlock = TrueBlock;
1553+
}
1554+
1555+
// Set block pointers according to Logical-OR (BO_LOr) semantics. This means
1556+
// we need to evaluate the condition and increment the counter on FALSE:
1557+
//
1558+
// if (Cond)
1559+
// goto TrueBlock;
1560+
// else
1561+
// goto CounterIncrBlock;
1562+
//
1563+
// CounterIncrBlock:
1564+
// Counter++;
1565+
// goto FalseBlock;
1566+
1567+
else if (LOp == BO_LOr) {
1568+
ThenBlock = TrueBlock;
1569+
ElseBlock = CounterIncrBlock;
1570+
NextBlock = FalseBlock;
1571+
} else {
1572+
llvm_unreachable("Expected Opcode must be that of a Logical Operator");
1573+
}
1574+
1575+
// Emit Branch based on condition.
1576+
EmitBranchOnBoolExpr(Cond, ThenBlock, ElseBlock, TrueCount, LH);
1577+
1578+
// Emit the block containing the counter increment(s).
1579+
EmitBlock(CounterIncrBlock);
1580+
1581+
// Increment corresponding counter; if index not provided, use Cond as index.
1582+
incrementProfileCounter(CntrIdx ? CntrIdx : Cond);
1583+
1584+
// Go to the next block.
1585+
EmitBranch(NextBlock);
1586+
}
1587+
15041588
/// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an if
15051589
/// statement) to the specified blocks. Based on the condition, this might try
15061590
/// to simplify the codegen of the conditional based on the branch.
@@ -1523,17 +1607,17 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
15231607
ConstantBool) {
15241608
// br(1 && X) -> br(X).
15251609
incrementProfileCounter(CondBOp);
1526-
return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock,
1527-
TrueCount, LH);
1610+
return EmitBranchToCounterBlock(CondBOp->getRHS(), BO_LAnd, TrueBlock,
1611+
FalseBlock, TrueCount, LH);
15281612
}
15291613

15301614
// If we have "X && 1", simplify the code to use an uncond branch.
15311615
// "X && 0" would have been constant folded to 0.
15321616
if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
15331617
ConstantBool) {
15341618
// br(X && 1) -> br(X).
1535-
return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock,
1536-
TrueCount, LH);
1619+
return EmitBranchToCounterBlock(CondBOp->getLHS(), BO_LAnd, TrueBlock,
1620+
FalseBlock, TrueCount, LH, CondBOp);
15371621
}
15381622

15391623
// Emit the LHS as a conditional. If the LHS conditional is false, we
@@ -1559,8 +1643,8 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
15591643

15601644
// Any temporaries created here are conditional.
15611645
eval.begin(*this);
1562-
EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, TrueCount,
1563-
LH);
1646+
EmitBranchToCounterBlock(CondBOp->getRHS(), BO_LAnd, TrueBlock,
1647+
FalseBlock, TrueCount, LH);
15641648
eval.end(*this);
15651649

15661650
return;
@@ -1574,17 +1658,17 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
15741658
!ConstantBool) {
15751659
// br(0 || X) -> br(X).
15761660
incrementProfileCounter(CondBOp);
1577-
return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock,
1578-
TrueCount, LH);
1661+
return EmitBranchToCounterBlock(CondBOp->getRHS(), BO_LOr, TrueBlock,
1662+
FalseBlock, TrueCount, LH);
15791663
}
15801664

15811665
// If we have "X || 0", simplify the code to use an uncond branch.
15821666
// "X || 1" would have been constant folded to 1.
15831667
if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
15841668
!ConstantBool) {
15851669
// br(X || 0) -> br(X).
1586-
return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock,
1587-
TrueCount, LH);
1670+
return EmitBranchToCounterBlock(CondBOp->getLHS(), BO_LOr, TrueBlock,
1671+
FalseBlock, TrueCount, LH, CondBOp);
15881672
}
15891673

15901674
// Emit the LHS as a conditional. If the LHS conditional is true, we
@@ -1613,8 +1697,8 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
16131697

16141698
// Any temporaries created here are conditional.
16151699
eval.begin(*this);
1616-
EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, RHSCount,
1617-
LH);
1700+
EmitBranchToCounterBlock(CondBOp->getRHS(), BO_LOr, TrueBlock, FalseBlock,
1701+
RHSCount, LH);
16181702

16191703
eval.end(*this);
16201704

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4394,6 +4394,21 @@ class CodeGenFunction : public CodeGenTypeCache {
43944394
bool ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APSInt &Result,
43954395
bool AllowLabels = false);
43964396

4397+
/// isInstrumentedCondition - Determine whether the given condition is an
4398+
/// instrumentable condition (i.e. no "&&" or "||").
4399+
static bool isInstrumentedCondition(const Expr *C);
4400+
4401+
/// EmitBranchToCounterBlock - Emit a conditional branch to a new block that
4402+
/// increments a profile counter based on the semantics of the given logical
4403+
/// operator opcode. This is used to instrument branch condition coverage
4404+
/// for logical operators.
4405+
void EmitBranchToCounterBlock(const Expr *Cond, BinaryOperator::Opcode LOp,
4406+
llvm::BasicBlock *TrueBlock,
4407+
llvm::BasicBlock *FalseBlock,
4408+
uint64_t TrueCount = 0,
4409+
Stmt::Likelihood LH = Stmt::LH_None,
4410+
const Expr *CntrIdx = nullptr);
4411+
43974412
/// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an
43984413
/// if statement) to the specified blocks. Based on the condition, this might
43994414
/// try to simplify the codegen of the conditional based on the branch.

0 commit comments

Comments
 (0)