From 10696527011185040b263b1cfd925a5905578fed Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 27 May 2023 12:43:40 -0400 Subject: [PATCH] Fix some AstExprStmt handling issues, towards side effect fixes. --- src/V3Dead.cpp | 8 +++++++- src/V3EmitV.cpp | 15 +++++++++++++++ src/V3Gate.cpp | 10 ++++++++++ src/V3Simulate.h | 3 ++- src/V3Slice.cpp | 3 ++- src/V3SplitAs.cpp | 12 ++++++++++++ 6 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 73b7f69a3..197b6658c 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -78,6 +78,7 @@ private: bool m_sideEffect = false; // Side effects discovered in assign RHS // STATE - for current visit position (use VL_RESTORER) + bool m_inAssign = false; // Currently in an assign AstNodeModule* m_modp = nullptr; // Current module AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars @@ -281,9 +282,13 @@ private: // See if simple assignments to variables may be eliminated because // that variable is never used. // Similar code in V3Life - VL_RESTORER(m_sideEffect); + const bool assignInAssign = m_inAssign; // Might be Assign(..., ExprStmt(Assign), ...) { + VL_RESTORER(m_inAssign); + VL_RESTORER(m_sideEffect); + m_inAssign = true; m_sideEffect = false; + if (assignInAssign) m_sideEffect = true; iterateAndNextNull(nodep->rhsp()); checkAll(nodep); // Has to be direct assignment without any EXTRACTing. @@ -298,6 +303,7 @@ private: } iterateNull(nodep->timingControlp()); } + if (assignInAssign) m_sideEffect = true; // Parent assign shouldn't optimize } //----- diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 67c0a274a..8314ec15c 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -424,6 +424,12 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst { iterateAndNextConstNull(nodep->exprsp()); puts(")"); } + void visit(AstExprStmt* nodep) override { + putfs(nodep, "$_EXPRSTMT(\n"); + iterateAndNextConstNull(nodep->stmtsp()); + putbs(", "); + puts(");\n"); + } void visit(AstCMethodHard* nodep) override { iterateConst(nodep->fromp()); @@ -434,6 +440,15 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst { } puts(")"); } + void visit(AstCMethodCall* nodep) override { + iterateConst(nodep->fromp()); + puts("." + nodep->name() + "("); + for (AstNode* pinp = nodep->argsp(); pinp; pinp = pinp->nextp()) { + if (pinp != nodep->argsp()) puts(", "); + iterateConst(pinp); + } + puts(")"); + } // Operators virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = nullptr, diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 09cc696d8..252a68ce4 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -333,6 +333,7 @@ private: AstActive* m_activep = nullptr; // Current active bool m_activeReducible = true; // Is activation block reducible? bool m_inSenItem = false; // Underneath AstSenItem; any varrefs are clocks + bool m_inExprStmt = false; // Underneath ExprStmt; don't optimize LHS vars bool m_inSlow = false; // Inside a slow structure std::vector m_optimized; // Logic blocks optimized @@ -498,6 +499,10 @@ private: // the weight will increase if (nodep->access().isWriteOrRW()) { new V3GraphEdge{&m_graph, m_logicVertexp, vvertexp, 1}; + if (m_inExprStmt) { + m_logicVertexp->clearReducibleAndDedupable("LHS var in ExprStmt"); + m_logicVertexp->setConsumed("LHS var in ExprStmt"); + } } if (nodep->access().isReadOrRW()) { new V3GraphEdge{&m_graph, vvertexp, m_logicVertexp, 1}; @@ -513,6 +518,11 @@ private: iterateNewStmt(nodep, "User C Function", "User C Function"); } void visit(AstClocking* nodep) override { iterateNewStmt(nodep, nullptr, nullptr); } + void visit(AstExprStmt* nodep) override { + VL_RESTORER(m_inExprStmt); + m_inExprStmt = true; + iterateChildren(nodep); + } void visit(AstSenItem* nodep) override { VL_RESTORER(m_inSenItem); m_inSenItem = true; diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 1feb44580..fa28b67b8 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -886,7 +886,8 @@ private: iterateAndNextConstNull(nodep->stmtsp()); if (!optimizable()) return; iterateAndNextConstNull(nodep->resultp()); - newValue(nodep, fetchValue(nodep->resultp())); + if (!optimizable()) return; + if (!m_checkOnly) newValue(nodep, fetchValue(nodep->resultp())); } void visit(AstJumpBlock* nodep) override { diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 0546bff76..e4aa7407f 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -112,7 +112,8 @@ class SliceVisitor final : public VNVisitor { : offset)); newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTree(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, CMethodHard) || VN_IS(nodep, MemberSel) + || VN_IS(nodep, ExprStmt)) { UINFO(9, " cloneSel(" << elements << "," << offset << ") " << nodep << endl); const int leOffset = !arrayp->rangep()->ascending() ? arrayp->rangep()->elementsConst() - 1 - offset diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index 34b4957fa..24bf6f831 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -48,6 +48,12 @@ private: m_splitVscp = nodep->varScopep(); } } + void visit(AstExprStmt* nodep) override { + // A function call inside the splitting assignment + // We need to presume the whole call is preserved (if the upper statement is) + // This will break if the m_splitVscp is a "ref" argument to the function, + // but little we can do. + } void visit(AstNode* nodep) override { iterateChildren(nodep); } public: @@ -102,6 +108,12 @@ private: m_keepStmt = oldKeep || m_keepStmt; UINFO(9, " upKeep=" << m_keepStmt << " STMT " << nodep << endl); } + void visit(AstExprStmt* nodep) override { + // A function call inside the splitting assignment + // We need to presume the whole call is preserved (if the upper statement is) + // This will break if the m_splitVscp is a "ref" argument to the function, + // but little we can do. + } void visit(AstNode* nodep) override { iterateChildren(nodep); } public: