Copyright (c) 2024-2026 Antmicro
sv-bugpoint minimizes SystemVerilog code while preserving a user-defined property of that code.
For example, it can be used for acquiring minimal test cases that trigger certain bugs in SystemVerilog tooling.
It uses Slang for parsing SystemVerilog into a syntax tree that is then traversed and reduced part by part. Each removal attempt is tested with a user-supplied script to check whether it didn't change the property of interest (e.g. hide the bug, or cause a different error message). Minimization is performed iteratively until no further changes can be applied.
sv-bugpoint can be used on multi-file input, but works best on single-file output of preprocessor (there is little support in sv-bugpoint for minimizing preprocessor constructs)
Run:
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j8For faster builds you may want to use following invocation instead (you may have to install mold, ninja and ccache beforehand):
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_LINKER_TYPE=MOLD -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake --build build -j8The dependencies will be fetched and built automatically.
The sv-bugpoint and sv-obfuscate executables are placed in the build/ directory.
If you are going to use the accompanying scripts, it is recommended to add the entire scripts/ dir
to your path, as some scripts may depend on each other.
First, you need to prepare:
- a script that takes one or more paths to SystemVerilog files as command-line arguments and asserts that the same bug (or another property you wish to preserve) is still occurring.
It should exit with 0 if the assertion is successful.
For reference, see
examples/caliptra_verilation_err/sv-bugpoint-check.shandexamples/caliptra_vcd/sv-bugpoint-check.sh. The script can be written in any language you are comfortable with, it just needs to be an executable. See the Python example:examples/caliptra_verilation_err/sv-bugpoint-check.py. - SystemVerilog code that
sv-bugpointwill attempt to minimize.
After that, run:
sv-bugpoint <OUT_DIR> <CHECK_SCRIPT> <INPUT_SV> [<INPUT_SV>]The output directory will be populated with:
minimized/<INPUT_SV>- minimized code for each input file. They are updated after each successful pass,tmp/<INPUT_SV>- a copy of the previous file with a removal attempt applied, to be checked with the provided script,sv-bugpoint-combined.sv- if sv-bugpoint is launched with multiple input files, this file contains the concatenation of all files inminimized/directory. It should be treated more as live preview of how minimization is going rather than as source of truth - it is very likely that concatenation will make no sense. If sv-bugpoint is executed on single input file, it is simply a copy ofminimized/<INPUT_SV>.debug/trace- verbose, tab-delimited trace with stats and additional info about each removal attempt (example). It can be turned into a concise, high-level summary with thesv-bugpoint-trace_summary script(example).
There are flags that enable additional dumps:
--save-intermediatessaves each removal attempt in<OUT_DIR>/debug/attempts/<INPUT_SV>.<index>.sv.--dump-treessaves dumps of Slang's AST in<OUT_DIR>/debug/
To get more information about available flags, run sv-bugpoint --help.
If your goal is to debug Verilator, the sv-bugpoint-verilator-gen script can automatically generate an input test case and a check script template for you.
Run sv-bugpoint-verilator-gen --init, and then run each command needed for bug reproduction, prepended with sv-bugpoint-verilator-gen. For example:
sv-bugpoint-verilator-gen --init
sv-bugpoint-verilator-gen verilator --cc -CFLAGS "-std=c++17" ...
sv-bugpoint-verilator-gen make -C obj_dir/ -j ...
sv-bugpoint-verilator-gen ./obj_dir/VsimThe script attempts to:
- Produce a single input file for
sv-bugpointwith preprocessed code. - Produce a template of the check script with:
- a Verilator invocation adjusted to use the preprocessed source,
- other required commands copied (and extended with
|| exit $?if feasible), - an example assertion for a simple failure case.
This script works on a best-effort basis, and it is expected that the result will require some manual adjustments.
While sv-bugpoint removes parts of code not needed for reproduction, the result still includes
names that may leak some details of your protected IP design. If that's your concern, you can use
the sv-obfuscate companion tool which replaces real identifiers with meaningless pseudonyms.
sv-bugpoint-obfuscate <OUTPUT_DIR> <INPUT_SV> [<INPUT_SV>...]The obfuscated files are written to <OUTPUT_DIR>, and a translation map from original identifiers to generated names is printed to standard output.
- Macros are not obfuscated
- Non-standard syntax extensions (such as
verilator_configblock) may be misrecognized as identifiers.
make, clang-format, shellcheck, gawk and verilator are prerequisites for testing and linting.
To run all tests, linters and format-checkers, invoke:
make -f check.mk
in project root. To auto-apply linter/formatter fixes, run:
make -f check.mk autofix
Golden files used in tests can be regenerated using:
GOLDEN=1 make -f check.mk test
