Author: Maciej Fijalkowski <[email protected]>
Branch: resume-refactor
Changeset: r66685:94ee63a63378
Date: 2013-08-30 19:26 +0100
http://bitbucket.org/pypy/pypy/changeset/94ee63a63378/

Log:    (fijal, arigo) write some tests and make them pass

diff --git a/rpython/jit/backend/llsupport/assembler.py 
b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -4,6 +4,7 @@
 from rpython.jit.metainterp.history import (INT, REF, FLOAT, JitCellToken,
     ConstInt, BoxInt, AbstractFailDescr)
 from rpython.jit.metainterp.resoperation import ResOperation, rop
+from rpython.jit.metainterp.resume2 import rebuild_locs_from_resumedata
 from rpython.rlib import rgc
 from rpython.rlib.debug import (debug_start, debug_stop, have_debug_prints,
                                 debug_print)
@@ -111,8 +112,9 @@
         return r
 
     def rebuild_faillocs_from_descr(self, descr, inputargs):
-        xxx
-        locs = []
+        XXX
+        loc_positions = rebuild_locs_from_resumedata(descr)
+        locs = [None] * len(loc_positions)
         GPR_REGS = len(self.cpu.gen_regs)
         XMM_REGS = len(self.cpu.float_regs)
         input_i = 0
@@ -120,19 +122,17 @@
             coeff = 1
         else:
             coeff = 2
-        for pos in descr.rd_locs:
-            if pos == -1:
-                continue
-            elif pos < GPR_REGS * WORD:
-                locs.append(self.cpu.gen_regs[pos // WORD])
+        for item, pos in enumerate(loc_positions):
+            if pos < GPR_REGS * WORD:
+                locs[item] = self.cpu.gen_regs[pos // WORD]
             elif pos < (GPR_REGS + XMM_REGS * coeff) * WORD:
                 pos = (pos // WORD - GPR_REGS) // coeff
-                locs.append(self.cpu.float_regs[pos])
+                locs[item] = self.cpu.float_regs[pos]
             else:
                 i = pos // WORD - self.cpu.JITFRAME_FIXED_SIZE
                 assert i >= 0
                 tp = inputargs[input_i].type
-                locs.append(self.new_stack_loc(i, pos, tp))
+                locs[item] = self.new_stack_loc(i, pos, tp)
             input_i += 1
         return locs
 
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
@@ -678,7 +678,7 @@
             return [self.loc(op.getarg(0))]
 
 
-def compute_vars_longevity(inputargs, operations):
+def compute_vars_longevity(inputargs, operations, descr=None):
     # compute a dictionary that maps variables to index in
     # operations that is a "last-time-seen"
 
@@ -689,21 +689,19 @@
     produced = {}
     last_used = {}
     last_real_usage = {}
+    frontend_alive = {}
     liveness_analyzer = LivenessAnalyzer()
+    start_pos = 0
     for position, op in enumerate(operations):
-        if op.getopnum() == rop.ENTER_FRAME:
-            liveness_analyzer.enter_frame(op.getdescr())
-        elif op.getopnum() == rop.LEAVE_FRAME:
-            liveness_analyzer.leave_frame()
-        elif op.getopnum() == rop.RESUME_PUT:
-            liveness_analyzer.put(op.getarg(0), op.getarg(1).getint(),
-                                  op.getarg(2).getint())
-        elif op.is_guard():
+        if op.is_guard():
+            liveness_analyzer.interpret_until(operations, position, start_pos)
+            start_pos = position
             framestack = liveness_analyzer.get_live_info()
             for frame in framestack:
-                for item in frame:
+                for item in liveness_analyzer.all_boxes_from(frame):
                     if item is not None:
                         last_used[item] = position
+                        frontend_alive[item] = position
 
     for i in range(len(operations)-1, -1, -1):
         op = operations[i]
@@ -740,7 +738,7 @@
             longevity[arg] = (0, last_used[arg])
             del last_used[arg]
     assert len(last_used) == 0
-    return longevity, last_real_usage
+    return longevity, last_real_usage, frontend_alive
 
 def is_comparison_or_ovf_op(opnum):
     from rpython.jit.metainterp.resoperation import opclasses
diff --git a/rpython/jit/backend/llsupport/resumebuilder.py 
b/rpython/jit/backend/llsupport/resumebuilder.py
--- a/rpython/jit/backend/llsupport/resumebuilder.py
+++ b/rpython/jit/backend/llsupport/resumebuilder.py
@@ -1,20 +1,39 @@
 
-from rpython.jit.metainterp.resoperation import rop
+from rpython.jit.metainterp.resoperation import rop, ResOperation
 from rpython.jit.metainterp.history import ConstInt
-from rpython.jit.metainterp.resume2 import ResumeBytecode
-from rpython.jit.codewriter.jitcode import JitCode
+from rpython.jit.metainterp.resume2 import ResumeBytecode, AbstractResumeReader
 
-class LivenessAnalyzer(object):
+class LivenessAnalyzer(AbstractResumeReader):
     def __init__(self):
+        self.liveness = {}
+        self.frame_starts = [0]
         self.framestack = []
+        self.deps = {}
 
-    def enter_frame(self, jitcode):
-        assert isinstance(jitcode, JitCode)
+    def enter_frame(self, pc, jitcode):
+        self.frame_starts.append(self.frame_starts[-1] + jitcode.num_regs())
         self.framestack.append([None] * jitcode.num_regs())
 
-    def put(self, value, depth, position):
-        # - depth - 1 can be expressed as ~depth (haha)
-        self.framestack[- depth - 1][position] = value
+    def resume_put(self, box, framepos, frontend_pos):
+        self.framestack[-framepos - 1][frontend_pos] = box
+
+    def resume_new(self, result, descr):
+        self.deps[result] = {}
+
+    def resume_setfield_gc(self, arg0, arg1, descr):
+        self.deps[arg0][descr] = arg1
+
+    def _track(self, allboxes, box):
+        if box in self.deps:
+            for dep in self.deps[box].values():
+                self._track(allboxes, dep)
+        allboxes.append(box)
+
+    def all_boxes_from(self, frame):
+        allboxes = []
+        for item in frame:
+            self._track(allboxes, item)
+        return allboxes
 
     def get_live_info(self):
         return self.framestack
@@ -23,45 +42,39 @@
         self.framestack.pop()
 
 class ResumeBuilder(object):
-    def __init__(self, regalloc):
-        self.framestack = []
+    def __init__(self, regalloc, frontend_liveness, descr):
         self.newops = []
         self.regalloc = regalloc
+        self.current_attachment = {}
+        self.frontend_liveness = frontend_liveness
 
     def process(self, op):
-        oplist[op.getopnum()](self, op)
-
-    def process_enter_frame(self, op):
-        self.framestack.append(op.getdescr())
         self.newops.append(op)
 
-    def _find_position_for_box(self, v):
-        return self.regalloc.loc(v).get_jitframe_position()
+    def _mark_visited(self, v, loc):
+        pos = loc.get_jitframe_position()
+        if (v not in self.frontend_liveness or
+            self.frontend_liveness[v] > self.regalloc.rm.position):
+            return
+        if (v not in self.current_attachment or
+            self.current_attachment[v] != pos):
+            self.newops.append(ResOperation(rop.BACKEND_ATTACH, [
+                v, ConstInt(pos)], None))
+        self.current_attachment[v] = pos
 
-    def process_resume_put(self, op):
-        pos = self._find_position_for_box(op.getarg(0))
-        self.newops.append(op.copy_and_change(rop.BACKEND_PUT,
-                                              args=[ConstInt(pos),
-                                                    op.getarg(1),
-                                                    op.getarg(2)]))
-
-    def process_leave_frame(self, op):
-        self.framestack.pop()
-        self.newops.append(op)
-
-    def get_position(self):
+    def mark_resumable_position(self):
+        visited = {}
+        for v, loc in self.regalloc.fm.bindings.iteritems():
+            self._mark_visited(v, loc)
+            visited[v] = None
+        for v, loc in self.regalloc.rm.reg_bindings.iteritems():
+            if v not in visited:
+                self._mark_visited(v, loc)
+        for v, loc in self.regalloc.xrm.reg_bindings.iteritems():
+            if v not in visited:
+                self._mark_visited(v, loc)
         return len(self.newops)
 
     def finish(self, parent, clt):
         return ResumeBytecode(self.newops, parent, clt)
 
-    def not_implemented_op(self, op):
-        print "Not implemented", op.getopname()
-        raise NotImplementedError(op.getopname())
-
-oplist = [ResumeBuilder.not_implemented_op] * rop._LAST
-for name, value in ResumeBuilder.__dict__.iteritems():
-    if name.startswith('process_'):
-        num = getattr(rop, name[len('process_'):].upper())
-        oplist[num] = value
-
diff --git a/rpython/jit/backend/llsupport/test/test_resume.py 
b/rpython/jit/backend/llsupport/test/test_resume.py
--- a/rpython/jit/backend/llsupport/test/test_resume.py
+++ b/rpython/jit/backend/llsupport/test/test_resume.py
@@ -1,12 +1,15 @@
 
 from rpython.jit.metainterp.history import JitCellToken
+from rpython.jit.metainterp.history import BasicFailDescr
 from rpython.jit.codewriter.jitcode import JitCode
 from rpython.jit.tool.oparser import parse
 from rpython.jit.metainterp.optimizeopt.util import equaloplists
+from rpython.rtyper.lltypesystem import lltype
 
 class MockJitCode(JitCode):
     def __init__(self, no):
         self.no = no
+        self.name = 'frame %d' % no
 
     def num_regs(self):
         return self.no
@@ -32,11 +35,72 @@
         self.cpu.compile_loop(None, loop.inputargs, loop.operations,
                               looptoken)
         descr = loop.operations[2].getdescr()
-        assert descr.rd_bytecode_position == 2
+        assert descr.rd_bytecode_position == 3
         expected_resume = parse("""
-        []
+        [i0]
         enter_frame(-1, descr=jitcode)
-        backend_put(28, 0, 2)
+        resume_put(i0, 0, 2)
+        backend_attach(i0, 28)
         leave_frame()
-        """, namespace={'jitcode': jitcode}).operations
-        equaloplists(descr.rd_resume_bytecode.opcodes, expected_resume)
+        """, namespace={'jitcode': jitcode})
+        i0 = descr.rd_resume_bytecode.opcodes[1].getarg(0)
+        i0b = expected_resume.inputargs[0]
+        equaloplists(descr.rd_resume_bytecode.opcodes,
+                     expected_resume.operations,
+                     remap={i0b:i0})
+
+    def test_resume_new(self):
+        jitcode = JitCode("name")
+        jitcode.setup(num_regs_i=1, num_regs_r=0, num_regs_f=0)
+        S = lltype.GcStruct('S', ('field', lltype.Signed))
+        structdescr = self.cpu.sizeof(S)
+        fielddescr = self.cpu.fielddescrof(S, 'field')
+        namespace = {'jitcode':jitcode, 'structdescr':structdescr,
+                     'fielddescr':fielddescr}
+        loop = parse("""
+        [i0, i1]
+        enter_frame(-1, descr=jitcode)
+        p0 = resume_new(descr=structdescr)
+        resume_setfield_gc(p0, i0, descr=fielddescr)
+        resume_put(p0, 0, 0)
+        i2 = int_lt(i1, 13)
+        guard_true(i2)
+        leave_frame()
+        finish()
+        """, namespace=namespace)
+        looptoken = JitCellToken()
+        self.cpu.compile_loop(None, loop.inputargs, loop.operations,
+                              looptoken)
+        expected_resume = parse("""
+        [i0]
+        enter_frame(-1, descr=jitcode)
+        p0 = resume_new(descr=structdescr)
+        resume_setfield_gc(p0, i0, descr=fielddescr)
+        resume_put(p0, 0, 0)
+        backend_attach(i0, 28)
+        leave_frame()
+        """, namespace=namespace)
+        descr = loop.operations[-3].getdescr()
+        assert descr.rd_bytecode_position == 5
+        i0 = descr.rd_resume_bytecode.opcodes[2].getarg(1)
+        i0b = expected_resume.inputargs[0]
+        equaloplists(descr.rd_resume_bytecode.opcodes,
+                     expected_resume.operations,
+                     remap={i0b:i0})
+
+    def test_spill(self):
+        jitcode = JitCode("name")
+        jitcode.setup(num_regs_i=2, num_regs_r=0, num_regs_f=0)
+        faildescr = BasicFailDescr(1)
+        loop = parse("""
+        [i0, i1]
+        enter_frame(-1, descr=jitcode)
+        i2 = int_add(i0, i1)
+        resume_put(i2, 0, 1)
+        force_spill(i2)
+        guard_true(i0, descr=faildescr)
+        leave_frame()
+        """, namespace={'jitcode':jitcode, 'faildescr':faildescr})
+        looptoken = JitCellToken()
+        self.cpu.compile_loop(None, loop.inputargs, loop.operations,
+                              looptoken)
diff --git a/rpython/jit/backend/x86/assembler.py 
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -532,7 +532,8 @@
         operations = regalloc.prepare_bridge(inputargs, arglocs,
                                              operations,
                                              self.current_clt.allgcrefs,
-                                             self.current_clt.frame_info)
+                                             self.current_clt.frame_info,
+                                             faildescr)
         self._check_frame_depth(self.mc, regalloc.get_gcmap())
         frame_depth_no_fixed_size = self._assemble(regalloc, inputargs, 
operations)
         codeendpos = self.mc.get_relative_pos()
@@ -1723,7 +1724,7 @@
         is_guard_not_invalidated = guard_opnum == rop.GUARD_NOT_INVALIDATED
         is_guard_not_forced = guard_opnum == rop.GUARD_NOT_FORCED
         gcmap = self._regalloc.get_gcmap()
-        pos = self._regalloc.resumebuilder.get_position()
+        pos = self._regalloc.resumebuilder.mark_resumable_position()
         faildescr.rd_bytecode_position = pos
         return GuardToken(self.cpu, gcmap, faildescr,
                           self._regalloc.uses_floats(),
diff --git a/rpython/jit/backend/x86/regalloc.py 
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -125,7 +125,6 @@
 
     def __init__(self, assembler, translate_support_code=False):
         assert isinstance(translate_support_code, bool)
-        self.resumebuilder = ResumeBuilder(self)
         # variables that have place in register
         self.assembler = assembler
         self.translate_support_code = translate_support_code
@@ -133,14 +132,15 @@
         self.jump_target_descr = None
         self.final_jump_op = None
 
-    def _prepare(self, inputargs, operations, allgcrefs):
+    def _prepare(self, inputargs, operations, allgcrefs, descr=None):
         cpu = self.assembler.cpu
         self.fm = X86FrameManager(cpu.get_baseofs_of_frame_field())
         operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations,
                                                        allgcrefs)
         # compute longevity of variables
-        longevity, last_real_usage = compute_vars_longevity(
-                                                    inputargs, operations)
+        x = compute_vars_longevity(inputargs, operations, descr)
+        longevity, last_real_usage, frontend_liveness = x
+        self.resumebuilder = ResumeBuilder(self, frontend_liveness, descr)
         self.longevity = longevity
         self.last_real_usage = last_real_usage
         self.rm = gpr_reg_mgr_cls(self.longevity,
@@ -163,8 +163,8 @@
         return operations
 
     def prepare_bridge(self, inputargs, arglocs, operations, allgcrefs,
-                       frame_info):
-        operations = self._prepare(inputargs, operations, allgcrefs)
+                       frame_info, descr):
+        operations = self._prepare(inputargs, operations, allgcrefs, descr)
         self._update_bindings(arglocs, inputargs)
         self.min_bytes_before_label = 0
         return operations
@@ -334,7 +334,6 @@
         self.assembler.mc.mark_op(None) # end of the loop
         for arg in inputargs:
             self.possibly_free_var(arg)
-        self.assembler.current_clt.rd_bytecode = self.resumebuilder.newops
 
     def flush_loop(self):
         # rare case: if the loop is too short, or if we are just after
diff --git a/rpython/jit/metainterp/optimizeopt/util.py 
b/rpython/jit/metainterp/optimizeopt/util.py
--- a/rpython/jit/metainterp/optimizeopt/util.py
+++ b/rpython/jit/metainterp/optimizeopt/util.py
@@ -125,8 +125,7 @@
 
 # ____________________________________________________________
 
-def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={},
-                 text_right=None):
+def equaloplists(oplist1, oplist2, remap={}, text_right=None):
     # try to use the full width of the terminal to display the list
     # unfortunately, does not work with the default capture method of py.test
     # (which is fd), you you need to use either -s or --capture=sys, else you
diff --git a/rpython/jit/metainterp/resoperation.py 
b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -472,7 +472,9 @@
     'ENTER_FRAME/1d',
     'LEAVE_FRAME/0',
     'RESUME_PUT/3',
-    'BACKEND_PUT/3',
+    'RESUME_NEW/0d',
+    'RESUME_SETFIELD_GC/2d',
+    'BACKEND_ATTACH/2',
     # same as resume_put, but the first arg is backend-dependent,
     # instead of a box
     '_RESUME_LAST',
diff --git a/rpython/jit/metainterp/resume2.py 
b/rpython/jit/metainterp/resume2.py
--- a/rpython/jit/metainterp/resume2.py
+++ b/rpython/jit/metainterp/resume2.py
@@ -20,8 +20,7 @@
             self._rebuild_until(rb.parent, rb.parent_position)
         self.interpret_until(rb.opcodes, position)
 
-    def interpret_until(self, bytecode, until):
-        pos = 0
+    def interpret_until(self, bytecode, until, pos=0):
         while pos < until:
             op = bytecode[pos]
             if op.getopnum() == rop.ENTER_FRAME:
@@ -30,14 +29,23 @@
                 self.enter_frame(op.getarg(0).getint(), descr)
             elif op.getopnum() == rop.LEAVE_FRAME:
                 self.leave_frame()
-            elif op.getopnum() == rop.BACKEND_PUT:
-                self.put(op.getarg(0).getint(), op.getarg(1).getint(),
+            elif op.getopnum() == rop.RESUME_PUT:
+                self.resume_put(op.getarg(0), op.getarg(1).getint(),
                          op.getarg(2).getint())
+            elif op.getopnum() == rop.RESUME_NEW:
+                self.resume_new(op.result, op.getdescr())
+            elif op.getopnum() == rop.RESUME_SETFIELD_GC:
+                self.resume_setfield_gc(op.getarg(0), op.getarg(1),
+                                        op.getdescr())
+            elif not op.is_resume():
+                pos += 1
+                continue
             else:
                 xxx
             pos += 1
 
-    def put(self, jitframe_index, depth, frontend_position):
+    def resume_put(self, jitframe_index, depth, frontend_position):
+        XXX
         jitcode = self.metainterp.framestack[-1].jitcode
         frame = self.metainterp.framestack[- depth - 1]
         if frontend_position < jitcode.num_regs_i():
@@ -82,6 +90,19 @@
     def leave_frame(self):
         self.framestack.pop()
 
+class SimpleResumeReader(AbstractResumeReader):
+    def __init__(self):
+        self.framestack = []
+
+    def enter_frame(self, pc, jitcode):
+        self.framestack.append(jitcode.num_regs())
+
+    def put(self, *args):
+        pass
+
+    def leave_frame(self):
+        self.framestack.pop()
+
 def rebuild_from_resumedata(metainterp, deadframe, faildescr):
     BoxResumeReader(metainterp, deadframe).rebuild(faildescr)
 
diff --git a/rpython/jit/metainterp/test/test_resume2.py 
b/rpython/jit/metainterp/test/test_resume2.py
--- a/rpython/jit/metainterp/test/test_resume2.py
+++ b/rpython/jit/metainterp/test/test_resume2.py
@@ -124,6 +124,17 @@
         assert f.registers_i[0].getint() == 42 + 3
         assert f.registers_i[1].getint() == 2 + 3
 
+    def test_new(self):
+        base = parse("""
+        []
+        enter_frame(-1, descr=jitcode)
+        i0 = new(descr=structdescr)
+        XXX
+        resume_setfield(i0, 13
+        backend_put(12,
+        leave_frame()
+        """)
+
     def test_reconstructing_resume_reader(self):
         jitcode1 = JitCode("jitcode")
         jitcode1.setup(num_regs_i=3, num_regs_f=0, num_regs_r=0)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to