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