[pypy-svn] r58937 - in pypy/branch/oo-jit/pypy/jit/codegen/x86_64: . test

witulski at codespeak.net witulski at codespeak.net
Fri Oct 10 20:29:09 CEST 2008


Author: witulski
Date: Fri Oct 10 20:29:08 2008
New Revision: 58937

Modified:
   pypy/branch/oo-jit/pypy/jit/codegen/x86_64/assembler.py
   pypy/branch/oo-jit/pypy/jit/codegen/x86_64/objmodel.py
   pypy/branch/oo-jit/pypy/jit/codegen/x86_64/rgenop.py
   pypy/branch/oo-jit/pypy/jit/codegen/x86_64/test/test_rgenop.py
Log:
memory access works
Mov REG, Stack added + Tests


Modified: pypy/branch/oo-jit/pypy/jit/codegen/x86_64/assembler.py
==============================================================================
--- pypy/branch/oo-jit/pypy/jit/codegen/x86_64/assembler.py	(original)
+++ pypy/branch/oo-jit/pypy/jit/codegen/x86_64/assembler.py	Fri Oct 10 20:29:08 2008
@@ -1,4 +1,4 @@
-from pypy.jit.codegen.x86_64.objmodel import IntVar, Register8, Register64, Immediate8, Immediate32, Immediate64
+from pypy.jit.codegen.x86_64.objmodel import IntVar, Register8, Register64, Immediate8, Immediate32, Immediate64, Stack64
 
 # Mapping from 64Bit-Register to coding (Rex.W or Rex.B , ModRM)
 REGISTER_MAP = {
@@ -74,7 +74,15 @@
                 # used in imul (extra long opcode)
                 if not extra == None:
                     self.write(extra)
-                self.write_modRM_byte(mod, modrm2, modrm1)        
+                self.write_modRM_byte(mod, modrm2, modrm1)
+            elif isinstance(arg2.location, Stack64):
+                self.write_rex_byte(rexW, rexR, rexX, rexB) 
+                self.write(opcode)
+                # exchanged mod1,mod2, dont know why :)
+                self.write_modRM_byte(mod, modrm1, modrm2)
+                # no scale, no index, base = rsp
+                self.write_SIB(0, 4, 4) 
+                self.writeImm32(arg2.location.offset)  
     return quadreg_instr
         
         
@@ -119,8 +127,8 @@
         modrm1 = md1
         modrm2 = md2
         rexW = W
-        rexR = R
-        rexX = X
+        rexR = R #not used?
+        rexX = X #not used?
         rexB = B
         # TODO: other cases e.g memory as operand
         # FIXME: rexB?
@@ -170,7 +178,7 @@
     #TODO: support all combinations
     # The opcodes differs depending on the operands
     # Params:
-    # W (64bit Operands), R (extends reg field), X (extend Index(SIB) field), B (extends r/m field, Base(SIB) field, opcode reg field), 
+    # W (Width, 64bit Operands), R (Register, extends reg field), X (IndeX, extend Index(SIB) field), B (Base, extends r/m field, Base(SIB) field, opcode reg field), 
     # Opcode, mod, modrm1, modrm2, tttn(JUMPS), extraopcode 
     
     # FIXME: rexB is set
@@ -193,8 +201,9 @@
     _MOV_QWREG_IMM32 = make_two_operand_instr(   1,    0,    0, None, "\xC7", 3, None, 0)
     _MOV_QWREG_QWREG = make_two_operand_instr(   1, None,    0, None, "\x89", 3, None, None)
     _MOV_QWREG_IMM64 = make_two_operand_instr_with_alternate_encoding(1,0,0,None,"B8",None,None)
+    _MOV_QWREG_STACK = make_two_operand_instr(   1,    0,    0, None, "\x8B", 2, None, 4)#4 =RSP    
         
-    _IDIV_QWREG      = make_one_operand_instr(  1,    0,    0, None, "\xF7", 3, None, 7)
+    _IDIV_QWREG      = make_one_operand_instr(   1,    0,    0, None, "\xF7", 3, None, 7)
     
     _IMUL_QWREG_QWREG = make_two_operand_instr(  1, None,    0, None, "\x0F", 3, None, None, None, "\xAF")
     _IMUL_QWREG_IMM32 = make_two_operand_instr(  1, None,    0, None, "\x69", 3, None, "sameReg")
@@ -412,6 +421,10 @@
         byte = mod << 6 | (reg << 3) | rm
         self.write(chr(byte))
         
+    def write_SIB(self, scale, index, base):
+        byte = scale << 6 | (index << 3) | base
+        self.write(chr(byte))
+        
     # calc. the "Two's complement"
     # and return as pos. hex value.
     # This method is used to calc jump displ.

Modified: pypy/branch/oo-jit/pypy/jit/codegen/x86_64/objmodel.py
==============================================================================
--- pypy/branch/oo-jit/pypy/jit/codegen/x86_64/objmodel.py	(original)
+++ pypy/branch/oo-jit/pypy/jit/codegen/x86_64/objmodel.py	Fri Oct 10 20:29:08 2008
@@ -6,22 +6,25 @@
 # The to_string method is used to choose the right
 # method inside the assembler
 
-class Register64(object):
+class Location(object):
+    pass
+
+class Register64(Location):
     def __init__(self, reg):
         self.reg = reg
         
-class Register8(object):
+class Register8(Location):
     def __init__(self, reg):
         self.reg = reg
         
-class Stack64(object):
+class Stack64(Location):
     def __init__(self, offset):
         self.offset = offset
 
 class IntVar(model.GenVar):
     def __init__(self, location):
         self.location = location
-        assert isinstance(location, Register64) or isinstance(location, Register8) or isinstance(location, Stack64)
+        assert isinstance(location, Location) 
     
     def to_string(self):
         if isinstance(self.location, Stack64): 

Modified: pypy/branch/oo-jit/pypy/jit/codegen/x86_64/rgenop.py
==============================================================================
--- pypy/branch/oo-jit/pypy/jit/codegen/x86_64/rgenop.py	(original)
+++ pypy/branch/oo-jit/pypy/jit/codegen/x86_64/rgenop.py	Fri Oct 10 20:29:08 2008
@@ -1,6 +1,6 @@
 from pypy.jit.codegen import model
 from pypy.rlib.objectmodel import specialize
-from pypy.jit.codegen.x86_64.objmodel import IntVar, Register64, Register8, Immediate8, Immediate32, Immediate64
+from pypy.jit.codegen.x86_64.objmodel import IntVar, Register64, Register8, Immediate8, Immediate32, Immediate64, Stack64
 from pypy.jit.codegen.x86_64.codebuf import InMemoryCodeBuilder
 #TODO: understand llTypesystem
 from pypy.rpython.lltypesystem import llmemory, lltype 
@@ -73,7 +73,8 @@
     MC_SIZE = 65536
 
     #FIXME: The MemCodeBuild. is not opend in an _open method
-    def __init__(self, used_registers=[]):
+    def __init__(self, stackdepth, used_registers=[]):
+        self.stackdepth = stackdepth 
         self.mc = InMemoryCodeBuilder(self.MC_SIZE)
         #callee-saved registers are commented out
         self.freeregisters ={        
@@ -101,15 +102,21 @@
                    
     @specialize.arg(1)
     def genop1(self, opname, gv_arg):
+        if isinstance(gv_arg, model.GenVar) and isinstance(gv_arg.location, Stack64):
+            move_back_to_register(gv_arg)
         genmethod = getattr(self, 'op_' + opname)
         return genmethod(gv_arg)
 
     @specialize.arg(1)
     def genop2(self, opname, gv_arg1, gv_arg2):
+        if isinstance(gv_arg1, model.GenVar) and isinstance(gv_arg1.location, Stack64):
+            move_back_to_register(gv_arg1)
+        if isinstance(gv_arg2, model.GenVar) and isinstance(gv_arg2.location, Stack64):
+            move_back_to_register(gv_arg2)
         genmethod = getattr(self, 'op_' + opname)
         return genmethod(gv_arg1, gv_arg2)
  
-    op_int_add  = make_two_argument_method("ADD")
+    op_int_add  = make_two_argument_method("ADD") #TODO: use inc
     op_int_and  = make_two_argument_method("AND")
     op_int_dec  = make_one_argument_method("DEC")  #for debuging
     op_int_inc  = make_one_argument_method("INC")  #for debuging
@@ -119,7 +126,7 @@
     op_int_or   = make_two_argument_method("OR")
     op_int_push = make_one_argument_method("PUSH") #for debuging
     op_int_pop  = make_one_argument_method("POP")  #for debuging
-    op_int_sub  = make_two_argument_method("SUB")
+    op_int_sub  = make_two_argument_method("SUB") # TODO: use DEC
     op_int_xor  = make_two_argument_method("XOR")
 
     # TODO: support reg8
@@ -241,7 +248,7 @@
         def jump(self, gv_condition, args_for_jump_gv): 
             # the targetbuilder must know the registers(live vars) 
             # of the calling block  
-            targetbuilder = Builder(args_for_jump_gv)
+            targetbuilder = Builder(self.stackdepth, args_for_jump_gv)
             self.mc.CMP(gv_condition, Immediate32(value))
             self.mc.JNE(targetbuilder.mc.tell())
             return targetbuilder
@@ -257,6 +264,7 @@
             self.mc.MOV(IntVar(Register64("rax")), gv_returnvar)
         self.mc.RET()
         self._close()
+        assert self.stackdepth == 0
         
     #FIXME: uses 32bit displ  
     # if the label is greater than 32bit
@@ -320,26 +328,44 @@
         
     # TODO: alloc strategy
     # TODO: support 8bit reg. alloc
-    # just greddy
+    # just greddy spilling
     def spill_register(self):
         # take the first gv which is not
         # on the stack
         gv_to_spill = None
         for i in range(len(known_gv)):
-           if not known_gv[i].location_type == "Stack64":
+           if not isinstance(known_gv[i].location, Stack64):
                 gv_to_spill = self.known_gv[i]
                 break
         # there must be genVars which are 
         # inside an register so:
-        assert not gv_to_spill==None 
-        
-        #TODO: update Stackposition
+        assert isinstance(gv_to_spill.location, Register64) 
         
+        self.stackdepth = self.stackdepth +1 
         self.mc.PUSH(gv_to_spill)      
         new_gv = IntVar(Register64(gv_to_spill.location.reg))
-        gv_to_spill.location = Stack64(42) #XXX
+        gv_to_spill.location = Stack64(self.stackdepth) 
         return new_gv
-
+        
+    def move_back_to_register(a_spilled_gv):
+        # if top of stack
+        if a_spilled_gv.location.offset ==  self.stackdepth:
+            gv_new = self.allocate_register()
+            self.mc.POP(gv_new)
+            self.stackdepth = self.stackdepth -1
+            assert self.stackdepth >= 0 
+            #update all offsets
+            for i in range(len(known_gv)):
+               if isinstance(known_gv[i].location, Stack64):
+                    known_gv[i].location.offset = known_gv[i].location.offset -1
+            a_spilled_gv = gv_new
+            # TODO: free gv_new (no double values in known_gv
+        # else access the memory
+        # FIXME: if this genVar becomes the top of stack it will never be pushed
+        else:
+            pass
+            
+            
 
 class RX86_64GenOp(model.AbstractRGenOp):
     
@@ -365,7 +391,7 @@
         arg_tokens, res_token = sigtoken
         #print "arg_tokens:",arg_tokens
         inputargs_gv = []
-        builder = Builder()
+        builder = Builder(0) # stackdepth = 0
         # TODO: Builder._open()
         entrypoint = builder.mc.tell()
         # from http://www.x86-64.org/documentation/abi.pdf

Modified: pypy/branch/oo-jit/pypy/jit/codegen/x86_64/test/test_rgenop.py
==============================================================================
--- pypy/branch/oo-jit/pypy/jit/codegen/x86_64/test/test_rgenop.py	(original)
+++ pypy/branch/oo-jit/pypy/jit/codegen/x86_64/test/test_rgenop.py	Fri Oct 10 20:29:08 2008
@@ -2,6 +2,7 @@
 from pypy.rpython.lltypesystem import lltype
 from pypy.jit.codegen.x86_64.rgenop import RX86_64GenOp, Label
 from pypy.jit.codegen.test.rgenop_tests import AbstractRGenOpTestsDirect
+from pypy.jit.codegen.x86_64.objmodel import IntVar, Stack64
 #from pypy.jit.codegen.test.rgenop_tests import AbstractRGenOpTestsCompile
 
 # for the individual tests see
@@ -10,14 +11,32 @@
 def skip(self):
     py.test.skip("not implemented yet")
     
+# pushes/pos some values and than uses a mem access to access the stack
+def make_mem_func(rgenop):
+    sigtoken = rgenop.sigToken(lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed))
+    builder, gv_mem_func, [gv_x, gv_y] = rgenop.newgraph(sigtoken, "mem_op")
+    builder.start_writing()
+    builder.genop1("int_inc",  gv_y) 
+    builder.genop1("int_inc",  gv_y) 
+    builder.genop1("int_inc",  gv_y)  
+    builder.genop1("int_push", gv_y)
+    builder.genop1("int_inc",  gv_y)     
+    builder.genop1("int_push", gv_y)
+    builder.mc.MOV(gv_x, IntVar(Stack64(8))) # rsp+8(bytes) (stack position of the first push)
+    builder.genop1("int_pop",  gv_y)
+    builder.genop1("int_pop",  gv_y)
+    builder.finish_and_return(sigtoken, gv_x)
+    builder.end()
+    return gv_mem_func
+
 def make_push_pop(rgenop):
     sigtoken = rgenop.sigToken(lltype.FuncType([lltype.Signed], lltype.Signed))
     builder, gv_push_pop, [gv_x] = rgenop.newgraph(sigtoken, "push_pop")
     builder.start_writing()
-    gv_x = builder.genop1("int_push", gv_x)
-    gv_x = builder.genop1("int_inc",  gv_x)
-    gv_x = builder.genop1("int_inc",  gv_x)
-    gv_x = builder.genop1("int_pop",  gv_x)
+    builder.genop1("int_push", gv_x)
+    builder.genop1("int_inc",  gv_x)
+    builder.genop1("int_inc",  gv_x)
+    builder.genop1("int_pop",  gv_x)
     builder.finish_and_return(sigtoken, gv_x)
     builder.end()
     return gv_push_pop
@@ -442,6 +461,17 @@
         fnptr = self.cast(pp_func,1)
         result = fnptr(1)
         assert result == 1
+        result = fnptr(42)
+        assert result == 42
+        
+    # return 
+    def test_memory_access(self):
+        mem_func = make_mem_func(self.RGenOp())
+        fnptr = self.cast(mem_func,2)
+        result = fnptr(0,0)
+        assert result == 3
+        result = fnptr(-1,2)
+        assert result == 5
         
 #    def test_invert(self):
 #        inv_function = make_one_op_instr(self.RGenOp(),"int_invert")



More information about the Pypy-commit mailing list