[pypy-svn] r59106 - in pypy/branch/oo-jit/pypy/jit/codegen/x86_64: . test
witulski at codespeak.net
witulski at codespeak.net
Wed Oct 15 16:33:52 CEST 2008
Author: witulski
Date: Wed Oct 15 16:33:51 2008
New Revision: 59106
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:
Added spilling features
-Registers which contain GenConst are thrown away by spilling
-compares use the throw away method
-Added a new atribute in Register: throw away. The value inside is not
needed anymore, so dont spill it
FIXED some spilling bugs.
-IMUL Exception: the result is in the other operand, it wont be thrown away
-fixed the wrong calc of the stack in move_back_to_register
-fixed bug in move_to_registers:append the alocatet registers to the dont_alloc list
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 Wed Oct 15 16:33:51 2008
@@ -1,3 +1,4 @@
+from pypy.jit.codegen import model
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)
@@ -270,6 +271,10 @@
# exchange the two arguments because
# the result is in the first register
if(op1.to_string()=="_QWREG" and op2.to_string()=="_QWREG"):
+ # after this operation, op2 contains
+ # the genVar/result, dont throw is away
+ op1.location.contains_genConst = False
+ op1.location.dont_spill(False)
method(op2, op1)
else:
method(op1, op2)
@@ -305,6 +310,7 @@
method = getattr(self, "_PUSH"+op1.to_string())
method(op1)
+ # TODO: support Register8
def MOV(self, op1, op2):
method = getattr(self, "_MOV"+op1.to_string()+op2.to_string())
method(op1, op2)
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 Wed Oct 15 16:33:51 2008
@@ -12,10 +12,26 @@
class Register64(Location):
def __init__(self, reg):
self.reg = reg
+ self.throw_away = False
+ self.contains_genConst = False
+
+ def dont_spill(self, throw_away):
+ self.throw_away = throw_away # this value is not needed anymore
+
+ def contains_Const(self):
+ self.contains_genConst = True
class Register8(Location):
def __init__(self, reg):
self.reg = reg
+ self.throw_away = False
+ self.contains_genConst = False
+
+ def dont_spill(self, throw_away):
+ self.throw_away = throw_away # this value is not needed anymore
+
+ def contains_Const(self):
+ self.contains_genConst = True
class Stack64(Location):
def __init__(self, offset):
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 Wed Oct 15 16:33:51 2008
@@ -18,19 +18,24 @@
# to choose the right method in assembler.py
def make_two_argument_method(name):
def op_int(self, gv_x, gv_y):
- gv_z = self.allocate_register()
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y])
+ dont_alloc = []
+ if not isinstance(gv_x, model.GenConst):
+ dont_alloc.append(gv_x.location.reg)
+ if not isinstance(gv_y, model.GenConst):
+ dont_alloc.append(gv_y.location.reg)
+ gv_z = self.allocate_register(None, dont_alloc)
self.mc.MOV(gv_z, gv_x)
method = getattr(self.mc, name)
# Many operations don't support
# 64 Bit Immmediates directly
if isinstance(gv_y,Immediate64):
- gv_w = self.allocate_register()
+ dont_alloc.append(gv_z.location.reg)
+ gv_w = self.allocate_register(None, dont_alloc)
self.mc.MOV(gv_w, gv_y)
- [gv_z, gv_w] = self.move_to_registers([gv_z, gv_w])
method(gv_z, gv_w)
else:
- [gv_z, gv_y] = self.move_to_registers([gv_z, gv_y])
method(gv_z, gv_y)
return gv_z
return op_int
@@ -106,39 +111,38 @@
pass
@specialize.arg(1)
- def genop1(self, opname, gv_arg):
- [gv_arg] = self.move_to_registers([gv_arg])
+ def genop1(self, opname, gv_arg):
genmethod = getattr(self, 'op_' + opname)
return genmethod(gv_arg)
- # TODO: check at the right point: always after the last allocton!
@specialize.arg(1)
- def genop2(self, opname, gv_arg1, gv_arg2):
- [gv_arg1, gv_arg2] = self.move_to_registers([gv_arg1, gv_arg2])
+ def genop2(self, opname, gv_arg1, gv_arg2):
genmethod = getattr(self, 'op_' + opname)
return genmethod(gv_arg1, gv_arg2)
- op_int_add = make_two_argument_method("ADD") #TODO: use inc
+ 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
+ op_int_dec = make_one_argument_method("DEC") # for debuging
+ op_int_inc = make_one_argument_method("INC") # for debuging
op_int_mul = make_two_argument_method("IMUL")
op_int_neg = make_one_argument_method("NEG")
- op_int_not = make_one_argument_method("NOT") #for debuging
+ op_int_not = make_one_argument_method("NOT") # for debuging
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") # TODO: use DEC
+ 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") # TODO: use DEC
op_int_xor = make_two_argument_method("XOR")
# TODO: support reg8
def op_cast_bool_to_int(self, gv_x):
+ [gv_x] = self.move_to_registers([gv_x])
assert isinstance(gv_x, IntVar) and isinstance(gv_x.location,Register64)
return gv_x
# 0 xor 1 == 1
# 1 xor 1 == 0
def op_bool_not(self, gv_x):
+ [gv_x] = self.move_to_registers([gv_x])
self.mc.XOR(gv_x, Immediate32(1))
return gv_x
@@ -146,6 +150,7 @@
# FIXME: uses rcx insted of cl
def op_int_lshift(self, gv_x, gv_y):
gv_z = self.allocate_register("rcx")
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], ["rcx"])
self.mc.MOV(gv_z, gv_y)
self.mc.SHL(gv_x)
return gv_x
@@ -153,6 +158,7 @@
# FIXME: uses rcx insted of cl
def op_int_rshift(self, gv_x, gv_y):
gv_z = self.allocate_register("rcx")
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], ["rcx"])
self.mc.MOV(gv_z, gv_y)
self.mc.SHR(gv_x)
return gv_x
@@ -164,34 +170,33 @@
for i in range(len(registers)):
if isinstance(registers[i], model.GenVar) and isinstance(registers[i].location, Stack64):
registers[i] = self.move_back_to_register(registers[i], dont_alloc)
+ dont_alloc.append(registers[i].location.reg)
# some operations dont suppoert immediateoperands
if move_imm_too and isinstance(registers[i], Immediate32):
gv_new = self.allocate_register(None, dont_alloc)
self.mc.MOV(gv_new, registers[i])
registers[i] = gv_new
+ dont_alloc.append(registers[i].location.reg)
+ registers[i].location.contains_Const()
return registers
# IDIV RDX:RAX with QWREG
# supports only RAX (64bit) with QWREG
def op_int_floordiv(self, gv_x, gv_y):
gv_z = self.allocate_register("rax")
- gv_w = self.allocate_register("rdx",["rax"])
+ gv_w = self.allocate_register("rdx")
[gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], ["rax", "rdx"], move_imm_too=True)
self.mc.MOV(gv_z, gv_x)
self.mc.CDQ() #sign extention of rdx:rax
- if isinstance(gv_y, Immediate32): #support imm32
- gv_u = self.allocate_register()
- self.mc.MOV(gv_u,gv_y)
- self.mc.IDIV(gv_u)
- else:
- self.mc.IDIV(gv_y)
+ self.mc.IDIV(gv_y)
return gv_z
# IDIV RDX:RAX with QWREG
# FIXME: supports only RAX with QWREG
def op_int_mod(self, gv_x, gv_y):
gv_z = self.allocate_register("rax")
- gv_w = self.allocate_register("rdx",["rax"])
+ gv_w = self.allocate_register("rdx")
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], ["rax", "rdx"], move_imm_too=True)
self.mc.MOV(gv_z, gv_x)
self.mc.XOR(gv_w, gv_w)
self.mc.IDIV(gv_y)
@@ -200,72 +205,60 @@
# def op_int_invert(self, gv_x):
# return self.mc.NOT(gv_x)
+ def throw_away_if_const(self, registers):
+ for i in range(len(registers)):
+ if registers[i].location.contains_genConst:
+ registers[i].location.dont_spill(True)
+ return registers
+
+ # You can not use every register for
+ # 8 bit operations, so you have to
+ # choose rax,rcx or rdx
+ # TODO: use also rcx rdx
def op_int_gt(self, gv_x, gv_y):
- if gv_x.to_string() == "_IMM32":
- gv_w = self.allocate_register(None, ["rax"])
- self.mc.MOV(gv_w, gv_x)
- self.mc.CMP(gv_w, gv_y)
- else:
- self.mc.CMP(gv_x, gv_y)
- # You can not use every register for
- # 8 bit operations, so you have to
- # choose rax,rcx or rdx
- # TODO: use also rcx rdx
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], None, move_imm_too=True)
+ self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.throw_away_if_const([gv_x,gv_y])
gv_z = self.allocate_register("rax")
self.mc.SETG(IntVar(Register8("al")))
return gv_z
def op_int_lt(self, gv_x, gv_y):
- if gv_x.to_string() == "_IMM32":
- gv_w = self.allocate_register(None, ["rax"])
- self.mc.MOV(gv_w, gv_x)
- self.mc.CMP(gv_w, gv_y)
- else:
- self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], None, move_imm_too=True)
+ self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.throw_away_if_const([gv_x,gv_y])
gv_z = self.allocate_register("rax")
self.mc.SETL(IntVar(Register8("al")))
return gv_z
def op_int_le(self, gv_x, gv_y):
- if gv_x.to_string() == "_IMM32":
- gv_w = self.allocate_register(None, ["rax"])
- self.mc.MOV(gv_w, gv_x)
- self.mc.CMP(gv_w, gv_y)
- else:
- self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], None, move_imm_too=True)
+ self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.throw_away_if_const([gv_x,gv_y])
gv_z = self.allocate_register("rax")
self.mc.SETLE(IntVar(Register8("al")))
return gv_z
def op_int_eq(self, gv_x, gv_y):
- if gv_x.to_string() == "_IMM32":
- gv_w = self.allocate_register(None, ["rax"])
- self.mc.MOV(gv_w, gv_x)
- self.mc.CMP(gv_w, gv_y)
- else:
- self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], None, move_imm_too=True)
+ self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.throw_away_if_const([gv_x,gv_y])
gv_z = self.allocate_register("rax")
self.mc.SETE(IntVar(Register8("al")))
return gv_z
def op_int_ne(self, gv_x, gv_y):
- if gv_x.to_string() == "_IMM32":
- gv_w = self.allocate_register(None, ["rax"])
- self.mc.MOV(gv_w, gv_x)
- self.mc.CMP(gv_w, gv_y)
- else:
- self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], None, move_imm_too=True)
+ self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.throw_away_if_const([gv_x,gv_y])
gv_z = self.allocate_register("rax")
self.mc.SETNE(IntVar(Register8("al")))
return gv_z
def op_int_ge(self, gv_x, gv_y):
- if gv_x.to_string() == "_IMM32":
- gv_w = self.allocate_register(None, ["rax"])
- self.mc.MOV(gv_w, gv_x)
- self.mc.CMP(gv_w, gv_y)
- else:
- self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.move_to_registers([gv_x, gv_y], None, move_imm_too=True)
+ self.mc.CMP(gv_x, gv_y)
+ [gv_x, gv_y] = self.throw_away_if_const([gv_x,gv_y])
gv_z = self.allocate_register("rax")
self.mc.SETGE(IntVar(Register8("al")))
return gv_z
@@ -305,6 +298,7 @@
jump_if_false = _new_jump("jump_if_false", 1)
jump_if_true = _new_jump('jump_if_true', 0)
+ # TODO: move stackpointer
def finish_and_return(self, sigtoken, gv_returnvar):
#self.mc.write("\xB8\x0F\x00\x00\x00")
self._open()
@@ -314,13 +308,14 @@
while not self.stackdepth == 0:
self.mc.POP(gv_return)
self.stackdepth = self.stackdepth -1
- if not gv_returnvar == None:#check void return
+ if not gv_returnvar == None:#check void return
self.mc.MOV(gv_return, gv_returnvar)
self.mc.RET()
self._close()
assert self.stackdepth == 0
- #FIXME: uses 32bit displ
+ # FIXME: uses 32bit displ
+ # TODO: return also stackdepth or pop!
# if the label is greater than 32bit
# it must be in a register (not supported)
def finish_and_goto(self, outputargs_gv, target):
@@ -337,6 +332,7 @@
# FIXME: returns only IntVars
# TODO: support the allocation of 8bit Reg
+ # TODO: (Optimization)Don't remember genVars which contain konstants
def allocate_register(self, register=None, dontalloc = None):
if dontalloc is None:
dontalloc = []
@@ -349,7 +345,7 @@
reg = None
seen_reg = 0
while not leave:
- # no or only "dontalloc" regs. are left
+ # none or only "dontalloc" regs. are left
if not self.freeregisters or seen_reg == len(self.freeregisters):
new_gv = self.spill_register(dontalloc)
self.known_gv.append(new_gv)
@@ -400,8 +396,8 @@
# 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.
+ # genVar after this Label. That will result in a
+ # wrong 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
@@ -437,27 +433,28 @@
# inside an register so:
if gv_to_spill == None:
raise WrongArgException("to many dont_spill/dont_alloc registers")
- 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)
- return new_gv
+ assert isinstance(gv_to_spill.location, Register64)
+ # if the register contains a genCons
+ # it has not to be saved
+ if gv_to_spill.location.throw_away:
+ return gv_to_spill
+ else:
+ 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)
+ return new_gv
# FIXME: pushed values are not allways poped (if not TOS)
def move_back_to_register(self, a_spilled_gv, dont_alloc):
# if a_spilled_gv is the top of stack
+ gv_new = self.allocate_register(None, dont_alloc)
if a_spilled_gv.location.offset == self.stackdepth:
- gv_new = self.allocate_register(None, dont_alloc)
self.mc.POP(gv_new)
self.stackdepth = self.stackdepth -1
assert self.stackdepth >= 0
- #update all offsets
- for i in range(len(self.known_gv)):
- if isinstance(self.known_gv[i].location, Stack64):
- self.known_gv[i].location.offset = self.known_gv[i].location.offset -1
- a_spilled_gv = gv_new
- # TODO: free gv_new (no double values in known_gv)
+ a_spilled_gv.location = Register64(gv_new.location.reg)
+ self.known_gv.remove(gv_new)
# 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
@@ -465,9 +462,11 @@
else:
# else access the memory
# FIXME: if this genVar becomes the top of stack it will never be pushed
- gv_new = self.allocate_register(None, dont_alloc)
- self.mc.MOV(gv_new, IntVar(Stack64(8*(self.stackdepth-a_spilled_gv.location.offset))))
- a_spilled_gv = gv_new
+ self.mc.MOV(gv_new, IntVar(Stack64(8*(self.stackdepth-a_spilled_gv.location.offset))))#8=scale
+ #print "debug:",self.stackdepth
+ #print a_spilled_gv.location.offset
+ a_spilled_gv.location = Register64(gv_new.location.reg)
+ self.known_gv.remove(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 Wed Oct 15 16:33:51 2008
@@ -105,13 +105,16 @@
builder.end()
return gv_bool_op
-def make_cmp(rgenop, which_cmp, const=None):
+def make_cmp(rgenop, which_cmp, const=None, switch_arg = False):
sigtoken = rgenop.sigToken(lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed))
builder, gv_cmp, [gv_x, gv_y] = rgenop.newgraph(sigtoken, "cmp")
builder.start_writing()
if not const == None:
- gv_result = builder.genop2(which_cmp, gv_x, rgenop.genconst(const))
+ if switch_arg:
+ gv_result = builder.genop2(which_cmp, rgenop.genconst(const), gv_x)
+ else:
+ gv_result = builder.genop2(which_cmp, gv_x, rgenop.genconst(const))
else:
gv_result = builder.genop2(which_cmp, gv_x, gv_y)
@@ -286,6 +289,22 @@
assert res == 0
res = fnptr(-4,0)
assert res == 1
+ cmp_function = make_cmp(self.RGenOp(), "int_lt", 4)
+ fnptr = self.cast(cmp_function,1)
+ res = fnptr(3) # 3<4
+ assert res == 1
+ res = fnptr(4) # 4<4
+ assert res == 0 # False
+ cmp_function = make_cmp(self.RGenOp(), "int_lt", 3, switch_arg=True)
+ fnptr = self.cast(cmp_function,1)
+ res = fnptr(4) # 3<4
+ assert res == 1
+ res = fnptr(3) # 3<3
+ assert res == 0 # False
+ cmp_function = make_cmp(self.RGenOp(), "int_lt", 1, switch_arg=True)
+ fnptr = self.cast(cmp_function,1)
+ res = fnptr(0) # 1<0
+ assert res == 0
def test_less_or_equal(self):
cmp_function = make_cmp(self.RGenOp(), "int_le")
More information about the Pypy-commit
mailing list