Home / Alt manpages / llvm-diff-18(1)

  • llvm-diff-18(1)
  • User command
  • linux

Compare LLVM IR Structure Safely with llvm-diff-18

You will compare two LLVM modules and get a scriptable answer: no output and exit status 0 means that llvm-diff found no structural difference it could diagnose; non-zero means that it found a difference or could not complete the comparison. This guide uses the llvm-18 package on Ubuntu, which provides llvm-diff-18 version 18.1.3.

Allow about 10 minutes if you already have two modules. You need a shell, the llvm-18 package, and two compatible LLVM assembly files or bitcode files. No root access is required. The command is a debugging aid for LLVM pass and frontend work, not a general-purpose semantic equivalence checker.

1. Check the installed tool

Run the version check before interpreting an example. The output format is not a stable interface, so record the package version with any diagnostic you pass to somebody else.

$ llvm-diff-18 --version
Ubuntu LLVM version 18.1.3
  Optimized build.

The corresponding local package is llvm-18 1:18.1.3-1ubuntu1 on the machine used for this guide. A different LLVM release can have different diagnostics and limitations.

2. Compare two LLVM assembly modules

Put the modules in files whose names end in .ll. That suffix matters: llvm-diff interprets a file ending in .ll as LLVM assembly. Any other filename is read as bitcode, so renaming a bitcode file to look like assembly can make the command fail.

$ llvm-diff-18 build/before.ll build/after.ll
$ status=$?
$ printf 'exit status: %s\n' "$status"
exit status: 0

When the modules match in the structures that llvm-diff checks, the normal result is no output and status 0. Keep the status immediately after the command: running printf first would replace $? with printf's status.

Checkpoint: establish what a difference means

Change a small, intentional part of a test module and run the comparison again.

$ llvm-diff-18 build/before.ll build/after.ll
... diagnostic text describing a structural difference ...
$ printf 'exit status: %s\n' "$?"
exit status: 1

The exact diagnostic is deliberately not shown as a stable transcript. The LLVM documentation says that llvm-diff's output is not a stable format. Treat the non-zero status as the automation signal and read the text as a human debugging hint.

3. Limit the comparison to named globals

With no names after the two filenames, llvm-diff compares all global values and reports globals that exist on only one side. Add one or more global names when you are investigating a particular function or global. Use the spelling that appears in the LLVM IR, including a leading @ where the IR uses one.

$ llvm-diff-18 build/before.ll build/after.ll @calculate
$ llvm-diff-18 build/before.ll build/after.ll @calculate @helper

This narrows the work and the diagnostic, but it does not turn the comparison into a proof that the selected functions have identical behaviour. The tool follows basic blocks from entry blocks. When terminators do not appear to match, downstream blocks are not compared, so an early control-flow change can hide later differences.

4. Use the result in a shell check

For a CI or regression check, branch on the exit status and preserve the tool's diagnostic on standard output or error as your surrounding script requires. This example stops at the first detected difference.

$ if llvm-diff-18 build/before.ll build/after.ll; then
>     echo 'no diagnosed structural differences'
> else
>     rc=$?
>     echo "llvm-diff found a difference or failed (status $rc)" >&2
>     exit "$rc"
> fi
no diagnosed structural differences

Do not write a check that treats every non-zero status as proof of a semantic regression without also considering malformed input, a wrong suffix, or an unsupported module feature. First rerun the command directly and inspect the diagnostic.

What llvm-diff does not promise

The comparison is structural and focuses primarily on function definitions. It ignores some insignificant changes, including global ordering and local value names. It also does not diagnose every meaningful change: the installed manpage specifically calls out linkage and function attributes as examples that may be missed. Memory-behaviour changes such as coalescing loads can instead produce very large block differences.

That boundary is the main safety rule. Use llvm-diff to investigate how an LLVM transformation changed a module, then use a suitable verifier, test suite, or domain-specific equivalence check for the property you actually need. Do not use its empty output as permission to replace a full validation process.

Common traps and recovery

  • Both files are called .ll but contain bitcode. Rename them to a non-.ll suffix or regenerate assembly with the appropriate LLVM tool. The suffix controls the input reader.
  • The command reports a surprising difference everywhere. Check whether control flow changed early, whether memory operations were rearranged, and whether the two modules were produced by compatible LLVM pipelines.
  • You expected attributes or linkage changes to be reported. The tool has known blind spots here. There is no destructive action to undo; switch to a checker that covers those properties.
  • You need coloured output. The installed help lists an explicit colour option, with automatic detection as the default. Use it for an interactive terminal, but avoid depending on colouring in logs.
$ llvm-diff-18 --color build/before.ll build/after.ll

Done means

  • You confirmed which llvm-diff-18 version is installed.
  • You supplied two correctly named LLVM modules and understood the .ll suffix rule.
  • You checked the exit status, rather than relying on whether text appeared.
  • You narrowed the comparison with global names only when that matched the debugging question.
  • You treated an empty result as "no diagnosed difference", not as a complete semantic proof.