It can do that in certain circumstances. Note the ret i8 1
, i.e. return the constant 1
(which is equivalent to true
here) at the end of code_llvm
:
; Function Signature: foo(Int64, Int64, Base.RefValue{Any})
; @ REPL[1]:1 within `foo`
define i8 @julia_foo_1525(i64 signext %"s::Int64", i64 signext %"ss::Int64", ptr noundef nonnull align 8 dereferenceable(8) %"func::RefValue") #0 {
top:
%gcframe1 = alloca [3 x ptr], align 16
call void @llvm.memset.p0.i64(ptr align 16 %gcframe1, i8 0, i64 24, i1 true)
%thread_ptr = call ptr asm "movq %fs:0, $0", "=r"() #8
%tls_ppgcstack = getelementptr i8, ptr %thread_ptr, i64 -8
%tls_pgcstack = load ptr, ptr %tls_ppgcstack, align 8
store i64 4, ptr %gcframe1, align 16
%frame.prev = getelementptr inbounds ptr, ptr %gcframe1, i64 1
%task.gcstack = load ptr, ptr %tls_pgcstack, align 8
store ptr %task.gcstack, ptr %frame.prev, align 8
store ptr %gcframe1, ptr %tls_pgcstack, align 8
; @ REPL[1]:3 within `foo`
; ┌ @ refvalue.jl:59 within `getindex`
; │┌ @ Base.jl:49 within `getproperty`
%"func::RefValue.x" = load atomic ptr, ptr %"func::RefValue" unordered, align 8
%.not = icmp eq ptr %"func::RefValue.x", null
br i1 %.not, label %fail, label %pass
fail: ; preds = %top
%jl_undefref_exception = load ptr, ptr @jl_undefref_exception, align 8
call void @ijl_throw(ptr nonnull %jl_undefref_exception)
unreachable
pass: ; preds = %top
%gc_slot_addr_0 = getelementptr inbounds ptr, ptr %gcframe1, i64 2
store ptr %"func::RefValue.x", ptr %gc_slot_addr_0, align 16
; └└
%0 = call nonnull ptr @ijl_apply_generic(ptr nonnull %"func::RefValue.x", ptr null, i32 0)
%frame.prev6 = load ptr, ptr %frame.prev, align 8
store ptr %frame.prev6, ptr %tls_pgcstack, align 8
; @ REPL[1]:5 within `foo`
ret i8 1
}
It can’t eliminate the call to func[]()
because of the Any
, which is all of the other stuff. After all, that call may modify some invisible state.