From 94d9b0f8c35aa86480e30d084b0f78cb0fc43311 Mon Sep 17 00:00:00 2001 From: Yilou Wang Date: Mon, 6 Apr 2026 00:57:37 +0200 Subject: [PATCH] rename AstSExprThroughout->AstSThroughout (AstNodeBiop), AstSExprGotoRep->AstSGotoRep; use emitVerilog() over V3EmitV visitor; collapse VL_RESTORER --- src/V3AssertPre.cpp | 6 ++-- src/V3AssertProp.cpp | 16 +++++------ src/V3AstNodeExpr.h | 67 ++++++++++++++++++++++++-------------------- src/V3EmitV.cpp | 6 ---- src/V3Width.cpp | 21 ++++++-------- src/verilog.y | 6 ++-- 6 files changed, 58 insertions(+), 64 deletions(-) diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index dbb5fadc7..6bed69be2 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -893,7 +893,7 @@ private: return new AstPExpr{flp, beginp, exprp->findBitDType()}; } - void visit(AstSExprGotoRep* nodep) override { + void visit(AstSGotoRep* nodep) override { // Standalone goto rep (not inside implication antecedent) iterateChildren(nodep); FileLine* const flp = nodep->fileline(); @@ -920,8 +920,8 @@ private: if (nodep->sentreep()) return; // Already processed // Handle goto repetition as antecedent before iterateChildren, - // so the standalone AstSExprGotoRep visitor doesn't process it - if (AstSExprGotoRep* const gotop = VN_CAST(nodep->lhsp(), SExprGotoRep)) { + // so the standalone AstSGotoRep visitor doesn't process it + if (AstSGotoRep* const gotop = VN_CAST(nodep->lhsp(), SGotoRep)) { iterateChildren(gotop); iterateAndNextNull(nodep->rhsp()); FileLine* const flp = nodep->fileline(); diff --git a/src/V3AssertProp.cpp b/src/V3AssertProp.cpp index e14d6af7b..98775107a 100644 --- a/src/V3AssertProp.cpp +++ b/src/V3AssertProp.cpp @@ -422,12 +422,12 @@ class AssertPropLowerVisitor final : public VNVisitor { VL_DO_DANGLING(nodep->deleteTree(), nodep); } } - void visit(AstSExprThroughout* nodep) override { + void visit(AstSThroughout* nodep) override { // IEEE 1800-2023 16.9.9: expr throughout seq // Transform by AND-ing cond with every leaf expression in the sequence, // and attaching cond to every delay for per-tick checking in V3AssertPre. - AstNodeExpr* const condp = nodep->condp()->unlinkFrBack(); - AstNodeExpr* const seqp = nodep->seqp()->unlinkFrBack(); + AstNodeExpr* const condp = nodep->lhsp()->unlinkFrBack(); + AstNodeExpr* const seqp = nodep->rhsp()->unlinkFrBack(); if (AstSExpr* const sexprp = VN_CAST(seqp, SExpr)) { // Walk all SExpr nodes: AND cond with leaf expressions, attach to delays sexprp->foreach([&](AstSExpr* sp) { @@ -1021,10 +1021,10 @@ class RangeDelayExpander final : public VNVisitor { } } - void visit(AstSExprThroughout* nodep) override { + void visit(AstSThroughout* nodep) override { // Reject throughout with range-delay sequences before FSM expansion // would silently lose per-tick enforcement (IEEE 1800-2023 16.9.9) - if (AstSExpr* const sexprp = VN_CAST(nodep->seqp(), SExpr)) { + if (AstSExpr* const sexprp = VN_CAST(nodep->rhsp(), SExpr)) { if (containsRangeDelay(sexprp)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: throughout with range delay sequence"); nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}}); @@ -1033,7 +1033,7 @@ class RangeDelayExpander final : public VNVisitor { } } // Reject throughout with nested throughout or goto repetition - if (VN_IS(nodep->seqp(), SExprThroughout) || VN_IS(nodep->seqp(), SExprGotoRep)) { + if (VN_IS(nodep->rhsp(), SThroughout) || VN_IS(nodep->rhsp(), SGotoRep)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: throughout with complex sequence operator"); nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}}); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -1041,9 +1041,9 @@ class RangeDelayExpander final : public VNVisitor { } // Reject throughout with temporal SAnd/SOr (containing SExpr = multi-cycle). // Pure boolean SAnd/SOr are OK -- AssertPropLowerVisitor lowers them to LogAnd/LogOr. - if (VN_IS(nodep->seqp(), SAnd) || VN_IS(nodep->seqp(), SOr)) { + if (VN_IS(nodep->rhsp(), SAnd) || VN_IS(nodep->rhsp(), SOr)) { bool hasSExpr = false; - nodep->seqp()->foreach([&](const AstSExpr*) { hasSExpr = true; }); + nodep->rhsp()->foreach([&](const AstSExpr*) { hasSExpr = true; }); if (hasSExpr) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: throughout with complex sequence operator"); diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 708f85fd6..830b67f6a 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -2165,37 +2165,6 @@ public: bool cleanOut() const override { V3ERROR_NA_RETURN(""); } int instrCount() const override { return widthInstrs(); } }; -class AstSExprGotoRep final : public AstNodeExpr { - // Goto repetition: expr [-> count] - // IEEE 1800-2023 16.9.2 - // @astgen op1 := exprp : AstNodeExpr - // @astgen op2 := countp : AstNodeExpr -public: - explicit AstSExprGotoRep(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* countp) - : ASTGEN_SUPER_SExprGotoRep(fl) { - this->exprp(exprp); - this->countp(countp); - } - ASTGEN_MEMBERS_AstSExprGotoRep; - string emitVerilog() override { V3ERROR_NA_RETURN(""); } - string emitC() override { V3ERROR_NA_RETURN(""); } - bool cleanOut() const override { V3ERROR_NA_RETURN(""); } -}; -class AstSExprThroughout final : public AstNodeExpr { - // expr throughout seq (IEEE 1800-2023 16.9.9) - // @astgen op1 := condp : AstNodeExpr // Boolean LHS - // @astgen op2 := seqp : AstNodeExpr // Sequence RHS -public: - AstSExprThroughout(FileLine* fl, AstNodeExpr* condp, AstNodeExpr* seqp) - : ASTGEN_SUPER_SExprThroughout(fl) { - this->condp(condp); - this->seqp(seqp); - } - ASTGEN_MEMBERS_AstSExprThroughout; - string emitVerilog() override { V3ERROR_NA_RETURN(""); } - string emitC() override { V3ERROR_NA_RETURN(""); } - bool cleanOut() const override { V3ERROR_NA_RETURN(""); } -}; class AstSFormatArg final : public AstNodeExpr { // Information for formatting each argument to AstSFormat, // used to pass to (potentially) runtime decoding of format arguments @@ -2298,6 +2267,22 @@ public: bool cleanOut() const override { V3ERROR_NA_RETURN(true); } bool isSystemFunc() const override { return true; } }; +class AstSGotoRep final : public AstNodeExpr { + // Goto repetition: expr [-> count] + // IEEE 1800-2023 16.9.2 + // @astgen op1 := exprp : AstNodeExpr + // @astgen op2 := countp : AstNodeExpr +public: + explicit AstSGotoRep(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* countp) + : ASTGEN_SUPER_SGotoRep(fl) { + this->exprp(exprp); + this->countp(countp); + } + ASTGEN_MEMBERS_AstSGotoRep; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } +}; class AstSScanF final : public AstNodeExpr { // @astgen op1 := exprsp : List[AstNodeExpr] // VarRefs for results // @astgen op2 := fromp : AstNodeExpr @@ -3704,6 +3689,26 @@ public: bool sizeMattersRhs() const override { return false; } int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } }; +class AstSThroughout final : public AstNodeBiop { + // expr throughout seq (IEEE 1800-2023 16.9.9) +public: + AstSThroughout(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) + : ASTGEN_SUPER_SThroughout(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_AstSThroughout; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLogAnd(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %fthroughout %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; class AstSel final : public AstNodeBiop { // *Resolved* (tyep checked) multiple bit range extraction. Always const width // @astgen alias op1 := fromp diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 05768d448..96724db78 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -1067,12 +1067,6 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst { } iterateConst(nodep->exprp()); } - void visit(AstSExprThroughout* nodep) override { - iterateConst(nodep->condp()); - puts(" throughout "); - iterateConst(nodep->seqp()); - } - // Terminals void visit(AstVarRef* nodep) override { if (nodep->varScopep()) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index b614e15e2..dfe5b655d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1637,7 +1637,7 @@ class WidthVisitor final : public VNVisitor { if (nodep->seedp()) iterateCheckSigned32(nodep, "seed", nodep->seedp(), BOTH); } } - void visit(AstSExprGotoRep* nodep) override { + void visit(AstSGotoRep* nodep) override { assertAtExpr(nodep); if (m_vup->prelim()) { iterateCheckBool(nodep, "exprp", nodep->exprp(), BOTH); @@ -1645,21 +1645,16 @@ class WidthVisitor final : public VNVisitor { nodep->dtypeSetBit(); } } - void visit(AstSExprThroughout* nodep) override { + void visit(AstSThroughout* nodep) override { m_hasSExpr = true; assertAtExpr(nodep); if (m_vup->prelim()) { - // condp is a boolean expression, not a sequence -- clear m_underSExpr - { - VL_RESTORER(m_underSExpr); - m_underSExpr = false; - iterateCheckBool(nodep, "condp", nodep->condp(), BOTH); - } - { - VL_RESTORER(m_underSExpr); - m_underSExpr = true; - iterate(nodep->seqp()); - } + // lhsp is a boolean expression, not a sequence -- clear m_underSExpr temporarily + VL_RESTORER(m_underSExpr); + m_underSExpr = false; + iterateCheckBool(nodep, "lhsp", nodep->lhsp(), BOTH); + m_underSExpr = true; + iterate(nodep->rhsp()); nodep->dtypeSetBit(); } } diff --git a/src/verilog.y b/src/verilog.y index f896ab059..5d77ccf22 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -6811,7 +6811,7 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg { $$ = new AstConsRep{$2, $1, $3}; } // // IEEE: goto_repetition (single count form) | ~p~sexpr/*sexpression_or_dist*/ yP_BRAMINUSGT constExpr ']' - { $$ = new AstSExprGotoRep{$2, $1, $3}; } + { $$ = new AstSGotoRep{$2, $1, $3}; } // // IEEE: goto_repetition (range form -- unsupported) | ~p~sexpr/*sexpression_or_dist*/ yP_BRAMINUSGT constExpr ':' constExpr ']' { $$ = $1; BBUNSUP($2, "Unsupported: [-> range goto repetition"); DEL($3); DEL($5); } @@ -6849,7 +6849,7 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg | yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' { $$ = $3; BBUNSUP($1, "Unsupported: first_match (in sequence expression)"); DEL($5); } | ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr - { $$ = new AstSExprThroughout{$2, $1, $3}; } + { $$ = new AstSThroughout{$2, $1, $3}; } // // Below pexpr's are really sequence_expr, but avoid conflict // // IEEE: sexpr yWITHIN sexpr | ~p~sexpr yWITHIN sexpr @@ -6915,7 +6915,7 @@ boolean_abbrev: // ==IEEE: boolean_abbrev | yP_BRAEQ constExpr ':' constExpr ']' { $$ = $2; BBUNSUP($1, "Unsupported: [= boolean abbrev expression"); DEL($4); } // // IEEE: goto_repetition - // // Goto repetition [->N] handled in sexpr rule (AstSExprGotoRep) + // // Goto repetition [->N] handled in sexpr rule (AstSGotoRep) // // Range form [->M:N] also handled there (unsupported) ;