From dd76a5b8ba675aca33caa9a40a215aa82802e7d4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 25 Oct 2025 09:57:18 -0400 Subject: [PATCH] Add t_dist_docs_options checks, and fix related docs and coverage issues --- bin/verilator | 7 +- docs/guide/exe_verilator.rst | 25 +++ src/V3OptionParser.cpp | 6 + src/V3OptionParser.h | 1 + src/V3Options.cpp | 23 ++- src/V3Options.h | 1 + src/V3String.h | 1 + test_regress/t/t_benchmarksim.py | 4 +- test_regress/t/t_dist_docs_options.py | 212 +++++++++++++++++++------- test_regress/t/t_flag_define.py | 6 +- 10 files changed, 221 insertions(+), 65 deletions(-) diff --git a/bin/verilator b/bin/verilator index 856d2122f..0af7411a7 100755 --- a/bin/verilator +++ b/bin/verilator @@ -400,7 +400,9 @@ detailed descriptions of these arguments. --getenv Get environment variable with defaults --help Show this help --hierarchical Enable hierarchical Verilation - --hierarchical-params-file Internal option that specifies parameters file for hier blocks + --hierarchical-block Internal use only for --hierarchical + --hierarchical-child Internal use only for --hierarchical + --hierarchical-params-file Internal option that specifies parameters file for hier blocks --hierarchical-threads Number of threads for hierarchical scheduling -I Directory to search for includes --if-depth Tune IFDEPTH warning @@ -418,6 +420,7 @@ detailed descriptions of these arguments. -LDFLAGS Linker pre-object arguments for makefile --lib-create Create a DPI library +libext++[ext]... Extensions for finding modules + +librescan Ignored for compatibility --lint-only Lint, but do not make output --localize-max-size Tune localize optimization variable size --main Generate C++ main() file @@ -432,6 +435,8 @@ detailed descriptions of these arguments. +notimingchecks Ignored -o Name of final executable -O0 Disable optimizations + -O1 Default optimizations + -O2 Stronger optimizations -O3 High-performance optimizations -O Selectable optimizations --output-groups Group .cpp files into larger ones diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index f6fc143fa..22ee03181 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -623,6 +623,10 @@ Summary: .. option:: -fno-const-eager +.. option:: -fno-dead-assigns + +.. option:: -fno-dead-cells + .. option:: -fno-dedup .. option:: -fno-dfg @@ -812,6 +816,14 @@ Summary: :option:`/*verilator&32;hier_block*/` metacomment is ignored. See :ref:`Hierarchical Verilation`. +.. option:: --hierarchical-block + + Internal use only, for :vlopt:`--hierarchical`. + +.. option:: --hierarchical-child + + Internal use only, for :vlopt:`--hierarchical`. + .. option:: --hierarchical-params-file Rarely needed - internal use. Internal flag inserted used during @@ -964,6 +976,10 @@ Summary: "+libext+" is relatively standard across Verilog tools. Defaults to ".v+.sv". +.. option:: +librescan + + Ignored for compatibility with other simulators. + .. option:: --lint-only Check the files for lint violations only, do not create any other @@ -1072,6 +1088,15 @@ Summary: Disables optimization of the model. +.. option:: -O1 + + Enables default optimization of the model. This is the default + optimization level. + +.. option:: -O2 + + Enables stronger than default optimization of the model. + .. option:: -O3 Enables slow optimizations for the code Verilator itself generates (as diff --git a/src/V3OptionParser.cpp b/src/V3OptionParser.cpp index c9cc59736..d19c27cc3 100644 --- a/src/V3OptionParser.cpp +++ b/src/V3OptionParser.cpp @@ -233,6 +233,12 @@ void V3OptionParser::finalize() { m_pimpl->m_isFinalized = true; } +void V3OptionParser::dumpOptions() { + for (const auto& opt : m_pimpl->m_spellCheck.candidates()) { + std::cout << "OPTION: \"" + opt + "\"\n"; + } +} + V3OptionParser::V3OptionParser() : m_pimpl{new Impl{}} {} diff --git a/src/V3OptionParser.h b/src/V3OptionParser.h index ac70c07c4..ec2c1f895 100644 --- a/src/V3OptionParser.h +++ b/src/V3OptionParser.h @@ -81,6 +81,7 @@ public: void addSuggestionCandidate(const string& s) VL_MT_DISABLED; // Call this function after all options are registered. void finalize() VL_MT_DISABLED; + void dumpOptions() VL_MT_DISABLED; // CONSTRUCTORS V3OptionParser() VL_MT_DISABLED; diff --git a/src/V3Options.cpp b/src/V3Options.cpp index ec431c3c6..90e7306d5 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1335,9 +1335,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, v3fatalSrc("--debug-fatal-src"); }).undocumented(); // See also --debug-abort DECL_OPTION("-debug-leak", OnOff, &m_debugLeak); - DECL_OPTION("-debug-nondeterminism", OnOff, &m_debugNondeterminism); + DECL_OPTION("-debug-nondeterminism", OnOff, &m_debugNondeterminism).undocumented(); + DECL_OPTION("-debug-options", OnOff, &m_debugOptions).undocumented(); DECL_OPTION("-debug-partition", OnOff, &m_debugPartition).undocumented(); - DECL_OPTION("-debug-preproc-passthru", OnOff, &m_debugPreprocPassthru); + DECL_OPTION("-debug-preproc-passthru", OnOff, &m_debugPreprocPassthru).undocumented(); DECL_OPTION("-debug-protect", OnOff, &m_debugProtect).undocumented(); DECL_OPTION("-debug-self-test", OnOff, &m_debugSelfTest).undocumented(); DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort @@ -1466,7 +1467,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-I", CbPartialMatch, [this, &optdir](const char* optp) { addIncDirUser(parseFileArg(optdir, optp)); }); DECL_OPTION("-if-depth", Set, &m_ifDepth); - DECL_OPTION("-ignc", OnOff, &m_ignc); + DECL_OPTION("-ignc", OnOff, &m_ignc).undocumented(); DECL_OPTION("-inline-mult", Set, &m_inlineMult); DECL_OPTION("-instr-count-dpi", CbVal, [this, fl](int val) { m_instrCountDpi = val; @@ -1546,7 +1547,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-o", Set, &m_exeName); DECL_OPTION("-order-clock-delay", CbOnOff, [fl](bool /*flag*/) { fl->v3warn(DEPRECATED, "Option order-clock-delay is deprecated and has no effect."); - }); + }).undocumented(); DECL_OPTION("-output-groups", CbVal, [this, fl](const char* valp) { m_outputGroups = std::atoi(valp); if (m_outputGroups < -1) fl->v3error("--output-groups must be >= -1: " << valp); @@ -1599,8 +1600,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-prof-cfuncs", CbCall, [this]() { m_profC = m_profCFuncs = true; }); DECL_OPTION("-prof-exec", OnOff, &m_profExec); DECL_OPTION("-prof-pgo", OnOff, &m_profPgo); - DECL_OPTION("-profile-cfuncs", CbCall, - [this]() { m_profC = m_profCFuncs = true; }); // Renamed + DECL_OPTION("-profile-cfuncs", CbCall, [this]() { + m_profC = m_profCFuncs = true; + }).undocumented(); // Renamed DECL_OPTION("-protect-ids", OnOff, &m_protectIds); DECL_OPTION("-protect-key", Set, &m_protectKey); DECL_OPTION("-protect-lib", CbVal, [this, fl](const char* valp) { @@ -1741,7 +1743,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, fl->v3warn(DEPRECATED, "Option --trace-fst-thread is deprecated. " "Use --trace-fst with --trace-threads > 0."); if (m_traceThreads == 0) m_traceThreads = 1; - }); + }).undocumented(); DECL_OPTION("-trace-max-array", Set, &m_traceMaxArray); DECL_OPTION("-trace-max-width", Set, &m_traceMaxWidth); DECL_OPTION("-trace-params", OnOff, &m_traceParams); @@ -1756,7 +1758,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-trace-vcd", CbCall, [this]() { m_traceEnabledVcd = true; }); DECL_OPTION("-U", CbPartialMatch, &V3PreShell::undef); - DECL_OPTION("-underline-zero", OnOff, &m_underlineZero); // Deprecated + DECL_OPTION("-underline-zero", OnOff, &m_underlineZero).undocumented(); // Deprecated DECL_OPTION("-no-unlimited-stack", CbCall, []() {}); // Processed only in bin/verilator shell DECL_OPTION("-unroll-count", Set, &m_unrollCount).undocumented(); // Optimization tweak DECL_OPTION("-unroll-stmts", Set, &m_unrollStmts).undocumented(); // Optimization tweak @@ -1968,6 +1970,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, ++i; } } + + if (m_debugOptions) { + parser.dumpOptions(); + v3Global.vlExit(0); + } } //====================================================================== diff --git a/src/V3Options.h b/src/V3Options.h index cb7f6df96..551b0a815 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -239,6 +239,7 @@ private: bool m_debugExitUvm23 = false; // main switch: --debug-exit-uvm23 bool m_debugLeak = true; // main switch: --debug-leak bool m_debugNondeterminism = false; // main switch: --debug-nondeterminism + bool m_debugOptions = false; // main switch: --debug-options bool m_debugPartition = false; // main switch: --debug-partition bool m_debugPreprocPassthru = false; // main switch: --debug-preproc-passthru bool m_debugProtect = false; // main switch: --debug-protect diff --git a/src/V3String.h b/src/V3String.h index eec386b6c..23dbe10fd 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -262,6 +262,7 @@ public: } } static void selfTest(); + const std::vector candidates() const { return m_candidates; } private: static EditDistance editDistance(const string& s, const string& t); diff --git a/test_regress/t/t_benchmarksim.py b/test_regress/t/t_benchmarksim.py index 966eea90c..501a8b0fd 100755 --- a/test_regress/t/t_benchmarksim.py +++ b/test_regress/t/t_benchmarksim.py @@ -15,10 +15,10 @@ test.top_filename = "t/t_gen_alw.v" # Use any top file test.init_benchmarksim() # As an example, compile and simulate the top file with varying optimization level -l_opts = [1, 2, 3] +l_opts = ['-O0', '-O1', '-O2', '-O3'] for l_opt in l_opts: - test.compile(benchmarksim=1, v_flags2=["-O" + str(l_opt)]) + test.compile(benchmarksim=1, v_flags2=[l_opt]) test.execute() diff --git a/test_regress/t/t_dist_docs_options.py b/test_regress/t/t_dist_docs_options.py index d7346c558..5e2702f0a 100755 --- a/test_regress/t/t_dist_docs_options.py +++ b/test_regress/t/t_dist_docs_options.py @@ -11,22 +11,63 @@ import vltest_bootstrap test.scenarios('dist') -Waivers = [ +Doc_Waivers = [ '+verilator+prof+threads+file+', # Deprecated '+verilator+prof+threads+start+', # Deprecated '+verilator+prof+threads+window+', # Deprecated '-clk', # Deprecated - '-fdfg-synthesize-all', # Mostly used for testing - '-fno-', # Documented differently - '-no-clk', # Deprecated - '-no-lineno', # Deprecated - '-no-order-clock-delay', # Deprecated + '-lineno', # Deprecated + '-order-clock-delay', # Deprecated '-prof-threads', # Deprecated ] +Test_Waivers = [ + # Covered: + '-G', # Covered; other text fallows option letter + '-O', # Covered; other text fallows option letter + '-U', # Covered; other text fallows option letter + '-gdb', # Covered: no way to test, part of --gdbbt + '-rr', # Not testing; not requiring rr installation + # Need testing: + '-Wno-lint', + '-Wno-style', + '-Wwarn-lint', + '-annotate-all', + '-annotate-min', + '-converge-limit', + '-coverage-underscore', + '-default-language', + '-dump-graph', + '-dumpi-tree-json', + '-facyc-simp', # Need test of -fno-... + '-fassemble', # Need test of -fno-... + '-fcase', # Need test of -fno-... + '-fcombine', # Need test of -fno-... + '-fconst', # Need test of -fno-... + '-fdedup', # Need test of -fno-... + '-fdfg-peephole', # Need test of -fno-... + '-fdfg-peephole-', # Need test of -fno-... + '-ffunc-opt-balance-cat', # Need test of -fno-... + '-ffunc-opt-split-cat', # Need test of -fno-... + '-flife', # Need test of -fno-... + '-flife-post', # Need test of -fno-... + '-fmerge-cond', # Need test of -fno-... + '-freloop', # Need test of -fno-... + '-fsubst', # Need test of -fno-... + '-fsubst-const', # Need test of -fno-... + '-ftable', # Need test of -fno-... + '-json-ids', # Need test of -no-json-ids + '-private', + '-trace-depth', +] -def get_summary_opts(): - args = {} +Sums = {} +Docs = {} +Srcs = {} +Tests = {} + + +def read_sums(): for filename in test.glob_some(test.root + "/bin/*"): with open(filename, "r", encoding="latin-1") as fh: on = False @@ -42,19 +83,19 @@ def get_summary_opts(): on = False elif on and m1: opt = opt_clean(m1.group(1)) + key = opt_key(opt) if test.verbose: - print("S '" + opt + "' " + line) - args[opt] = filename + ":" + str(lineno) + print("A '" + opt + "' " + line) + Sums[key] = filename + ":" + str(lineno) + ": " + opt elif m2: opt = opt_clean(m2.group(1)) + key = opt_key(opt) if test.verbose: - print("S '" + opt + "' " + line) - args[opt] = filename + ":" + str(lineno) - return args + print("A '" + opt + "' " + line) + Sums[key] = filename + ":" + str(lineno) + ": " + opt -def get_docs_opts(): - args = {} +def read_docs(): for filename in test.glob_some(test.root + "/docs/guide/*.rst"): with open(filename, "r", encoding="latin-1") as fh: lineno = 0 @@ -68,10 +109,60 @@ def get_docs_opts(): m = re.search(r':vlopt:`((-|\+)+[^ `]+)', line) if m: opt = opt_clean(m.group(1)) + key = opt_key(opt) if test.verbose: print("D '" + opt + "' " + line) - args[opt] = filename + ":" + str(lineno) - return args + Docs[key] = filename + ":" + str(lineno) + ": " + opt + + +def read_srcs(): + filename = "bin/verilator --debug-options" + opts = test.run_capture("perl " + os.environ["VERILATOR_ROOT"] + "/bin/verilator" + + " --debug-options 2>&1") + lineno = 0 + for line in opts.split("\n"): + lineno += 1 + m1 = re.search(r'OPTION: "([^"]+)"', line) + if m1: + opt = opt_clean(m1.group(1)) + key = opt_key(opt) + if re.match(r'-Werror-[A-Z ]', opt): + continue + if re.match(r'-Wno-[A-Z ]', opt): + continue + if re.match(r'-Wwarn-[A-Z ]', opt): + continue + if test.verbose: + print("S '" + opt + "' " + line) + Srcs[key] = filename + ":" + str(lineno) + ": " + opt + if len(Srcs) < 5: + test.error("Didn't parse any options") + return Srcs + + +def read_tests(): + filename = "test_regress/t/*.py" + for filename in (test.glob_some(test.root + "/test_regress/t/*.py")): + if "t_dist_docs_options" in filename: # Avoid our own suppressions + continue + with open(filename, 'r', encoding="latin-1") as fh: + lineno = 0 + for line in fh: + lineno += 1 + line = line.lstrip().rstrip() + for opt in re.findall(r'[-+]+[-+a-zA-Z0-9]+', line): + opt = opt_clean(opt) + key = opt_key(opt) + if test.verbose: + print("T '" + opt + "' " + line) + Tests[key] = filename + ":" + str(lineno) + ": " + opt + # For e.g. +verilator+seed+ and -dumpi-<#> + pos = max(opt.rfind('+'), opt.rfind('-')) + if pos > 1: + subkey = opt[:pos + 1] + if test.verbose: + print("t '" + subkey + "' " + line) + Tests[subkey] = filename + ":" + str(lineno) + ": " + opt def opt_clean(opt): @@ -81,53 +172,68 @@ def opt_clean(opt): return opt -def alt_names(opt): - opts = [opt] - if re.search(r'^-', opt): - opts.append("-no" + opt) - m = re.search(r'^-no(-.*)', opt) - if m: - opts.append(m.group(1)) - return opts +def opt_key(opt): + opt = opt_clean(opt) + opt = re.sub(r'^-fno-', '-f', opt) + opt = re.sub(r'^-no-', '-', opt) + return opt if not os.path.exists(test.root + "/.git"): test.skip("Not in a git repository") -sums = get_summary_opts() -docs = get_docs_opts() +read_sums() +read_docs() +read_srcs() +read_tests() both = {} -both.update(sums) -both.update(docs) +both.update(Sums) +both.update(Docs) +both.update(Srcs) -waiver = {k: 1 for k in Waivers} +doc_waiver = {k: 1 for k in Doc_Waivers} for opt in sorted(both.keys()): - if opt in waiver: + if opt in doc_waiver: continue - sum_ok = False - docs_ok = False - for alt in alt_names(opt): - if alt in sums: - sum_ok = True - if test.verbose: - print(str(sum_ok) + " SAC '" + opt + "' -> '" + alt + "'") - if re.search(r'-fno-', opt): # Minimal-documented optimization option - sum_ok = True - for alt in alt_names(opt): - if alt in docs: - docs_ok = True - if test.verbose: - print(str(docs_ok) + " DAC '" + opt + "' -> '" + alt + "'") - if not sum_ok: - test.error(docs[opt] + ": Option documented in docs/guide '" + opt + - "' not found in bin/* ARGUMENT SUMMARY documentation") - elif not docs_ok: - test.error(sums[opt] + ": Option documented in bin/ ARGUMENT SUMMARY '" + opt + - "' not found in docs/guide documentation") - elif test.verbose: - print(": ok '" + opt) + is_in = [] + not_in = [] + summ = None + if opt in Sums: + summ = Sums[opt] + is_in.append("summary " + summ) + else: + if not re.match(r'-f', opt): + not_in.append("ARGUMENT SUMMARY in bin/verilator or bin/verilator_coverage") + + doc = None + if opt in Docs: + doc = Docs[opt] + is_in.append("documentation " + doc) + else: + not_in.append("documentation in docs/guide/exe_*.rst") + + src = None + if opt in Srcs: + src = Srcs[opt] + is_in.append("sources " + src) + # Ok if not in sources + + if opt in Tests: + if opt in Test_Waivers: + print("Unnecessary Test_Waiver for option: '" + opt + "'") + + else: + if opt in Test_Waivers: + is_in.append("Test_Waiver for test_regress/t/*.py") + else: + not_in.append("uncovered in test_regress/t/*.py") + + if not_in: + test.error_keep_going("Option '" + opt + "' has inconsistent references\n" + + " Missing in " + "\n Missing in ".join(not_in) + "\n Found in " + + "\n Found in ".join(is_in)) test.passes() diff --git a/test_regress/t/t_flag_define.py b/test_regress/t/t_flag_define.py index 68eca8398..4bf777524 100755 --- a/test_regress/t/t_flag_define.py +++ b/test_regress/t/t_flag_define.py @@ -11,7 +11,11 @@ import vltest_bootstrap test.scenarios('vlt') -test.compile(v_flags2=["-f t/t_flag_define.vc -DCMD_DEF -DCMD_UNDEF -UCMD_UNDEF +define+CMD_DEF2"]) +# We also test +librescan and +notimingchecks here, which are NOPs +test.compile(v_flags2=[ + "-f t/t_flag_define.vc -DCMD_DEF -DCMD_UNDEF -UCMD_UNDEF +define+CMD_DEF2", "+librescan", + "+notimingchecks" +]) test.execute()