mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 19:31:58 +00:00
28fa9e1e9f
This change includes the most basic possible GCStrategy for a GC which is using the statepoint lowering code. At the moment, this GCStrategy doesn't really do much - aside from actually generate correct stackmaps that is - but I went ahead and added a few extra correctness checks as proof of concept. It's mostly here to provide documentation on how to do one, and to provide a point for various optimization legality hooks I'd like to add going forward. (For context, see the TODOs in InstCombine around gc.relocate.) Most of the validation logic added here as proof of concept will soon move in to the Verifier. That move is dependent on http://reviews.llvm.org/D6811 There was discussion in the review thread about addrspace(1) being reserved for something. I'm going to follow up on a seperate llvmdev thread. If needed, I'll update all the code at once. Note that I am deliberately not making a GCStrategy required to use gc.statepoints with this change. I want to give folks out of tree - including myself - a chance to migrate. In a week or two, I'll make having a GCStrategy be required for gc.statepoints. To this end, I added the gc tag to one of the test cases but not others. Differential Revision: http://reviews.llvm.org/D6808 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225365 91177308-0d34-0410-b5e6-96231b3b80d8
108 lines
4.8 KiB
LLVM
108 lines
4.8 KiB
LLVM
; RUN: opt -O3 -S < %s | FileCheck --check-prefix=CHECK-OPT %s
|
|
; RUN: llc < %s | FileCheck --check-prefix=CHECK-LLC %s
|
|
; These tests are targetted at making sure we don't retain information
|
|
; about memory which contains potential gc references across a statepoint.
|
|
; They're carefully written to only outlaw forwarding of references.
|
|
; Depending on the collector, forwarding non-reference fields or
|
|
; constant null references may be perfectly legal. (If unimplemented.)
|
|
; The general structure of these tests is:
|
|
; - learn a fact about memory (via an assume)
|
|
; - cross a statepoint
|
|
; - check the same fact about memory (which we no longer know)
|
|
|
|
target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"
|
|
target triple = "x86_64-pc-linux-gnu"
|
|
|
|
; If not at a statepoint, we could forward known memory values
|
|
; across this call.
|
|
declare void @func() readonly
|
|
|
|
;; Forwarding the value of a pointer load is invalid since it may have
|
|
;; changed at the safepoint. Forwarding a non-gc pointer value would
|
|
;; be valid, but is not currently implemented.
|
|
define i1 @test_load_forward(i32 addrspace(1)* addrspace(1)* %p) gc "statepoint-example" {
|
|
entry:
|
|
%before = load i32 addrspace(1)* addrspace(1)* %p
|
|
%cmp1 = call i1 @f(i32 addrspace(1)* %before)
|
|
call void @llvm.assume(i1 %cmp1)
|
|
%safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* addrspace(1)* %p)
|
|
%pnew = call i32 addrspace(1)* addrspace(1)* @llvm.experimental.gc.relocate.p1p1i32(i32 %safepoint_token, i32 4, i32 4)
|
|
%after = load i32 addrspace(1)* addrspace(1)* %pnew
|
|
%cmp2 = call i1 @f(i32 addrspace(1)* %after)
|
|
ret i1 %cmp2
|
|
|
|
; CHECK-OPT-LABEL: test_load_forward
|
|
; CHECK-OPT: ret i1 %cmp2
|
|
; CHECK-LLC-LABEL: test_load_forward
|
|
; CHECK-LLC: callq f
|
|
}
|
|
|
|
;; Same as above, but forwarding from a store
|
|
define i1 @test_store_forward(i32 addrspace(1)* addrspace(1)* %p,
|
|
i32 addrspace(1)* %v) gc "statepoint-example" {
|
|
entry:
|
|
%cmp1 = call i1 @f(i32 addrspace(1)* %v)
|
|
call void @llvm.assume(i1 %cmp1)
|
|
store i32 addrspace(1)* %v, i32 addrspace(1)* addrspace(1)* %p
|
|
%safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* addrspace(1)* %p)
|
|
%pnew = call i32 addrspace(1)* addrspace(1)* @llvm.experimental.gc.relocate.p1p1i32(i32 %safepoint_token, i32 4, i32 4)
|
|
%after = load i32 addrspace(1)* addrspace(1)* %pnew
|
|
%cmp2 = call i1 @f(i32 addrspace(1)* %after)
|
|
ret i1 %cmp2
|
|
|
|
; CHECK-OPT-LABEL: test_store_forward
|
|
; CHECK-OPT: ret i1 %cmp2
|
|
; CHECK-LLC-LABEL: test_store_forward
|
|
; CHECK-LLC: callq f
|
|
}
|
|
|
|
; A predicate on the pointer which is not simply null, but whose value
|
|
; would be known unchanged if the pointer value could be forwarded.
|
|
; The implementation of such a function could inspect the integral value
|
|
; of the pointer and is thus not safe to reuse after a statepoint.
|
|
declare i1 @f(i32 addrspace(1)* %v) readnone
|
|
|
|
; This is a variant of the test_load_forward test which is intended to
|
|
; highlight the fact that a gc pointer can be stored in part of the heap
|
|
; that is not itself GC managed. The GC may have an external mechanism
|
|
; to know about and update that value at a safepoint. Note that the
|
|
; statepoint does not provide the collector with this root.
|
|
define i1 @test_load_forward_nongc_heap(i32 addrspace(1)** %p) gc "statepoint-example" {
|
|
entry:
|
|
%before = load i32 addrspace(1)** %p
|
|
%cmp1 = call i1 @f(i32 addrspace(1)* %before)
|
|
call void @llvm.assume(i1 %cmp1)
|
|
call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0)
|
|
%after = load i32 addrspace(1)** %p
|
|
%cmp2 = call i1 @f(i32 addrspace(1)* %after)
|
|
ret i1 %cmp2
|
|
|
|
; CHECK-OPT-LABEL: test_load_forward_nongc_heap
|
|
; CHECK-OPT: ret i1 %cmp2
|
|
; CHECK-LLC-LABEL: test_load_forward_nongc_heap
|
|
; CHECK-LLC: callq f
|
|
}
|
|
|
|
;; Same as above, but forwarding from a store
|
|
define i1 @test_store_forward_nongc_heap(i32 addrspace(1)** %p,
|
|
i32 addrspace(1)* %v) gc "statepoint-example" {
|
|
entry:
|
|
%cmp1 = call i1 @f(i32 addrspace(1)* %v)
|
|
call void @llvm.assume(i1 %cmp1)
|
|
store i32 addrspace(1)* %v, i32 addrspace(1)** %p
|
|
call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0)
|
|
%after = load i32 addrspace(1)** %p
|
|
%cmp2 = call i1 @f(i32 addrspace(1)* %after)
|
|
ret i1 %cmp2
|
|
|
|
; CHECK-OPT-LABEL: test_store_forward_nongc_heap
|
|
; CHECK-OPT: ret i1 %cmp2
|
|
; CHECK-LLC-LABEL: test_store_forward_nongc_heap
|
|
; CHECK-LLC: callq f
|
|
}
|
|
|
|
declare void @llvm.assume(i1)
|
|
declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
|
|
declare i32 addrspace(1)* addrspace(1)* @llvm.experimental.gc.relocate.p1p1i32(i32, i32, i32) #3
|
|
|