Internal: Refactor AstAssignAlias (#6280) (#6473)

Rename AstAssignAlias to AstAlias and make it derive from AstNode
instead of AstNodeStmt.

Replace AstAlias with AstAssignW in V3LinkDot::linkDotScope, which is
the last place we need to be aware of the alias construct. Using
AstAssignW dowstream enables further optimization while preserving the
same functionality.
This commit is contained in:
Geza Lore
2025-09-22 16:30:26 -04:00
committed by GitHub
parent a647747260
commit 40ca0527db
31 changed files with 120 additions and 128 deletions
-1
View File
@@ -505,7 +505,6 @@ class ActiveVisitor final : public VNVisitor {
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
moveUnderSpecial<AstSenItem::Final>(nodep);
}
void visit(AstAssignAlias* nodep) override { moveUnderSpecial<AstSenItem::Combo>(nodep); }
void visit(AstCoverToggle* nodep) override { moveUnderSpecial<AstSenItem::Combo>(nodep); }
void visit(AstAssignW* nodep) override { moveUnderSpecial<AstSenItem::Combo>(nodep); }
void visit(AstAlways* nodep) override {
-3
View File
@@ -131,9 +131,6 @@ class ActiveTopVisitor final : public VNVisitor {
void visit(AstNodeProcedure* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
void visit(AstAssignAlias* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
void visit(AstAssignW* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
+15
View File
@@ -456,6 +456,21 @@ public:
inline bool hasClocked() const;
inline bool hasCombo() const;
};
class AstAlias final : public AstNode {
// Alias (currently only used internally, not as the SV 'alias' construct).
// All references to the LHS are treated as references to the RHS
// If both sides are wires, there's no LHS vs RHS,
// @astgen op1 := rhsp : AstVarRef
// @astgen op2 := lhsp : AstVarRef
public:
AstAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp)
: ASTGEN_SUPER_Alias(fl) {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstAlias;
};
class AstBind final : public AstNode {
// Parents: MODULE
// Children: CELL
-13
View File
@@ -1070,19 +1070,6 @@ public:
}
bool brokeLhsMustBeLvalue() const override { return true; }
};
class AstAssignAlias final : public AstNodeAssign {
// Like AstAssignW, but a true bidirect interconnection alias
// If both sides are wires, there's no LHS vs RHS,
public:
AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp)
: ASTGEN_SUPER_AssignAlias(fl, reinterpret_cast<AstNodeExpr*>(lhsp),
reinterpret_cast<AstNodeExpr*>(rhsp)) {}
ASTGEN_MEMBERS_AstAssignAlias;
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
V3ERROR_NA_RETURN(nullptr);
}
bool brokeLhsMustBeLvalue() const override { return false; }
};
class AstAssignDly final : public AstNodeAssign {
public:
AstAssignDly(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
+1 -1
View File
@@ -3145,7 +3145,7 @@ class ConstVisitor final : public VNVisitor {
if (nodep->timingControlp()) m_hasJumpDelay = true;
if (m_doNConst && replaceNodeAssign(nodep)) return;
}
void visit(AstAssignAlias* nodep) override {
void visit(AstAlias* nodep) override {
// Don't perform any optimizations, keep the alias around
}
void visit(AstAssignVarScope* nodep) override {
+1 -1
View File
@@ -155,7 +155,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
iterateAndNextConstNull(nodep->rhsp());
puts(";\n");
}
void visit(AstAssignAlias* nodep) override {
void visit(AstAlias* nodep) override {
putbs("alias ");
iterateAndNextConstNull(nodep->lhsp());
putfs(nodep, " = ");
-3
View File
@@ -257,9 +257,6 @@ class GateBuildVisitor final : public VNVisitorConst {
const bool slow = VN_IS(nodep, Initial) || VN_IS(nodep, Final);
iterateLogic(nodep, slow, nodep->isJustOneBodyStmt() ? nullptr : "Multiple Stmts");
}
void visit(AstAssignAlias* nodep) override { //
iterateLogic(nodep);
}
void visit(AstAssignW* nodep) override { //
iterateLogic(nodep);
}
+2 -3
View File
@@ -317,7 +317,7 @@ class InlineRelinkVisitor final : public VNVisitor {
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
iterateChildren(nodep);
}
void visit(AstAssignAlias* nodep) override {
void visit(AstAlias* nodep) override {
// Don't replace port variable in the alias
}
void visit(AstVarRef* nodep) override {
@@ -501,8 +501,7 @@ void connectPort(AstNodeModule* modp, AstVar* nodep, AstNodeExpr* pinExprp) {
modp->addStmtsp(
new AstAssignVarScope{flp, portRef(VAccess::WRITE), pinRef(VAccess::READ)});
} else {
modp->addStmtsp(
new AstAssignAlias{flp, portRef(VAccess::WRITE), pinRef(VAccess::READ)});
modp->addStmtsp(new AstAlias{flp, portRef(VAccess::WRITE), pinRef(VAccess::READ)});
}
// They will become the same variable, so propagate file-line and variable attributes
pinRefp->varp()->fileline()->modifyStateInherit(flp);
+15 -16
View File
@@ -2102,18 +2102,7 @@ class LinkDotParamVisitor final : public VNVisitor {
pinImplicitExprRecurse(nodep->lhsp());
iterateChildren(nodep);
}
void visit(AstAssignAlias* nodep) override { // ParamVisitor::
// tran gates need implicit creation
// As VarRefs don't exist in forPrimary, sanity check
UASSERT_OBJ(!m_statep->forPrimary(), nodep, "Assign aliases unexpected pre-dot");
if (AstVarRef* const forrefp = VN_CAST(nodep->lhsp(), VarRef)) {
pinImplicitExprRecurse(forrefp);
}
if (AstVarRef* const forrefp = VN_CAST(nodep->rhsp(), VarRef)) {
pinImplicitExprRecurse(forrefp);
}
iterateChildren(nodep);
}
void visit(AstImplicit* nodep) override { // ParamVisitor::
// Unsupported gates need implicit creation
pinImplicitExprRecurse(nodep->exprsp());
@@ -2265,15 +2254,25 @@ class LinkDotScopeVisitor final : public VNVisitor {
symp->fallbackp(m_modSymp);
// No recursion, we don't want to pick up variables
}
void visit(AstAssignAlias* nodep) override { // ScopeVisitor::
void visit(AstAlias* nodep) override { // ScopeVisitor::
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
// we'll need to replace it with a VARXREF(aliased_to)
UINFOTREE(9, nodep, "", "alias");
AstVarScope* const fromVscp = VN_AS(nodep->lhsp(), VarRef)->varScopep();
AstVarScope* const toVscp = VN_AS(nodep->rhsp(), VarRef)->varScopep();
AstVarRef* const lhsp = nodep->lhsp();
AstVarRef* const rhsp = nodep->rhsp();
AstVarScope* const fromVscp = lhsp->varScopep();
AstVarScope* const toVscp = rhsp->varScopep();
UASSERT_OBJ(fromVscp && toVscp, nodep, "Bad alias scopes");
fromVscp->user2p(toVscp);
iterateChildren(nodep);
// Replace alias with an assignment. The LHS might still be references from otuside,
// eg throught the VPI, and is traced, so we need the value to propagate.
// TODO: this means external writes to the LHS (e.g.: through the VPI) don't work
AstAssignW* const newp
= new AstAssignW{nodep->fileline(), lhsp->unlinkFrBack(), rhsp->unlinkFrBack()};
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
iterateChildren(newp);
}
void visit(AstAssignVarScope* nodep) override { // ScopeVisitor::
UINFO(5, "ASSIGNVARSCOPE " << nodep);
+1 -1
View File
@@ -98,7 +98,7 @@ class LinkLValueVisitor final : public VNVisitor {
VL_RESTORER(m_setStrengthSpecified);
{
m_setRefLvalue = VAccess::WRITE;
m_setContinuously = VN_IS(nodep, AssignW) || VN_IS(nodep, AssignAlias);
m_setContinuously = VN_IS(nodep, AssignW);
if (const AstAssignW* const assignwp = VN_CAST(nodep, AssignW)) {
if (assignwp->strengthSpecp()) m_setStrengthSpecified = true;
}
+1 -4
View File
@@ -327,10 +327,7 @@ class OrderGraphBuilder final : public VNVisitor {
nodep->v3fatalSrc("AstFinal should not need ordering");
} // LCOV_EXCL_STOP
//--- Logic akin go SystemVerilog continuous assignments
void visit(AstAssignAlias* nodep) override { //
iterateLogic(nodep);
}
//--- SystemVerilog continuous assignments
void visit(AstAssignW* nodep) override { iterateLogic(nodep); }
//--- Verilator concoctions
+2 -2
View File
@@ -208,7 +208,7 @@ class ScopeVisitor final : public VNVisitor {
m_scopep->addBlocksp(clonep);
iterateChildren(clonep); // We iterate under the *clone*
}
void visit(AstAssignAlias* nodep) override {
void visit(AstAlias* nodep) override {
// Add to list of blocks under this scope
UINFO(4, " Move " << nodep);
AstNode* const clonep = nodep->cloneTree(false);
@@ -353,7 +353,7 @@ class ScopeCleanupVisitor final : public VNVisitor {
}
void visit(AstNodeProcedure* nodep) override { movedDeleteOrIterate(nodep); }
void visit(AstAssignAlias* nodep) override { movedDeleteOrIterate(nodep); }
void visit(AstAlias* nodep) override { movedDeleteOrIterate(nodep); }
void visit(AstAssignVarScope* nodep) override { movedDeleteOrIterate(nodep); }
void visit(AstAssignW* nodep) override { movedDeleteOrIterate(nodep); }
void visit(AstCoverToggle* nodep) override { movedDeleteOrIterate(nodep); }
-1
View File
@@ -286,7 +286,6 @@ class SliceVisitor final : public VNVisitor {
void visit(AstNodeAssign* nodep) override {
// Called recursively on newly created assignments
if (nodep->user1SetOnce()) return; // Process once
if (VN_IS(nodep, AssignAlias)) return;
UINFOTREE(9, nodep, "", "Deslice-In");
VL_RESTORER(m_assignError);
VL_RESTORER(m_assignp);
+1
View File
@@ -337,6 +337,7 @@ static void process() {
V3Const::constifyAll(v3Global.rootp());
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
// No more AstAlias after linkDotScope
V3Scope::scopeAll(v3Global.rootp());
V3LinkDot::linkDotScope(v3Global.rootp());