Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix assertion/crash when optimizing function with dead basic block #54690

Merged
merged 2 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
topolarity marked this conversation as resolved.
Show resolved Hide resolved
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 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 @@ -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") }