[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