1; RUN: opt -S -rewrite-statepoints-for-gc < %s | FileCheck %s 2 3; constants don't get relocated. 4@G = addrspace(1) global i8 5 5 6declare void @foo() 7 8define i8 @test() gc "statepoint-example" { 9; CHECK-LABEL: @test 10; CHECK: gc.statepoint 11; CHECK-NEXT: load i8, i8 addrspace(1)* inttoptr (i64 15 to i8 addrspace(1)*) 12; Mostly just here to show reasonable code test can come from. 13entry: 14 call void @foo() [ "deopt"() ] 15 %res = load i8, i8 addrspace(1)* inttoptr (i64 15 to i8 addrspace(1)*) 16 ret i8 %res 17} 18 19define i8 @test2(i8 addrspace(1)* %p) gc "statepoint-example" { 20; CHECK-LABEL: @test2 21; CHECK: gc.statepoint 22; CHECK-NEXT: gc.relocate 23; CHECK-NEXT: icmp 24; Globals don't move and thus don't get relocated 25entry: 26 call void @foo() [ "deopt"() ] 27 %cmp = icmp eq i8 addrspace(1)* %p, null 28 br i1 %cmp, label %taken, label %not_taken 29 30taken: ; preds = %not_taken, %entry 31 ret i8 0 32 33not_taken: ; preds = %entry 34 %cmp2 = icmp ne i8 addrspace(1)* %p, null 35 br i1 %cmp2, label %taken, label %dead 36 37dead: ; preds = %not_taken 38 %addr = getelementptr i8, i8 addrspace(1)* %p, i32 15 39 %res = load i8, i8 addrspace(1)* %addr 40 ret i8 %res 41} 42 43define i8 @test3(i1 %always_true) gc "statepoint-example" { 44; CHECK-LABEL: @test3 45; CHECK: gc.statepoint 46; CHECK-NEXT: load i8, i8 addrspace(1)* @G 47entry: 48 call void @foo() [ "deopt"() ] 49 %res = load i8, i8 addrspace(1)* @G, align 1 50 ret i8 %res 51} 52 53; Even for source languages without constant references, we can 54; see constants can show up along paths where the value is dead. 55; This is particular relevant when computing bases of PHIs. 56define i8 addrspace(1)* @test4(i8 addrspace(1)* %p) gc "statepoint-example" { 57; CHECK-LABEL: @test4 58entry: 59 %is_null = icmp eq i8 addrspace(1)* %p, null 60 br i1 %is_null, label %split, label %join 61 62split: 63 call void @foo() 64 %arg_value_addr.i = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8 65 %arg_value_addr_casted.i = bitcast i8 addrspace(1)* %arg_value_addr.i to i8 addrspace(1)* addrspace(1)* 66 br label %join 67 68join: 69; CHECK-LABEL: join 70; CHECK: %addr2.base = 71 %addr2 = phi i8 addrspace(1)* addrspace(1)* [ %arg_value_addr_casted.i, %split ], [ inttoptr (i64 8 to i8 addrspace(1)* addrspace(1)*), %entry ] 72 ;; NOTE: This particular example can be jump-threaded, but in general, 73 ;; we can't, and have to deal with the resulting IR. 74 br i1 %is_null, label %early-exit, label %use 75 76early-exit: 77 ret i8 addrspace(1)* null 78 79use: 80; CHECK-LABEL: use: 81; CHECK: gc.statepoint 82; CHECK: gc.relocate 83 call void @foo() 84 %res = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)* %addr2, align 1 85 ret i8 addrspace(1)* %res 86} 87 88; Globals don't move and thus don't get relocated 89define i8 addrspace(1)* @test5(i1 %always_true) gc "statepoint-example" { 90; CHECK-LABEL: @test5 91; CHECK: gc.statepoint 92; CHECK-NEXT: %res = extractelement <2 x i8 addrspace(1)*> <i8 addrspace(1)* @G, i8 addrspace(1)* @G>, i32 0 93entry: 94 call void @foo() 95 %res = extractelement <2 x i8 addrspace(1)*> <i8 addrspace(1)* @G, i8 addrspace(1)* @G>, i32 0 96 ret i8 addrspace(1)* %res 97} 98 99define i8 addrspace(1)* @test6(i64 %arg) gc "statepoint-example" { 100entry: 101 ; Don't fail any assertions and don't record null as a live value 102 ; CHECK-LABEL: test6 103 ; CHECK: gc.statepoint 104 ; CHECK-NOT: call {{.*}}gc.relocate 105 %load_addr = getelementptr i8, i8 addrspace(1)* null, i64 %arg 106 call void @foo() [ "deopt"() ] 107 ret i8 addrspace(1)* %load_addr 108} 109 110define i8 addrspace(1)* @test7(i64 %arg) gc "statepoint-example" { 111entry: 112 ; Same as test7 but use regular constant instead of a null 113 ; CHECK-LABEL: test7 114 ; CHECK: gc.statepoint 115 ; CHECK-NOT: call {{.*}}gc.relocate 116 %load_addr = getelementptr i8, i8 addrspace(1)* inttoptr (i64 15 to i8 addrspace(1)*), i64 %arg 117 call void @foo() [ "deopt"() ] 118 ret i8 addrspace(1)* %load_addr 119} 120 121define i8 @test8(i8 addrspace(1)* %p) gc "statepoint-example" { 122; Checks that base( phi(gep null, oop) ) = phi(null, base(oop)) and that we 123; correctly relocate this value 124; CHECK-LABEL: @test8 125entry: 126 %is_null = icmp eq i8 addrspace(1)* %p, null 127 br i1 %is_null, label %null.crit-edge, label %not-null 128 129not-null: 130 %load_addr = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8 131 br label %join 132 133null.crit-edge: 134 %load_addr.const = getelementptr inbounds i8, i8 addrspace(1)* null, i64 8 135 br label %join 136 137join: 138 %addr = phi i8 addrspace(1)* [ %load_addr, %not-null ], [%load_addr.const, %null.crit-edge] 139 ; CHECK: %addr.base = phi i8 addrspace(1)* 140 ; CHECK-DAG: [ %p, %not-null ] 141 ; CHECK-DAG: [ null, %null.crit-edge ] 142 ; CHECK: gc.statepoint 143 call void @foo() [ "deopt"() ] 144 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr.base) 145 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr) 146 br i1 %is_null, label %early-exit, label %use 147 148early-exit: 149 ret i8 0 150 151use: 152 %res = load i8, i8 addrspace(1)* %addr, align 1 153 ret i8 %res 154} 155 156define i8 @test9(i8 addrspace(1)* %p) gc "statepoint-example" { 157; Checks that base( phi(inttoptr, oop) ) = phi(null, base(oop)) and that we 158; correctly relocate this value 159; CHECK-LABEL: @test9 160entry: 161 %is_null = icmp eq i8 addrspace(1)* %p, null 162 br i1 %is_null, label %null.crit-edge, label %not-null 163 164not-null: 165 %load_addr = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8 166 br label %join 167 168null.crit-edge: 169 br label %join 170 171join: 172 %addr = phi i8 addrspace(1)* [ %load_addr, %not-null ], [inttoptr (i64 8 to i8 addrspace(1)*), %null.crit-edge] 173 ; CHECK: %addr.base = phi i8 addrspace(1)* 174 ; CHECK-DAG: [ %p, %not-null ] 175 ; CHECK-DAG: [ null, %null.crit-edge ] 176 ; CHECK: gc.statepoint 177 call void @foo() [ "deopt"() ] 178 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr.base) 179 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr) 180 br i1 %is_null, label %early-exit, label %use 181 182early-exit: 183 ret i8 0 184 185use: 186 %res = load i8, i8 addrspace(1)* %addr, align 1 187 ret i8 %res 188} 189 190define i8 @test10(i8 addrspace(1)* %p) gc "statepoint-example" { 191; Checks that base( phi(const gep, oop) ) = phi(null, base(oop)) and that we 192; correctly relocate this value 193; CHECK-LABEL: @test10 194entry: 195 %is_null = icmp eq i8 addrspace(1)* %p, null 196 br i1 %is_null, label %null.crit-edge, label %not-null 197 198not-null: 199 %load_addr = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8 200 br label %join 201 202null.crit-edge: 203 br label %join 204 205join: 206 %addr = phi i8 addrspace(1)* [ %load_addr, %not-null ], [getelementptr (i8, i8 addrspace(1)* null, i64 8), %null.crit-edge] 207 ; CHECK: %addr.base = phi i8 addrspace(1)* 208 ; CHECK-DAG: [ %p, %not-null ] 209 ; CHECK-DAG: [ null, %null.crit-edge ] 210 ; CHECK: gc.statepoint 211 call void @foo() [ "deopt"() ] 212 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr.base) 213 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr) 214 br i1 %is_null, label %early-exit, label %use 215 216early-exit: 217 ret i8 0 218 219use: 220 %res = load i8, i8 addrspace(1)* %addr, align 1 221 ret i8 %res 222} 223 224define i32 addrspace(1)* @test11(i1 %c) gc "statepoint-example" { 225; CHECK-LABEL: @test11 226; Checks that base( select(const1, const2) ) == null and that we don't record 227; such value in the oop map 228entry: 229 %val = select i1 %c, i32 addrspace(1)* inttoptr (i64 8 to i32 addrspace(1)*), i32 addrspace(1)* inttoptr (i64 15 to i32 addrspace(1)*) 230 ; CHECK: gc.statepoint 231 ; CHECK-NOT: call {{.*}}gc.relocate 232 call void @foo() [ "deopt"() ] 233 ret i32 addrspace(1)* %val 234} 235 236 237define <2 x i32 addrspace(1)*> @test12(i1 %c) gc "statepoint-example" { 238; CHECK-LABEL: @test12 239; Same as test11 but with vectors 240entry: 241 %val = select i1 %c, <2 x i32 addrspace(1)*> <i32 addrspace(1)* inttoptr (i64 5 to i32 addrspace(1)*), 242 i32 addrspace(1)* inttoptr (i64 15 to i32 addrspace(1)*)>, 243 <2 x i32 addrspace(1)*> <i32 addrspace(1)* inttoptr (i64 30 to i32 addrspace(1)*), 244 i32 addrspace(1)* inttoptr (i64 60 to i32 addrspace(1)*)> 245 ; CHECK: gc.statepoint 246 ; CHECK-NOT: call {{.*}}gc.relocate 247 call void @foo() [ "deopt"() ] 248 ret <2 x i32 addrspace(1)*> %val 249} 250 251define <2 x i32 addrspace(1)*> @test13(i1 %c, <2 x i32 addrspace(1)*> %ptr) gc "statepoint-example" { 252; CHECK-LABEL: @test13 253; Similar to test8, test9 and test10 but with vectors 254entry: 255 %val = select i1 %c, <2 x i32 addrspace(1)*> %ptr, 256 <2 x i32 addrspace(1)*> <i32 addrspace(1)* inttoptr (i64 30 to i32 addrspace(1)*), i32 addrspace(1)* inttoptr (i64 60 to i32 addrspace(1)*)> 257 ; CHECK: %val.base = select i1 %c, <2 x i32 addrspace(1)*> %ptr, <2 x i32 addrspace(1)*> zeroinitializer, !is_base_value !0 258 ; CHECK: gc.statepoint 259 call void @foo() [ "deopt"() ] 260 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%val.base, %val.base) 261 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%val.base, %val) 262 ret <2 x i32 addrspace(1)*> %val 263} 264