Skip to content

Commit 6ee9546

Browse files
gbaraldiKristofferC
authored andcommitted
Fix assertion/crash when optimizing function with dead basic block (#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)
1 parent 4b063cf commit 6ee9546

File tree

3 files changed

+116
-60
lines changed

3 files changed

+116
-60
lines changed

src/llvm-alloc-opt.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ void Optimizer::insertLifetime(Value *ptr, Constant *sz, Instruction *orig)
400400
auto bb = use->getParent();
401401
if (!bbs.insert(bb).second)
402402
continue;
403+
if (pred_empty(bb))
404+
continue; // No predecessors so the block is dead
403405
assert(lifetime_stack.empty());
404406
Lifetime::Frame cur{bb};
405407
while (true) {

test/compiler/codegen.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,3 +852,21 @@ end
852852
# https://github.com/JuliaLang/julia/issues/51233
853853
obj51233 = (1,)
854854
@test_throws ErrorException obj51233.x
855+
856+
bar54599() = Base.inferencebarrier(true) ? (Base.PkgId(Main),1) : nothing
857+
858+
function foo54599()
859+
pkginfo = @noinline bar54599()
860+
pkgid = pkginfo !== nothing ? pkginfo[1] : nothing
861+
@noinline println(devnull, pkgid)
862+
pkgid.uuid !== nothing ? pkgid.uuid : false
863+
end
864+
865+
#this function used to crash allocopt due to a no predecessors bug
866+
barnopreds() = Base.inferencebarrier(true) ? (Base.PkgId(Test),1) : nothing
867+
function foonopreds()
868+
pkginfo = @noinline barnopreds()
869+
pkgid = pkginfo !== nothing ? pkginfo[1] : nothing
870+
pkgid.uuid !== nothing ? pkgid.uuid : false
871+
end
872+
@test foonopreds() !== nothing

test/llvmpasses/alloc-opt-pass.ll

Lines changed: 96 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,23 @@
2323
; CHECK-NEXT: br label %L3
2424

2525
; CHECK: L3:
26-
define void @preserve_branches(i8* %fptr, i1 %b, i1 %b2) {
27-
%pgcstack = call {}*** @julia.get_pgcstack()
28-
%ptls = call {}*** @julia.ptls_states()
29-
%ptls_i8 = bitcast {}*** %ptls to i8*
26+
define void @preserve_branches(ptr %fptr, i1 %b, i1 %b2) {
27+
%pgcstack = call ptr @julia.get_pgcstack()
28+
%ptls = call ptr @julia.ptls_states()
29+
%ptls_i8 = bitcast ptr %ptls to ptr
3030
br i1 %b, label %L1, label %L3
3131

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

38-
L2:
38+
L2: ; preds = %L1
3939
call void @external_function()
4040
br label %L3
4141

42-
L3:
42+
L3: ; preds = %L2, %L1, %0
4343
ret void
4444
}
4545
; CHECK-LABEL: }{{$}}
@@ -58,24 +58,24 @@ L3:
5858
; CHECK-NEXT: br label %L3
5959

6060
; CHECK: L3:
61-
define void @preserve_branches2(i8* %fptr, i1 %b, i1 %b2) {
62-
%pgcstack = call {}*** @julia.get_pgcstack()
63-
%ptls = call {}*** @julia.ptls_states()
64-
%ptls_i8 = bitcast {}*** %ptls to i8*
65-
%v2 = call {} addrspace(10)* @external_function2()
61+
define void @preserve_branches2(ptr %fptr, i1 %b, i1 %b2) {
62+
%pgcstack = call ptr @julia.get_pgcstack()
63+
%ptls = call ptr @julia.ptls_states()
64+
%ptls_i8 = bitcast ptr %ptls to ptr
65+
%v2 = call ptr addrspace(10) @external_function2()
6666
br i1 %b, label %L1, label %L3
6767

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

74-
L2:
74+
L2: ; preds = %L1
7575
call void @external_function()
7676
br label %L3
7777

78-
L3:
78+
L3: ; preds = %L2, %L1, %0
7979
ret void
8080
}
8181
; CHECK-LABEL: }{{$}}
@@ -85,26 +85,30 @@ L3:
8585
; CHECK-NOT: alloca i96
8686
; CHECK: ret void
8787
define void @legal_int_types() {
88-
%pgcstack = call {}*** @julia.get_pgcstack()
89-
%ptls = call {}*** @julia.ptls_states()
90-
%ptls_i8 = bitcast {}*** %ptls to i8*
91-
%var1 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 12, {} addrspace(10)* @tag)
92-
%var2 = addrspacecast {} addrspace(10)* %var1 to {} addrspace(11)*
93-
%var3 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var2)
88+
%pgcstack = call ptr @julia.get_pgcstack()
89+
%ptls = call ptr @julia.ptls_states()
90+
%ptls_i8 = bitcast ptr %ptls to ptr
91+
%var1 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 12, ptr addrspace(10) @tag)
92+
%var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11)
93+
%var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2)
9494
ret void
9595
}
9696
; CHECK-LABEL: }{{$}}
9797

98-
9998
declare void @external_function()
100-
declare {} addrspace(10)* @external_function2()
101-
declare {}*** @julia.ptls_states()
102-
declare {}*** @julia.get_pgcstack()
103-
declare noalias {} addrspace(10)* @julia.gc_alloc_obj(i8*, i64, {} addrspace(10)*)
104-
declare {}* @julia.pointer_from_objref({} addrspace(11)*)
105-
declare void @llvm.memcpy.p11i8.p0i8.i64(i8 addrspace(11)* nocapture writeonly, i8* nocapture readonly, i64, i32, i1)
106-
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1)
99+
100+
declare ptr addrspace(10) @external_function2()
101+
102+
declare ptr @julia.ptls_states()
103+
104+
declare ptr @julia.get_pgcstack()
105+
106+
declare noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr, i64, ptr addrspace(10))
107+
108+
declare ptr @julia.pointer_from_objref(ptr addrspace(11))
109+
107110
declare token @llvm.julia.gc_preserve_begin(...)
111+
108112
declare void @llvm.julia.gc_preserve_end(token)
109113

110114
; CHECK-LABEL: @memref_collision
@@ -121,44 +125,76 @@ declare void @llvm.julia.gc_preserve_end(token)
121125
; CHECK: L2:
122126
; CHECK: load i
123127
define void @memref_collision(i64 %x) {
124-
%pgcstack = call {}*** @julia.get_pgcstack()
125-
%ptls = call {}*** @julia.ptls_states()
126-
%ptls_i8 = bitcast {}*** %ptls to i8*
127-
%v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 8, {} addrspace(10)* @tag)
128-
%v_p = bitcast {} addrspace(10)* %v to i64 addrspace(10)*
129-
store i64 %x, i64 addrspace(10)* %v_p
130-
br i1 0, label %L1, label %L2
131-
132-
L1:
133-
%v1 = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)*
134-
%v1_x = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %v1
128+
%pgcstack = call ptr @julia.get_pgcstack()
129+
%ptls = call ptr @julia.ptls_states()
130+
%ptls_i8 = bitcast ptr %ptls to ptr
131+
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
132+
%v_p = bitcast ptr addrspace(10) %v to ptr addrspace(10)
133+
store i64 %x, ptr addrspace(10) %v_p, align 4
134+
br i1 false, label %L1, label %L2
135+
136+
L1: ; preds = %0
137+
%v1 = bitcast ptr addrspace(10) %v to ptr addrspace(10)
138+
%v1_x = load ptr addrspace(10), ptr addrspace(10) %v1, align 8
135139
ret void
136140

137-
L2:
138-
%v2 = bitcast {} addrspace(10)* %v to i64 addrspace(10)*
139-
%v2_x = load i64, i64 addrspace(10)* %v2
141+
L2: ; preds = %0
142+
%v2 = bitcast ptr addrspace(10) %v to ptr addrspace(10)
143+
%v2_x = load i64, ptr addrspace(10) %v2, align 4
140144
ret void
141145
}
146+
142147
; CHECK-LABEL: }{{$}}
143148

144149
; CHECK-LABEL: @lifetime_no_preserve_end
145150
; CHECK: alloca
146151
; CHECK-NOT: call token(...) @llvm.julia.gc_preserve_begin
147152
; CHECK: call void @llvm.lifetime.start
148153
; CHECK-NOT: call void @llvm.lifetime.end
149-
define void @lifetime_no_preserve_end({}* noalias nocapture noundef nonnull sret({}) %0) {
150-
%pgcstack = call {}*** @julia.get_pgcstack()
151-
%ptls = call {}*** @julia.ptls_states()
152-
%ptls_i8 = bitcast {}*** %ptls to i8*
153-
%v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 8, {} addrspace(10)* @tag)
154-
%token = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %v)
155-
%v_derived = addrspacecast {} addrspace(10)* %v to {} addrspace(11)*
156-
%ptr = call nonnull {}* @julia.pointer_from_objref({} addrspace(11)* %v_derived)
157-
%ptr_raw = bitcast {}* %ptr to i8*
158-
call void @external_function() ; safepoint
159-
%ret_raw = bitcast {}* %0 to i8*
160-
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %ret_raw, i8 * align 8 %ptr_raw, i64 0, i1 false)
161-
%ret_raw2 = bitcast {}* %0 to i8*
154+
define void @lifetime_no_preserve_end(ptr noalias nocapture noundef nonnull sret({}) %0) {
155+
%pgcstack = call ptr @julia.get_pgcstack()
156+
%ptls = call ptr @julia.ptls_states()
157+
%ptls_i8 = bitcast ptr %ptls to ptr
158+
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
159+
%token = call token (...) @llvm.julia.gc_preserve_begin(ptr addrspace(10) %v)
160+
%v_derived = addrspacecast ptr addrspace(10) %v to ptr addrspace(11)
161+
%ptr = call nonnull ptr @julia.pointer_from_objref(ptr addrspace(11) %v_derived)
162+
%ptr_raw = bitcast ptr %ptr to ptr
163+
call void @external_function()
164+
%ret_raw = bitcast ptr %0 to ptr
165+
call void @llvm.memcpy.p0.p0.i64(ptr align 8 %ret_raw, ptr align 8 %ptr_raw, i64 0, i1 false)
166+
%ret_raw2 = bitcast ptr %0 to ptr
162167
ret void
163168
}
164169
; CHECK-LABEL: }{{$}}
170+
171+
; Test that the pass handles dead basic blocks with references to the allocation
172+
; CHECK-LABEL: @nopreds
173+
; CHECK: alloca i8, i64 0, align 1
174+
; CHECK: call void @llvm.lifetime.start
175+
define swiftcc { ptr addrspace(10), i8 } @nopreds() {
176+
top:
177+
%0 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr null, i64 0, ptr addrspace(10) null)
178+
%1 = addrspacecast ptr addrspace(10) %0 to ptr addrspace(11)
179+
br label %common.ret
180+
181+
common.ret: ; preds = %union_move9, %top
182+
ret { ptr addrspace(10), i8 } zeroinitializer
183+
184+
union_move9: ; No predecessors!
185+
call void @llvm.memcpy.p0.p11.i64(ptr null, ptr addrspace(11) %1, i64 0, i1 false)
186+
br label %common.ret
187+
}
188+
; CHECK-LABEL: }{{$}}
189+
190+
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
191+
declare void @llvm.memcpy.p11.p0.i64(ptr addrspace(11) noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
192+
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
193+
declare void @llvm.memcpy.p0.p11.i64(ptr noalias nocapture writeonly, ptr addrspace(11) noalias nocapture readonly, i64, i1 immarg) #0
194+
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
195+
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
196+
197+
attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
198+
attributes #1 = { allockind("alloc") }
199+
attributes #2 = { allockind("alloc,uninitialized") }
200+
attributes #3 = { allockind("alloc,zeroed") }

0 commit comments

Comments
 (0)