[pypy-commit] pypy libgccjit-backend: Implement an OO-style rffi wrapper to libgccjit

dmalcolm noreply at buildbot.pypy.org
Wed Dec 17 17:48:32 CET 2014


Author: David Malcolm <dmalcolm at redhat.com>
Branch: libgccjit-backend
Changeset: r74978:947cc4471f74
Date: 2014-12-16 06:46 -0500
http://bitbucket.org/pypy/pypy/changeset/947cc4471f74/

Log:	Implement an OO-style rffi wrapper to libgccjit

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
@@ -46,6 +46,15 @@
     return array
     # FIXME: don't leak!
 
+def make_field_array(lib, l):
+    array = lltype.malloc(lib.FIELD_P_P.TO,
+                          len(l),
+                          flavor='raw') # of maybe gc?
+    for i in range(len(l)):
+        array[i] = l[i]
+    return array
+    # FIXME: don't leak!
+
 class Library:
     def __init__(self, eci):
         self.eci = eci
@@ -57,6 +66,10 @@
                                                    compilation_info=eci))
         self.GCC_JIT_TYPE_P = lltype.Ptr(COpaque(name='gcc_jit_type',
                                                  compilation_info=eci))
+        self.GCC_JIT_FIELD_P = lltype.Ptr(COpaque(name='gcc_jit_field',
+                                                  compilation_info=eci))
+        self.GCC_JIT_STRUCT_P = lltype.Ptr(COpaque(name='gcc_jit_struct',
+                                                   compilation_info=eci))
         self.GCC_JIT_LOCATION_P = lltype.Ptr(COpaque(name='gcc_jit_location',
                                                      compilation_info=eci))
         self.GCC_JIT_PARAM_P = lltype.Ptr(COpaque(name='gcc_jit_param',
@@ -70,6 +83,8 @@
         self.GCC_JIT_BLOCK_P = lltype.Ptr(COpaque(name='gcc_jit_block',
                                                      compilation_info=eci))
 
+        self.FIELD_P_P = lltype.Ptr(lltype.Array(self.GCC_JIT_FIELD_P,
+                                                 hints={'nolength': True}))
         self.PARAM_P_P = lltype.Ptr(lltype.Array(self.GCC_JIT_PARAM_P,
                                                  hints={'nolength': True}))
 
@@ -94,6 +109,11 @@
                  'gcc_jit_context_compile', [self.GCC_JIT_CONTEXT_P]),
 
 
+                (lltype.Void,
+                 'gcc_jit_context_dump_to_file', [self.GCC_JIT_CONTEXT_P,
+                                                  CCHARP,
+                                                  INT]),
+
                 (VOIDP,
                  'gcc_jit_result_get_code', [self.GCC_JIT_RESULT_P,
                                              CCHARP]),
@@ -108,6 +128,34 @@
                  'gcc_jit_context_get_type', [self.GCC_JIT_CONTEXT_P,
                                               INT]),
 
+                (self.GCC_JIT_TYPE_P,
+                 'gcc_jit_type_get_pointer', [self.GCC_JIT_TYPE_P]),
+
+                (self.GCC_JIT_FIELD_P,
+                 'gcc_jit_context_new_field', [self.GCC_JIT_CONTEXT_P,
+                                               self.GCC_JIT_LOCATION_P,
+                                               self.GCC_JIT_TYPE_P,
+                                               CCHARP]),
+                (self.GCC_JIT_STRUCT_P,
+                 'gcc_jit_context_new_struct_type', [self.GCC_JIT_CONTEXT_P,
+                                                     self.GCC_JIT_LOCATION_P,
+                                                     CCHARP,
+                                                     INT,
+                                                     self.FIELD_P_P]),
+
+                (self.GCC_JIT_STRUCT_P,
+                 'gcc_jit_context_new_opaque_struct', [self.GCC_JIT_CONTEXT_P,
+                                                       self.GCC_JIT_LOCATION_P,
+                                                       CCHARP]),
+                (self.GCC_JIT_TYPE_P,
+                 'gcc_jit_struct_as_type', [self.GCC_JIT_STRUCT_P]),
+
+                (lltype.Void,
+                 'gcc_jit_struct_set_fields', [self.GCC_JIT_STRUCT_P,
+                                               self.GCC_JIT_LOCATION_P,
+                                               INT,
+                                               self.FIELD_P_P]),
+
                 ############################################################
                 # Constructing functions.
                 ############################################################
@@ -159,6 +207,11 @@
                                          self.GCC_JIT_TYPE_P]),
 
                 (self.GCC_JIT_RVALUE_P,
+                 'gcc_jit_context_new_rvalue_from_ptr', [self.GCC_JIT_CONTEXT_P,
+                                                         self.GCC_JIT_TYPE_P,
+                                                         VOIDP]),
+
+                (self.GCC_JIT_RVALUE_P,
                  'gcc_jit_context_new_binary_op', [self.GCC_JIT_CONTEXT_P,
                                                    self.GCC_JIT_LOCATION_P,
                                                    INT, # enum gcc_jit_binary_op op,
@@ -166,6 +219,11 @@
                                                    self.GCC_JIT_RVALUE_P,
                                                    self.GCC_JIT_RVALUE_P]),
 
+                (self.GCC_JIT_LVALUE_P,
+                 'gcc_jit_rvalue_dereference_field', [self.GCC_JIT_RVALUE_P,
+                                                      self.GCC_JIT_LOCATION_P,
+                                                      self.GCC_JIT_FIELD_P]),
+
                 ############################################################
                 # Statement-creation.
                 ############################################################
@@ -259,5 +317,181 @@
             name = name.strip()
             if name:
                 setattr(self, name, r_int(value))
-        
 
+# An object-oriented interfact to the library
+
+class Wrapper:
+    def __init__(self, lib):
+        self.lib = lib
+
+class Context(Wrapper):
+    def __init__(self, lib, inner_ctxt):
+        Wrapper.__init__(self, lib)
+        self.inner_ctxt = inner_ctxt
+
+    @staticmethod
+    def acquire(lib):
+        return Context(lib, lib.gcc_jit_context_acquire())
+
+    def release(self):
+        self.lib.gcc_jit_context_release(self.inner_ctxt)
+
+    def set_bool_option(self, key, val):
+        self.lib.gcc_jit_context_set_bool_option(self.inner_ctxt,
+                                                 key, val)
+
+    def set_int_option(self, key, val):
+        self.lib.gcc_jit_context_set_int_option(self.inner_ctxt,
+                                                key, val)
+
+    def compile(self):
+        inner_result = self.lib.gcc_jit_context_compile(self.inner_ctxt)
+        if not inner_result:
+            # FIXME: get error from context
+            raise Exception("result is NULL")
+        return Result(self.lib, inner_result)
+
+    def get_type(self, r_enum):
+        return Type(self.lib,
+                    self.lib.gcc_jit_context_get_type(self.inner_ctxt,
+                                                      r_enum))
+
+    def new_field(self, type_, name):
+        name_charp = str2charp(name)
+        field = self.lib.gcc_jit_context_new_field(self.inner_ctxt,
+                                                   self.lib.null_location_ptr,
+                                                   type_.inner_type,
+                                                   name_charp)
+        free_charp(name_charp)
+        return Field(self.lib, field)
+    
+    def new_rvalue_from_int(self, type_, llvalue):
+        return RValue(self.lib,
+                      self.lib.gcc_jit_context_new_rvalue_from_int(self.inner_ctxt,
+                                                                   type_.inner_type,
+                                                                   llvalue))
+
+    def new_binary_op(self, op, type_, a, b):
+        return RValue(self.lib,
+                      self.lib.gcc_jit_context_new_binary_op(self.inner_ctxt,
+                                                             self.lib.null_location_ptr,
+                                                             op,
+                                                             type_.inner_type,
+                                                             a.inner_rvalue, b.inner_rvalue))
+
+    def new_param(self, type_, name):
+        name_charp = str2charp(name)
+        param = self.lib.gcc_jit_context_new_param(self.inner_ctxt,
+                                                   self.lib.null_location_ptr,
+                                                   type_.inner_type,
+                                                   name_charp)
+        free_charp(name_charp)
+        return Param(self.lib, param)
+
+    def new_function(self, kind, returntype, name, params, is_variadic):
+        name_charp = str2charp(name)
+        raw_param_array = lltype.malloc(self.lib.PARAM_P_P.TO,
+                                    len(params),
+                                    flavor='raw') # of maybe gc?
+        for i in range(len(params)):
+            raw_param_array[i] = params[i].inner_param
+
+        fn = self.lib.gcc_jit_context_new_function(self.inner_ctxt,
+                                                   self.lib.null_location_ptr,
+                                                   kind,
+                                                   returntype.inner_type,
+                                                   name_charp,
+                                                   r_int(len(params)),
+                                                   raw_param_array,
+                                                   is_variadic)
+        lltype.free(raw_param_array, flavor='raw')
+        free_charp(name_charp)
+
+        return Function(self.lib, fn)
+
+
+class Type(Wrapper):
+    def __init__(self, lib, inner_type):
+        Wrapper.__init__(self, lib)
+        self.inner_type = inner_type
+
+
+class Field(Wrapper):
+    def __init__(self, lib, inner_field):
+        Wrapper.__init__(self, lib)
+        self.inner_field = inner_field
+
+class RValue(Wrapper):
+    def __init__(self, lib, inner_rvalue):
+        Wrapper.__init__(self, lib)
+        self.inner_rvalue = inner_rvalue
+
+class LValue(Wrapper):
+    def __init__(self, lib, inner_lvalue):
+        Wrapper.__init__(self, lib)
+        self.inner_lvalue = inner_lvalue
+
+    def as_rvalue(self):
+        return RValue(self.lib,
+                      self.lib.gcc_jit_lvalue_as_rvalue(self.inner_lvalue))
+
+class Param(Wrapper):
+    def __init__(self, lib, inner_param):
+        Wrapper.__init__(self, lib)
+        self.inner_param = inner_param
+
+    def as_rvalue(self):
+        return RValue(self.lib,
+                      self.lib.gcc_jit_param_as_rvalue(self.inner_param))
+
+class Function(Wrapper):
+    def __init__(self, lib, inner_function):
+        Wrapper.__init__(self, lib)
+        self.inner_function = inner_function
+
+    def new_local(self, type_, name):
+        name_charp = str2charp(name)
+        local = self.lib.gcc_jit_function_new_local(self.inner_function,
+                                                    self.lib.null_location_ptr,
+                                                    type_.inner_type,
+                                                    name_charp)
+        free_charp(name_charp)
+        return LValue(self.lib, local)
+
+    def new_block(self, name):
+        name_charp = str2charp(name)
+        block = self.lib.gcc_jit_function_new_block(self.inner_function,
+                                                    name_charp)
+        free_charp(name_charp)
+        return Block(self.lib, block)
+
+class Block(Wrapper):
+    def __init__(self, lib, inner_block):
+        Wrapper.__init__(self, lib)
+        self.inner_block = inner_block
+
+    def add_assignment(self, lvalue, rvalue):
+        self.lib.gcc_jit_block_add_assignment(self.inner_block,
+                                              self.lib.null_location_ptr,
+                                              lvalue.inner_lvalue,
+                                              rvalue.inner_rvalue)
+
+    def end_with_return(self, rvalue):
+        self.lib.gcc_jit_block_end_with_return(self.inner_block,
+                                               self.lib.null_location_ptr,
+                                               rvalue.inner_rvalue)
+
+class Result(Wrapper):
+    def __init__(self, lib, inner_result):
+        Wrapper.__init__(self, lib)
+        self.inner_result = inner_result
+
+    def get_code(self, name):
+        name_charp = str2charp(name)
+        fn_ptr = self.lib.gcc_jit_result_get_code(self.inner_result,
+                                                  name_charp)
+        free_charp(name_charp)
+        return fn_ptr
+
+    def release(self):
+        self.lib.gcc_jit_result_release(self.inner_result)
diff --git a/rpython/jit/backend/libgccjit/test/test_rffi_bindings.py b/rpython/jit/backend/libgccjit/test/test_rffi_bindings.py
--- a/rpython/jit/backend/libgccjit/test/test_rffi_bindings.py
+++ b/rpython/jit/backend/libgccjit/test/test_rffi_bindings.py
@@ -34,7 +34,7 @@
     assert xf() == 3
 """
 
-from rpython.jit.backend.libgccjit.rffi_bindings import make_eci, Library, make_param_array
+from rpython.jit.backend.libgccjit.rffi_bindings import make_eci, Library, make_param_array, Context
 
 def test_compile_empty_context():
     eci = make_eci()
@@ -84,6 +84,7 @@
                                               t_int,
                                               param_name)
         free_charp(param_name)
+
         # FIXME: how to build an array of params at this level?
         # see liststr2charpp in rffi.py
         
@@ -156,6 +157,75 @@
     f1 = compile_c(f, [], backendopt=False)
     assert f1() == 42
     assert False # to see stderr
+
+def test_oo_compile_add_one_to():
+    eci = make_eci()
+
+    lib = Library(eci)
+
+    ft = lltype.FuncType([INT], INT)#, abi="C")
+    ftp = lltype.Ptr(ft)
+
+    def f():
+        ctxt = Context.acquire(lib)
+        # FIXME: etc:
+        ctxt.set_bool_option(lib.GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+                             r_int(1))
+        ctxt.set_int_option(lib.GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+                            r_int(3))
+        ctxt.set_bool_option(lib.GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+                             r_int(1))
+        ctxt.set_bool_option(lib.GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+                             r_int(1))
+        ctxt.set_bool_option(lib.GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+                             r_int(1))
+        t_int = ctxt.get_type(lib.GCC_JIT_TYPE_INT)
+        param = ctxt.new_param(t_int, "input")
+        fn = ctxt.new_function(lib.GCC_JIT_FUNCTION_EXPORTED,
+                               t_int,
+                               "add_one_to",
+                               [param],
+                               r_int(0))
+        v_res = fn.new_local(t_int, "v_res")
+        b_initial = fn.new_block("initial")
+        c_one = ctxt.new_rvalue_from_int(t_int, r_int(1))
+        op_add = ctxt.new_binary_op(lib.GCC_JIT_BINARY_OP_PLUS,
+                                    t_int,
+                                    param.as_rvalue(),
+                                    c_one)
+        b_initial.add_assignment(v_res, op_add)
+        b_initial.end_with_return(v_res.as_rvalue())
+
+        jit_result = ctxt.compile()
+        ctxt.release()
+        fn_ptr = jit_result.get_code("add_one_to")
+        if not fn_ptr:
+            raise Exception("fn_ptr is NULL")
+        print('fn_ptr: %s' % fn_ptr)
+
+        #ft = lltype.FuncType([INT], INT)#, abi="C")
+        # looks like we can't build a FuncType inside RPython
+        # but we can use one built outside:
+        print(ft)
+        print(ftp)
+
+        typed_fn_ptr = cast(ftp, fn_ptr)
+        print(typed_fn_ptr)
+        fn_result = typed_fn_ptr (r_int(41))
+        #print('fn_result: %d' % fn_result)
+        #assert fn_result == r_int(42)
+
+        # and it looks like we can't create a functionptr from this
+        # FuncType:
+        #funcptr = lltype.functionptr(ft)
+
+        jit_result.release()
+
+        return int(fn_result)
+        
+    f1 = compile_c(f, [], backendopt=False)
+    assert f1() == 42
+    assert False # to see stderr
     
 # TODO: test of an error
 # should turn it into an exception, and capture the error


More information about the pypy-commit mailing list