aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp405
1 files changed, 380 insertions, 25 deletions
diff --git a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
index 56411e2240e5..bf227386a71b 100644
--- a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -95,6 +95,8 @@ void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) {
}
namespace {
+using MCDCConditionID = CounterMappingRegion::MCDCConditionID;
+using MCDCParameters = CounterMappingRegion::MCDCParameters;
/// A region of source code that can be mapped to a counter.
class SourceMappingRegion {
@@ -104,6 +106,9 @@ class SourceMappingRegion {
/// Secondary Counter used for Branch Regions for "False" branches.
std::optional<Counter> FalseCount;
+ /// Parameters used for Modified Condition/Decision Coverage
+ MCDCParameters MCDCParams;
+
/// The region's starting location.
std::optional<SourceLocation> LocStart;
@@ -122,11 +127,18 @@ public:
}
SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
+ MCDCParameters MCDCParams,
std::optional<SourceLocation> LocStart,
std::optional<SourceLocation> LocEnd,
bool GapRegion = false)
- : Count(Count), FalseCount(FalseCount), LocStart(LocStart),
- LocEnd(LocEnd), GapRegion(GapRegion) {}
+ : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
+ LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {}
+
+ SourceMappingRegion(MCDCParameters MCDCParams,
+ std::optional<SourceLocation> LocStart,
+ std::optional<SourceLocation> LocEnd)
+ : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd),
+ GapRegion(false) {}
const Counter &getCounter() const { return Count; }
@@ -163,6 +175,10 @@ public:
void setGap(bool Gap) { GapRegion = Gap; }
bool isBranch() const { return FalseCount.has_value(); }
+
+ bool isMCDCDecision() const { return MCDCParams.NumConditions != 0; }
+
+ const MCDCParameters &getMCDCParams() const { return MCDCParams; }
};
/// Spelling locations for the start and end of a source region.
@@ -454,8 +470,13 @@ public:
SR.LineEnd, SR.ColumnEnd));
} else if (Region.isBranch()) {
MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
- Region.getCounter(), Region.getFalseCounter(), *CovFileID,
- SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
+ Region.getCounter(), Region.getFalseCounter(),
+ Region.getMCDCParams(), *CovFileID, SR.LineStart, SR.ColumnStart,
+ SR.LineEnd, SR.ColumnEnd));
+ } else if (Region.isMCDCDecision()) {
+ MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion(
+ Region.getMCDCParams(), *CovFileID, SR.LineStart, SR.ColumnStart,
+ SR.LineEnd, SR.ColumnEnd));
} else {
MappingRegions.push_back(CounterMappingRegion::makeRegion(
Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
@@ -542,6 +563,239 @@ struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
}
};
+/// A wrapper object for maintaining stacks to track the resursive AST visitor
+/// walks for the purpose of assigning IDs to leaf-level conditions measured by
+/// MC/DC. The object is created with a reference to the MCDCBitmapMap that was
+/// created during the initial AST walk. The presence of a bitmap associated
+/// with a boolean expression (top-level logical operator nest) indicates that
+/// the boolean expression qualified for MC/DC. The resulting condition IDs
+/// are preserved in a map reference that is also provided during object
+/// creation.
+struct MCDCCoverageBuilder {
+
+ /// The AST walk recursively visits nested logical-AND or logical-OR binary
+ /// operator nodes and then visits their LHS and RHS children nodes. As this
+ /// happens, the algorithm will assign IDs to each operator's LHS and RHS side
+ /// as the walk moves deeper into the nest. At each level of the recursive
+ /// nest, the LHS and RHS may actually correspond to larger subtrees (not
+ /// leaf-conditions). If this is the case, when that node is visited, the ID
+ /// assigned to the subtree is re-assigned to its LHS, and a new ID is given
+ /// to its RHS. At the end of the walk, all leaf-level conditions will have a
+ /// unique ID -- keep in mind that the final set of IDs may not be in
+ /// numerical order from left to right.
+ ///
+ /// Example: "x = (A && B) || (C && D) || (D && F)"
+ ///
+ /// Visit Depth1:
+ /// (A && B) || (C && D) || (D && F)
+ /// ^-------LHS--------^ ^-RHS--^
+ /// ID=1 ID=2
+ ///
+ /// Visit LHS-Depth2:
+ /// (A && B) || (C && D)
+ /// ^-LHS--^ ^-RHS--^
+ /// ID=1 ID=3
+ ///
+ /// Visit LHS-Depth3:
+ /// (A && B)
+ /// LHS RHS
+ /// ID=1 ID=4
+ ///
+ /// Visit RHS-Depth3:
+ /// (C && D)
+ /// LHS RHS
+ /// ID=3 ID=5
+ ///
+ /// Visit RHS-Depth2: (D && F)
+ /// LHS RHS
+ /// ID=2 ID=6
+ ///
+ /// Visit Depth1:
+ /// (A && B) || (C && D) || (D && F)
+ /// ID=1 ID=4 ID=3 ID=5 ID=2 ID=6
+ ///
+ /// A node ID of '0' always means MC/DC isn't being tracked.
+ ///
+ /// As the AST walk proceeds recursively, the algorithm will also use stacks
+ /// to track the IDs of logical-AND and logical-OR operations on the RHS so
+ /// that it can be determined which nodes are executed next, depending on how
+ /// a LHS or RHS of a logical-AND or logical-OR is evaluated. This
+ /// information relies on the assigned IDs and are embedded within the
+ /// coverage region IDs of each branch region associated with a leaf-level
+ /// condition. This information helps the visualization tool reconstruct all
+ /// possible test vectors for the purposes of MC/DC analysis. if a "next" node
+ /// ID is '0', it means it's the end of the test vector. The following rules
+ /// are used:
+ ///
+ /// For logical-AND ("LHS && RHS"):
+ /// - If LHS is TRUE, execution goes to the RHS node.
+ /// - If LHS is FALSE, execution goes to the LHS node of the next logical-OR.
+ /// If that does not exist, execution exits (ID == 0).
+ ///
+ /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND.
+ /// If that does not exist, execution exits (ID == 0).
+ /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR.
+ /// If that does not exist, execution exits (ID == 0).
+ ///
+ /// For logical-OR ("LHS || RHS"):
+ /// - If LHS is TRUE, execution goes to the LHS node of the next logical-AND.
+ /// If that does not exist, execution exits (ID == 0).
+ /// - If LHS is FALSE, execution goes to the RHS node.
+ ///
+ /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND.
+ /// If that does not exist, execution exits (ID == 0).
+ /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR.
+ /// If that does not exist, execution exits (ID == 0).
+ ///
+ /// Finally, the condition IDs are also used when instrumenting the code to
+ /// indicate a unique offset into a temporary bitmap that represents the true
+ /// or false evaluation of that particular condition.
+ ///
+ /// NOTE regarding the use of CodeGenFunction::stripCond(). Even though, for
+ /// simplicity, parentheses and unary logical-NOT operators are considered
+ /// part of their underlying condition for both MC/DC and branch coverage, the
+ /// condition IDs themselves are assigned and tracked using the underlying
+ /// condition itself. This is done solely for consistency since parentheses
+ /// and logical-NOTs are ignored when checking whether the condition is
+ /// actually an instrumentable condition. This can also make debugging a bit
+ /// easier.
+
+private:
+ CodeGenModule &CGM;
+
+ llvm::SmallVector<MCDCConditionID> AndRHS;
+ llvm::SmallVector<MCDCConditionID> OrRHS;
+ llvm::SmallVector<const BinaryOperator *> NestLevel;
+ llvm::DenseMap<const Stmt *, MCDCConditionID> &CondIDs;
+ llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap;
+ MCDCConditionID NextID = 1;
+ bool NotMapped = false;
+
+ /// Is this a logical-AND operation?
+ bool isLAnd(const BinaryOperator *E) const {
+ return E->getOpcode() == BO_LAnd;
+ }
+
+ /// Push an ID onto the corresponding RHS stack.
+ void pushRHS(const BinaryOperator *E) {
+ llvm::SmallVector<MCDCConditionID> &rhs = isLAnd(E) ? AndRHS : OrRHS;
+ rhs.push_back(CondIDs[CodeGenFunction::stripCond(E->getRHS())]);
+ }
+
+ /// Pop an ID from the corresponding RHS stack.
+ void popRHS(const BinaryOperator *E) {
+ llvm::SmallVector<MCDCConditionID> &rhs = isLAnd(E) ? AndRHS : OrRHS;
+ if (!rhs.empty())
+ rhs.pop_back();
+ }
+
+ /// If the expected ID is on top, pop it off the corresponding RHS stack.
+ void popRHSifTop(const BinaryOperator *E) {
+ if (!OrRHS.empty() && CondIDs[E] == OrRHS.back())
+ OrRHS.pop_back();
+ else if (!AndRHS.empty() && CondIDs[E] == AndRHS.back())
+ AndRHS.pop_back();
+ }
+
+public:
+ MCDCCoverageBuilder(CodeGenModule &CGM,
+ llvm::DenseMap<const Stmt *, MCDCConditionID> &CondIDMap,
+ llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap)
+ : CGM(CGM), CondIDs(CondIDMap), MCDCBitmapMap(MCDCBitmapMap) {}
+
+ /// Return the ID of the RHS of the next, upper nest-level logical-OR.
+ MCDCConditionID getNextLOrCondID() const {
+ return OrRHS.empty() ? 0 : OrRHS.back();
+ }
+
+ /// Return the ID of the RHS of the next, upper nest-level logical-AND.
+ MCDCConditionID getNextLAndCondID() const {
+ return AndRHS.empty() ? 0 : AndRHS.back();
+ }
+
+ /// Return the ID of a given condition.
+ MCDCConditionID getCondID(const Expr *Cond) const {
+ auto I = CondIDs.find(CodeGenFunction::stripCond(Cond));
+ if (I == CondIDs.end())
+ return 0;
+ else
+ return I->second;
+ }
+
+ /// Push the binary operator statement to track the nest level and assign IDs
+ /// to the operator's LHS and RHS. The RHS may be a larger subtree that is
+ /// broken up on successive levels.
+ void pushAndAssignIDs(const BinaryOperator *E) {
+ if (!CGM.getCodeGenOpts().MCDCCoverage)
+ return;
+
+ // If binary expression is disqualified, don't do mapping.
+ if (NestLevel.empty() && MCDCBitmapMap.find(CodeGenFunction::stripCond(
+ E)) == MCDCBitmapMap.end())
+ NotMapped = true;
+
+ // Push Stmt on 'NestLevel' stack to keep track of nest location.
+ NestLevel.push_back(E);
+
+ // Don't go any further if we don't need to map condition IDs.
+ if (NotMapped)
+ return;
+
+ // If the operator itself has an assigned ID, this means it represents a
+ // larger subtree. In this case, pop its ID out of the RHS stack and
+ // assign that ID to its LHS node. Its RHS will receive a new ID.
+ if (CondIDs.find(CodeGenFunction::stripCond(E)) != CondIDs.end()) {
+ // If Stmt has an ID, assign its ID to LHS
+ CondIDs[CodeGenFunction::stripCond(E->getLHS())] = CondIDs[E];
+
+ // Since the operator's LHS assumes the operator's same ID, pop the
+ // operator from the RHS stack so that if LHS short-circuits, it won't be
+ // incorrectly re-used as the node executed next.
+ popRHSifTop(E);
+ } else {
+ // Otherwise, assign ID+1 to LHS.
+ CondIDs[CodeGenFunction::stripCond(E->getLHS())] = NextID++;
+ }
+
+ // Assign ID+1 to RHS.
+ CondIDs[CodeGenFunction::stripCond(E->getRHS())] = NextID++;
+
+ // Push ID of Stmt's RHS so that LHS nodes know about it
+ pushRHS(E);
+ }
+
+ /// Pop the binary operator from the next level. If the walk is at the top of
+ /// the next, assign the total number of conditions.
+ unsigned popAndReturnCondCount(const BinaryOperator *E) {
+ if (!CGM.getCodeGenOpts().MCDCCoverage)
+ return 0;
+
+ unsigned TotalConds = 0;
+
+ // Pop Stmt from 'NestLevel' stack.
+ assert(NestLevel.back() == E);
+ NestLevel.pop_back();
+
+ // Reset state if not doing mapping.
+ if (NestLevel.empty() && NotMapped) {
+ NotMapped = false;
+ return 0;
+ }
+
+ // Pop RHS ID.
+ popRHS(E);
+
+ // If at the parent (NestLevel=0), set conds and reset.
+ if (NestLevel.empty()) {
+ TotalConds = NextID - 1;
+
+ // Reset ID back to beginning.
+ NextID = 1;
+ }
+ return TotalConds;
+ }
+};
+
/// A StmtVisitor that creates coverage mapping regions which map
/// from the source code locations to the PGO counters.
struct CounterCoverageMappingBuilder
@@ -550,8 +804,14 @@ struct CounterCoverageMappingBuilder
/// The map of statements to count values.
llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
+ /// The map of statements to bitmap coverage object values.
+ llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap;
+
/// A stack of currently live regions.
- std::vector<SourceMappingRegion> RegionStack;
+ llvm::SmallVector<SourceMappingRegion> RegionStack;
+
+ /// An object to manage MCDC regions.
+ MCDCCoverageBuilder MCDCBuilder;
CounterExpressionBuilder Builder;
@@ -589,6 +849,8 @@ struct CounterCoverageMappingBuilder
return Counter::getCounter(CounterMap[S]);
}
+ unsigned getRegionBitmap(const Stmt *S) { return MCDCBitmapMap[S]; }
+
/// Push a region onto the stack.
///
/// Returns the index on the stack where the region was pushed. This can be
@@ -596,7 +858,9 @@ struct CounterCoverageMappingBuilder
size_t pushRegion(Counter Count,
std::optional<SourceLocation> StartLoc = std::nullopt,
std::optional<SourceLocation> EndLoc = std::nullopt,
- std::optional<Counter> FalseCount = std::nullopt) {
+ std::optional<Counter> FalseCount = std::nullopt,
+ MCDCConditionID ID = 0, MCDCConditionID TrueID = 0,
+ MCDCConditionID FalseID = 0) {
if (StartLoc && !FalseCount) {
MostRecentLocation = *StartLoc;
@@ -615,7 +879,19 @@ struct CounterCoverageMappingBuilder
StartLoc = std::nullopt;
if (EndLoc && EndLoc->isInvalid())
EndLoc = std::nullopt;
- RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
+ RegionStack.emplace_back(Count, FalseCount,
+ MCDCParameters{0, 0, ID, TrueID, FalseID},
+ StartLoc, EndLoc);
+
+ return RegionStack.size() - 1;
+ }
+
+ size_t pushRegion(unsigned BitmapIdx, unsigned Conditions,
+ std::optional<SourceLocation> StartLoc = std::nullopt,
+ std::optional<SourceLocation> EndLoc = std::nullopt) {
+
+ RegionStack.emplace_back(MCDCParameters{BitmapIdx, Conditions}, StartLoc,
+ EndLoc);
return RegionStack.size() - 1;
}
@@ -746,7 +1022,9 @@ struct CounterCoverageMappingBuilder
/// and add it to the function's SourceRegions. A branch region tracks a
/// "True" counter and a "False" counter for boolean expressions that
/// result in the generation of a branch.
- void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt) {
+ void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt,
+ MCDCConditionID ID = 0, MCDCConditionID TrueID = 0,
+ MCDCConditionID FalseID = 0) {
// Check for NULL conditions.
if (!C)
return;
@@ -764,13 +1042,21 @@ struct CounterCoverageMappingBuilder
// CodeGenFunction.c always returns false, but that is very heavy-handed.
if (ConditionFoldsToBool(C))
popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C),
- Counter::getZero()));
+ Counter::getZero(), ID, TrueID, FalseID));
else
// Otherwise, create a region with the True counter and False counter.
- popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt));
+ popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt, ID,
+ TrueID, FalseID));
}
}
+ /// Create a Decision Region with a BitmapIdx and number of Conditions. This
+ /// type of region "contains" branch regions, one for each of the conditions.
+ /// The visualization tool will group everything together.
+ void createDecisionRegion(const Expr *C, unsigned BitmapIdx, unsigned Conds) {
+ popRegions(pushRegion(BitmapIdx, Conds, getStart(C), getEnd(C)));
+ }
+
/// Create a Branch Region around a SwitchCase for code coverage
/// and add it to the function's SourceRegions.
void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt,
@@ -851,8 +1137,12 @@ struct CounterCoverageMappingBuilder
// we've seen this region.
if (StartLocs.insert(Loc).second) {
if (I.isBranch())
- SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
- getEndOfFileOrMacro(Loc), I.isBranch());
+ SourceRegions.emplace_back(
+ I.getCounter(), I.getFalseCounter(),
+ MCDCParameters{0, 0, I.getMCDCParams().ID,
+ I.getMCDCParams().TrueID,
+ I.getMCDCParams().FalseID},
+ Loc, getEndOfFileOrMacro(Loc), I.isBranch());
else
SourceRegions.emplace_back(I.getCounter(), Loc,
getEndOfFileOrMacro(Loc));
@@ -971,9 +1261,13 @@ struct CounterCoverageMappingBuilder
CounterCoverageMappingBuilder(
CoverageMappingModuleGen &CVM,
- llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
- const LangOptions &LangOpts)
- : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
+ llvm::DenseMap<const Stmt *, unsigned> &CounterMap,
+ llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap,
+ llvm::DenseMap<const Stmt *, MCDCConditionID> &CondIDMap,
+ SourceManager &SM, const LangOptions &LangOpts)
+ : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
+ MCDCBitmapMap(MCDCBitmapMap),
+ MCDCBuilder(CVM.getCodeGenModule(), CondIDMap, MCDCBitmapMap) {}
/// Write the mapping data to the output stream
void write(llvm::raw_ostream &OS) {
@@ -1519,6 +1813,9 @@ struct CounterCoverageMappingBuilder
}
void VisitBinLAnd(const BinaryOperator *E) {
+ // Keep track of Binary Operator and assign MCDC condition IDs
+ MCDCBuilder.pushAndAssignIDs(E);
+
extendRegion(E->getLHS());
propagateCounts(getRegion().getCounter(), E->getLHS());
handleFileExit(getEnd(E->getLHS()));
@@ -1527,6 +1824,11 @@ struct CounterCoverageMappingBuilder
extendRegion(E->getRHS());
propagateCounts(getRegionCounter(E), E->getRHS());
+ // Process Binary Operator and create MCDC Decision Region if top-level
+ unsigned NumConds = 0;
+ if ((NumConds = MCDCBuilder.popAndReturnCondCount(E)))
+ createDecisionRegion(E, getRegionBitmap(E), NumConds);
+
// Extract the RHS's Execution Counter.
Counter RHSExecCnt = getRegionCounter(E);
@@ -1536,13 +1838,30 @@ struct CounterCoverageMappingBuilder
// Extract the Parent Region Counter.
Counter ParentCnt = getRegion().getCounter();
+ // Extract the MCDC condition IDs (returns 0 if not needed).
+ MCDCConditionID NextOrID = MCDCBuilder.getNextLOrCondID();
+ MCDCConditionID NextAndID = MCDCBuilder.getNextLAndCondID();
+ MCDCConditionID LHSid = MCDCBuilder.getCondID(E->getLHS());
+ MCDCConditionID RHSid = MCDCBuilder.getCondID(E->getRHS());
+
// Create Branch Region around LHS condition.
+ // MC/DC: For "LHS && RHS"
+ // - If LHS is TRUE, execution goes to the RHS.
+ // - If LHS is FALSE, execution goes to the LHS of the next logical-OR.
+ // If that does not exist, execution exits (ID == 0).
createBranchRegion(E->getLHS(), RHSExecCnt,
- subtractCounters(ParentCnt, RHSExecCnt));
+ subtractCounters(ParentCnt, RHSExecCnt), LHSid, RHSid,
+ NextOrID);
// Create Branch Region around RHS condition.
+ // MC/DC: For "LHS && RHS"
+ // - If RHS is TRUE, execution goes to LHS of the next logical-AND.
+ // If that does not exist, execution exits (ID == 0).
+ // - If RHS is FALSE, execution goes to the LHS of the next logical-OR.
+ // If that does not exist, execution exits (ID == 0).
createBranchRegion(E->getRHS(), RHSTrueCnt,
- subtractCounters(RHSExecCnt, RHSTrueCnt));
+ subtractCounters(RHSExecCnt, RHSTrueCnt), RHSid,
+ NextAndID, NextOrID);
}
// Determine whether the right side of OR operation need to be visited.
@@ -1556,6 +1875,9 @@ struct CounterCoverageMappingBuilder
}
void VisitBinLOr(const BinaryOperator *E) {
+ // Keep track of Binary Operator and assign MCDC condition IDs
+ MCDCBuilder.pushAndAssignIDs(E);
+
extendRegion(E->getLHS());
Counter OutCount = propagateCounts(getRegion().getCounter(), E->getLHS());
handleFileExit(getEnd(E->getLHS()));
@@ -1564,6 +1886,11 @@ struct CounterCoverageMappingBuilder
extendRegion(E->getRHS());
propagateCounts(getRegionCounter(E), E->getRHS());
+ // Process Binary Operator and create MCDC Decision Region if top-level
+ unsigned NumConds = 0;
+ if ((NumConds = MCDCBuilder.popAndReturnCondCount(E)))
+ createDecisionRegion(E, getRegionBitmap(E), NumConds);
+
// Extract the RHS's Execution Counter.
Counter RHSExecCnt = getRegionCounter(E);
@@ -1577,13 +1904,28 @@ struct CounterCoverageMappingBuilder
// Extract the Parent Region Counter.
Counter ParentCnt = getRegion().getCounter();
+ // Extract the MCDC condition IDs (returns 0 if not needed).
+ MCDCConditionID NextOrID = MCDCBuilder.getNextLOrCondID();
+ MCDCConditionID NextAndID = MCDCBuilder.getNextLAndCondID();
+ MCDCConditionID LHSid = MCDCBuilder.getCondID(E->getLHS());
+ MCDCConditionID RHSid = MCDCBuilder.getCondID(E->getRHS());
+
// Create Branch Region around LHS condition.
+ // MC/DC: For "LHS || RHS"
+ // - If LHS is TRUE, execution goes to the LHS of the next logical-AND.
+ // If that does not exist, execution exits (ID == 0).
+ // - If LHS is FALSE, execution goes to the RHS.
createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
- RHSExecCnt);
+ RHSExecCnt, LHSid, NextAndID, RHSid);
// Create Branch Region around RHS condition.
+ // MC/DC: For "LHS || RHS"
+ // - If RHS is TRUE, execution goes to LHS of the next logical-AND.
+ // If that does not exist, execution exits (ID == 0).
+ // - If RHS is FALSE, execution goes to the LHS of the next logical-OR.
+ // If that does not exist, execution exits (ID == 0).
createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
- RHSFalseCnt);
+ RHSFalseCnt, RHSid, NextAndID, NextOrID);
}
void VisitLambdaExpr(const LambdaExpr *LE) {
@@ -1633,11 +1975,23 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
<< " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
- Ctx.dump(R.Count, OS);
- if (R.Kind == CounterMappingRegion::BranchRegion) {
- OS << ", ";
- Ctx.dump(R.FalseCount, OS);
+ if (R.Kind == CounterMappingRegion::MCDCDecisionRegion) {
+ OS << "M:" << R.MCDCParams.BitmapIdx;
+ OS << ", C:" << R.MCDCParams.NumConditions;
+ } else {
+ Ctx.dump(R.Count, OS);
+
+ if (R.Kind == CounterMappingRegion::BranchRegion ||
+ R.Kind == CounterMappingRegion::MCDCBranchRegion) {
+ OS << ", ";
+ Ctx.dump(R.FalseCount, OS);
+ }
+ }
+
+ if (R.Kind == CounterMappingRegion::MCDCBranchRegion) {
+ OS << " [" << R.MCDCParams.ID << "," << R.MCDCParams.TrueID;
+ OS << "," << R.MCDCParams.FalseID << "] ";
}
if (R.Kind == CounterMappingRegion::ExpansionRegion)
@@ -1846,8 +2200,9 @@ unsigned CoverageMappingModuleGen::getFileID(FileEntryRef File) {
void CoverageMappingGen::emitCounterMapping(const Decl *D,
llvm::raw_ostream &OS) {
- assert(CounterMap);
- CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts);
+ assert(CounterMap && MCDCBitmapMap);
+ CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCBitmapMap,
+ *CondIDMap, SM, LangOpts);
Walker.VisitDecl(D);
Walker.write(OS);
}