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 <geek4ci...@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; _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits