From 761adf1cf01eaa1a2fa927f63719b67ed17e48b4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Sep 2023 22:50:54 -0400 Subject: [PATCH] Internals: Add cloneTreePure to prepare for side effect check. Use cloneTreePure when what is being cloned must be side-effect free. Use cloneTree when safe to contain side effects (e.g. cloning module). --- src/V3Assert.cpp | 16 +++---- src/V3AssertPre.cpp | 16 +++---- src/V3Ast.h | 3 +- src/V3AstNodeExpr.h | 6 +-- src/V3AstNodes.cpp | 4 +- src/V3Case.cpp | 12 ++--- src/V3Const.cpp | 26 +++++------ src/V3Delayed.cpp | 2 +- src/V3DfgDfgToAst.cpp | 4 +- src/V3Expand.cpp | 54 ++++++++++----------- src/V3Force.cpp | 8 ++-- src/V3Gate.cpp | 11 +++-- src/V3LinkInc.cpp | 6 +-- src/V3MergeCond.cpp | 4 +- src/V3Premit.cpp | 12 ++--- src/V3Randomize.cpp | 2 +- src/V3Slice.cpp | 9 ++-- src/V3Split.cpp | 2 + src/V3SplitAs.cpp | 3 ++ src/V3Subst.cpp | 2 +- src/V3Tristate.cpp | 26 +++++------ src/V3Unknown.cpp | 10 ++-- src/V3Width.cpp | 26 ++++++----- src/astgen | 3 ++ src/verilog.y | 106 +++++++++++++++++++++--------------------- 25 files changed, 193 insertions(+), 180 deletions(-) diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 59fd8ede5..e010215d9 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -243,7 +243,7 @@ private: } // Build a bitmask of the true predicates - AstNodeExpr* const predp = ifp->condp()->cloneTree(false); + AstNodeExpr* const predp = ifp->condp()->cloneTreePure(false); if (propp) { propp = new AstConcat{nodep->fileline(), predp, propp}; } else { @@ -312,17 +312,17 @@ private: icondp = VN_AS(icondp->nextp(), NodeExpr)) { AstNodeExpr* onep; if (AstInsideRange* const rcondp = VN_CAST(icondp, InsideRange)) { - onep = rcondp->newAndFromInside(nodep->exprp(), - rcondp->lhsp()->cloneTree(true), - rcondp->rhsp()->cloneTree(true)); + onep = rcondp->newAndFromInside( + nodep->exprp(), rcondp->lhsp()->cloneTreePure(true), + rcondp->rhsp()->cloneTreePure(true)); } else if (nodep->casex() || nodep->casez() || nodep->caseInside()) { onep = AstEqWild::newTyped(itemp->fileline(), - nodep->exprp()->cloneTree(false), - icondp->cloneTree(false)); + nodep->exprp()->cloneTreePure(false), + icondp->cloneTreePure(false)); } else { onep = AstEq::newTyped(icondp->fileline(), - nodep->exprp()->cloneTree(false), - icondp->cloneTree(false)); + nodep->exprp()->cloneTreePure(false), + icondp->cloneTreePure(false)); } if (propp) { propp = new AstConcat{icondp->fileline(), onep, propp}; diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 341204593..766d454d1 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -177,7 +177,7 @@ private: if (nodep->direction() == VDirection::OUTPUT) { AstVarRef* const skewedRefp = new AstVarRef{flp, varp, VAccess::READ}; skewedRefp->user1(true); - AstAssign* const assignp = new AstAssign{flp, exprp->cloneTree(false), skewedRefp}; + AstAssign* const assignp = new AstAssign{flp, exprp->cloneTreePure(false), skewedRefp}; if (skewp->isZero()) { // Drive the var in Re-NBA (IEEE 1800-2017 14.16) m_clockingp->addNextHere(new AstAlwaysReactive{ @@ -208,12 +208,12 @@ private: refp->user1(true); if (skewp->num().is1Step()) { // Assign the sampled expression to the clockvar (IEEE 1800-2017 14.13) - AstSampled* const sampledp = new AstSampled{flp, exprp->cloneTree(false)}; + AstSampled* const sampledp = new AstSampled{flp, exprp->cloneTreePure(false)}; sampledp->dtypeFrom(exprp); m_clockingp->addNextHere(new AstAssignW{flp, refp, sampledp}); } else if (skewp->isZero()) { // #0 means the var has to be sampled in Observed (IEEE 1800-2017 14.13) - AstAssign* const assignp = new AstAssign{flp, refp, exprp->cloneTree(false)}; + AstAssign* const assignp = new AstAssign{flp, refp, exprp->cloneTreePure(false)}; m_clockingp->addNextHere(new AstAlwaysObserved{ flp, new AstSenTree{flp, m_clockingp->sensesp()->cloneTree(false)}, assignp}); } else { @@ -230,7 +230,7 @@ private: AstCMethodHard* const pushp = new AstCMethodHard{ flp, new AstVarRef{flp, queueVarp, VAccess::WRITE}, "push", new AstTime{nodep->fileline(), m_modp->timeunit()}}; - pushp->addPinsp(exprp->cloneTree(false)); + pushp->addPinsp(exprp->cloneTreePure(false)); pushp->dtypeSetVoid(); m_clockingp->addNextHere( new AstAlways{flp, VAlwaysKwd::ALWAYS, nullptr, pushp->makeStmt()}); @@ -372,7 +372,7 @@ private: if (sentreep) sentreep->unlinkFrBack(); AstNodeExpr* const past = new AstPast{fl, exprp, nullptr}; past->dtypeFrom(exprp); - exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTree(false)}}; + exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTreePure(false)}}; exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep, sentreep)); @@ -393,7 +393,7 @@ private: if (sentreep) sentreep->unlinkFrBack(); AstNodeExpr* const past = new AstPast{fl, exprp, nullptr}; past->dtypeFrom(exprp); - exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTree(false)}; + exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTreePure(false)}; exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep, sentreep)); @@ -408,7 +408,7 @@ private: if (sentreep) sentreep->unlinkFrBack(); AstNodeExpr* const past = new AstPast{fl, exprp, nullptr}; past->dtypeFrom(exprp); - exprp = new AstEq{fl, past, exprp->cloneTree(false)}; + exprp = new AstEq{fl, past, exprp->cloneTreePure(false)}; exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep, sentreep)); @@ -442,7 +442,7 @@ private: // Block is the new expression to evaluate AstNodeExpr* blockp = VN_AS(nodep->propp()->unlinkFrBack(), NodeExpr); if (AstNodeExpr* const disablep = nodep->disablep()) { - m_disablep = disablep->cloneTree(false); + m_disablep = disablep->cloneTreePure(false); if (VN_IS(nodep->backp(), Cover)) { blockp = new AstAnd{disablep->fileline(), new AstNot{disablep->fileline(), disablep->unlinkFrBack()}, diff --git a/src/V3Ast.h b/src/V3Ast.h index b925d7f26..5de6ab906 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1998,7 +1998,8 @@ public: AstNode* belowp); // When calling, "this" is second argument // METHODS - Iterate on a tree - AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep + AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep // + AstNode* cloneTreePure(bool cloneNextLink) { return cloneTree(cloneNextLink); } bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable? inline bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p? // Does tree of this == node2p?, not allowing non-isGateOptimizable diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 4c4250b96..e5e44c785 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -4187,10 +4187,10 @@ class AstCountBits final : public AstNodeQuadop { // Number of bits set in vector public: AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), - ctrl1p->cloneTree(false)) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTreePure(false), + ctrl1p->cloneTreePure(false)) {} AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTreePure(false)) {} AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p, AstNodeExpr* ctrl3p) : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index b08d56f9e..9a35b190b 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -279,8 +279,8 @@ AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* lhsp, AstNodeExpr* rhsp) { - AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTree(true), lhsp}; - AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTree(true), rhsp}; + AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTreePure(true), lhsp}; + AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTreePure(true), rhsp}; ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true); bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true); return new AstAnd{fileline(), ap, bp}; diff --git a/src/V3Case.cpp b/src/V3Case.cpp index 8297c1b69..9110d9b93 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -362,10 +362,10 @@ private: // Alternate scheme if we ever do multiple bits at a time: // V3Number nummask (cexprp, cexprp->width(), (1UL<fileline(), cexprp->cloneTree(false), + // AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTreePure(false), // new AstConst(cexprp->fileline(), nummask)); AstNodeExpr* const and1p - = new AstSel{cexprp->fileline(), cexprp->cloneTree(false), msb, 1}; + = new AstSel{cexprp->fileline(), cexprp->cloneTreePure(false), msb, 1}; AstNodeExpr* const eqp = new AstNeq{cexprp->fileline(), new AstConst{cexprp->fileline(), 0}, and1p}; AstIf* const ifp = new AstIf{cexprp->fileline(), eqp, tree1p, tree0p}; @@ -450,7 +450,7 @@ private: V3Number numval{itemp, iconstp->width()}; numval.opBitsOne(iconstp->num()); AstNodeExpr* const and1p - = new AstAnd{itemp->fileline(), cexprp->cloneTree(false), + = new AstAnd{itemp->fileline(), cexprp->cloneTreePure(false), new AstConst{itemp->fileline(), nummask}}; AstNodeExpr* const and2p = new AstAnd{ itemp->fileline(), new AstConst{itemp->fileline(), numval}, @@ -460,7 +460,7 @@ private: condp = AstEq::newTyped(itemp->fileline(), and1p, and2p); } else { // Not a caseX mask, we can build CASEEQ(cexpr icond) - AstNodeExpr* const and1p = cexprp->cloneTree(false); + AstNodeExpr* const and1p = cexprp->cloneTreePure(false); AstNodeExpr* const and2p = icondp; condp = AstEq::newTyped(itemp->fileline(), and1p, and2p); } @@ -502,7 +502,7 @@ private: if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1; if (depth == 1) { // First group or starting new group itemnextp = nullptr; - AstIf* const newp = new AstIf{itemp->fileline(), ifexprp->cloneTree(true)}; + AstIf* const newp = new AstIf{itemp->fileline(), ifexprp->cloneTreePure(true)}; if (groupnextp) { groupnextp->addElsesp(newp); } else { @@ -512,7 +512,7 @@ private: } else { // Continue group, modify if condition to OR in this new condition AstNodeExpr* const condp = groupnextp->condp()->unlinkFrBack(); groupnextp->condp( - new AstOr{ifexprp->fileline(), condp, ifexprp->cloneTree(true)}); + new AstOr{ifexprp->fileline(), condp, ifexprp->cloneTreePure(true)}); } } { // Make the new lower IF and attach in the tree diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 696fceb5e..888bd7780 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1494,13 +1494,13 @@ private: const AstSel* rselp = VN_CAST(rhsp, Sel); // a[i:0] a if (lselp && !rselp && rhsp->sameGateTree(lselp->fromp())) - rselp = new AstSel{rhsp->fileline(), rhsp->cloneTree(false), 0, rhsp->width()}; + rselp = new AstSel{rhsp->fileline(), rhsp->cloneTreePure(false), 0, rhsp->width()}; // a[i:j] {a[j-1:k], b} if (lselp && !rselp && VN_IS(rhsp, Concat)) return ifMergeAdjacent(lhsp, VN_CAST(rhsp, Concat)->lhsp()); // a a[msb:j] if (rselp && !lselp && lhsp->sameGateTree(rselp->fromp())) - lselp = new AstSel{lhsp->fileline(), lhsp->cloneTree(false), 0, lhsp->width()}; + lselp = new AstSel{lhsp->fileline(), lhsp->cloneTreePure(false), 0, lhsp->width()}; // {b, a[j:k]} a[k-1:i] if (rselp && !lselp && VN_IS(lhsp, Concat)) return ifMergeAdjacent(VN_CAST(lhsp, Concat)->rhsp(), rhsp); @@ -1812,10 +1812,10 @@ private: // {llp OP lrp, rlp OP rrp} => {llp, rlp} OP {lrp, rrp}, where OP = AND/OR/XOR AstNodeBiop* const lp = VN_AS(nodep->lhsp(), NodeBiop); AstNodeBiop* const rp = VN_AS(nodep->rhsp(), NodeBiop); - AstNodeExpr* const llp = lp->lhsp()->cloneTree(false); - AstNodeExpr* const lrp = lp->rhsp()->cloneTree(false); - AstNodeExpr* const rlp = rp->lhsp()->cloneTree(false); - AstNodeExpr* const rrp = rp->rhsp()->cloneTree(false); + AstNodeExpr* const llp = lp->lhsp()->cloneTreePure(false); + AstNodeExpr* const lrp = lp->rhsp()->cloneTreePure(false); + AstNodeExpr* const rlp = rp->lhsp()->cloneTreePure(false); + AstNodeExpr* const rrp = rp->rhsp()->cloneTreePure(false); if (concatMergeable(lp, rp, 0)) { AstConcat* const newlp = new AstConcat{rlp->fileline(), llp, rlp}; AstConcat* const newrp = new AstConcat{rrp->fileline(), lrp, rrp}; @@ -1897,9 +1897,9 @@ private: AstNodeExpr* const ap = lhsp->lhsp()->unlinkFrBack(); AstNodeExpr* const bp = lhsp->rhsp()->unlinkFrBack(); AstNodeBiop* const shift1p = nodep; - AstNodeBiop* const shift2p = nodep->cloneTree(true); + AstNodeBiop* const shift2p = nodep->cloneTreePure(true); shift1p->lhsp(ap); - shift1p->rhsp(shiftp->cloneTree(true)); + shift1p->rhsp(shiftp->cloneTreePure(true)); shift2p->lhsp(bp); shift2p->rhsp(shiftp); AstNodeBiop* const newp = lhsp; @@ -2085,7 +2085,7 @@ private: AstNodeExpr* const lc2p = VN_AS(nodep->lhsp(), Concat)->rhsp()->unlinkFrBack(); AstNodeExpr* const conp = VN_AS(nodep->lhsp(), Concat)->unlinkFrBack(); AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack(); - AstNodeExpr* const rhs2p = rhsp->cloneTree(false); + AstNodeExpr* const rhs2p = rhsp->cloneTreePure(false); // Calc widths const int lsb2 = 0; const int msb2 = lsb2 + lc2p->width() - 1; @@ -2430,8 +2430,8 @@ private: nodep->fileline(), new AstLogOr{nodep->fileline(), new AstLogNot{nodep->fileline(), lhsp}, rhsp}, new AstLogOr{nodep->fileline(), - new AstLogNot{nodep->fileline(), rhsp->cloneTree(false)}, - lhsp->cloneTree(false)}}; + new AstLogNot{nodep->fileline(), rhsp->cloneTreePure(false)}, + lhsp->cloneTreePure(false)}}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -2588,8 +2588,8 @@ private: AstNodeExpr* const bilhsp = fromp->lhsp()->unlinkFrBack(); AstNodeExpr* const birhsp = fromp->rhsp()->unlinkFrBack(); // - fromp->lhsp( - new AstSel{nodep->fileline(), bilhsp, lsbp->cloneTree(true), widthp->cloneTree(true)}); + fromp->lhsp(new AstSel{nodep->fileline(), bilhsp, lsbp->cloneTreePure(true), + widthp->cloneTreePure(true)}); fromp->rhsp(new AstSel{nodep->fileline(), birhsp, lsbp, widthp}); fromp->dtypeFrom(nodep); nodep->replaceWith(fromp); diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 226185e89..d8d9185ff 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -353,7 +353,7 @@ private: } if (bitselp) { selectsp = new AstSel{nodep->fileline(), selectsp, bitreadp, - bitselp->widthp()->cloneTree(false)}; + bitselp->widthp()->cloneTreePure(false)}; // Always pure } // Build "IF (changeit) ... UINFO(9, " For " << setvscp << endl); diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index 6667ee35f..089e551b4 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -282,8 +282,8 @@ class DfgToAstVisitor final : DfgVisitor { FileLine* const flp = dfgVarp->driverFileLine(idx); AstConst* const lsbp = new AstConst{flp, dfgVarp->driverLsb(idx)}; AstConst* const widthp = new AstConst{flp, edge.sourcep()->width()}; - AstSel* const rhsp = new AstSel{flp, rRef(), lsbp, widthp->cloneTree(false)}; - AstSel* const lhsp = new AstSel{flp, wRef(), lsbp->cloneTree(false), widthp}; + AstSel* const rhsp = new AstSel{flp, rRef(), lsbp, widthp->cloneTreePure(false)}; + AstSel* const lhsp = new AstSel{flp, wRef(), lsbp->cloneTreePure(false), widthp}; // Add assignment of the value to the selected bits addResultEquation(flp, lhsp, rhsp); }); diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 54cb31068..7af734fe8 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -137,7 +137,7 @@ private: AstNodeExpr* rhsp) { FileLine* const fl = placep->fileline(); return new AstAssign{fl, - new AstWordSel{fl, lhsp->cloneTree(true), + new AstWordSel{fl, lhsp->cloneTreePure(true), new AstConst{fl, static_cast(word)}}, rhsp}; } @@ -166,20 +166,20 @@ private: // Concat may pass negative word numbers, that means it wants a zero FileLine* const fl = nodep->fileline(); if (nodep->isWide() && word >= 0 && word < nodep->widthWords()) { - return new AstWordSel{fl, nodep->cloneTree(true), + return new AstWordSel{fl, nodep->cloneTreePure(true), new AstConst{fl, static_cast(word)}}; } else if (nodep->isQuad() && word == 0) { - AstNodeExpr* const quadfromp = nodep->cloneTree(true); + AstNodeExpr* const quadfromp = nodep->cloneTreePure(true); quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), VSigning::UNSIGNED); return new AstCCast{fl, quadfromp, VL_EDATASIZE}; } else if (nodep->isQuad() && word == 1) { - AstNodeExpr* const quadfromp = nodep->cloneTree(true); + AstNodeExpr* const quadfromp = nodep->cloneTreePure(true); quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), VSigning::UNSIGNED); return new AstCCast{ fl, new AstShiftR{fl, quadfromp, new AstConst{fl, VL_EDATASIZE}, VL_EDATASIZE}, VL_EDATASIZE}; } else if (!nodep->isWide() && !nodep->isQuad() && word == 0) { - return nodep->cloneTree(true); + return nodep->cloneTreePure(true); } else { // Out of bounds return new AstConst{fl, 0}; } @@ -231,7 +231,7 @@ private: if (VN_IS(lsbp, Const)) { wordp = new AstConst{lfl, wordOffset + VL_BITWORD_E(VN_AS(lsbp, Const)->toUInt())}; } else { - wordp = new AstShiftR{lfl, lsbp->cloneTree(true), + wordp = new AstShiftR{lfl, lsbp->cloneTreePure(true), new AstConst{lfl, VL_EDATASIZE_LOG2}, VL_EDATASIZE}; if (wordOffset != 0) { // This is indexing a arraysel, so a 32 bit constant is fine @@ -260,7 +260,7 @@ private: return new AstConst{fl, VL_BITBIT_E(VN_AS(lsbp, Const)->toUInt())}; } else { return new AstAnd{fl, new AstConst{fl, VL_EDATASIZE - 1}, - dropCondBound(lsbp)->cloneTree(true)}; + dropCondBound(lsbp)->cloneTreePure(true)}; } } @@ -351,7 +351,7 @@ private: FileLine* const fl = nodep->fileline(); for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, - new AstCond{fl, rhsp->condp()->cloneTree(true), + new AstCond{fl, rhsp->condp()->cloneTreePure(true), newAstWordSelClone(rhsp->thenp(), w), newAstWordSelClone(rhsp->elsep(), w)}); } @@ -419,7 +419,7 @@ private: FileLine* const lfl = nodep->lsbp()->fileline(); FileLine* const ffl = nodep->fromp()->fileline(); AstNodeExpr* lowwordp - = newWordSel(ffl, nodep->fromp()->cloneTree(true), nodep->lsbp()); + = newWordSel(ffl, nodep->fromp()->cloneTreePure(true), nodep->lsbp()); if (nodep->isQuad() && !lowwordp->isQuad()) { lowwordp = new AstCCast{nfl, lowwordp, nodep}; } @@ -431,9 +431,9 @@ private: const uint32_t midMsbOffset = std::min(nodep->widthConst(), VL_EDATASIZE) - 1; AstNodeExpr* const midMsbp = new AstAdd{lfl, new AstConst{lfl, midMsbOffset}, - nodep->lsbp()->cloneTree(true)}; + nodep->lsbp()->cloneTreePure(true)}; AstNodeExpr* midwordp = // SEL(from,[midwordnum]) - newWordSel(ffl, nodep->fromp()->cloneTree(true), midMsbp, 0); + newWordSel(ffl, nodep->fromp()->cloneTreePure(true), midMsbp, 0); // newWordSel clones the index, so delete it VL_DO_DANGLING(midMsbp->deleteTree(), midMsbp); if (nodep->isQuad() && !midwordp->isQuad()) { @@ -459,9 +459,9 @@ private: if (nodep->widthConst() > VL_EDATASIZE) { const uint32_t hiMsbOffset = nodep->widthConst() - 1; AstNodeExpr* const hiMsbp = new AstAdd{lfl, new AstConst{lfl, hiMsbOffset}, - nodep->lsbp()->cloneTree(true)}; + nodep->lsbp()->cloneTreePure(true)}; AstNodeExpr* hiwordp = // SEL(from,[hiwordnum]) - newWordSel(ffl, nodep->fromp()->cloneTree(true), hiMsbp); + newWordSel(ffl, nodep->fromp()->cloneTreePure(true), hiMsbp); // newWordSel clones the index, so delete it VL_DO_DANGLING(hiMsbp->deleteTree(), hiMsbp); if (nodep->isQuad() && !hiwordp->isQuad()) { @@ -518,13 +518,13 @@ private: for (int w = 0; w < nodep->widthWords(); ++w) { // Grab lowest bits AstNodeExpr* const lowwordp - = newWordSel(rfl, rhsp->fromp()->cloneTree(true), rhsp->lsbp(), w); + = newWordSel(rfl, rhsp->fromp()->cloneTreePure(true), rhsp->lsbp(), w); AstNodeExpr* const lowp = new AstShiftR{rfl, lowwordp, newSelBitBit(rhsp->lsbp()), VL_EDATASIZE}; // Upper bits const V3Number zero{nodep, VL_EDATASIZE, 0}; AstNodeExpr* const midwordp = // SEL(from,[1+wordnum]) - newWordSel(ffl, rhsp->fromp()->cloneTree(true), rhsp->lsbp(), w + 1); + newWordSel(ffl, rhsp->fromp()->cloneTreePure(true), rhsp->lsbp(), w + 1); AstNodeExpr* const midshiftp = new AstSub{lfl, new AstConst{lfl, VL_EDATASIZE}, newSelBitBit(rhsp->lsbp())}; AstNodeExpr* const midmayp = new AstShiftL{rfl, midwordp, midshiftp, VL_EDATASIZE}; @@ -596,9 +596,9 @@ private: } else { UINFO(8, " ASSIGNSEL(const,narrow) " << nodep << endl); if (destp->isQuad() && !rhsp->isQuad()) { rhsp = new AstCCast{nfl, rhsp, nodep}; } - AstNodeExpr* oldvalp = destp->cloneTree(true); + AstNodeExpr* oldvalp = destp->cloneTreePure(true); fixCloneLvalue(oldvalp); - if (!ones) { oldvalp = new AstAnd{lfl, new AstConst{lfl, maskold}, oldvalp}; } + if (!ones) oldvalp = new AstAnd{lfl, new AstConst{lfl, maskold}, oldvalp}; // The bit-select can refer to bits outside the width of nodep // which we aren't allowed to assign to. This is a mask of the @@ -619,7 +619,7 @@ private: UINFO(8, " ASSIGNSEL(varlsb,wide,1bit) " << nodep << endl); AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack(); AstNodeExpr* const destp = lhsp->fromp()->unlinkFrBack(); - AstNodeExpr* oldvalp = newWordSel(lfl, destp->cloneTree(true), lhsp->lsbp()); + AstNodeExpr* oldvalp = newWordSel(lfl, destp->cloneTreePure(true), lhsp->lsbp()); fixCloneLvalue(oldvalp); if (!ones) { oldvalp = new AstAnd{ @@ -633,7 +633,7 @@ private: oldvalp}; } // Restrict the shift amount to 0-31, see bug804. - AstNodeExpr* const shiftp = new AstAnd{nfl, lhsp->lsbp()->cloneTree(true), + AstNodeExpr* const shiftp = new AstAnd{nfl, lhsp->lsbp()->cloneTreePure(true), new AstConst{nfl, VL_EDATASIZE - 1}}; AstNode* const newp = new AstAssign{ nfl, newWordSel(nfl, destp, lhsp->lsbp()), @@ -657,7 +657,7 @@ private: // nodep->dumpTree("- old: "); AstNodeExpr* rhsp = nodep->rhsp()->unlinkFrBack(); AstNodeExpr* const destp = lhsp->fromp()->unlinkFrBack(); - AstNodeExpr* oldvalp = destp->cloneTree(true); + AstNodeExpr* oldvalp = destp->cloneTreePure(true); fixCloneLvalue(oldvalp); V3Number maskwidth{nodep, destp->widthMin()}; @@ -667,13 +667,13 @@ private: if (!ones) { oldvalp = new AstAnd{ lfl, - new AstNot{lfl, - new AstShiftL{lfl, new AstConst{nfl, maskwidth}, - lhsp->lsbp()->cloneTree(true), destp->width()}}, + new AstNot{lfl, new AstShiftL{lfl, new AstConst{nfl, maskwidth}, + lhsp->lsbp()->cloneTreePure(true), + destp->width()}}, oldvalp}; } AstNodeExpr* newp - = new AstShiftL{lfl, rhsp, lhsp->lsbp()->cloneTree(true), destp->width()}; + = new AstShiftL{lfl, rhsp, lhsp->lsbp()->cloneTreePure(true), destp->width()}; // Apply cleaning to the new value being inserted. Mask is // slightly wider than necessary to avoid an AND with all ones // being optimized out. No need to clean if destp is @@ -749,12 +749,12 @@ private: "Replication value isn't a constant. Checked earlier!"); const uint32_t times = constp->toUInt(); if (nodep->isQuad() && !lhsp->isQuad()) { lhsp = new AstCCast{fl, lhsp, nodep}; } - newp = lhsp->cloneTree(true); + newp = lhsp->cloneTreePure(true); for (unsigned repnum = 1; repnum < times; repnum++) { const int rhsshift = repnum * lhswidth; newp = new AstOr{ fl, - new AstShiftL{fl, lhsp->cloneTree(true), + new AstShiftL{fl, lhsp->cloneTreePure(true), new AstConst{fl, static_cast(rhsshift)}, nodep->width()}, newp}; @@ -778,7 +778,7 @@ private: for (int w = 0; w < rhsp->widthWords(); ++w) { AstNodeExpr* newp; if (lhswidth == 1) { - newp = new AstNegate{fl, lhsp->cloneTree(true)}; + newp = new AstNegate{fl, lhsp->cloneTreePure(true)}; // Replicate always unsigned newp->dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); } else { diff --git a/src/V3Force.cpp b/src/V3Force.cpp index 6eab5f0d4..464ea6237 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -188,13 +188,13 @@ class ForceConvertVisitor final : public VNVisitor { V3Number ones{lhsp, isRangedDType(lhsp) ? lhsp->width() : 1}; ones.setAllBits1(); AstAssign* const setEnp - = new AstAssign{flp, lhsp->cloneTree(false), new AstConst{rhsp->fileline(), ones}}; + = new AstAssign{flp, lhsp->cloneTreePure(false), new AstConst{rhsp->fileline(), ones}}; transformWritenVarScopes(setEnp->lhsp(), [this](AstVarScope* vscp) { return getForceComponents(vscp).m_enVscp; }); // Set corresponding value signals to the forced value AstAssign* const setValp - = new AstAssign{flp, lhsp->cloneTree(false), rhsp->cloneTree(false)}; + = new AstAssign{flp, lhsp->cloneTreePure(false), rhsp->cloneTreePure(false)}; transformWritenVarScopes(setValp->lhsp(), [this](AstVarScope* vscp) { return getForceComponents(vscp).m_valVscp; }); @@ -223,7 +223,7 @@ class ForceConvertVisitor final : public VNVisitor { V3Number zero{lhsp, isRangedDType(lhsp) ? lhsp->width() : 1}; zero.setAllBits0(); AstAssign* const resetEnp - = new AstAssign{flp, lhsp->cloneTree(false), new AstConst{lhsp->fileline(), zero}}; + = new AstAssign{flp, lhsp->cloneTreePure(false), new AstConst{lhsp->fileline(), zero}}; transformWritenVarScopes(resetEnp->lhsp(), [this](AstVarScope* vscp) { return getForceComponents(vscp).m_enVscp; }); @@ -235,7 +235,7 @@ class ForceConvertVisitor final : public VNVisitor { FileLine* const fl_nowarn = new FileLine{flp}; fl_nowarn->warnOff(V3ErrorCode::BLKANDNBLK, true); AstAssign* const resetRdp - = new AstAssign{fl_nowarn, lhsp->cloneTree(false), lhsp->unlinkFrBack()}; + = new AstAssign{fl_nowarn, lhsp->cloneTreePure(false), lhsp->unlinkFrBack()}; // Replace write refs on the LHS resetRdp->lhsp()->foreach([this](AstNodeVarRef* refp) { if (refp->access() != VAccess::WRITE) return; diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index e99c1561f..b3811bce8 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -395,7 +395,7 @@ private: void optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* consumerp) { if (debug() >= 5) consumerp->dumpTree("- elimUsePre: "); if (!m_substitutions.tryGet(consumerp)) m_optimized.push_back(consumerp); - m_substitutions(consumerp).emplace(varscp, substp->cloneTree(false)); + m_substitutions(consumerp).emplace(varscp, substp->cloneTreePure(false)); } void commitElimVar(AstNode* logicp) { @@ -1008,7 +1008,7 @@ static void eliminate(AstNode* logicp, // Prevent an infinite loop... substp, "Replacing node with itself; perhaps circular logic?"); // The replacement - AstNode* const newp = substp->cloneTree(false); + AstNode* const newp = substp->cloneTreePure(false); // Which fileline() to use? If replacing with logic, an error/warning is likely to want // to point to the logic IE what we're replacing with. However, a VARREF should point // to the original as it's otherwise confusing to throw warnings that point to a PIN @@ -1219,9 +1219,10 @@ private: preselp->replaceWith(newselp); VL_DO_DANGLING(preselp->deleteTree(), preselp); // create new rhs for pre assignment - AstNode* const newrhsp = new AstConcat{ - m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false), - assignp->rhsp()->cloneTree(false)}; + AstNode* const newrhsp + = new AstConcat{m_assignp->rhsp()->fileline(), + m_assignp->rhsp()->cloneTreePure(false), + assignp->rhsp()->cloneTreePure(false)}; AstNode* const oldrhsp = m_assignp->rhsp(); oldrhsp->replaceWith(newrhsp); VL_DO_DANGLING(oldrhsp->deleteTree(), oldrhsp); diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 3a6eb7eaf..6c0834182 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -283,9 +283,9 @@ private: // Define what operation will we be doing AstNodeExpr* operp; if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) { - operp = new AstSub{fl, readp->cloneTree(true), newconstp}; + operp = new AstSub{fl, readp->cloneTreePure(true), newconstp}; } else { - operp = new AstAdd{fl, readp->cloneTree(true), newconstp}; + operp = new AstAdd{fl, readp->cloneTreePure(true), newconstp}; } if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) { @@ -301,7 +301,7 @@ private: // PostAdd/PostSub operations // Assign the original variable to the temporary one AstAssign* const assignp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, - readp->cloneTree(true)}; + readp->cloneTreePure(true)}; insertNextToStmt(nodep, assignp); // Increment the original variable by one assignp->addNextHere(new AstAssign{fl, writep, operp}); diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 8a237c8ba..52c6a4dfa 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -601,7 +601,7 @@ private: if (condp == rhsp) return resp; if (const AstAnd* const andp = VN_CAST(rhsp, And)) { UASSERT_OBJ(andp->rhsp() == condp, rhsp, "Should not try to fold this"); - return new AstAnd{andp->fileline(), andp->lhsp()->cloneTree(false), resp}; + return new AstAnd{andp->fileline(), andp->lhsp()->cloneTreePure(false), resp}; } } else if (const AstAnd* const andp = VN_CAST(rhsp, And)) { if (andp->lhsp()->sameTree(m_mgCondp)) { @@ -655,7 +655,7 @@ private: // We need a copy of the condition in the new equivalent 'if' statement, // and we also need to keep track of it for comparisons later. - m_mgCondp = m_mgCondp->cloneTree(false); + m_mgCondp = m_mgCondp->cloneTreePure(false); // Create equivalent 'if' statement and insert it before the first node AstIf* const resultp = new AstIf{m_mgCondp->fileline(), m_mgCondp}; m_mgFirstp->addHereThisAsNext(resultp); diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 2d1d3cfdb..9b58dc8b4 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -257,7 +257,7 @@ private: // Create equivalent of VL_SIGNONES_(node_width) constzerop = new AstNegate{ nodep->fileline(), - new AstShiftR{nodep->fileline(), nodep->lhsp()->cloneTree(false), + new AstShiftR{nodep->fileline(), nodep->lhsp()->cloneTreePure(false), new AstConst(nodep->fileline(), m1value), nodep->width()}}; } else { constzerop = new AstConst{nodep->fileline(), AstConst::WidthedValue{}, @@ -269,10 +269,10 @@ private: = new AstConst(nodep->fileline(), AstConst::WidthedValue{}, nodep->rhsp()->widthMin(), m1value); constwidthp->dtypeFrom(nodep->rhsp()); // unsigned - AstCond* const newp = new AstCond{ - nodep->fileline(), - new AstGte{nodep->fileline(), constwidthp, nodep->rhsp()->cloneTree(false)}, - nodep, constzerop}; + AstCond* const newp = new AstCond{nodep->fileline(), + new AstGte{nodep->fileline(), constwidthp, + nodep->rhsp()->cloneTreePure(false)}, + nodep, constzerop}; replaceHandle.relink(newp); } } @@ -370,7 +370,7 @@ private: UINFO(4, "Autoflush " << nodep << endl); nodep->addNextHere( new AstFFlush{nodep->fileline(), - nodep->filep() ? nodep->filep()->cloneTree(true) : nullptr}); + nodep->filep() ? nodep->filep()->cloneTreePure(true) : nullptr}); } } } diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 7d6aad6f9..95c4ce2e9 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -338,7 +338,7 @@ private: = new AstIf{itemp->fileline(), new AstLte{condp->fileline(), new AstVarRef{condp->fileline(), randVarp, VAccess::READ}, - sump->cloneTree(true)}, + sump->cloneTreePure(true)}, stmtsp, nullptr}; ifsp->addElsesp(newifp); ifsp = newifp; diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index e4aa7407f..968a16571 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -98,10 +98,10 @@ class SliceVisitor final : public VNVisitor { nodep->v3error("Array initialization has too few elements, need element " << offset); } - newp = itemp ? itemp->cloneTree(false) : new AstConst{nodep->fileline(), 0}; + newp = itemp ? itemp->cloneTreePure(false) : new AstConst{nodep->fileline(), 0}; } else if (AstNodeCond* const snodep = VN_CAST(nodep, NodeCond)) { UINFO(9, " cloneCond(" << elements << "," << offset << ") " << nodep << endl); - return snodep->cloneType(snodep->condp()->cloneTree(false), + return snodep->cloneType(snodep->condp()->cloneTreePure(false), cloneAndSel(snodep->thenp(), elements, offset), cloneAndSel(snodep->elsep(), elements, offset)); } else if (const AstSliceSel* const snodep = VN_CAST(nodep, SliceSel)) { @@ -110,7 +110,8 @@ class SliceVisitor final : public VNVisitor { + (!snodep->declRange().ascending() ? snodep->declRange().elements() - 1 - offset : offset)); - newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset}; + newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTreePure(false), + leOffset}; } else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel) || VN_IS(nodep, CMethodHard) || VN_IS(nodep, MemberSel) || VN_IS(nodep, ExprStmt)) { @@ -118,7 +119,7 @@ class SliceVisitor final : public VNVisitor { const int leOffset = !arrayp->rangep()->ascending() ? arrayp->rangep()->elementsConst() - 1 - offset : offset; - newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTree(false), + newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTreePure(false), leOffset}; } else { if (!m_assignError) { diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 5ff887b59..1e6b82801 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -767,6 +767,8 @@ protected: // Clone this if into its set of split blocks AstSplitPlaceholder* const if_placeholderp = makePlaceholderp(); AstSplitPlaceholder* const else_placeholderp = makePlaceholderp(); + // We check for condition isPure earlier, but may still clone a + // non-pure to separate from other pure statements. AstIf* const clonep = new AstIf{nodep->fileline(), nodep->condp()->cloneTree(true), if_placeholderp, else_placeholderp}; const AstIf* const origp = VN_CAST(nodep, If); diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index 24bf6f831..f67263dd7 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -142,6 +142,9 @@ private: void splitAlways(AstAlways* nodep, AstVarScope* splitVscp) { if (debug() >= 9) nodep->dumpTree("- in: "); // Duplicate it and link in + // Below cloneTree should perhaps be cloneTreePure, but given + // isolate_assignments is required to hit this code, we presume the user + // knows what they are asking for AstAlways* const newp = nodep->cloneTree(false); newp->user1(true); // So we don't clone it again nodep->addNextHere(newp); diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index 38ebafb6a..79aa116a6 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -292,7 +292,7 @@ private: } void replaceSubstEtc(AstNode* nodep, AstNodeExpr* substp) { if (debug() > 5) nodep->dumpTree("- substw_old: "); - AstNodeExpr* newp = substp->cloneTree(true); + AstNodeExpr* newp = substp->cloneTreePure(true); if (!nodep->isQuad() && newp->isQuad()) { newp = new AstCCast{newp->fileline(), newp, nodep}; } diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 99ff0f328..ded800d65 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -516,14 +516,14 @@ class TristateVisitor final : public TristateBaseVisitor { // Unlink lhsp before copying to save unnecessary copy of lhsp AstNodeExpr* const lhsp = extendp->lhsp()->unlinkFrBack(); - AstExtend* const enExtendp = extendp->cloneTree(false); + AstExtend* const enExtendp = extendp->cloneTreePure(false); extendp->lhsp(lhsp); AstNodeExpr* const enLhsp = getEnExprBasedOnOriginalp(lhsp); enExtendp->lhsp(new AstNot{enLhsp->fileline(), enLhsp}); return new AstNot{enExtendp->fileline(), enExtendp}; } else if (AstSel* const selp = VN_CAST(nodep, Sel)) { AstNodeExpr* const fromp = selp->fromp()->unlinkFrBack(); - AstSel* const enSelp = selp->cloneTree(false); + AstSel* const enSelp = selp->cloneTreePure(false); selp->fromp(fromp); AstNodeExpr* const enFromp = getEnExprBasedOnOriginalp(fromp); enSelp->fromp(enFromp); @@ -572,7 +572,7 @@ class TristateVisitor final : public TristateBaseVisitor { // Would be nicer if we made this a new AST type AstNodeExpr* const newp = new AstShiftL{ selp->fileline(), new AstExtend{selp->fileline(), enp, selp->fromp()->width()}, - selp->lsbp()->cloneTree(false), selp->fromp()->width()}; + selp->lsbp()->cloneTreePure(false), selp->fromp()->width()}; return newp; } @@ -779,7 +779,7 @@ class TristateVisitor final : public TristateBaseVisitor { // If weaker driver should be overwritten by a stronger, replace its value with z exprCurrentStrengthp = new AstAnd{fl, new AstVarRef{fl, varStrengthp, VAccess::READ}, - new AstNot{fl, enp->cloneTree(false)}}; + new AstNot{fl, enp->cloneTreePure(false)}}; } else { exprCurrentStrengthp = new AstVarRef{fl, varStrengthp, VAccess::READ}; } @@ -1086,7 +1086,7 @@ class TristateVisitor final : public TristateBaseVisitor { if (nodep->fromp()->user1p()) { // SEL(VARREF, lsb) AstNodeExpr* const en1p = getEnp(nodep->fromp()); AstNodeExpr* const enp - = new AstSel{nodep->fileline(), en1p, nodep->lsbp()->cloneTree(true), + = new AstSel{nodep->fileline(), en1p, nodep->lsbp()->cloneTreePure(true), nodep->widthp()->cloneTree(true)}; UINFO(9, " newsel " << enp << endl); nodep->user1p(enp); // propagate up SEL(fromp->enable, value) @@ -1113,7 +1113,7 @@ class TristateVisitor final : public TristateBaseVisitor { // Each half of the concat gets a select of the enable expression AstNodeExpr* const enp = VN_AS(nodep->user1p(), NodeExpr); nodep->user1p(nullptr); - nodep->lhsp()->user1p(new AstSel{nodep->fileline(), enp->cloneTree(true), + nodep->lhsp()->user1p(new AstSel{nodep->fileline(), enp->cloneTreePure(true), nodep->rhsp()->width(), nodep->lhsp()->width()}); nodep->rhsp()->user1p( @@ -1208,8 +1208,8 @@ class TristateVisitor final : public TristateBaseVisitor { m_tgraph.didProcess(nodep); AstNodeExpr* const en1p = getEnp(expr1p); AstNodeExpr* const en2p = getEnp(expr2p); - AstNodeExpr* subexpr1p = expr1p->cloneTree(false); - AstNodeExpr* subexpr2p = expr2p->cloneTree(false); + AstNodeExpr* subexpr1p = expr1p->cloneTreePure(false); + AstNodeExpr* subexpr2p = expr2p->cloneTreePure(false); if (isAnd) { subexpr1p = new AstNot{nodep->fileline(), subexpr1p}; subexpr2p = new AstNot{nodep->fileline(), subexpr2p}; @@ -1407,15 +1407,15 @@ class TristateVisitor final : public TristateBaseVisitor { if (nonXp) { // Need to still count '0 or '1 or 'x's if (dropop[0]) { nodep->rhsp()->unlinkFrBack()->deleteTree(); - nodep->rhsp(nonXp->cloneTree(true)); + nodep->rhsp(nonXp->cloneTreePure(true)); } if (dropop[1]) { nodep->thsp()->unlinkFrBack()->deleteTree(); - nodep->thsp(nonXp->cloneTree(true)); + nodep->thsp(nonXp->cloneTreePure(true)); } if (dropop[2]) { nodep->fhsp()->unlinkFrBack()->deleteTree(); - nodep->fhsp(nonXp->cloneTree(true)); + nodep->fhsp(nonXp->cloneTreePure(true)); } newp = new AstAdd{nodep->fileline(), nodep, newp}; } @@ -1582,8 +1582,8 @@ class TristateVisitor final : public TristateBaseVisitor { << nodep->prettyNameQ()); } } else { - AstNodeExpr* const outexprp - = VN_AS(nodep->exprp(), NodeExpr)->cloneTree(false); // Note has lvalue() set + AstNodeExpr* const outexprp = VN_AS(nodep->exprp(), NodeExpr) + ->cloneTreePure(false); // Note has lvalue() set outpinp = new AstPin{nodep->fileline(), nodep->pinNum(), outModVarp->name(), // should be {var}"__out" outexprp}; diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index bf597e4e3..66a6c78c4 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -306,15 +306,15 @@ private: } if (dropop[0]) { nodep->rhsp()->unlinkFrBack()->deleteTree(); - nodep->rhsp(nonXp->cloneTree(true)); + nodep->rhsp(nonXp->cloneTreePure(true)); } if (dropop[1]) { nodep->thsp()->unlinkFrBack()->deleteTree(); - nodep->thsp(nonXp->cloneTree(true)); + nodep->thsp(nonXp->cloneTreePure(true)); } if (dropop[2]) { nodep->fhsp()->unlinkFrBack()->deleteTree(); - nodep->fhsp(nonXp->cloneTree(true)); + nodep->fhsp(nonXp->cloneTreePure(true)); } iterateChildren(nodep); } @@ -398,7 +398,7 @@ private: = new AstGte{nodep->fileline(), new AstConst(nodep->fileline(), AstConst::WidthedValue{}, nodep->lsbp()->width(), maxmsb), - nodep->lsbp()->cloneTree(false)}; + nodep->lsbp()->cloneTreePure(false)}; // See if the condition is constant true (e.g. always in bound due to constant select) // Note below has null backp(); the Edit function knows how to deal with that. condp = V3Const::constifyEdit(condp); @@ -457,7 +457,7 @@ private: = new AstGte{nodep->fileline(), new AstConst(nodep->fileline(), AstConst::WidthedValue{}, nodep->bitp()->width(), declElements - 1), - nodep->bitp()->cloneTree(false)}; + nodep->bitp()->cloneTreePure(false)}; // Note below has null backp(); the Edit function knows how to deal with that. condp = V3Const::constifyEdit(condp); if (condp->isOne()) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index e1c0edff1..c00628e92 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1858,7 +1858,7 @@ private: if (assoc) { AstVar* const varp = enumVarp(enumDtp, VAttrType::ENUM_VALID, true, 0); testp = new AstAssocSel{fl_novalue, newVarRefDollarUnit(varp), - nodep->fromp()->cloneTree(false)}; + nodep->fromp()->cloneTreePure(false)}; } else { const int selwidth = V3Number::log2b(maxval) + 1; // Width to address a bit AstVar* const varp @@ -1867,12 +1867,12 @@ private: fl_nowidth->warnOff(V3ErrorCode::WIDTH, true); testp = new AstCond{ fl, - new AstGt{fl_nowidth, nodep->fromp()->cloneTree(false), + new AstGt{fl_nowidth, nodep->fromp()->cloneTreePure(false), new AstConst{fl_nowidth, AstConst::Unsized64{}, maxval}}, new AstConst{fl, AstConst::BitFalse{}}, - new AstArraySel{ - fl, newVarRefDollarUnit(varp), - new AstSel{fl_novalue, nodep->fromp()->cloneTree(false), 0, selwidth}}}; + new AstArraySel{fl, newVarRefDollarUnit(varp), + new AstSel{fl_novalue, nodep->fromp()->cloneTreePure(false), 0, + selwidth}}}; } newp = new AstCond{ fl, testp, @@ -2550,7 +2550,7 @@ private: "Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13)"); continue; } else { - inewp = AstEqWild::newTyped(itemp->fileline(), nodep->exprp()->cloneTree(true), + inewp = AstEqWild::newTyped(itemp->fileline(), nodep->exprp()->cloneTreePure(true), itemp->unlinkFrBack()); } if (newp) { @@ -3625,7 +3625,7 @@ private: FileLine* const fl = nodep->fileline(); AstNodeExpr* newp = nullptr; for (int i = 0; i < adtypep->elementsConst(); ++i) { - AstNodeExpr* const arrayRef = nodep->fromp()->cloneTree(false); + AstNodeExpr* const arrayRef = nodep->fromp()->cloneTreePure(false); AstNodeExpr* const selector = new AstArraySel{fl, arrayRef, i}; if (!newp) { newp = selector; @@ -4552,8 +4552,9 @@ private: if (adtypep->isString()) { if (varp) { AstConst* const leftp = new AstConst{fl, AstConst::Signed32{}, 0}; - AstLt* const condp = new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ}, - new AstLenN{fl, fromp->cloneTree(false)}}; + AstLt* const condp + = new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ}, + new AstLenN{fl, fromp->cloneTreePure(false)}}; AstAdd* const incp = new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1}, new AstVarRef{fl, varp, VAccess::READ}}; @@ -4576,7 +4577,8 @@ private: } else if (VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType)) { if (varp) { auto* const leftp = new AstConst{fl, AstConst::Signed32{}, 0}; - auto* const sizep = new AstCMethodHard{fl, fromp->cloneTree(false), "size"}; + auto* const sizep + = new AstCMethodHard{fl, fromp->cloneTreePure(false), "size"}; sizep->dtypeSetSigned32(); sizep->didWidth(true); sizep->protect(false); @@ -4601,10 +4603,10 @@ private: fl, VVarType::BLOCKTEMP, varp->name() + "__Vfirst", VFlagBitPacked{}, 1}; first_varp->usedLoopIdx(true); AstNodeExpr* const firstp = new AstMethodCall{ - fl, fromp->cloneTree(false), "first", + fl, fromp->cloneTreePure(false), "first", new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}}; AstNodeExpr* const nextp = new AstMethodCall{ - fl, fromp->cloneTree(false), "next", + fl, fromp->cloneTreePure(false), "next", new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}}; AstNode* const first_clearp = new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE}, diff --git a/src/astgen b/src/astgen index 048077e3d..761313ee5 100755 --- a/src/astgen +++ b/src/astgen @@ -961,6 +961,9 @@ def write_ast_macros(filename): Ast{t}* cloneTree(bool cloneNext) {{ return static_cast(AstNode::cloneTree(cloneNext)); }} + Ast{t}* cloneTreePure(bool cloneNext) {{ + return static_cast(AstNode::cloneTreePure(cloneNext)); + }} Ast{t}* clonep() const {{ return static_cast(AstNode::clonep()); }} Ast{t}* addNext(Ast{t}* nodep) {{ return static_cast(AstNode::addNext(this, nodep)); }} ''', diff --git a/src/verilog.y b/src/verilog.y index 65d92bc6b..794a4cf61 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2885,40 +2885,40 @@ genvar_iteration: // ==IEEE: genvar_iteration varRefBase '=' expr { $$ = new AstAssign{$2, $1, $3}; } | varRefBase yP_PLUSEQ expr - { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_MINUSEQ expr - { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_TIMESEQ expr - { $$ = new AstAssign{$2, $1, new AstMul{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstMul{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_DIVEQ expr - { $$ = new AstAssign{$2, $1, new AstDiv{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstDiv{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_MODEQ expr - { $$ = new AstAssign{$2, $1, new AstModDiv{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstModDiv{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_ANDEQ expr - { $$ = new AstAssign{$2, $1, new AstAnd{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstAnd{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_OREQ expr - { $$ = new AstAssign{$2, $1, new AstOr{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstOr{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_XOREQ expr - { $$ = new AstAssign{$2, $1, new AstXor{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstXor{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_SLEFTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftL{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftL{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_SRIGHTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_SSRIGHTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTreePure(true), $3}}; } // // inc_or_dec_operator // When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeExprStmt? | yP_PLUSPLUS varRefBase - { $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTree(true), + { $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTreePure(true), new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; } | yP_MINUSMINUS varRefBase - { $$ = new AstAssign{$1, $2, new AstSub{$1, $2->cloneTree(true), + { $$ = new AstAssign{$1, $2, new AstSub{$1, $2->cloneTreePure(true), new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; } | varRefBase yP_PLUSPLUS - { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTree(true), + { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTreePure(true), new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; } | varRefBase yP_MINUSMINUS - { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTree(true), + { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTreePure(true), new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; } ; @@ -3681,44 +3681,44 @@ foperator_assignment: // IEEE: operator_assignment (for first part of fexprLvalue '=' delay_or_event_controlE expr { $$ = new AstAssign{$2, $1, $4, $3}; } // | fexprLvalue yP_PLUSEQ expr - { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_MINUSEQ expr - { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_TIMESEQ expr - { $$ = new AstAssign{$2, $1, new AstMul{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstMul{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_DIVEQ expr - { $$ = new AstAssign{$2, $1, new AstDiv{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstDiv{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_MODEQ expr - { $$ = new AstAssign{$2, $1, new AstModDiv{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstModDiv{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_ANDEQ expr - { $$ = new AstAssign{$2, $1, new AstAnd{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstAnd{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_OREQ expr - { $$ = new AstAssign{$2, $1, new AstOr{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstOr{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_XOREQ expr - { $$ = new AstAssign{$2, $1, new AstXor{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstXor{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_SLEFTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftL{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftL{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_SRIGHTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_SSRIGHTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTreePure(true), $3}}; } ; inc_or_dec_expression: // ==IEEE: inc_or_dec_expression // // Need fexprScope instead of variable_lvalue to prevent conflict ~l~exprScope yP_PLUSPLUS { $$ = $1; $$ = new AstPostAdd{$2, new AstConst{$2, AstConst::StringToParse{}, "'b1"}, - $1, $1->cloneTree(true)}; } + $1, $1->cloneTreePure(true)}; } | ~l~exprScope yP_MINUSMINUS { $$ = $1; $$ = new AstPostSub{$2, new AstConst{$2, AstConst::StringToParse{}, "'b1"}, - $1, $1->cloneTree(true)}; } + $1, $1->cloneTreePure(true)}; } // // Need expr instead of variable_lvalue to prevent conflict | yP_PLUSPLUS expr { $$ = $1; $$ = new AstPreAdd{$1, new AstConst{$1, AstConst::StringToParse{}, "'b1"}, - $2, $2->cloneTree(true)}; } + $2, $2->cloneTreePure(true)}; } | yP_MINUSMINUS expr { $$ = $1; $$ = new AstPreSub{$1, new AstConst{$1, AstConst::StringToParse{}, "'b1"}, - $2, $2->cloneTree(true)}; } + $2, $2->cloneTreePure(true)}; } ; finc_or_dec_expression: // ==IEEE: inc_or_dec_expression @@ -4734,40 +4734,40 @@ expr: // IEEE: part of expression/constant_expression/ // // Need exprScope of variable_lvalue to prevent conflict | '(' ~p~exprScope '=' expr ')' { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, $4}, - $2->cloneTree(true)}; } + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_PLUSEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstAdd{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstAdd{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_MINUSEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstSub{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstSub{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_TIMESEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstMul{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstMul{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_DIVEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstDiv{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstDiv{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_MODEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstModDiv{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstModDiv{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_ANDEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstAnd{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstAnd{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_OREQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstOr{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstOr{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_XOREQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstXor{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstXor{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_SLEFTEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftL{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftL{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_SRIGHTEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftR{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftR{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_SSRIGHTEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftRS{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftRS{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } // // // IEEE: expression binary_operator expression | ~l~expr '+' ~r~expr { $$ = new AstAdd{$2, $1, $3}; }