diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp index 5df4f52aca425..9638ca7e68c48 100644 --- a/src/llvm-alloc-opt.cpp +++ b/src/llvm-alloc-opt.cpp @@ -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) { diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index 19321cf9f21a7..e8f43236c1bd1 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -889,10 +889,17 @@ dims54166 = (1,2) @test (minimum(ex54166; dims=dims54166)[1] === missing) 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 diff --git a/test/llvmpasses/alloc-opt-pass.ll b/test/llvmpasses/alloc-opt-pass.ll index 6bee0fd325105..d5adbb424f848 100644 --- a/test/llvmpasses/alloc-opt-pass.ll +++ b/test/llvmpasses/alloc-opt-pass.ll @@ -21,23 +21,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: }{{$}} @@ -56,24 +56,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: }{{$}} @@ -84,26 +84,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 @@ -120,24 +124,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 @@ -146,19 +151,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: }{{$}} @@ -175,26 +180,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") }