[pypy-commit] pypy libgccjit-backend: Split out guard failure into a tail call to another function

dmalcolm noreply at buildbot.pypy.org
Thu Dec 18 19:01:28 CET 2014


Author: David Malcolm <dmalcolm at redhat.com>
Branch: libgccjit-backend
Changeset: r75018:eb3ba1b9910e
Date: 2014-12-17 15:43 -0500
http://bitbucket.org/pypy/pypy/changeset/eb3ba1b9910e/

Log:	Split out guard failure into a tail call to another function

	Eventually this could be a jump through a function pointer.

	Right now it's simply a call to a internal function. The call gets
	inlined away, back into the code we had before.

diff --git a/rpython/jit/backend/libgccjit/assembler.py b/rpython/jit/backend/libgccjit/assembler.py
--- a/rpython/jit/backend/libgccjit/assembler.py
+++ b/rpython/jit/backend/libgccjit/assembler.py
@@ -10,6 +10,17 @@
 from rpython.rtyper.lltypesystem.rffi import *
 from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory
 
+class Params:
+    def __init__(self, assembler):
+        self.paramlist = []
+        self.param_frame = assembler.ctxt.new_param(assembler.t_jit_frame_ptr,
+                                                    "jitframe")
+        self.paramlist.append(self.param_frame)
+
+        self.param_addr = assembler.ctxt.new_param(assembler.t_void_ptr,
+                                                   "addr")
+        self.paramlist.append(self.param_addr)
+
 class AssemblerLibgccjit(BaseAssembler):
     _regalloc = None
     #_output_loop_log = None
@@ -34,6 +45,7 @@
         #self.teardown()
 
         self.num_anon_loops = 0
+        self.num_guard_failure_fns = 0
 
         self.sizeof_signed = rffi.sizeof(lltype.Signed)
 
@@ -98,6 +110,7 @@
         self.t_float = self.ctxt.get_type(self.lib.GCC_JIT_TYPE_DOUBLE) # FIXME                                          
         self.t_bool = self.ctxt.get_type(self.lib.GCC_JIT_TYPE_BOOL)
         self.t_void_ptr = self.ctxt.get_type(self.lib.GCC_JIT_TYPE_VOID_PTR)
+        self.t_void = self.ctxt.get_type(self.lib.GCC_JIT_TYPE_VOID)
 
         self.u_signed = self.ctxt.new_field(self.t_Signed, "u_signed")
         self.u_float = self.ctxt.new_field(self.t_float, "u_float")
@@ -134,7 +147,7 @@
 
         struct_jit_frame = self.ctxt.new_opaque_struct ("JITFRAME")
 
-        t_jit_frame_ptr = struct_jit_frame.as_type().get_pointer()
+        self.t_jit_frame_ptr = struct_jit_frame.as_type().get_pointer()
 
         fields = []
         # FIXME: Does the GCStruct implicitly add any fields?
@@ -149,7 +162,7 @@
         make_field('jf_extra_stack_depth', self.t_Signed)
         make_field('jf_savedata', self.t_void_ptr)
         make_field('jf_guard_exc', self.t_void_ptr)
-        make_field('jf_forward', t_jit_frame_ptr)
+        make_field('jf_forward', self.t_jit_frame_ptr)
         # FIXME: for some reason there's an implicit word here;
         # create it
         make_field('jf_frame', self.t_Signed)
@@ -176,22 +189,16 @@
         # Make function:
         #print('  inputargs: %r' % (inputargs, ))
         #jitframe.JITFRAMEINFOPTR
-        params = []
-
-        self.param_frame = self.ctxt.new_param(t_jit_frame_ptr, "jitframe")
-        params.append(self.param_frame)
-
-        self.param_addr = self.ctxt.new_param(self.t_void_ptr, "addr")
-        params.append(self.param_addr)
+        self.loop_params = Params(self)
 
         if not loopname:
             loopname = 'anonloop_%i' % self.num_anon_loops
             self.num_anon_loops += 1
         print("  loopname: %r" % loopname)
         self.fn = self.ctxt.new_function(self.lib.GCC_JIT_FUNCTION_EXPORTED,
-                                         t_jit_frame_ptr,
+                                         self.t_jit_frame_ptr,
                                          loopname,
-                                         params,
+                                         self.loop_params.paramlist,
                                          r_int(0))
 
         self.b_current = self.fn.new_block("initial")
@@ -300,7 +307,7 @@
         return self.lvalue_for_box[box]
 
     def get_arg_as_lvalue(self, idx):
-        return self.param_frame.as_rvalue ().dereference_field (
+        return self.loop_params.param_frame.as_rvalue ().dereference_field (
             self.field_for_arg_idx[idx])
 
     def expr_to_lvalue(self, expr):
@@ -371,9 +378,9 @@
         self.b_current.end_with_jump(self.block_for_label_descr[jumpop.getdescr()])
 
     def emit_finish(self, resop):
-        self._impl_write_output_args(resop._args)
-        self._impl_write_jf_descr(resop)
-        self.b_current.end_with_return(self.param_frame.as_rvalue ())
+        self._impl_write_output_args(self.loop_params, resop._args)
+        self._impl_write_jf_descr(self.loop_params, resop)
+        self.b_current.end_with_return(self.loop_params.param_frame.as_rvalue ())
 
     def emit_label(self, resop):
         print(resop)
@@ -408,15 +415,34 @@
 
         # Write out guard failure impl:
         self.b_current = b_guard_failure
-        self._impl_write_output_args(resop._fail_args)
-        self._impl_write_jf_descr(resop)
-        self.b_current.end_with_return(self.param_frame.as_rvalue ())
+
+        # Implement it as a tail-call to a handler function
+        # This will eventually become a function ptr, allowing
+        # patchability
+        failure_params = Params(self)
+        failure_fn = (
+            self.ctxt.new_function(self.lib.GCC_JIT_FUNCTION_INTERNAL,
+                                   self.t_jit_frame_ptr,
+                                   "on_guard_failure_%i" % self.num_guard_failure_fns,
+                                   failure_params.paramlist,
+                                   r_int(0)))
+        self.num_guard_failure_fns += 1
+        call = self.ctxt.new_call (failure_fn,
+                                   [param.as_rvalue()
+                                    for param in self.loop_params.paramlist])
+        self._impl_write_output_args(self.loop_params, resop._fail_args)
+        self.b_current.end_with_return(call)
+
+        b_within_failure_fn = failure_fn.new_block("initial")
+        self.b_current = b_within_failure_fn
+        self._impl_write_jf_descr(failure_params, resop)
+        self.b_current.end_with_return(failure_params.param_frame.as_rvalue ())
         rd_locs = []
         for idx, arg in enumerate(resop._fail_args):
             rd_locs.append(idx * self.sizeof_signed)
         resop.getdescr().rd_locs = rd_locs
 
-        # Further operations go into the guard success block:
+        # Further operations go into the guard success block in the original fn:
         self.b_current = b_guard_success
 
     def emit_guard_true(self, resop):
@@ -425,7 +451,7 @@
     def emit_guard_false(self, resop):
         self._impl_guard(resop, r_int(0))
 
-    def _impl_write_output_args(self, args):
+    def _impl_write_output_args(self, params, args):
         # Write outputs back:
         for idx, arg in enumerate(args):
             if arg is not None:
@@ -443,14 +469,14 @@
                                                    r_int(0)))
                 """
 
-    def _impl_write_jf_descr(self, resop):
+    def _impl_write_jf_descr(self, params, resop):
         # Write back to the jf_descr:
         #  "jitframe->jf_descr = resop.getdescr();"
         descr = rffi.cast(lltype.Signed,
                           cast_instance_to_gcref(resop.getdescr()))
 
         self.b_current.add_assignment(
-            self.param_frame.as_rvalue ().dereference_field (
+            params.param_frame.as_rvalue ().dereference_field (
                 self.field_jf_descr),
             self.ctxt.new_rvalue_from_ptr (self.t_void_ptr,
                                            rffi.cast(VOIDP, descr)))
@@ -603,4 +629,3 @@
         self.impl_float_cmp(resop, self.lib.GCC_JIT_COMPARISON_GT)
     def emit_float_ge(self, resop):
         self.impl_float_cmp(resop, self.lib.GCC_JIT_COMPARISON_GE)
-
diff --git a/rpython/jit/backend/libgccjit/rffi_bindings.py b/rpython/jit/backend/libgccjit/rffi_bindings.py
--- a/rpython/jit/backend/libgccjit/rffi_bindings.py
+++ b/rpython/jit/backend/libgccjit/rffi_bindings.py
@@ -87,6 +87,8 @@
                                                  hints={'nolength': True}))
         self.PARAM_P_P = lltype.Ptr(lltype.Array(self.GCC_JIT_PARAM_P,
                                                  hints={'nolength': True}))
+        self.RVALUE_P_P = lltype.Ptr(lltype.Array(self.GCC_JIT_RVALUE_P,
+                                                  hints={'nolength': True}))
 
         # Entrypoints:
         for returntype, name, paramtypes in [
@@ -253,6 +255,13 @@
                                                     self.GCC_JIT_RVALUE_P]),
 
                 (self.GCC_JIT_RVALUE_P,
+                 'gcc_jit_context_new_call', [self.GCC_JIT_CONTEXT_P,
+                                              self.GCC_JIT_LOCATION_P,
+                                              self.GCC_JIT_FUNCTION_P,
+                                              INT,
+                                              self.RVALUE_P_P]),
+
+                (self.GCC_JIT_RVALUE_P,
                  'gcc_jit_context_new_cast', [self.GCC_JIT_CONTEXT_P,
                                               self.GCC_JIT_LOCATION_P,
                                               self.GCC_JIT_RVALUE_P,
@@ -540,6 +549,20 @@
                                                               op,
                                                               a.inner_rvalue, b.inner_rvalue))
 
+    def new_call(self, fn, args):
+        raw_arg_array = lltype.malloc(self.lib.RVALUE_P_P.TO,
+                                      len(args),
+                                      flavor='raw') # of maybe gc?
+        for i in range(len(args)):
+            raw_arg_array[i] = args[i].inner_rvalue
+        rvalue = self.lib.gcc_jit_context_new_call(self.inner_ctxt,
+                                                   self.lib.null_location_ptr,
+                                                   fn.inner_function,
+                                                   r_int(len(args)),
+                                                   raw_arg_array)
+        lltype.free(raw_arg_array, flavor='raw')
+        return RValue(self.lib, rvalue)
+
     def new_param(self, type_, name):
         name_charp = str2charp(name)
         param = self.lib.gcc_jit_context_new_param(self.inner_ctxt,


More information about the pypy-commit mailing list