diff --git a/Changes b/Changes index 28d1e558a..a0e6292c0 100644 --- a/Changes +++ b/Changes @@ -24,6 +24,8 @@ Verilator 5.031 devel * Add `--no-std-package` as subset-alias of `--no-std` (#5607). * Add `lint_off --contents` in configuration files (#5606). * Add `--waiver-multiline` for context-sensitive `--waiver-output` (#5608). +* Add `--fno-inline-funcs` to disable function inlining. +* Add `--fno-slice` to disable array assignment slicing (#5644). * Add error on illegal enum base type (#3010). [Iztok Jeras] * Add error on `wait` with missing `.triggered` (#4457). * Add error when improperly storing to parameter (#5147). [Gökçe Aydos] @@ -31,7 +33,6 @@ Verilator 5.031 devel * Add coverage point hierarchy to coverage reports (#5575) (#5576). [Andrew Nolte] * Add warning on global constraints (#5625). [Ryszard Rozak, Antmicro Ltd.] * Add error on `solve before` or soft constraints of `randc` variable. -* Add `--fno-inline-funcs` to disable function inlining. * Improve concatenation performance (#5598) (#5599) (#5602). [Geza Lore] * Fix dotted reference in delay value (#2410). * Fix `function fork...join_none` regression with unknown type (#4449). diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 5b9aaf3f0..7a88b6180 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -617,6 +617,8 @@ Summary: .. option:: -fno-reorder +.. option:: -fno-slice + .. option:: -fno-split .. option:: -fno-subst diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 01b57af48..422c09a30 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1332,6 +1332,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-fmerge-const-pool", FOnOff, &m_fMergeConstPool); DECL_OPTION("-freloop", FOnOff, &m_fReloop); DECL_OPTION("-freorder", FOnOff, &m_fReorder); + DECL_OPTION("-fslice", FOnOff, &m_fSlice); DECL_OPTION("-fsplit", FOnOff, &m_fSplit); DECL_OPTION("-fsubst", FOnOff, &m_fSubst); DECL_OPTION("-fsubst-const", FOnOff, &m_fSubstConst); diff --git a/src/V3Options.h b/src/V3Options.h index f7a05a022..a1e9b1b0c 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -399,6 +399,7 @@ private: bool m_fMergeConstPool = true; // main switch: -fno-merge-const-pool bool m_fReloop; // main switch: -fno-reloop: reform loops bool m_fReorder; // main switch: -fno-reorder: reorder assignments in blocks + bool m_fSlice = true; // main switch: -fno-slice: array assignment slicing bool m_fSplit; // main switch: -fno-split: always assignment splitting bool m_fSubst; // main switch: -fno-subst: substitute expression temp values bool m_fSubstConst; // main switch: -fno-subst-const: final constant substitution @@ -696,6 +697,7 @@ public: bool fMergeConstPool() const { return m_fMergeConstPool; } bool fReloop() const { return m_fReloop; } bool fReorder() const { return m_fReorder; } + bool fSlice() const { return m_fSlice; } bool fSplit() const { return m_fSplit; } bool fSubst() const { return m_fSubst; } bool fSubstConst() const { return m_fSubstConst; } diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index c63dd6a25..c9f6238a5 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -39,6 +39,8 @@ #include "V3Slice.h" +#include "V3Stats.h" + VL_DEFINE_DEBUG_FUNCTIONS; //************************************************************************* @@ -54,6 +56,9 @@ class SliceVisitor final : public VNVisitor { // AstInitItem::user2() -> Corresponding first elemIdx const VNUser2InUse m_inuser2; + // STATE - across all visitors + VDouble0 m_statAssigns; // Statistic tracking + // STATE - for current visit position (use VL_RESTORER) AstNode* m_assignp = nullptr; // Assignment we are under bool m_assignError = false; // True if the current assign already has an error @@ -218,6 +223,46 @@ class SliceVisitor final : public VNVisitor { return newp; } + bool assignOptimize(AstNodeAssign* nodep) { + // Return true if did optimization + AstNodeDType* const dtp = nodep->lhsp()->dtypep()->skipRefp(); + AstNode* stp = nodep->rhsp(); + const AstUnpackArrayDType* const arrayp = VN_CAST(dtp, UnpackArrayDType); + if (!arrayp) return false; + if (VN_IS(stp, CvtPackedToArray)) return false; + + // Any isSc variables must be expanded regardless of --fno-slice + const bool hasSc + = nodep->exists([&](const AstVarRef* refp) -> bool { return refp->varp()->isSc(); }); + if (!hasSc && !v3Global.opt.fSlice()) { + m_okInitArray = true; // VL_RESTORER in visit(AstNodeAssign) + return false; + } + + UINFO(4, "Slice optimizing " << nodep << endl); + ++m_statAssigns; + + // Left and right could have different ascending/descending range, + // but #elements is common and all variables are realigned to start at zero + // Assign of an ascending range slice to a descending range one must reverse + // the elements + AstNodeAssign* newlistp = nullptr; + const int elements = arrayp->rangep()->elementsConst(); + for (int elemIdx = 0; elemIdx < elements; ++elemIdx) { + AstNodeAssign* const newp + = nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx), + cloneAndSel(nodep->rhsp(), elements, elemIdx)); + if (debug() >= 9) newp->dumpTree("- new: "); + newlistp = AstNode::addNext(newlistp, newp); + } + if (debug() >= 9) nodep->dumpTree("- Deslice-Dn: "); + nodep->replaceWith(newlistp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + // Normal edit iterator will now iterate on all of the expansion assignments + // This will potentially call this function again to resolve next level of slicing + return true; + } + void visit(AstNodeAssign* nodep) override { // Called recursively on newly created assignments if (nodep->user1SetOnce()) return; // Process once @@ -225,34 +270,10 @@ class SliceVisitor final : public VNVisitor { if (debug() >= 9) nodep->dumpTree("- Deslice-In: "); VL_RESTORER(m_assignError); VL_RESTORER(m_assignp); + VL_RESTORER(m_okInitArray); // Set in assignOptimize m_assignError = false; m_assignp = nodep; - AstNodeDType* const dtp = nodep->lhsp()->dtypep()->skipRefp(); - AstNode* stp = nodep->rhsp(); - if (const AstUnpackArrayDType* const arrayp = VN_CAST(dtp, UnpackArrayDType)) { - if (!VN_IS(stp, CvtPackedToArray)) { - // Left and right could have different ascending/descending range, - // but #elements is common and all variables are realigned to start at zero - // Assign of an ascending range slice to a descending range one must reverse - // the elements - AstNodeAssign* newlistp = nullptr; - const int elements = arrayp->rangep()->elementsConst(); - for (int elemIdx = 0; elemIdx < elements; ++elemIdx) { - AstNodeAssign* const newp - = nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx), - cloneAndSel(nodep->rhsp(), elements, elemIdx)); - if (debug() >= 9) newp->dumpTree("- new: "); - newlistp = AstNode::addNext(newlistp, newp); - } - if (debug() >= 9) nodep->dumpTree("- Deslice-Dn: "); - nodep->replaceWith(newlistp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); - // Normal edit iterator will now iterate on all of the expansion assignments - // This will potentially call this function again to resolve next level of - // slicing - return; - } - } + if (assignOptimize(nodep)) return; iterateChildren(nodep); } @@ -337,7 +358,9 @@ class SliceVisitor final : public VNVisitor { public: // CONSTRUCTORS explicit SliceVisitor(AstNetlist* nodep) { iterate(nodep); } - ~SliceVisitor() override = default; + ~SliceVisitor() override { + V3Stats::addStat("Optimizations, Slice array assignments", m_statAssigns); + } }; //###################################################################### diff --git a/test_regress/t/t_opt_slice.py b/test_regress/t/t_opt_slice.py new file mode 100755 index 000000000..b39ad3229 --- /dev/null +++ b/test_regress/t/t_opt_slice.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--sc', '--stats']) + +test.file_grep(test.stats, r'Optimizations, Slice array assignments\s+(\d+)', 3) + +test.passes() diff --git a/test_regress/t/t_opt_slice.v b/test_regress/t/t_opt_slice.v new file mode 100644 index 000000000..92ac3dd37 --- /dev/null +++ b/test_regress/t/t_opt_slice.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Outputs + o1a2, + // Inputs + i1a2 + ); + + input i1a2 [1:0]; + output logic o1a2 [1:0]; + + always o1a2 = i1a2; + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_opt_slice_no.py b/test_regress/t/t_opt_slice_no.py new file mode 100755 index 000000000..3ee92e4e0 --- /dev/null +++ b/test_regress/t/t_opt_slice_no.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') +test.top_filename = 't/t_opt_slice.v' + +test.compile(verilator_flags2=['--sc', '--stats', '-fno-slice']) + +test.file_grep(test.stats, r'Optimizations, Slice array assignments\s+(\d+)', 2) + +test.passes()