1 ; RUN: opt -S -rewrite-statepoints-for-gc %s | FileCheck %s 2 3 declare void @foo() 4 declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...) 5 6 ; constants don't get relocated. 7 define i8 @test() gc "statepoint-example" { 8 ; CHECK-LABEL: @test 9 ; CHECK: gc.statepoint 10 ; CHECK-NEXT: load i8, i8 addrspace(1)* inttoptr (i64 15 to i8 addrspace(1)*) 11 entry: 12 call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 0) 13 %res = load i8, i8 addrspace(1)* inttoptr (i64 15 to i8 addrspace(1)*) 14 ret i8 %res 15 } 16 17 18 ; Mostly just here to show reasonable code test can come from. 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 entry: 25 call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 0) 26 %cmp = icmp eq i8 addrspace(1)* %p, null 27 br i1 %cmp, label %taken, label %not_taken 28 29 taken: 30 ret i8 0 31 32 not_taken: 33 %cmp2 = icmp ne i8 addrspace(1)* %p, null 34 br i1 %cmp2, label %taken, label %dead 35 36 dead: 37 ; We see that dead can't be reached, but the optimizer might not. It's 38 ; completely legal for it to exploit the fact that if dead executed, %p 39 ; would have to equal null. This can produce intermediate states which 40 ; look like that of test above, even if arbitrary constant addresses aren't 41 ; legal in the source language 42 %addr = getelementptr i8, i8 addrspace(1)* %p, i32 15 43 %res = load i8, i8addrspace(1)* %addr 44 ret i8 %res 45 } 46 47 @G = addrspace(1) global i8 5 48 49 ; Globals don't move and thus don't get relocated 50 define i8 @test3(i1 %always_true) gc "statepoint-example" { 51 ; CHECK-LABEL: @test3 52 ; CHECK: gc.statepoint 53 ; CHECK-NEXT: load i8, i8 addrspace(1)* @G 54 entry: 55 call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 0) 56 %res = load i8, i8 addrspace(1)* @G, align 1 57 ret i8 %res 58 } 59 60 ; Even for source languages without constant references, we can 61 ; see constants can show up along paths where the value is dead. 62 ; This is particular relevant when computing bases of PHIs. 63 define i8 addrspace(1)* @test4(i8 addrspace(1)* %p) gc "statepoint-example" { 64 ; CHECK-LABEL: @test4 65 entry: 66 %is_null = icmp eq i8 addrspace(1)* %p, null 67 br i1 %is_null, label %split, label %join 68 69 split: 70 call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 0) 71 %arg_value_addr.i = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8 72 %arg_value_addr_casted.i = bitcast i8 addrspace(1)* %arg_value_addr.i to i8 addrspace(1)* addrspace(1)* 73 br label %join 74 75 join: 76 ; CHECK-LABEL: join 77 ; CHECK: %addr2.base = 78 %addr2 = phi i8 addrspace(1)* addrspace(1)* [ %arg_value_addr_casted.i, %split ], [ inttoptr (i64 8 to i8 addrspace(1)* addrspace(1)*), %entry ] 79 ;; NOTE: This particular example can be jump-threaded, but in general, 80 ;; we can't, and have to deal with the resulting IR. 81 br i1 %is_null, label %early-exit, label %use 82 83 early-exit: 84 ret i8 addrspace(1)* null 85 86 use: 87 ; CHECK-LABEL: use: 88 ; CHECK: gc.statepoint 89 ; CHECK: gc.relocate 90 call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 0) 91 %res = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)* %addr2, align 1 92 ret i8 addrspace(1)* %res 93 } 94 95 96