Diagnosing LLVM IR Verifier Failures: Causes, Checks, and Fixes
A step‑by‑step guide to identify and fix LLVM IR verifier failures, with concrete examples, commands, and escalation paths.
20 Jan 2026, 09:15 UTC

Recognizable Condition
The LLVM IR verifier stops with an error message that points to a specific function and instruction, for example:
verifier failed for function @foo: expected type i32 found i64
This indicates that the intermediate representation violates one of the verifier’s rules: a type mismatch, a use‑before‑definition, an invalid phi node, or bad metadata.
Cause/Diagnostic Table
| Symptom in verifier output | Likely cause |
|---|---|
| "expected type X found Y" on a phi node | Phi node incoming values have different types |
| "use of undefined value" or "use before definition" | An instruction uses a value that is not defined on all dominating paths |
| "argument type mismatch" in a call or return | Function prototype does not match the actual call/site |
| "invalid metadata" attached to an instruction | Metadata node is malformed or refers to a non‑existent value |
Ordered Checks
Locate the failing function: run the verifier on the bitcode or assembly.
# Run where you have read access to the file; no special privileges needed. opt -verify input.bc 2>&1 # or, from source: clang -emit-llvm -S -o - file.c | opt -verify 2>&1Expected check: the command exits with a non‑zero status and prints the verifier message.
Identify the offending instruction from the message (it usually names the instruction or gives a line number after
llvm-dis).Convert the bitcode to readable IR to inspect context.
llvm-dis input.bc -o input.ll # Open input.ll in an editor or view with less/grep.Look at:
- Phi node incoming blocks and the types of the values they bring.
- Definition‑use chains: find where the used value is created.
- Function signatures for calls/returns.
- Metadata attachments (look for
!dbg,!tbaa, etc.).
If the error mentions use‑before‑definition, verify dominance: ensure every path from the function entry to the use defines the variable.
You can inspect the control‑flow graph with
opt -dot-cfgor simply reason about the source.
Fixes Tied to Findings
Phi node type mismatch: cast each incoming value to a common type before the phi.
; original (failing) %phi = phi i32 [ %a, %bb1 ], [ %b, %bb2 ] ; fix: extend the i32 to i64 if the phi needs i64 %a64 = sext i32 %a to i64 %b64 = sext i32 %b to i64 %phi = phi i64 [ %a64, %bb1 ], [ %b64, %bb2 ]Where to run: edit
input.llwith any text editor; no special permissions required.Risk: ensure the cast preserves program semantics (sign‑extension vs zero‑extension).
Use‑before‑definition: make sure the definition dominates all uses.
- Move the defining store/earlier instruction up the control flow.
- Or insert a default definition on paths that lack it (e.g., store zero to an
allocaat function entry).
; before: store after use on some path %ptr = alloca i32 %val = load i32, i32* %ptr ; may be undefined store i32 42, i32* %ptr ; after: store a default first %ptr = alloca i32 store i32 0, i32* %ptr ; default %val = load i32, i32* %ptr store i32 42, i32* %ptrRisk: changing dominance can affect optimizations; re‑run the verifier after editing.
Call/return type mismatch: adjust the function prototype or insert appropriate casts at the call site.
; mismatched call declare i32 @foo(i64) ; fix: change prototype or cast %arg64 = sext i32 %arg32 to i64 call i32 @foo(i64 %arg64)Risk: altering the prototype may break other callers; verify all call sites.
Bad metadata: strip or correct the metadata.
# Strip all debug metadata (safe for verification) opt -strip-debug input.bc -o input-stripped.bc # Or manually edit the offending !dbg node in input.llRisk: stripping metadata may lose debug information but does not affect code generation.
Escalation Criteria
- If the verifier passes but the program still miscompiles or crashes, the issue lies beyond the verifier’s scope (e.g., undefined behavior in the source).
- In that case, reduce the test case to a minimal reproducer and file a bug in the LLVM bug tracker, attaching the IR before and after the failing optimization pass.
- When repeatedly encountering verifier failures in a code‑generation toolchain, consider enabling
-verify-passesto run the verifier after each pass and pinpoint the transformation that introduces the error.
Verification of the Fix
- Re‑run the verifier on the corrected IR:
opt -verify input-fixed.bcshould succeed (exit code 0, no error output). - Run a representative optimization pipeline to ensure the fix does not break later passes:
opt -O2 input-fixed.bc -o opto.bc. - If you have an executable, compile the optimized bitcode and run it:
clang opto.bc -o prog && ./prog. Compare the output with a known‑good version or with the source‑level expectation. - If the binary behaves correctly, the immediate verifier issue is resolved; otherwise, revisit the IR for additional problems.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.