[pypy-commit] pypy arm-backend-2: refactor regalloc_mov, create separate methods for different casese and add tests checking the generated instructions and also add tests that check that the not supported cases raise an error

bivab noreply at buildbot.pypy.org
Fri Sep 30 12:00:16 CEST 2011


Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r47704:9f76d024fa8d
Date: 2011-09-29 11:20 +0200
http://bitbucket.org/pypy/pypy/changeset/9f76d024fa8d/

Log:	refactor regalloc_mov, create separate methods for different casese
	and add tests checking the generated instructions and also add tests
	that check that the not supported cases raise an error

diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py
--- a/pypy/jit/backend/arm/assembler.py
+++ b/pypy/jit/backend/arm/assembler.py
@@ -861,69 +861,109 @@
             self.mc.gen_load_int(r.ip.value, value.getint())
             self.mc.VLDR(loc.value, r.ip.value)
 
+    def _mov_imm_to_loc(self, prev_loc, loc, cond=c.AL):
+        if not loc.is_reg() and not loc.is_stack():
+            raise AssertionError("invalid target for move from imm value")
+        if loc.is_reg():
+            new_loc = loc
+        elif loc.is_stack():
+            # we use LR here, because the consequent move to the stack uses the
+            # IP register
+            self.mc.PUSH([r.lr.value], cond=cond)
+            new_loc = r.lr
+        self.mc.gen_load_int(new_loc.value, prev_loc.value, cond=cond)
+        if loc.is_stack():
+            self.regalloc_mov(new_loc, loc)
+            self.mc.POP([r.lr.value], cond=cond)
+
+    def _mov_reg_to_loc(self, prev_loc, loc, cond=c.AL):
+        if loc.is_imm():
+            raise AssertionError("mov reg to imm doesn't make sense")
+        if loc.is_reg():
+            self.mc.MOV_rr(loc.value, prev_loc.value, cond=cond)
+        elif loc.is_stack():
+            # spill a core register
+            offset = ConstInt(loc.position*WORD)
+            if not _check_imm_arg(offset, size=0xFFF):
+                self.mc.PUSH([r.ip.value], cond=cond)
+                self.mc.gen_load_int(r.ip.value, -offset.value, cond=cond)
+                self.mc.STR_rr(prev_loc.value, r.fp.value, r.ip.value, cond=cond)
+                self.mc.POP([r.ip.value], cond=cond)
+            else:
+                self.mc.STR_ri(prev_loc.value, r.fp.value, imm=-1*offset.value, cond=cond)
+        else:
+            assert 0, 'unsupported case'
+
+    def _mov_stack_to_loc(self, prev_loc, loc, cond=c.AL):
+        pushed = False
+        if loc.is_reg():
+            assert prev_loc.type == INT, 'trying to load from an incompatible location into a core register'
+            # unspill a core register
+            offset = ConstInt(prev_loc.position*WORD)
+            if not _check_imm_arg(offset, size=0xFFF):
+                self.mc.PUSH([r.ip.value], cond=cond)
+                pushed = True
+                self.mc.gen_load_int(r.ip.value, -offset.value, cond=cond)
+                self.mc.LDR_rr(loc.value, r.fp.value, r.ip.value, cond=cond)
+            else:
+                self.mc.LDR_ri(loc.value, r.fp.value, imm=-offset.value, cond=cond)
+            if pushed:
+                self.mc.POP([r.ip.value], cond=cond)
+        elif loc.is_vfp_reg():
+            assert prev_loc.type == FLOAT, 'trying to load from an incompatible location into a float register'
+            # load spilled value into vfp reg
+            offset = ConstInt(prev_loc.position*WORD)
+            self.mc.PUSH([r.ip.value], cond=cond)
+            pushed = True
+            if not _check_imm_arg(offset):
+                self.mc.gen_load_int(r.ip.value, offset.value, cond=cond)
+                self.mc.SUB_rr(r.ip.value, r.fp.value, r.ip.value, cond=cond)
+            else:
+                self.mc.SUB_ri(r.ip.value, r.fp.value, offset.value, cond=cond)
+            self.mc.VLDR(loc.value, r.ip.value, cond=cond)
+            if pushed:
+                self.mc.POP([r.ip.value], cond=cond)
+        else:
+            assert 0, 'unsupported case'
+
+    def _mov_imm_float_to_loc(self, prev_loc, loc, cond=c.AL):
+        if not loc.is_vfp_reg():
+            assert 0, 'unsupported case'
+        self.mc.PUSH([r.ip.value], cond=cond)
+        self.mc.gen_load_int(r.ip.value, prev_loc.getint(), cond=cond)
+        self.mc.VLDR(loc.value, r.ip.value, cond=cond)
+        self.mc.POP([r.ip.value], cond=cond)
+
+    def _mov_vfp_reg_to_loc(self, prev_loc, loc, cond=c.AL):
+        if loc.is_vfp_reg():
+            self.mc.VMOV_cc(loc.value, prev_loc.value, cond=cond)
+        elif loc.is_stack():
+            assert loc.type == FLOAT, 'trying to store to an incompatible location from a float register'
+            # spill vfp register
+            self.mc.PUSH([r.ip.value], cond=cond)
+            offset = ConstInt(loc.position*WORD)
+            if not _check_imm_arg(offset):
+                self.mc.gen_load_int(r.ip.value, offset.value, cond=cond)
+                self.mc.SUB_rr(r.ip.value, r.fp.value, r.ip.value, cond=cond)
+            else:
+                self.mc.SUB_ri(r.ip.value, r.fp.value, offset.value, cond=cond)
+            self.mc.VSTR(prev_loc.value, r.ip.value, cond=cond)
+            self.mc.POP([r.ip.value], cond=cond)
+        else:
+            assert 0, 'unsupported case'
+
     def regalloc_mov(self, prev_loc, loc, cond=c.AL):
-        # really XXX add tests
+        """Moves a value from a previous location to some other location"""
         if prev_loc.is_imm():
-            if loc.is_reg():
-                new_loc = loc
-            else:
-                assert loc is not r.ip
-                new_loc = r.ip
-            if _check_imm_arg(ConstInt(prev_loc.getint())):
-                self.mc.MOV_ri(new_loc.value, prev_loc.getint(), cond=cond)
-            else:
-                self.mc.gen_load_int(new_loc.value, prev_loc.getint(), cond=cond)
-            prev_loc = new_loc
-            if not loc.is_stack():
-                return
-        if prev_loc.is_imm_float():
-            assert loc.is_vfp_reg()
-            temp = r.lr
-            self.mc.gen_load_int(temp.value, prev_loc.getint())
-            self.mc.VLDR(loc.value, temp.value)
-            return
-        if loc.is_stack() or prev_loc.is_stack():
-            temp = r.lr
-            if loc.is_stack() and prev_loc.is_reg():
-                # spill a core register
-                offset = ConstInt(loc.position*WORD)
-                if not _check_imm_arg(offset, size=0xFFF):
-                    self.mc.gen_load_int(temp.value, -offset.value)
-                    self.mc.STR_rr(prev_loc.value, r.fp.value, temp.value, cond=cond)
-                else:
-                    self.mc.STR_ri(prev_loc.value, r.fp.value, imm=-1*offset.value, cond=cond)
-            elif loc.is_reg() and prev_loc.is_stack():
-                # unspill a core register
-                offset = ConstInt(prev_loc.position*WORD)
-                if not _check_imm_arg(offset, size=0xFFF):
-                    self.mc.gen_load_int(temp.value, -offset.value)
-                    self.mc.LDR_rr(loc.value, r.fp.value, temp.value, cond=cond)
-                else:
-                    self.mc.LDR_ri(loc.value, r.fp.value, imm=-offset.value, cond=cond)
-            elif loc.is_stack() and prev_loc.is_vfp_reg():
-                # spill vfp register
-                offset = ConstInt(loc.position*WORD)
-                if not _check_imm_arg(offset):
-                    self.mc.gen_load_int(temp.value, offset.value)
-                    self.mc.SUB_rr(temp.value, r.fp.value, temp.value)
-                else:
-                    self.mc.SUB_ri(temp.value, r.fp.value, offset.value)
-                self.mc.VSTR(prev_loc.value, temp.value, cond=cond)
-            elif loc.is_vfp_reg() and prev_loc.is_stack():
-                # load spilled value into vfp reg
-                offset = ConstInt(prev_loc.position*WORD)
-                if not _check_imm_arg(offset):
-                    self.mc.gen_load_int(temp.value, offset.value)
-                    self.mc.SUB_rr(temp.value, r.fp.value, temp.value)
-                else:
-                    self.mc.SUB_ri(temp.value, r.fp.value, offset.value)
-                self.mc.VLDR(loc.value, temp.value, cond=cond)
-            else:
-                assert 0, 'unsupported case'
-        elif loc.is_reg() and prev_loc.is_reg():
-            self.mc.MOV_rr(loc.value, prev_loc.value, cond=cond)
-        elif loc.is_vfp_reg() and prev_loc.is_vfp_reg():
-            self.mc.VMOV_cc(loc.value, prev_loc.value, cond=cond)
+            return self._mov_imm_to_loc(prev_loc, loc, cond)
+        elif prev_loc.is_reg():
+            self._mov_reg_to_loc(prev_loc, loc, cond)
+        elif prev_loc.is_stack():
+            self._mov_stack_to_loc(prev_loc, loc, cond)
+        elif prev_loc.is_imm_float():
+            self._mov_imm_float_to_loc(prev_loc, loc, cond)
+        elif prev_loc.is_vfp_reg():
+            self._mov_vfp_reg_to_loc(prev_loc, loc, cond)
         else:
             assert 0, 'unsupported case'
     mov_loc_loc = regalloc_mov
diff --git a/pypy/jit/backend/arm/test/test_regalloc_mov.py b/pypy/jit/backend/arm/test/test_regalloc_mov.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/backend/arm/test/test_regalloc_mov.py
@@ -0,0 +1,240 @@
+from pypy.rlib.objectmodel import instantiate
+from pypy.jit.backend.arm.assembler import AssemblerARM
+from pypy.jit.backend.arm.locations import imm, ImmLocation, ConstFloatLoc,\
+                                        RegisterLocation, StackLocation, \
+                                        VFPRegisterLocation
+from pypy.jit.backend.arm.registers import lr, ip, fp
+from pypy.jit.backend.arm.conditions import AL
+from pypy.jit.metainterp.history import INT, FLOAT, REF
+import py
+class MockInstr(object):
+    def __init__(self, name, *args, **kwargs):
+        self.name = name
+        self.args = args
+        self.kwargs = kwargs
+
+    def __call__(self, *args, **kwargs):
+        self.args = args
+        self.kwargs = kwargs
+
+    def __repr__(self):
+        return "%s %r %r" % (self.name, self.args, self.kwargs)
+
+    __str__ = __repr__
+
+    def __eq__(self, other):
+        return (self.__class__ == other.__class__
+                and self.name == other.name
+                and self.args == other.args
+                and self.kwargs == other.kwargs)
+mi = MockInstr
+# helper method for tests
+def r(i):
+    return RegisterLocation(i)
+
+def vfp(i):
+    return VFPRegisterLocation(i)
+
+stack = StackLocation
+def stack_float(i):
+    return stack(i, num_words=2, type=FLOAT)
+
+def imm_float(value):
+    addr = int(value) # whatever
+    return ConstFloatLoc(addr)
+
+class MockBuilder(object):
+    def __init__(self):
+        self.instrs = []
+
+    def __getattr__(self, name):
+        i = MockInstr(name)
+        self.instrs.append(i)
+        return i
+
+class TestRegallocMov(object):
+    def setup_method(self, method):
+        self.builder = MockBuilder()
+        self.asm = instantiate(AssemblerARM)
+        self.asm.mc = self.builder
+
+    def mov(self, a, b, expected=None):
+        self.asm.regalloc_mov(a, b)
+        result =self.builder.instrs
+        assert result == expected
+
+    def test_mov_imm_to_reg(self):
+        val = imm(123)
+        reg = r(7)
+        expected = [mi('gen_load_int', 7, 123, cond=AL)]
+        self.mov(val, reg, expected)
+
+    def test_mov_large_imm_to_reg(self):
+        val = imm(65536)
+        reg = r(7)
+        expected = [mi('gen_load_int', 7, 65536, cond=AL)]
+        self.mov(val, reg, expected)
+
+    def test_mov_imm_to_stacklock(self):
+        val = imm(100)
+        s = stack(7)
+        expected = [
+                mi('PUSH', [lr.value], cond=AL),
+                mi('gen_load_int', lr.value, 100, cond=AL), 
+                mi('STR_ri', lr.value, fp.value, imm=-28, cond=AL),
+                mi('POP', [lr.value], cond=AL)]
+        self.mov(val, s, expected)
+
+    def test_mov_big_imm_to_stacklock(self):
+        val = imm(65536)
+        s = stack(7)
+        expected = [
+                mi('PUSH', [lr.value], cond=AL),
+                mi('gen_load_int', lr.value, 65536, cond=AL), 
+                mi('STR_ri', lr.value, fp.value, imm=-28, cond=AL),
+                mi('POP', [lr.value], cond=AL)]
+
+        self.mov(val, s, expected)
+    def test_mov_imm_to_big_stacklock(self):
+        val = imm(100)
+        s = stack(8191)
+        expected = [mi('PUSH', [lr.value], cond=AL),
+                    mi('gen_load_int', lr.value, 100, cond=AL),
+                    mi('PUSH', [ip.value], cond=AL),
+                    mi('gen_load_int', ip.value, -32764, cond=AL),
+                    mi('STR_rr', lr.value, fp.value, ip.value, cond=AL),
+                    mi('POP', [ip.value], cond=AL),
+                    mi('POP', [lr.value], cond=AL)]
+        self.mov(val, s, expected)
+
+    def test_mov_big_imm_to_big_stacklock(self):
+        val = imm(65536)
+        s = stack(8191)
+        expected = [mi('PUSH', [lr.value], cond=AL),
+                    mi('gen_load_int', lr.value, 65536, cond=AL),
+                    mi('PUSH', [ip.value], cond=AL),
+                    mi('gen_load_int', ip.value, -32764, cond=AL),
+                    mi('STR_rr', lr.value, fp.value, ip.value, cond=AL),
+                    mi('POP', [ip.value], cond=AL),
+                    mi('POP', [lr.value], cond=AL)]
+        self.mov(val, s, expected)
+
+    def test_mov_reg_to_reg(self):
+        r1 = r(1)
+        r9 = r(9)
+        expected = [mi('MOV_rr', r9.value, r1.value, cond=AL)]
+        self.mov(r1, r9, expected)
+
+    def test_mov_reg_to_stack(self):
+        s = stack(10)
+        r6 = r(6)
+        expected = [mi('STR_ri', r6.value, fp.value, imm=-40, cond=AL)]
+        self.mov(r6, s, expected)
+
+    def test_mov_reg_to_big_stackloc(self):
+        s = stack(8191)
+        r6 = r(6)
+        expected = [mi('PUSH', [ip.value], cond=AL),
+                    mi('gen_load_int', ip.value, -32764, cond=AL),
+                    mi('STR_rr', r6.value, fp.value, ip.value, cond=AL),
+                    mi('POP', [ip.value], cond=AL)]
+        self.mov(r6, s, expected)
+
+    def test_mov_stack_to_reg(self):
+        s = stack(10)
+        r6 = r(6)
+        expected = [mi('LDR_ri', r6.value, fp.value, imm=-40, cond=AL)]
+        self.mov(s, r6, expected)
+
+    def test_mov_big_stackloc_to_reg(self):
+        s = stack(8191)
+        r6 = r(6)
+        expected = [
+                    mi('PUSH', [ip.value], cond=AL),
+                    mi('gen_load_int', ip.value, -32764, cond=AL),
+                    mi('LDR_rr', r6.value, fp.value, ip.value, cond=AL),
+                    mi('POP', [ip.value], cond=AL)]
+        self.mov(s, r6, expected)
+
+    def test_mov_float_imm_to_vfp_reg(self):
+        f = imm_float(3.5)
+        reg = vfp(5)
+        expected = [
+                    mi('PUSH', [ip.value], cond=AL),
+                    mi('gen_load_int', ip.value, f.value, cond=AL),
+                    mi('VLDR', 5, ip.value, cond=AL),
+                    mi('POP', [ip.value], cond=AL)]
+        self.mov(f, reg, expected)
+
+    def test_mov_vfp_reg_to_vfp_reg(self):
+        reg1 = vfp(5)
+        reg2 = vfp(14)
+        expected = [mi('VMOV_cc', reg2.value, reg1.value, cond=AL)]
+        self.mov(reg1, reg2, expected)
+
+    def test_mov_vfp_reg_to_stack(self):
+        reg = vfp(7)
+        s = stack_float(3)
+        expected = [mi('PUSH', [ip.value], cond=AL),
+                    mi('SUB_ri', ip.value, fp.value, 12, cond=AL),
+                    mi('VSTR', reg.value, ip.value, cond=AL),
+                    mi('POP', [ip.value], cond=AL)]
+        self.mov(reg, s, expected)
+
+    def test_mov_vfp_reg_to_large_stackloc(self):
+        reg = vfp(7)
+        s = stack_float(800)
+        expected = [mi('PUSH', [ip.value], cond=AL),
+                    mi('gen_load_int', ip.value, 3200, cond=AL),
+                    mi('SUB_rr', ip.value, fp.value, ip.value, cond=AL),
+                    mi('VSTR', reg.value, ip.value, cond=AL),
+                    mi('POP', [ip.value], cond=AL)]
+        self.mov(reg, s, expected)
+
+    def test_mov_stack_to_vfp_reg(self):
+        reg = vfp(7)
+        s = stack_float(3)
+        expected = [mi('PUSH', [ip.value], cond=AL),
+                    mi('SUB_ri', ip.value, fp.value, 12, cond=AL),
+                    mi('VLDR', reg.value, ip.value, cond=AL),
+                    mi('POP', [ip.value], cond=AL)]
+        self.mov(s, reg, expected)
+
+    def test_mov_big_stackloc_to_vfp_reg(self):
+        reg = vfp(7)
+        s = stack_float(800)
+        expected = [mi('PUSH', [ip.value], cond=AL),
+                    mi('gen_load_int', ip.value, 3200, cond=AL),
+                    mi('SUB_rr', ip.value, fp.value, ip.value, cond=AL),
+                    mi('VSTR', reg.value, ip.value, cond=AL),
+                    mi('POP', [ip.value], cond=AL)]
+        self.mov(reg, s, expected)
+
+    def test_unsopported_cases(self):
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm(1), imm(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm(1), imm_float(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm(1), vfp(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), r(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), stack(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), stack_float(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), imm_float(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), imm(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(r(1), imm(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(r(1), imm_float(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), imm(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), imm_float(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), stack(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), imm_float(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), imm(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), vfp(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), r(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm_float(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), stack_float(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), imm(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), imm_float(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), r(2))')
+        py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), stack(2))')
+
+class TestMovFromToVFPLoc(object):
+    pass


More information about the pypy-commit mailing list