[pypy-commit] pypy regalloc-playground: a kludgy and lengthy explicit way to test the register allocator with a fake

cfbolz pypy.commits at gmail.com
Tue Aug 22 11:05:45 EDT 2017


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: regalloc-playground
Changeset: r92202:7ffc9b6f6e75
Date: 2017-08-22 12:14 +0200
http://bitbucket.org/pypy/pypy/changeset/7ffc9b6f6e75/

Log:	a kludgy and lengthy explicit way to test the register allocator
	with a fake set or registers

diff --git a/rpython/jit/backend/llsupport/regalloc.py b/rpython/jit/backend/llsupport/regalloc.py
--- a/rpython/jit/backend/llsupport/regalloc.py
+++ b/rpython/jit/backend/llsupport/regalloc.py
@@ -1,4 +1,3 @@
-import os
 from rpython.jit.metainterp.history import Const, REF, JitCellToken
 from rpython.rlib.objectmodel import we_are_translated, specialize
 from rpython.jit.metainterp.resoperation import rop, AbstractValue
diff --git a/rpython/jit/backend/llsupport/test/test_regalloc.py b/rpython/jit/backend/llsupport/test/test_regalloc.py
--- a/rpython/jit/backend/llsupport/test/test_regalloc.py
+++ b/rpython/jit/backend/llsupport/test/test_regalloc.py
@@ -1,10 +1,17 @@
 import py
 from rpython.jit.metainterp.history import ConstInt, INT, FLOAT
+from rpython.jit.metainterp.history import BasicFailDescr, TargetToken
+from rpython.jit.metainterp.resoperation import rop
+from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef,\
+     InputArgFloat
+from rpython.jit.backend.detect_cpu import getcpuclass
 from rpython.jit.backend.llsupport.regalloc import FrameManager, LinkedList
 from rpython.jit.backend.llsupport.regalloc import RegisterManager as BaseRegMan,\
-     Lifetime as RealLifetime, UNDEF_POS
-from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef,\
-     InputArgFloat
+     Lifetime as RealLifetime, UNDEF_POS, BaseRegalloc, compute_vars_longevity
+from rpython.jit.tool.oparser import parse
+from rpython.jit.codewriter.effectinfo import EffectInfo
+from rpython.rtyper.lltypesystem import lltype
+from rpython.rtyper.annlowlevel import llhelper
 
 def newboxes(*values):
     return [InputArgInt(v) for v in values]
@@ -49,6 +56,7 @@
 class FakeFramePos(object):
     def __init__(self, pos, box_type):
         self.pos = pos
+        self.value = pos
         self.box_type = box_type
     def __repr__(self):
         return 'FramePos<%d,%s>' % (self.pos, self.box_type)
@@ -78,9 +86,15 @@
         assert isinstance(loc, FakeFramePos)
         return loc.pos
 
+class FakeCPU(object):
+    def get_baseofs_of_frame_field(self):
+        return 0
+
 class MockAsm(object):
     def __init__(self):
         self.moves = []
+        self.emitted = []
+        self.cpu = FakeCPU()
 
         # XXX register allocation statistics to be removed later
         self.num_moves_calls = 0
@@ -97,6 +111,7 @@
 
     def regalloc_mov(self, from_loc, to_loc):
         self.moves.append((from_loc, to_loc))
+        self.emitted.append(("move", to_loc, from_loc))
 
 
 def test_lifetime_next_real_usage():
@@ -649,3 +664,171 @@
         assert fm.get_loc_index(floc) == 0
         for box in fm.bindings.keys():
             fm.mark_as_free(box)
+
+# _____________________________________________________
+# tests that assign registers in a mocked way for a fake CPU
+
+r4, r5, r6, r7, r8, r9 = [FakeReg(i) for i in range(4, 10)]
+
+class RegisterManager2(BaseRegMan):
+    all_regs = [r0, r1, r2, r3, r4, r5, r6, r7]
+
+    save_around_call_regs = [r0, r1, r2, r3]
+
+    frame_reg = r8
+
+    # calling conventions: r0 is result
+    # r1 r2 r3 are arguments and callee-saved registers
+    # r4 r5 r6 r7 are caller-saved registers
+
+    def convert_to_imm(self, v):
+        return v.value
+
+
+class FakeRegalloc(BaseRegalloc):
+    def __init__(self):
+        self.assembler = MockAsm()
+
+    def prepare_loop(self, inputargs, operations, looptoken, allgcrefs):
+        operations = self._prepare(inputargs, operations, allgcrefs)
+        self.operations = operations
+        self._set_initial_bindings(inputargs, looptoken)
+        # note: we need to make a copy of inputargs because possibly_free_vars
+        # is also used on op args, which is a non-resizable list
+        self.possibly_free_vars(list(inputargs))
+        return operations
+
+    def _prepare(self, inputargs, operations, allgcrefs):
+        self.fm = TFrameManager()
+        # compute longevity of variables
+        longevity = compute_vars_longevity(inputargs, operations)
+        self.longevity = longevity
+        self.rm = RegisterManager2(
+            longevity, assembler=self.assembler, frame_manager=self.fm)
+        return operations
+
+    def possibly_free_var(self, var):
+        self.rm.possibly_free_var(var)
+
+    def possibly_free_vars(self, vars):
+        for var in vars:
+            if var is not None: # xxx kludgy
+                self.possibly_free_var(var)
+
+    def loc(self, x):
+        return self.rm.loc(x)
+
+    def force_allocate_reg_or_cc(self, var):
+        assert var.type == INT
+        if self.next_op_can_accept_cc(self.operations, self.rm.position):
+            # hack: return the ebp location to mean "lives in CC".  This
+            # ebp will not actually be used, and the location will be freed
+            # after the next op as usual.
+            self.rm.force_allocate_frame_reg(var)
+            return r8
+        else:
+            # else, return a regular register (not ebp).
+            return self.rm.force_allocate_reg(var, need_lower_byte=True)
+
+    def fake_allocate(self, loop):
+        emit = self.assembler.emitted.append
+        for i, op in enumerate(loop.operations):
+            self.rm.position = i
+            if rop.is_comparison(op.getopnum()):
+                locs = [self.loc(x) for x in op.getarglist()]
+                loc = self.force_allocate_reg_or_cc(op)
+                emit((op.getopname(), loc, locs))
+            elif op.getopname().startswith("int_"):
+                locs = [self.loc(x) for x in op.getarglist()]
+                loc = self.rm.force_result_in_reg(
+                    op, op.getarg(0), op.getarglist())
+                emit((op.getopname(), loc, locs[1:]))
+            elif op.is_guard():
+                emit((op.getopname(), self.loc(op.getarg(0))))
+            else:
+                locs = [self.loc(x) for x in op.getarglist()]
+                if op.type != "v":
+                    loc = self.rm.force_allocate_reg(op)
+                    emit((op.getopname(), loc, locs))
+                else:
+                    emit((op.getopname(), locs))
+        return self.assembler.emitted
+
+CPU = getcpuclass()
+class TestFullRegallocFakeCPU(object):
+    # XXX copy-paste from test_regalloc_integration
+    cpu = CPU(None, None)
+    cpu.setup_once()
+
+    targettoken = TargetToken()
+    targettoken2 = TargetToken()
+    fdescr1 = BasicFailDescr(1)
+    fdescr2 = BasicFailDescr(2)
+    fdescr3 = BasicFailDescr(3)
+
+    def setup_method(self, meth):
+        self.targettoken._ll_loop_code = 0
+        self.targettoken2._ll_loop_code = 0
+
+    def f1(x):
+        return x+1
+
+    def f2(x, y):
+        return x*y
+
+    def f10(*args):
+        assert len(args) == 10
+        return sum(args)
+
+    F1PTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed))
+    F2PTR = lltype.Ptr(lltype.FuncType([lltype.Signed]*2, lltype.Signed))
+    F10PTR = lltype.Ptr(lltype.FuncType([lltype.Signed]*10, lltype.Signed))
+    f1ptr = llhelper(F1PTR, f1)
+    f2ptr = llhelper(F2PTR, f2)
+    f10ptr = llhelper(F10PTR, f10)
+
+    f1_calldescr = cpu.calldescrof(F1PTR.TO, F1PTR.TO.ARGS, F1PTR.TO.RESULT,
+                                   EffectInfo.MOST_GENERAL)
+    f2_calldescr = cpu.calldescrof(F2PTR.TO, F2PTR.TO.ARGS, F2PTR.TO.RESULT,
+                                   EffectInfo.MOST_GENERAL)
+    f10_calldescr = cpu.calldescrof(F10PTR.TO, F10PTR.TO.ARGS, F10PTR.TO.RESULT,
+                                    EffectInfo.MOST_GENERAL)
+
+    namespace = locals().copy()
+
+    def parse(self, s, boxkinds=None, namespace=None):
+        return parse(s, self.cpu, namespace or self.namespace,
+                     boxkinds=boxkinds)
+
+    def allocate(self, s):
+        loop = self.parse(s)
+        self.loop = loop
+        regalloc = FakeRegalloc()
+        regalloc.prepare_loop(loop.inputargs, loop.operations,
+                              loop.original_jitcell_token, [])
+        return regalloc.fake_allocate(loop)
+
+    def _consider_binop(self, op):
+        loc, argloc = self._consider_binop_part(op)
+        self.perform(op, [loc, argloc], loc)
+
+
+    def test_simple(self):
+        ops = '''
+        [i0]
+        label(i0, descr=targettoken)
+        i1 = int_add(i0, 1)
+        i2 = int_lt(i1, 20)
+        guard_true(i2) [i1]
+        jump(i1, descr=targettoken)
+        '''
+        emitted = self.allocate(ops)
+        fp0 = FakeFramePos(0, INT)
+        assert emitted == [
+            ("label", [fp0]),
+            ("move", r0, fp0),
+            ("int_add", r0, [1]),
+            ("int_lt", r8, [r0, 20]),
+            ("guard_true", r8),
+            ("jump", [r0]),
+            ]


More information about the pypy-commit mailing list