[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