llvm-reduce-18 shrinks a crashing LLVM IR file down to the smallest version that still triggers the bug. It works by repeatedly stripping parts out and keeping each cut only when your own test script says the remaining file is still interesting. This guide uses the llvm-reduce-18 supplied by Ubuntu's llvm-18 package, version 18.1.3.
Allow roughly 10 minutes for a small example and considerably longer for a large or expensive reproducer. You need a reproducible IR or MIR input, a command that exposes the failure, and a POSIX shell script that returns success when the failure is present. No root access is needed. Work in a disposable directory and keep the original input unchanged.
Check that the versioned executable is the one you expect:
llvm-reduce-18 --version
dpkg-query -W -f='${Package} ${Version}\n' llvm-18
On the system used for this guide, the first command reports Ubuntu LLVM version 18.1.3 and the package is llvm-18 1:18.1.3-1ubuntu1.
--in-place on the first run. The manpage warns that it replaces the input file.mkdir -p /tmp/llvm-reduce-work
cp /path/to/failing-test.ll /tmp/llvm-reduce-work/input.ll
cd /tmp/llvm-reduce-work
Safety boundary: The reducer executes the interestingness test many times. Treat the input and every command used by the script as untrusted test data. Use a dedicated temporary directory, avoid scripts that delete files or change services, and never put secrets in test arguments or the input.
The test receives the candidate file as its first argument. It must exit with status zero when the candidate still demonstrates the bug, and non-zero otherwise. For a compiler crash, run the same compiler command you already use and match a stable error marker:
#!/bin/sh
set -eu
/usr/bin/opt-18 -O2 -disable-output "$1" 2>&1 \
| grep -F 'Assertion failed at line 1234 of WhateverFile.cpp'
Save this as interesting.sh and make it executable:
chmod 755 interesting.sh
./interesting.sh input.ll
echo "test exit status: $?"
The expected status is zero for the original reproducer. If the test prints an error from opt-18 but still returns zero because of a pipeline mistake, fix the script before reducing anything. grep earns its place at the end of the pipeline here because its zero status is the signal you actually want. Match a distinctive, stable symptom rather than a line number that changes between builds.
Give the test script and input to llvm-reduce-18, and write the result to a new file:
llvm-reduce-18 \
--test=./interesting.sh \
input.ll \
-o reduced.ll
The command prints progress for reduction passes and finishes with a line like:
Done reducing! Reduced testcase: reduced.ll
A zero exit status means normal operation, not proof the output is actually useful. Confirm both the test result and the output file:
./interesting.sh reduced.ll
llvm-as-18 reduced.ll -o /tmp/llvm-reduce-work/reduced.bc
wc -l input.ll reduced.ll
Checkpoint: the first command above should still return zero. The llvm-as-18 check catches a malformed textual IR file, and wc gives you a quick, visible size comparison. Reduction is not guaranteed to produce the smallest possible file, and a flaky test can cause unrelated or excessive removals.
By default, LLVM runs all available delta passes and may repeat the full set up to five times. Start with the default when correctness matters more than speed. For a quick, repeatable diagnostic, restrict the work:
llvm-reduce-18 \
--test=./interesting.sh \
--delta-passes=function-bodies \
--max-pass-iterations=1 \
-j 1 \
input.ll \
-o reduced-pass.ll
-j 1 disables parallelism. That makes test output easier to follow and cuts load, but it does not make an unstable test stable.--print-delta-passes lists pass names before you pick one.--skip-delta-passes=pass1,pass2 drops a pass that does not suit this input.These narrower runs are useful for diagnosis, but a final reduction normally deserves a broader pass set. For machine-code IR, select the input language explicitly with -x=mir; for ordinary textual LLVM IR, use -x=ir. The tool can also read standard input when the input argument is -, but a named file is easier to audit and rerun.
-j, fewer pass iterations, or selected delta passes for an exploratory run, then restore a broader run before treating the result as final.--in-place was used. Restore it from version control or your untouched copy. With the commands above, discard a bad result with rm reduced.ll; the source remains input.ll.Warning: do not use --in-place unless you have a verified backup and genuinely want the replacement. The option changes the input file, while an ordinary output path keeps the before-and-after files around for review.
llvm-reduce-18 --version identifies the expected LLVM 18 installation.llvm-as-18 accepts the reduced IR, when the assembler is available.