Fix expression coverage on additional nodes (#5849 partial) (#5867)

This commit is contained in:
Todd Strader 2025-03-19 19:01:31 -04:00 committed by GitHub
parent 39bdd427d6
commit d2b7b567df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 74 additions and 14 deletions

View File

@ -2486,6 +2486,8 @@ public:
virtual bool isGateOptimizable() const { return !isTimingControl(); }
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
virtual bool isGateDedupable() const { return isGateOptimizable(); }
// Whether the node can be used in expression coverage
virtual bool isExprCoverageEligible() const { return isGateDedupable(); }
// Else creates output or exits, etc, not unconsumed
virtual bool isOutputter() { return false; }
// Else a AstTime etc which output can't be predicted from input

View File

@ -1600,6 +1600,7 @@ public:
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const string& name) override { m_name = name; }
bool index() const { return m_index; }
bool isExprCoverageEligible() const override { return false; }
};
class AstMemberSel final : public AstNodeExpr {
// @astgen op1 := fromp : AstNodeExpr

View File

@ -35,6 +35,23 @@
VL_DEFINE_DEBUG_FUNCTIONS;
class ExprCoverageEligibleVisitor final : public VNVisitor {
// STATE
bool m_eligible = true;
void visit(AstNode* nodep) override {
if (!nodep->isExprCoverageEligible()) { m_eligible = false; }
iterateChildren(nodep);
}
public:
// CONSTRUCTORS
explicit ExprCoverageEligibleVisitor(AstNode* nodep) { iterateChildren(nodep); }
~ExprCoverageEligibleVisitor() override = default;
bool eligible() { return m_eligible; }
};
//######################################################################
// Coverage state, as a visitor of each AstNode
@ -669,6 +686,7 @@ class CoverageVisitor final : public VNVisitor {
m_objective = true;
iterate(nodep);
if (checkMaxExprs(falseExprs.size())) return;
if (m_seeking == ABORTED) return;
addExprCoverInc(nodep);
const int start = m_exprs.size();
@ -872,26 +890,30 @@ class CoverageVisitor final : public VNVisitor {
lineTrack(nodep);
}
// Lambdas not supported for expression coverage
void visit(AstWith* nodep) override {
VL_RESTORER(m_seeking);
if (m_seeking == SEEKING) abortExprCoverage();
m_seeking = ABORTED;
iterateChildren(nodep);
lineTrack(nodep);
void visit(AstFuncRef* nodep) override {
if (nodep->taskp()->lifetime().isAutomatic()) {
visit(static_cast<AstNodeExpr*>(nodep));
} else {
exprUnsupported(nodep, "non-automatic function");
}
}
void visit(AstNodeExpr* nodep) override {
if (m_seeking != SEEKING) {
iterateChildren(nodep);
} else {
std::stringstream emitV;
V3EmitV::verilogForTree(nodep, emitV);
// Add new expression with a single term
CoverExpr expr;
expr.emplace_back(nodep, m_objective, emitV.str());
m_exprs.push_back(std::move(expr));
checkMaxExprs();
ExprCoverageEligibleVisitor elgibleVisitor(nodep);
if (elgibleVisitor.eligible()) {
std::stringstream emitV;
V3EmitV::verilogForTree(nodep, emitV);
// Add new expression with a single term
CoverExpr expr;
expr.emplace_back(nodep, m_objective, emitV.str());
m_exprs.push_back(std::move(expr));
checkMaxExprs();
} else {
exprUnsupported(nodep, "not coverage eligible");
}
}
lineTrack(nodep);
}
@ -902,6 +924,17 @@ class CoverageVisitor final : public VNVisitor {
lineTrack(nodep);
}
void exprUnsupported(AstNode* nodep, const string& why) {
UINFO(9, "unsupported: " << why << " " << nodep << endl);
bool wasSeeking = m_seeking == SEEKING;
Objective oldSeeking = m_seeking;
if (wasSeeking) { abortExprCoverage(); }
m_seeking = ABORTED;
iterateChildren(nodep);
lineTrack(nodep);
if (!wasSeeking) { m_seeking = oldSeeking; }
}
public:
// CONSTRUCTORS
explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); }

View File

@ -5,6 +5,10 @@
// any use, without warranty, 2024 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class cls;
rand int x;
endclass
module t (/*AUTOARG*/
// Inputs
clk
@ -284,6 +288,7 @@
logic ta, tb, tc;
initial begin
cls obj = new;
int q[5];
int qv[$];
@ -304,6 +309,7 @@
tb = ta;
ta = '0;
end
if (!bit'(obj.randomize() with {x < 100;})) $write("");
end
sub the_sub_1 (.p(t1), .q(t2));

View File

@ -4,6 +4,10 @@
// any use, without warranty, 2024 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class cls;
rand int x;
endclass
module t (/*AUTOARG*/
// Inputs
clk
@ -124,6 +128,7 @@ module t (/*AUTOARG*/
logic ta, tb, tc;
initial begin
cls obj = new;
int q[5];
int qv[$];
@ -140,6 +145,7 @@ module t (/*AUTOARG*/
tb = ta;
ta = '0;
end
if (!bit'(obj.randomize() with {x < 100;})) $write("");
end
sub the_sub_1 (.p(t1), .q(t2));

View File

@ -5,6 +5,10 @@
// any use, without warranty, 2024 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class cls;
rand int x;
endclass
module t (/*AUTOARG*/
// Inputs
clk
@ -412,6 +416,7 @@
logic ta, tb, tc;
initial begin
cls obj = new;
int q[5];
int qv[$];
@ -432,6 +437,7 @@
tb = ta;
ta = '0;
end
if (!bit'(obj.randomize() with {x < 100;})) $write("");
end
sub the_sub_1 (.p(t1), .q(t2));

View File

@ -5,6 +5,10 @@
// any use, without warranty, 2024 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class cls;
rand int x;
endclass
module t (/*AUTOARG*/
// Inputs
clk
@ -284,6 +288,7 @@
logic ta, tb, tc;
initial begin
cls obj = new;
int q[5];
int qv[$];
@ -304,6 +309,7 @@
tb = ta;
ta = '0;
end
if (!bit'(obj.randomize() with {x < 100;})) $write("");
end
sub the_sub_1 (.p(t1), .q(t2));