diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 302c74c6c..648779532 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1110,6 +1110,7 @@ public: string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } + bool isPure() const override { return false; } bool same(const AstNode*) const override { return true; } }; class AstFError final : public AstNodeExpr { diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 197b6658c..dd91a542d 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -288,7 +288,6 @@ private: 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. diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index a744b31fa..226185e89 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -551,7 +551,9 @@ private: } if (!lhsp->backp()) VL_DO_DANGLING(pushDeletep(lhsp), lhsp); } else { - iterateChildren(nodep); + iterate(nodep->lhsp()); + m_inDly = false; + iterate(nodep->rhsp()); } } @@ -623,9 +625,9 @@ private: m_inLoop = true; iterateChildren(nodep); } - void visit(AstNodeAssign* nodep) override { + void visit(AstExprStmt* nodep) override { VL_RESTORER(m_inDly); - // Restoring is needed in nested assignments, like a <= (x = y); + // Restoring is needed, because AstExprStmt may contain assignments m_inDly = false; iterateChildren(nodep); } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index db2bf9e40..459618ff7 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -419,7 +419,8 @@ public: && !VN_IS(nodep->rhsp(), AssocSel) // && !VN_IS(nodep->rhsp(), MemberSel) // && !VN_IS(nodep->rhsp(), StructSel) // - && !VN_IS(nodep->rhsp(), ArraySel)) { + && !VN_IS(nodep->rhsp(), ArraySel) // + && !VN_IS(nodep->rhsp(), ExprStmt)) { // Wide functions assign into the array directly, don't need separate assign statement m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef); paren = false; diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 8314ec15c..953a3d937 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -664,6 +664,12 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst { iterateAndNextConstNull(nodep->pinsp()); puts(")"); } + void visit(AstCCall* nodep) override { + puts(nodep->funcp()->name()); + puts("("); + iterateAndNextConstNull(nodep->argsp()); + puts(")"); + } void visit(AstArg* nodep) override { iterateAndNextConstNull(nodep->exprp()); } void visit(AstPrintTimeScale* nodep) override { puts(nodep->verilogKwd()); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 09ff35046..e1a9375a4 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -331,7 +331,6 @@ 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 @@ -497,10 +496,6 @@ 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}; @@ -516,11 +511,6 @@ 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; @@ -905,6 +895,7 @@ class GateDedupeVarVisitor final : public VNVisitor { // (Note, the IF must be the only node under the always, // and the assign must be the only node under the if, other than the ifcond) // Any other ordering or node type, except for an AstComment, makes it not dedupable + // AstExprStmt in the subtree of a node also makes the node not dedupable. private: // STATE GateDedupeHash m_ghash; // Hash used to find dupes of rhs of assign @@ -920,6 +911,7 @@ private: // non-blocking statements, but erring on side of caution here if (!m_assignp) { m_assignp = assignp; + m_dedupable = !assignp->exists([&](AstExprStmt*) { return true; }); } else { m_dedupable = false; } @@ -944,6 +936,7 @@ private: if (m_always && !m_ifCondp && !ifp->elsesp()) { // we're under an always, this is the first IF, and there's no else m_ifCondp = ifp->condp(); + m_dedupable = !m_ifCondp->exists([&](AstExprStmt*) { return true; }); iterateAndNextNull(ifp->thensp()); } else { m_dedupable = false; diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 2a3d09db1..6a134cd89 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -54,11 +54,11 @@ private: const VNUser2InUse m_inuser2; // STATE - across all visitors - V3UniqueNames m_tempNames; // For generating unique temporary variable names VDouble0 m_extractedToConstPool; // Statistic tracking // STATE - for current visit position (use VL_RESTORER) AstCFunc* m_cfuncp = nullptr; // Current block + int m_tmpVarCnt = 0; // Number of temporary variables created inside a function AstNode* m_stmtp = nullptr; // Current statement AstCCall* m_callp = nullptr; // Current AstCCall AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions @@ -138,7 +138,8 @@ private: ++m_extractedToConstPool; } else { // Keep as local temporary. Name based on hash of node for output stability. - varp = new AstVar{fl, VVarType::STMTTEMP, m_tempNames.get(nodep), nodep->dtypep()}; + varp = new AstVar{fl, VVarType::STMTTEMP, "__Vtemp_" + cvtToStr(++m_tmpVarCnt), + nodep->dtypep()}; m_cfuncp->addInitsp(varp); // Put assignment before the referencing statement insertBeforeStmt(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, nodep}); @@ -158,8 +159,9 @@ private: } void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); + VL_RESTORER(m_tmpVarCnt); m_cfuncp = nodep; - m_tempNames.reset(); + m_tmpVarCnt = 0; iterateChildren(nodep); } @@ -391,10 +393,7 @@ private: public: // CONSTRUCTORS - explicit PremitVisitor(AstNetlist* nodep) - : m_tempNames{"__Vtemp"} { - iterate(nodep); - } + explicit PremitVisitor(AstNetlist* nodep) { iterate(nodep); } ~PremitVisitor() override { V3Stats::addStat("Optimizations, Prelim extracted value to ConstPool", m_extractedToConstPool); diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index f71d8913b..284c0df36 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -253,6 +253,7 @@ private: m_mgIndexHi = lindex; UINFO(9, "Start merge i=" << lindex << " o=" << m_mgOffset << nodep << endl); } + void visit(AstExprStmt* nodep) override { iterateChildren(nodep); } //-------------------- void visit(AstVar*) override {} // Accelerate void visit(AstNodeExpr*) override {} // Accelerate diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index 1c80c3736..f52870299 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -236,6 +236,7 @@ TimingKit prepareTiming(AstNetlist* const netlistp) { m_writtenBySuspendable.push_back(nodep->varScopep()); } } + void visit(AstExprStmt* nodep) override { iterateChildren(nodep); } //-------------------- void visit(AstNodeExpr*) override {} // Accelerate @@ -405,6 +406,7 @@ void transformForks(AstNetlist* const netlistp) { if (nodep->funcp()->needProcess()) m_beginNeedProcess = true; iterateChildrenConst(nodep); } + void visit(AstExprStmt* nodep) override { iterateChildren(nodep); } //-------------------- void visit(AstNodeExpr*) override {} // Accelerate diff --git a/src/V3Task.cpp b/src/V3Task.cpp index fd4cb172b..e1435a43b 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1420,18 +1420,27 @@ private: beginp = createInlinedFTask(nodep, namePrefix, outvscp); } // Replace the ref - AstNode* const visitp = insertBeforeStmt(nodep, beginp); + AstNode* visitp = nullptr; if (VN_IS(nodep, New)) { + visitp = insertBeforeStmt(nodep, beginp); UASSERT_OBJ(cnewp, nodep, "didn't create cnew for new"); nodep->replaceWith(cnewp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else if (VN_IS(nodep->backp(), NodeAssign)) { + UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function"); + visitp = insertBeforeStmt(nodep, beginp); + AstVarRef* const outrefp = new AstVarRef{nodep->fileline(), outvscp, VAccess::READ}; + nodep->replaceWith(outrefp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (!VN_IS(nodep->backp(), StmtExpr)) { UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function"); AstVarRef* const outrefp = new AstVarRef{nodep->fileline(), outvscp, VAccess::READ}; - nodep->replaceWith(outrefp); + beginp = new AstExprStmt{nodep->fileline(), beginp, outrefp}; + nodep->replaceWith(beginp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { + visitp = insertBeforeStmt(nodep, beginp); if (nodep->taskp()->isFunction()) { nodep->v3warn( IGNOREDRETURN, diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index b886b2ed9..5b8651d20 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -550,7 +550,10 @@ private: ss << '"'; V3EmitV::verilogForTree(sensesp, ss); ss << '"'; - auto* const commentp = new AstCExpr{sensesp->fileline(), ss.str(), 0}; + // possibly a multiline string + std::string comment = ss.str(); + std::replace(comment.begin(), comment.end(), '\n', ' '); + AstCExpr* const commentp = new AstCExpr{sensesp->fileline(), comment, 0}; commentp->dtypeSetString(); sensesp->user2p(commentp); return commentp; diff --git a/test_regress/t/t_dpi_shortcircuit.out b/test_regress/t/t_dpi_shortcircuit.out index 53f6dc0e8..2cc554bcf 100644 --- a/test_regress/t/t_dpi_shortcircuit.out +++ b/test_regress/t/t_dpi_shortcircuit.out @@ -10,8 +10,6 @@ %Error: Line 136: Bad result, got=0 expect=1 %Error: Line 148: Bad result, got=1 expect=0 %Error: Line 152: Bad result, got=1 expect=0 -%Error: Line 166: Bad result, got=1 expect=0 -%Error: Line 170: Bad result, got=1 expect=0 %Error: Line 179: Bad result, got=0 expect=1 %Error: Line 219: Bad result, got=64 expect=32 %Error: Line 220: Bad result, got=64 expect=16 diff --git a/test_regress/t/t_unopt_combo_isolate.pl b/test_regress/t/t_unopt_combo_isolate.pl index c875fbf2b..a6196c6d9 100755 --- a/test_regress/t/t_unopt_combo_isolate.pl +++ b/test_regress/t/t_unopt_combo_isolate.pl @@ -18,7 +18,7 @@ compile( ); if ($Self->{vlt_all}) { - file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+5/i); + file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+3/i); file_grep("$out_filename", qr/\/i); file_grep("$out_filename", qr/\/i); file_grep("$out_filename", qr/\/i); diff --git a/test_regress/t/t_unopt_combo_isolate_vlt.pl b/test_regress/t/t_unopt_combo_isolate_vlt.pl index dedfa5e76..0d44d64e2 100755 --- a/test_regress/t/t_unopt_combo_isolate_vlt.pl +++ b/test_regress/t/t_unopt_combo_isolate_vlt.pl @@ -18,7 +18,7 @@ compile( ); if ($Self->{vlt_all}) { - file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+5/i); + file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+3/i); file_grep("$out_filename", qr/\/i); file_grep("$out_filename", qr/\/i); file_grep("$out_filename", qr/\/i); diff --git a/test_regress/t/t_xml_debugcheck.out b/test_regress/t/t_xml_debugcheck.out index 9e7447c4c..b50189df9 100644 --- a/test_regress/t/t_xml_debugcheck.out +++ b/test_regress/t/t_xml_debugcheck.out @@ -61,7 +61,7 @@ - + @@ -510,11 +510,11 @@ - + - + @@ -700,9 +700,9 @@ - - - + + + @@ -762,11 +762,11 @@ - + - + @@ -1012,11 +1012,11 @@ - + - + @@ -1262,11 +1262,11 @@ - + - +