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