[pypy-svn] r65009 - in pypy/branch/pyjitpl5/pypy/jit/backend/llvm: . test
arigo at codespeak.net
arigo at codespeak.net
Sun May 3 21:49:38 CEST 2009
Author: arigo
Date: Sun May 3 21:49:36 2009
New Revision: 65009
Modified:
pypy/branch/pyjitpl5/pypy/jit/backend/llvm/llvm_rffi.py
pypy/branch/pyjitpl5/pypy/jit/backend/llvm/runner.py
pypy/branch/pyjitpl5/pypy/jit/backend/llvm/test/test_llvm_rffi.py
pypy/branch/pyjitpl5/pypy/jit/backend/llvm/test/test_runner.py
Log:
Pass a test with a simple loop.
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/llvm/llvm_rffi.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/llvm/llvm_rffi.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/llvm/llvm_rffi.py Sun May 3 21:49:36 2009
@@ -56,6 +56,18 @@
LLVMGenericValueRef = opaqueptr('struct LLVMOpaqueGenericValue')
LLVMExecutionEngineRef = opaqueptr('struct LLVMOpaqueExecutionEngine')
+class Predicate:
+ EQ = 32 # equal
+ NE = 33 # not equal
+ UGT = 34 # unsigned greater than
+ UGE = 35 # unsigned greater or equal
+ ULT = 36 # unsigned less than
+ ULE = 37 # unsigned less or equal
+ SGT = 38 # signed greater than
+ SGE = 39 # signed greater or equal
+ SLT = 40 # signed less than
+ SLE = 41 # signed less or equal
+
# ____________________________________________________________
LLVMDisposeMessage = llexternal('LLVMDisposeMessage', [rffi.CCHARP],
@@ -66,7 +78,9 @@
LLVMModuleRef)
LLVMDumpModule = llexternal('LLVMDumpModule', [LLVMModuleRef], lltype.Void)
+LLVMInt1Type = llexternal('LLVMInt1Type', [], LLVMTypeRef)
LLVMInt32Type = llexternal('LLVMInt32Type', [], LLVMTypeRef)
+LLVMInt64Type = llexternal('LLVMInt64Type', [], LLVMTypeRef)
LLVMFunctionType = llexternal('LLVMFunctionType',
[LLVMTypeRef, # return type
rffi.CArrayPtr(LLVMTypeRef), # param types
@@ -77,6 +91,7 @@
rffi.UINT], # address space
LLVMTypeRef)
+LLVMTypeOf = llexternal('LLVMTypeOf', [LLVMValueRef], LLVMTypeRef)
LLVMConstInt = llexternal('LLVMConstInt', [LLVMTypeRef, # type
rffi.ULONGLONG, # value
rffi.INT], # flag: is_signed
@@ -101,6 +116,11 @@
rffi.CCHARP], # name
LLVMBasicBlockRef)
+LLVMSetTailCall = llexternal('LLVMSetTailCall',
+ [LLVMValueRef, # call instruction
+ rffi.INT], # flag: is_tail
+ lltype.Void)
+
LLVMCreateBuilder = llexternal('LLVMCreateBuilder', [], LLVMBuilderRef)
LLVMPositionBuilderAtEnd = llexternal('LLVMPositionBuilderAtEnd',
[LLVMBuilderRef, # builder
@@ -112,6 +132,12 @@
LLVMBuildRet = llexternal('LLVMBuildRet', [LLVMBuilderRef, # builder,
LLVMValueRef], # result
LLVMValueRef)
+LLVMBuildCondBr = llexternal('LLVMBuildCondBr',
+ [LLVMBuilderRef, # builder
+ LLVMValueRef, # condition
+ LLVMBasicBlockRef, # block if true
+ LLVMBasicBlockRef], # block if false
+ LLVMValueRef)
for _name in ['Add', 'Sub', 'LShr']:
globals()['LLVMBuild' + _name] = llexternal('LLVMBuild' + _name,
@@ -133,6 +159,32 @@
LLVMValueRef, # value
LLVMValueRef], # pointer location
LLVMValueRef)
+LLVMBuildTrunc = llexternal('LLVMBuildTrunc',
+ [LLVMBuilderRef, # builder
+ LLVMValueRef, # value
+ LLVMTypeRef, # destination type
+ rffi.CCHARP], # name of result
+ LLVMValueRef)
+LLVMBuildZExt = llexternal('LLVMBuildZExt',
+ [LLVMBuilderRef, # builder
+ LLVMValueRef, # value
+ LLVMTypeRef, # destination type
+ rffi.CCHARP], # name of result
+ LLVMValueRef)
+LLVMBuildICmp = llexternal('LLVMBuildICmp',
+ [LLVMBuilderRef, # builder
+ rffi.INT, # predicate (see LLVMIntPredicate)
+ LLVMValueRef, # left-hand side
+ LLVMValueRef, # right-hand side
+ rffi.CCHARP], # name of result
+ LLVMValueRef)
+LLVMBuildCall = llexternal('LLVMBuildCall',
+ [LLVMBuilderRef, # builder
+ LLVMValueRef, # function
+ rffi.CArrayPtr(LLVMValueRef), # arguments
+ rffi.UINT, # argument count
+ rffi.CCHARP], # name of result
+ LLVMValueRef)
LLVMCreateModuleProviderForExistingModule = llexternal(
'LLVMCreateModuleProviderForExistingModule', [LLVMModuleRef],
@@ -159,6 +211,9 @@
rffi.INT, # "fast"
rffi.CArrayPtr(rffi.CCHARP)], # -> error
rffi.INT)
+LLVMDisposeExecutionEngine = llexternal('LLVMDisposeExecutionEngine',
+ [LLVMExecutionEngineRef],
+ lltype.Void)
LLVMRunFunction = llexternal('LLVMRunFunction',
[LLVMExecutionEngineRef,
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/llvm/runner.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/llvm/runner.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/llvm/runner.py Sun May 3 21:49:36 2009
@@ -1,5 +1,6 @@
-import sys
+import py, sys
from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.unroll import unrolling_iterable
from pypy.jit.metainterp.history import ConstInt
from pypy.jit.backend import model
@@ -28,12 +29,14 @@
self.out_args = []
def setup_once(self):
+ if not we_are_translated():
+ teardown_now()
self.module = llvm_rffi.LLVMModuleCreateWithName("pypyjit")
if sys.maxint == 2147483647:
self.ty_int = llvm_rffi.LLVMInt32Type()
else:
self.ty_int = llvm_rffi.LLVMInt64Type()
- self.ty_int_ptr = llvm_rffi.LLVMPointerType(self.ty_int, 0)
+ self.ty_bit = llvm_rffi.LLVMInt1Type()
mp = llvm_rffi.LLVMCreateModuleProviderForExistingModule(self.module)
ee_out = lltype.malloc(rffi.CArray(llvm_rffi.LLVMExecutionEngineRef),
@@ -51,25 +54,35 @@
llvm_rffi.LLVMDisposeMessage(error_out[0])
lltype.free(error_out, flavor='raw')
lltype.free(ee_out, flavor='raw')
+ if not we_are_translated():
+ set_teardown_function(self._teardown)
+
+ def _teardown(self):
+ llvm_rffi.LLVMDisposeExecutionEngine(self.ee)
# ------------------------------
# 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)
+ loop._llvm_func = func
self.vars = {}
for i in range(len(loop.inputargs)):
self.vars[loop.inputargs[i]] = llvm_rffi.LLVMGetParam(func, i)
self.builder = llvm_rffi.LLVMCreateBuilder()
- self._generate_branch(loop.operations, func)
+ bb_start = llvm_rffi.LLVMAppendBasicBlock(func, "entry")
+ self.pending_blocks = [(loop.operations, bb_start)]
+ while self.pending_blocks:
+ operations, bb = self.pending_blocks.pop()
+ self._generate_branch(operations, bb)
llvm_rffi.LLVMDisposeBuilder(self.builder)
- self.builder = None
self.vars = None
#...
llvm_rffi.LLVMDumpModule(self.module)
- loop._llvm_func = func
+ self.compiling_loop = None
def get_ty_func(self, nb_args):
try:
@@ -99,14 +112,10 @@
while len(self.out_args) < count:
self.out_args.append(lltype.malloc(self.RAW_VALUE, flavor='raw'))
- def _generate_branch(self, operations, func):
- bb = llvm_rffi.LLVMAppendBasicBlock(func, "")
- llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, bb)
- #
+ def _generate_branch(self, operations, basicblock):
+ llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, basicblock)
for op in operations:
self._generate_op(op)
- #
- return bb
def _generate_op(self, op):
opnum = op.opnum
@@ -118,41 +127,107 @@
else:
raise MissingOperation(resoperation.opname[opnum])
- def getarg(self, v):
+ def getintarg(self, v):
try:
- return self.vars[v]
+ value_ref = self.vars[v]
except KeyError:
assert isinstance(v, ConstInt)
return self._make_const_int(v.value)
+ else:
+ return self._cast_to_int(value_ref)
def _make_const_int(self, value):
return llvm_rffi.LLVMConstInt(self.ty_int, value, True)
- def generate_int_add(self, op):
- self.vars[op.result] = llvm_rffi.LLVMBuildAdd(self.builder,
- self.getarg(op.args[0]),
- self.getarg(op.args[1]),
- "")
-
- def generate_uint_rshift(self, op):
- self.vars[op.result] = llvm_rffi.LLVMBuildLShr(self.builder,
- self.getarg(op.args[0]),
- self.getarg(op.args[1]),
- "")
+ def _cast_to_int(self, value_ref):
+ ty = llvm_rffi.LLVMTypeOf(value_ref)
+ if ty == self.ty_int:
+ return value_ref
+ elif ty == self.ty_bit:
+ return llvm_rffi.LLVMBuildZExt(self.builder, value_ref,
+ self.ty_int, "")
+ else:
+ raise AssertionError("type is not an int nor a bit")
+
+ def getbitarg(self, v):
+ try:
+ value_ref = self.vars[v]
+ except KeyError:
+ assert isinstance(v, ConstInt)
+ return self._make_const_bit(v.value)
+ else:
+ return self._cast_to_bit(value_ref)
+
+ def _make_const_bit(self, value):
+ assert (value & ~1) == 0, "value is not 0 or 1"
+ return llvm_rffi.LLVMConstInt(self.ty_bit, value, True)
+
+ def _cast_to_bit(self, value_ref):
+ ty = llvm_rffi.LLVMTypeOf(value_ref)
+ if ty == self.ty_bit:
+ return value_ref
+ elif ty == self.ty_int:
+ return llvm_rffi.LLVMBuildTrunc(self.builder, value_ref,
+ self.ty_bit, "")
+ else:
+ raise AssertionError("type is not an int nor a bit")
+
+ for _opname, _llvmname in [('INT_ADD', 'Add'),
+ ('INT_SUB', 'Sub'),
+ ('UINT_RSHIFT', 'LShr'),
+ ]:
+ exec py.code.Source('''
+ def generate_%s(self, op):
+ self.vars[op.result] = llvm_rffi.LLVMBuild%s(
+ self.builder,
+ self.getintarg(op.args[0]),
+ self.getintarg(op.args[1]),
+ "")
+ ''' % (_opname, _llvmname)).compile()
- def generate_int_invert(self, op):
+ def generate_INT_INVERT(self, op):
self.vars[op.result] = llvm_rffi.LLVMBuildNot(self.builder,
- self.vars[op.args[0]],
- "")
+ self.getintarg(op.args[0]),
+ "")
- def generate_fail(self, op):
+ def generate_INT_IS_TRUE(self, op):
+ self.vars[op.result] = llvm_rffi.LLVMBuildICmp(self.builder,
+ llvm_rffi.Predicate.NE,
+ self.getintarg(op.args[0]),
+ self._make_const_int(0),
+ "")
+
+ def generate_GUARD_TRUE(self, op):
+ func = self.compiling_loop._llvm_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]),
+ bb_on_track, bb_off_track)
+ # generate the on-track part first, and the off-track part later
+ self.pending_blocks.append((op.suboperations, bb_off_track))
+ 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.LLVMBuildRet(self.builder, res)
+ llvm_rffi.LLVMSetTailCall(res, True)
+ lltype.free(args, flavor='raw')
+
+ def generate_FAIL(self, op):
self._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.out_args[i])
llvmconstint = self._make_const_int(addr_as_signed)
- llvmconstptr = llvm_rffi.LLVMConstIntToPtr(llvmconstint,
- self.ty_int_ptr)
- llvm_rffi.LLVMBuildStore(self.builder, self.vars[op.args[i]],
+ llvmconstptr = llvm_rffi.LLVMConstIntToPtr(llvmconstint, typtr)
+ llvm_rffi.LLVMBuildStore(self.builder, value_ref,
llvmconstptr)
i = len(self.fail_ops)
self.fail_ops.append(op)
@@ -178,6 +253,7 @@
llvm_rffi.LLVMDisposeGenericValue(self.in_args[i])
self.in_args[i] = lltype.nullptr(llvm_rffi.LLVMGenericValueRef.TO)
i += 1
+ return self.fail_ops[res]
def get_latest_value_int(self, index):
return rffi.cast(lltype.Signed, self.out_args[index][0])
@@ -191,7 +267,20 @@
for _key, _value in rop.__dict__.items():
if 'A' <= _key <= 'Z':
assert _value not in all_operations
- methname = 'generate_' + _key.lower()
+ methname = 'generate_' + _key
if hasattr(LLVMCPU, methname):
all_operations[_value] = methname
all_operations = unrolling_iterable(all_operations.items())
+
+_teardown = None
+
+def set_teardown_function(fn):
+ global _teardown
+ _teardown = fn
+
+def teardown_now():
+ global _teardown
+ fn = _teardown
+ _teardown = None
+ if fn is not None:
+ fn()
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/llvm/test/test_llvm_rffi.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/llvm/test/test_llvm_rffi.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/llvm/test/test_llvm_rffi.py Sun May 3 21:49:36 2009
@@ -80,19 +80,29 @@
lltype.free(error_out, flavor='raw')
lltype.free(ee_out, flavor='raw')
- # The arguments needs to be passed as "GenericValue" objects.
- args = lltype.malloc(rffi.CArray(LLVMGenericValueRef), 2, flavor='raw')
- args[0] = LLVMCreateGenericValueOfInt(ty_int, 100, True)
- args[1] = LLVMCreateGenericValueOfInt(ty_int, 42, True)
-
- # Now let's compile and run!
- retval = LLVMRunFunction(ee, f_sum, 2, args)
- LLVMDisposeGenericValue(args[1])
- LLVMDisposeGenericValue(args[0])
- lltype.free(args, flavor='raw')
-
- # The return value is also GenericValue. Let's check it.
- ulonglong = LLVMGenericValueToInt(retval, True)
- LLVMDisposeGenericValue(retval)
- res = rffi.cast(lltype.Signed, ulonglong)
- assert res == 142
+ try:
+ # The arguments needs to be passed as "GenericValue" objects.
+ args = lltype.malloc(rffi.CArray(LLVMGenericValueRef), 2, flavor='raw')
+ args[0] = LLVMCreateGenericValueOfInt(ty_int, 100, True)
+ args[1] = LLVMCreateGenericValueOfInt(ty_int, 42, True)
+
+ # Now let's compile and run!
+ retval = LLVMRunFunction(ee, f_sum, 2, args)
+ LLVMDisposeGenericValue(args[1])
+ LLVMDisposeGenericValue(args[0])
+ lltype.free(args, flavor='raw')
+
+ # The return value is also GenericValue. Let's check it.
+ ulonglong = LLVMGenericValueToInt(retval, True)
+ LLVMDisposeGenericValue(retval)
+ res = rffi.cast(lltype.Signed, ulonglong)
+ assert res == 142
+
+ finally:
+ LLVMDisposeExecutionEngine(ee)
+
+
+def test_from_llvm_py_example_3():
+ """This test is the same as the previous one. Just tests that we
+ have freed enough stuff to be able to call it again."""
+ test_from_llvm_py_example_2()
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/llvm/test/test_runner.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/llvm/test/test_runner.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/llvm/test/test_runner.py Sun May 3 21:49:36 2009
@@ -25,3 +25,28 @@
cpu.execute_operations(loop)
assert cpu.get_latest_value_int(0) == (19 >> 3)
assert cpu.get_latest_value_int(1) == (~38)
+
+def test_loop_1():
+ v1 = BoxInt(); v2 = BoxInt(); v3 = BoxInt()
+ v4 = BoxInt(); v5 = BoxInt(); v6 = BoxInt()
+ loop = TreeLoop('loop_1')
+ loop.inputargs = [v1, v2, v3]
+ loop.operations = [
+ ResOperation(rop.INT_IS_TRUE, [v1], v4),
+ ResOperation(rop.GUARD_TRUE, [v4], None),
+ ResOperation(rop.INT_ADD, [v2, v3], v5),
+ ResOperation(rop.INT_SUB, [v1, ConstInt(1)], v6),
+ ResOperation(rop.JUMP, [v6, v2, v5], None),
+ ]
+ loop.operations[-1].jump_target = loop
+ loop.operations[1].suboperations = [
+ ResOperation(rop.FAIL, [v3], None),
+ ]
+ cpu = LLVMCPU(None)
+ cpu.setup_once()
+ cpu.compile_operations(loop)
+ cpu.set_future_value_int(0, 7)
+ cpu.set_future_value_int(1, 6)
+ cpu.set_future_value_int(2, 0)
+ cpu.execute_operations(loop)
+ assert cpu.get_latest_value_int(0) == 42
More information about the Pypy-commit
mailing list