Add --func-recursion-depth CLI option

CONST_FUNC_RECURSION_MAX was hardcoded to 1000 in V3Simulate.h.
When a recursive constant function exceeds this depth, Verilator
silently gives up on constant folding with no way to increase the
limit. Add --func-recursion-depth <N> (default 1000) so users can
raise it without patching the source.
This commit is contained in:
jalcim 2026-03-02 19:53:50 +01:00
parent 446bec3d1a
commit 0494d0f8bf
7 changed files with 56 additions and 3 deletions

View File

@ -390,6 +390,7 @@ detailed descriptions of these arguments.
-f <file> Parse arguments from a file
-FI <file> Force include of a file
--flatten Force inlining of all modules, tasks and functions
--func-recursion-depth <value> Maximum recursive constant function depth
--future0 <option> Ignore an option for compatibility
--future1 <option> Ignore an option with argument for compatibility
-fno-<optimization> Disable internal optimization stage

View File

@ -610,6 +610,14 @@ Summary:
Flattening large designs may require significant CPU time, memory and
storage.
.. option:: --func-recursion-depth <value>
Specifies the maximum depth of recursive constant function evaluation.
When a recursive function exceeds this depth during constant folding,
Verilator gives up and treats the expression as non-constant.
Defaults to 1000.
.. option:: -fno-acyc-simp
.. option:: -fno-assemble

View File

@ -1592,6 +1592,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
fl->v3error("Unknown --make system specified: '" << valp << "'");
}
});
DECL_OPTION("-func-recursion-depth", Set, &m_funcRecursion);
DECL_OPTION("-max-num-width", Set, &m_maxNumWidth);
DECL_OPTION("-mod-prefix", CbVal, [this, fl](const char* valp) {
validateIdentifier(fl, valp, "--mod-prefix");

View File

@ -328,6 +328,7 @@ private:
int m_localizeMaxSize = 1024; // main switch: --localize-max-size
VOptionBool m_makeDepend; // main switch: -MMD
int m_maxNumWidth = 65536; // main switch: --max-num-width
int m_funcRecursion = 1000; // main switch: --func-recursion-depth
int m_moduleRecursion = 100; // main switch: --module-recursion-depth
int m_outputGroups = -1; // main switch: --output-groups
int m_outputSplit = 20000; // main switch: --output-split
@ -606,6 +607,7 @@ public:
bool jsonIds() const { return m_jsonIds; }
VOptionBool makeDepend() const { return m_makeDepend; }
int maxNumWidth() const { return m_maxNumWidth; }
int funcRecursionDepth() const { return m_funcRecursion; }
int moduleRecursionDepth() const { return m_moduleRecursion; }
int outputSplit() const { return m_outputSplit; }
int outputSplitCFuncs() const { return m_outputSplitCFuncs; }

View File

@ -75,7 +75,6 @@ class SimulateVisitor VL_NOT_FINAL : public VNVisitorConst {
private:
// CONSTANTS
static constexpr int CONST_FUNC_RECURSION_MAX = 1000;
static constexpr int CALL_STACK_MAX = 100;
// NODE STATE
@ -1150,9 +1149,9 @@ private:
UASSERT_OBJ(funcp, nodep, "Not linked");
if (funcp->recursive()) {
if (m_recurseCount >= CONST_FUNC_RECURSION_MAX) {
if (m_recurseCount >= v3Global.opt.funcRecursionDepth()) {
clearOptimizable(funcp, "Constant function recursed more than "s
+ std::to_string(CONST_FUNC_RECURSION_MAX) + " times");
+ std::to_string(v3Global.opt.funcRecursionDepth()) + " times");
return;
}
++m_recurseCount;

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2026 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=['--func-recursion-depth 2000'])
test.execute()
test.passes()

View File

@ -0,0 +1,24 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2026 by jalcim.
// SPDX-License-Identifier: CC0-1.0
module t;
// Recursive function that needs depth > 1000 to constant-fold
function automatic int recurse_sum;
input int i;
if (i == 0) recurse_sum = 0;
else recurse_sum = i + recurse_sum(i - 1);
endfunction
localparam int S1500 = recurse_sum(1500);
initial begin
if (S1500 !== 1125750) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule