diff --git a/src/V3AstAttr.h b/src/V3AstAttr.h index 8c931d885..bd52bd825 100644 --- a/src/V3AstAttr.h +++ b/src/V3AstAttr.h @@ -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 diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index dfa31a739..1b1724a2d 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -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 { diff --git a/src/V3AstNodeStmt.h b/src/V3AstNodeStmt.h index a891469cb..444a129d7 100644 --- a/src/V3AstNodeStmt.h +++ b/src/V3AstNodeStmt.h @@ -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: diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index e9240b18e..a23eb6c98 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -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(); diff --git a/src/V3Control.cpp b/src/V3Control.cpp index 3043bfdd3..36debc804 100644 --- a/src/V3Control.cpp +++ b/src/V3Control.cpp @@ -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; +using V3ControlLineAttribute = std::bitset; 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) { diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index beacc4f76..9c1b707e4 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -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; diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index b00c3bb25..58e66b8bb 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -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 { diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 428cca95f..ee831dc3a 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -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 { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 8c4a88ba7..f362d8bb7 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -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); } diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index c7d7ecefe..8d86f1508 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -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}; } } diff --git a/src/verilog.y b/src/verilog.y index 8ab960153..c28320bec 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -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: // IEEE: statement_item // | task_subroutine_callNoSemi ';' { $$ = $1; } // - | statementVerilatorPragmas { $$ = $1; } + | statementVerilatorPragmas { $$ = new AstStmtPragma{$1, $1}; } // // // IEEE: disable_statement | yDISABLE yFORK ';' { $$ = new AstDisableFork{$1}; } @@ -3654,7 +3655,7 @@ statement_item: // IEEE: statement_item { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); DEL($3, $6); } ; -statementVerilatorPragmas: +statementVerilatorPragmas: yVL_COVERAGE_BLOCK_OFF { $$ = new AstPragma{$1, VPragmaType::COVERAGE_BLOCK_OFF}; } | yVL_UNROLL_DISABLE