rename AstSExprThroughout->AstSThroughout (AstNodeBiop), AstSExprGotoRep->AstSGotoRep; use emitVerilog() over V3EmitV visitor; collapse VL_RESTORER

This commit is contained in:
Yilou Wang 2026-04-06 00:57:37 +02:00
parent d7aea7f7b3
commit 94d9b0f8c3
6 changed files with 58 additions and 64 deletions

View File

@ -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();

View File

@ -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");

View File

@ -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

View File

@ -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()) {

View File

@ -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();
}
}

View File

@ -6811,7 +6811,7 @@ sexpr<nodeExprp>: // ==IEEE: sequence_expr (The name sexpr is important as reg
{ $$ = new AstConsRep{$<fl>2, $1, $3}; }
// // IEEE: goto_repetition (single count form)
| ~p~sexpr/*sexpression_or_dist*/ yP_BRAMINUSGT constExpr ']'
{ $$ = new AstSExprGotoRep{$<fl>2, $1, $3}; }
{ $$ = new AstSGotoRep{$<fl>2, $1, $3}; }
// // IEEE: goto_repetition (range form -- unsupported)
| ~p~sexpr/*sexpression_or_dist*/ yP_BRAMINUSGT constExpr ':' constExpr ']'
{ $$ = $1; BBUNSUP($<fl>2, "Unsupported: [-> range goto repetition"); DEL($3); DEL($5); }
@ -6849,7 +6849,7 @@ sexpr<nodeExprp>: // ==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<nodeExprp>: // ==IEEE: boolean_abbrev
| yP_BRAEQ constExpr ':' constExpr ']'
{ $$ = $2; BBUNSUP($<fl>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)
;