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
  • Loading branch information
gbaraldi committed Jun 5, 2024
1 parent 30542e0 commit 702842f
Show file tree
Hide file tree
Showing 3 changed files with 123 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
19 changes: 14 additions & 5 deletions test/compiler/codegen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -939,11 +939,20 @@ BigStructAnyInt() = BigStructAnyInt((Union{Base.inferencebarrier(Float64), Int}=
@test egal_any54109(Torture2_54109(), Torture2_54109())
@test !egal_any54109(Torture1_54109(), Torture1_54109((DefaultOr54109(2.0, false) for i = 1:897)...))

bar54599() = Base.inferencebarrier(true) ? (Base.PkgId(Main),1) : nothing

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 foonopred()
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 @@ -18,23 +18,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 @@ -51,24 +51,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 @@ -79,26 +79,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 @@ -111,24 +115,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 @@ -137,19 +142,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 @@ -166,26 +171,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 702842f

Please sign in to comment.