Author: David Schneider <david.schnei...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit