Module verification failed: Instruction does not dominate all uses!

I can’t seem to figure out whats wrong with the following IR. I searched for similar issues here and still can’t figure out whats wrong with this IR.
The IR is generated from a custom language that I’m developing for learning purposes (code attached below).

Generated IR & Error:

Instruction does not dominate all uses!
  %u2 = alloca i32, align 4
  %1 = load i32, ptr %u2, align 4
Instruction does not dominate all uses!
  %i3 = alloca i32, align 4
  %2 = load i32, ptr %i3, align 4
; ModuleID = '/Users/dccarter/projects/cxy/tests/hello.cxy'
source_filename = "/Users/dccarter/projects/cxy/tests/hello.cxy"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-darwin23.2.0"

%__Closure6 = type { i8 }
%tuple.116 = type { ptr, ptr }

define i32 @__Closure6_op__call(ptr %this, i32 %u, i32 %i) {
entry:
  %res = alloca i32, align 4
  %i3 = alloca i32, align 4
  %u2 = alloca i32, align 4
  %this1 = alloca ptr, align 8
  store ptr %this, ptr %this1, align 8
  store i32 %u, ptr %u2, align 4
  store i32 %i, ptr %i3, align 4
  %0 = load i32, ptr %u2, align 4
  %1 = load i32, ptr %i3, align 4
  %2 = add i32 %0, %1
  %3 = load ptr, ptr %this1, align 8
  %j = getelementptr inbounds %__Closure6, ptr %3, i32 0, i32 0
  %4 = load i8, ptr %j, align 1
  %5 = zext i8 %4 to i32
  %6 = add i32 %2, %5
  store i32 %6, ptr %res, align 4
  br label %end

end:                                              ; preds = %entry
  %7 = load i32, ptr %res, align 4
  ret i32 %7
}

define internal i32 @accumulate7(%tuple.116 %fun, i32 %acc) {
entry:
  %i = alloca i64, align 8
  %res = alloca i32, align 4
  %acc2 = alloca i32, align 4
  %fun1 = alloca %tuple.116, align 8
  store %tuple.116 %fun, ptr %fun1, align 8
  store i32 %acc, ptr %acc2, align 4
  store i64 0, ptr %i, align 8
  br label %while.cond

while.cond:                                       ; preds = %while.update, %entry
  %0 = load i64, ptr %i, align 8
  %1 = icmp ne i64 %0, 10
  br i1 %1, label %while.body, label %while.end

while.body:                                       ; preds = %while.cond
  %2 = getelementptr inbounds %tuple.116, ptr %fun1, i32 0, i32 1
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %tuple.116, ptr %fun1, i32 0, i32 0
  %5 = load ptr, ptr %4, align 8
  %6 = load i32, ptr %acc2, align 4
  %7 = load i64, ptr %i, align 8
  %8 = trunc i64 %7 to i32
  %9 = call i32 %3(ptr %5, i32 %6, i32 %8)
  store i32 %9, ptr %acc2, align 4
  br label %while.update

while.update:                                     ; preds = %while.body
  %10 = load i64, ptr %i, align 8
  %11 = add i64 %10, 1
  store i64 %11, ptr %i, align 8
  br label %while.cond

while.end:                                        ; preds = %while.cond
  %12 = load i32, ptr %acc2, align 4
  store i32 %12, ptr %res, align 4
  br label %end

end:                                              ; preds = %while.end
  %13 = load i32, ptr %res, align 4
  ret i32 %13
}

define internal i32 @__Closure6__fwd(ptr %ptr, i32 %u, i32 %i) {
entry:
  %res = alloca i32, align 4
  %i3 = alloca i32, align 4
  %u2 = alloca i32, align 4
  %ptr1 = alloca ptr, align 8
  store ptr %ptr, ptr %ptr1, align 8
  store i32 %u, ptr %u2, align 4
  store i32 %i, ptr %i3, align 4
  %0 = load ptr, ptr %ptr1, align 8
  %1 = load i32, ptr %u2, align 4
  %2 = load i32, ptr %i3, align 4
  %3 = call i32 @__Closure6_op__call(ptr %0, i32 %1, i32 %2)
  store i32 %3, ptr %res, align 4
  br label %end

end:                                              ; preds = %entry
  %4 = load i32, ptr %res, align 4
  ret i32 %4
}

define void @main(i32 %argc, ptr %argv) {
entry:
  %0 = alloca %__Closure6, align 8
  %j = alloca i8, align 1
  %argv2 = alloca ptr, align 8
  %argc1 = alloca i32, align 4
  store i32 %argc, ptr %argc1, align 4
  store ptr %argv, ptr %argv2, align 8
  store i8 10, ptr %j, align 1
  %1 = load i8, ptr %j, align 1
  %2 = insertvalue %__Closure6 undef, i8 %1, 0
  store %__Closure6 %2, ptr %0, align 1
  %3 = insertvalue %tuple.116 undef, ptr %0, 0
  %4 = insertvalue %tuple.116 %3, ptr @__Closure6__fwd, 1
  %5 = call i32 @accumulate7(%tuple.116 %4, i32 0)
  br label %end

end:                                              ; preds = %entry
  ret void
}

Original Source:


func accumulate[U](fun: func(acc: U, item: u32) -> U, acc: U) {
    for (var i: 0..10) {
        acc = fun(acc, <u32>i)
    }
    return acc
}

pub func main(argc: i32, argv: &string) {
    var j = 10;
    accumulate((u: u32, i: u32) => u + i + j, <u32>0)
}

Or Simplified:


struct __Closure0 {
  - j: i8
}

pub func __Closure0_op__call(this: &__Closure0, u: u32, i: u32): u32 {
  return u + i + this.j
}

func accumulate1(fun: (&void, func(_: &void, acc: u32, item: u32) -> u32), acc: u32): u32 {
  {
    var i = 0
    while (i != 10)
    {
      acc = fun.1(fun.0, acc, <u32>i)
    }
  }
  return acc
}

func __Closure0__fwd(ptr: &void, u: u32, i: u32): u32 => __Closure0_op__call(<&__Closure0>ptr, u, i)

pub func main(argc: i32, argv: &string) {
  var j = 10
  accumulate1((<&void>&__Closure0{j = j}, __Closure0__fwd), 0)
}

Wild guess: You have values named %u2 and %i3 in two different functions, and you have an instruction in function 1 referencing the %u2 in function 2 or vice versa.

Thanks a lot, pointed to the right spot where I had the bug in my compiler. In the __Closure0_fwd when invoking __Closure0_op__call with u and i, I’m referencing the wrong function arguments

This should help anybody else who runs into this in the future: Verifier: More helpful error message for cross-function references by nhaehnle · Pull Request #82906 · llvm/llvm-project · GitHub

2 Likes