Inspect LLVM Bitcode Size and Encoding with llvm-bcanalyzer-20
You will finish with a repeatable way to inspect an LLVM bitcode file, read its size and block statistics, and produce a low-level dump when the summary is not enough. The examples use the installed LLVM 20.1.8 build from the llvm-20 package.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need a shell, a readable bitcode file, and llvm-bcanalyzer-20. The examples only read files and write a temporary test file, so they do not need sudo. Do not point the command at an untrusted file merely because it has a .bc suffix: analysis parses structured input, and the tool's output may contain data from that file.
1. Confirm the installed tool
Check the executable and version before relying on option details. This is an ordinary, read-only check:
$ command -v llvm-bcanalyzer-20
/usr/bin/llvm-bcanalyzer-20
$ llvm-bcanalyzer-20 --version
Ubuntu LLVM version 20.1.8
Optimized build.
Ask the same binary for its help:
$ llvm-bcanalyzer-20 --help
The installed command accepts the documented --dump option and also exposes build-specific analyser options such as histogram control. The local manpage is the useful contract for the normal workflow, while --help shows what this particular build accepts. Keep those two sources together when writing scripts.
Checkpoint
You have confirmed the binary is LLVM 20.1.8, not a similarly named tool from another LLVM installation.
2. Obtain a known-good bitcode file
If you already have a bitcode file, record its path and check that it is readable:
$ test -r /path/to/module.bc && echo readable
readable
$ file /path/to/module.bc
/path/to/module.bc: LLVM IR bitcode
For a controlled smoke test, assemble a tiny LLVM IR module. This uses llvm-as-20, if it is installed, and keeps the generated file in /tmp:
$ cat > /tmp/counter.ll <<'EOF'
; ModuleID = 'counter'
source_filename = "counter.ll"
define i32 @add(i32 %a, i32 %b) {
entry:
%sum = add i32 %a, %b
ret i32 %sum
}
EOF
$ llvm-as-20 /tmp/counter.ll -o /tmp/counter.bc
$ file /tmp/counter.bc
/tmp/counter.bc: LLVM IR bitcode
If llvm-as-20 is not installed, use a bitcode file produced by the compiler or build that created your module. Do not rename LLVM assembly text to .bc: the analyser expects bitcode bytes, not source text.
Checkpoint
file identifies the input as LLVM IR bitcode, and the input path is readable by your account.
3. Read the normal report
Pass one filename to the analyser. It writes the report to standard output and returns zero when the analysis succeeds:
$ llvm-bcanalyzer-20 /tmp/counter.bc
Summary of /tmp/counter.bc:
Total size: 11072b/1384.00B/346W
Stream type: LLVM IR
# Toplevel Blocks: 3
Per-block Summary:
Block ID #0 (BLOCKINFO_BLOCK):
Num Instances: 1
Total Size: 864b/108.00B/27W
...
The exact report grows with the module, so the important first lines are the input name, total size, stream type and number of top-level blocks. The per-block section lets you see where the bitcode stream is spending space. The local manual describes related measurements such as block size, functions, instructions, operands and variable-bit-rate encoding; the precise sections depend on the bitcode and this LLVM build.
For a script, check the exit status rather than matching a particular byte count:
$ llvm-bcanalyzer-20 /tmp/counter.bc > /tmp/counter-report.txt
$ printf 'analyser status: %s\n' "$?"
analyser status: 0
Redirecting standard output is safe for the input, but choose a new report path or make a backup before overwriting a report you still need. The analyser does not modify the bitcode file.
4. Use the low-level dump for format detail
Add --dump when you need records and block boundaries rather than only measurements:
$ llvm-bcanalyzer-20 --dump /tmp/counter.bc | sed -n '1,14p'
<IDENTIFICATION_BLOCK_ID NumWords=5 BlockCodeSize=5>
<STRING abbrevid=4 op0=76 op1=76 op2=86 op3=77 op4=50 op5=48 .../> record string = 'LLVM20.1.8'
<EPOCH abbrevid=5 op0=0/>
</IDENTIFICATION_BLOCK_ID>
<MODULE_BLOCK NumWords=327 BlockCodeSize=3>
<VERSION op0=2/>
<BLOCKINFO_BLOCK/>
...
This is a bitcode encoding trace, not LLVM assembly. Values such as op0 and abbreviated record names are useful when comparing producers or investigating a format issue, but they are not a source file you can assemble unchanged. Pipe it through less for a large module, or save it to a separate file for comparison.
The dump can be much larger than the bitcode. Avoid sending it into an unbounded log on a busy build host. A bounded preview such as the command above keeps an initial inspection manageable.
5. Analyse standard input in a pipeline
Omit the filename, or pass -, to read bitcode from standard input. This is useful when another tool produces the stream:
$ cat /tmp/counter.bc | llvm-bcanalyzer-20 - | sed -n '1,5p'
Summary of -:
Total size: 11072b/1384.00B/346W
Stream type: LLVM IR
# Toplevel Blocks: 3
Keep the binary stream on standard input and the report on standard output. Do not mix diagnostic text into the stream before the analyser reads it. If you need to preserve both input and output, save the original bitcode first and redirect the report to a different path.
6. Diagnose failures without guessing
LLVM assembly text is a common mistake. Passing .ll directly produces a non-zero status because it is not a bitcode stream:
$ llvm-bcanalyzer-20 /tmp/counter.ll >/tmp/report.txt
llvm-bcanalyzer: Bitcode stream should be a multiple of 4 bytes in length
$ printf 'analyser status: %s\n' "$?"
analyser status: 1
Use llvm-as-20 to assemble the file first, or obtain the matching .bc output from the build. A missing file, unreadable path or truncated transfer is a different problem: check the path and permissions, then compare the file size with the producer's copy.
Version mismatches can also matter. The dump identifies the LLVM producer string, and the report identifies the stream type, but neither makes an invalid or incompatible input valid. Keep the producer's LLVM version and the analyser's version in the diagnostic record. If a tool refuses the file, retrying with sudo will not repair its contents and is normally unnecessary.
There is no persistent state to undo in these examples. To remove the temporary smoke-test files after checking them, delete only the named files:
$ rm -f /tmp/counter.ll /tmp/counter.bc /tmp/counter-report.txt /tmp/report.txt
That removal is irreversible. Keep any report needed for an investigation, and never include a real module path in a copy-and-paste cleanup command.
Done means
llvm-bcanalyzer-20 --versionreports the expected installed LLVM build.- The input is genuine, readable LLVM bitcode rather than renamed assembly text.
- The normal report completes with exit status 0 and gives a total size and stream type.
--dumpis reserved for format-level inspection and bounded or saved output.- Pipeline use keeps bitcode on standard input and report text on standard output.
- No source bitcode or persistent system configuration was changed.