Skip to content

Commit 5cb1107

Browse files
authored
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.
1 parent fc6acc7 commit 5cb1107

File tree

3 files changed

+123
-84
lines changed

3 files changed

+123
-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: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -939,11 +939,20 @@ BigStructAnyInt() = BigStructAnyInt((Union{Base.inferencebarrier(Float64), Int}=
939939
@test egal_any54109(Torture2_54109(), Torture2_54109())
940940
@test !egal_any54109(Torture1_54109(), Torture1_54109((DefaultOr54109(2.0, false) for i = 1:897)...))
941941

942+
bar54599() = Base.inferencebarrier(true) ? (Base.PkgId(Main),1) : nothing
943+
942944
function foo54599()
943-
pkgid = Base.identify_package("Test")
944-
println(devnull,pkgid)
945-
println(devnull, pkgid.uuid)
946-
pkgid.uuid
945+
pkginfo = @noinline bar54599()
946+
pkgid = pkginfo !== nothing ? pkginfo[1] : nothing
947+
@noinline println(devnull, pkgid)
948+
pkgid.uuid !== nothing ? pkgid.uuid : false
947949
end
948950

949-
@test foo54599() !== nothing
951+
#this function used to crash allocopt due to a no predecessors bug
952+
barnopreds() = Base.inferencebarrier(true) ? (Base.PkgId(Test),1) : nothing
953+
function foonopreds()
954+
pkginfo = @noinline barnopreds()
955+
pkgid = pkginfo !== nothing ? pkginfo[1] : nothing
956+
pkgid.uuid !== nothing ? pkgid.uuid : false
957+
end
958+
@test foonopreds() !== nothing

test/llvmpasses/alloc-opt-pass.ll

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

2020
; CHECK: L3:
21-
define void @preserve_branches(i8* %fptr, i1 %b, i1 %b2) {
22-
%pgcstack = call {}*** @julia.get_pgcstack()
23-
%ptls = call {}*** @julia.ptls_states()
24-
%ptls_i8 = bitcast {}*** %ptls to i8*
21+
define void @preserve_branches(ptr %fptr, i1 %b, i1 %b2) {
22+
%pgcstack = call ptr @julia.get_pgcstack()
23+
%ptls = call ptr @julia.ptls_states()
24+
%ptls_i8 = bitcast ptr %ptls to ptr
2525
br i1 %b, label %L1, label %L3
2626

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

33-
L2:
33+
L2: ; preds = %L1
3434
call void @external_function()
3535
br label %L3
3636

37-
L3:
37+
L3: ; preds = %L2, %L1, %0
3838
ret void
3939
}
4040
; CHECK-LABEL: }{{$}}
@@ -51,24 +51,24 @@ L3:
5151
; CHECK-NEXT: br label %L3
5252

5353
; CHECK: L3:
54-
define void @preserve_branches2(i8* %fptr, i1 %b, i1 %b2) {
55-
%pgcstack = call {}*** @julia.get_pgcstack()
56-
%ptls = call {}*** @julia.ptls_states()
57-
%ptls_i8 = bitcast {}*** %ptls to i8*
58-
%v2 = call {} addrspace(10)* @external_function2()
54+
define void @preserve_branches2(ptr %fptr, i1 %b, i1 %b2) {
55+
%pgcstack = call ptr @julia.get_pgcstack()
56+
%ptls = call ptr @julia.ptls_states()
57+
%ptls_i8 = bitcast ptr %ptls to ptr
58+
%v2 = call ptr addrspace(10) @external_function2()
5959
br i1 %b, label %L1, label %L3
6060

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

67-
L2:
67+
L2: ; preds = %L1
6868
call void @external_function()
6969
br label %L3
7070

71-
L3:
71+
L3: ; preds = %L2, %L1, %0
7272
ret void
7373
}
7474
; CHECK-LABEL: }{{$}}
@@ -79,26 +79,30 @@ L3:
7979
; CHECK: store [12 x i8] zeroinitializer,
8080
; CHECK: ret void
8181
define void @legal_int_types() {
82-
%pgcstack = call {}*** @julia.get_pgcstack()
83-
%ptls = call {}*** @julia.ptls_states()
84-
%ptls_i8 = bitcast {}*** %ptls to i8*
85-
%var1 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 12, {} addrspace(10)* @tag)
86-
%var2 = addrspacecast {} addrspace(10)* %var1 to {} addrspace(11)*
87-
%var3 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var2)
82+
%pgcstack = call ptr @julia.get_pgcstack()
83+
%ptls = call ptr @julia.ptls_states()
84+
%ptls_i8 = bitcast ptr %ptls to ptr
85+
%var1 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 12, ptr addrspace(10) @tag)
86+
%var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11)
87+
%var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2)
8888
ret void
8989
}
9090
; CHECK-LABEL: }{{$}}
9191

92-
9392
declare void @external_function()
94-
declare {} addrspace(10)* @external_function2()
95-
declare {}*** @julia.ptls_states()
96-
declare {}*** @julia.get_pgcstack()
97-
declare noalias {} addrspace(10)* @julia.gc_alloc_obj(i8*, i64, {} addrspace(10)*)
98-
declare {}* @julia.pointer_from_objref({} addrspace(11)*)
99-
declare void @llvm.memcpy.p11i8.p0i8.i64(i8 addrspace(11)* nocapture writeonly, i8* nocapture readonly, i64, i32, i1)
100-
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1)
93+
94+
declare ptr addrspace(10) @external_function2()
95+
96+
declare ptr @julia.ptls_states()
97+
98+
declare ptr @julia.get_pgcstack()
99+
100+
declare noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr, i64, ptr addrspace(10))
101+
102+
declare ptr @julia.pointer_from_objref(ptr addrspace(11))
103+
101104
declare token @llvm.julia.gc_preserve_begin(...)
105+
102106
declare void @llvm.julia.gc_preserve_end(token)
103107

104108
; CHECK-LABEL: @memref_collision
@@ -111,24 +115,25 @@ declare void @llvm.julia.gc_preserve_end(token)
111115
; CHECK: L2:
112116
; CHECK: load i
113117
define void @memref_collision(i64 %x) {
114-
%pgcstack = call {}*** @julia.get_pgcstack()
115-
%ptls = call {}*** @julia.ptls_states()
116-
%ptls_i8 = bitcast {}*** %ptls to i8*
117-
%v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 8, {} addrspace(10)* @tag)
118-
%v_p = bitcast {} addrspace(10)* %v to i64 addrspace(10)*
119-
store i64 %x, i64 addrspace(10)* %v_p
120-
br i1 0, label %L1, label %L2
121-
122-
L1:
123-
%v1 = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)*
124-
%v1_x = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %v1
118+
%pgcstack = call ptr @julia.get_pgcstack()
119+
%ptls = call ptr @julia.ptls_states()
120+
%ptls_i8 = bitcast ptr %ptls to ptr
121+
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
122+
%v_p = bitcast ptr addrspace(10) %v to ptr addrspace(10)
123+
store i64 %x, ptr addrspace(10) %v_p, align 4
124+
br i1 false, label %L1, label %L2
125+
126+
L1: ; preds = %0
127+
%v1 = bitcast ptr addrspace(10) %v to ptr addrspace(10)
128+
%v1_x = load ptr addrspace(10), ptr addrspace(10) %v1, align 8
125129
ret void
126130

127-
L2:
128-
%v2 = bitcast {} addrspace(10)* %v to i64 addrspace(10)*
129-
%v2_x = load i64, i64 addrspace(10)* %v2
131+
L2: ; preds = %0
132+
%v2 = bitcast ptr addrspace(10) %v to ptr addrspace(10)
133+
%v2_x = load i64, ptr addrspace(10) %v2, align 4
130134
ret void
131135
}
136+
132137
; CHECK-LABEL: }{{$}}
133138

134139
; CHECK-LABEL: @lifetime_no_preserve_end
@@ -137,19 +142,19 @@ L2:
137142
; CHECK: call void @llvm.lifetime.start
138143
; CHECK: store [8 x i8] zeroinitializer,
139144
; CHECK-NOT: call void @llvm.lifetime.end
140-
define void @lifetime_no_preserve_end({}* noalias nocapture noundef nonnull sret({}) %0) {
141-
%pgcstack = call {}*** @julia.get_pgcstack()
142-
%ptls = call {}*** @julia.ptls_states()
143-
%ptls_i8 = bitcast {}*** %ptls to i8*
144-
%v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 8, {} addrspace(10)* @tag)
145-
%token = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %v)
146-
%v_derived = addrspacecast {} addrspace(10)* %v to {} addrspace(11)*
147-
%ptr = call nonnull {}* @julia.pointer_from_objref({} addrspace(11)* %v_derived)
148-
%ptr_raw = bitcast {}* %ptr to i8*
149-
call void @external_function() ; safepoint
150-
%ret_raw = bitcast {}* %0 to i8*
151-
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %ret_raw, i8 * align 8 %ptr_raw, i64 0, i1 false)
152-
%ret_raw2 = bitcast {}* %0 to i8*
145+
define void @lifetime_no_preserve_end(ptr noalias nocapture noundef nonnull sret({}) %0) {
146+
%pgcstack = call ptr @julia.get_pgcstack()
147+
%ptls = call ptr @julia.ptls_states()
148+
%ptls_i8 = bitcast ptr %ptls to ptr
149+
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
150+
%token = call token (...) @llvm.julia.gc_preserve_begin(ptr addrspace(10) %v)
151+
%v_derived = addrspacecast ptr addrspace(10) %v to ptr addrspace(11)
152+
%ptr = call nonnull ptr @julia.pointer_from_objref(ptr addrspace(11) %v_derived)
153+
%ptr_raw = bitcast ptr %ptr to ptr
154+
call void @external_function()
155+
%ret_raw = bitcast ptr %0 to ptr
156+
call void @llvm.memcpy.p0.p0.i64(ptr align 8 %ret_raw, ptr align 8 %ptr_raw, i64 0, i1 false)
157+
%ret_raw2 = bitcast ptr %0 to ptr
153158
ret void
154159
}
155160
; CHECK-LABEL: }{{$}}
@@ -166,26 +171,49 @@ define void @lifetime_no_preserve_end({}* noalias nocapture noundef nonnull sret
166171
; CHECK-NOT: zeroinitializer
167172
; CHECK: ret void
168173
define void @initializers() {
169-
%pgcstack = call {}*** @julia.get_pgcstack()
170-
%ptls = call {}*** @julia.ptls_states()
171-
%ptls_i8 = bitcast {}*** %ptls to i8*
172-
173-
%var1 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 1, {} addrspace(10)* @tag) #0
174-
%var2 = addrspacecast {} addrspace(10)* %var1 to {} addrspace(11)*
175-
%var3 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var2)
176-
177-
%var4 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 2, {} addrspace(10)* @tag) #1
178-
%var5 = addrspacecast {} addrspace(10)* %var4 to {} addrspace(11)*
179-
%var6 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var5)
180-
181-
%var7 = call {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, i64 3, {} addrspace(10)* @tag) #2
182-
%var8 = addrspacecast {} addrspace(10)* %var7 to {} addrspace(11)*
183-
%var9 = call {}* @julia.pointer_from_objref({} addrspace(11)* %var8)
184-
174+
%pgcstack = call ptr @julia.get_pgcstack()
175+
%ptls = call ptr @julia.ptls_states()
176+
%ptls_i8 = bitcast ptr %ptls to ptr
177+
%var1 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 1, ptr addrspace(10) @tag) #1
178+
%var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11)
179+
%var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2)
180+
%var4 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 2, ptr addrspace(10) @tag) #2
181+
%var5 = addrspacecast ptr addrspace(10) %var4 to ptr addrspace(11)
182+
%var6 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var5)
183+
%var7 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 3, ptr addrspace(10) @tag) #3
184+
%var8 = addrspacecast ptr addrspace(10) %var7 to ptr addrspace(11)
185+
%var9 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var8)
185186
ret void
186187
}
187188
; CHECK-LABEL: }{{$}}
188189

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

0 commit comments

Comments
 (0)