[pypy-commit] pypy s390x-backend: adding resoperations to regalloc/assembler (label, int_(lt, eq, ...), guards)

plan_rich noreply at buildbot.pypy.org
Wed Oct 28 07:02:25 EDT 2015


Author: Richard Plangger <planrichi at gmail.com>
Branch: s390x-backend
Changeset: r80471:3a2cb683d03e
Date: 2015-10-28 10:11 +0100
http://bitbucket.org/pypy/pypy/changeset/3a2cb683d03e/

Log:	adding resoperations to regalloc/assembler (label,int_(lt,eq,...),
	guards)

diff --git a/rpython/jit/backend/zarch/assembler.py b/rpython/jit/backend/zarch/assembler.py
--- a/rpython/jit/backend/zarch/assembler.py
+++ b/rpython/jit/backend/zarch/assembler.py
@@ -11,7 +11,7 @@
         STD_FRAME_SIZE_IN_BYTES, GPR_STACK_SAVE_IN_BYTES,
         THREADLOCAL_ADDR_OFFSET)
 from rpython.jit.backend.zarch.opassembler import (IntOpAssembler,
-    FloatOpAssembler)
+    FloatOpAssembler, GuardOpAssembler)
 from rpython.jit.backend.zarch.regalloc import Regalloc
 from rpython.jit.metainterp.resoperation import rop
 from rpython.rlib.debug import (debug_print, debug_start, debug_stop,
@@ -105,7 +105,8 @@
         self.places = []
 
 class AssemblerZARCH(BaseAssembler,
-        IntOpAssembler, FloatOpAssembler):
+        IntOpAssembler, FloatOpAssembler,
+        GuardOpAssembler):
 
     def __init__(self, cpu, translate_support_code=False):
         BaseAssembler.__init__(self, cpu, translate_support_code)
@@ -145,6 +146,9 @@
         self.mc = None
         self.pending_guards = None
 
+    def target_arglocs(self, looptoken):
+        return looptoken._zarch_arglocs
+
     def get_asmmemmgr_blocks(self, looptoken):
         clt = looptoken.compiled_loop_token
         if clt.asmmemmgr_blocks is None:
@@ -333,7 +337,7 @@
         if prev_loc.is_imm():
             value = prev_loc.getint()
             # move immediate value to register
-            if loc.is_core_reg():
+            if loc.is_reg():
                 self.mc.load_imm(loc, value)
                 return
             # move immediate value to memory
@@ -347,7 +351,7 @@
         elif prev_loc.is_stack():
             offset = prev_loc.value
             # move from memory to register
-            if loc.is_core_reg():
+            if loc.is_reg():
                 self.mc.load(loc, r.SPP, offset)
                 return
             # move in memory
@@ -363,17 +367,15 @@
                 self.mc.LDY(loc, l.addr(offset, r.SPP))
                 return
             assert 0, "not supported location"
-        elif prev_loc.is_core_reg():
-            reg = prev_loc.value
+        elif prev_loc.is_reg():
             # move to another register
-            if loc.is_core_reg():
-                other_reg = loc.value
-                self.mc.mr(other_reg, reg)
+            if loc.is_reg():
+                self.mc.LGR(loc, prev_loc)
                 return
             # move to memory
             elif loc.is_stack():
                 offset = loc.value
-                self.mc.store(reg, r.SPP, offset)
+                self.mc.store(prev_loc, r.SPP, offset)
                 return
             assert 0, "not supported location"
         elif prev_loc.is_imm_float():
@@ -517,6 +519,9 @@
     def emit_increment_debug_counter(self, op, arglocs, regalloc):
         pass # TODO
 
+    def emit_label(self, op, arglocs, regalloc):
+        pass
+
     def emit_finish(self, op, arglocs, regalloc):
         base_ofs = self.cpu.get_baseofs_of_frame_field()
         if len(arglocs) > 1:
diff --git a/rpython/jit/backend/zarch/codebuilder.py b/rpython/jit/backend/zarch/codebuilder.py
--- a/rpython/jit/backend/zarch/codebuilder.py
+++ b/rpython/jit/backend/zarch/codebuilder.py
@@ -1,8 +1,9 @@
-from rpython.jit.backend.zarch import conditions as cond
-from rpython.jit.backend.zarch import registers as reg
-from rpython.jit.backend.zarch import locations as loc
+from rpython.jit.backend.zarch import conditions as c
+from rpython.jit.backend.zarch import registers as r
+from rpython.jit.backend.zarch import locations as l
 from rpython.jit.backend.zarch.instruction_builder import build_instr_codes
 from rpython.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin
+from rpython.jit.backend.llsupport.assembler import GuardToken
 from rpython.rlib.objectmodel import we_are_translated
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
@@ -19,15 +20,19 @@
 def binary_helper_call(name):
     function = getattr(support, 'arm_%s' % name)
 
-    def f(self, c=cond.AL):
+    def f(self, c=c.AL):
         """Generates a call to a helper function, takes its
         arguments in r0 and r1, result is placed in r0"""
         addr = rffi.cast(lltype.Signed, function)
         self.BL(addr, c)
     return f
 
-class Operand(object):
-    pass
+class ZARCHGuardToken(GuardToken):
+    def __init__(self, cpu, gcmap, descr, failargs, faillocs,
+                 guard_opnum, frame_depth, fcond=c.cond_none):
+        GuardToken.__init__(self, cpu, gcmap, descr, failargs, faillocs,
+                            guard_opnum, frame_depth)
+        self.fcond = fcond
 
 class AbstractZARCHBuilder(object):
     def write_i32(self, word):
@@ -85,11 +90,32 @@
         self._dump(addr, "jit-backend-dump", "s390x")
 
     def load(self, treg, sreg, offset):
-        self.LG(treg, loc.addr(offset, sreg))
+        self.LG(treg, l.addr(offset, sreg))
 
     def currpos(self):
         return self.get_relative_pos()
 
+    def cmp_op(self, a, b, pool=False, signed=True, fp=False):
+        if fp == True:
+            xxx
+            self.fcmpu(a, b)
+        else:
+            if signed:
+                if pool:
+                    # 64 bit immediate signed
+                    self.CLG(a, b)
+                else:
+                    # 64 bit signed
+                    self.CLGR(a, b)
+            else:
+                if pool:
+                    # 64 bit immediate unsigned
+                    self.CG(a, b)
+                else:
+                    # 64 bit unsigned
+                    self.CGR(a, b)
+
+
 _classes = (AbstractZARCHBuilder,)
 
 # Used to build the MachineCodeBlockWrapper
diff --git a/rpython/jit/backend/zarch/conditions.py b/rpython/jit/backend/zarch/conditions.py
--- a/rpython/jit/backend/zarch/conditions.py
+++ b/rpython/jit/backend/zarch/conditions.py
@@ -6,6 +6,10 @@
 GT = loc.imm(0x2)
 LE = loc.imm(EQ.value | LT.value)
 GE = loc.imm(EQ.value | GT.value)
+NE = loc.imm(LT.value | GT.value)
 OVERFLOW = loc.imm(0x1)
 
 cond_none = loc.imm(0x0)
+
+def negate(cond):
+    return cond
diff --git a/rpython/jit/backend/zarch/helper/assembler.py b/rpython/jit/backend/zarch/helper/assembler.py
--- a/rpython/jit/backend/zarch/helper/assembler.py
+++ b/rpython/jit/backend/zarch/helper/assembler.py
@@ -0,0 +1,69 @@
+import rpython.jit.backend.zarch.conditions as c
+import rpython.jit.backend.zarch.registers as r
+from rpython.rlib.rarithmetic import intmask
+from rpython.jit.backend.zarch.arch import WORD
+from rpython.jit.metainterp.history import FLOAT
+from rpython.jit.metainterp.resoperation import rop
+from rpython.rtyper.lltypesystem import rffi, lltype
+
+def flush_cc(asm, condition, result_loc):
+    # After emitting an instruction that leaves a boolean result in
+    # a condition code (cc), call this.  In the common case, result_loc
+    # will be set to SPP by the regalloc, which in this case means
+    # "propagate it between this operation and the next guard by keeping
+    # it in the cc".  In the uncommon case, result_loc is another
+    # register, and we emit a load from the cc into this register.
+    assert asm.guard_success_cc == c.cond_none
+    if result_loc is r.SPP:
+        asm.guard_success_cc = condition
+    else:
+        # Possibly invert the bit in the CR
+        bit, invert = c.encoding[condition]
+        assert 0 <= bit <= 3
+        if invert == 12:
+            pass
+        elif invert == 4:
+            asm.mc.crnor(bit, bit, bit)
+        else:
+            assert 0
+
+        resval = result_loc.value
+        # move the content of the CR to resval
+        asm.mc.mfcr(resval)
+        # zero out everything except of the result
+        asm.mc.rlwinm(resval, resval, 1 + bit, 31, 31)
+
+
+def do_emit_cmp_op(self, arglocs, condition, signed, fp):
+    l0 = arglocs[0]
+    l1 = arglocs[1]
+    assert not l0.is_imm()
+    # do the comparison
+    self.mc.cmp_op(l0, l1, pool=l1.is_in_pool(), signed=signed, fp=fp)
+
+    # CR bits:
+    #     0: LT
+    #     1: GT
+    #     2: EQ
+    #     3: UNordered
+
+    if fp:
+        # Support for NaNs: with LE or GE, if one of the operands is a
+        # NaN, we get CR=1,0,0,0 (unordered bit only).  We're about to
+        # check "not GT" or "not LT", but in case of NaN we want to
+        # get the answer False.
+        #if condition == c.LE:
+        #    self.mc.crnor(1, 1, 3)
+        #    condition = c.GT
+        #elif condition == c.GE:
+        #    self.mc.crnor(0, 0, 3)
+        #    condition = c.LT
+        pass
+
+    flush_cc(self, condition, r.SPP)
+
+
+def gen_emit_cmp_op(condition, signed=True, fp=False):
+    def f(self, op, arglocs, regalloc):
+        do_emit_cmp_op(self, arglocs, condition, signed, fp)
+    return f
diff --git a/rpython/jit/backend/zarch/helper/regalloc.py b/rpython/jit/backend/zarch/helper/regalloc.py
--- a/rpython/jit/backend/zarch/helper/regalloc.py
+++ b/rpython/jit/backend/zarch/helper/regalloc.py
@@ -7,7 +7,7 @@
         return lower_bound <= i <= upper_bound
     return False
 
-def _prepare_int_binary_arith(self, op):
+def prepare_int_add_or_mul(self, op):
     a0 = op.getarg(0)
     a1 = op.getarg(1)
     if check_imm(a0):
@@ -21,7 +21,32 @@
     self.force_result_in_reg(op, a0)
     return [l0, l1]
 
-def _prepare_float_binary_arith(self, op):
+def prepare_int_sub(self, op):
+    a0 = op.getarg(0)
+    a1 = op.getarg(1)
+    if isinstance(a0, ConstInt):
+        a0, a1 = a1, a0
+    l0 = self.ensure_reg(a0)
+    l1 = self.ensure_reg(a1)
+    self.free_op_vars()
+    self.force_result_in_reg(op, a0)
+    return [l0, l1]
+
+def prepare_cmp_op(self, op):
+    a0 = op.getarg(0)
+    a1 = op.getarg(1)
+    if check_imm(a0):
+        a0, a1 = a1, a0
+    l0 = self.ensure_reg(a0)
+    if check_imm(a1):
+        l1 = imm(a1.getint())
+    else:
+        l1 = self.ensure_reg(a1)
+    self.free_op_vars()
+    self.force_result_in_reg(op, a0)
+    return [l0, l1]
+
+def prepare_binary_op(self, op):
     a0 = op.getarg(0)
     a1 = op.getarg(1)
     l0 = self.ensure_reg(a0)
diff --git a/rpython/jit/backend/zarch/instructions.py b/rpython/jit/backend/zarch/instructions.py
--- a/rpython/jit/backend/zarch/instructions.py
+++ b/rpython/jit/backend/zarch/instructions.py
@@ -21,6 +21,13 @@
     'AGF':     ('rxy',   ['\xE3','\x18']),
     'AHI':     ('ri',    ['\xA7','\x0A']),
     'AGHI':    ('ri',    ['\xA7','\x0B']),
+
+
+    # comparision
+    'CGR':     ('rre',    ['\xB9','\x20']),
+    'CG':      ('rxy',    ['\xE3','\x20']),
+    'CLGR':    ('rre',    ['\xB9','\x21']),
+    'CLG':     ('rxy',    ['\xE3','\x20']),
 }
 
 logic_mnemonic_codes = {
diff --git a/rpython/jit/backend/zarch/locations.py b/rpython/jit/backend/zarch/locations.py
--- a/rpython/jit/backend/zarch/locations.py
+++ b/rpython/jit/backend/zarch/locations.py
@@ -14,7 +14,7 @@
     def is_raw_sp(self):
         return False
 
-    def is_core_reg(self):
+    def is_reg(self):
         return False
 
     def is_fp_reg(self):
@@ -45,7 +45,7 @@
     def __repr__(self):
         return 'r%d' % self.value
 
-    def is_core_reg(self):
+    def is_reg(self):
         return True
 
     def as_key(self):       # 0 <= as_key <= 15
@@ -60,7 +60,7 @@
     def __repr__(self):
         return 'f%d' % self.value
 
-    def is_core_reg(self):
+    def is_reg(self):
         return False
 
     def is_fp_reg(self):
diff --git a/rpython/jit/backend/zarch/opassembler.py b/rpython/jit/backend/zarch/opassembler.py
--- a/rpython/jit/backend/zarch/opassembler.py
+++ b/rpython/jit/backend/zarch/opassembler.py
@@ -1,15 +1,28 @@
+from rpython.jit.backend.zarch.helper.assembler import gen_emit_cmp_op
+from rpython.jit.backend.zarch.codebuilder import ZARCHGuardToken
+import rpython.jit.backend.zarch.conditions as c
+import rpython.jit.backend.zarch.registers as r
+from rpython.jit.backend.llsupport.gcmap import allocate_gcmap
 
 class IntOpAssembler(object):
     _mixin_ = True
 
     def emit_int_add(self, op, arglocs, regalloc):
         l0, l1 = arglocs
-        assert not l0.is_imm()
         if l1.is_imm():
             self.mc.AGHI(l0, l1)
+        elif l1.is_in_pool():
+            self.mc.AG(l0, l1)
         else:
             self.mc.AGR(l0, l1)
 
+    emit_int_le = gen_emit_cmp_op(c.LE)
+    emit_int_lt = gen_emit_cmp_op(c.LT)
+    emit_int_gt = gen_emit_cmp_op(c.GT)
+    emit_int_ge = gen_emit_cmp_op(c.GE)
+    emit_int_eq = gen_emit_cmp_op(c.EQ)
+    emit_int_ne = gen_emit_cmp_op(c.NE)
+
 class FloatOpAssembler(object):
     _mixin_ = True
 
@@ -40,3 +53,192 @@
             self.mc.DDB(l0, l1)
         else:
             self.mc.DDBR(l0, l1)
+
+class GuardOpAssembler(object):
+    _mixin_ = True
+
+    def _emit_guard(self, op, arglocs, is_guard_not_invalidated=False):
+        if is_guard_not_invalidated:
+            fcond = c.cond_none
+        else:
+            fcond = self.guard_success_cc
+            self.guard_success_cc = c.cond_none
+            assert fcond != c.cond_none
+            fcond = c.negate(fcond)
+        token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], fcond)
+        token.pos_jump_offset = self.mc.currpos()
+        assert token.guard_not_invalidated() == is_guard_not_invalidated
+        if not is_guard_not_invalidated:
+            self.mc.trap()     # has to be patched later on
+        self.pending_guard_tokens.append(token)
+
+    def build_guard_token(self, op, frame_depth, arglocs, fcond):
+        descr = op.getdescr()
+        gcmap = allocate_gcmap(self, frame_depth, r.JITFRAME_FIXED_SIZE)
+        token = ZARCHGuardToken(self.cpu, gcmap, descr, op.getfailargs(),
+                              arglocs, op.getopnum(), frame_depth,
+                              fcond)
+        return token
+
+    def emit_guard_true(self, op, arglocs, regalloc):
+        self._emit_guard(op, arglocs)
+
+    def emit_guard_false(self, op, arglocs, regalloc):
+        self.guard_success_cc = c.negate(self.guard_success_cc)
+        self._emit_guard(op, arglocs)
+
+    def emit_guard_overflow(self, op, arglocs, regalloc):
+        self.guard_success_cc = c.SO
+        self._emit_guard(op, arglocs)
+
+    def emit_guard_no_overflow(self, op, arglocs, regalloc):
+        self.guard_success_cc = c.NS
+        self._emit_guard(op, arglocs)
+
+    def emit_guard_value(self, op, arglocs, regalloc):
+        l0 = arglocs[0]
+        l1 = arglocs[1]
+        failargs = arglocs[2:]
+
+        if l0.is_reg():
+            if l1.is_imm():
+                self.mc.cmp_op(0, l0.value, l1.getint(), imm=True)
+            else:
+                self.mc.cmp_op(0, l0.value, l1.value)
+        elif l0.is_fp_reg():
+            assert l1.is_fp_reg()
+            self.mc.cmp_op(0, l0.value, l1.value, fp=True)
+        self.guard_success_cc = c.EQ
+        self._emit_guard(op, failargs)
+
+    emit_guard_nonnull = emit_guard_true
+    emit_guard_isnull = emit_guard_false
+
+    def emit_guard_class(self, op, arglocs, regalloc):
+        self._cmp_guard_class(op, arglocs, regalloc)
+        self.guard_success_cc = c.EQ
+        self._emit_guard(op, arglocs[2:])
+
+    def emit_guard_nonnull_class(self, op, arglocs, regalloc):
+        self.mc.cmp_op(0, arglocs[0].value, 1, imm=True, signed=False)
+        patch_pos = self.mc.currpos()
+        self.mc.trap()
+        self._cmp_guard_class(op, arglocs, regalloc)
+        pmc = OverwritingBuilder(self.mc, patch_pos, 1)
+        pmc.blt(self.mc.currpos() - patch_pos)
+        pmc.overwrite()
+        self.guard_success_cc = c.EQ
+        self._emit_guard(op, arglocs[2:])
+
+    def _cmp_guard_class(self, op, locs, regalloc):
+        offset = self.cpu.vtable_offset
+        if offset is not None:
+            # could be one instruction shorter, but don't care because
+            # it's not this case that is commonly translated
+            self.mc.load(r.SCRATCH.value, locs[0].value, offset)
+            self.mc.load_imm(r.SCRATCH2, locs[1].value)
+            self.mc.cmp_op(0, r.SCRATCH.value, r.SCRATCH2.value)
+        else:
+            expected_typeid = (self.cpu.gc_ll_descr
+                    .get_typeid_from_classptr_if_gcremovetypeptr(locs[1].value))
+            self._cmp_guard_gc_type(locs[0], expected_typeid)
+
+    def _read_typeid(self, targetreg, loc_ptr):
+        # Note that the typeid half-word is at offset 0 on a little-endian
+        # machine; it is at offset 2 or 4 on a big-endian machine.
+        assert self.cpu.supports_guard_gc_type
+        if IS_PPC_32:
+            self.mc.lhz(targetreg.value, loc_ptr.value, 2 * IS_BIG_ENDIAN)
+        else:
+            self.mc.lwz(targetreg.value, loc_ptr.value, 4 * IS_BIG_ENDIAN)
+
+    def _cmp_guard_gc_type(self, loc_ptr, expected_typeid):
+        self._read_typeid(r.SCRATCH2, loc_ptr)
+        assert 0 <= expected_typeid <= 0x7fffffff   # 4 bytes are always enough
+        if expected_typeid > 0xffff:     # if 2 bytes are not enough
+            self.mc.subis(r.SCRATCH2.value, r.SCRATCH2.value,
+                          expected_typeid >> 16)
+            expected_typeid = expected_typeid & 0xffff
+        self.mc.cmp_op(0, r.SCRATCH2.value, expected_typeid,
+                       imm=True, signed=False)
+
+    def emit_guard_gc_type(self, op, arglocs, regalloc):
+        self._cmp_guard_gc_type(arglocs[0], arglocs[1].value)
+        self.guard_success_cc = c.EQ
+        self._emit_guard(op, arglocs[2:])
+
+    def emit_guard_is_object(self, op, arglocs, regalloc):
+        assert self.cpu.supports_guard_gc_type
+        loc_object = arglocs[0]
+        # idea: read the typeid, fetch one byte of the field 'infobits' from
+        # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'.
+        base_type_info, shift_by, sizeof_ti = (
+            self.cpu.gc_ll_descr.get_translated_info_for_typeinfo())
+        infobits_offset, IS_OBJECT_FLAG = (
+            self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object())
+
+        self._read_typeid(r.SCRATCH2, loc_object)
+        self.mc.load_imm(r.SCRATCH, base_type_info + infobits_offset)
+        assert shift_by == 0     # on PPC64; fixme for PPC32
+        self.mc.lbzx(r.SCRATCH2.value, r.SCRATCH2.value, r.SCRATCH.value)
+        self.mc.andix(r.SCRATCH2.value, r.SCRATCH2.value, IS_OBJECT_FLAG & 0xff)
+        self.guard_success_cc = c.NE
+        self._emit_guard(op, arglocs[1:])
+
+    def emit_guard_subclass(self, op, arglocs, regalloc):
+        assert self.cpu.supports_guard_gc_type
+        loc_object = arglocs[0]
+        loc_check_against_class = arglocs[1]
+        offset = self.cpu.vtable_offset
+        offset2 = self.cpu.subclassrange_min_offset
+        if offset is not None:
+            # read this field to get the vtable pointer
+            self.mc.load(r.SCRATCH2.value, loc_object.value, offset)
+            # read the vtable's subclassrange_min field
+            assert _check_imm_arg(offset2)
+            self.mc.ld(r.SCRATCH2.value, r.SCRATCH2.value, offset2)
+        else:
+            # read the typeid
+            self._read_typeid(r.SCRATCH, loc_object)
+            # read the vtable's subclassrange_min field, as a single
+            # step with the correct offset
+            base_type_info, shift_by, sizeof_ti = (
+                self.cpu.gc_ll_descr.get_translated_info_for_typeinfo())
+            self.mc.load_imm(r.SCRATCH2, base_type_info + sizeof_ti + offset2)
+            assert shift_by == 0     # on PPC64; fixme for PPC32
+            self.mc.ldx(r.SCRATCH2.value, r.SCRATCH2.value, r.SCRATCH.value)
+        # get the two bounds to check against
+        vtable_ptr = loc_check_against_class.getint()
+        vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr)
+        check_min = vtable_ptr.subclassrange_min
+        check_max = vtable_ptr.subclassrange_max
+        assert check_max > check_min
+        check_diff = check_max - check_min - 1
+        # right now, a full PyPy uses less than 6000 numbers,
+        # so we'll assert here that it always fit inside 15 bits
+        assert 0 <= check_min <= 0x7fff
+        assert 0 <= check_diff <= 0xffff
+        # check by doing the unsigned comparison (tmp - min) < (max - min)
+        self.mc.subi(r.SCRATCH2.value, r.SCRATCH2.value, check_min)
+        self.mc.cmp_op(0, r.SCRATCH2.value, check_diff, imm=True, signed=False)
+        # the guard passes if we get a result of "below or equal"
+        self.guard_success_cc = c.LE
+        self._emit_guard(op, arglocs[2:])
+
+    def emit_guard_not_invalidated(self, op, arglocs, regalloc):
+        self._emit_guard(op, arglocs, is_guard_not_invalidated=True)
+
+    def emit_guard_not_forced(self, op, arglocs, regalloc):
+        ofs = self.cpu.get_ofs_of_frame_field('jf_descr')
+        self.mc.ld(r.SCRATCH.value, r.SPP.value, ofs)
+        self.mc.cmp_op(0, r.SCRATCH.value, 0, imm=True)
+        self.guard_success_cc = c.EQ
+        self._emit_guard(op, arglocs)
+
+    def emit_guard_not_forced_2(self, op, arglocs, regalloc):
+        guard_token = self.build_guard_token(op, arglocs[0].value, arglocs[1:],
+                                             c.cond_none)
+        self._finish_gcmap = guard_token.gcmap
+        self._store_force_index(op)
+        self.store_info_on_descr(0, guard_token)
+
diff --git a/rpython/jit/backend/zarch/regalloc.py b/rpython/jit/backend/zarch/regalloc.py
--- a/rpython/jit/backend/zarch/regalloc.py
+++ b/rpython/jit/backend/zarch/regalloc.py
@@ -8,7 +8,7 @@
                                             INT, REF, FLOAT, VOID)
 from rpython.jit.metainterp.history import JitCellToken, TargetToken
 from rpython.jit.metainterp.resoperation import rop
-from rpython.jit.backend.zarch import locations
+from rpython.jit.backend.zarch import locations as l
 from rpython.rtyper.lltypesystem import rffi, lltype, rstr, llmemory
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rtyper.annlowlevel import cast_instance_to_gcref
@@ -16,7 +16,7 @@
 from rpython.jit.backend.llsupport.descr import ArrayDescr
 import rpython.jit.backend.zarch.registers as r
 import rpython.jit.backend.zarch.conditions as c
-import rpython.jit.backend.zarch.helper.regalloc as regallochelp
+import rpython.jit.backend.zarch.helper.regalloc as helper
 from rpython.jit.backend.llsupport.descr import unpack_arraydescr
 from rpython.jit.backend.llsupport.descr import unpack_fielddescr
 from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr
@@ -64,7 +64,7 @@
 
     def convert_to_imm(self, c):
         adr = self.convert_to_adr(c)
-        return locations.ConstFloatLoc(adr)
+        return l.ConstFloatLoc(adr)
 
     def __init__(self, longevity, frame_manager=None, assembler=None):
         RegisterManager.__init__(self, longevity, frame_manager, assembler)
@@ -74,7 +74,7 @@
 
     def place_in_pool(self, var):
         offset = self.assembler.pool.place(var)
-        return locations.pool(offset, r.POOL)
+        return l.pool(offset, r.POOL)
 
     def ensure_reg(self, box):
         if isinstance(box, Const):
@@ -116,7 +116,7 @@
 
     def convert_to_imm(self, c):
         val = self.convert_to_int(c)
-        return locations.ImmLocation(val)
+        return l.ImmLocation(val)
 
     def ensure_reg(self, box):
         if isinstance(box, Const):
@@ -143,8 +143,8 @@
         self.base_ofs = base_ofs
 
     def frame_pos(self, loc, box_type):
-        #return locations.StackLocation(loc, get_fp_offset(self.base_ofs, loc), box_type)
-        return locations.StackLocation(loc, get_fp_offset(self.base_ofs, loc), box_type)
+        #return l.StackLocation(loc, get_fp_offset(self.base_ofs, loc), box_type)
+        return l.StackLocation(loc, get_fp_offset(self.base_ofs, loc), box_type)
 
     @staticmethod
     def frame_size(type):
@@ -152,7 +152,7 @@
 
     @staticmethod
     def get_loc_index(loc):
-        assert isinstance(loc, locations.StackLocation)
+        assert isinstance(loc, l.StackLocation)
         return loc.position
 
 
@@ -350,7 +350,7 @@
                 gcmap[val // WORD // 8] |= r_uint(1) << (val % (WORD * 8))
         for box, loc in self.fm.bindings.iteritems():
             if box.type == REF and self.rm.is_still_alive(box):
-                assert isinstance(loc, locations.StackLocation)
+                assert isinstance(loc, l.StackLocation)
                 val = loc.get_position() + r.JITFRAME_FIXED_SIZE
                 gcmap[val // WORD // 8] |= r_uint(1) << (val % (WORD * 8))
         return gcmap
@@ -463,11 +463,103 @@
     def prepare_increment_debug_counter(self, op):
         pass # XXX
 
-    prepare_int_add = regallochelp._prepare_int_binary_arith
-    prepare_float_add = regallochelp._prepare_float_binary_arith
-    prepare_float_sub = regallochelp._prepare_float_binary_arith
-    prepare_float_mul = regallochelp._prepare_float_binary_arith
-    prepare_float_div = regallochelp._prepare_float_binary_arith
+    prepare_int_add = helper.prepare_int_add_or_mul
+    prepare_int_sub = helper.prepare_int_sub
+    prepare_int_mul = helper.prepare_int_add_or_mul
+
+    prepare_int_le = helper.prepare_cmp_op
+    prepare_int_lt = helper.prepare_cmp_op
+    prepare_int_ge = helper.prepare_cmp_op
+    prepare_int_gt = helper.prepare_cmp_op
+    prepare_int_eq = helper.prepare_cmp_op
+    prepare_int_ne = helper.prepare_cmp_op
+
+    prepare_float_add = helper.prepare_binary_op
+    prepare_float_sub = helper.prepare_binary_op
+    prepare_float_mul = helper.prepare_binary_op
+    prepare_float_truediv = helper.prepare_binary_op
+
+    def _prepare_guard(self, op, args=None):
+        if args is None:
+            args = []
+        args.append(imm(self.fm.get_frame_depth()))
+        for arg in op.getfailargs():
+            if arg:
+                args.append(self.loc(arg))
+            else:
+                args.append(None)
+        self.possibly_free_vars(op.getfailargs())
+        #
+        # generate_quick_failure() produces up to 14 instructions per guard
+        self.limit_loop_break -= 14 * 4
+        #
+        return args
+
+    def load_condition_into_cc(self, box):
+        if self.assembler.guard_success_cc == c.cond_none:
+            xxx
+            loc = self.ensure_reg(box)
+            mc = self.assembler.mc
+            mc.cmp_op(loc, l.imm(0), imm=True)
+            self.assembler.guard_success_cc = c.NE
+
+    def _prepare_guard_cc(self, op):
+        self.load_condition_into_cc(op.getarg(0))
+        return self._prepare_guard(op)
+
+    prepare_guard_true = _prepare_guard_cc
+    prepare_guard_false = _prepare_guard_cc
+    prepare_guard_nonnull = _prepare_guard_cc
+    prepare_guard_isnull = _prepare_guard_cc
+
+    def prepare_label(self, op):
+        descr = op.getdescr()
+        assert isinstance(descr, TargetToken)
+        inputargs = op.getarglist()
+        arglocs = [None] * len(inputargs)
+        #
+        # we use force_spill() on the boxes that are not going to be really
+        # used any more in the loop, but that are kept alive anyway
+        # by being in a next LABEL's or a JUMP's argument or fail_args
+        # of some guard
+        position = self.rm.position
+        for arg in inputargs:
+            assert not isinstance(arg, Const)
+            if self.last_real_usage.get(arg, -1) <= position:
+                self.force_spill_var(arg)
+        #
+        # we need to make sure that no variable is stored in spp (=r31)
+        for arg in inputargs:
+            assert self.loc(arg) is not r.SPP, (
+                "variable stored in spp in prepare_label")
+        self.rm.bindings_to_frame_reg.clear()
+        #
+        for i in range(len(inputargs)):
+            arg = inputargs[i]
+            assert not isinstance(arg, Const)
+            loc = self.loc(arg)
+            assert loc is not r.SPP
+            arglocs[i] = loc
+            if loc.is_reg():
+                self.fm.mark_as_free(arg)
+        #
+        # if we are too close to the start of the loop, the label's target may
+        # get overridden by redirect_call_assembler().  (rare case)
+        self.flush_loop()
+        #
+        descr._zarch_arglocs = arglocs
+        descr._ll_loop_code = self.assembler.mc.currpos()
+        descr._zarch_clt = self.assembler.current_clt
+        self.assembler.target_tokens_currently_compiling[descr] = None
+        self.possibly_free_vars_for_op(op)
+        #
+        # if the LABEL's descr is precisely the target of the JUMP at the
+        # end of the same loop, i.e. if what we are compiling is a single
+        # loop that ends up jumping to this LABEL, then we can now provide
+        # the hints about the expected position of the spilled variables.
+        jump_op = self.final_jump_op
+        if jump_op is not None and jump_op.getdescr() is descr:
+            self._compute_hint_frame_locations_from_descr(descr)
 
     def prepare_finish(self, op):
         descr = op.getdescr()


More information about the pypy-commit mailing list