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

witulski at codespeak.net witulski at codespeak.net
Sun Oct 12 16:26:36 CEST 2008


Author: witulski
Date: Sun Oct 12 16:26:33 2008
New Revision: 59034

Modified:
   pypy/branch/oo-jit/pypy/jit/codegen/x86_64/assembler.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:
spilling implemented.

- the args_gv of the label of enter_next_block are now copys (spilling could change refs)
- gv_temp is removed from known_gv in allocate_register to avoid double entrys in that list
- some comments added
- move_back_to_register access the memory if the spilled gv is not the top of stack
- allocate register uses spill_register when are no more free regs. left
- stackdepth calc fixed
- compares return refs of rax 


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	Sun Oct 12 16:26:33 2008
@@ -76,11 +76,11 @@
                     self.write(extra)
                 self.write_modRM_byte(mod, modrm2, modrm1)
             elif isinstance(arg2.location, Stack64):
-                self.write_rex_byte(rexW, rexR, rexX, rexB) 
+                self.write_rex_byte(rexW, rexB, rexX, rexR) 
                 self.write(opcode)
                 # exchanged mod1,mod2, dont know why :)
                 self.write_modRM_byte(mod, modrm1, modrm2)
-                # no scale, no index, base = rsp
+                # no scale(has no effect on rsp), no index, base = rsp
                 self.write_SIB(0, 4, 4) 
                 self.writeImm32(arg2.location.offset)  
     return quadreg_instr
@@ -206,7 +206,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")
+    _IMUL_QWREG_IMM32 = make_two_operand_instr(  1, None,    0, None, "\x69", 3, None, "sameReg")#3 op instr
     
     _NEG_QWREG       = make_one_operand_instr(   1,    0,    0, None, "\xF7", 3, None, 3)
     

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	Sun Oct 12 16:26:33 2008
@@ -103,16 +103,16 @@
     @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)
+            gv_arg = self.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)
+            gv_arg1 = self.move_back_to_register(gv_arg1)
         if isinstance(gv_arg2, model.GenVar) and isinstance(gv_arg2.location, Stack64):
-            move_back_to_register(gv_arg2)
+            gv_arg2 = self.move_back_to_register(gv_arg2)
         genmethod = getattr(self, 'op_' + opname)
         return genmethod(gv_arg1, gv_arg2)
  
@@ -191,39 +191,40 @@
         # TODO: use also rcx rdx
         gv_z = self.allocate_register("rax")
         self.mc.SETG(IntVar(Register8("al")))
-        return IntVar(Register64("rax"))
+        return gv_z
     
     def op_int_lt(self, gv_x, gv_y):
         self.mc.CMP(gv_x, gv_y)
         gv_z = self.allocate_register("rax")
         self.mc.SETL(IntVar(Register8("al")))
-        return IntVar(Register64("rax"))
+        return gv_z
     
     def op_int_le(self, gv_x, gv_y):
         self.mc.CMP(gv_x, gv_y)
         gv_z = self.allocate_register("rax")
         self.mc.SETLE(IntVar(Register8("al")))
-        return IntVar(Register64("rax"))
+        return gv_z
      
     def op_int_eq(self, gv_x, gv_y):
         self.mc.CMP(gv_x, gv_y)
         gv_z = self.allocate_register("rax")
         self.mc.SETE(IntVar(Register8("al")))
-        return IntVar(Register64("rax"))
+        return gv_z
     
     def op_int_ne(self, gv_x, gv_y):
         self.mc.CMP(gv_x, gv_y)
         gv_z = self.allocate_register("rax")
         self.mc.SETNE(IntVar(Register8("al")))
-        return IntVar(Register64("rax"))
+        return gv_z
     
     def op_int_ge(self, gv_x, gv_y):
         self.mc.CMP(gv_x, gv_y)
         gv_z = self.allocate_register("rax")
         self.mc.SETGE(IntVar(Register8("al")))
-        return IntVar(Register64("rax"))
+        return gv_z
     
     # the moves to pass arg. when making a jump to a block
+    # the targetvars are only copys
     #FIXME: problem with mapping of stackpositions
     def _compute_moves(self, outputargs_gv, targetargs_gv):
         tar2src = {}
@@ -260,8 +261,14 @@
     def finish_and_return(self, sigtoken, gv_returnvar):
         #self.mc.write("\xB8\x0F\x00\x00\x00")
         self._open()
+        gv_return = self.allocate_register("rax")
+        # if there unused genVars on the stack
+        # pop them away
+        while not self.stackdepth == 0:
+            self.mc.POP(gv_return)
+            self.stackdepth = self.stackdepth -1
         if not gv_returnvar == None:#check void return
-            self.mc.MOV(IntVar(Register64("rax")), gv_returnvar)
+            self.mc.MOV(gv_return, gv_returnvar)
         self.mc.RET()
         self._close()
         assert self.stackdepth == 0
@@ -281,29 +288,39 @@
         self.mc.JMP(target.startaddr)
         self._close()
         
+    # FIXME: returns only ints
+    # FIXME: Double values in known_gv??    
     # TODO: support the allocation of 8bit Reg
     def allocate_register(self, register=None):
         if register is None:
             if not self.freeregisters:
-                #raise NotImplementedError("spilling not implemented")
-                return self.spill_register()
+                new_gv = self.spill_register()
+                self.known_gv.append(new_gv)
+                return new_gv
+            
             new_gv = IntVar(Register64(self.freeregisters.popitem()[0]))
             self.known_gv.append(new_gv)
             return new_gv
+        
         else:
             if register not in self.freeregisters:
                 # the register must be in the list!
                 for i in range(len(self.known_gv)):
-                    if register == self.known_gv[i].location.reg:
-                        # move the values from the requiered register
-                        # to an other one and return the
-                        # requested one.
-                        gv = self.allocate_register()
-                        self.mc.MOV(gv,self.known_gv[i])
+                    if isinstance(self.known_gv[i].location, Register64) and register == self.known_gv[i].location.reg:
+                        # move the values from the requiered 
+                        # register to an other one and 
+                        # return the requested one.
+                        gv_temp = self.allocate_register()
+                        self.mc.MOV(gv_temp, self.known_gv[i])
                         new_gv = IntVar(Register64(register))
                         self.known_gv.append(new_gv)
+                        self.known_gv[i].location.reg = gv_temp.location.reg
+                        self.known_gv.remove(gv_temp)
                         return new_gv
-                raise NotImplementedError("register moves")           
+                    
+                # raised when the register is not in freereg. and not
+                # used by a gen_var 
+                raise Exception("error while register moves")           
             del self.freeregisters[register]
             new_gv = IntVar(Register64(register))
             self.known_gv.append(new_gv)
@@ -312,15 +329,22 @@
     def end(self):
         pass
     
-    #TODO: args_gv muste be a list of unique GenVars
+    # TODO: args_gv muste be a list of unique GenVars
+    # Spilling could change the location of a
+    # genVar after this Label. That will result in
+    # wrong a mapping in _compute_moves when leaving this block.
+    # So the parameters must be inmutable(copy them)
     def enter_next_block(self, args_gv):
         # move constants into an register
+        copy_args = []
         for i in range(len(args_gv)):
             if isinstance(args_gv[i],model.GenConst):
                 gv_x = self.allocate_register()
                 self.mc.MOV(gv_x, args_gv[i])
                 args_gv[i] = gv_x
-        L = Label(self.mc.tell(), args_gv, 0)
+            # copy the gv
+            copy_args.append(IntVar(Register64(args_gv[i].location.reg)))
+        L = Label(self.mc.tell(), copy_args, 0)
         return L
     
     def _close(self):
@@ -333,37 +357,44 @@
         # take the first gv which is not
         # on the stack
         gv_to_spill = None
-        for i in range(len(known_gv)):
-           if not isinstance(known_gv[i].location, Stack64):
+        for i in range(len(self.known_gv)):
+           if not isinstance(self.known_gv[i].location, Stack64):
                 gv_to_spill = self.known_gv[i]
                 break
         # there must be genVars which are 
         # inside an register so:
         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(self.stackdepth) 
+        gv_to_spill.location = Stack64(self.stackdepth)         
         return new_gv
         
-    def move_back_to_register(a_spilled_gv):
-        # if top of stack
+    # FIXME: pushed values are not allways poped (if not TOS)
+    def move_back_to_register(self, a_spilled_gv):
+        # if a_spilled_gv is the 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):
+            for i in range(len(self.known_gv)):
+               if isinstance(self.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
+            # TODO: free gv_new (no double values in known_gv)
+            # TODO: look if there is a genVar with stackdepth
+            #       if not it has already been moved to a reg. 
+            #       pop it or change the stackpointer
+            return a_spilled_gv
+        else:
         # else access the memory
         # FIXME: if this genVar becomes the top of stack it will never be pushed
-        else:
-            pass
+            gv_new = self.allocate_register()
+            self.mc.MOV(gv_new, IntVar(Stack64(8*(self.stackdepth-a_spilled_gv.location.offset))))
+            a_spilled_gv = gv_new 
+            return a_spilled_gv
             
             
 

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	Sun Oct 12 16:26:33 2008
@@ -126,6 +126,15 @@
     gv_result = builder.genop2(instr_name, gv_x, rgenop.genconst(num))
     builder.finish_and_return(sigtoken, gv_result)
     builder.end()
+    return gv_op_imm  
+      
+def make_one_op_imm_instr_args_inv(rgenop,  instr_name, num):
+    sigtoken = rgenop.sigToken(lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed))
+    builder, gv_op_imm, [gv_x, gv_y] = rgenop.newgraph(sigtoken, "one_op_imm_instr_args_inv")
+    builder.start_writing()
+    gv_result = builder.genop2(instr_name, rgenop.genconst(num), gv_x)
+    builder.finish_and_return(sigtoken, gv_result)
+    builder.end()
     return gv_op_imm        
 
 class TestRGenopDirect(AbstractRGenOpTestsDirect):
@@ -174,6 +183,14 @@
         mul_function = make_one_op_imm_instr(rgenop, "int_mul", -9876)
         fnptr = self.cast(mul_function,1)
         res = fnptr(12345)
+        assert res == -121919220   
+        mul_function =make_one_op_imm_instr_args_inv(rgenop, "int_mul", 200)
+        fnptr = self.cast(mul_function,1)
+        res = fnptr(210)
+        assert res == 42000
+        mul_function = make_one_op_imm_instr_args_inv(rgenop, "int_mul", -9876)
+        fnptr = self.cast(mul_function,1)
+        res = fnptr(12345)
         assert res == -121919220
         
     def test_idiv_imm32(self):
@@ -497,7 +514,7 @@
     test_calling_pause_direct = skip
     test_longwinded_and_direct = skip
     test_condition_result_cross_link_direct = skip
-    test_multiple_cmps = skip
+    ##test_multiple_cmps = skip##
     test_flipped_cmp_with_immediate = skip
     test_jump_to_block_with_many_vars = skip
     test_same_as = skip



More information about the Pypy-commit mailing list