mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-21 19:32:16 +00:00
5c7f7462e4
This changes the shape of the statepoint intrinsic from: @llvm.experimental.gc.statepoint(anyptr target, i32 # call args, i32 unused, ...call args, i32 # deopt args, ...deopt args, ...gc args) to: @llvm.experimental.gc.statepoint(anyptr target, i32 # call args, i32 flags, ...call args, i32 # transition args, ...transition args, i32 # deopt args, ...deopt args, ...gc args) This extension offers the backend the opportunity to insert (somewhat) arbitrary code to manage the transition from GC-aware code to code that is not GC-aware and back. In order to support the injection of transition code, this extension wraps the STATEPOINT ISD node generated by the usual lowering lowering with two additional nodes: GC_TRANSITION_START and GC_TRANSITION_END. The transition arguments that were passed passed to the intrinsic (if any) are lowered and provided as operands to these nodes and may be used by the backend during code generation. Eventually, the lowering of the GC_TRANSITION_{START,END} nodes should be informed by the GC strategy in use for the function containing the intrinsic call; for now, these nodes are instead replaced with no-ops. Differential Revision: http://reviews.llvm.org/D9501 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236888 91177308-0d34-0410-b5e6-96231b3b80d8
84 lines
3.8 KiB
LLVM
84 lines
3.8 KiB
LLVM
; RUN: opt -S %s -verify | FileCheck %s
|
|
|
|
declare void @use(...)
|
|
declare i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32, i32, i32)
|
|
declare i64 addrspace(1)* @llvm.experimental.gc.relocate.p1i64(i32, i32, i32)
|
|
declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
|
|
declare i32 @"personality_function"()
|
|
|
|
;; Basic usage
|
|
define i64 addrspace(1)* @test1(i8 addrspace(1)* %arg) gc "statepoint-example" {
|
|
entry:
|
|
%cast = bitcast i8 addrspace(1)* %arg to i64 addrspace(1)*
|
|
%safepoint_token = call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* undef, i32 0, i32 0, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg, i8 addrspace(1)* %arg)
|
|
%reloc = call i64 addrspace(1)* @llvm.experimental.gc.relocate.p1i64(i32 %safepoint_token, i32 10, i32 11)
|
|
;; It is perfectly legal to relocate the same value multiple times...
|
|
%reloc2 = call i64 addrspace(1)* @llvm.experimental.gc.relocate.p1i64(i32 %safepoint_token, i32 10, i32 11)
|
|
%reloc3 = call i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %safepoint_token, i32 11, i32 10)
|
|
ret i64 addrspace(1)* %reloc
|
|
; CHECK-LABEL: test1
|
|
; CHECK: statepoint
|
|
; CHECK: gc.relocate
|
|
; CHECK: gc.relocate
|
|
; CHECK: gc.relocate
|
|
; CHECK: ret i64 addrspace(1)* %reloc
|
|
}
|
|
|
|
; This test catches two cases where the verifier was too strict:
|
|
; 1) A base doesn't need to be relocated if it's never used again
|
|
; 2) A value can be replaced by one which is known equal. This
|
|
; means a potentially derived pointer can be known base and that
|
|
; we can't check that derived pointer are never bases.
|
|
define void @test2(i8 addrspace(1)* %arg, i64 addrspace(1)* %arg2) gc "statepoint-example" {
|
|
entry:
|
|
%cast = bitcast i8 addrspace(1)* %arg to i64 addrspace(1)*
|
|
%c = icmp eq i64 addrspace(1)* %cast, %arg2
|
|
br i1 %c, label %equal, label %notequal
|
|
|
|
notequal:
|
|
ret void
|
|
|
|
equal:
|
|
%safepoint_token = call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* undef, i32 0, i32 0, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg, i8 addrspace(1)* %arg)
|
|
%reloc = call i64 addrspace(1)* @llvm.experimental.gc.relocate.p1i64(i32 %safepoint_token, i32 10, i32 11)
|
|
call void undef(i64 addrspace(1)* %reloc)
|
|
ret void
|
|
; CHECK-LABEL: test2
|
|
; CHECK-LABEL: equal
|
|
; CHECK: statepoint
|
|
; CHECK-NEXT: %reloc = call
|
|
; CHECK-NEXT: call
|
|
; CHECK-NEXT: ret voi
|
|
}
|
|
|
|
; Basic test for invoke statepoints
|
|
define i8 addrspace(1)* @test3(i8 addrspace(1)* %obj, i8 addrspace(1)* %obj1) gc "statepoint-example" {
|
|
; CHECK-LABEL: test3
|
|
entry:
|
|
; CHECK-LABEL: entry
|
|
; CHECK: statepoint
|
|
%0 = invoke i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* undef, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0, i8 addrspace(1)* %obj, i8 addrspace(1)* %obj1)
|
|
to label %normal_dest unwind label %exceptional_return
|
|
|
|
normal_dest:
|
|
; CHECK-LABEL: normal_dest:
|
|
; CHECK: gc.relocate
|
|
; CHECK: gc.relocate
|
|
; CHECK: ret
|
|
%obj.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %0, i32 10, i32 10)
|
|
%obj1.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %0, i32 10, i32 10)
|
|
ret i8 addrspace(1)* %obj.relocated
|
|
|
|
exceptional_return:
|
|
; CHECK-LABEL: exceptional_return
|
|
; CHECK: gc.relocate
|
|
; CHECK: gc.relocate
|
|
%landing_pad = landingpad { i8*, i32 } personality i32 ()* @"personality_function"
|
|
cleanup
|
|
%relocate_token = extractvalue { i8*, i32 } %landing_pad, 1
|
|
%obj.relocated1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %relocate_token, i32 10, i32 10)
|
|
%obj1.relocated1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %relocate_token, i32 10, i32 10)
|
|
ret i8 addrspace(1)* %obj1.relocated1
|
|
}
|
|
|