Reason for duplicated llvm code in pseudo-vtable

Apologies if this is answered somewhere else, but I couldn’t find it.
I have the following two functions; testvt is intended to do some sort of dispatch, while remaining type-stable:

@noinline f(x, a, b, c, ::Val{N}) where N = muladd.(x, 0.1a + 0.5b + 2c, N*c)
testvt(x, a, b, c, k) = Base.@nif 10 d -> (k == d) d -> f(x, a, b, c, Val(d))

With these arguments:

x, a, b, c = (rand(1000) for _ in 1:4)

It looks like there is a lot of duplicated llvm code.

all vector args
julia> @code_llvm testvt(x, a, b, c, 10)
;  @ REPL[2]:1 within `testvt`
; Function Attrs: uwtable
define nonnull {}* @julia_testvt_226({}* noundef nonnull align 16 dereferenceable(40) %0, {}* noundef nonnull align 16 dereferenceable(40) %1, {}* noundef nonnull align 16 dereferenceable(40) %2, {}* noundef nonnull align 16 dereferenceable(40) %3, i64 signext %4) #0 {
top:
  %5 = alloca [5 x {}*], align 8
  %.sub = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 0
  switch i64 %4, label %L37 [
    i64 1, label %L3
    i64 2, label %L7
    i64 3, label %L11
    i64 4, label %L15
    i64 5, label %L19
    i64 6, label %L23
    i64 7, label %L27
    i64 8, label %L31
    i64 9, label %L35
  ]

common.ret:                                       ; preds = %L37, %L35, %L31, %L27, %L23, %L19, %L15, %L11, %L7, %L3
  %common.ret.op = phi {}* [ %10, %L3 ], [ %15, %L7 ], [ %20, %L11 ], [ %25, %L15 ], [ %30, %L19 ], [ %35, %L23 ], [ %40, %L27 ], [ %45, %L31 ], [ %50, %L35 ], [ %55, %L37 ]
  ret {}* %common.ret.op

L3:                                               ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %6 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %6, align 8
  %7 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %7, align 8
  %8 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %8, align 8
  %9 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735412136144 to {}*), {}** %9, align 8
  %10 = call nonnull {}* @j1_f_228({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L7:                                               ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %11 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %11, align 8
  %12 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %12, align 8
  %13 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %13, align 8
  %14 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735412139296 to {}*), {}** %14, align 8
  %15 = call nonnull {}* @j1_f_229({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L11:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %16 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %16, align 8
  %17 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %17, align 8
  %18 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %18, align 8
  %19 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735427216096 to {}*), {}** %19, align 8
  %20 = call nonnull {}* @j1_f_230({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L15:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %21 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %21, align 8
  %22 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %22, align 8
  %23 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %23, align 8
  %24 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735425748336 to {}*), {}** %24, align 8
  %25 = call nonnull {}* @j1_f_231({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L19:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %26 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %26, align 8
  %27 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %27, align 8
  %28 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %28, align 8
  %29 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735427217952 to {}*), {}** %29, align 8
  %30 = call nonnull {}* @j1_f_232({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L23:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %31 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %31, align 8
  %32 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %32, align 8
  %33 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %33, align 8
  %34 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735427219520 to {}*), {}** %34, align 8
  %35 = call nonnull {}* @j1_f_233({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L27:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %36 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %36, align 8
  %37 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %37, align 8
  %38 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %38, align 8
  %39 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 2425037422688 to {}*), {}** %39, align 8
  %40 = call nonnull {}* @j1_f_234({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L31:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %41 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %41, align 8
  %42 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %42, align 8
  %43 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %43, align 8
  %44 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 2425037408776 to {}*), {}** %44, align 8
  %45 = call nonnull {}* @j1_f_235({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L35:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %46 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %46, align 8
  %47 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %47, align 8
  %48 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %48, align 8
  %49 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735423996592 to {}*), {}** %49, align 8
  %50 = call nonnull {}* @j1_f_236({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L37:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %51 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %51, align 8
  %52 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %52, align 8
  %53 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %53, align 8
  %54 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735432190096 to {}*), {}** %54, align 8
  %55 = call nonnull {}* @j1_f_237({}* inttoptr (i64 2425037407000 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret
}

But with just one less vector argument, it looks a whole lot cleaner:

c = 1.
julia> @code_llvm testvt(x, a, b, 1., 10)
;  @ REPL[2]:1 within `testvt`
; Function Attrs: noreturn uwtable
define void @julia_testvt_277({}* noundef nonnull align 16 dereferenceable(40) %0, {}* noundef nonnull align 16 dereferenceable(40) %1, {}* noundef nonnull align 16 dereferenceable(40) %2, double %3, i64 signext %4) #0 {
top:
  switch i64 %4, label %L37 [
    i64 1, label %L3
    i64 2, label %L7
    i64 3, label %L11
    i64 4, label %L15
    i64 5, label %L19
    i64 6, label %L23
    i64 7, label %L27
    i64 8, label %L31
    i64 9, label %L35
  ]

L3:                                               ; preds = %top
  call void @j_f_279({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable

L7:                                               ; preds = %top
  call void @j_f_280({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable

L11:                                              ; preds = %top
  call void @j_f_281({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable

L15:                                              ; preds = %top
  call void @j_f_282({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable

L19:                                              ; preds = %top
  call void @j_f_283({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable

L23:                                              ; preds = %top
  call void @j_f_284({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable

L27:                                              ; preds = %top
  call void @j_f_285({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable

L31:                                              ; preds = %top
  call void @j_f_286({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable

L35:                                              ; preds = %top
  call void @j_f_287({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable

L37:                                              ; preds = %top
  call void @j_f_288({}* nonnull %0, {}* nonnull %1, {}* nonnull %2, double %3) #6
  unreachable
}

Is there some reason for this? I don’t have too much knowledge about processors/codegen in general, so I would appreciate some enlightenment.

@nif transforms an expression into an if statement with near-duplicate branches, that’s why you see 10 near-duplicates. The initial switch block just jumps to one of the branches. The “cleaner” call has 10 near-duplicate branches that are unreachable because the compiler knows that (0.1a + 0.5b) + 2c when c is a scalar lacks an implementation method. Elementwise operations, especially between instances with different dimensions, are usually done with dot syntax broadcasting .+; a few non-broadcasted elementwise matrix-matrix and vector-vector operations are only supported for the sake of linear algebra.

Sorry, I messed up that function. However, I think the @noinline stops the compiler from reasoning about the contents of f. Anyway, even with

@noinline f(x, a, b, c, ::Val{N}) where N = x * N

which is valid code that does not error, this still happens.

EDIT: simplified further. also, a small modification to return a tuple triggers the duplication.

@noinline f(x, a, b, c, ::Val{N}) where N = (x * N, N)

This is true for some other cases but it has nothing to do with the duplicated unreachable branches of the erroring call and is already present in the working call you posted. All the getelementpr are just preparing for the call nonnull ... non-inlined function call.

Of course changes to f don’t affect the duplication because it is the @nif in testvt that duplicates code across if-statement branches.

Ok, I think I read this too hastily

as saying that the cleaner call is so because f will error as I neglected a broadcast, leading to unreachable branches in testvt and no getelementptrs.

IIRC, what you meant is that the function calls of different methods of f along with the getelementptrs etc. that prepare for the calls or unreachables are copy-pasted into the if-else blocks.

In this case, if c=1., f is just called in a nicer way. I mistakenly assumed that they were all called the same way, and that the prep for testvt with c=1. was brought to the top, although there isn’t any prep now that I look at it again.

But then I have two questions:

  1. How does Julia decide which method (EDIT: in code_llvm, directly call … or to do something like %5 = alloca [5 x {}*], align 8 and store things in .sub, then calling a function with that as an argument) is used to call a function?
  2. Is there a reason the compiler / optimizer is unable to detect that most of the preparations for these function calls are identical, and hoist some getelementptrs and stores / unreachable out, or is it not good for the compiler to do that, or just that someone hasn’t written a compiler pass for a niche case yet?

The call-time types of the callable and the arguments are used to find the most specific method signature, if it exists, and compile the method for those types. In this case it’s done at compile-time per branch so you only see the function pointers being accessed. I don’t know the internals.

I’d guess this but not sure; it doesn’t seem worth examining all branches of an if-statement on the off-chance that you can hoist and merge the cheap arguments-loading phase of a function call. As far as I can tell, the @nif if-statement lacks an argument for a custom else clause so it does 9 cases k in 1:9 and does the call with Val(10) for an else clause, so the argument loading (store, getelementpr) does seem inevitable and identical. The calls to separately compiled code and unreachable must be specific to each branch.

What’s the purpose of @noinline here?

In this example, I just wanted to prevent the inling of f, so that it is called from testvt. I didn’t realize it wasn’t going to (completely) inline anyway. I guess it also prevented this from happening:

no noinline
julia> f(x, a, b, c, ::Val{N}) where N = x * N
f (generic function with 1 method)

julia> @code_llvm testvt(x, a, b, c, 10)
;  @ REPL[32]:1 within `testvt`
; Function Attrs: uwtable
define nonnull {}* @julia_testvt_1193({}* noundef nonnull align 16 dereferenceable(40) %0, {}* noundef nonnull align 16 dereferenceable(40) %1, {}* noundef nonnull align 16 dereferenceable(40) %2, {}* noundef nonnull align 16 dereferenceable(40) %3, i64 signext %4) #0 {
top:
  switch i64 %4, label %L37 [
    i64 1, label %L3
    i64 2, label %L7
    i64 3, label %L11
    i64 4, label %L15
    i64 5, label %L19
    i64 6, label %L23
    i64 7, label %L27
    i64 8, label %L31
    i64 9, label %L35
  ]

common.ret:                                       ; preds = %L37, %L35, %L31, %L27, %L23, %L19, %L15, %L11, %L7, %L3
  %common.ret.op = phi {}* [ %5, %L3 ], [ %6, %L7 ], [ %7, %L11 ], [ %8, %L15 ], [ %9, %L19 ], [ %10, %L23 ], [ %11, %L27 ], [ %12, %L31 ], [ %13, %L35 ], [ %14, %L37 ]
  ret {}* %common.ret.op

L3:                                               ; preds = %top
; ┌ @ REPL[27]:1 within `f`
   %5 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 1)
   br label %common.ret

L7:                                               ; preds = %top
   %6 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 2)
   br label %common.ret

L11:                                              ; preds = %top
   %7 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 3)
   br label %common.ret

L15:                                              ; preds = %top
   %8 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 4)
   br label %common.ret

L19:                                              ; preds = %top
   %9 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 5)
   br label %common.ret

L23:                                              ; preds = %top
   %10 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 6)
   br label %common.ret

L27:                                              ; preds = %top
   %11 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 7)
   br label %common.ret

L31:                                              ; preds = %top
   %12 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 8)
   br label %common.ret

L35:                                              ; preds = %top
   %13 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 9)
   br label %common.ret

L37:                                              ; preds = %top
   %14 = call nonnull {}* @"j_*_1195"({}* nonnull %0, i64 signext 10)
   br label %common.ret
; └
}

vs

with noinline
julia> @noinline f(x, a, b, c, ::Val{N}) where N = x * N
f (generic function with 1 method)

julia> @code_llvm testvt(x, a, b, c, 10)
;  @ REPL[32]:1 within `testvt`
; Function Attrs: uwtable
define nonnull {}* @julia_testvt_1196({}* noundef nonnull align 16 dereferenceable(40) %0, {}* noundef nonnull align 16 dereferenceable(40) %1, {}* noundef nonnull align 16 dereferenceable(40) %2, {}* noundef nonnull align 16 dereferenceable(40) %3, i64 signext %4) #0 {
top:
  %5 = alloca [5 x {}*], align 8
  %.sub = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 0
  switch i64 %4, label %L37 [
    i64 1, label %L3
    i64 2, label %L7
    i64 3, label %L11
    i64 4, label %L15
    i64 5, label %L19
    i64 6, label %L23
    i64 7, label %L27
    i64 8, label %L31
    i64 9, label %L35
  ]

common.ret:                                       ; preds = %L37, %L35, %L31, %L27, %L23, %L19, %L15, %L11, %L7, %L3
  %common.ret.op = phi {}* [ %10, %L3 ], [ %15, %L7 ], [ %20, %L11 ], [ %25, %L15 ], [ %30, %L19 ], [ %35, %L23 ], [ %40, %L27 ], [ %45, %L31 ], [ %50, %L35 ], [ %55, %L37 ]
  ret {}* %common.ret.op

L3:                                               ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %6 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %6, align 8
  %7 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %7, align 8
  %8 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %8, align 8
  %9 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735629256912 to {}*), {}** %9, align 8
  %10 = call nonnull {}* @j1_f_1198({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L7:                                               ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %11 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %11, align 8
  %12 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %12, align 8
  %13 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %13, align 8
  %14 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735629260064 to {}*), {}** %14, align 8
  %15 = call nonnull {}* @j1_f_1199({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L11:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %16 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %16, align 8
  %17 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %17, align 8
  %18 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %18, align 8
  %19 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735644336864 to {}*), {}** %19, align 8
  %20 = call nonnull {}* @j1_f_1200({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L15:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %21 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %21, align 8
  %22 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %22, align 8
  %23 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %23, align 8
  %24 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735642869104 to {}*), {}** %24, align 8
  %25 = call nonnull {}* @j1_f_1201({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L19:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %26 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %26, align 8
  %27 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %27, align 8
  %28 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %28, align 8
  %29 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735644338720 to {}*), {}** %29, align 8
  %30 = call nonnull {}* @j1_f_1202({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L23:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %31 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %31, align 8
  %32 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %32, align 8
  %33 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %33, align 8
  %34 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735644340288 to {}*), {}** %34, align 8
  %35 = call nonnull {}* @j1_f_1203({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L27:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %36 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %36, align 8
  %37 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %37, align 8
  %38 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %38, align 8
  %39 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 2458706370536 to {}*), {}** %39, align 8
  %40 = call nonnull {}* @j1_f_1204({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L31:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %41 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %41, align 8
  %42 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %42, align 8
  %43 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %43, align 8
  %44 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 2458706335712 to {}*), {}** %44, align 8
  %45 = call nonnull {}* @j1_f_1205({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L35:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %46 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %46, align 8
  %47 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %47, align 8
  %48 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %48, align 8
  %49 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735641117360 to {}*), {}** %49, align 8
  %50 = call nonnull {}* @j1_f_1206({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret

L37:                                              ; preds = %top
  store {}* %0, {}** %.sub, align 8
  %51 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 1
  store {}* %1, {}** %51, align 8
  %52 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 2
  store {}* %2, {}** %52, align 8
  %53 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 3
  store {}* %3, {}** %53, align 8
  %54 = getelementptr inbounds [5 x {}*], [5 x {}*]* %5, i64 0, i64 4
  store {}* inttoptr (i64 140735649310864 to {}*), {}** %54, align 8
  %55 = call nonnull {}* @j1_f_1207({}* inttoptr (i64 2458706367760 to {}*), {}** nonnull %.sub, i32 5)
  br label %common.ret
}

Or did you mean something else?