1*cee313d2SEric Christopher; RUN: opt < %s -rewrite-statepoints-for-gc -spp-rematerialization-threshold=0 -S | FileCheck %s 2*cee313d2SEric Christopher; RUN: opt < %s -passes=rewrite-statepoints-for-gc -spp-rematerialization-threshold=0 -S | FileCheck %s 3*cee313d2SEric Christopher 4*cee313d2SEric Christopher 5*cee313d2SEric Christopherdeclare void @foo() 6*cee313d2SEric Christopher 7*cee313d2SEric Christopherdeclare void @use(...) "gc-leaf-function" 8*cee313d2SEric Christopher 9*cee313d2SEric Christopherdefine i64 addrspace(1)* @test1(i64 addrspace(1)* %obj, i64 addrspace(1)* %obj2, i1 %condition) gc "statepoint-example" { 10*cee313d2SEric Christopher; CHECK-LABEL: @test1 11*cee313d2SEric Christopher; CHECK-DAG: %obj.relocated 12*cee313d2SEric Christopher; CHECK-DAG: %obj2.relocated 13*cee313d2SEric Christopherentry: 14*cee313d2SEric Christopher call void @foo() [ "deopt"() ] 15*cee313d2SEric Christopher br label %joint 16*cee313d2SEric Christopher 17*cee313d2SEric Christopherjoint: ; preds = %joint2, %entry 18*cee313d2SEric Christopher; CHECK-LABEL: joint: 19*cee313d2SEric Christopher; CHECK: %phi1 = phi i64 addrspace(1)* [ %obj.relocated.casted, %entry ], [ %obj3, %joint2 ] 20*cee313d2SEric Christopher %phi1 = phi i64 addrspace(1)* [ %obj, %entry ], [ %obj3, %joint2 ] 21*cee313d2SEric Christopher br i1 %condition, label %use, label %joint2 22*cee313d2SEric Christopher 23*cee313d2SEric Christopheruse: ; preds = %joint 24*cee313d2SEric Christopher br label %joint2 25*cee313d2SEric Christopher 26*cee313d2SEric Christopherjoint2: ; preds = %use, %joint 27*cee313d2SEric Christopher; CHECK-LABEL: joint2: 28*cee313d2SEric Christopher; CHECK: %phi2 = phi i64 addrspace(1)* [ %obj.relocated.casted, %use ], [ %obj2.relocated.casted, %joint ] 29*cee313d2SEric Christopher; CHECK: %obj3 = getelementptr i64, i64 addrspace(1)* %obj2.relocated.casted, i32 1 30*cee313d2SEric Christopher %phi2 = phi i64 addrspace(1)* [ %obj, %use ], [ %obj2, %joint ] 31*cee313d2SEric Christopher %obj3 = getelementptr i64, i64 addrspace(1)* %obj2, i32 1 32*cee313d2SEric Christopher br label %joint 33*cee313d2SEric Christopher} 34*cee313d2SEric Christopher 35*cee313d2SEric Christopherdeclare i64 addrspace(1)* @generate_obj() "gc-leaf-function" 36*cee313d2SEric Christopher 37*cee313d2SEric Christopherdeclare void @consume_obj(i64 addrspace(1)*) "gc-leaf-function" 38*cee313d2SEric Christopher 39*cee313d2SEric Christopherdeclare i1 @rt() "gc-leaf-function" 40*cee313d2SEric Christopher 41*cee313d2SEric Christopherdefine void @test2() gc "statepoint-example" { 42*cee313d2SEric Christopher; CHECK-LABEL: @test2 43*cee313d2SEric Christopherentry: 44*cee313d2SEric Christopher %obj_init = call i64 addrspace(1)* @generate_obj() 45*cee313d2SEric Christopher %obj = getelementptr i64, i64 addrspace(1)* %obj_init, i32 42 46*cee313d2SEric Christopher br label %loop 47*cee313d2SEric Christopher 48*cee313d2SEric Christopherloop: ; preds = %loop.backedge, %entry 49*cee313d2SEric Christopher; CHECK: loop: 50*cee313d2SEric Christopher; CHECK-DAG: [ %obj_init.relocated.casted, %loop.backedge ] 51*cee313d2SEric Christopher; CHECK-DAG: [ %obj_init, %entry ] 52*cee313d2SEric Christopher; CHECK-DAG: [ %obj.relocated.casted, %loop.backedge ] 53*cee313d2SEric Christopher; CHECK-DAG: [ %obj, %entry ] 54*cee313d2SEric Christopher; CHECK-NOT: %location = getelementptr i64, i64 addrspace(1)* %obj, i32 %index 55*cee313d2SEric Christopher %index = phi i32 [ 0, %entry ], [ %index.inc, %loop.backedge ] 56*cee313d2SEric Christopher %location = getelementptr i64, i64 addrspace(1)* %obj, i32 %index 57*cee313d2SEric Christopher call void @consume_obj(i64 addrspace(1)* %location) 58*cee313d2SEric Christopher %index.inc = add i32 %index, 1 59*cee313d2SEric Christopher %condition = call i1 @rt() 60*cee313d2SEric Christopher br i1 %condition, label %loop_x, label %loop_y 61*cee313d2SEric Christopher 62*cee313d2SEric Christopherloop_x: ; preds = %loop 63*cee313d2SEric Christopher br label %loop.backedge 64*cee313d2SEric Christopher 65*cee313d2SEric Christopherloop.backedge: ; preds = %loop_y, %loop_x 66*cee313d2SEric Christopher call void @do_safepoint() [ "deopt"() ] 67*cee313d2SEric Christopher br label %loop 68*cee313d2SEric Christopher 69*cee313d2SEric Christopherloop_y: ; preds = %loop 70*cee313d2SEric Christopher br label %loop.backedge 71*cee313d2SEric Christopher} 72*cee313d2SEric Christopher 73*cee313d2SEric Christopherdeclare void @some_call(i8 addrspace(1)*) "gc-leaf-function" 74*cee313d2SEric Christopher 75*cee313d2SEric Christopherdefine void @relocate_merge(i1 %cnd, i8 addrspace(1)* %arg) gc "statepoint-example" { 76*cee313d2SEric Christopher; CHECK-LABEL: @relocate_merge 77*cee313d2SEric Christopher 78*cee313d2SEric Christopherbci_0: 79*cee313d2SEric Christopher br i1 %cnd, label %if_branch, label %else_branch 80*cee313d2SEric Christopher 81*cee313d2SEric Christopherif_branch: ; preds = %bci_0 82*cee313d2SEric Christopher; CHECK-LABEL: if_branch: 83*cee313d2SEric Christopher; CHECK: gc.statepoint 84*cee313d2SEric Christopher; CHECK: gc.relocate 85*cee313d2SEric Christopher call void @foo() [ "deopt"() ] 86*cee313d2SEric Christopher br label %join 87*cee313d2SEric Christopher 88*cee313d2SEric Christopherelse_branch: ; preds = %bci_0 89*cee313d2SEric Christopher; CHECK-LABEL: else_branch: 90*cee313d2SEric Christopher; CHECK: gc.statepoint 91*cee313d2SEric Christopher; CHECK: gc.relocate 92*cee313d2SEric Christopher; We need to end up with a single relocation phi updated from both paths 93*cee313d2SEric Christopher call void @foo() [ "deopt"() ] 94*cee313d2SEric Christopher br label %join 95*cee313d2SEric Christopher 96*cee313d2SEric Christopherjoin: ; preds = %else_branch, %if_branch 97*cee313d2SEric Christopher; CHECK-LABEL: join: 98*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* 99*cee313d2SEric Christopher; CHECK-DAG: [ %arg.relocated, %if_branch ] 100*cee313d2SEric Christopher; CHECK-DAG: [ %arg.relocated2, %else_branch ] 101*cee313d2SEric Christopher; CHECK-NOT: phi 102*cee313d2SEric Christopher call void @some_call(i8 addrspace(1)* %arg) 103*cee313d2SEric Christopher ret void 104*cee313d2SEric Christopher} 105*cee313d2SEric Christopher 106*cee313d2SEric Christopherdeclare void @goo(i64) 107*cee313d2SEric Christopher 108*cee313d2SEric Christopherdeclare i32 @moo(i64 addrspace(1)*) 109*cee313d2SEric Christopher 110*cee313d2SEric Christopher; Make sure a use in a statepoint gets properly relocated at a previous one. 111*cee313d2SEric Christopher; This is basically just making sure that statepoints aren't accidentally 112*cee313d2SEric Christopher; treated specially. 113*cee313d2SEric Christopherdefine void @test3(i64 addrspace(1)* %obj) gc "statepoint-example" { 114*cee313d2SEric Christopher; CHECK-LABEL: @test3 115*cee313d2SEric Christopher; CHECK: gc.statepoint 116*cee313d2SEric Christopher; CHECK-NEXT: gc.relocate 117*cee313d2SEric Christopher; CHECK-NEXT: bitcast 118*cee313d2SEric Christopher; CHECK-NEXT: gc.statepoint 119*cee313d2SEric Christopherentry: 120*cee313d2SEric Christopher call void @goo(i64 undef) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ] 121*cee313d2SEric Christopher %0 = call i32 @moo(i64 addrspace(1)* %obj) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ] 122*cee313d2SEric Christopher ret void 123*cee313d2SEric Christopher} 124*cee313d2SEric Christopher 125*cee313d2SEric Christopherdeclare i8 addrspace(1)* @boo() 126*cee313d2SEric Christopher 127*cee313d2SEric Christopher; Check specifically for the case where the result of a statepoint needs to 128*cee313d2SEric Christopher; be relocated itself 129*cee313d2SEric Christopherdefine void @test4() gc "statepoint-example" { 130*cee313d2SEric Christopher; CHECK-LABEL: @test4 131*cee313d2SEric Christopher; CHECK: gc.statepoint 132*cee313d2SEric Christopher; CHECK: gc.result 133*cee313d2SEric Christopher; CHECK: gc.statepoint 134*cee313d2SEric Christopher; CHECK: [[RELOCATED:%[^ ]+]] = call {{.*}}gc.relocate 135*cee313d2SEric Christopher; CHECK: @use(i8 addrspace(1)* [[RELOCATED]]) 136*cee313d2SEric Christopher %1 = call i8 addrspace(1)* @boo() [ "deopt"() ] 137*cee313d2SEric Christopher %2 = call i8 addrspace(1)* @boo() [ "deopt"() ] 138*cee313d2SEric Christopher call void (...) @use(i8 addrspace(1)* %1) 139*cee313d2SEric Christopher ret void 140*cee313d2SEric Christopher} 141*cee313d2SEric Christopher 142*cee313d2SEric Christopher; Test updating a phi where not all inputs are live to begin with 143*cee313d2SEric Christopherdefine void @test5(i8 addrspace(1)* %arg) gc "statepoint-example" { 144*cee313d2SEric Christopher; CHECK-LABEL: test5 145*cee313d2SEric Christopherentry: 146*cee313d2SEric Christopher %0 = call i8 addrspace(1)* @boo() [ "deopt"() ] 147*cee313d2SEric Christopher switch i32 undef, label %kill [ 148*cee313d2SEric Christopher i32 10, label %merge 149*cee313d2SEric Christopher i32 13, label %merge 150*cee313d2SEric Christopher ] 151*cee313d2SEric Christopher 152*cee313d2SEric Christopherkill: ; preds = %entry 153*cee313d2SEric Christopher br label %merge 154*cee313d2SEric Christopher 155*cee313d2SEric Christophermerge: ; preds = %kill, %entry, %entry 156*cee313d2SEric Christopher; CHECK: merge: 157*cee313d2SEric Christopher; CHECK: %test = phi i8 addrspace(1) 158*cee313d2SEric Christopher; CHECK-DAG: [ null, %kill ] 159*cee313d2SEric Christopher; CHECK-DAG: [ %arg.relocated, %entry ] 160*cee313d2SEric Christopher; CHECK-DAG: [ %arg.relocated, %entry ] 161*cee313d2SEric Christopher %test = phi i8 addrspace(1)* [ null, %kill ], [ %arg, %entry ], [ %arg, %entry ] 162*cee313d2SEric Christopher call void (...) @use(i8 addrspace(1)* %test) 163*cee313d2SEric Christopher ret void 164*cee313d2SEric Christopher} 165*cee313d2SEric Christopher 166*cee313d2SEric Christopher; Check to make sure we handle values live over an entry statepoint 167*cee313d2SEric Christopherdefine void @test6(i8 addrspace(1)* %arg1, i8 addrspace(1)* %arg2, i8 addrspace(1)* %arg3) gc "statepoint-example" { 168*cee313d2SEric Christopher; CHECK-LABEL: @test6 169*cee313d2SEric Christopherentry: 170*cee313d2SEric Christopher br i1 undef, label %gc.safepoint_poll.exit2, label %do_safepoint 171*cee313d2SEric Christopher 172*cee313d2SEric Christopherdo_safepoint: ; preds = %entry 173*cee313d2SEric Christopher; CHECK-LABEL: do_safepoint: 174*cee313d2SEric Christopher; CHECK: gc.statepoint 175*cee313d2SEric Christopher; CHECK: arg1.relocated = 176*cee313d2SEric Christopher; CHECK: arg2.relocated = 177*cee313d2SEric Christopher; CHECK: arg3.relocated = 178*cee313d2SEric Christopher call void @foo() [ "deopt"(i8 addrspace(1)* %arg1, i8 addrspace(1)* %arg2, i8 addrspace(1)* %arg3) ] 179*cee313d2SEric Christopher br label %gc.safepoint_poll.exit2 180*cee313d2SEric Christopher 181*cee313d2SEric Christophergc.safepoint_poll.exit2: ; preds = %do_safepoint, %entry 182*cee313d2SEric Christopher; CHECK-LABEL: gc.safepoint_poll.exit2: 183*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* 184*cee313d2SEric Christopher; CHECK-DAG: [ %arg3, %entry ] 185*cee313d2SEric Christopher; CHECK-DAG: [ %arg3.relocated, %do_safepoint ] 186*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* 187*cee313d2SEric Christopher; CHECK-DAG: [ %arg2, %entry ] 188*cee313d2SEric Christopher; CHECK-DAG: [ %arg2.relocated, %do_safepoint ] 189*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* 190*cee313d2SEric Christopher; CHECK-DAG: [ %arg1, %entry ] 191*cee313d2SEric Christopher; CHECK-DAG: [ %arg1.relocated, %do_safepoint ] 192*cee313d2SEric Christopher call void (...) @use(i8 addrspace(1)* %arg1, i8 addrspace(1)* %arg2, i8 addrspace(1)* %arg3) 193*cee313d2SEric Christopher ret void 194*cee313d2SEric Christopher} 195*cee313d2SEric Christopher 196*cee313d2SEric Christopher; Check relocation in a loop nest where a relocation happens in the outer 197*cee313d2SEric Christopher; but not the inner loop 198*cee313d2SEric Christopherdefine void @test_outer_loop(i8 addrspace(1)* %arg1, i8 addrspace(1)* %arg2, i1 %cmp) gc "statepoint-example" { 199*cee313d2SEric Christopher; CHECK-LABEL: @test_outer_loop 200*cee313d2SEric Christopher 201*cee313d2SEric Christopherbci_0: 202*cee313d2SEric Christopher br label %outer-loop 203*cee313d2SEric Christopher 204*cee313d2SEric Christopherouter-loop: ; preds = %outer-inc, %bci_0 205*cee313d2SEric Christopher; CHECK-LABEL: outer-loop: 206*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* [ %arg2, %bci_0 ], [ %arg2.relocated, %outer-inc ] 207*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* [ %arg1, %bci_0 ], [ %arg1.relocated, %outer-inc ] 208*cee313d2SEric Christopher br label %inner-loop 209*cee313d2SEric Christopher 210*cee313d2SEric Christopherinner-loop: ; preds = %inner-loop, %outer-loop 211*cee313d2SEric Christopher br i1 %cmp, label %inner-loop, label %outer-inc 212*cee313d2SEric Christopher 213*cee313d2SEric Christopherouter-inc: ; preds = %inner-loop 214*cee313d2SEric Christopher; CHECK-LABEL: outer-inc: 215*cee313d2SEric Christopher; CHECK: %arg1.relocated 216*cee313d2SEric Christopher; CHECK: %arg2.relocated 217*cee313d2SEric Christopher call void @foo() [ "deopt"(i8 addrspace(1)* %arg1, i8 addrspace(1)* %arg2) ] 218*cee313d2SEric Christopher br label %outer-loop 219*cee313d2SEric Christopher} 220*cee313d2SEric Christopher 221*cee313d2SEric Christopher; Check that both inner and outer loops get phis when relocation is in 222*cee313d2SEric Christopher; inner loop 223*cee313d2SEric Christopherdefine void @test_inner_loop(i8 addrspace(1)* %arg1, i8 addrspace(1)* %arg2, i1 %cmp) gc "statepoint-example" { 224*cee313d2SEric Christopher; CHECK-LABEL: @test_inner_loop 225*cee313d2SEric Christopher 226*cee313d2SEric Christopherbci_0: 227*cee313d2SEric Christopher br label %outer-loop 228*cee313d2SEric Christopher 229*cee313d2SEric Christopherouter-loop: ; preds = %outer-inc, %bci_0 230*cee313d2SEric Christopher; CHECK-LABEL: outer-loop: 231*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* [ %arg2, %bci_0 ], [ %arg2.relocated, %outer-inc ] 232*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* [ %arg1, %bci_0 ], [ %arg1.relocated, %outer-inc ] 233*cee313d2SEric Christopher br label %inner-loop 234*cee313d2SEric Christopher; CHECK-LABEL: inner-loop 235*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* 236*cee313d2SEric Christopher; CHECK-DAG: %outer-loop ] 237*cee313d2SEric Christopher; CHECK-DAG: [ %arg2.relocated, %inner-loop ] 238*cee313d2SEric Christopher; CHECK: phi i8 addrspace(1)* 239*cee313d2SEric Christopher; CHECK-DAG: %outer-loop ] 240*cee313d2SEric Christopher; CHECK-DAG: [ %arg1.relocated, %inner-loop ] 241*cee313d2SEric Christopher; CHECK: gc.statepoint 242*cee313d2SEric Christopher; CHECK: %arg1.relocated 243*cee313d2SEric Christopher; CHECK: %arg2.relocated 244*cee313d2SEric Christopher 245*cee313d2SEric Christopherinner-loop: ; preds = %inner-loop, %outer-loop 246*cee313d2SEric Christopher call void @foo() [ "deopt"(i8 addrspace(1)* %arg1, i8 addrspace(1)* %arg2) ] 247*cee313d2SEric Christopher br i1 %cmp, label %inner-loop, label %outer-inc 248*cee313d2SEric Christopher 249*cee313d2SEric Christopherouter-inc: ; preds = %inner-loop 250*cee313d2SEric Christopher; CHECK-LABEL: outer-inc: 251*cee313d2SEric Christopher; This test shows why updating just those uses of the original value being 252*cee313d2SEric Christopher; relocated dominated by the inserted relocation is not always sufficient. 253*cee313d2SEric Christopher br label %outer-loop 254*cee313d2SEric Christopher} 255*cee313d2SEric Christopher 256*cee313d2SEric Christopherdefine i64 addrspace(1)* @test7(i64 addrspace(1)* %obj, i64 addrspace(1)* %obj2, i1 %condition) gc "statepoint-example" { 257*cee313d2SEric Christopher; CHECK-LABEL: @test7 258*cee313d2SEric Christopherentry: 259*cee313d2SEric Christopher br i1 %condition, label %branch2, label %join 260*cee313d2SEric Christopher 261*cee313d2SEric Christopherbranch2: ; preds = %entry 262*cee313d2SEric Christopher br i1 %condition, label %callbb, label %join2 263*cee313d2SEric Christopher 264*cee313d2SEric Christophercallbb: ; preds = %branch2 265*cee313d2SEric Christopher call void @foo() [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ] 266*cee313d2SEric Christopher br label %join 267*cee313d2SEric Christopher 268*cee313d2SEric Christopherjoin: ; preds = %callbb, %entry 269*cee313d2SEric Christopher; CHECK-LABEL: join: 270*cee313d2SEric Christopher; CHECK: phi i64 addrspace(1)* [ %obj.relocated.casted, %callbb ], [ %obj, %entry ] 271*cee313d2SEric Christopher; CHECK: phi i64 addrspace(1)* 272*cee313d2SEric Christopher; CHECK-DAG: [ %obj, %entry ] 273*cee313d2SEric Christopher; CHECK-DAG: [ %obj2.relocated.casted, %callbb ] 274*cee313d2SEric Christopher %phi1 = phi i64 addrspace(1)* [ %obj, %entry ], [ %obj2, %callbb ] 275*cee313d2SEric Christopher br label %join2 276*cee313d2SEric Christopher 277*cee313d2SEric Christopherjoin2: ; preds = %join, %branch2 278*cee313d2SEric Christopher; CHECK-LABEL: join2: 279*cee313d2SEric Christopher; CHECK: phi2 = phi i64 addrspace(1)* 280*cee313d2SEric Christopher; CHECK-DAG: %join ] 281*cee313d2SEric Christopher; CHECK-DAG: [ %obj2, %branch2 ] 282*cee313d2SEric Christopher %phi2 = phi i64 addrspace(1)* [ %obj, %join ], [ %obj2, %branch2 ] 283*cee313d2SEric Christopher ret i64 addrspace(1)* %phi2 284*cee313d2SEric Christopher} 285*cee313d2SEric Christopher 286*cee313d2SEric Christopherdeclare void @do_safepoint() 287