Internals: Simplify AstForeach header handling (#7126)
Rename AstSelLoopVars to AstForeachHeader, and make it a non-NodeExpr. Tweak parser to always create an AstForeachHeader, so no need to fix it up later.
This commit is contained in:
parent
e238a2ca5e
commit
da51021b0a
|
|
@ -52,8 +52,8 @@ public:
|
|||
// METHODS
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
// TODO: The only AstNodeExpr without dtype is AstArg. Otherwise this could be final.
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
// Every expression must have a data type after V3Width
|
||||
bool hasDType() const override final VL_MT_SAFE { return true; }
|
||||
virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV
|
||||
// For documentation on emitC format see EmitCFunc::emitOpName
|
||||
virtual string emitC() = 0;
|
||||
|
|
@ -746,7 +746,6 @@ public:
|
|||
this->rhsp(rhsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCastSize;
|
||||
// No hasDType because widthing removes this node before the hasDType check
|
||||
string emitVerilog() override { return "((%r)'(%l))"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
|
||||
|
|
@ -2273,27 +2272,6 @@ public:
|
|||
// Name for __Vscopep variable including children
|
||||
string scopePrettyDpiName() const { return scopePrettyNameFormatter(m_scopeEntr); }
|
||||
};
|
||||
class AstSelLoopVars final : public AstNodeExpr {
|
||||
// Parser only concept "[id, id, id]" for a foreach statement
|
||||
// Unlike normal selects elements is a list
|
||||
// TODO: Should not be an AstNodeExpr, model foreach better
|
||||
// @astgen op1 := fromp : AstNodeExpr
|
||||
// @astgen op2 := elementsp : List[AstNode]
|
||||
public:
|
||||
AstSelLoopVars(FileLine* fl, AstNodeExpr* fromp, AstNode* elementsp)
|
||||
: ASTGEN_SUPER_SelLoopVars(fl) {
|
||||
this->fromp(fromp);
|
||||
addElementsp(elementsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSelLoopVars;
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return false; }
|
||||
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
|
||||
bool hasDType() const override VL_MT_SAFE { return false; }
|
||||
};
|
||||
class AstSetAssoc final : public AstNodeExpr {
|
||||
// Set an assoc array element and return object, '{}
|
||||
// @astgen op1 := lhsp : AstNode
|
||||
|
|
|
|||
|
|
@ -126,13 +126,13 @@ public:
|
|||
}
|
||||
};
|
||||
class AstNodeForeach VL_NOT_FINAL : public AstNodeStmt {
|
||||
// @astgen op1 := arrayp : AstNode
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
// @astgen op1 := headerp : AstForeachHeader
|
||||
// @astgen op2 := bodyp : List[AstNode]
|
||||
public:
|
||||
AstNodeForeach(VNType t, FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
|
||||
AstNodeForeach(VNType t, FileLine* fl, AstForeachHeader* headerp, AstNode* bodyp)
|
||||
: AstNodeStmt(t, fl) {
|
||||
this->arrayp(arrayp);
|
||||
addStmtsp(stmtsp);
|
||||
this->headerp(headerp);
|
||||
addBodyp(bodyp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstNodeForeach;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
|
|
@ -213,6 +213,23 @@ public:
|
|||
bool isDefault() const { return condsp() == nullptr; }
|
||||
};
|
||||
|
||||
class AstForeachHeader final : public AstNode {
|
||||
// Variable reference + index enumeration "ref [id, id, id]" for a foreach statement
|
||||
// @astgen op1 := fromp : AstNodeExpr
|
||||
// @astgen op2 := elementsp : List[AstNode<AstNodeExpr|AstVar|AstEmpty>]
|
||||
// AstNodeExpr/AstEmpty during parsing (only AstParseRef/AstEmpty is well formed)
|
||||
// then AstVar/AstEmpty after LinkDot
|
||||
public:
|
||||
AstForeachHeader(FileLine* fl, AstNodeExpr* fromp, AstNode* elementsp)
|
||||
: ASTGEN_SUPER_ForeachHeader(fl) {
|
||||
this->fromp(fromp);
|
||||
addElementsp(elementsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstForeachHeader;
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return false; }
|
||||
};
|
||||
|
||||
// === AstNodeStmt ===
|
||||
class AstAssertCtl final : public AstNodeStmt {
|
||||
// @astgen op1 := controlTypep : AstNodeExpr
|
||||
|
|
@ -1485,14 +1502,14 @@ public:
|
|||
class AstConstraintForeach final : public AstNodeForeach {
|
||||
// Constraint foreach statement
|
||||
public:
|
||||
AstConstraintForeach(FileLine* fl, AstNodeExpr* exprp, AstNode* bodysp)
|
||||
: ASTGEN_SUPER_ConstraintForeach(fl, exprp, bodysp) {}
|
||||
AstConstraintForeach(FileLine* fl, AstForeachHeader* headerp, AstNode* bodyp)
|
||||
: ASTGEN_SUPER_ConstraintForeach(fl, headerp, bodyp) {}
|
||||
ASTGEN_MEMBERS_AstConstraintForeach;
|
||||
};
|
||||
class AstForeach final : public AstNodeForeach {
|
||||
public:
|
||||
AstForeach(FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
|
||||
: ASTGEN_SUPER_Foreach(fl, arrayp, stmtsp) {}
|
||||
AstForeach(FileLine* fl, AstForeachHeader* headerp, AstNode* stmtsp)
|
||||
: ASTGEN_SUPER_Foreach(fl, headerp, stmtsp) {}
|
||||
ASTGEN_MEMBERS_AstForeach;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -471,9 +471,8 @@ static AstNode* createForeachLoopRanged(AstNodeForeach* nodep, AstNode* bodysp,
|
|||
}
|
||||
AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
|
||||
// UINFOTREE(1, nodep, "", "foreach-old");
|
||||
const AstSelLoopVars* const loopsp = VN_CAST(nodep->arrayp(), SelLoopVars);
|
||||
UASSERT_OBJ(loopsp, nodep, "No loop variables under foreach");
|
||||
AstNodeExpr* const fromp = loopsp->fromp();
|
||||
const AstForeachHeader* const headerp = nodep->headerp();
|
||||
AstNodeExpr* const fromp = headerp->fromp();
|
||||
UASSERT_OBJ(fromp->dtypep(), fromp, "Missing data type");
|
||||
AstNodeDType* fromDtp = fromp->dtypep()->skipRefp();
|
||||
// Split into for loop
|
||||
|
|
@ -486,7 +485,7 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
|
|||
// dyn-arr and associative-arr)
|
||||
AstNodeExpr* subfromp = fromp->cloneTreePure(false);
|
||||
// Major dimension first
|
||||
for (AstNode *argsp = loopsp->elementsp(), *next_argsp; argsp; argsp = next_argsp) {
|
||||
for (AstNode *argsp = headerp->elementsp(), *next_argsp; argsp; argsp = next_argsp) {
|
||||
next_argsp = argsp->nextp();
|
||||
const bool empty = VN_IS(argsp, Empty);
|
||||
AstVar* const varp = VN_CAST(argsp, Var);
|
||||
|
|
@ -578,7 +577,7 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
|
|||
}
|
||||
VL_DO_DANGLING(subfromp->deleteTree(), subfromp);
|
||||
// The parser validates we don't have "foreach (array[,,,])"
|
||||
AstNode* const bodyp = nodep->stmtsp();
|
||||
AstNode* const bodyp = nodep->bodyp();
|
||||
if (!newp) {
|
||||
nodep->v3warn(NOEFFECT, "foreach with no loop variable has no effect");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
|
|
|
|||
|
|
@ -193,6 +193,8 @@ private:
|
|||
UASSERT_OBJ(nodep->dtypep(), nodep,
|
||||
"No dtype on node with hasDType(): " << nodep->prettyTypeName());
|
||||
} else {
|
||||
UASSERT_OBJ(!VN_IS(nodep, NodeExpr), nodep,
|
||||
"All AstNodeExpr must have a dtype post V3WidthCommit");
|
||||
UASSERT_OBJ(!nodep->dtypep(), nodep,
|
||||
"DType on node without hasDType(): " << nodep->prettyTypeName());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class DeadVisitor final : public VNVisitor {
|
|||
bool m_inAssign = false; // Currently in an assign
|
||||
AstNodeDType* m_curDTypep = nullptr; // Current NodeDType
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars
|
||||
AstForeachHeader* m_foreachHeaderp = nullptr; // Current foreach header
|
||||
|
||||
// STATE - Statistic tracking
|
||||
VDouble0 m_statFTasksDeadified;
|
||||
|
|
@ -268,10 +268,10 @@ class DeadVisitor final : public VNVisitor {
|
|||
}
|
||||
checkAll(nodep);
|
||||
}
|
||||
void visit(AstSelLoopVars* nodep) override {
|
||||
// Var under a SelLoopVars means we haven't called V3Width to remove them yet
|
||||
VL_RESTORER(m_selloopvarsp);
|
||||
m_selloopvarsp = nodep;
|
||||
void visit(AstForeachHeader* nodep) override {
|
||||
// Var under a ForeachHeader means we haven't called V3Width to remove them yet
|
||||
VL_RESTORER(m_foreachHeaderp);
|
||||
m_foreachHeaderp = nodep;
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
}
|
||||
|
|
@ -292,7 +292,7 @@ class DeadVisitor final : public VNVisitor {
|
|||
void visit(AstVar* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (m_selloopvarsp) nodep->user1Inc();
|
||||
if (m_foreachHeaderp) nodep->user1Inc();
|
||||
if (mightElimVar(nodep)) {
|
||||
m_varsp.push_back(nodep);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ class HasherVisitor final : public VNVisitorConst {
|
|||
void visit(AstClassExtends* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, []() {});
|
||||
}
|
||||
void visit(AstSelLoopVars* nodep) override {
|
||||
void visit(AstForeachHeader* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, []() {});
|
||||
}
|
||||
void visit(AstDefParam* nodep) override {
|
||||
|
|
|
|||
|
|
@ -1910,29 +1910,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
m_curSymp = m_statep->insertBlock(m_curSymp, "__Vforeach" + cvtToStr(m_modWithNum),
|
||||
nodep, m_classOrPackagep);
|
||||
m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp));
|
||||
// DOT(x, SELLOOPVARS(var, loops)) -> SELLOOPVARS(DOT(x, var), loops)
|
||||
if (AstDot* const dotp = VN_CAST(nodep->arrayp(), Dot)) {
|
||||
AstDot* dotAbovep = dotp;
|
||||
while (AstDot* const dotNextp = VN_CAST(dotAbovep->rhsp(), Dot)) {
|
||||
dotAbovep = dotNextp;
|
||||
}
|
||||
if (AstSelLoopVars* const loopvarsp = VN_CAST(dotAbovep->rhsp(), SelLoopVars)) {
|
||||
AstNodeExpr* const fromp = loopvarsp->fromp()->unlinkFrBack();
|
||||
loopvarsp->unlinkFrBack();
|
||||
dotp->replaceWith(loopvarsp);
|
||||
dotAbovep->rhsp(fromp);
|
||||
loopvarsp->fromp(dotp);
|
||||
}
|
||||
}
|
||||
const auto loopvarsp = VN_CAST(nodep->arrayp(), SelLoopVars);
|
||||
if (!loopvarsp) {
|
||||
AstNode* const warnp = nodep->arrayp() ? nodep->arrayp() : nodep;
|
||||
warnp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported (or syntax error): Foreach on this array's construct");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
for (AstNode *nextp, *argp = loopvarsp->elementsp(); argp; argp = nextp) {
|
||||
for (AstNode *nextp, *argp = nodep->headerp()->elementsp(); argp; argp = nextp) {
|
||||
nextp = argp->nextp();
|
||||
AstVar* argrefp = nullptr;
|
||||
if (AstParseRef* const parserefp = VN_CAST(argp, ParseRef)) {
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
underp = fTaskp->stmtsp();
|
||||
} else if (AstForeach* const foreachp = VN_CAST(nodep, Foreach)) {
|
||||
if (endOfIter) {
|
||||
underp = foreachp->stmtsp();
|
||||
underp = foreachp->bodyp();
|
||||
// Keep a LoopTest **at the front** outside the jump block
|
||||
if (VN_IS(underp, LoopTest)) underp = underp->nextp();
|
||||
} else {
|
||||
|
|
@ -351,7 +351,7 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
void visit(AstNodeForeach* nodep) override {
|
||||
VL_RESTORER(m_loopp);
|
||||
m_loopp = nodep;
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextNull(nodep->bodyp());
|
||||
}
|
||||
void visit(AstReturn* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -594,18 +594,8 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
// 4. DOT(DOT(first, second), ASTSELBIT(third, var0))
|
||||
VL_RESTORER(m_insideLoop);
|
||||
m_insideLoop = true;
|
||||
AstNode* bracketp = nodep->arrayp();
|
||||
while (AstDot* dotp = VN_CAST(bracketp, Dot)) bracketp = dotp->rhsp();
|
||||
if (AstSelBit* const selp = VN_CAST(bracketp, SelBit)) {
|
||||
// Convert to AstSelLoopVars so V3LinkDot knows what's being defined
|
||||
AstNode* const newp
|
||||
= new AstSelLoopVars{selp->fileline(), selp->fromp()->unlinkFrBack(),
|
||||
selp->bitp()->unlinkFrBackWithNext()};
|
||||
selp->replaceWith(newp);
|
||||
VL_DO_DANGLING2(selp->deleteTree(), selp, bracketp);
|
||||
} else if (VN_IS(bracketp, SelLoopVars)) {
|
||||
// Ok
|
||||
} else {
|
||||
AstForeachHeader* const headerp = nodep->headerp();
|
||||
if (!headerp->elementsp()) {
|
||||
nodep->v3error("Foreach missing bracketed loop variable is no-operation"
|
||||
" (IEEE 1800-2023 12.7.3)");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
|
|
|
|||
|
|
@ -1738,10 +1738,10 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
// Convert to plain foreach
|
||||
FileLine* const fl = nodep->fileline();
|
||||
|
||||
if (!nodep->stmtsp()) {
|
||||
if (!nodep->bodyp()) {
|
||||
nodep->unlinkFrBack();
|
||||
} else if (m_wantSingle) {
|
||||
AstNodeExpr* const itemp = editSingle(fl, nodep->stmtsp());
|
||||
AstNodeExpr* const itemp = editSingle(fl, nodep->bodyp());
|
||||
AstCStmt* const cstmtp = new AstCStmt{fl};
|
||||
cstmtp->add("ret += \" \";\n");
|
||||
cstmtp->add("ret += ");
|
||||
|
|
@ -1751,16 +1751,15 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
cexprp->dtypeSetString();
|
||||
cexprp->add("([&]{\nstd::string ret;\n");
|
||||
cexprp->add(new AstBegin{
|
||||
fl, "", new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), cstmtp}, true});
|
||||
fl, "", new AstForeach{fl, nodep->headerp()->unlinkFrBack(), cstmtp}, true});
|
||||
cexprp->add("return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";\n})()");
|
||||
nodep->replaceWith(new AstSFormatF{fl, "%@", false, cexprp});
|
||||
} else {
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
nodep->replaceWith(
|
||||
new AstBegin{fl, "",
|
||||
new AstForeach{fl, nodep->arrayp()->unlinkFrBack(),
|
||||
nodep->stmtsp()->unlinkFrBackWithNext()},
|
||||
true});
|
||||
iterateAndNextNull(nodep->bodyp());
|
||||
nodep->replaceWith(new AstBegin{fl, "",
|
||||
new AstForeach{fl, nodep->headerp()->unlinkFrBack(),
|
||||
nodep->bodyp()->unlinkFrBackWithNext()},
|
||||
true});
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
|
@ -1962,8 +1961,8 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
AstVar* const newVarp
|
||||
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vinside", nodep->findSigned32DType()};
|
||||
AstNodeExpr* const idxRefp = new AstVarRef{nodep->fileline(), newVarp, VAccess::READ};
|
||||
AstSelLoopVars* const arrayp
|
||||
= new AstSelLoopVars{fl, nodep->fromp()->cloneTreePure(false), newVarp};
|
||||
AstForeachHeader* const headerp
|
||||
= new AstForeachHeader{fl, nodep->fromp()->cloneTreePure(false), newVarp};
|
||||
AstNodeExpr* const selp = newSel(nodep->fileline(), nodep->fromp(), idxRefp);
|
||||
selp->user1(randArr);
|
||||
AstNode* const itemp = new AstEq{fl, selp, nodep->pinsp()->unlinkFrBack()};
|
||||
|
|
@ -1977,7 +1976,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
AstCExpr* const cexprp = new AstCExpr{fl};
|
||||
cexprp->dtypeSetString();
|
||||
cexprp->add("([&]{\nstd::string ret;\n");
|
||||
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, arrayp, cstmtp}, true});
|
||||
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, headerp, cstmtp}, true});
|
||||
cexprp->add("return ret.empty() ? \"#b0\" : \"(bvor\" + ret + \")\";\n})()");
|
||||
nodep->replaceWith(new AstSFormatF{fl, "%@", false, cexprp});
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -2022,8 +2021,8 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
|
||||
AstVar* const newVarp
|
||||
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vreduce", nodep->findSigned32DType()};
|
||||
AstSelLoopVars* const arrayp
|
||||
= new AstSelLoopVars{fl, nodep->fromp()->cloneTreePure(false), newVarp};
|
||||
AstForeachHeader* const headerp
|
||||
= new AstForeachHeader{fl, nodep->fromp()->cloneTreePure(false), newVarp};
|
||||
|
||||
// Foreach body: register element as scalar solver var + append name
|
||||
AstCStmt* const cstmtp = new AstCStmt{fl};
|
||||
|
|
@ -2045,7 +2044,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
AstCExpr* const cexprp = new AstCExpr{fl};
|
||||
cexprp->dtypeSetString();
|
||||
cexprp->add("([&]{\nstd::string ret;\n");
|
||||
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, arrayp, cstmtp}, true});
|
||||
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, headerp, cstmtp}, true});
|
||||
|
||||
const char* smtOp = nullptr;
|
||||
std::string identity;
|
||||
|
|
@ -2243,7 +2242,7 @@ class CaptureVisitor final : public VNVisitor {
|
|||
const bool varIsFieldOfCaller = AstClass::isClassExtendedFrom(callerClassp, varClassp);
|
||||
const bool varIsParam = varRefp->varp()->isParam();
|
||||
const bool varIsConstraintIterator
|
||||
= VN_IS(varRefp->varp()->firstAbovep(), SelLoopVars)
|
||||
= VN_IS(varRefp->varp()->firstAbovep(), ForeachHeader)
|
||||
&& VN_IS(varRefp->varp()->firstAbovep()->firstAbovep(), ConstraintForeach);
|
||||
if (refIsXref) return CaptureMode::CAP_VALUE | CaptureMode::CAP_F_XREF;
|
||||
if (varIsConstraintIterator) return CaptureMode::CAP_NO;
|
||||
|
|
@ -2939,12 +2938,12 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
tempDTypep = tempDTypep->virtRefDTypep();
|
||||
}
|
||||
|
||||
AstSelLoopVars* const randLoopVarp
|
||||
= new AstSelLoopVars{fl, exprp->cloneTree(false), randLoopIndxp};
|
||||
AstForeachHeader* const headerp
|
||||
= new AstForeachHeader{fl, exprp->cloneTree(false), randLoopIndxp};
|
||||
AstNodeStmt* const randStmtsp = newRandStmtsp(fl, tempElementp, nullptr, outputVarp);
|
||||
// TODO: we should just not clone in 'newRandStmtsp' if not necessary
|
||||
if (!tempElementp->backp()) VL_DO_DANGLING(pushDeletep(tempElementp), tempElementp);
|
||||
return new AstForeach{fl, randLoopVarp, randStmtsp};
|
||||
return new AstForeach{fl, headerp, randStmtsp};
|
||||
}
|
||||
AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeExpr* exprp, AstVar* randcVarp,
|
||||
AstVar* const outputVarp, int offset = 0,
|
||||
|
|
|
|||
|
|
@ -5658,15 +5658,14 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstNodeForeach* nodep) override {
|
||||
if (nodep->didWidth()) return;
|
||||
nodep->didWidth(true);
|
||||
const AstSelLoopVars* const loopsp = VN_CAST(nodep->arrayp(), SelLoopVars);
|
||||
UASSERT_OBJ(loopsp, nodep, "No loop variables under foreach");
|
||||
const AstForeachHeader* const headerp = nodep->headerp();
|
||||
// UINFOTREE(1, nodep, "", "foreach-old");
|
||||
userIterateAndNext(loopsp->fromp(), WidthVP{SELF, BOTH}.p());
|
||||
AstNodeExpr* const fromp = loopsp->fromp();
|
||||
userIterateAndNext(headerp->fromp(), WidthVP{SELF, BOTH}.p());
|
||||
AstNodeExpr* const fromp = headerp->fromp();
|
||||
UASSERT_OBJ(fromp->dtypep(), fromp, "Missing data type");
|
||||
AstNodeDType* fromDtp = fromp->dtypep()->skipRefp();
|
||||
// Major dimension first
|
||||
for (AstNode *argsp = loopsp->elementsp(), *next_argsp; argsp; argsp = next_argsp) {
|
||||
for (AstNode *argsp = headerp->elementsp(), *next_argsp; argsp; argsp = next_argsp) {
|
||||
next_argsp = argsp->nextp();
|
||||
const bool empty = VN_IS(argsp, Empty);
|
||||
AstVar* const varp = VN_CAST(argsp, Var);
|
||||
|
|
@ -5704,7 +5703,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
fromDtp = fromDtp->subDTypep();
|
||||
}
|
||||
// The parser validates we don't have "foreach (array[,,,])"
|
||||
AstNode* const bodyp = nodep->stmtsp();
|
||||
AstNode* const bodyp = nodep->bodyp();
|
||||
userIterateAndNext(bodyp, nullptr);
|
||||
if (AstForeach* const loopp = VN_CAST(nodep, Foreach)) {
|
||||
VL_DO_DANGLING2(V3Begin::convertToWhile(loopp), loopp, nodep);
|
||||
|
|
|
|||
|
|
@ -2927,48 +2927,48 @@ c_loop_generate_construct<nodep>: // IEEE: loop_generate_construct (for checker
|
|||
;
|
||||
|
||||
genvar_initialization<nodep>: // ==IEEE: genvar_initialization
|
||||
varRefBase '=' expr { $$ = new AstAssign{$2, $1, $3}; }
|
||||
parseRefBase '=' expr { $$ = new AstAssign{$2, $1, $3}; }
|
||||
| yGENVAR genvar_identifierDecl '=' constExpr
|
||||
{ $$ = $2; AstNode::addNext<AstNode, AstNode>($$,
|
||||
new AstAssign{$3, new AstVarRef{$2->fileline(), $2, VAccess::WRITE}, $4}); }
|
||||
;
|
||||
|
||||
genvar_iteration<nodep>: // ==IEEE: genvar_iteration
|
||||
varRefBase '=' expr
|
||||
parseRefBase '=' expr
|
||||
{ $$ = new AstAssign{$2, $1, $3}; }
|
||||
| varRefBase yP_PLUSEQ expr
|
||||
| parseRefBase yP_PLUSEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_MINUSEQ expr
|
||||
| parseRefBase yP_MINUSEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_TIMESEQ expr
|
||||
| parseRefBase yP_TIMESEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstMul{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_DIVEQ expr
|
||||
| parseRefBase yP_DIVEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstDiv{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_MODEQ expr
|
||||
| parseRefBase yP_MODEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstModDiv{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_ANDEQ expr
|
||||
| parseRefBase yP_ANDEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstAnd{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_OREQ expr
|
||||
| parseRefBase yP_OREQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstOr{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_XOREQ expr
|
||||
| parseRefBase yP_XOREQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstXor{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_SLEFTEQ expr
|
||||
| parseRefBase yP_SLEFTEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstShiftL{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_SRIGHTEQ expr
|
||||
| parseRefBase yP_SRIGHTEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTreePure(true), $3}}; }
|
||||
| varRefBase yP_SSRIGHTEQ expr
|
||||
| parseRefBase yP_SSRIGHTEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTreePure(true), $3}}; }
|
||||
// // inc_or_dec_operator
|
||||
| yP_PLUSPLUS varRefBase
|
||||
| yP_PLUSPLUS parseRefBase
|
||||
{ $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTreePure(true),
|
||||
new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; }
|
||||
| yP_MINUSMINUS varRefBase
|
||||
| yP_MINUSMINUS parseRefBase
|
||||
{ $$ = new AstAssign{$1, $2, new AstSub{$1, $2->cloneTreePure(true),
|
||||
new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; }
|
||||
| varRefBase yP_PLUSPLUS
|
||||
| parseRefBase yP_PLUSPLUS
|
||||
{ $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTreePure(true),
|
||||
new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; }
|
||||
| varRefBase yP_MINUSMINUS
|
||||
| parseRefBase yP_MINUSMINUS
|
||||
{ $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTreePure(true),
|
||||
new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; }
|
||||
;
|
||||
|
|
@ -6125,17 +6125,18 @@ idClassSel<nodeExprp>: // Misc Ref to dotted, and/or arrayed, and/or bi
|
|||
| packageClassScope idDottedSel { $$ = new AstDot{$<fl>2, true, $1, $2}; }
|
||||
;
|
||||
|
||||
idClassSelForeach<nodeExprp>:
|
||||
idClassSelForeach<foreachHeaderp>:
|
||||
idDottedForeach { $$ = $1; }
|
||||
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
|
||||
| yTHIS '.' idDottedForeach
|
||||
{ $$ = new AstDot{$2, false, new AstParseRef{$<fl>1, "this"}, $3}; }
|
||||
{ $3->fromp(new AstDot{$2, false, new AstParseRef{$<fl>1, "this"}, $3->fromp()->unlinkFrBack()}); $$ = $3; }
|
||||
| ySUPER '.' idDottedForeach
|
||||
{ $$ = new AstDot{$2, false, new AstParseRef{$<fl>1, "super"}, $3}; }
|
||||
{ $3->fromp(new AstDot{$2, false, new AstParseRef{$<fl>1, "super"}, $3->fromp()->unlinkFrBack()}); $$ = $3; }
|
||||
| yTHIS '.' ySUPER '.' idDottedForeach
|
||||
{ $$ = new AstDot{$4, false, new AstParseRef{$<fl>3, "super"}, $5}; }
|
||||
{ $5->fromp(new AstDot{$4, false, new AstParseRef{$<fl>3, "super"}, $5->fromp()->unlinkFrBack()}); $$ = $5; }
|
||||
// // Expanded: package_scope idForeach
|
||||
| packageClassScope idDottedForeach { $$ = new AstDot{$<fl>2, true, $1, $2}; }
|
||||
| packageClassScope idDottedForeach
|
||||
{ $2->fromp(new AstDot{$<fl>2, true, $1, $2->fromp()->unlinkFrBack()}); $$ = $2; }
|
||||
;
|
||||
|
||||
|
||||
|
|
@ -6160,15 +6161,15 @@ idDottedSel<nodeExprp>:
|
|||
| idDottedSelMore { $$ = $1; }
|
||||
;
|
||||
|
||||
idDottedForeach<nodeExprp>:
|
||||
idDottedForeach<foreachHeaderp>:
|
||||
yD_ROOT '.' idDottedMoreForeach
|
||||
{ $$ = new AstDot{$2, false, new AstParseRef{$<fl>1, "$root"}, $3}; }
|
||||
{ $3->fromp(new AstDot{$2, false, new AstParseRef{$<fl>1, "$root"}, $3->fromp()->unlinkFrBack()}); $$ = $3; }
|
||||
| idDottedMoreForeach { $$ = $1; }
|
||||
;
|
||||
|
||||
idDottedMore<nodeExprp>:
|
||||
varRefBase { $$ = $1; }
|
||||
| idDottedMore '.' varRefBase { $$ = new AstDot{$2, false, $1, $3}; }
|
||||
parseRefBase { $$ = $1; }
|
||||
| idDottedMore '.' parseRefBase { $$ = new AstDot{$2, false, $1, $3}; }
|
||||
;
|
||||
|
||||
idDottedSelMore<nodeExprp>:
|
||||
|
|
@ -6176,9 +6177,10 @@ idDottedSelMore<nodeExprp>:
|
|||
| idDottedSelMore '.' idArrayed { $$ = new AstDot{$2, false, $1, $3}; }
|
||||
;
|
||||
|
||||
idDottedMoreForeach<nodeExprp>:
|
||||
idDottedMoreForeach<foreachHeaderp>:
|
||||
idArrayedForeach { $$ = $1; }
|
||||
| idDottedMoreForeach '.' idArrayedForeach { $$ = new AstDot{$2, false, $1, $3}; }
|
||||
| idDottedSelMore '.' idArrayedForeach
|
||||
{ $3->fromp(new AstDot{$2, false, $1, $3->fromp()->unlinkFrBack()}); $$ = $3; }
|
||||
;
|
||||
|
||||
// Single component of dotted path, maybe [#].
|
||||
|
|
@ -6197,36 +6199,24 @@ idArrayed<nodeExprp>: // IEEE: id + select
|
|||
| idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus{$2, $1, $3, $5}; }
|
||||
;
|
||||
|
||||
idArrayedForeach<nodeExprp>: // IEEE: id + select (under foreach expression)
|
||||
id
|
||||
{ $$ = new AstParseRef{$<fl>1, *$1, nullptr, nullptr}; }
|
||||
// // IEEE: id + part_select_range/constant_part_select_range
|
||||
| idArrayed '[' expr ']' { $$ = new AstSelBit{$2, $1, $3}; } // Or AstArraySel, don't know yet.
|
||||
| idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract{$2, $1, $3, $5}; }
|
||||
// // IEEE: id + indexed_range/constant_indexed_range
|
||||
| idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus{$2, $1, $3, $5}; }
|
||||
| idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus{$2, $1, $3, $5}; }
|
||||
// // IEEE: loop_variables (under foreach expression)
|
||||
// // To avoid conflicts we allow expr as first element, must post-check
|
||||
idArrayedForeach<foreachHeaderp>: // IEEE: id + select (under foreach expression)
|
||||
parseRefBase // Malformed, but accept for better error reporting
|
||||
{ $$ = new AstForeachHeader{$<fl>1, $1, nullptr}; }
|
||||
| idArrayed '[' expr ']'
|
||||
{ $$ = new AstForeachHeader{$2, $1, $3}; }
|
||||
| idArrayed '[' ']'
|
||||
{ $$ = new AstSelLoopVars{$2, $1, new AstEmpty{$3}}; }
|
||||
| idArrayed '[' expr ',' loop_variables ']'
|
||||
{ $$ = new AstSelLoopVars{$2, $1, addNextNull(static_cast<AstNode*>($3), $5)}; }
|
||||
{ $$ = new AstForeachHeader{$2, $1, new AstEmpty{$3}}; }
|
||||
| idArrayed '[' parseRefBase ',' loop_variables ']'
|
||||
{ $$ = new AstForeachHeader{$2, $1, addNextNull(static_cast<AstNode*>($3), $5)}; }
|
||||
| idArrayed '[' ',' loop_variables ']'
|
||||
{ $$ = new AstSelLoopVars{$2, $1, addNextNull(static_cast<AstNode*>(new AstEmpty{$3}), $4)}; }
|
||||
{ $$ = new AstForeachHeader{$2, $1, addNextNull(static_cast<AstNode*>(new AstEmpty{$3}), $4)}; }
|
||||
;
|
||||
|
||||
// VarRef without any dots or vectorizaion
|
||||
varRefBase<parseRefp>:
|
||||
// ParseRef without any dots or vectorizaion
|
||||
parseRefBase<parseRefp>:
|
||||
id { $$ = new AstParseRef{$<fl>1, *$1}; }
|
||||
;
|
||||
|
||||
// ParseRef
|
||||
parseRefBase<nodep>:
|
||||
id
|
||||
{ $$ = new AstParseRef{$<fl>1, *$1, nullptr, nullptr}; }
|
||||
;
|
||||
|
||||
// yaSTRING shouldn't be used directly, instead via an abstraction below
|
||||
str<strp>: // yaSTRING but with \{escapes} need decoded
|
||||
yaSTRING { $$ = PARSEP->newString(GRAMMARP->unquoteString($<fl>1, *$1)); }
|
||||
|
|
|
|||
Loading…
Reference in New Issue