Author: David Schneider <[email protected]>
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
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit