Internals: Add AstStmtPragma (#6280)

Trivial adaptor node to put AstPragma in AstNodeStmt position, which
will be required in various places. Also fix dumping of AstPragma.
This commit is contained in:
Geza Lore 2025-10-22 16:04:15 +01:00
parent 43373010dc
commit 5ac345e09c
11 changed files with 81 additions and 25 deletions

View File

@ -1439,7 +1439,6 @@ inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) {
class VPragmaType final {
public:
enum en : uint8_t {
ILLEGAL,
COVERAGE_BLOCK_OFF,
HIER_BLOCK,
HIER_PARAMS,
@ -1453,11 +1452,28 @@ public:
UNROLL_FULL,
FULL_CASE,
PARALLEL_CASE,
ENUM_SIZE
_ENUM_SIZE
};
enum en m_e;
VPragmaType()
: m_e{ILLEGAL} {}
const char* ascii() const {
static const char* const names[] = {
"COVERAGE_BLOCK_OFF", //
"HIER_BLOCK", //
"HIER_PARAMS", //
"INLINE_MODULE", //
"NO_INLINE_MODULE", //
"NO_INLINE_TASK", //
"PUBLIC_MODULE", //
"PUBLIC_TASK", //
"TIMEUNIT_SET", //
"UNROLL_DISABLE", //
"UNROLL_FULL", //
"FULL_CASE", //
"PARALLEL_CASE", //
"_ENUM_SIZE" //
};
return names[m_e];
}
// cppcheck-suppress noExplicitConstructor
constexpr VPragmaType(en _e)
: m_e{_e} {}
@ -1470,6 +1486,9 @@ constexpr bool operator==(const VPragmaType& lhs, const VPragmaType& rhs) {
}
constexpr bool operator==(const VPragmaType& lhs, VPragmaType::en rhs) { return lhs.m_e == rhs; }
constexpr bool operator==(VPragmaType::en lhs, const VPragmaType& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VPragmaType& rhs) {
return os << rhs.ascii();
}
// ######################################################################
// Defines what kind of randomization is done on a variable

View File

@ -1388,12 +1388,16 @@ public:
// other processing in verilator.
AstPragma(FileLine* fl, VPragmaType pragType)
: ASTGEN_SUPER_Pragma(fl)
, m_pragType{pragType} {}
AstPragma(FileLine* fl, VPragmaType pragType, const VTimescale& timescale)
, m_pragType{pragType} {
UASSERT_OBJ(pragType != VPragmaType::TIMEUNIT_SET, fl, "Should use other constructor");
}
AstPragma(FileLine* fl, const VTimescale& timescale)
: ASTGEN_SUPER_Pragma(fl)
, m_pragType{pragType}
, m_pragType{VPragmaType::TIMEUNIT_SET}
, m_timescale{timescale} {}
ASTGEN_MEMBERS_AstPragma;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
VPragmaType pragType() const { return m_pragType; } // *=type of the pragma
bool isPredictOptimizable() const override { return false; }
bool sameNode(const AstNode* samep) const override {

View File

@ -1097,6 +1097,16 @@ public:
// cppcheck-suppress uselessOverride
bool isPure() override { return exprp()->isPure(); }
};
class AstStmtPragma final : public AstNodeStmt {
// Pragma in statement position
// @astgen op1 := pragp : AstPragma
public:
AstStmtPragma(FileLine* fl, AstPragma* pragp)
: ASTGEN_SUPER_StmtPragma(fl) {
this->pragp(pragp);
}
ASTGEN_MEMBERS_AstStmtPragma;
};
class AstStop final : public AstNodeStmt {
const bool m_isFatal; // $fatal not $stop
public:

View File

@ -2179,6 +2179,20 @@ string AstPin::prettyOperatorName() const {
+ "port connection " + modVarp()->prettyNameQ())
: "port connection";
}
void AstPragma::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " " << pragType();
if (pragType() == VPragmaType::TIMEUNIT_SET) { //
str << " timescale=" << timescale();
}
}
void AstPragma::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "pragType", pragType().ascii());
if (pragType() == VPragmaType::TIMEUNIT_SET) {
dumpJsonStr(str, "timescale", timescale().ascii());
}
dumpJsonGen(str);
}
void AstPrintTimeScale::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
str << " " << timeunit();

View File

@ -272,10 +272,11 @@ public:
void applyBlock(AstNodeBlock* nodep) {
const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF;
FileLine* const flp = nodep->fileline();
if (!nodep->unnamed()) {
for (const string& i : m_coverageOffBlocks) {
if (VString::wildmatch(nodep->prettyDehashOrigOrName(), i)) {
nodep->addStmtsp(new AstPragma{nodep->fileline(), pragma});
nodep->addStmtsp(new AstStmtPragma{flp, new AstPragma{flp, pragma}});
}
}
}
@ -316,7 +317,7 @@ std::ostream& operator<<(std::ostream& os, const V3ControlIgnoresLine& rhs) {
// Some attributes are attached to entities of the occur on a fileline
// and multiple attributes can be attached to a line
using V3ControlLineAttribute = std::bitset<VPragmaType::ENUM_SIZE>;
using V3ControlLineAttribute = std::bitset<VPragmaType::_ENUM_SIZE>;
class WaiverSetting final {
public:
@ -396,8 +397,9 @@ public:
void applyBlock(AstNodeBlock* nodep) {
// Apply to block at this line
const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF;
if (lineMatch(nodep->fileline()->lineno(), pragma)) {
nodep->addStmtsp(new AstPragma{nodep->fileline(), pragma});
FileLine* const flp = nodep->fileline();
if (lineMatch(flp->lineno(), pragma)) {
nodep->addStmtsp(new AstStmtPragma{flp, new AstPragma{flp, pragma}});
}
}
void applyCase(AstCase* nodep) {

View File

@ -710,8 +710,8 @@ class CoverageVisitor final : public VNVisitor {
UINFO(4, " STOP: " << nodep);
m_state.m_on = false;
}
void visit(AstPragma* nodep) override {
if (nodep->pragType() == VPragmaType::COVERAGE_BLOCK_OFF) {
void visit(AstStmtPragma* nodep) override {
if (nodep->pragp()->pragType() == VPragmaType::COVERAGE_BLOCK_OFF) {
// Skip all NEXT nodes under this block, and skip this if/case branch
UINFO(4, " OFF: h" << m_state.m_handle << " " << nodep);
m_state.m_on = false;

View File

@ -1145,6 +1145,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
void visit(AstTraceInc*) override {}
// NOPs
void visit(AstPragma*) override {}
void visit(AstStmtPragma*) override {}
void visit(AstCell*) override {} // Handled outside the Visit class
// Default
void visit(AstNode* nodep) override {

View File

@ -267,11 +267,11 @@ class LinkJumpVisitor final : public VNVisitor {
}
m_blockStack.pop_back();
}
void visit(AstPragma* nodep) override {
if (nodep->pragType() == VPragmaType::UNROLL_DISABLE) {
void visit(AstStmtPragma* nodep) override {
if (nodep->pragp()->pragType() == VPragmaType::UNROLL_DISABLE) {
m_unrollFull = VOptionBool::OPT_FALSE;
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
} else if (nodep->pragType() == VPragmaType::UNROLL_FULL) {
} else if (nodep->pragp()->pragType() == VPragmaType::UNROLL_FULL) {
m_unrollFull = VOptionBool::OPT_TRUE;
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
} else {

View File

@ -269,6 +269,17 @@ class LinkResolveVisitor final : public VNVisitor {
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstStmtPragma* nodep) override {
if (nodep->pragp()->pragType() == VPragmaType::COVERAGE_BLOCK_OFF) {
// Strip pragma if not needed, may optimize better without
if (!v3Global.opt.coverageLine()) {
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return;
}
}
iterateChildren(nodep);
}
void visit(AstPragma* nodep) override {
if (nodep->pragType() == VPragmaType::HIER_BLOCK) {
UASSERT_OBJ(m_modp, nodep, "HIER_BLOCK not under a module");
@ -291,12 +302,6 @@ class LinkResolveVisitor final : public VNVisitor {
m_modp->modPublic(true); // Need to get to the task...
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (nodep->pragType() == VPragmaType::COVERAGE_BLOCK_OFF) {
if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize
// better without
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
} else {
iterateChildren(nodep);
}

View File

@ -146,7 +146,7 @@ AstPragma* V3ParseImp::createTimescale(FileLine* fl, bool unitSet, double unitVa
return nullptr;
} else {
unit = v3Global.opt.timeComputeUnit(unit);
return new AstPragma{fl, VPragmaType::TIMEUNIT_SET, unit};
return new AstPragma{fl, unit};
}
}

View File

@ -994,6 +994,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
// Blank lines for type insertion
// Blank lines for type insertion
// Blank lines for type insertion
// Blank lines for type insertion
%start source_text
@ -3553,7 +3554,7 @@ statement_item<nodep>: // IEEE: statement_item
//
| task_subroutine_callNoSemi ';' { $$ = $1; }
//
| statementVerilatorPragmas { $$ = $1; }
| statementVerilatorPragmas { $$ = new AstStmtPragma{$<fl>1, $1}; }
//
// // IEEE: disable_statement
| yDISABLE yFORK ';' { $$ = new AstDisableFork{$1}; }
@ -3654,7 +3655,7 @@ statement_item<nodep>: // IEEE: statement_item
{ $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); DEL($3, $6); }
;
statementVerilatorPragmas<nodep>:
statementVerilatorPragmas<pragmap>:
yVL_COVERAGE_BLOCK_OFF
{ $$ = new AstPragma{$1, VPragmaType::COVERAGE_BLOCK_OFF}; }
| yVL_UNROLL_DISABLE