Commits

Armin Rigo committed 432e12a

in-progress

Comments (0)

Files changed (6)

pypy/jit/backend/llgraph/runner.py

 from pypy.jit.backend.llgraph import support
 from pypy.jit.metainterp.history import AbstractDescr
 from pypy.jit.metainterp.resoperation import Const, getkind
-from pypy.jit.metainterp.resoperation import INT, REF, FLOAT, VOID
+from pypy.jit.metainterp.resoperation import INT, REF, FLOAT, VOID, FLOAT_SIZE
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.codewriter import longlong, heaptracker
 from pypy.jit.codewriter.effectinfo import EffectInfo
                                        map(mapping, op.getarglist()),
                                        mapping(op.result),
                                        newdescr)
-            if op.getfailargs() is not None:
-                newop.setfailargs(map(mapping, op.getfailargs()))
             self.operations.append(newop)
 
 class WeakrefDescr(AbstractDescr):
         self.realdescrref = weakref.ref(realdescr)
 
 class GuardFailed(Exception):
-    def __init__(self, failargs, descr):
-        self.failargs = failargs
+    def __init__(self, descr):
         self.descr = descr
 
 class ExecutionFinished(Exception):
-    def __init__(self, descr, arg, failargs):
+    def __init__(self, descr, arg):
         self.descr = descr
         self.arg = arg
-        self.failargs = failargs
 
 class Jump(Exception):
     def __init__(self, descr, args):
             assert False
         except ExecutionFinished, e:
             frame.finish_value = e.arg
-            frame.latest_values = e.failargs
             frame.latest_descr = e.descr
             frame._execution_finished_normally = e.descr.fast_path_done
             return frame
         except GuardFailed, e:
-            frame.latest_values = e.failargs
             frame.latest_descr = e.descr
             return frame
 
-    def get_latest_value_int(self, frame, index):
-        return frame.latest_values[index]
-    get_latest_value_float = get_latest_value_int
-    get_latest_value_ref   = get_latest_value_int
-
-    def get_latest_value_count(self, frame):
-        return len(frame.latest_values)
+    def get_frame_value_int(self, frame, index):
+        return frame.framecontent[index]
+    get_frame_value_float = get_frame_value_int
+    get_frame_value_ref   = get_frame_value_int
 
     def get_latest_descr(self, frame):
         return frame.latest_descr
     
     def __init__(self, cpu, argboxes, args):
         self.env = {}
+        self.framecontent = {}
         self.cpu = cpu
         assert len(argboxes) == len(args)
         for box, arg in zip(argboxes, args):
-            self.env[box] = arg
+            self.setenv(box, arg)
         self.overflow_flag = False
         self.last_exception = None
 
+    def setenv(self, box, arg):
+        self.env[box] = arg
+        self.framecontent[box.getvarindex()] = arg
+        if box.type == FLOAT and FLOAT_SIZE > 1:
+            self.framecontent[box.getvarindex() + 1] = '2nd float word'
+
     def lookup(self, arg):
         if isinstance(arg, Const):
             return arg.value
-        return self.env[arg]
+        result = self.env[arg]
+        assert result is self.framecontent[arg.getvarindex()]
+        return result
 
     def execute(self, lltrace):
         self.lltrace = lltrace
                 if hasattr(gf.descr, '_llgraph_bridge'):
                     i = 0
                     self.lltrace = gf.descr._llgraph_bridge
-                    newargs = [self.env[arg] for arg in
-                              self.current_op.getfailargs() if arg is not None]
-                    self.do_renaming(self.lltrace.inputargs, newargs)
+                    newvals = [self.env[arg] for arg in self.lltrace.inputargs]
+                    self.do_renaming(self.lltrace.inputargs, newvals)
                     continue
                 raise
             if op.type == INT:
             else:
                 assert op.type == VOID
                 assert resval is None
-            self.env[op] = resval
+            if op.type != VOID:
+                self.setenv(op, resval)
             i += 1
 
-    def _getfailargs(self, op=None, skip=None):
-        if op is None:
-            op = self.current_op
-        r = []
-        for arg in op.getfailargs():
-            if arg is None:
-                r.append(None)
-            elif arg is skip:
-                r.append(_example_res[skip.type])
-            else:
-                r.append(self.env[arg])
-        return r
-
-    def do_renaming(self, newargs, oldargs):
-        assert len(newargs) == len(oldargs)
-        newenv = {}
-        for new, old in zip(newargs, oldargs):
-            newenv[new] = old
-        self.env = newenv
+    def do_renaming(self, newargs, newvalues):
+        assert len(newargs) == len(newvalues)
+        self.env = {}
+        self.framecontent = {}
+        for new, newvalue in zip(newargs, newvalues):
+            self.setenv(new, newvalue)
 
     # -----------------------------------------------------
 
     def fail_guard(self, descr):
-        raise GuardFailed(self._getfailargs(), descr)
+        raise GuardFailed(descr)
 
     def execute_force_spill(self, _, arg):
         pass
 
     def execute_finish(self, descr, arg=None):
-        if self.current_op.getfailargs() is not None:
-            failargs = self._getfailargs()
-        else:
-            failargs = None   # compatibility
-        raise ExecutionFinished(descr, arg, failargs)
+        raise ExecutionFinished(descr, arg)
 
     def execute_label(self, descr, *args):
         argboxes = self.current_op.getarglist()
         call_op = self.lltrace.operations[self.current_index]
         guard_op = self.lltrace.operations[self.current_index + 1]
         assert guard_op.getopnum() == rop.GUARD_NOT_FORCED
+        XXX
         self.latest_values = self._getfailargs(guard_op, skip=call_op)
         self.latest_descr = _getdescr(guard_op)
         res = self.execute_call(calldescr, func, *args)
         call_op = self.lltrace.operations[self.current_index]
         guard_op = self.lltrace.operations[self.current_index + 1]
         assert guard_op.getopnum() == rop.GUARD_NOT_FORCED
+        XXX
         self.latest_values = self._getfailargs(guard_op, skip=call_op)
         self.latest_descr = _getdescr(guard_op)
         #

pypy/jit/backend/model.py

         Execute the generated code referenced by the looptoken.
         It runs it until either a guard fails, or until we reach
         the FINISH operation.  It returns the "jit frame" object
-        which should be inspected with the get_latest_xyz() methods.
+        which should be inspected with the get_frame_value_xyz() methods.
         """
         argtypes = [lltype.typeOf(x) for x in args]
         execute = self.make_execute_token(*argtypes)
         jitframe."""
         raise NotImplementedError
 
-    def get_latest_value_int(self, jitframe, index):
-        """Returns the value for the index'th 'fail_args' of the
-        last executed operation.  Returns an int."""
+    def get_frame_value_int(self, jitframe, index):
+        """Returns the value for the index'th value in the frame.
+        Returns an int."""
         raise NotImplementedError
 
-    def get_latest_value_float(self, jitframe, index):
-        """Returns the value for the index'th 'fail_args' of the
-        last executed operation.  Returns a FLOATSTORAGE."""
+    def get_frame_value_float(self, jitframe, index):
+        """Returns the value for the index'th value in the frame.
+        Returns a FLOATSTORAGE."""
         raise NotImplementedError
 
-    def get_latest_value_ref(self, jitframe, index):
-        """Returns the value for the index'th 'fail_args' of the
-        last executed operation.  Returns a GCREF."""
-        raise NotImplementedError
-
-    def get_latest_value_count(self, jitframe):
-        """Return how many values are ready to be returned by
-        get_latest_value_xxx()."""
+    def get_frame_value_ref(self, jitframe, index):
+        """Returns the value for the index'th value in the frame.
+        Returns a GCREF."""
         raise NotImplementedError
 
     def get_finish_value_int(self, jitframe):

pypy/jit/backend/test/runner_test.py

 
     avoid_instances = False
 
-    def parse(self, s, namespace):
+    def parse(self, s, namespace, invent_varindex=True):
         if namespace is None:
             namespace = {}
         else:
             namespace['faildescr3'] = BasicFailDescr(3)
         if 'faildescr4' not in namespace:
             namespace['faildescr4'] = BasicFailDescr(4)
-        loop = oparser.parse(s, namespace=namespace, guards_with_failargs=True)
+        loop = oparser.parse(s, namespace=namespace, mutable=True,
+                             vars=getattr(self, 'original_vars', {}))
+        self.original_vars = loop.original_vars
         return loop.inputargs, loop.operations, JitCellToken()
 
+    def get_frame_value(self, frame, varname):
+        op = self.original_vars[varname]
+        index = op.getvarindex()
+        if varname.startswith('i'):
+            return self.cpu.get_frame_value_int(frame, index)
+        if varname.startswith('p'):
+            return self.cpu.get_frame_value_ref(frame, index)
+        if varname.startswith('f'):
+            return self.cpu.get_frame_value_float(frame, index)
+        raise ValueError(varname)
+
     def test_compile_linear_loop(self):
         faildescr = BasicFailDescr(1)
         inputargs, ops, token = self.parse("""
         [i0]
         i1 = int_add(i0, 1)
-        finish(i1, descr=faildescr) []
+        finish(i1, descr=faildescr)
         """, namespace=locals())
         self.cpu.compile_loop(inputargs, ops, token)
         frame = self.cpu.execute_token(token, 2)
         inputargs, ops, token = self.parse("""
         [f0]
         f1 = float_add(f0, 1.)
-        finish(f1, descr=faildescr) []
+        finish(f1, descr=faildescr)
         """, namespace=locals())
         self.cpu.compile_loop(inputargs, ops, token)
         frame = self.cpu.execute_token(token, longlong.getfloatstorage(2.8))
         label(i0, descr=targettoken)
         i1 = int_add(i0, 1)
         i2 = int_le(i1, 9)
-        guard_true(i2, descr=faildescr) [i1]
+        guard_true(i2, descr=faildescr)
         jump(i1, descr=targettoken)
         ''', namespace=locals())
         self.cpu.compile_loop(inputargs, operations, looptoken)
         frame = self.cpu.execute_token(looptoken, 2)
         assert self.cpu.get_latest_descr(frame).identifier == 2
-        res = self.cpu.get_latest_value_int(frame, 0)
+        res = self.get_frame_value(frame, 'i1')
         assert res == 10
 
-    def test_compile_with_holes_in_fail_args(self):
+    def test_compile_loop_2(self):
         faildescr3 = BasicFailDescr(3)
         targettoken = TargetToken()
         inputargs, operations, looptoken = self.parse("""
         label(i0, descr=targettoken)
         i1 = int_add(i0, 1)
         i2 = int_le(i1, 9)
-        guard_true(i2, descr=faildescr3) [None, None, i1, None]
+        guard_true(i2, descr=faildescr3)
         jump(i1, descr=targettoken)
         """, namespace=locals())
 
         self.cpu.compile_loop(inputargs, operations, looptoken)
         frame = self.cpu.execute_token(looptoken, 44)
         assert self.cpu.get_latest_descr(frame).identifier == 3
-        res = self.cpu.get_latest_value_int(frame, 2)
+        res = self.get_frame_value(frame, 'i1')
         assert res == 10
 
     def test_backends_dont_keep_loops_alive(self):
         label(i0, descr=targettoken)
         i1 = int_add(i0, 1)
         i2 = int_le(i1, 9)
-        guard_true(i2, descr=faildescr) [i1]
+        guard_true(i2, descr=faildescr)
         jump(i1, descr=targettoken)
         """, namespace={'targettoken': TargetToken()})
         i1 = inputargs[0]
         label(i0, descr=targettoken)
         i1 = int_add(i0, 1)
         i2 = int_le(i1, 9)
-        guard_true(i2, descr=faildescr) [i1]
+        guard_true(i2, descr=faildescr)
         jump(i1, descr=targettoken)
         """, namespace={'faildescr': faildescr4,
                         'targettoken': targettoken})
         self.cpu.compile_loop(inputargs, operations, looptoken)
 
         inputargs, bridge_ops, _ = self.parse("""
-        [i1b]
-        i3 = int_le(i1b, 19)
-        guard_true(i3, descr=faildescr5) [i1b]
-        jump(i1b, descr=targettoken)
+        [i1]
+        i3 = int_le(i1, 19)
+        guard_true(i3, descr=faildescr5)
+        jump(i1, descr=targettoken)
         """, namespace={'faildescr5': BasicFailDescr(5),
                         'targettoken': targettoken})
         self.cpu.compile_bridge(faildescr4,

pypy/jit/metainterp/optmodel.py

 
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.jit.metainterp.resoperation import opclasses, opclasses_mutable, rop,\
-     INT, REF, ConstInt, Const
+     VOID, INT, REF, ConstInt, Const
 from pypy.jit.metainterp.optimizeopt.intutils import ImmutableIntUnbounded,\
      ConstantIntBound
 
                 else:
                     def force(self, _):
                         return self
-            if cls.is_guard() or cls.getopnum() == rop.FINISH:
-                addattr(Mutable, 'failargs')
+            if cls.type != VOID:
+                addattr(Mutable, 'varindex', -1)
+                #if cls.type == REF:
+                #    addattr(Mutable, 'varrange', sys.maxint // 2)
             if cls.is_guard():
                 addattr(Mutable, 'descr') # mutable guards have descrs
             if cls.type == INT:

pypy/jit/metainterp/resoperation.py

 
 """
 
+import sys
 from pypy.jit.codewriter import longlong
 from pypy.jit.codewriter import heaptracker
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 VOID  = 'v'
 HOLE = '_'
 
+if sys.maxint == 2**31 - 1:
+    FLOAT_SIZE = 2         # a FLOAT variable uses two INT or REF positions
+else:
+    FLOAT_SIZE = 1         # FLOAT is the same size as INT and REF
+
+
 def create_resop_dispatch(opnum, result, args, descr=None, mutable=False):
     """ NOT_RPYTHON this is for tests only!
     """
                 t = 'i'
             elif self.type == FLOAT:
                 t = 'f'
+            elif self.type == REF:
+                t = 'p'
             else:
-                t = 'p'
-            self._str = '%s%d' % (t, AbstractResOp._counter)
-            AbstractResOp._counter += 1
+                t = '?'
+            if not hasattr(self, '_varindex'):
+                self._str = '%s%d' % (t, AbstractResOp._counter)
+                AbstractResOp._counter += 1
+            else:
+                self._str = '%s%s' % (t.upper(), self._varindex)
         return self._str
 
     def repr(self, graytext=False):

pypy/jit/tool/oparser.py

     use_mock_model = False
 
     def __init__(self, input, cpu, namespace, type_system,
-                 invent_fail_descr=True, results=None,
-                 guards_with_failargs=False):
+                 invent_fail_descr=True, results=None, mutable=False, vars={}):
         self.input = input
-        self.vars = {}
+        self.vars = vars.copy()
         self.cpu = cpu
         self._consts = namespace
         self.type_system = type_system
-        self.guards_with_failargs = guards_with_failargs
-        if namespace is not None:
-            self._cache = namespace.setdefault('_CACHE_', {})
-        else:
-            self._cache = {}
         self.invent_fail_descr = invent_fail_descr
         self.model = get_model(self.use_mock_model)
         self.original_jitcell_token = self.model.JitCellToken()
         self.results = results
+        self.mutable = mutable
 
     def get_const(self, name, typ):
         if self._consts is None:
                 return tt
             raise
 
-    def box_for_var(self, elem):
-        try:
-            return self._cache[self.type_system, elem]
-        except KeyError:
-            pass
-        if elem[0] in 'ifp':
-            if elem[0] == 'p':
-                p = 'r'
-            else:
-                p = elem[0]
-            opnum = getattr(rop, 'INPUT_' + p)
-            box = create_resop_0(opnum, example_for_opnum(opnum))
-        else:
-            raise ParseError("Unknown variable type: %s" % elem)
-        self._cache[self.type_system, elem] = box
-        box._str = elem
-        return box
-
     def parse_header_line(self, line):
         elements = line.split(",")
         vars = []
         return vars
 
     def newvar(self, elem):
-        box = self.box_for_var(elem)
-        self.vars[elem] = box
-        return box
+        if elem not in self.vars:
+            if elem[0] in 'ifp':
+                if elem[0] == 'p':
+                    p = 'r'
+                else:
+                    p = elem[0]
+                opnum = getattr(rop, 'INPUT_' + p)
+                box = create_resop_0(opnum, example_for_opnum(opnum),
+                                     mutable=self.mutable)
+            else:
+                raise ParseError("Unknown variable type: %s" % elem)
+            self.setstr(box, elem)
+            self.vars[elem] = box
+        return self.vars[elem]
+
+    def setstr(self, op, text):
+        if hasattr(op, 'setvarindex') and text[1:].isdigit():
+            op.setvarindex(int(text[1:]))
+        else:
+            op._res = text
 
     def is_float(self, arg):
         try:
         endnum = line.rfind(')')
         if endnum == -1:
             raise ParseError("invalid line: %s" % line)
+        if line.find('[', endnum) >= 0:
+            raise ParseError("fail_args should be removed: %s" % line)
         args, descr = self.parse_args(opname, line[num + 1:endnum])
-        fail_args = None
-        if rop._GUARD_FIRST <= opnum <= rop._GUARD_LAST or opnum == rop.FINISH:
-            i = line.find('[', endnum) + 1
-            j = line.find(']', i)
-            if i <= 0 or j <= 0:
-                if self.guards_with_failargs and opnum != rop.FINISH:
-                    raise ParseError("missing fail_args for guard operation")
-                fail_args = None
-            else:
-                if not self.guards_with_failargs:
-                    raise ParseError("fail_args should be NULL")
-                fail_args = []
-                if i < j:
-                    for arg in line[i:j].split(','):
-                        arg = arg.strip()
-                        if arg == 'None':
-                            fail_arg = None
-                        else:
-                            try:
-                                fail_arg = self.vars[arg]
-                            except KeyError:
-                                raise ParseError(
-                                    "Unknown var in fail_args: %s" % arg)
-                        fail_args.append(fail_arg)
-        else:
-            if opnum == rop.FINISH:
-                if descr is None and self.invent_fail_descr:
-                    descr = self.invent_fail_descr(self.model, fail_args)
-            elif opnum == rop.JUMP:
-                if descr is None and self.invent_fail_descr:
-                    descr = self.original_jitcell_token
-
-        return opnum, args, descr, fail_args
+        if descr is None and opnum == rop.JUMP:
+            descr = self.original_jitcell_token
+        return opnum, args, descr
 
     def create_op(self, opnum, result, args, descr):
-        r = create_resop_dispatch(opnum, result, args,
-                                  mutable=self.guards_with_failargs)
+        r = create_resop_dispatch(opnum, result, args, mutable=self.mutable)
         if descr is not None:
             r.setdescr(descr)
         return r
         res, op = line.split("=", 1)
         res = res.strip()
         op = op.strip()
-        opnum, args, descr, fail_args = self.parse_op(op)
+        opnum, args, descr = self.parse_op(op)
         if res in self.vars:
             raise ParseError("Double assign to var %s in line: %s" % (res, line))
         if self.results is None:
         else:
             result = self.results[num]
         opres = self.create_op(opnum, result, args, descr)
+        self.setstr(opres, res)
         self.vars[res] = opres
-        if fail_args is not None:
-            opres.setfailargs(fail_args)
         return opres
 
     def parse_op_no_result(self, line):
-        opnum, args, descr, fail_args = self.parse_op(line)
+        opnum, args, descr = self.parse_op(line)
         res = self.create_op(opnum, None, args, descr)
-        if fail_args is not None:
-            res.setfailargs(fail_args)
         return res
 
     def parse_next_op(self, line, num):
         loop.operations = ops
         loop.inputargs = inpargs
         loop.last_offset = last_offset
+        loop.original_vars = self.vars
         return loop
 
     def parse_ops(self, indent, lines, start):
 
 def parse(input, cpu=None, namespace=DEFAULT, type_system='lltype',
           invent_fail_descr=True, OpParser=OpParser,
-          results=None, guards_with_failargs=False):
+          results=None, mutable=False, vars={}):
     if namespace is DEFAULT:
         namespace = {}
     return OpParser(input, cpu, namespace, type_system,
-                    invent_fail_descr, results, guards_with_failargs).parse()
+                    invent_fail_descr, results, mutable, vars).parse()
 
 def pure_parse(*args, **kwds):
     kwds['invent_fail_descr'] = False