[llvm-branch-commits] [clang] [MC/DC] Introduce `-fmcdc-single-conditions` to include also single conditions (PR #125484)
NAKAMURA Takumi via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Feb 3 03:42:57 PST 2025
https://github.com/chapuni created https://github.com/llvm/llvm-project/pull/125484
`-fmcdc-single-conditions` is `CC1Option` for now.
This change discovers `isInstrumentedCondition(Cond)` on `DoStmt/ForStmt/IfStmt/WhleStmt/AbstractConditionalOperator` and add them into Decisions.
An example of the report:
```
MC/DC Decision Region (mmm:nn) to (mmm:nn)
Number of Conditions: 1
Condition C1 -->(mmm:nn)
Executed MC/DC Test Vectors:
C1 Result
1 { F = F }
2 { T = T }
C1-Pair: covered: (1,2)
MC/DC Coverage for Expression: 100.00%
```
The Decision is covered only if both `true` and `false` are covered.
Fixes #95336
>From af336315f37021ccc6d21059ecfe28a0f30248ff Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 3 Feb 2025 20:35:06 +0900
Subject: [PATCH] [MC/DC] Introduce `-fmcdc-single-conditions` to include also
single conditions
`-fmcdc-single-conditions` is `CC1Option` for now.
This change discovers `isInstrumentedCondition(Cond)` on
`DoStmt/ForStmt/IfStmt/WhleStmt/AbstractConditionalOperator` and add
them into Decisions.
An example of the report:
```
MC/DC Decision Region (mmm:nn) to (mmm:nn)
Number of Conditions: 1
Condition C1 -->(mmm:nn)
Executed MC/DC Test Vectors:
C1 Result
1 { F = F }
2 { T = T }
C1-Pair: covered: (1,2)
MC/DC Coverage for Expression: 100.00%
```
The Decision is covered only if both `true` and `false` are covered.
Fixes #95336
---
clang/docs/ReleaseNotes.rst | 3 +
clang/docs/SourceBasedCodeCoverage.rst | 4 +
clang/include/clang/Basic/CodeGenOptions.def | 1 +
clang/include/clang/Driver/Options.td | 4 +
clang/lib/CodeGen/CGExpr.cpp | 32 +++++--
clang/lib/CodeGen/CodeGenFunction.h | 4 +-
clang/lib/CodeGen/CodeGenPGO.cpp | 38 ++++++++-
clang/lib/CodeGen/CoverageMappingGen.cpp | 46 +++++++---
.../test/CoverageMapping/mcdc-single-cond.cpp | 85 ++++++++++++++++++-
9 files changed, 190 insertions(+), 27 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 42054fe27c5ee1c..4138fc2f11e0c17 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -118,6 +118,9 @@ Improvements to Coverage Mapping
- [MC/DC] Nested expressions are handled as individual MC/DC expressions.
+- [MC/DC] Non-boolean expressions on conditions can be included with
+ `-fmcdc-single-conditions`. (#GH95336)
+
Bug Fixes in This Version
-------------------------
diff --git a/clang/docs/SourceBasedCodeCoverage.rst b/clang/docs/SourceBasedCodeCoverage.rst
index d26babe829ab5be..bcd4ae0e9748d15 100644
--- a/clang/docs/SourceBasedCodeCoverage.rst
+++ b/clang/docs/SourceBasedCodeCoverage.rst
@@ -510,6 +510,10 @@ requires 8 test vectors.
Expressions such as ``((a0 && b0) || (a1 && b1) || ...)`` can cause the
number of test vectors to increase exponentially.
+Clang handles only binary logical operators as MC/DC coverage. Single
+conditions without logcal operators on `do/for/while/if/?!` can be
+included with `-Xclang -fmcdc-single-conditions`.
+
Switch statements
-----------------
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 259972bdf8f0013..1a9ebae845619b7 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -236,6 +236,7 @@ CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping
CODEGENOPT(MCDCCoverage , 1, 0) ///< Enable MC/DC code coverage criteria.
VALUE_CODEGENOPT(MCDCMaxConds, 16, 32767) ///< MC/DC Maximum conditions.
VALUE_CODEGENOPT(MCDCMaxTVs, 32, 0x7FFFFFFE) ///< MC/DC Maximum test vectors.
+VALUE_CODEGENOPT(MCDCSingleCond, 1, 0) ///< Enable MC/DC single conditions.
/// If -fpcc-struct-return or -freg-struct-return is specified.
ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6eabd9f76a792db..57b826bce6da821 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1742,6 +1742,10 @@ def fmcdc_max_test_vectors_EQ : Joined<["-"], "fmcdc-max-test-vectors=">,
Group<f_Group>, Visibility<[CC1Option]>,
HelpText<"Maximum number of test vectors in MC/DC coverage">,
MarshallingInfoInt<CodeGenOpts<"MCDCMaxTVs">, "0x7FFFFFFE">;
+def fmcdc_single_conditions : Flag<["-"], "fmcdc-single-conditions">,
+ Group<f_Group>, Visibility<[CC1Option]>,
+ HelpText<"Include also single conditions as MC/DC coverage">,
+ MarshallingInfoFlag<CodeGenOpts<"MCDCSingleCond">>;
def fprofile_generate : Flag<["-"], "fprofile-generate">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 9676e61cf322d92..82a31cb3721473b 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -196,20 +196,36 @@ RawAddress CodeGenFunction::CreateMemTempWithoutCast(QualType Ty,
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
/// expression and compare the result against zero, returning an Int1Ty value.
llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
+ auto DecisionExpr = stripCond(E);
+ if (isMCDCDecisionExpr(DecisionExpr) && isInstrumentedCondition(DecisionExpr))
+ maybeResetMCDCCondBitmap(DecisionExpr);
+ else
+ DecisionExpr = nullptr;
+
PGO.setCurrentStmt(E);
+ llvm::Value *Result;
if (const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>()) {
llvm::Value *MemPtr = EmitScalarExpr(E);
- return CGM.getCXXABI().EmitMemberPointerIsNotNull(*this, MemPtr, MPT);
+ Result = CGM.getCXXABI().EmitMemberPointerIsNotNull(*this, MemPtr, MPT);
+ } else {
+ QualType BoolTy = getContext().BoolTy;
+ SourceLocation Loc = E->getExprLoc();
+ CGFPOptionsRAII FPOptsRAII(*this, E);
+ if (!E->getType()->isAnyComplexType())
+ Result =
+ EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy, Loc);
+ else
+ Result = EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(),
+ BoolTy, Loc);
}
- QualType BoolTy = getContext().BoolTy;
- SourceLocation Loc = E->getExprLoc();
- CGFPOptionsRAII FPOptsRAII(*this, E);
- if (!E->getType()->isAnyComplexType())
- return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy, Loc);
+ if (DecisionExpr) {
+ if (isMCDCBranchExpr(stripCond(E)))
+ maybeUpdateMCDCCondBitmap(stripCond(E), Result);
+ maybeUpdateMCDCTestVectorBitmap(DecisionExpr);
+ }
- return EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(), BoolTy,
- Loc);
+ return Result;
}
/// EmitIgnoredExpr - Emit code to compute the specified expression,
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index e4780f880260091..de8d61c448d0c3e 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1684,7 +1684,7 @@ class CodeGenFunction : public CodeGenTypeCache {
/// Zero-init the MCDC temp value.
void maybeResetMCDCCondBitmap(const Expr *E) {
- if (isMCDCCoverageEnabled() && isBinaryLogicalOp(E)) {
+ if (isMCDCCoverageEnabled()) {
PGO.emitMCDCCondBitmapReset(Builder, E);
PGO.setCurrentStmt(E);
}
@@ -1693,7 +1693,7 @@ class CodeGenFunction : public CodeGenTypeCache {
/// Increment the profiler's counter for the given expression by \p StepV.
/// If \p StepV is null, the default increment is 1.
void maybeUpdateMCDCTestVectorBitmap(const Expr *E) {
- if (isMCDCCoverageEnabled() && isBinaryLogicalOp(E)) {
+ if (isMCDCCoverageEnabled()) {
PGO.emitMCDCTestVectorBitmapUpdate(Builder, E, *this);
PGO.setCurrentStmt(E);
}
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 0c3973aa4dccfdc..b1a6c8714fe7835 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -168,6 +168,8 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
MCDC::State &MCDCState;
/// Maximum number of supported MC/DC conditions in a boolean expression.
unsigned MCDCMaxCond;
+ /// Take single conditions into account.
+ bool MCDCSingleCond;
/// The profile version.
uint64_t ProfileVersion;
/// Diagnostics Engine used to report warnings.
@@ -176,10 +178,11 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
MapRegionCounters(PGOHashVersion HashVersion, uint64_t ProfileVersion,
llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
MCDC::State &MCDCState, unsigned MCDCMaxCond,
- DiagnosticsEngine &Diag)
+ bool MCDCSingleCond, DiagnosticsEngine &Diag)
: NextCounter(0), Hash(HashVersion), CounterMap(CounterMap),
MCDCState(MCDCState), MCDCMaxCond(MCDCMaxCond),
- ProfileVersion(ProfileVersion), Diag(Diag) {}
+ MCDCSingleCond(MCDCSingleCond), ProfileVersion(ProfileVersion),
+ Diag(Diag) {}
// Blocks and lambdas are handled as separate functions, so we need not
// traverse them in the parent context.
@@ -240,12 +243,31 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
SmallVector<DecisionState, 1> DecisionStack;
+ llvm::DenseSet<const Expr *> StagingDecisions;
+
+ template <class T> bool pushInstrumentedCond(Stmt *S) {
+ if (auto *St = dyn_cast<T>(S)) {
+ if (auto *Cond = St->getCond();
+ Cond && CodeGenFunction::isInstrumentedCondition(Cond)) {
+ StagingDecisions.insert(CodeGenFunction::stripCond(Cond));
+ return true;
+ }
+ }
+
+ return false;
+ }
+
// Hook: dataTraverseStmtPre() is invoked prior to visiting an AST Stmt node.
bool dataTraverseStmtPre(Stmt *S) {
/// If MC/DC is not enabled, MCDCMaxCond will be set to 0. Do nothing.
if (MCDCMaxCond == 0)
return true;
+ const auto *E = dyn_cast<Expr>(S);
+
+ if (StagingDecisions.contains(E))
+ DecisionStack.emplace_back(E, true);
+
/// Mark "in splitting" when a leaf is met.
if (!DecisionStack.empty()) {
auto &StackTop = DecisionStack.back();
@@ -262,13 +284,20 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
assert(!StackTop.Leaves.contains(S));
}
- if (const auto *E = dyn_cast<Expr>(S)) {
+ if (E) {
if (const auto *BinOp =
dyn_cast<BinaryOperator>(CodeGenFunction::stripCond(E));
BinOp && BinOp->isLogicalOp())
DecisionStack.emplace_back(E);
}
+ if (MCDCSingleCond) {
+ pushInstrumentedCond<AbstractConditionalOperator>(S) ||
+ pushInstrumentedCond<DoStmt>(S) || pushInstrumentedCond<IfStmt>(S) ||
+ pushInstrumentedCond<ForStmt>(S) ||
+ pushInstrumentedCond<WhileStmt>(S);
+ }
+
return true;
}
@@ -1098,7 +1127,8 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, CounterPair>);
RegionMCDCState.reset(new MCDC::State);
MapRegionCounters Walker(HashVersion, ProfileVersion, *RegionCounterMap,
- *RegionMCDCState, MCDCMaxConditions, CGM.getDiags());
+ *RegionMCDCState, MCDCMaxConditions,
+ CGM.getCodeGenOpts().MCDCSingleCond, CGM.getDiags());
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
Walker.TraverseDecl(const_cast<FunctionDecl *>(FD));
else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 3a281fd39b4bcb1..6f600a00296a690 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1164,9 +1164,7 @@ struct CounterCoverageMappingBuilder
/// result in the generation of a branch.
void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt,
const mcdc::ConditionIDs &Conds = {}) {
- // Check for NULL conditions.
- if (!C)
- return;
+ assert(C && "Condition Expr shouldn't be null!");
// Ensure we are an instrumentable condition (i.e. no "&&" or "||"). Push
// region onto RegionStack but immediately pop it (which adds it to the
@@ -1630,6 +1628,9 @@ struct CounterCoverageMappingBuilder
}
void VisitWhileStmt(const WhileStmt *S) {
+ unsigned SourceRegionsSince = SourceRegions.size();
+ MCDCBuilder.checkDecisionRootOrPush(S->getCond());
+
extendRegion(S);
Counter ParentCount = getRegion().getCounter();
@@ -1676,10 +1677,15 @@ struct CounterCoverageMappingBuilder
// Create Branch Region around condition.
if (!llvm::EnableSingleByteCoverage)
- createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
+ createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped,
+ MCDCBuilder.getCurCondIDs());
+ createOrCancelDecision(S->getCond(), SourceRegionsSince);
}
void VisitDoStmt(const DoStmt *S) {
+ unsigned SourceRegionsSince = SourceRegions.size();
+ MCDCBuilder.checkDecisionRootOrPush(S->getCond());
+
extendRegion(S);
Counter ParentCount = getRegion().getCounter();
@@ -1722,13 +1728,20 @@ struct CounterCoverageMappingBuilder
// Create Branch Region around condition.
if (!llvm::EnableSingleByteCoverage)
- createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
+ createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped,
+ MCDCBuilder.getCurCondIDs());
+ createOrCancelDecision(S->getCond(), SourceRegionsSince);
if (BodyHasTerminateStmt)
HasTerminateStmt = true;
}
void VisitForStmt(const ForStmt *S) {
+ const Expr *Cond = S->getCond();
+ unsigned SourceRegionsSince = SourceRegions.size();
+ if (Cond)
+ MCDCBuilder.checkDecisionRootOrPush(Cond);
+
extendRegion(S);
if (S->getInit())
Visit(S->getInit());
@@ -1775,7 +1788,7 @@ struct CounterCoverageMappingBuilder
assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
llvm::EnableSingleByteCoverage);
- if (const Expr *Cond = S->getCond()) {
+ if (Cond) {
propagateCounts(CondCount, Cond);
adjustForOutOfOrderTraversal(getEnd(S));
}
@@ -1797,8 +1810,11 @@ struct CounterCoverageMappingBuilder
}
// Create Branch Region around condition.
- if (!llvm::EnableSingleByteCoverage)
- createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
+ if (!llvm::EnableSingleByteCoverage && Cond) {
+ createBranchRegion(Cond, BodyCount, BranchCount.Skipped,
+ MCDCBuilder.getCurCondIDs());
+ createOrCancelDecision(Cond, SourceRegionsSince);
+ }
}
void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
@@ -2069,6 +2085,9 @@ struct CounterCoverageMappingBuilder
else if (S->isConstexpr())
return coverIfConstexpr(S);
+ unsigned SourceRegionsSince = SourceRegions.size();
+ MCDCBuilder.checkDecisionRootOrPush(S->getCond());
+
extendRegion(S);
if (S->getInit())
Visit(S->getInit());
@@ -2127,7 +2146,9 @@ struct CounterCoverageMappingBuilder
if (!llvm::EnableSingleByteCoverage)
// Create Branch Region around condition.
- createBranchRegion(S->getCond(), ThenCount, ElseCount);
+ createBranchRegion(S->getCond(), ThenCount, ElseCount,
+ MCDCBuilder.getCurCondIDs());
+ createOrCancelDecision(S->getCond(), SourceRegionsSince);
}
void VisitCXXTryStmt(const CXXTryStmt *S) {
@@ -2150,6 +2171,9 @@ struct CounterCoverageMappingBuilder
}
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
+ unsigned SourceRegionsSince = SourceRegions.size();
+ MCDCBuilder.checkDecisionRootOrPush(E->getCond());
+
extendRegion(E);
Counter ParentCount = getRegion().getCounter();
@@ -2189,7 +2213,9 @@ struct CounterCoverageMappingBuilder
// Create Branch Region around condition.
if (!llvm::EnableSingleByteCoverage)
- createBranchRegion(E->getCond(), TrueCount, FalseCount);
+ createBranchRegion(E->getCond(), TrueCount, FalseCount,
+ MCDCBuilder.getCurCondIDs());
+ createOrCancelDecision(E->getCond(), SourceRegionsSince);
}
inline unsigned findMCDCBranchesInSourceRegion(
diff --git a/clang/test/CoverageMapping/mcdc-single-cond.cpp b/clang/test/CoverageMapping/mcdc-single-cond.cpp
index d6c694a63dd285e..67b011b7be66c8d 100644
--- a/clang/test/CoverageMapping/mcdc-single-cond.cpp
+++ b/clang/test/CoverageMapping/mcdc-single-cond.cpp
@@ -1,3 +1,5 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -disable-llvm-passes -emit-llvm -o %t1.ll %s -fmcdc-single-conditions | FileCheck %s --check-prefixes=MM,MM1
+// RUN: FileCheck %s --check-prefixes=LL,LL1 < %t1.ll
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -disable-llvm-passes -emit-llvm -o %t2.ll %s | FileCheck %s --check-prefixes=MM,MM2
// RUN: FileCheck %s --check-prefixes=LL,LL2 < %t2.ll
@@ -5,33 +7,69 @@
// MM: func_cond{{.*}}:
int func_cond(bool a, bool b) {
// %mcdc.addr* are emitted by static order.
+ // LL1: %[[MA1:mcdc.addr.*]] = alloca i32, align 4
+ // LL1: %[[MA2:mcdc.addr.*]] = alloca i32, align 4
+ // LL1: %[[MA3:mcdc.addr.*]] = alloca i32, align 4
// LL: %[[MA4:mcdc.addr.*]] = alloca i32, align 4
+ // LL1: %[[MA5:mcdc.addr.*]] = alloca i32, align 4
// LL: %[[MA6:mcdc.addr.*]] = alloca i32, align 4
// LL: %[[MA7:mcdc.addr.*]] = alloca i32, align 4
+ // LL1: %[[MA8:mcdc.addr.*]] = alloca i32, align 4
// LL: %[[MA9:mcdc.addr.*]] = alloca i32, align 4
// LL: %[[MA10:mcdc.addr.*]] = alloca i32, align 4
+ // LL1: %[[MA11:mcdc.addr.*]] = alloca i32, align 4
+ // LL1: %[[MA12:mcdc.addr.*]] = alloca i32, align 4
+ // LL1: %[[MA13:mcdc.addr.*]] = alloca i32, align 4
+ // LL1: %[[MA14:mcdc.addr.*]] = alloca i32, align 4
+ // LL1: %[[MA15:mcdc.addr.*]] = alloca i32, align 4
// LL: call void @llvm.instrprof.mcdc.parameters(ptr @[[PROFN:.+]], i64 [[#H:]], i32 [[#BS:]])
int count = 0;
if (a)
// NB=2 Single cond
+ // MM1: Decision,File 0, [[#L:@LINE-2]]:7 -> [[#L:@LINE-2]]:8 = M:[[#I:2]], C:1
+ // MM1: Branch,File 0, [[#L]]:7 -> [[#L]]:8 = #1, (#0 - #1) [1,0,0]
// MM2-NOT: Decision
+ // LL1: store i32 0, ptr %[[MA1]], align 4
+ // LL1: = load i32, ptr %[[MA1]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA1]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:0]], ptr %[[MA1]])
++count;
if (a ? true : false)
// NB=2,2 Wider decision comes first.
+ // MM1: Decision,File 0, [[@LINE-2]]:7 -> [[#L:@LINE-2]]:23 = M:[[#I:I+2+2]], C:1
+ // MM1: Decision,File 0, [[#L]]:7 -> [[#L]]:8 = M:[[#I-2]], C:1
+ // MM1: Branch,File 0, [[#L]]:7 -> [[#L]]:23 = #2, (#0 - #2) [1,0,0]
+ // MM1: Branch,File 0, [[#L]]:7 -> [[#L]]:8 = #3, (#0 - #3) [1,0,0]
+ // LL1: store i32 0, ptr %[[MA3]], align 4
+ // LL1: store i32 0, ptr %[[MA2]], align 4
// MA2 has C:2
+ // LL1: = load i32, ptr %[[MA2]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA2]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+2]], ptr %[[MA2]])
// MA3 has C:1
+ // LL1: = load i32, ptr %[[MA3]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA3]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+2]], ptr %[[MA3]])
++count;
if (a && b ? true : false)
// NB=2,3 Wider decision comes first.
- // MM2: Decision,File 0, [[@LINE-2]]:7 -> [[#L:@LINE-2]]:13 = M:[[#I:3]], C:2
+ // MM1: Decision,File 0, [[@LINE-2]]:7 -> [[#L:@LINE-2]]:28 = M:[[#I:I+3+2]], C:1
+ // MM1: Decision,File 0, [[@LINE-3]]:7 -> [[#L:@LINE-3]]:13 = M:[[#I-2]], C:2
+ // MM2: Decision,File 0, [[@LINE-4]]:7 -> [[#L:@LINE-4]]:13 = M:[[#I:3]], C:2
+ // MM1: Branch,File 0, [[#L]]:7 -> [[#L]]:28 = #4, (#0 - #4) [1,0,0]
// MM: Branch,File 0, [[#L]]:7 -> [[#L]]:8 = #6, (#0 - #6) [1,2,0]
// MM: Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #7, (#6 - #7) [2,0,0]
+ // LL1: store i32 0, ptr %[[MA5]], align 4
// LL: store i32 0, ptr %[[MA4]], align 4
// LL: = load i32, ptr %[[MA4]], align 4
// LL: store i32 %{{.+}}, ptr %[[MA4]], align 4
// LL: = load i32, ptr %[[MA4]], align 4
// LL: store i32 %{{.+}}, ptr %[[MA4]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+2]], ptr %[[MA4]])
// LL2: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:0]], ptr %[[MA4]])
+ // LL1: = load i32, ptr %[[MA5]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA5]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA5]])
++count;
while (a || true) {
// NB=3 BinOp only
@@ -43,21 +81,29 @@ int func_cond(bool a, bool b) {
// LL: store i32 %{{.+}}, ptr %[[MA6]], align 4
// LL: = load i32, ptr %[[MA6]], align 4
// LL: store i32 %{{.+}}, ptr %[[MA6]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+2]], ptr %[[MA6]])
// LL2: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA6]])
++count;
break;
}
while (a || true ? false : true) {
// Wider decision comes first.
- // MM2: Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2
+ // MM1: Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:34 = M:[[#I:I+3+2]], C:1
+ // MM1: Decision,File 0, [[@LINE-3]]:10 -> [[#L:@LINE-3]]:19 = M:[[#I-2]], C:2
+ // MM2: Decision,File 0, [[@LINE-4]]:10 -> [[#L:@LINE-4]]:19 = M:[[#I:I+3]], C:2
+ // MM1: Branch,File 0, [[#L]]:10 -> [[#L]]:34 = #11, #0 [1,0,0]
// MM: Branch,File 0, [[#L]]:10 -> [[#L]]:11 = ((#0 + #11) - #13), #13 [1,0,2]
// MM: Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#13 - #14), 0 [2,0,0]
+ // LL1: store i32 0, ptr %[[MA8]], align 4
// LL: store i32 0, ptr %[[MA7]], align 4
// LL: = load i32, ptr %[[MA7]], align 4
// LL: store i32 %{{.+}}, ptr %[[MA7]], align 4
// LL: = load i32, ptr %[[MA7]], align 4
// LL: store i32 %{{.+}}, ptr %[[MA7]], align 4
// LL: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA7]])
+ // LL1: = load i32, ptr %[[MA8]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA8]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA8]])
++count;
}
do {
@@ -72,29 +118,62 @@ int func_cond(bool a, bool b) {
// LL: store i32 %{{.+}}, ptr %[[MA9]], align 4
// LL: = load i32, ptr %[[MA9]], align 4
// LL: store i32 %{{.+}}, ptr %[[MA9]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+2]], ptr %[[MA9]])
// LL2: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA9]])
do {
++count;
} while (a && false ? true : false);
// Wider decision comes first.
- // MM2: Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:15, C:2
+ // MM1: Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:37 = M:[[#I:I+3+2]], C:1
+ // MM1: Decision,File 0, [[@LINE-3]]:12 -> [[#L:@LINE-3]]:22 = M:[[#I-2]], C:2
+ // MM2: Decision,File 0, [[@LINE-4]]:12 -> [[#L:@LINE-4]]:22 = M:15, C:2
+ // MM1: Branch,File 0, [[#L]]:12 -> [[#L]]:37 = #18, #0 [1,0,0]
// MM: Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #20, ((#0 + #18) - #20) [1,2,0]
// MM: Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#20 - #21) [2,0,0]
+ // LL1: store i32 0, ptr %[[MA11]], align 4
// LL: store i32 0, ptr %[[MA10]], align 4
// LL: = load i32, ptr %[[MA10]], align 4
// LL: store i32 %{{.+}}, ptr %[[MA10]], align 4
// LL: = load i32, ptr %[[MA10]], align 4
// LL: store i32 %{{.+}}, ptr %[[MA10]], align 4
// LL: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA10]])
+ // LL1: = load i32, ptr %[[MA11]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA11]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA11]])
// FIXME: Confirm (B+3==BS)
for (int i = 0; i < (a ? 2 : 1); ++i) {
// Simple nested decision (different column)
+ // MM1: Decision,File 0, [[@LINE-2]]:19 -> [[#L:@LINE-2]]:34 = M:[[#I:I+2+2]], C:1
+ // MM1: Branch,File 0, [[#L]]:19 -> [[#L]]:34 = #22, #0 [1,0,0]
+ // MM1: Decision,File 0, [[#L]]:24 -> [[#L]]:25 = M:[[#I-2]], C:1
+ // MM1: Branch,File 0, [[#L]]:24 -> [[#L]]:25 = #23, ((#0 + #22) - #23) [1,0,0]
// MM2-NOT: Decision
+ // LL1: store i32 0, ptr %[[MA13]], align 4
+ // LL1: store i32 0, ptr %[[MA12]], align 4
+ // LL1: = load i32, ptr %[[MA12]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA12]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+2]], ptr %[[MA12]])
+ // LL1: = load i32, ptr %[[MA13]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA13]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+2]], ptr %[[MA13]])
// LL2-NOT: call void @llvm.instrprof.mcdc.tvbitmap.update
++count;
}
for (int i = 0; i >= 4 ? false : true; ++i) {
// Wider decision comes first.
+ // MM1: Decision,File 0, [[@LINE-2]]:19 -> [[#L:@LINE-2]]:40 = M:[[#I:I+2+2]], C:1
+ // MM1: Decision,File 0, [[#L]]:19 -> [[#L]]:25 = M:[[#I-2]], C:1
+ // MM1: Branch,File 0, [[#L]]:19 -> [[#L]]:40 = #24, #0 [1,0,0]
+ // MM1: Branch,File 0, [[#L]]:19 -> [[#L]]:25 = #25, ((#0 + #24) - #25) [1,0,0]
+ // LL1: store i32 0, ptr %[[MA15]], align 4
+ // LL1: store i32 0, ptr %[[MA14]], align 4
+ // LL1: = load i32, ptr %[[MA14]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA14]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+2]], ptr %[[MA14]])
+ // LL1: = load i32, ptr %[[MA15]], align 4
+ // LL1: store i32 %{{.+}}, ptr %[[MA15]], align 4
+ // LL1: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#BS-2]], ptr %[[MA15]])
+ // FIXME: Confirm (B+2+2==BS)
++count;
}
return count;
More information about the llvm-branch-commits
mailing list