Skip to content

Commit

Permalink
Fix assertion/crash when optimizing function with dead basic block (#…
Browse files Browse the repository at this point in the history
…54690)

AllocOpt probably needs to handle that in other places more smartly but
this seems to at least stop it crashing. Fixes issue found in
#54604 (comment) by
@topolarity.

(cherry picked from commit 5cb1107)
  • Loading branch information
gbaraldi authored and KristofferC committed Jun 7, 2024
1 parent 5cba5da commit a8f84ef
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 84 deletions.
2 changes: 2 additions & 0 deletions src/llvm-alloc-opt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,8 @@ void Optimizer::insertLifetime(Value *ptr, Constant *sz, Instruction *orig)
auto bb = use->getParent();
if (!bbs.insert(bb).second)
continue;
if (pred_empty(bb))
continue; // No predecessors so the block is dead
assert(lifetime_stack.empty());
Lifetime::Frame cur{bb};
while (true) {
Expand Down
17 changes: 12 additions & 5 deletions test/compiler/codegen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -889,10 +889,17 @@ dims54166 = (1,2)
@test (minimum(ex54166; dims=dims54166)[1] === missing)

function foo54599()
pkgid = Base.identify_package("Test")
println(devnull,pkgid)
println(devnull, pkgid.uuid)
pkgid.uuid
pkginfo = @noinline bar54599()
pkgid = pkginfo !== nothing ? pkginfo[1] : nothing
@noinline println(devnull, pkgid)
pkgid.uuid !== nothing ? pkgid.uuid : false
end

@test foo54599() !== nothing
#this function used to crash allocopt due to a no predecessors bug
barnopreds() = Base.inferencebarrier(true) ? (Base.PkgId(Test),1) : nothing
function foonopreds()
pkginfo = @noinline barnopreds()
pkgid = pkginfo !== nothing ? pkginfo[1] : nothing
pkgid.uuid !== nothing ? pkgid.uuid : false
end
@test foonopreds() !== nothing
186 changes: 107 additions & 79 deletions test/llvmpasses/alloc-opt-pass.ll
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,23 @@
; CHECK-NEXT: br label %L3

; CHECK: L3:
define void @preserve_branches(i8* %fptr, i1 %b, i1 %b2) {
%pgcstack = call {}*** @julia.get_pgcstack()
%ptls = call {}*** @julia.ptls_states()
%ptls_i8 = bitcast {}*** %ptls to i8*
define void @preserve_branches(ptr %fptr, i1 %b, i1 %b2) {
%pgcstack = call ptr @julia.get_pgcstack()
%ptls = call ptr @julia.ptls_states()
%ptls_i8 = bitcast ptr %ptls to ptr
br i1 %b, label %L1, label %L3

L1:
%v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 8, {} addrspace(10)* @tag)
%tok = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* nonnull %v)
L1: ; preds = %0
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
%tok = call token (...) @llvm.julia.gc_preserve_begin(ptr addrspace(10) nonnull %v)
call void @external_function()
br i1 %b2, label %L2, label %L3

L2:
L2: ; preds = %L1
call void @external_function()
br label %L3

L3:
L3: ; preds = %L2, %L1, %0
ret void
}
; CHECK-LABEL: }{{$}}
Expand All @@ -56,24 +56,24 @@ L3:
; CHECK-NEXT: br label %L3

; CHECK: L3:
define void @preserve_branches2(i8* %fptr, i1 %b, i1 %b2) {
%pgcstack = call {}*** @julia.get_pgcstack()
%ptls = call {}*** @julia.ptls_states()
%ptls_i8 = bitcast {}*** %ptls to i8*
%v2 = call {} addrspace(10)* @external_function2()
define void @preserve_branches2(ptr %fptr, i1 %b, i1 %b2) {
%pgcstack = call ptr @julia.get_pgcstack()
%ptls = call ptr @julia.ptls_states()
%ptls_i8 = bitcast ptr %ptls to ptr
%v2 = call ptr addrspace(10) @external_function2()
br i1 %b, label %L1, label %L3

L1:
%v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 8, {} addrspace(10)* @tag)
%tok = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %v, {} addrspace(10)* nonnull %v2)
L1: ; preds = %0
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
%tok = call token (...) @llvm.julia.gc_preserve_begin(ptr addrspace(10) %v, ptr addrspace(10) nonnull %v2)
call void @external_function()
br i1 %b2, label %L2, label %L3

L2:
L2: ; preds = %L1
call void @external_function()
br label %L3

L3:
L3: ; preds = %L2, %L1, %0
ret void
}
; CHECK-LABEL: }{{$}}
Expand All @@ -84,26 +84,30 @@ L3:
; CHECK: store [12 x i8] zeroinitializer,
; CHECK: ret void
define void @legal_int_types() {
%pgcstack = call {}*** @julia.get_pgcstack()
%ptls = call {}*** @julia.ptls_states()
%ptls_i8 = bitcast {}*** %ptls to i8*
%var1 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 12, {} addrspace(10)* @tag)
%var2 = addrspacecast {} addrspace(10)* %var1 to {} addrspace(11)*
%var3 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var2)
%pgcstack = call ptr @julia.get_pgcstack()
%ptls = call ptr @julia.ptls_states()
%ptls_i8 = bitcast ptr %ptls to ptr
%var1 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 12, ptr addrspace(10) @tag)
%var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11)
%var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2)
ret void
}
; CHECK-LABEL: }{{$}}


declare void @external_function()
declare {} addrspace(10)* @external_function2()
declare {}*** @julia.ptls_states()
declare {}*** @julia.get_pgcstack()
declare noalias {} addrspace(10)* @julia.gc_alloc_obj(i8*, i64, {} addrspace(10)*)
declare {}* @julia.pointer_from_objref({} addrspace(11)*)
declare void @llvm.memcpy.p11i8.p0i8.i64(i8 addrspace(11)* nocapture writeonly, i8* nocapture readonly, i64, i32, i1)
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1)

declare ptr addrspace(10) @external_function2()

declare ptr @julia.ptls_states()

declare ptr @julia.get_pgcstack()

declare noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr, i64, ptr addrspace(10))

declare ptr @julia.pointer_from_objref(ptr addrspace(11))

declare token @llvm.julia.gc_preserve_begin(...)

declare void @llvm.julia.gc_preserve_end(token)

; CHECK-LABEL: @memref_collision
Expand All @@ -120,24 +124,25 @@ declare void @llvm.julia.gc_preserve_end(token)
; CHECK: L2:
; CHECK: load i
define void @memref_collision(i64 %x) {
%pgcstack = call {}*** @julia.get_pgcstack()
%ptls = call {}*** @julia.ptls_states()
%ptls_i8 = bitcast {}*** %ptls to i8*
%v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 8, {} addrspace(10)* @tag)
%v_p = bitcast {} addrspace(10)* %v to i64 addrspace(10)*
store i64 %x, i64 addrspace(10)* %v_p
br i1 0, label %L1, label %L2

L1:
%v1 = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)*
%v1_x = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %v1
%pgcstack = call ptr @julia.get_pgcstack()
%ptls = call ptr @julia.ptls_states()
%ptls_i8 = bitcast ptr %ptls to ptr
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
%v_p = bitcast ptr addrspace(10) %v to ptr addrspace(10)
store i64 %x, ptr addrspace(10) %v_p, align 4
br i1 false, label %L1, label %L2

L1: ; preds = %0
%v1 = bitcast ptr addrspace(10) %v to ptr addrspace(10)
%v1_x = load ptr addrspace(10), ptr addrspace(10) %v1, align 8
ret void

L2:
%v2 = bitcast {} addrspace(10)* %v to i64 addrspace(10)*
%v2_x = load i64, i64 addrspace(10)* %v2
L2: ; preds = %0
%v2 = bitcast ptr addrspace(10) %v to ptr addrspace(10)
%v2_x = load i64, ptr addrspace(10) %v2, align 4
ret void
}

; CHECK-LABEL: }{{$}}

; CHECK-LABEL: @lifetime_no_preserve_end
Expand All @@ -146,19 +151,19 @@ L2:
; CHECK: call void @llvm.lifetime.start
; CHECK: store [8 x i8] zeroinitializer,
; CHECK-NOT: call void @llvm.lifetime.end
define void @lifetime_no_preserve_end({}* noalias nocapture noundef nonnull sret({}) %0) {
%pgcstack = call {}*** @julia.get_pgcstack()
%ptls = call {}*** @julia.ptls_states()
%ptls_i8 = bitcast {}*** %ptls to i8*
%v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 8, {} addrspace(10)* @tag)
%token = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %v)
%v_derived = addrspacecast {} addrspace(10)* %v to {} addrspace(11)*
%ptr = call nonnull {}* @julia.pointer_from_objref({} addrspace(11)* %v_derived)
%ptr_raw = bitcast {}* %ptr to i8*
call void @external_function() ; safepoint
%ret_raw = bitcast {}* %0 to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %ret_raw, i8 * align 8 %ptr_raw, i64 0, i1 false)
%ret_raw2 = bitcast {}* %0 to i8*
define void @lifetime_no_preserve_end(ptr noalias nocapture noundef nonnull sret({}) %0) {
%pgcstack = call ptr @julia.get_pgcstack()
%ptls = call ptr @julia.ptls_states()
%ptls_i8 = bitcast ptr %ptls to ptr
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
%token = call token (...) @llvm.julia.gc_preserve_begin(ptr addrspace(10) %v)
%v_derived = addrspacecast ptr addrspace(10) %v to ptr addrspace(11)
%ptr = call nonnull ptr @julia.pointer_from_objref(ptr addrspace(11) %v_derived)
%ptr_raw = bitcast ptr %ptr to ptr
call void @external_function()
%ret_raw = bitcast ptr %0 to ptr
call void @llvm.memcpy.p0.p0.i64(ptr align 8 %ret_raw, ptr align 8 %ptr_raw, i64 0, i1 false)
%ret_raw2 = bitcast ptr %0 to ptr
ret void
}
; CHECK-LABEL: }{{$}}
Expand All @@ -175,26 +180,49 @@ define void @lifetime_no_preserve_end({}* noalias nocapture noundef nonnull sret
; CHECK-NOT: zeroinitializer
; CHECK: ret void
define void @initializers() {
%pgcstack = call {}*** @julia.get_pgcstack()
%ptls = call {}*** @julia.ptls_states()
%ptls_i8 = bitcast {}*** %ptls to i8*

%var1 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 1, {} addrspace(10)* @tag) #0
%var2 = addrspacecast {} addrspace(10)* %var1 to {} addrspace(11)*
%var3 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var2)

%var4 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 2, {} addrspace(10)* @tag) #1
%var5 = addrspacecast {} addrspace(10)* %var4 to {} addrspace(11)*
%var6 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var5)

%var7 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 3, {} addrspace(10)* @tag) #2
%var8 = addrspacecast {} addrspace(10)* %var7 to {} addrspace(11)*
%var9 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var8)

%pgcstack = call ptr @julia.get_pgcstack()
%ptls = call ptr @julia.ptls_states()
%ptls_i8 = bitcast ptr %ptls to ptr
%var1 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 1, ptr addrspace(10) @tag) #1
%var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11)
%var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2)
%var4 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 2, ptr addrspace(10) @tag) #2
%var5 = addrspacecast ptr addrspace(10) %var4 to ptr addrspace(11)
%var6 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var5)
%var7 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 3, ptr addrspace(10) @tag) #3
%var8 = addrspacecast ptr addrspace(10) %var7 to ptr addrspace(11)
%var9 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var8)
ret void
}
; CHECK-LABEL: }{{$}}

attributes #0 = { allockind("alloc") }
attributes #1 = { allockind("alloc,uninitialized") }
attributes #2 = { allockind("alloc,zeroed") }
; Test that the pass handles dead basic blocks with references to the allocation
; CHECK-LABEL: @nopreds
; CHECK: alloca i8, i64 0, align 1
; CHECK: call void @llvm.lifetime.start
define swiftcc { ptr addrspace(10), i8 } @nopreds() {
top:
%0 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr null, i64 0, ptr addrspace(10) null)
%1 = addrspacecast ptr addrspace(10) %0 to ptr addrspace(11)
br label %common.ret

common.ret: ; preds = %union_move9, %top
ret { ptr addrspace(10), i8 } zeroinitializer

union_move9: ; No predecessors!
call void @llvm.memcpy.p0.p11.i64(ptr null, ptr addrspace(11) %1, i64 0, i1 false)
br label %common.ret
}
; CHECK-LABEL: }{{$}}

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memcpy.p11.p0.i64(ptr addrspace(11) noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memcpy.p0.p11.i64(ptr noalias nocapture writeonly, ptr addrspace(11) noalias nocapture readonly, i64, i1 immarg) #0
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0

attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #1 = { allockind("alloc") }
attributes #2 = { allockind("alloc,uninitialized") }
attributes #3 = { allockind("alloc,zeroed") }

0 comments on commit a8f84ef

Please sign in to comment.