[llvm] r230601 - [GC docs] Add example IR, assembly, and stackmaps to Statepoint documentation

Philip Reames listmail at philipreames.com
Wed Feb 25 17:18:21 PST 2015


Author: reames
Date: Wed Feb 25 19:18:21 2015
New Revision: 230601

URL: http://llvm.org/viewvc/llvm-project?rev=230601&view=rev
Log:
[GC docs] Add example IR, assembly, and stackmaps to Statepoint documentation

When I originally committed the statepoint docs, I left placeholders for example IR fragments.  I'm finally getting around to filling those in.  

I also added IR fragments to illustrate the usage of the PlaceSafepoints pass while I was at it.


Modified:
    llvm/trunk/docs/Statepoints.rst

Modified: llvm/trunk/docs/Statepoints.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/Statepoints.rst?rev=230601&r1=230600&r2=230601&view=diff
==============================================================================
--- llvm/trunk/docs/Statepoints.rst (original)
+++ llvm/trunk/docs/Statepoints.rst Wed Feb 25 19:18:21 2015
@@ -115,21 +115,37 @@ garbage collected objects.
   <statepoint-utilities>` described below. 
 
 This abstract function call is concretely represented by a sequence of
-intrinsic calls known as a 'statepoint sequence'.
-
+intrinsic calls known collectively as a "statepoint relocation sequence".
 
 Let's consider a simple call in LLVM IR:
-  todo
 
-Depending on our language we may need to allow a safepoint during the
-execution of the function called from this site.  If so, we need to
-let the collector update local values in the current frame.
+.. code-block:: llvm
+
+  define i8 addrspace(1)* @test1(i8 addrspace(1)* %obj) 
+         gc "statepoint-example" {
+    call void ()* @foo()
+    ret i8 addrspace(1)* %obj
+  }
+
+Depending on our language we may need to allow a safepoint during the execution 
+of ``foo``. If so, we need to let the collector update local values in the 
+current frame.  If we don't, we'll be accessing a potential invalid reference 
+once we eventually return from the call.
+
+In this example, we need to relocate the SSA value ``%obj``.  Since we can't 
+actually change the value in the SSA value ``%obj``, we need to introduce a new 
+SSA value ``%obj.relocated`` which represents the potentially changed value of
+``%obj`` after the safepoint and update any following uses appropriately.  The 
+resulting relocation sequence is:
 
-Let's say we need to relocate SSA values 'a', 'b', and 'c' at this
-safepoint.  To represent this, we would generate the statepoint
-sequence:
+.. code-block:: llvm
 
-  todo
+  define i8 addrspace(1)* @test1(i8 addrspace(1)* %obj) 
+         gc "statepoint-example" {
+    %0 = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0, i8 addrspace(1)* %obj)
+    %obj.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %0, i32 9, i32 9)
+    ret i8 addrspace(1)* %obj.relocated
+  }
 
 Ideally, this sequence would have been represented as a M argument, N
 return value function (where M is the number of values being
@@ -140,21 +156,60 @@ representation.
 Instead, the statepoint intrinsic marks the actual site of the
 safepoint or statepoint.  The statepoint returns a token value (which
 exists only at compile time).  To get back the original return value
-of the call, we use the 'gc.result' intrinsic.  To get the relocation
-of each pointer in turn, we use the 'gc.relocate' intrinsic with the
-appropriate index.  Note that both the gc.relocate and gc.result are
-tied to the statepoint.  The combination forms a "statepoint sequence"
-and represents the entitety of a parseable call or 'statepoint'.
-
-When lowered, this example would generate the following x86 assembly::
-  put assembly here
+of the call, we use the ``gc.result`` intrinsic.  To get the relocation
+of each pointer in turn, we use the ``gc.relocate`` intrinsic with the
+appropriate index.  Note that both the ``gc.relocate`` and ``gc.result`` are
+tied to the statepoint.  The combination forms a "statepoint relocation 
+sequence" and represents the entitety of a parseable call or 'statepoint'.
+
+When lowered, this example would generate the following x86 assembly:
+
+.. code-block:: gas
+  
+	  .globl	test1
+	  .align	16, 0x90
+	  pushq	%rax
+	  callq	foo
+  .Ltmp1:
+	  movq	(%rsp), %rax  # This load is redundant (oops!)
+	  popq	%rdx
+	  retq
 
 Each of the potentially relocated values has been spilled to the
 stack, and a record of that location has been recorded to the
-:ref: `Stack Map section <stackmap-section>`.  If the garbage collector
+:ref:`Stack Map section <stackmap-section>`.  If the garbage collector
 needs to update any of these pointers during the call, it knows
 exactly what to change.
 
+The relevant parts of the StackMap section for our example are:
+
+.. code-block:: gas
+  
+  # This describes the call site
+  # Stack Maps: callsite 2882400000
+	  .quad	2882400000
+	  .long	.Ltmp1-test1
+	  .short	0
+  # .. 8 entries skipped ..
+  # This entry describes the spill slot which is directly addressable
+  # off RSP with offset 0.  Given the value was spilled with a pushq, 
+  # that makes sense.
+  # Stack Maps:   Loc 8: Direct RSP     [encoding: .byte 2, .byte 8, .short 7, .int 0]
+	  .byte	2
+	  .byte	8
+	  .short	7
+	  .long	0
+
+This example was taken from the tests for the :ref:`RewriteStatepointsForGC` utility pass.  As such, it's full StackMap can be easily examined with the following command.
+
+.. code-block:: bash
+
+  opt -rewrite-statepoints-for-gc test/Transforms/RewriteStatepointsForGC/basics.ll -S | llc -debug-only=stackmaps
+
+
+
+
+
 Intrinsics
 ===========
 
@@ -459,6 +514,35 @@ and inserting safepoint polls sufficient
 safepoint request on a timely manner.  This pass is expected to be run before 
 RewriteStatepointsForGC and thus does not produce full relocation sequences.  
 
+As an example, given input IR of the following:
+
+.. code-block:: llvm
+
+  define void @test() gc "statepoint-example" {
+    call void @foo()
+    ret void
+  }
+
+  declare void @do_safepoint()
+  define void @gc.safepoint_poll() {
+    call void @do_safepoint()
+    ret void
+  }
+
+
+This pass would produce the following IR:
+
+.. code-block:: llvm
+
+  define void @test() gc "statepoint-example" {
+    %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 0)
+    %safepoint_token1 = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0)
+    ret void
+  }
+
+In this case, we've added an (unconditional) entry safepoint poll and converted the call into a ``gc.statepoint``.  Note that despite appearances, the entry poll is not necessarily redundant.  We'd have to know that ``foo`` and ``test`` were not mutually recursive for the poll to be redundant.  In practice, you'd probably want to your poll definition to contain a conditional branch of some form.
+
+
 At the moment, PlaceSafepoints can insert safepoint polls at method entry and 
 loop backedges locations.  Extending this to work with return polls would be 
 straight forward if desired.





More information about the llvm-commits mailing list