[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