Skip to content

Commit e8662da

Browse files
gbaraldiKristofferC
authored and
KristofferC
committed
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 bab6633 commit e8662da

File tree

3 files changed

+121
-84
lines changed

3 files changed

+121
-84
lines changed

src/llvm-alloc-opt.cpp

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

test/compiler/codegen.jl

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -889,10 +889,17 @@ dims54166 = (1,2)
889889
@test (minimum(ex54166; dims=dims54166)[1] === missing)
890890

891891
function foo54599()
892-
pkgid = Base.identify_package("Test")
893-
println(devnull,pkgid)
894-
println(devnull, pkgid.uuid)
895-
pkgid.uuid
892+
pkginfo = @noinline bar54599()
893+
pkgid = pkginfo !== nothing ? pkginfo[1] : nothing
894+
@noinline println(devnull, pkgid)
895+
pkgid.uuid !== nothing ? pkgid.uuid : false
896896
end
897897

898-
@test foo54599() !== nothing
898+
#this function used to crash allocopt due to a no predecessors bug
899+
barnopreds() = Base.inferencebarrier(true) ? (Base.PkgId(Test),1) : nothing
900+
function foonopreds()
901+
pkginfo = @noinline barnopreds()
902+
pkgid = pkginfo !== nothing ? pkginfo[1] : nothing
903+
pkgid.uuid !== nothing ? pkgid.uuid : false
904+
end
905+
@test foonopreds() !== nothing

test/llvmpasses/alloc-opt-pass.ll

Lines changed: 107 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,23 @@
2121
; CHECK-NEXT: br label %L3
2222

2323
; CHECK: L3:
24-
define void @preserve_branches(i8* %fptr, i1 %b, i1 %b2) {
25-
%pgcstack = call {}*** @julia.get_pgcstack()
26-
%ptls = call {}*** @julia.ptls_states()
27-
%ptls_i8 = bitcast {}*** %ptls to i8*
24+
define void @preserve_branches(ptr %fptr, i1 %b, i1 %b2) {
25+
%pgcstack = call ptr @julia.get_pgcstack()
26+
%ptls = call ptr @julia.ptls_states()
27+
%ptls_i8 = bitcast ptr %ptls to ptr
2828
br i1 %b, label %L1, label %L3
2929

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

36-
L2:
36+
L2: ; preds = %L1
3737
call void @external_function()
3838
br label %L3
3939

40-
L3:
40+
L3: ; preds = %L2, %L1, %0
4141
ret void
4242
}
4343
; CHECK-LABEL: }{{$}}
@@ -56,24 +56,24 @@ L3:
5656
; CHECK-NEXT: br label %L3
5757

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

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

72-
L2:
72+
L2: ; preds = %L1
7373
call void @external_function()
7474
br label %L3
7575

76-
L3:
76+
L3: ; preds = %L2, %L1, %0
7777
ret void
7878
}
7979
; CHECK-LABEL: }{{$}}
@@ -84,26 +84,30 @@ L3:
8484
; CHECK: store [12 x i8] zeroinitializer,
8585
; CHECK: ret void
8686
define void @legal_int_types() {
87-
%pgcstack = call {}*** @julia.get_pgcstack()
88-
%ptls = call {}*** @julia.ptls_states()
89-
%ptls_i8 = bitcast {}*** %ptls to i8*
90-
%var1 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 12, {} addrspace(10)* @tag)
91-
%var2 = addrspacecast {} addrspace(10)* %var1 to {} addrspace(11)*
92-
%var3 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var2)
87+
%pgcstack = call ptr @julia.get_pgcstack()
88+
%ptls = call ptr @julia.ptls_states()
89+
%ptls_i8 = bitcast ptr %ptls to ptr
90+
%var1 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 12, ptr addrspace(10) @tag)
91+
%var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11)
92+
%var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2)
9393
ret void
9494
}
9595
; CHECK-LABEL: }{{$}}
9696

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

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

136-
L2:
137-
%v2 = bitcast {} addrspace(10)* %v to i64 addrspace(10)*
138-
%v2_x = load i64, i64 addrspace(10)* %v2
140+
L2: ; preds = %0
141+
%v2 = bitcast ptr addrspace(10) %v to ptr addrspace(10)
142+
%v2_x = load i64, ptr addrspace(10) %v2, align 4
139143
ret void
140144
}
145+
141146
; CHECK-LABEL: }{{$}}
142147

143148
; CHECK-LABEL: @lifetime_no_preserve_end
@@ -146,19 +151,19 @@ L2:
146151
; CHECK: call void @llvm.lifetime.start
147152
; CHECK: store [8 x i8] zeroinitializer,
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: }{{$}}
@@ -175,26 +180,49 @@ define void @lifetime_no_preserve_end({}* noalias nocapture noundef nonnull sret
175180
; CHECK-NOT: zeroinitializer
176181
; CHECK: ret void
177182
define void @initializers() {
178-
%pgcstack = call {}*** @julia.get_pgcstack()
179-
%ptls = call {}*** @julia.ptls_states()
180-
%ptls_i8 = bitcast {}*** %ptls to i8*
181-
182-
%var1 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 1, {} addrspace(10)* @tag) #0
183-
%var2 = addrspacecast {} addrspace(10)* %var1 to {} addrspace(11)*
184-
%var3 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var2)
185-
186-
%var4 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 2, {} addrspace(10)* @tag) #1
187-
%var5 = addrspacecast {} addrspace(10)* %var4 to {} addrspace(11)*
188-
%var6 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var5)
189-
190-
%var7 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 3, {} addrspace(10)* @tag) #2
191-
%var8 = addrspacecast {} addrspace(10)* %var7 to {} addrspace(11)*
192-
%var9 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var8)
193-
183+
%pgcstack = call ptr @julia.get_pgcstack()
184+
%ptls = call ptr @julia.ptls_states()
185+
%ptls_i8 = bitcast ptr %ptls to ptr
186+
%var1 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 1, ptr addrspace(10) @tag) #1
187+
%var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11)
188+
%var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2)
189+
%var4 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 2, ptr addrspace(10) @tag) #2
190+
%var5 = addrspacecast ptr addrspace(10) %var4 to ptr addrspace(11)
191+
%var6 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var5)
192+
%var7 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 3, ptr addrspace(10) @tag) #3
193+
%var8 = addrspacecast ptr addrspace(10) %var7 to ptr addrspace(11)
194+
%var9 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var8)
194195
ret void
195196
}
196197
; CHECK-LABEL: }{{$}}
197198

198-
attributes #0 = { allockind("alloc") }
199-
attributes #1 = { allockind("alloc,uninitialized") }
200-
attributes #2 = { allockind("alloc,zeroed") }
199+
; Test that the pass handles dead basic blocks with references to the allocation
200+
; CHECK-LABEL: @nopreds
201+
; CHECK: alloca i8, i64 0, align 1
202+
; CHECK: call void @llvm.lifetime.start
203+
define swiftcc { ptr addrspace(10), i8 } @nopreds() {
204+
top:
205+
%0 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr null, i64 0, ptr addrspace(10) null)
206+
%1 = addrspacecast ptr addrspace(10) %0 to ptr addrspace(11)
207+
br label %common.ret
208+
209+
common.ret: ; preds = %union_move9, %top
210+
ret { ptr addrspace(10), i8 } zeroinitializer
211+
212+
union_move9: ; No predecessors!
213+
call void @llvm.memcpy.p0.p11.i64(ptr null, ptr addrspace(11) %1, i64 0, i1 false)
214+
br label %common.ret
215+
}
216+
; CHECK-LABEL: }{{$}}
217+
218+
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
219+
declare void @llvm.memcpy.p11.p0.i64(ptr addrspace(11) noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
220+
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
221+
declare void @llvm.memcpy.p0.p11.i64(ptr noalias nocapture writeonly, ptr addrspace(11) noalias nocapture readonly, i64, i1 immarg) #0
222+
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
223+
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
224+
225+
attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
226+
attributes #1 = { allockind("alloc") }
227+
attributes #2 = { allockind("alloc,uninitialized") }
228+
attributes #3 = { allockind("alloc,zeroed") }

0 commit comments

Comments
 (0)