[pypy-commit] pypy jit-usable_retrace_3: a third athempt at generalizing retraces enough to make them useable

hakanardo noreply at buildbot.pypy.org
Wed Sep 5 17:06:41 CEST 2012


Author: Hakan Ardo <hakan at debian.org>
Branch: jit-usable_retrace_3
Changeset: r57147:120455cfb1d3
Date: 2012-09-05 17:04 +0200
http://bitbucket.org/pypy/pypy/changeset/120455cfb1d3/

Log:	a third athempt at generalizing retraces enough to make them useable

diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -192,50 +192,72 @@
     loop_jitcell_token = metainterp.get_procedure_token(greenkey)
     assert loop_jitcell_token
     assert partial_trace.operations[-1].getopnum() == rop.LABEL
-
-    part = create_empty_loop(metainterp)
-    part.inputargs = inputargs[:]
-    part.resume_at_jump_descr = resume_at_jump_descr
+    orignial_label = partial_trace.operations[-1].clone()
     h_ops = history.operations
 
-    part.operations = [partial_trace.operations[-1]] + \
-                      [h_ops[i].clone() for i in range(start, len(h_ops))] + \
-                      [ResOperation(rop.JUMP, jumpargs, None, descr=loop_jitcell_token)]
-    label = part.operations[0]
-    orignial_label = label.clone()
-    assert label.getopnum() == rop.LABEL
+    preamble = create_empty_loop(metainterp)
+    loop = create_empty_loop(metainterp)
     try:
-        optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
+        preamble.inputargs = inputargs[:]
+        preamble.resume_at_jump_descr = resume_at_jump_descr
+        preamble.operations = [partial_trace.operations[-1]] + \
+                          [h_ops[i].clone() for i in range(start, len(h_ops))] + \
+                          [ResOperation(rop.LABEL, jumpargs, None, descr=loop_jitcell_token)]
+        optimize_trace(metainterp_sd, preamble, jitdriver_sd.warmstate.enable_opts)
+
+        label = preamble.operations[-1]
+        assert label.getopnum() == rop.LABEL
+        label.getdescr().exported_state.generalize_virtual_state = \
+                preamble.operations[0].getdescr().virtual_state
+
+        loop.inputargs = inputargs[:]
+        loop.resume_at_jump_descr = resume_at_jump_descr
+        inliner = Inliner(inputargs, jumpargs)
+        loop.operations = [label] + \
+                          [inliner.inline_op(h_ops[i]) for i in range(start, len(h_ops))] + \
+                          [ResOperation(rop.JUMP, [inliner.inline_arg(a) for a in jumpargs],
+                                        None, descr=loop_jitcell_token)]
+        optimize_trace(metainterp_sd, loop, jitdriver_sd.warmstate.enable_opts)
+
+        preamble.operations = preamble.operations[:-1]
+
     except InvalidLoop:
         # Fall back on jumping to preamble
         target_token = label.getdescr()
         assert isinstance(target_token, TargetToken)
         assert target_token.exported_state
-        part.operations = [orignial_label] + \
-                          [ResOperation(rop.JUMP, inputargs[:],
-                                        None, descr=loop_jitcell_token)]
+        target_token.exported_state.generalize_virtual_state = None
+        # FIXME: Test
+        preamble.operations = [orignial_label] + \
+                              [ResOperation(rop.JUMP, inputargs[:],
+                                            None, descr=loop_jitcell_token)]
+        loop.operations = []
         try:
-            optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts,
+            optimize_trace(metainterp_sd, preamble, jitdriver_sd.warmstate.enable_opts,
                            inline_short_preamble=False)
             
         except InvalidLoop:
             return None
-    assert part.operations[-1].getopnum() != rop.LABEL
+
+    trace = partial_trace
+    trace.operations = partial_trace.operations[:-1] + preamble.operations + loop.operations
+    loop = trace # FIXME: rename
+
+    assert loop.operations[-1].getopnum() != rop.LABEL
     target_token = label.getdescr()
     assert isinstance(target_token, TargetToken)
     assert loop_jitcell_token.target_tokens
-    loop_jitcell_token.target_tokens.append(target_token)
+    loop_jitcell_token.target_tokens.append(target_token) # FIXME: register all labels
     if target_token.short_preamble:
         metainterp_sd.logger_ops.log_short_preamble([], target_token.short_preamble)
 
-    loop = partial_trace
-    loop.operations = loop.operations[:-1] + part.operations
 
     quasi_immutable_deps = {}
     if loop.quasi_immutable_deps:
         quasi_immutable_deps.update(loop.quasi_immutable_deps)
-    if part.quasi_immutable_deps:
-        quasi_immutable_deps.update(part.quasi_immutable_deps)
+    # FIXME
+    #if part.quasi_immutable_deps:
+    #    quasi_immutable_deps.update(part.quasi_immutable_deps)
     if quasi_immutable_deps:
         loop.quasi_immutable_deps = quasi_immutable_deps
 
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -1013,19 +1013,43 @@
         loops = self.get_all_loops()
         assert len(loops) == 1
         loop = loops[0]
-        jumpop = loop.operations[-1]
+        insns = self.sum_simple_loop(loop.operations, insns)
+        return self._check_insns(insns, expected, check)
+
+    def sum_simple_loop(self, operations, insns=None):
+        if insns is None:
+            insns = {}
+        jumpop = operations[-1]
         assert jumpop.getopnum() == rop.JUMP
-        labels = [op for op in loop.operations if op.getopnum() == rop.LABEL]
+        labels = [op for op in operations if op.getopnum() == rop.LABEL]
         targets = [op._descr_wref() for op in labels]
         assert None not in targets # TargetToken was freed, give up
         target = jumpop._descr_wref()
         assert target
         assert targets.count(target) == 1
-        i = loop.operations.index(labels[targets.index(target)])
-        insns = {}
-        for op in loop.operations[i:]:
+        i = operations.index(labels[targets.index(target)])
+        for op in operations[i:]:
             opname = op.getopname()
             insns[opname] = insns.get(opname, 0) + 1
+        return insns
+
+    def check_retraced_simple_loop(self, count, expected=None, **check):
+        """ Similar to check_simple_loop, but will also count ops found in retraces
+            located within the bridges found.
+        """
+        insns = {}
+        worklist = [loop.operations for loop in self.get_all_loops()]
+        simple_loops = 0
+        while worklist:
+            operations = worklist.pop()
+            if len([1 for op in operations if op.getopnum() == rop.LABEL]) > 0:
+                self.sum_simple_loop(operations, insns)
+                simple_loops += 1
+            for op in operations:
+                if op.is_guard() and op.getdescr():
+                    if hasattr(op.getdescr(), '_debug_suboperations'):
+                        worklist.append(op.getdescr()._debug_suboperations)
+        assert simple_loops == count
         return self._check_insns(insns, expected, check)
         
     def check_loops(self, expected=None, everywhere=False, **check):
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -211,7 +211,7 @@
                 exported_values[box] = self.optimizer.getvalue(box)
             
         target_token.exported_state = ExportedState(short_boxes, inputarg_setup_ops,
-                                                    exported_values)
+                                                    exported_values, jump_args)
 
     def import_state(self, targetop):
         if not targetop: # Trace did not start with a label
@@ -279,6 +279,28 @@
         self.optimizer.flush()
         self.optimizer.emitting_dissabled = False
 
+        if exported_state.generalize_virtual_state:
+            # XXX: Hack
+            # FIXME: Rearange stuff to emit label after this (but prior to inputarg_setup_ops)?
+            assert self.optimizer._newoperations[0].getopnum() == rop.LABEL
+            del self.optimizer._newoperations[0]
+
+            virtual_state = self.initial_virtual_state
+            values = [self.getvalue(arg) for arg in exported_state.jump_args]
+            virtual_state = virtual_state.make_generalization_of(exported_state.generalize_virtual_state,
+                                                                 exported_state.jump_args,
+                                                                 self.optimizer)
+            values = [self.getvalue(arg) for arg in exported_state.jump_args]            
+            self.initial_virtual_state = virtual_state
+            inputargs = virtual_state.make_inputargs(values, self.optimizer)
+            target_token.virtual_state = virtual_state 
+            op = ResOperation(rop.LABEL, inputargs, None, descr=target_token)
+            self.optimizer._newoperations.append(op)
+            self.inputargs = inputargs
+            short_inputargs = virtual_state.make_inputargs(values, self.optimizer, keyboxes=True)
+            self.short[0] = ResOperation(rop.LABEL, short_inputargs, None)
+
+
     def close_bridge(self, start_label):
         inputargs = self.inputargs
         short_jumpargs = inputargs[:]
@@ -625,7 +647,9 @@
         self.unroll.add_op_to_short(self.op, False, True)        
 
 class ExportedState(object):
-    def __init__(self, short_boxes, inputarg_setup_ops, exported_values):
+    def __init__(self, short_boxes, inputarg_setup_ops, exported_values, jump_args):
         self.short_boxes = short_boxes
         self.inputarg_setup_ops = inputarg_setup_ops
         self.exported_values = exported_values
+        self.jump_args = jump_args
+        self.generalize_virtual_state = None
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -23,6 +23,9 @@
     def generalization_of(self, other, renum, bad):
         raise NotImplementedError
 
+    def make_generalization_of(self, other, value, optimizer):
+        pass
+
     def generate_guards(self, other, box, cpu, extra_guards, renum):
         if self.generalization_of(other, renum, {}):
             return
@@ -106,6 +109,28 @@
 
         return True
 
+    def make_generalization_of(self, other, value, optimizer):
+        if not self._generalization_of(other):
+            raise InvalidLoop
+        assert isinstance(other, AbstractVirtualStructStateInfo)
+        assert len(self.fielddescrs) == len(self.fieldstate)
+        assert len(other.fielddescrs) == len(other.fieldstate)
+        assert isinstance(value, virtualize.AbstractVirtualStructValue)
+        if len(self.fielddescrs) != len(other.fielddescrs):
+            raise InvalidLoop
+        for i in range(len(self.fielddescrs)):
+            if other.fielddescrs[i] is not self.fielddescrs[i]:
+                raise InvalidLoop
+            new_field_value = self.fieldstate[i].make_generalization_of(other.fieldstate[i],
+                                                                        value.getfield(self.fielddescrs[i], None),
+                                                                        optimizer)
+            if new_field_value:
+                value.setfield(self.fielddescrs[i], new_field_value)
+            #FIXME: default value of getfield
+
+
+
+
     def _generalization_of(self, other):
         raise NotImplementedError
 
@@ -349,6 +374,23 @@
             return False
         return True
 
+    def make_generalization_of(self, other, value, optimizer):
+        if not self.generalization_of(other, {}, {}):
+            box = value.get_key_box()
+            try:
+                self._generate_guards(other, box, optimizer.cpu, [])
+                return # It is enough if we can generate guards to make states compatibe, FIXME: rename method
+            except InvalidLoop:
+                pass
+            if value.is_constant():
+                op = ResOperation(rop.SAME_AS, [box], box.clonebox())
+                optimizer._newoperations.append(op)
+                return optimizer.getvalue(op.result)
+            else:
+                v = OptValue(box)
+                optimizer.make_equal_to(box, v, True)
+                return v
+
     def _generate_guards(self, other, box, cpu, extra_guards):
         if not isinstance(other, NotVirtualStateInfo):
             raise InvalidLoop('The VirtualStates does not match as a ' +
@@ -476,6 +518,22 @@
                 return False
         return True
 
+    def make_generalization_of(self, other, jumpargs, optimizer):
+        assert len(self.state) == len(other.state) == len(jumpargs)
+        values = [optimizer.getvalue(arg) for arg in jumpargs]
+        for i in range(len(self.state)):
+            new_value = self.state[i].make_generalization_of(other.state[i], values[i], optimizer)
+            if new_value:
+                optimizer.make_equal_to(jumpargs[i], new_value, True)
+
+        modifier = VirtualStateAdder(optimizer)
+        virtual_state = modifier.get_virtual_state(jumpargs)
+        
+        # Only a few cases currently implemenetd, so we need to check if we succeeded
+        virtual_state.generate_guards(other, jumpargs, optimizer.cpu, []) # Will raise if not possible
+        virtual_state.generate_guards(self, jumpargs, optimizer.cpu, []) # Will raise if not possible
+        return virtual_state
+
     def generate_guards(self, other, args, cpu, extra_guards):
         assert len(self.state) == len(other.state) == len(args)
         renum = {}
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
--- a/pypy/jit/metainterp/test/support.py
+++ b/pypy/jit/metainterp/test/support.py
@@ -159,6 +159,9 @@
         get_stats().check_resops(expected=expected, **check)
     def check_simple_loop(self, expected=None, **check):
         get_stats().check_simple_loop(expected=expected, **check)
+    def check_retraced_simple_loop(self, count, expected=None, **check):
+        get_stats().check_retraced_simple_loop(count, expected=expected, **check)
+
 
     
 
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -3022,6 +3022,50 @@
         res = self.meta_interp(f, [32])
         assert res == f(32)
 
+    def test_nested_loops(self):
+        class Int(object):
+            def __init__(self, val):
+                self.val = val
+        bytecode = "iajb+JI"
+        def get_printable_location(i):
+            return "%d: %s" % (i, bytecode[i])
+        myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'sa', 'c', 'i', 'j'],
+                                get_printable_location=get_printable_location)
+        def f(n):
+            pc = sa = 0
+            i = j = Int(0)
+            c = Int(n)
+            while pc < len(bytecode):
+                myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i, j=j, c=c)
+                op = bytecode[pc]
+                if op == 'i':
+                    i = Int(1)
+                elif op == 'j':
+                    j = Int(1) # FIXME: test with 0 aswell
+                elif op == '+':
+                    sa += 3 * i.val + j.val + 5 * c.val
+                elif op == 'a':
+                    i = Int(i.val + 1)
+                elif op == 'b':
+                    j = Int(j.val + 1)
+                elif op == 'J':
+                    if j.val < n:
+                        pc -= 2
+                        myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i, j=j, c=c)
+                        continue
+                elif op == 'I':
+                    if i.val < n:
+                        pc -= 5
+                        myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i, j=j, c=c)
+                        continue
+                pc += 1
+            return sa
+        res = self.meta_interp(f, [10])
+        assert res == f(10)
+        self.check_resops(new_with_vtable=0)
+        self.check_retraced_simple_loop(2, getfield_gc=0)
+
+
 
 class TestOOtype(BasicTests, OOJitMixin):
 


More information about the pypy-commit mailing list