285 lines · plain
1; RUN: opt < %s -passes=rewrite-statepoints-for-gc -spp-rematerialization-threshold=0 -S | FileCheck %s2 3 4declare void @foo()5 6declare void @use(...) "gc-leaf-function"7 8define ptr addrspace(1) @test1(ptr addrspace(1) %obj, ptr addrspace(1) %obj2, i1 %condition) gc "statepoint-example" {9; CHECK-LABEL: @test110; CHECK-DAG: %obj.relocated11; CHECK-DAG: %obj2.relocated12entry:13 call void @foo() [ "deopt"() ]14 br label %joint15 16joint: ; preds = %joint2, %entry17; CHECK-LABEL: joint:18; CHECK: %phi1 = phi ptr addrspace(1) [ %obj.relocated, %entry ], [ %obj3, %joint2 ]19 %phi1 = phi ptr addrspace(1) [ %obj, %entry ], [ %obj3, %joint2 ]20 br i1 %condition, label %use, label %joint221 22use: ; preds = %joint23 br label %joint224 25joint2: ; preds = %use, %joint26; CHECK-LABEL: joint2:27; CHECK: %phi2 = phi ptr addrspace(1) [ %obj.relocated, %use ], [ %obj2.relocated, %joint ]28; CHECK: %obj3 = getelementptr i64, ptr addrspace(1) %obj2.relocated, i32 129 %phi2 = phi ptr addrspace(1) [ %obj, %use ], [ %obj2, %joint ]30 %obj3 = getelementptr i64, ptr addrspace(1) %obj2, i32 131 br label %joint32}33 34declare ptr addrspace(1) @generate_obj() "gc-leaf-function"35 36declare void @consume_obj(ptr addrspace(1)) "gc-leaf-function"37 38declare i1 @rt() "gc-leaf-function"39 40define void @test2() gc "statepoint-example" {41; CHECK-LABEL: @test242entry:43 %obj_init = call ptr addrspace(1) @generate_obj()44 %obj = getelementptr i64, ptr addrspace(1) %obj_init, i32 4245 br label %loop46 47loop: ; preds = %loop.backedge, %entry48; CHECK: loop:49; CHECK-DAG: [ %obj_init.relocated, %loop.backedge ]50; CHECK-DAG: [ %obj_init, %entry ]51; CHECK-DAG: [ %obj.relocated, %loop.backedge ]52; CHECK-DAG: [ %obj, %entry ]53; CHECK-NOT: %location = getelementptr i64, ptr addrspace(1) %obj, i32 %index54 %index = phi i32 [ 0, %entry ], [ %index.inc, %loop.backedge ]55 %location = getelementptr i64, ptr addrspace(1) %obj, i32 %index56 call void @consume_obj(ptr addrspace(1) %location)57 %index.inc = add i32 %index, 158 %condition = call i1 @rt()59 br i1 %condition, label %loop_x, label %loop_y60 61loop_x: ; preds = %loop62 br label %loop.backedge63 64loop.backedge: ; preds = %loop_y, %loop_x65 call void @do_safepoint() [ "deopt"() ]66 br label %loop67 68loop_y: ; preds = %loop69 br label %loop.backedge70}71 72declare void @some_call(ptr addrspace(1)) "gc-leaf-function"73 74define void @relocate_merge(i1 %cnd, ptr addrspace(1) %arg) gc "statepoint-example" {75; CHECK-LABEL: @relocate_merge76 77bci_0:78 br i1 %cnd, label %if_branch, label %else_branch79 80if_branch: ; preds = %bci_081; CHECK-LABEL: if_branch:82; CHECK: gc.statepoint83; CHECK: gc.relocate84 call void @foo() [ "deopt"() ]85 br label %join86 87else_branch: ; preds = %bci_088; CHECK-LABEL: else_branch:89; CHECK: gc.statepoint90; CHECK: gc.relocate91; We need to end up with a single relocation phi updated from both paths92 call void @foo() [ "deopt"() ]93 br label %join94 95join: ; preds = %else_branch, %if_branch96; CHECK-LABEL: join:97; CHECK: phi ptr addrspace(1)98; CHECK-DAG: [ %arg.relocated, %if_branch ]99; CHECK-DAG: [ %arg.relocated2, %else_branch ]100; CHECK-NOT: phi101 call void @some_call(ptr addrspace(1) %arg)102 ret void103}104 105declare void @goo(i64)106 107declare i32 @moo(ptr addrspace(1))108 109; Make sure a use in a statepoint gets properly relocated at a previous one.110; This is basically just making sure that statepoints aren't accidentally111; treated specially.112define void @test3(ptr addrspace(1) %obj) gc "statepoint-example" {113; CHECK-LABEL: @test3114; CHECK: gc.statepoint115; CHECK-NEXT: gc.relocate116; CHECK-NEXT: gc.statepoint117entry:118 call void @goo(i64 undef) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]119 %0 = call i32 @moo(ptr addrspace(1) %obj) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]120 ret void121}122 123declare ptr addrspace(1) @boo()124 125; Check specifically for the case where the result of a statepoint needs to126; be relocated itself127define void @test4() gc "statepoint-example" {128; CHECK-LABEL: @test4129; CHECK: gc.statepoint130; CHECK: gc.result131; CHECK: gc.statepoint132; CHECK: [[RELOCATED:%[^ ]+]] = call {{.*}}gc.relocate133; CHECK: @use(ptr addrspace(1) [[RELOCATED]])134 %1 = call ptr addrspace(1) @boo() [ "deopt"() ]135 %2 = call ptr addrspace(1) @boo() [ "deopt"() ]136 call void (...) @use(ptr addrspace(1) %1)137 ret void138}139 140; Test updating a phi where not all inputs are live to begin with141define void @test5(ptr addrspace(1) %arg) gc "statepoint-example" {142; CHECK-LABEL: test5143entry:144 %0 = call ptr addrspace(1) @boo() [ "deopt"() ]145 switch i32 undef, label %kill [146 i32 10, label %merge147 i32 13, label %merge148 ]149 150kill: ; preds = %entry151 br label %merge152 153merge: ; preds = %kill, %entry, %entry154; CHECK: merge:155; CHECK: %test = phi ptr addrspace(1)156; CHECK-DAG: [ null, %kill ]157; CHECK-DAG: [ %arg.relocated, %entry ]158; CHECK-DAG: [ %arg.relocated, %entry ]159 %test = phi ptr addrspace(1) [ null, %kill ], [ %arg, %entry ], [ %arg, %entry ]160 call void (...) @use(ptr addrspace(1) %test)161 ret void162}163 164; Check to make sure we handle values live over an entry statepoint165define void @test6(ptr addrspace(1) %arg1, ptr addrspace(1) %arg2, ptr addrspace(1) %arg3, i1 %c) gc "statepoint-example" {166; CHECK-LABEL: @test6167entry:168 br i1 %c, label %gc.safepoint_poll.exit2, label %do_safepoint169 170do_safepoint: ; preds = %entry171; CHECK-LABEL: do_safepoint:172; CHECK: gc.statepoint173; CHECK: arg1.relocated =174; CHECK: arg2.relocated =175; CHECK: arg3.relocated =176 call void @foo() [ "deopt"(ptr addrspace(1) %arg1, ptr addrspace(1) %arg2, ptr addrspace(1) %arg3) ]177 br label %gc.safepoint_poll.exit2178 179gc.safepoint_poll.exit2: ; preds = %do_safepoint, %entry180; CHECK-LABEL: gc.safepoint_poll.exit2:181; CHECK: phi ptr addrspace(1)182; CHECK-DAG: [ %arg3, %entry ]183; CHECK-DAG: [ %arg3.relocated, %do_safepoint ]184; CHECK: phi ptr addrspace(1)185; CHECK-DAG: [ %arg2, %entry ]186; CHECK-DAG: [ %arg2.relocated, %do_safepoint ]187; CHECK: phi ptr addrspace(1)188; CHECK-DAG: [ %arg1, %entry ]189; CHECK-DAG: [ %arg1.relocated, %do_safepoint ]190 call void (...) @use(ptr addrspace(1) %arg1, ptr addrspace(1) %arg2, ptr addrspace(1) %arg3)191 ret void192}193 194; Check relocation in a loop nest where a relocation happens in the outer195; but not the inner loop196define void @test_outer_loop(ptr addrspace(1) %arg1, ptr addrspace(1) %arg2, i1 %cmp) gc "statepoint-example" {197; CHECK-LABEL: @test_outer_loop198 199bci_0:200 br label %outer-loop201 202outer-loop: ; preds = %outer-inc, %bci_0203; CHECK-LABEL: outer-loop:204; CHECK: phi ptr addrspace(1) [ %arg2, %bci_0 ], [ %arg2.relocated, %outer-inc ]205; CHECK: phi ptr addrspace(1) [ %arg1, %bci_0 ], [ %arg1.relocated, %outer-inc ]206 br label %inner-loop207 208inner-loop: ; preds = %inner-loop, %outer-loop209 br i1 %cmp, label %inner-loop, label %outer-inc210 211outer-inc: ; preds = %inner-loop212; CHECK-LABEL: outer-inc:213; CHECK: %arg1.relocated214; CHECK: %arg2.relocated215 call void @foo() [ "deopt"(ptr addrspace(1) %arg1, ptr addrspace(1) %arg2) ]216 br label %outer-loop217}218 219; Check that both inner and outer loops get phis when relocation is in220; inner loop221define void @test_inner_loop(ptr addrspace(1) %arg1, ptr addrspace(1) %arg2, i1 %cmp) gc "statepoint-example" {222; CHECK-LABEL: @test_inner_loop223 224bci_0:225 br label %outer-loop226 227outer-loop: ; preds = %outer-inc, %bci_0228; CHECK-LABEL: outer-loop:229; CHECK: phi ptr addrspace(1) [ %arg2, %bci_0 ], [ %arg2.relocated, %outer-inc ]230; CHECK: phi ptr addrspace(1) [ %arg1, %bci_0 ], [ %arg1.relocated, %outer-inc ]231 br label %inner-loop232; CHECK-LABEL: inner-loop233; CHECK: phi ptr addrspace(1)234; CHECK-DAG: %outer-loop ]235; CHECK-DAG: [ %arg2.relocated, %inner-loop ]236; CHECK: phi ptr addrspace(1)237; CHECK-DAG: %outer-loop ]238; CHECK-DAG: [ %arg1.relocated, %inner-loop ]239; CHECK: gc.statepoint240; CHECK: %arg1.relocated241; CHECK: %arg2.relocated242 243inner-loop: ; preds = %inner-loop, %outer-loop244 call void @foo() [ "deopt"(ptr addrspace(1) %arg1, ptr addrspace(1) %arg2) ]245 br i1 %cmp, label %inner-loop, label %outer-inc246 247outer-inc: ; preds = %inner-loop248; CHECK-LABEL: outer-inc:249; This test shows why updating just those uses of the original value being250; relocated dominated by the inserted relocation is not always sufficient.251 br label %outer-loop252}253 254define ptr addrspace(1) @test7(ptr addrspace(1) %obj, ptr addrspace(1) %obj2, i1 %condition) gc "statepoint-example" {255; CHECK-LABEL: @test7256entry:257 br i1 %condition, label %branch2, label %join258 259branch2: ; preds = %entry260 br i1 %condition, label %callbb, label %join2261 262callbb: ; preds = %branch2263 call void @foo() [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]264 br label %join265 266join: ; preds = %callbb, %entry267; CHECK-LABEL: join:268; CHECK: phi ptr addrspace(1) [ %obj.relocated, %callbb ], [ %obj, %entry ]269; CHECK: phi ptr addrspace(1)270; CHECK-DAG: [ %obj, %entry ]271; CHECK-DAG: [ %obj2.relocated, %callbb ]272 %phi1 = phi ptr addrspace(1) [ %obj, %entry ], [ %obj2, %callbb ]273 br label %join2274 275join2: ; preds = %join, %branch2276; CHECK-LABEL: join2:277; CHECK: phi2 = phi ptr addrspace(1)278; CHECK-DAG: %join ]279; CHECK-DAG: [ %obj2, %branch2 ]280 %phi2 = phi ptr addrspace(1) [ %obj, %join ], [ %obj2, %branch2 ]281 ret ptr addrspace(1) %phi2282}283 284declare void @do_safepoint()285