[pypy-svn] r36657 - pypy/branch/i386-regalloc/pypy/jit/codegen/i386
arigo at codespeak.net
arigo at codespeak.net
Sat Jan 13 15:00:01 CET 2007
Author: arigo
Date: Sat Jan 13 14:59:59 2007
New Revision: 36657
Modified:
pypy/branch/i386-regalloc/pypy/jit/codegen/i386/rgenop.py
Log:
Fix condition code handling over links. More tests pass.
Modified: pypy/branch/i386-regalloc/pypy/jit/codegen/i386/rgenop.py
==============================================================================
--- pypy/branch/i386-regalloc/pypy/jit/codegen/i386/rgenop.py (original)
+++ pypy/branch/i386-regalloc/pypy/jit/codegen/i386/rgenop.py Sat Jan 13 14:59:59 2007
@@ -1,4 +1,4 @@
-from pypy.rlib.objectmodel import specialize
+from pypy.rlib.objectmodel import specialize, we_are_translated
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.jit.codegen.model import AbstractRGenOp, GenLabel, GenBuilder
from pypy.jit.codegen.model import GenVar, GenConst, CodeGenSwitch
@@ -32,13 +32,19 @@
self.x = x
def allocate(self, allocator):
allocator.using(self.x)
-## def generate(self, allocator):
-## try:
-## loc = allocator.var2loc[self]
-## except KeyError:
-## return # simple operation whose result is not used anyway
-## op = allocator.load_location_with(loc, self.x)
-## self.emit(allocator.mc, op)
+
+class UnaryOp(Op1):
+ def generate(self, allocator):
+ try:
+ loc = allocator.var2loc[self]
+ except KeyError:
+ return # simple operation whose result is not used anyway
+ op = allocator.load_location_with(loc, self.x)
+ self.emit(allocator.mc, op)
+
+class OpIntNeg(UnaryOp):
+ opname = 'int_neg'
+ emit = staticmethod(I386CodeBuilder.NEG)
class OpSameAs(Op1):
clobbers_cc = False
@@ -65,19 +71,21 @@
class OpIntIsTrue(OpCompare1):
opname = 'int_is_true'
- cc_result = I386CodeBuilder.JNE
+ cc_result = Conditions['NE']
@staticmethod
def emit(mc, x):
mc.CMP(x, imm8(0))
class Op2(Operation):
- commutative = False
def __init__(self, x, y):
self.x = x
self.y = y
def allocate(self, allocator):
allocator.using(self.x)
allocator.using(self.y)
+
+class BinaryOp(Op2):
+ commutative = False
def generate(self, allocator):
try:
dstop = allocator.get_operand(self)
@@ -126,19 +134,41 @@
self.emit(mc, ecx, op2)
mc.MOV(dstop, ecx)
-class OpIntAdd(Op2):
+class OpIntAdd(BinaryOp):
opname = 'int_add'
emit = staticmethod(I386CodeBuilder.ADD)
commutative = True
-class OpIntSub(Op2):
+class OpIntSub(BinaryOp):
opname = 'int_sub'
emit = staticmethod(I386CodeBuilder.SUB)
class OpIntMul(Op2):
opname = 'int_mul'
- emit = staticmethod(I386CodeBuilder.IMUL)
- commutative = True
+ def generate(self, allocator):
+ try:
+ dstop = allocator.get_operand(self)
+ except KeyError:
+ return # simple operation whose result is not used anyway
+ op1 = allocator.get_operand(self.x)
+ op2 = allocator.get_operand(self.y)
+ mc = allocator.mc
+ if isinstance(dstop, REG):
+ tmpop = dstop
+ else:
+ tmpop = ecx
+ if tmpop == op1:
+ mc.IMUL(tmpop, op2)
+ elif isinstance(op2, IMM32):
+ mc.IMUL(tmpop, op1, op2)
+ elif isinstance(op1, IMM32):
+ mc.IMUL(tmpop, op2, op1)
+ else:
+ if tmpop != op2:
+ mc.MOV(tmpop, op2)
+ mc.IMUL(tmpop, op1)
+ if dstop != tmpop:
+ mc.MOV(dstop, tmpop)
class OpIntFloorDiv(Op2):
opname = 'int_floordiv'
@@ -187,20 +217,41 @@
mc.MOV(ecx, srcop)
mc.CMP(ecx, dstop)
+class OpIntLt(OpCompare2):
+ opname = 'int_lt'
+ cc_result = Conditions['L']
+
+class OpIntLe(OpCompare2):
+ opname = 'int_le'
+ cc_result = Conditions['LE']
+
+class OpIntEq(OpCompare2):
+ opname = 'int_eq'
+ cc_result = Conditions['E']
+
+class OpIntNe(OpCompare2):
+ opname = 'int_ne'
+ cc_result = Conditions['NE']
+
class OpIntGt(OpCompare2):
opname = 'int_gt'
cc_result = Conditions['G']
+class OpIntGe(OpCompare2):
+ opname = 'int_ge'
+ cc_result = Conditions['GE']
+
class JumpIf(Operation):
clobbers_cc = False
result_kind = RK_NO_RESULT
def __init__(self, gv_condition, targetbuilder, negate):
- assert 0 <= gv_condition.cc_result < INSN_JMP
self.gv_condition = gv_condition
self.targetbuilder = targetbuilder
self.negate = negate
def allocate(self, allocator):
allocator.using_cc(self.gv_condition)
+ for gv in self.targetbuilder.inputargs_gv:
+ allocator.using(gv)
def generate(self, allocator):
cc = self.gv_condition.cc_result
if self.negate:
@@ -307,13 +358,15 @@
del setup_opclasses
def setup_conditions():
- result = [None] * 16
+ result1 = [None] * 16
+ result2 = [None] * 16
for key, value in Conditions.items():
- result[value] = getattr(I386CodeBuilder, 'J'+key)
- return result
-EMIT_CONDITION = setup_conditions()
-INSN_JMP = len(EMIT_CONDITION)
-EMIT_CONDITION.append(I386CodeBuilder.JMP)
+ result1[value] = getattr(I386CodeBuilder, 'J'+key)
+ result2[value] = getattr(I386CodeBuilder, 'SET'+key)
+ return result1, result2
+EMIT_JCOND, EMIT_SETCOND = setup_conditions()
+INSN_JMP = len(EMIT_JCOND)
+EMIT_JCOND.append(I386CodeBuilder.JMP) # not really a conditional jump
del setup_conditions
def cond_negate(cond):
@@ -387,17 +440,21 @@
# common case: v is a compare operation whose result is precisely
# what we need to be in the CC
self.need_var_in_cc = None
+ self.creating(v)
def save_cc(self):
# we need a value to be in the CC, but we see a clobbering
# operation, so we copy the original CC-creating operation down
# past the clobbering operation
v = self.need_var_in_cc
+ if not we_are_translated():
+ assert v in self.operations[:self.operationindex]
self.operations.insert(self.operationindex, v)
self.need_var_in_cc = None
def using_cc(self, v):
- assert not v.is_const
+ assert isinstance(v, Operation)
+ assert 0 <= v.cc_result < INSN_JMP
if self.need_var_in_cc is not None:
self.save_cc()
self.need_var_in_cc = v
@@ -426,26 +483,32 @@
force_operand2loc = self.force_operand2loc
for i in range(len(force_vars)):
v = force_vars[i]
+ operand = force_operands[i]
try:
loc = self.var2loc[v]
except KeyError:
- pass
+ if at_start:
+ raise NotImplementedError
+ else:
+ self.add_final_move(v, operand)
else:
- operand = force_operands[i]
if loc in force_loc2operand or operand in force_operand2loc:
if at_start:
self.initial_moves.append((loc, operand))
else:
- v2 = OpSameAs(v)
- self.operations.append(v2)
- loc = self.nextloc
- self.nextloc += 1
- self.var2loc[v2] = loc
- force_loc2operand[loc] = operand
+ self.add_final_move(v, operand)
else:
force_loc2operand[loc] = operand
force_operand2loc[operand] = loc
+ def add_final_move(self, v, targetoperand):
+ v2 = OpSameAs(v)
+ self.operations.append(v2)
+ loc = self.nextloc
+ self.nextloc += 1
+ self.var2loc[v2] = loc
+ self.force_loc2operand[loc] = targetoperand
+
def allocate_registers(self):
# assign registers to locations that don't have one already
force_loc2operand = self.force_loc2operand
@@ -513,6 +576,23 @@
if self.operands[loc] != srcoperand:
self.mc.POP(self.operands[loc])
+ def generate_operations(self):
+ for v in self.operations:
+ v.generate(self)
+ cc = v.cc_result
+ if cc >= 0 and v in self.var2loc:
+ # force a comparison instruction's result into a
+ # regular location
+ dstop = self.get_operand(v)
+ mc = self.mc
+ insn = EMIT_SETCOND[cc]
+ insn(mc, cl)
+ try:
+ mc.MOVZX(dstop, cl)
+ except FailedToImplement:
+ mc.MOVZX(ecx, cl)
+ mc.MOV(dstop, ecx)
+
class Builder(GenBuilder):
coming_from = 0
@@ -538,8 +618,7 @@
mc = self.start_mc()
allocator.mc = mc
allocator.generate_initial_moves()
- for op in self.operations:
- op.generate(allocator)
+ allocator.generate_operations()
self.operations = None
self.inputargs_gv = [GenVar() for v in final_vars_gv]
self.inputoperands = [allocator.get_operand(v) for v in final_vars_gv]
@@ -564,7 +643,7 @@
def set_coming_from(self, mc, insncond=INSN_JMP):
self.coming_from_cond = insncond
self.coming_from = mc.tell()
- insnemit = EMIT_CONDITION[insncond]
+ insnemit = EMIT_JCOND[insncond]
insnemit(mc, rel32(0))
def start_mc(self):
@@ -575,27 +654,28 @@
targetaddr = mc.tell()
end = start + 6 # XXX hard-coded, enough for JMP and Jcond
oldmc = self.rgenop.InMemoryCodeBuilder(start, end)
- insn = EMIT_CONDITION[self.coming_from_cond]
+ insn = EMIT_JCOND[self.coming_from_cond]
insn(oldmc, rel32(targetaddr))
oldmc.done()
self.coming_from = 0
return mc
- def jump_if_false(self, gv_condition, args_for_jump_gv):
+ def _jump_if(self, gv_condition, args_for_jump_gv, negate):
newbuilder = Builder(self.rgenop, list(args_for_jump_gv), None)
- if gv_condition.cc_result < 0:
+ # if the condition does not come from an obvious comparison operation,
+ # e.g. a getfield of a Bool or an input argument to the current block,
+ # then insert an OpIntIsTrue
+ if gv_condition.cc_result < 0 or gv_condition not in self.operations:
gv_condition = OpIntIsTrue(gv_condition)
self.operations.append(gv_condition)
- self.operations.append(JumpIf(gv_condition, newbuilder, negate=True))
+ self.operations.append(JumpIf(gv_condition, newbuilder, negate=negate))
return newbuilder
+ def jump_if_false(self, gv_condition, args_for_jump_gv):
+ return self._jump_if(gv_condition, args_for_jump_gv, True)
+
def jump_if_true(self, gv_condition, args_for_jump_gv):
- newbuilder = Builder(self.rgenop, list(args_for_jump_gv), None)
- if gv_condition.cc_result < 0:
- gv_condition = OpIntIsTrue(gv_condition)
- self.operations.append(gv_condition)
- self.operations.append(JumpIf(gv_condition, newbuilder, negate=False))
- return newbuilder
+ return self._jump_if(gv_condition, args_for_jump_gv, False)
def finish_and_goto(self, outputargs_gv, targetlbl):
operands = targetlbl.inputoperands
More information about the Pypy-commit
mailing list