1; RUN: opt -S -rewrite-statepoints-for-gc %s | FileCheck %s 2 3declare void @foo() 4declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...) 5 6; constants don't get relocated. 7define 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)*) 11entry: 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. 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 24entry: 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 29taken: 30 ret i8 0 31 32not_taken: 33 %cmp2 = icmp ne i8 addrspace(1)* %p, null 34 br i1 %cmp2, label %taken, label %dead 35 36dead: 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 50define 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 54entry: 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. 63define i8 addrspace(1)* @test4(i8 addrspace(1)* %p) gc "statepoint-example" { 64; CHECK-LABEL: @test4 65entry: 66 %is_null = icmp eq i8 addrspace(1)* %p, null 67 br i1 %is_null, label %split, label %join 68 69split: 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 75join: 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 83early-exit: 84 ret i8 addrspace(1)* null 85 86use: 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