mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +00:00 
			
		
		
		
	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
		
	
		
			
				
	
	
		
			62 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			LLVM
		
	
	
	
	
	
			
		
		
	
	
			62 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			LLVM
		
	
	
	
	
	
| ; RUN: opt -S -rewrite-statepoints-for-gc %s | FileCheck %s
 | |
| 
 | |
| declare void @foo()
 | |
| declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
 | |
| 
 | |
| ; constants don't get relocated.
 | |
| define i8 @test() gc "statepoint-example" {
 | |
| ; CHECK-LABEL: @test
 | |
| ; CHECK: gc.statepoint
 | |
| ; CHECK-NEXT: load i8, i8 addrspace(1)* inttoptr (i64 15 to i8 addrspace(1)*)
 | |
| entry:
 | |
|   call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0)
 | |
|   %res = load i8, i8 addrspace(1)* inttoptr (i64 15 to i8 addrspace(1)*)
 | |
|   ret i8 %res
 | |
| }
 | |
| 
 | |
| 
 | |
| ; Mostly just here to show reasonable code test can come from.  
 | |
| define i8 @test2(i8 addrspace(1)* %p) gc "statepoint-example" {
 | |
| ; CHECK-LABEL: @test2
 | |
| ; CHECK: gc.statepoint
 | |
| ; CHECK-NEXT: gc.relocate
 | |
| ; CHECK-NEXT: icmp
 | |
| entry:
 | |
|   call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0)
 | |
|   %cmp = icmp eq i8 addrspace(1)* %p, null
 | |
|   br i1 %cmp, label %taken, label %not_taken
 | |
| 
 | |
| taken:
 | |
|   ret i8 0
 | |
| 
 | |
| not_taken:
 | |
|   %cmp2 = icmp ne i8 addrspace(1)* %p, null
 | |
|   br i1 %cmp2, label %taken, label %dead
 | |
| 
 | |
| dead:
 | |
|   ; We see that dead can't be reached, but the optimizer might not.  It's 
 | |
|   ; completely legal for it to exploit the fact that if dead executed, %p 
 | |
|   ; would have to equal null.  This can produce intermediate states which 
 | |
|   ; look like that of test above, even if arbitrary constant addresses aren't
 | |
|   ; legal in the source language
 | |
|   %addr = getelementptr i8, i8 addrspace(1)* %p, i32 15
 | |
|   %res = load i8, i8addrspace(1)* %addr
 | |
|   ret i8 %res
 | |
| }
 | |
| 
 | |
| @G = addrspace(1) global i8 5
 | |
| 
 | |
| ; Globals don't move and thus don't get relocated
 | |
| define i8 @test3(i1 %always_true) gc "statepoint-example" {
 | |
| ; CHECK-LABEL: @test3
 | |
| ; CHECK: gc.statepoint
 | |
| ; CHECK-NEXT: load i8, i8 addrspace(1)* @G
 | |
| entry:
 | |
|   call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0)
 | |
|   %res = load i8, i8 addrspace(1)* @G, align 1
 | |
|   ret i8 %res
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 |