; This file is a part of Julia. License is MIT: https://julialang.org/license ; RUN: opt -enable-new-pm=0 --opaque-pointers=0 -load libjulia-codegen%shlibext -LateLowerGCFrame -FinalLowerGC -S %s | FileCheck %s --check-prefixes=CHECK,TYPED ; RUN: opt -enable-new-pm=1 --opaque-pointers=0 --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LateLowerGCFrame),FinalLowerGC' -S %s | FileCheck %s --check-prefixes=CHECK,TYPED ; RUN: opt -enable-new-pm=0 --opaque-pointers=1 -load libjulia-codegen%shlibext -LateLowerGCFrame -FinalLowerGC -S %s | FileCheck %s --check-prefixes=CHECK,OPAQUE ; RUN: opt -enable-new-pm=1 --opaque-pointers=1 --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LateLowerGCFrame),FinalLowerGC' -S %s | FileCheck %s --check-prefixes=CHECK,OPAQUE declare {}*** @julia.ptls_states() declare {}*** @julia.get_pgcstack() declare void @jl_safepoint() declare void @one_arg_boxed({} addrspace(10)*) declare {} addrspace(10)* @ijl_box_int64(i64) declare {} addrspace(10)* @allocate_some_value() define void @argument_refinement({} addrspace(10)* %a) { ; CHECK-LABEL: @argument_refinement ; CHECK-NOT: %gcframe %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %casted1 = bitcast {} addrspace(10)* %a to {} addrspace(10)* addrspace(10)* %loaded1 = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %casted1, !tbaa !1 call void @jl_safepoint() %casted2 = bitcast {} addrspace(10)* %loaded1 to i64 addrspace(10)* %loaded2 = load i64, i64 addrspace(10)* %casted2 ret void } ; Check that we reuse the gc slot from the box define void @heap_refinement1(i64 %a) { ; CHECK-LABEL: @heap_refinement1 ; TYPED: %gcframe = alloca {} addrspace(10)*, i32 3 ; OPAQUE: %gcframe = alloca ptr addrspace(10), i32 3 %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %aboxed = call {} addrspace(10)* @ijl_box_int64(i64 signext %a) %casted1 = bitcast {} addrspace(10)* %aboxed to {} addrspace(10)* addrspace(10)* %loaded1 = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %casted1, !tbaa !1 ; TYPED: store {} addrspace(10)* %aboxed ; OPAQUE: store ptr addrspace(10) %aboxed call void @jl_safepoint() %casted2 = bitcast {} addrspace(10)* %loaded1 to i64 addrspace(10)* %loaded2 = load i64, i64 addrspace(10)* %casted2 call void @one_arg_boxed({} addrspace(10)* %aboxed) ret void } ; Check that we don't root the allocated value here, just the derived value define void @heap_refinement2(i64 %a) { ; CHECK-LABEL: @heap_refinement2 ; TYPED: %gcframe = alloca {} addrspace(10)*, i32 3 ; OPAQUE: %gcframe = alloca ptr addrspace(10), i32 3 %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %aboxed = call {} addrspace(10)* @ijl_box_int64(i64 signext %a) %casted1 = bitcast {} addrspace(10)* %aboxed to {} addrspace(10)* addrspace(10)* %loaded1 = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %casted1, !tbaa !1 ; TYPED: store {} addrspace(10)* %loaded1 ; OPAQUE: store ptr addrspace(10) %loaded1 call void @jl_safepoint() %casted2 = bitcast {} addrspace(10)* %loaded1 to i64 addrspace(10)* %loaded2 = load i64, i64 addrspace(10)* %casted2 ret void } ; Check that the way we compute rooting is compatible with refinements define void @issue22770() { ; CHECK-LABEL: @issue22770 ; TYPED: %gcframe = alloca {} addrspace(10)*, i32 4 ; OPAQUE: %gcframe = alloca ptr addrspace(10), i32 4 %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %y = call {} addrspace(10)* @allocate_some_value() %casted1 = bitcast {} addrspace(10)* %y to {} addrspace(10)* addrspace(10)* %x = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %casted1, !tbaa !1 ; TYPED: store {} addrspace(10)* %y, ; OPAQUE: store ptr addrspace(10) %y, %a = call {} addrspace(10)* @allocate_some_value() ; TYPED: store {} addrspace(10)* %a ; TYPED: call void @one_arg_boxed({} addrspace(10)* %x) ; TYPED: call void @one_arg_boxed({} addrspace(10)* %a) ; TYPED: call void @one_arg_boxed({} addrspace(10)* %y) ; OPAQUE: store ptr addrspace(10) %a ; OPAQUE: call void @one_arg_boxed(ptr addrspace(10) %x) ; OPAQUE: call void @one_arg_boxed(ptr addrspace(10) %a) ; OPAQUE: call void @one_arg_boxed(ptr addrspace(10) %y) call void @one_arg_boxed({} addrspace(10)* %x) call void @one_arg_boxed({} addrspace(10)* %a) call void @one_arg_boxed({} addrspace(10)* %y) ; TYPED: store {} addrspace(10)* %x ; OPAQUE: store ptr addrspace(10) %x %c = call {} addrspace(10)* @allocate_some_value() ; TYPED: store {} addrspace(10)* %c ; OPAQUE: store ptr addrspace(10) %c call void @one_arg_boxed({} addrspace(10)* %x) call void @one_arg_boxed({} addrspace(10)* %c) ret void } define void @refine_select_phi({} addrspace(10)* %x, {} addrspace(10)* %y, i1 %b) { ; CHECK-LABEL: @refine_select_phi ; CHECK-NOT: %gcframe top: %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %s = select i1 %b, {} addrspace(10)* %x, {} addrspace(10)* %y br i1 %b, label %L1, label %L2 L1: br label %L3 L2: br label %L3 L3: %p = phi {} addrspace(10)* [ %x, %L1 ], [ %y, %L2 ] call void @one_arg_boxed({} addrspace(10)* %s) call void @one_arg_boxed({} addrspace(10)* %p) ret void } define void @dont_refine_loop({} addrspace(10)* %x) { ; CHECK-LABEL: @dont_refine_loop ; TYPED: %gcframe = alloca {} addrspace(10)*, i32 4 ; OPAQUE: %gcframe = alloca ptr addrspace(10), i32 4 top: %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() br label %L1 L1: %continue = phi i1 [ true, %top ], [ false, %L1 ] %p = phi {} addrspace(10)* [ %x, %top ], [ %v, %L1 ] %v = call {} addrspace(10)* @allocate_some_value() call void @one_arg_boxed({} addrspace(10)* %v) call void @one_arg_boxed({} addrspace(10)* %p) br i1 %continue, label %L1, label %L2 L2: ret void } @gv1 = external global {}* define void @refine_loop_const({} addrspace(10)* %x) { ; CHECK-LABEL: @refine_loop_const ; CHECK-NOT: %gcframe top: %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() br label %L1 L1: %continue = phi i1 [ true, %top ], [ false, %L1 ] %p = phi {} addrspace(10)* [ %x, %top ], [ %v, %L1 ] %v0 = load {}*, {}** @gv1, !tbaa !4 %v = addrspacecast {}* %v0 to {} addrspace(10)* call void @one_arg_boxed({} addrspace(10)* %v) call void @one_arg_boxed({} addrspace(10)* %p) br i1 %continue, label %L1, label %L2 L2: ret void } define void @refine_loop_indirect({} addrspace(10)* %x) { ; CHECK-LABEL: @refine_loop_indirect ; TYPED: %gcframe = alloca {} addrspace(10)*, i32 3 ; OPAQUE: %gcframe = alloca ptr addrspace(10), i32 3 top: %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %a = call {} addrspace(10)* @allocate_some_value() br label %L1 L1: %continue = phi i1 [ true, %top ], [ false, %L1 ] ; `%v` is not a valid refinement incoming value of the phi node `%p`, ; however, `%v` can be refined to `%a` and `%a` is a valid refinement ; of the phi node. Therefore, we need only one gc slot for `%a`. %p = phi {} addrspace(10)* [ %x, %top ], [ %v, %L1 ] %ca = bitcast {} addrspace(10)* %a to {} addrspace(10)* addrspace(10)* %v = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %ca, !tbaa !1 call void @one_arg_boxed({} addrspace(10)* %v) call void @one_arg_boxed({} addrspace(10)* %p) br i1 %continue, label %L1, label %L2 L2: ret void } define void @refine_loop_indirect2({} addrspace(10)* %x) { ; CHECK-LABEL: @refine_loop_indirect2 ; TYPED: %gcframe = alloca {} addrspace(10)*, i32 3 ; OPAQUE: %gcframe = alloca ptr addrspace(10), i32 3 top: %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %a = call {} addrspace(10)* @allocate_some_value() br label %L1 L1: %continue = phi i1 [ true, %top ], [ false, %L1 ] ; `%p` has circular dependency but it can only be derived from `%a` which dominate `%p`. %p = phi {} addrspace(10)* [ %a, %top ], [ %v, %L1 ] %ca = bitcast {} addrspace(10)* %p to {} addrspace(10)* addrspace(10)* %v = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %ca, !tbaa !1 call void @one_arg_boxed({} addrspace(10)* %v) call void @one_arg_boxed({} addrspace(10)* %p) br i1 %continue, label %L1, label %L2 L2: ret void } declare {} addrspace(10)* @julia.typeof({} addrspace(10)*) #0 define {} addrspace(10)* @typeof({} addrspace(10)* %x) { ; CHECK-LABEL: @typeof( ; CHECK-NOT: %gcframe %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %v = call {} addrspace(10)* @julia.typeof({} addrspace(10)* %x) call void @one_arg_boxed({} addrspace(10)* %v) ret {} addrspace(10)* %v } declare void @julia.write_barrier({} addrspace(10)*, {} addrspace(10)*) #1 define {} addrspace(10)* @setfield({} addrspace(10)* %p) { ; CHECK-LABEL: @setfield( ; CHECK-NOT: %gcframe ; CHECK: call void @ijl_gc_queue_root %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %c = call {} addrspace(10)* @allocate_some_value() %fp = bitcast {} addrspace(10)* %p to {} addrspace(10)* addrspace(10)* store {} addrspace(10)* %c, {} addrspace(10)* addrspace(10)* %fp call void @julia.write_barrier({} addrspace(10)* %p, {} addrspace(10)* %c) ret {} addrspace(10)* %c } attributes #0 = { argmemonly norecurse nounwind readonly } attributes #1 = { inaccessiblememonly norecurse nounwind } !0 = !{!"jtbaa"} !1 = !{!2, !2, i64 0} !2 = !{!"jtbaa_immut", !0, i64 0} !3 = !{!"jtbaa_const", !0, i64 0} !4 = !{!3, !3, i64 0, i64 1}