[pypy-svn] r65613 - in pypy/branch/pyjitpl5-experiments/pypy/jit/backend/llvm: . test
arigo at codespeak.net
arigo at codespeak.net
Sat Jun 6 12:51:10 CEST 2009
Author: arigo
Date: Sat Jun 6 12:51:08 2009
New Revision: 65613
Modified:
pypy/branch/pyjitpl5-experiments/pypy/jit/backend/llvm/runner.py
pypy/branch/pyjitpl5-experiments/pypy/jit/backend/llvm/test/test_runner.py
Log:
Rewrite the LLVM logic so that execute_operations() is no longer a simple
call to a stub function, but instead it is a loop of calls to the real
functions. This avoids recursive tail calls, at least.
Modified: pypy/branch/pyjitpl5-experiments/pypy/jit/backend/llvm/runner.py
==============================================================================
--- pypy/branch/pyjitpl5-experiments/pypy/jit/backend/llvm/runner.py (original)
+++ pypy/branch/pyjitpl5-experiments/pypy/jit/backend/llvm/runner.py Sat Jun 6 12:51:08 2009
@@ -6,22 +6,23 @@
from pypy.jit.backend import model
from pypy.jit.backend.llvm import llvm_rffi
from pypy.jit.metainterp import resoperation
+from pypy.jit.metainterp.history import TreeLoop
from pypy.jit.metainterp.resoperation import rop
+TreeLoop._llvm_compiled_index = -1
+
class LLVMCPU(model.AbstractCPU):
RAW_VALUE = rffi.CFixedArray(rffi.ULONGLONG, 1)
SIGNED_VALUE = rffi.CFixedArray(lltype.Signed, 1)
- STUB_FUNC = lltype.FuncType([rffi.VOIDP], lltype.Signed)
def __init__(self, rtyper, stats=None, translate_support_code=False,
annmixlevel=None):
self.rtyper = rtyper
self.translate_support_code = translate_support_code
- self.ty_funcs = {}
+ self.compiled_functions = []
self.fail_ops = []
self.in_out_args = []
- self.entry_stubs = {}
def setup_once(self):
if not we_are_translated():
@@ -34,19 +35,18 @@
self.ty_int = llvm_rffi.LLVMInt64Type()
self.ty_bit = llvm_rffi.LLVMInt1Type()
self.ty_char = llvm_rffi.LLVMInt8Type()
- self.ty_charp = llvm_rffi.LLVMPointerType(self.ty_char, 0)
+ self.ty_int_ptr = llvm_rffi.LLVMPointerType(self.ty_int, 0)
#
- arglist = lltype.malloc(rffi.CArray(llvm_rffi.LLVMTypeRef), 1,
+ arglist = lltype.malloc(rffi.CArray(llvm_rffi.LLVMTypeRef), 0,
flavor='raw')
- arglist[0] = self.ty_charp
- self.ty_stub_func = llvm_rffi.LLVMFunctionType(self.ty_int, arglist,
- 1, False)
+ self.ty_func = llvm_rffi.LLVMFunctionType(self.ty_int, arglist, 0,
+ False)
lltype.free(arglist, flavor='raw')
#
self.ee = llvm_rffi.LLVM_EE_Create(self.module)
if not we_are_translated():
set_teardown_function(self._teardown)
-
+
def _teardown(self):
llvm_rffi.LLVMDisposeExecutionEngine(self.ee)
@@ -54,89 +54,124 @@
# Compilation
def compile_operations(self, loop):
- self.compiling_loop = loop
- self._ensure_in_args(len(loop.inputargs))
- ty_func = self.get_ty_func(len(loop.inputargs))
- func = llvm_rffi.LLVMAddFunction(self.module, "", ty_func)
- llvm_rffi.LLVMSetFunctionCallConv(func, llvm_rffi.CallConv.Fast)
- loop._llvm_func = func
+ compiler = LLVMJITCompiler(self, loop)
+ compiler.start_generating_function()
+ compiler.generate_initial_arguments_load()
+ compiler.generate_loop_body()
+ compiler.close_phi_nodes()
+ compiler.done_generating_function()
+ llvm_rffi.LLVMDumpModule(self.module) # xxx for debugging
+
+ def _ensure_in_args(self, count):
+ while len(self.in_out_args) < count:
+ self.in_out_args.append(lltype.malloc(self.RAW_VALUE, flavor='raw'))
+
+ _ensure_out_args = _ensure_in_args
+
+ # ------------------------------
+ # Execution
+
+ def set_future_value_int(self, index, intvalue):
+ p = rffi.cast(lltype.Ptr(self.SIGNED_VALUE), self.in_out_args[index])
+ p[0] = intvalue
+
+ def execute_operations(self, loop):
+ index = loop._llvm_compiled_index
+ assert index >= 0
+ while True:
+ func_ptr = self.compiled_functions[index]
+ print 'execute_operations: %d (at 0x%x)' % (
+ index, rffi.cast(lltype.Signed, func_ptr))
+ index = func_ptr()
+ print '\t--->', index
+ if index < 0:
+ break
+ return self.fail_ops[~index]
+
+ def get_latest_value_int(self, index):
+ p = rffi.cast(lltype.Ptr(self.SIGNED_VALUE), self.in_out_args[index])
+ return p[0]
+
+# ____________________________________________________________
+
+class LLVMJITCompiler(object):
+ FUNC = lltype.FuncType([], lltype.Signed)
+
+ def __init__(self, cpu, loop):
+ self.cpu = cpu
+ self.loop = loop
+
+ def start_generating_function(self):
+ if self.loop._llvm_compiled_index < 0:
+ self.loop._llvm_compiled_index = len(self.cpu.compiled_functions)
+ self.cpu.compiled_functions.append(lltype.nullptr(self.FUNC))
+ func = llvm_rffi.LLVMAddFunction(self.cpu.module, "", self.cpu.ty_func)
+ self.compiling_func = func
+ self.builder = llvm_rffi.LLVMCreateBuilder()
self.vars = {}
+
+ def generate_initial_arguments_load(self):
+ loop = self.loop
+ func = self.compiling_func
+ bb_entry = llvm_rffi.LLVMAppendBasicBlock(func, "entry")
+ llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, bb_entry)
+ self.cpu._ensure_in_args(len(loop.inputargs))
+ self.phi_incoming_blocks = [bb_entry]
+ self.phi_incoming_values = []
for i in range(len(loop.inputargs)):
- self.vars[loop.inputargs[i]] = llvm_rffi.LLVMGetParam(func, i)
- self.builder = llvm_rffi.LLVMCreateBuilder()
- bb_start = llvm_rffi.LLVMAppendBasicBlock(func, "entry")
- self.pending_blocks = [(loop.operations, bb_start)]
+ addr_as_signed = rffi.cast(lltype.Signed, self.cpu.in_out_args[i])
+ llvmconstint = self._make_const_int(addr_as_signed)
+ llvmconstptr = llvm_rffi.LLVMConstIntToPtr(llvmconstint,
+ self.cpu.ty_int_ptr)
+ res = llvm_rffi.LLVMBuildLoad(self.builder, llvmconstptr, "")
+ self.phi_incoming_values.append([res])
+ self.bb_start = llvm_rffi.LLVMAppendBasicBlock(func, "")
+ llvm_rffi.LLVMBuildBr(self.builder, self.bb_start)
+ #
+ llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, self.bb_start)
+ for i in range(len(loop.inputargs)):
+ phi = llvm_rffi.LLVMBuildPhi(self.builder, self.cpu.ty_int, "")
+ self.vars[loop.inputargs[i]] = phi
+
+ def generate_loop_body(self):
+ func = self.compiling_func
+ self.pending_blocks = [(self.loop.operations, self.bb_start)]
while self.pending_blocks:
operations, bb = self.pending_blocks.pop()
self._generate_branch(operations, bb)
- llvm_rffi.LLVMDisposeBuilder(self.builder)
- self.vars = None
- #
- loop._llvm_func_addr = llvm_rffi.LLVM_EE_getPointerToFunction(
- self.ee, loop._llvm_func)
- if not we_are_translated():
- print '--- function is at %r ---' % (loop._llvm_func_addr,)
- #
- loop._llvm_entry_stub = self._get_entry_stub(loop)
- llvm_rffi.LLVMDumpModule(self.module)
- self.compiling_loop = None
+ self.bb_start = lltype.nullptr(llvm_rffi.LLVMBasicBlockRef.TO)
- def _get_entry_stub(self, loop):
- key = len(loop.inputargs)
- try:
- stub = self.entry_stubs[key]
- except KeyError:
- stub = self.entry_stubs[key] = self._build_entry_stub(key)
- return stub
+ def close_phi_nodes(self):
+ incoming_blocks = lltype.malloc(
+ rffi.CArray(llvm_rffi.LLVMBasicBlockRef),
+ len(self.phi_incoming_blocks), flavor='raw')
+ incoming_values = lltype.malloc(
+ rffi.CArray(llvm_rffi.LLVMValueRef),
+ len(self.phi_incoming_blocks), flavor='raw')
+ for j in range(len(self.phi_incoming_blocks)):
+ incoming_blocks[j] = self.phi_incoming_blocks[j]
+ loop = self.loop
+ for i in range(len(loop.inputargs)):
+ phi = self.vars[loop.inputargs[i]]
+ incoming = self.phi_incoming_values[i]
+ for j in range(len(self.phi_incoming_blocks)):
+ incoming_values[j] = incoming[j]
+ llvm_rffi.LLVMAddIncoming(phi, incoming_values, incoming_blocks,
+ len(self.phi_incoming_blocks))
+ lltype.free(incoming_values, flavor='raw')
+ lltype.free(incoming_blocks, flavor='raw')
- def _build_entry_stub(self, nb_args):
- stubfunc = llvm_rffi.LLVMAddFunction(self.module, "stub",
- self.ty_stub_func)
- basicblock = llvm_rffi.LLVMAppendBasicBlock(stubfunc, "entry")
- builder = llvm_rffi.LLVMCreateBuilder()
- llvm_rffi.LLVMPositionBuilderAtEnd(builder, basicblock)
- args = lltype.malloc(rffi.CArray(llvm_rffi.LLVMValueRef), nb_args,
- flavor='raw')
- for i in range(nb_args):
- ty_int_ptr = llvm_rffi.LLVMPointerType(self.ty_int, 0)
- addr_as_signed = rffi.cast(lltype.Signed, self.in_out_args[i])
- llvmconstint = self._make_const_int(addr_as_signed)
- llvmconstptr = llvm_rffi.LLVMConstIntToPtr(llvmconstint, ty_int_ptr)
- args[i] = llvm_rffi.LLVMBuildLoad(builder, llvmconstptr, "")
- #
- realtype = llvm_rffi.LLVMPointerType(self.get_ty_func(nb_args), 0)
- realfunc = llvm_rffi.LLVMGetParam(stubfunc, 0)
- realfunc = llvm_rffi.LLVMBuildBitCast(builder, realfunc, realtype, "")
- res = llvm_rffi.LLVMBuildCall(builder, realfunc, args, nb_args, "")
- llvm_rffi.LLVMSetInstructionCallConv(res, llvm_rffi.CallConv.Fast)
- lltype.free(args, flavor='raw')
- llvm_rffi.LLVMBuildRet(builder, res)
- llvm_rffi.LLVMDisposeBuilder(builder)
+ def done_generating_function(self):
+ llvm_rffi.LLVMDisposeBuilder(self.builder)
#
- stub = llvm_rffi.LLVM_EE_getPointerToFunction(self.ee, stubfunc)
+ func_addr = llvm_rffi.LLVM_EE_getPointerToFunction(self.cpu.ee,
+ self.compiling_func)
if not we_are_translated():
- print '--- stub is at %r ---' % (stub,)
- return rffi.cast(lltype.Ptr(self.STUB_FUNC), stub)
-
- def get_ty_func(self, nb_args):
- try:
- return self.ty_funcs[nb_args]
- except KeyError:
- arglist = lltype.malloc(rffi.CArray(llvm_rffi.LLVMTypeRef),
- nb_args, flavor='raw')
- for i in range(nb_args):
- arglist[i] = self.ty_int
- ty_func = llvm_rffi.LLVMFunctionType(self.ty_int, arglist,
- nb_args, False)
- lltype.free(arglist, flavor='raw')
- self.ty_funcs[nb_args] = ty_func
- return ty_func
-
- def _ensure_in_args(self, count):
- while len(self.in_out_args) < count:
- self.in_out_args.append(lltype.malloc(self.RAW_VALUE, flavor='raw'))
-
- _ensure_out_args = _ensure_in_args
+ print '--- function is at %r ---' % (func_addr,)
+ #
+ func_ptr = rffi.cast(lltype.Ptr(self.FUNC), func_addr)
+ index = self.loop._llvm_compiled_index
+ self.cpu.compiled_functions[index] = func_ptr
def _generate_branch(self, operations, basicblock):
llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, basicblock)
@@ -163,15 +198,15 @@
return self._cast_to_int(value_ref)
def _make_const_int(self, value):
- return llvm_rffi.LLVMConstInt(self.ty_int, value, True)
+ return llvm_rffi.LLVMConstInt(self.cpu.ty_int, value, True)
def _cast_to_int(self, value_ref):
ty = llvm_rffi.LLVMTypeOf(value_ref)
- if ty == self.ty_int:
+ if ty == self.cpu.ty_int:
return value_ref
- elif ty == self.ty_bit:
+ elif ty == self.cpu.ty_bit:
return llvm_rffi.LLVMBuildZExt(self.builder, value_ref,
- self.ty_int, "")
+ self.cpu.ty_int, "")
else:
raise AssertionError("type is not an int nor a bit")
@@ -190,11 +225,11 @@
def _cast_to_bit(self, value_ref):
ty = llvm_rffi.LLVMTypeOf(value_ref)
- if ty == self.ty_bit:
+ if ty == self.cpu.ty_bit:
return value_ref
- elif ty == self.ty_int:
+ elif ty == self.cpu.ty_int:
return llvm_rffi.LLVMBuildTrunc(self.builder, value_ref,
- self.ty_bit, "")
+ self.cpu.ty_bit, "")
else:
raise AssertionError("type is not an int nor a bit")
@@ -224,7 +259,7 @@
"")
def generate_GUARD_TRUE(self, op):
- func = self.compiling_loop._llvm_func
+ func = self.compiling_func
bb_on_track = llvm_rffi.LLVMAppendBasicBlock(func, "")
bb_off_track = llvm_rffi.LLVMAppendBasicBlock(func, "")
llvm_rffi.LLVMBuildCondBr(self.builder, self.getbitarg(op.args[0]),
@@ -234,49 +269,30 @@
llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, bb_on_track)
def generate_JUMP(self, op):
- args = lltype.malloc(rffi.CArray(llvm_rffi.LLVMValueRef), len(op.args),
- flavor='raw')
- for i in range(len(op.args)):
- args[i] = self.getintarg(op.args[i])
- res = llvm_rffi.LLVMBuildCall(self.builder, op.jump_target._llvm_func,
- args, len(op.args), "")
- llvm_rffi.LLVMSetInstructionCallConv(res, llvm_rffi.CallConv.Fast)
- llvm_rffi.LLVMSetTailCall(res, True)
- llvm_rffi.LLVMBuildRet(self.builder, res)
- lltype.free(args, flavor='raw')
+ if op.jump_target is self.loop:
+ basicblock = llvm_rffi.LLVMGetInsertBlock(self.builder)
+ self.phi_incoming_blocks.append(basicblock)
+ for i in range(len(op.args)):
+ incoming = self.phi_incoming_values[i]
+ incoming.append(self.getintarg(op.args[i]))
+ llvm_rffi.LLVMBuildBr(self.builder, self.bb_start)
+ else:
+ xxx
def generate_FAIL(self, op):
- self._ensure_out_args(len(op.args))
+ self.cpu._ensure_out_args(len(op.args))
for i in range(len(op.args)):
value_ref = self.vars[op.args[i]]
ty = llvm_rffi.LLVMTypeOf(value_ref)
typtr = llvm_rffi.LLVMPointerType(ty, 0)
- addr_as_signed = rffi.cast(lltype.Signed, self.in_out_args[i])
+ addr_as_signed = rffi.cast(lltype.Signed, self.cpu.in_out_args[i])
llvmconstint = self._make_const_int(addr_as_signed)
llvmconstptr = llvm_rffi.LLVMConstIntToPtr(llvmconstint, typtr)
llvm_rffi.LLVMBuildStore(self.builder, value_ref,
llvmconstptr)
- i = len(self.fail_ops)
- self.fail_ops.append(op)
- llvm_rffi.LLVMBuildRet(self.builder, self._make_const_int(i))
-
- # ------------------------------
- # Execution
-
- def set_future_value_int(self, index, intvalue):
- p = rffi.cast(lltype.Ptr(self.SIGNED_VALUE), self.in_out_args[index])
- p[0] = intvalue
-
- def execute_operations(self, loop):
- print 'execute_operations: %s' % (loop._llvm_func_addr,)
- #import time; time.sleep(2)
- res = loop._llvm_entry_stub(loop._llvm_func_addr)
- print '\t--->', res
- return self.fail_ops[res]
-
- def get_latest_value_int(self, index):
- p = rffi.cast(lltype.Ptr(self.SIGNED_VALUE), self.in_out_args[index])
- return p[0]
+ i = len(self.cpu.fail_ops)
+ self.cpu.fail_ops.append(op)
+ llvm_rffi.LLVMBuildRet(self.builder, self._make_const_int(~i))
# ____________________________________________________________
@@ -288,7 +304,7 @@
if 'A' <= _key <= 'Z':
assert _value not in all_operations
methname = 'generate_' + _key
- if hasattr(LLVMCPU, methname):
+ if hasattr(LLVMJITCompiler, methname):
all_operations[_value] = methname
all_operations = unrolling_iterable(all_operations.items())
Modified: pypy/branch/pyjitpl5-experiments/pypy/jit/backend/llvm/test/test_runner.py
==============================================================================
--- pypy/branch/pyjitpl5-experiments/pypy/jit/backend/llvm/test/test_runner.py (original)
+++ pypy/branch/pyjitpl5-experiments/pypy/jit/backend/llvm/test/test_runner.py Sat Jun 6 12:51:08 2009
@@ -50,7 +50,6 @@
cpu.set_future_value_int(2, 0)
cpu.execute_operations(loop)
assert cpu.get_latest_value_int(0) == 3*(2**11)
- py.test.skip("fails because tail-recursion is not handled yet")
cpu.set_future_value_int(0, 2**29)
cpu.set_future_value_int(1, 3)
cpu.set_future_value_int(2, 0)
More information about the Pypy-commit
mailing list