[pypy-svn] r35687 - in pypy/dist/pypy/jit/codegen/llvm: . test

ericvrp at codespeak.net ericvrp at codespeak.net
Wed Dec 13 18:06:02 CET 2006


Author: ericvrp
Date: Wed Dec 13 18:06:01 2006
New Revision: 35687

Modified:
   pypy/dist/pypy/jit/codegen/llvm/conftest.py
   pypy/dist/pypy/jit/codegen/llvm/rgenop.py
   pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py
   pypy/dist/pypy/jit/codegen/llvm/test/test_operation.py
Log:
Quite a few fixes and additions to the llvm jit backend.
    - float arithmetic (apart from pow()) passes
    - calling gc_malloc_fnaddr() works
    - op_get/setarrayitem kind of work (well enought for those tests to pass)
    - added py.test options --lineno, --print-debug and --print-source
    - fix operations that needed to be told what the returntype was


Modified: pypy/dist/pypy/jit/codegen/llvm/conftest.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llvm/conftest.py	(original)
+++ pypy/dist/pypy/jit/codegen/llvm/conftest.py	Wed Dec 13 18:06:01 2006
@@ -15,3 +15,18 @@
 #                py.test.skip('detected a %r CPU' % (processor,))
 #
 #        return super(Directory, self).run()
+
+Option = py.test.Config.Option
+
+option = py.test.Config.addoptions("llvm options",
+        Option('--lineno', action="store_true", default=False,
+               dest="lineno",
+               help="add linenumbers to the generated code"),
+
+        Option('--print-source', action="store_true", default=False,
+               dest="print_source",
+               help="print generated sources"),
+
+        Option('--print-debug', action="store_true", default=False,
+               dest="print_debug",
+               help="print debug information"))

Modified: pypy/dist/pypy/jit/codegen/llvm/rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llvm/rgenop.py	(original)
+++ pypy/dist/pypy/jit/codegen/llvm/rgenop.py	Wed Dec 13 18:06:01 2006
@@ -5,10 +5,18 @@
 from pypy.jit.codegen.model import GenVar, GenConst, CodeGenSwitch
 from pypy.jit.codegen.llvm import llvmjit
 from pypy.rlib.objectmodel import we_are_translated
+from pypy.jit.codegen.i386.rgenop import gc_malloc_fnaddr
+
+
+from pypy.jit.codegen.llvm.conftest import option
+
+LINENO       = option.lineno
+PRINT_SOURCE = option.print_source
+PRINT_DEBUG  = option.print_debug
 
 
 def log(s):
-    if not we_are_translated():
+    if PRINT_DEBUG and not we_are_translated():
         print str(s)
 
 
@@ -61,12 +69,18 @@
 
 
 class BoolConst(GenericConst):
-    type = 'int'
+    type = 'bool'
 
 
 class CharConst(GenericConst):
     type = 'ubyte'
 
+    def __init__(self, value):
+        if type(value) is str:
+            self.value = ord(value)
+        else:
+            self.value = value
+
 
 class UniCharConst(GenericConst):
     type = 'int'
@@ -289,19 +303,22 @@
 
     @specialize.arg(1)
     def genop1(self, opname, gv_arg):
-        #log('%s Builder.genop1' % self.block.label)
+        log('%s Builder.genop1 %s %s' % (
+            self.block.label, opname, gv_arg.operand()))
         genmethod = getattr(self, 'op_' + opname)
         return genmethod(gv_arg)
 
     @specialize.arg(1)
     def genop2(self, opname, gv_arg1, gv_arg2):
-        #log('%s Builder.genop2' % self.block.label)
+        log('%s Builder.genop2 %s %s,%s' % (
+            self.block.label, opname, gv_arg1.operand(), gv_arg2.operand()))
         genmethod = getattr(self, 'op_' + opname)
         return genmethod(gv_arg1, gv_arg2)
 
-    def _rgenop2_generic(self, llvm_opcode, gv_arg1, gv_arg2, restype='int'):
+    def _rgenop2_generic(self, llvm_opcode, gv_arg1, gv_arg2, restype=None):
         log('%s Builder._rgenop2_generic %s %s,%s' % (
             self.block.label, llvm_opcode, gv_arg1.operand(), gv_arg2.operand2()))
+        restype = restype or gv_arg1.type
         gv_result = Var(restype)
         self.asm.append(' %s=%s %s,%s' % (
             gv_result.operand2(), llvm_opcode, gv_arg1.operand(), gv_arg2.operand2()))
@@ -335,13 +352,16 @@
     op_uint_add = op_float_add = op_int_add
     op_uint_sub = op_float_sub = op_int_sub
     op_uint_mul = op_float_mul = op_int_mul
-    op_uint_floordiv = op_float_floordiv = op_int_floordiv
+    op_uint_floordiv = op_int_floordiv
     op_uint_mod = op_int_mod
     op_uint_and = op_int_and
     op_uint_or  = op_int_or
     op_uint_xor = op_int_xor
     op_uint_lshift = op_int_lshift
     op_uint_rshift = op_int_rshift
+ 
+    def op_float_truediv(self, gv_x, gv_y):  return self._rgenop2_generic('fdiv', gv_x, gv_y)
+    def op_float_neg(self, gv_x): return self._rgenop2_generic('sub', FloatConst(0.0), gv_x)
 
     def op_int_lt(self, gv_x, gv_y): return self._rgenop2_generic('setlt', gv_x, gv_y, 'bool')
     def op_int_le(self, gv_x, gv_y): return self._rgenop2_generic('setle', gv_x, gv_y, 'bool')
@@ -357,9 +377,10 @@
     op_char_gt = op_uint_gt = op_float_gt = op_int_gt
     op_char_ge = op_uint_ge = op_float_ge = op_int_ge
 
-    def _rgenop1_generic(self, llvm_opcode, gv_x, restype='int'):
+    def _rgenop1_generic(self, llvm_opcode, gv_x, restype=None):
         log('%s Builder._rgenop1_generic %s %s' % (
             self.block.label, llvm_opcode, gv_x.operand()))
+        restype = restype or gv_x.type
         gv_result = Var(restype)
         self.asm.append(' %s=%s %s' % (
             gv_result.operand2(), llvm_opcode, gv_x.operand()))
@@ -369,19 +390,25 @@
     def op_int_invert(self, gv_x):  return self._rgenop2_generic('xor', gv_x, IntConst(-1))
     def op_uint_invert(self, gv_x): return self._rgenop2_generic('xor', gv_x, UIntConst((1<<32)-1))
 
-    def op_int_abs(self, gv_x):
+    def _abs(self, gv_x, nullstr='0'):
         gv_comp    = Var('bool')
         gv_abs_pos = Var(gv_x.type)
         gv_result  = Var(gv_x.type)
-        self.asm.append(' %s=setgt %s,-1' % (gv_comp.operand2(), gv_x.operand()))
-        self.asm.append(' %s=sub %s 0,%s' % (gv_abs_pos.operand2(), gv_x.type, gv_x.operand2()))
+        self.asm.append(' %s=setge %s,%s' % (
+            gv_comp.operand2(), gv_x.operand(), nullstr))
+        self.asm.append(' %s=sub %s %s,%s' % (
+            gv_abs_pos.operand2(), gv_x.type, nullstr, gv_x.operand2()))
         self.asm.append(' %s=select %s,%s,%s' % (
             gv_result.operand2(), gv_comp.operand(), gv_x.operand(), gv_abs_pos.operand()))
         return gv_result
 
+    op_int_abs = _abs
+    def op_float_abs(self, gv_x):   return self._abs(gv_x, '0.0')
+
     #def op_bool_not(self, gv_x): #use select, xor or sub XXXX todo: did not see a test for this
 
-    def _cast_to(self, gv_x, restype='int'):
+    def _cast_to(self, gv_x, restype=None):
+        restype = restype or gv_x.type
         gv_result = Var(restype)
         self.asm.append(' %s=cast %s to %s' % (
             gv_result.operand2(), gv_x.operand(), restype))
@@ -484,8 +511,98 @@
 
     def op_float_is_true(self, gv_x):   return self._is_true(gv_x, '0.0')
 
+    def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index):
+        #XXX what about non char arrays?
+        log('%s Builder.genop_getarrayitem %s,%s,%s' % (
+            self.block.label, arraytoken, gv_ptr, gv_index))
+        gv_result = Var('ubyte')
+        gv_p = Var(gv_result.type+'*')    #XXX get this from arraytoken
+        self.asm.append(' %s=getelementptr [0x%s]* %s,int 0,%s' % (
+            gv_p.operand2(), gv_result.type, gv_ptr.operand2(), gv_index.operand()))
+        self.asm.append(' %s=load %s' % (
+            gv_result.operand2(), gv_p.operand()))
+        return gv_result
+
+    def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index):
+        '''
+        self.mc.MOV(edx, gv_ptr.operand(self))
+        op = self.itemaddr(edx, arraytoken, gv_index)
+        self.mc.LEA(eax, op)
+        return self.returnvar(eax)
+        '''
+        #XXX TODO
+        gv_result = Var('int')
+        log('%s Builder.genop_getarraysubstruct %s,%s,%s' % (
+            self.block.label, arraytoken, gv_ptr, gv_index))
+        self.asm.append(' %s=int 0 ;%s Builder.genop_getarraysubstruct %s,%s,%s' % (
+            gv_result.operand2(), self.block.label, arraytoken, gv_ptr, gv_index))
+        return gv_result
+
+    def genop_getarraysize(self, arraytoken, gv_ptr):
+        '''
+        lengthoffset, startoffset, itemoffset = arraytoken
+        self.mc.MOV(edx, gv_ptr.operand(self))
+        return self.returnvar(mem(edx, lengthoffset))
+        '''
+        #XXX TODO
+        gv_result = Var('int')
+        log('%s Builder.genop_getarraysize %s,%s' % (
+            self.block.label, arraytoken, gv_ptr))
+        self.asm.append(' %s=int 0 ;%s Builder.genop_getarraysize %s,%s' % (
+            gv_result.operand2(), self.block.label, arraytoken, gv_ptr))
+        return gv_result
+
+    def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value):
+        #XXX what about non char arrays?
+        log('%s Builder.genop_setarrayitem %s,%s,%s,%s' % (
+            self.block.label, arraytoken, gv_ptr, gv_index, gv_value))
+        gv_p = Var('ubyte*')    #XXX get this from arraytoken
+        self.asm.append(' %s=getelementptr [0x%s]* %s,int 0,%s' % (
+            gv_p.operand2(), gv_ptr.type[:-1], gv_ptr.operand2(), gv_index.operand()))
+        self.asm.append(' store %s,%s' % (
+            gv_value.operand(), gv_p.operand()))
+
+    def genop_malloc_fixedsize(self, size):
+        '''
+        # XXX boehm only, no atomic/non atomic distinction for now
+        self.push(imm(size))
+        self.mc.CALL(rel32(gc_malloc_fnaddr()))
+        return self.returnvar(eax)
+        '''
+        log('%s Builder.genop_malloc_fixedsize %s' % (
+            self.block.label, size))
+        gv_result = Var('ubyte*')
+        gv_gc_malloc_fnaddr = Var('[0xubyte]* (int)*')
+        #XXX or use addGlobalFunctionMapping in libllvmjit.restart()
+        self.asm.append(' %s=cast int %d to %s ;gc_malloc_fnaddr' % (
+            gv_gc_malloc_fnaddr.operand2(), gc_malloc_fnaddr(), gv_gc_malloc_fnaddr.type))
+        self.asm.append(' %s=call %s(int %d)' % (
+            gv_result.operand2(), gv_gc_malloc_fnaddr.operand(), size))
+        return gv_result
+
     def genop_malloc_varsize(self, varsizealloctoken, gv_size):
-        gv_result = Var('sbyte') #XXX  TODO
+        '''
+        # XXX boehm only, no atomic/non atomic distinction for now
+        # XXX no overflow checking for now
+        op_size = self.itemaddr(None, varsizealloctoken, gv_size)
+        self.mc.LEA(edx, op_size)
+        self.push(edx)
+        self.mc.CALL(rel32(gc_malloc_fnaddr()))
+        lengthoffset, _, _ = varsizealloctoken
+        self.mc.MOV(ecx, gv_size.operand(self))
+        self.mc.MOV(mem(eax, lengthoffset), ecx)
+        return self.returnvar(eax)
+        '''
+        log('%s Builder.genop_malloc_varsize %s,%s' % (
+            self.block.label, varsizealloctoken, gv_size))
+        gv_result = Var('ubyte*')
+        gv_gc_malloc_fnaddr = Var('[0xubyte]* (int)*')
+        #XXX or use addGlobalFunctionMapping in libllvmjit.restart()
+        self.asm.append(' %s=cast int %d to %s ;gc_malloc_fnaddr' % (
+            gv_gc_malloc_fnaddr.operand2(), gc_malloc_fnaddr(), gv_gc_malloc_fnaddr.type))
+        self.asm.append(' %s=call %s(%s)' % (
+            gv_result.operand2(), gv_gc_malloc_fnaddr.operand(), gv_size.operand()))
+        #XXX TODO set length field
         return gv_result
         
     def genop_call(self, sigtoken, gv_fnptr, args_gv):
@@ -493,10 +610,10 @@
             self.block.label, sigtoken, gv_fnptr, [v.operand() for v in args_gv]))
         argtypes, restype = sigtoken
         gv_returnvar = Var(restype)
-        #XXX we probably need to call an address directly if we can't resolve the funcname
+        #XXX we probably need to call an address directly if we can't resolve the funcsig
         self.asm.append(' %s=call %s(%s)' % (
                         gv_returnvar.operand2(),
-                        self.rgenop.funcname[gv_fnptr.value],
+                        self.rgenop.funcsig[gv_fnptr.value],
                         ','.join([v.operand() for v in args_gv])))
         return gv_returnvar
     
@@ -530,27 +647,29 @@
 
 class RLLVMGenOp(object):   #changed baseclass from (AbstractRGenOp) for better error messages
 
-    funcname = {} #HACK for looking up function names given a pre/post compilation function pointer
+    funcsig  = {} #HACK for looking up function signatures
     funcused = {} #we rename functions when encountered multiple times (for test_branching_compile)
 
     def end(self):
-        log('RLLVMGenOp.end')
+        log('   RLLVMGenOp.end')
         self.blocklist.append(EpilogueBlock())
         asmlines = []
         for block in self.blocklist:
             block.writecode(asmlines)
-        asmlines.append('')
+        if LINENO:
+            asmlines = ['%s ;%d' % (asmlines[i], i+1) for i in range(len(asmlines))]
         asm_string = '\n'.join(asmlines)
 
         self.blocklist = None
-        log(asm_string)
+        if PRINT_SOURCE:
+            print asm_string
         llvmjit.parse(asm_string)
         llvmjit.transform(3) #optimize module (should be on functions actually)
         function   = llvmjit.getNamedFunction(self.name)
         entrypoint = llvmjit.getPointerToFunctionAsInt(function)
         # XXX or directly cast the ctypes ptr to int with:
         #   ctypes.cast(ptr, c_void_p).value
-        self.funcname[entrypoint] = self.funcname[self.gv_entrypoint.value]
+        self.funcsig[entrypoint] = self.funcsig[self.gv_entrypoint.value]
         self.gv_entrypoint.value = entrypoint
 
     # ----------------------------------------------------------------
@@ -563,7 +682,7 @@
         else:
             self.funcused[name] = 0
 
-        log('RLLVMGenOp.newgraph %s,%s' % (sigtoken, name))
+        log('   RLLVMGenOp.newgraph %s,%s' % (sigtoken, name))
 
         prologueblock = PrologueBlock(sigtoken, name)
         self.blocklist = [prologueblock]
@@ -571,9 +690,9 @@
         prologueblock.startblocklabel = builder.nextlabel
 
         argtypes, restype = sigtoken
-        n = len(self.funcname) * 2 + 1     #+1 so we recognize these pre compilation 'pointers'
+        n = len(self.funcsig) * 2 + 1     #+1 so we recognize these pre compilation 'pointers'
         self.name = name
-        self.funcname[n] = '%s %%%s' % (restype, name)
+        self.funcsig[n] = '%s %%%s' % (restype, name)
         self.gv_entrypoint = IntConst(n)    #note: updated by Builder.end() (i.e after compilation)
         args = list(prologueblock.inputargs)
         builder.enter_next_block(argtypes, args)

Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py	(original)
+++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py	Wed Dec 13 18:06:01 2006
@@ -136,12 +136,6 @@
     llvmjit.restart()
     assert execute(llsquare, 'square', 4) == 4 * 4
 
-def test_execute_with_ctypes():
-    py.test.skip('TODO: implement execute with ctypes thru real pointer to function')
-    llvmjit.restart()
-    #should use function.getPointerToFunction
-    assert execute(llsquare, 'square', 4) == 4 * 4
-
 def test_execute_nothing():
     llvmjit.restart()
     assert llvmjit.execute(None, 4) == -1 #-1 == no function supplied

Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_operation.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llvm/test/test_operation.py	(original)
+++ pypy/dist/pypy/jit/codegen/llvm/test/test_operation.py	Wed Dec 13 18:06:01 2006
@@ -5,11 +5,12 @@
 
 
 skip_unsupported_platform()
-#py.test.skip('WIP')
+
 
 class LLVMTestBasicMixin(object):
     RGenOp = RLLVMGenOp
 
+
 class TestBasic(LLVMTestBasicMixin,
                 BasicTests):
 
@@ -19,35 +20,6 @@
     def skip(self):
         py.test.skip('WIP')
 
-    #test_unsigned = skip
-    #XXX -r_uint(n) generated op_int_sub(0,n) , why not op_uint_sub?
-    # -AR- for me it crashes on the 'x%y' test.  The LLVM ref manual
-    #      seems to mention only 'srem' and 'urem' instructions and
-    #      not 'rem'.  Same for 'sdiv' and 'udiv' and no 'div'.
-    #      Strange, the translator/llvm backend seems to produce
-    #      'div' and 'rem' anyway...
-    # -ER- the langref on llvm.org seems to be for the upcoming llvm version 2.0
-    # -AR- I see in llvm.rgenop that op_uint_invert uses an IntConst
-    #      (should be UIntConst).
-    # -ER- indeed
-
-    test_float_arithmetic = skip
-    #XXX bool(f - 2.0) generated op_float_sub(f,IntConst(2)) , why not FloatConst(2.0) ?
-    #   E           assert fp(40.0, 2.0) == fn(40.0, 2.0)
-    #   >           ArgumentError: argument 1: exceptions.TypeError: int expected instead of float instance
-
-    #   [/mnt/hdb3/projects.eric/pypy-dist/pypy/jit/codegen/i386/test/test_operation.py:240]
-    # -AR- the ctypes function type need to be fixed in rgen() in
-    #      i386.test.test_operation.  For now it assumes that all args are
-    #      c_int.  The llvm.rgenop.genconst() method should have more cases
-    #      instead of always returning IntConst for any Primitive type;
-    #      e.g. return UIntConst for unsigned integer types, FloatConst for
-    #      float types, and possibly things like CharConst UniCharConst etc.
-    #      based on what T is (the same kind of checks as in kindToken())
-    # -ER- extended genconst()
-
-    test_char_array = skip
-    test_char_varsize_array = skip
+    test_float_pow = skip
     test_unichar_array = skip
     test_char_unichar_fields = skip
-



More information about the Pypy-commit mailing list