I believe the kind of pattern you show up top will be compiled to a switch and then jump table (via Julia and LLVM respectively), much like I assume a Fortran compiler could.
Edit: it doesn’t generate a jump table, but I wasn’t able to coax gfortran to create one either on Godbolt. If someone figures out how to, please let me know
Adapting that example:
step11(it) = print("step11", it)
step12(it) = print("step12", it)
function steps(it)
if it === 11
step11(it)
elseif it === 12
step12(it)
else
throw("illegal value $it")
end
return
end
@code_llvm steps(1)
clearly shows a jump table being constructed:
define void @julia_steps_214(i64 signext %0) #0 {
top:
%1 = alloca [2 x {}*], align 8
%gcframe3 = alloca [3 x {}*], align 16
%gcframe3.sub = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe3, i64 0, i64 0
%.sub = getelementptr inbounds [2 x {}*], [2 x {}*]* %1, i64 0, i64 0
%2 = bitcast [3 x {}*]* %gcframe3 to i8*
call void @llvm.memset.p0i8.i32(i8* nonnull align 16 dereferenceable(24) %2, i8 0, i32 24, i1 false)
%thread_ptr = call i8* asm "movq %fs:0, $0", "=r"() #8
%ppgcstack_i8 = getelementptr i8, i8* %thread_ptr, i64 -8
%ppgcstack = bitcast i8* %ppgcstack_i8 to {}****
%pgcstack = load {}***, {}**** %ppgcstack, align 8
; @ REPL[3]:2 within `steps`
%3 = bitcast [3 x {}*]* %gcframe3 to i64*
store i64 4, i64* %3, align 16
%4 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe3, i64 0, i64 1
%5 = bitcast {}** %4 to {}***
%6 = load {}**, {}*** %pgcstack, align 8
store {}** %6, {}*** %5, align 8
%7 = bitcast {}*** %pgcstack to {}***
store {}** %gcframe3.sub, {}*** %7, align 8
switch i64 %0, label %L11 [
i64 11, label %L3
i64 12, label %L8
]
L3: ; preds = %top
; @ REPL[3]:3 within `steps`
; ┌ @ REPL[1]:1 within `step11`
call void @j_print_216({}* inttoptr (i64 140108222856496 to {}*), i64 signext 11) #0
; └
br label %L14
L8: ; preds = %top
; @ REPL[3]:5 within `steps`
; ┌ @ REPL[2]:1 within `step12`
call void @j_print_217({}* inttoptr (i64 140108217624080 to {}*), i64 signext 12) #0
; └
br label %L14
L11: ; preds = %top
; @ REPL[3]:7 within `steps`
%8 = call nonnull {}* @jl_box_int64(i64 signext %0)
%9 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe3, i64 0, i64 2
store {}* %8, {}** %9, align 16
store {}* inttoptr (i64 140108212808048 to {}*), {}** %.sub, align 8
%10 = getelementptr inbounds [2 x {}*], [2 x {}*]* %1, i64 0, i64 1
store {}* %8, {}** %10, align 8
%11 = call nonnull {}* @jl_apply_generic({}* inttoptr (i64 140108035749248 to {}*), {}** nonnull %.sub, i32 2)
call void @jl_throw({}* %11)
unreachable
L14: ; preds = %L8, %L3
%12 = load {}*, {}** %4, align 8
%13 = bitcast {}*** %pgcstack to {}**
store {}* %12, {}** %13, align 8
; @ REPL[3]:9 within `steps`
ret void
}
See Computed goto (or labels as values) in Julia? for more.
For a terser way of switching on values, have a look into https://github.com/thautwarm/MLStyle.jl:
using MLStyle
...
function steps_match(it)
@match it begin
11 => step11(it)
12 => step12(it)
_ => throw("illegal value $it")
end
return
end
I’ve verified that this also generates a switch at the LLVM level.