[pypy-svn] r65024 - in pypy/branch/pyjitpl5/pypy/jit/backend/llvm: . test

arigo at codespeak.net arigo at codespeak.net
Mon May 4 17:18:30 CEST 2009


Author: arigo
Date: Mon May  4 17:18:29 2009
New Revision: 65024

Added:
   pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo2.cpp   (contents, props changed)
   pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo2.h   (contents, props changed)
Modified:
   pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo1.c
   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_runner.py
Log:
Revert the phi node trick, and start writing a version of
execute_operations() that is much simpler, not involing the
tricky LLVMRunFunction().  Also generate a helper function
and a main function, in preparation for tail-call optimization
(not implemented yet).


Modified: pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo1.c
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo1.c	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo1.c	Mon May  4 17:18:29 2009
@@ -2,11 +2,13 @@
 #include "llvm-c/Analysis.h"
 #include "llvm-c/Transforms/Scalar.h"
 #include "llvm-c/ExecutionEngine.h"
+#include "demo2.h"
 
 /* The following list of functions seems to be necessary to force the
  * functions to be included in pypy_cache_llvm.so.  The list is never
  * used.  Actually, any single function seems to be enough...
  */
 void* llvm_c_functions[] = {
-  (void*) LLVMModuleCreateWithName
+  (void*) LLVMModuleCreateWithName,
+  (void*) _LLVM_EE_getPointerToFunction
 };

Added: pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo2.cpp
==============================================================================
--- (empty file)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo2.cpp	Mon May  4 17:18:29 2009
@@ -0,0 +1,16 @@
+/* LLVM includes */
+#include "llvm-c/ExecutionEngine.h"
+#include "llvm/ExecutionEngine/GenericValue.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "demo2.h"
+
+using namespace llvm;
+
+
+/* Missing pieces of the C interface...
+ */
+void *_LLVM_EE_getPointerToFunction(LLVMExecutionEngineRef EE,
+                                   LLVMValueRef F)
+{
+  return unwrap(EE)->getPointerToFunction(unwrap<Function>(F));
+}

Added: pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo2.h
==============================================================================
--- (empty file)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/llvm/demo2.h	Mon May  4 17:18:29 2009
@@ -0,0 +1,10 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void* _LLVM_EE_getPointerToFunction(LLVMExecutionEngineRef EE,
+                                    LLVMValueRef F);
+
+#ifdef __cplusplus
+}
+#endif

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	Mon May  4 17:18:29 2009
@@ -13,9 +13,11 @@
 dirname = os.path.join(cachename, 'libs')
 libname = os.path.join(dirname, 'pypy_cache_llvm.so')
 cname = os.path.join(os.path.dirname(__file__), 'demo1.c')
+cppname = os.path.join(os.path.dirname(__file__), 'demo2.cpp')
 
-if not os.path.isfile(libname) or (os.path.getmtime(cname) >
-                                   os.path.getmtime(libname)):
+if (not os.path.isfile(libname) or
+        os.path.getmtime(cname) > os.path.getmtime(libname) or
+        os.path.getmtime(cppname) > os.path.getmtime(libname)):
     if not os.path.isdir(dirname):
         if not os.path.isdir(cachename):
             os.mkdir(cachename)
@@ -27,9 +29,11 @@
         if err:
             raise Exception("gcc command failed")
 
-    oname = os.path.join(dirname, 'demo1.o')
-    do("gcc -c '%s' -o '%s'" % (cname, oname))
-    do("g++ -shared '%s' -o '%s'" % (oname, libname) +
+    o1name = os.path.join(dirname, 'demo1.o')
+    o2name = os.path.join(dirname, 'demo2.o')
+    do("gcc -c '%s' -o '%s'" % (cname, o1name))
+    do("g++ -c '%s' -o '%s' `%s --cppflags`" % (cppname, o2name, llvm_config))
+    do("g++ -shared '%s' '%s' -o '%s'" % (o1name, o2name, libname) +
        " `%s --cflags --ldflags --libs jit engine`" % llvm_config)
 
 compilation_info = ExternalCompilationInfo(
@@ -39,10 +43,21 @@
 
 # ____________________________________________________________
 
+Debug = False
+
 def llexternal(name, args, result, **kwds):
-    return rffi.llexternal(name, args, result,
-                           compilation_info=compilation_info,
-                           **kwds)
+    ll = rffi.llexternal(name, args, result,
+                         compilation_info=compilation_info,
+                         **kwds)
+    if Debug:
+        def func(*args):
+            print name
+            res = ll(*args)
+            print '\t->', res
+            return res
+        return func
+    else:
+        return ll
 
 def opaqueptr(name):
     return rffi.VOIDP  # lltype.Ptr(rffi.COpaque(name))
@@ -86,6 +101,7 @@
 LLVMDumpModule = llexternal('LLVMDumpModule', [LLVMModuleRef], lltype.Void)
 
 LLVMInt1Type = llexternal('LLVMInt1Type', [], LLVMTypeRef)
+LLVMInt8Type = llexternal('LLVMInt8Type', [], LLVMTypeRef)
 LLVMInt32Type = llexternal('LLVMInt32Type', [], LLVMTypeRef)
 LLVMInt64Type = llexternal('LLVMInt64Type', [], LLVMTypeRef)
 LLVMFunctionType = llexternal('LLVMFunctionType',
@@ -127,6 +143,10 @@
                                    rffi.CCHARP],            # name
                                   LLVMBasicBlockRef)
 
+LLVMSetInstructionCallConv = llexternal('LLVMSetInstructionCallConv',
+                                        [LLVMValueRef,   # call instruction
+                                         rffi.UINT],     # new call conv
+                                        lltype.Void)
 LLVMSetTailCall = llexternal('LLVMSetTailCall',
                              [LLVMValueRef,        # call instruction
                               rffi.INT],           # flag: is_tail
@@ -175,6 +195,11 @@
          rffi.CCHARP],    # name of result
         LLVMValueRef)
 
+LLVMBuildLoad = llexternal('LLVMBuildLoad',
+                           [LLVMBuilderRef,     # builder
+                            LLVMValueRef,       # pointer location
+                            rffi.CCHARP],       # name of result
+                           LLVMValueRef)
 LLVMBuildStore = llexternal('LLVMBuildStore',
                             [LLVMBuilderRef,    # builder
                              LLVMValueRef,      # value
@@ -192,6 +217,12 @@
                             LLVMTypeRef,       # destination type
                             rffi.CCHARP],      # name of result
                            LLVMValueRef)
+LLVMBuildBitCast = llexternal('LLVMBuildBitCast',
+                              [LLVMBuilderRef, # builder
+                               LLVMValueRef,   # value
+                               LLVMTypeRef,    # destination type
+                               rffi.CCHARP],   # name of result
+                              LLVMValueRef)
 LLVMBuildICmp = llexternal('LLVMBuildICmp',
                            [LLVMBuilderRef,  # builder
                             rffi.INT,        # predicate (see LLVMIntPredicate)
@@ -247,3 +278,8 @@
                               rffi.UINT,                            # num args
                               rffi.CArrayPtr(LLVMGenericValueRef)], # args
                              LLVMGenericValueRef)   # return value
+
+LLVM_EE_getPointerToFunction = llexternal('_LLVM_EE_getPointerToFunction',
+                                          [LLVMExecutionEngineRef,
+                                           LLVMValueRef],           # function
+                                          rffi.VOIDP)

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	Mon May  4 17:18:29 2009
@@ -14,8 +14,9 @@
 
 
 class LLVMCPU(model.AbstractCPU):
-    ARRAY_OF_VALUE_REFS = rffi.CArray(llvm_rffi.LLVMGenericValueRef)
     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):
@@ -23,10 +24,8 @@
         self.translate_support_code = translate_support_code
         self.ty_funcs = {}
         self.fail_ops = []
-        self.in_args_count = 0
-        self.in_args = lltype.malloc(self.ARRAY_OF_VALUE_REFS, 0,
-                                     flavor='raw')
-        self.out_args = []
+        self.in_out_args = []
+        self.entry_stubs = {}
 
     def setup_once(self):
         if not we_are_translated():
@@ -37,7 +36,16 @@
         else:
             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)
+        #
+        arglist = lltype.malloc(rffi.CArray(llvm_rffi.LLVMTypeRef), 1,
+                                flavor='raw')
+        arglist[0] = self.ty_charp
+        self.ty_stub_func = llvm_rffi.LLVMFunctionType(self.ty_int, arglist,
+                                                       1, False)
+        lltype.free(arglist, flavor='raw')
+        #
         mp = llvm_rffi.LLVMCreateModuleProviderForExistingModule(self.module)
         ee_out = lltype.malloc(rffi.CArray(llvm_rffi.LLVMExecutionEngineRef),
                                1, flavor='raw')
@@ -68,53 +76,66 @@
         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
         self.vars = {}
-        self.builder = llvm_rffi.LLVMCreateBuilder()
-        bb_entry = llvm_rffi.LLVMAppendBasicBlock(func, "entry")
-        bb_start_code = llvm_rffi.LLVMAppendBasicBlock(func, "")
-        self.bb_start_code = bb_start_code
-        llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, bb_entry)
-        llvm_rffi.LLVMBuildBr(self.builder, bb_start_code)
-        #
-        llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, bb_start_code)
-        self.phi_incoming_blocks = [bb_entry]
-        self.phi_incoming_values = []
         for i in range(len(loop.inputargs)):
-            phi = llvm_rffi.LLVMBuildPhi(self.builder, self.ty_int, "")
-            incoming = [llvm_rffi.LLVMGetParam(func, i)]
-            self.phi_incoming_values.append(incoming)
-            self.vars[loop.inputargs[i]] = phi
-        #
-        self.pending_blocks = [(loop.operations, bb_start_code)]
+            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)]
         while self.pending_blocks:
             operations, bb = self.pending_blocks.pop()
             self._generate_branch(operations, bb)
-        #
-        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]
-        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')
-        #
         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
 
+    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 _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)
+        #
+        stub = llvm_rffi.LLVM_EE_getPointerToFunction(self.ee, stubfunc)
+        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]
@@ -130,18 +151,10 @@
             return ty_func
 
     def _ensure_in_args(self, count):
-        if self.in_args_count <= count:
-            count = (count + 8) & ~7       # increment by at least one
-            new = lltype.malloc(self.ARRAY_OF_VALUE_REFS, count, flavor='raw')
-            lltype.free(self.in_args, flavor='raw')
-            for i in range(count):
-                new[i] = lltype.nullptr(llvm_rffi.LLVMGenericValueRef.TO)
-            self.in_args = new
-            self.in_args_count = count
-
-    def _ensure_out_args(self, count):
-        while len(self.out_args) < count:
-            self.out_args.append(lltype.malloc(self.RAW_VALUE, flavor='raw'))
+        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
 
     def _generate_branch(self, operations, basicblock):
         llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, basicblock)
@@ -239,24 +252,16 @@
         llvm_rffi.LLVMPositionBuilderAtEnd(self.builder, bb_on_track)
 
     def generate_JUMP(self, op):
-        if op.jump_target is self.compiling_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_code)
-        else:
-            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.LLVMSetTailCall(res, True)     # XXX no effect :-(
-            llvm_rffi.LLVMBuildRet(self.builder, res)
-            lltype.free(args, flavor='raw')
+        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')
 
     def generate_FAIL(self, op):
         self._ensure_out_args(len(op.args))
@@ -264,7 +269,7 @@
             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])
+            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, typtr)
             llvm_rffi.LLVMBuildStore(self.builder, value_ref,
@@ -277,28 +282,16 @@
     # Execution
 
     def set_future_value_int(self, index, intvalue):
-        assert index < self.in_args_count - 1
-        if self.in_args[index]:
-            llvm_rffi.LLVMDisposeGenericValue(self.in_args[index])
-        self.in_args[index] = llvm_rffi.LLVMCreateGenericValueOfInt(
-            self.ty_int, intvalue, True)
+        p = rffi.cast(lltype.Ptr(self.SIGNED_VALUE), self.in_out_args[index])
+        p[0] = intvalue
 
     def execute_operations(self, loop):
-        retval = llvm_rffi.LLVMRunFunction(self.ee, loop._llvm_func,
-                                           len(loop.inputargs),
-                                           self.in_args)
-        ulonglong = llvm_rffi.LLVMGenericValueToInt(retval, True)
-        res = rffi.cast(lltype.Signed, ulonglong)
-        llvm_rffi.LLVMDisposeGenericValue(retval)
-        i = 0
-        while self.in_args[i]:
-            llvm_rffi.LLVMDisposeGenericValue(self.in_args[i])
-            self.in_args[i] = lltype.nullptr(llvm_rffi.LLVMGenericValueRef.TO)
-            i += 1
+        res = loop._llvm_entry_stub(loop._llvm_func_addr)
         return self.fail_ops[res]
 
     def get_latest_value_int(self, index):
-        return rffi.cast(lltype.Signed, self.out_args[index][0])
+        p = rffi.cast(lltype.Ptr(self.SIGNED_VALUE), self.in_out_args[index])
+        return p[0]
 
 # ____________________________________________________________
 

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	Mon May  4 17:18:29 2009
@@ -1,4 +1,4 @@
-
+import py
 from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\
      BoxPtr, ConstPtr, TreeLoop
 from pypy.jit.metainterp.resoperation import rop
@@ -45,6 +45,12 @@
     cpu = LLVMCPU(None)
     cpu.setup_once()
     cpu.compile_operations(loop)
+    cpu.set_future_value_int(0, 2**11)
+    cpu.set_future_value_int(1, 3)
+    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