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 6 declare void @foo() 7 8 define 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. 13 entry: 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 19 define 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 25 entry: 26 call void @foo() [ "deopt"() ] 27 %cmp = icmp eq i8 addrspace(1)* %p, null 28 br i1 %cmp, label %taken, label %not_taken 29 30 taken: ; preds = %not_taken, %entry 31 ret i8 0 32 33 not_taken: ; preds = %entry 34 %cmp2 = icmp ne i8 addrspace(1)* %p, null 35 br i1 %cmp2, label %taken, label %dead 36 37 dead: ; 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 43 define 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 47 entry: 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. 56 define i8 addrspace(1)* @test4(i8 addrspace(1)* %p) gc "statepoint-example" { 57 ; CHECK-LABEL: @test4 58 entry: 59 %is_null = icmp eq i8 addrspace(1)* %p, null 60 br i1 %is_null, label %split, label %join 61 62 split: 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 68 join: 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 76 early-exit: 77 ret i8 addrspace(1)* null 78 79 use: 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 89 define 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 93 entry: 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 99 define i8 addrspace(1)* @test6(i64 %arg) gc "statepoint-example" { 100 entry: 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 110 define i8 addrspace(1)* @test7(i64 %arg) gc "statepoint-example" { 111 entry: 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 121 define 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 125 entry: 126 %is_null = icmp eq i8 addrspace(1)* %p, null 127 br i1 %is_null, label %null.crit-edge, label %not-null 128 129 not-null: 130 %load_addr = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8 131 br label %join 132 133 null.crit-edge: 134 %load_addr.const = getelementptr inbounds i8, i8 addrspace(1)* null, i64 8 135 br label %join 136 137 join: 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 148 early-exit: 149 ret i8 0 150 151 use: 152 %res = load i8, i8 addrspace(1)* %addr, align 1 153 ret i8 %res 154 } 155 156 define 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 160 entry: 161 %is_null = icmp eq i8 addrspace(1)* %p, null 162 br i1 %is_null, label %null.crit-edge, label %not-null 163 164 not-null: 165 %load_addr = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8 166 br label %join 167 168 null.crit-edge: 169 br label %join 170 171 join: 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 182 early-exit: 183 ret i8 0 184 185 use: 186 %res = load i8, i8 addrspace(1)* %addr, align 1 187 ret i8 %res 188 } 189 190 define 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 194 entry: 195 %is_null = icmp eq i8 addrspace(1)* %p, null 196 br i1 %is_null, label %null.crit-edge, label %not-null 197 198 not-null: 199 %load_addr = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8 200 br label %join 201 202 null.crit-edge: 203 br label %join 204 205 join: 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 216 early-exit: 217 ret i8 0 218 219 use: 220 %res = load i8, i8 addrspace(1)* %addr, align 1 221 ret i8 %res 222 } 223 224 define 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 228 entry: 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 237 define <2 x i32 addrspace(1)*> @test12(i1 %c) gc "statepoint-example" { 238 ; CHECK-LABEL: @test12 239 ; Same as test11 but with vectors 240 entry: 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 251 define <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 254 entry: 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