Author: Carl Friedrich Bolz <cfb...@gmx.de>
Branch: guard-compatible
Changeset: r83003:818cabf99bbf
Date: 2016-03-12 23:02 +0100
http://bitbucket.org/pypy/pypy/changeset/818cabf99bbf/

Log:    in-progress: tracing support for guard_compatible, also some
        sketched code for how failures and checking of the conditions would
        work. needs proper integration with the backends

diff --git a/rpython/jit/backend/llgraph/runner.py 
b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -50,7 +50,7 @@
         self.operations = []
         for op in operations:
             opnum = op.getopnum()
-            if opnum == rop.GUARD_VALUE:
+            if opnum == rop.GUARD_VALUE or opnum == rop.GUARD_COMPATIBLE:
                 # we don't care about the value 13 here, because we gonna
                 # fish it from the extra slot on frame anyway
                 op.getdescr().make_a_counter_per_value(op, 13)
@@ -1271,6 +1271,12 @@
         if self.lltrace.invalid:
             self.fail_guard(descr)
 
+    def execute_guard_compatible(self, descr, arg1, arg2):
+        if arg1 != arg2:
+            if descr.fake_check_against_list(self.cpu, arg1):
+                return
+            self.fail_guard(descr, extra_value=arg1)
+
     def execute_int_add_ovf(self, _, x, y):
         try:
             z = ovfcheck(x + y)
diff --git a/rpython/jit/metainterp/blackhole.py 
b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -582,6 +582,10 @@
     def bhimpl_str_guard_value(a, i, d):
         return a
 
+    @arguments("r")
+    def bhimpl_ref_guard_compatible(a):
+        pass
+
     @arguments("self", "i")
     def bhimpl_int_push(self, a):
         self.tmpreg_i = a
diff --git a/rpython/jit/metainterp/compatible.py 
b/rpython/jit/metainterp/compatible.py
--- a/rpython/jit/metainterp/compatible.py
+++ b/rpython/jit/metainterp/compatible.py
@@ -1,5 +1,51 @@
 from rpython.jit.metainterp.history import newconst
 
+def do_call(cpu, argboxes, descr):
+    from rpython.jit.metainterp.history import INT, REF, FLOAT, VOID
+    from rpython.jit.metainterp.blackhole import NULL
+    # XXX XXX almost copy from executor.py
+    rettype = descr.get_result_type()
+    # count the number of arguments of the different types
+    count_i = count_r = count_f = 0
+    for i in range(1, len(argboxes)):
+        type = argboxes[i].type
+        if   type == INT:   count_i += 1
+        elif type == REF:   count_r += 1
+        elif type == FLOAT: count_f += 1
+    # allocate lists for each type that has at least one argument
+    if count_i: args_i = [0] * count_i
+    else:       args_i = None
+    if count_r: args_r = [NULL] * count_r
+    else:       args_r = None
+    if count_f: args_f = [longlong.ZEROF] * count_f
+    else:       args_f = None
+    # fill in the lists
+    count_i = count_r = count_f = 0
+    for i in range(1, len(argboxes)):
+        box = argboxes[i]
+        if   box.type == INT:
+            args_i[count_i] = box.getint()
+            count_i += 1
+        elif box.type == REF:
+            args_r[count_r] = box.getref_base()
+            count_r += 1
+        elif box.type == FLOAT:
+            args_f[count_f] = box.getfloatstorage()
+            count_f += 1
+    # get the function address as an integer
+    func = argboxes[0].getint()
+    # do the call using the correct function from the cpu
+    if rettype == INT:
+        return newconst(cpu.bh_call_i(func, args_i, args_r, args_f, descr))
+    if rettype == REF:
+        return newconst(cpu.bh_call_r(func, args_i, args_r, args_f, descr))
+    if rettype == FLOAT:
+        return newconst(cpu.bh_call_f(func, args_i, args_r, args_f, descr))
+    if rettype == VOID:
+        # don't even need to call the void function, result will always match
+        return None
+    raise AssertionError("bad rettype")
+
 class CompatibilityCondition(object):
     """ A collections of conditions that an object needs to fulfil. """
     def __init__(self, ptr):
@@ -8,3 +54,14 @@
 
     def record_pure_call(self, op, res):
         self.pure_call_conditions.append((op, res))
+
+    def check_compat(self, cpu, ref):
+        for op, correct_res in self.pure_call_conditions:
+            calldescr = op.getdescr()
+            # change exactly the first argument
+            arglist = op.getarglist()
+            arglist[1] = newconst(ref)
+            res = do_call(cpu, arglist, calldescr)
+            if not res.same_constant(correct_res):
+                return False
+        return True
diff --git a/rpython/jit/metainterp/compile.py 
b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -810,7 +810,7 @@
                                metainterp.box_names_memo)
 
     def make_a_counter_per_value(self, guard_value_op, index):
-        assert guard_value_op.getopnum() == rop.GUARD_VALUE
+        assert guard_value_op.getopnum() in (rop.GUARD_VALUE, 
rop.GUARD_COMPATIBLE)
         box = guard_value_op.getarg(0)
         if box.type == history.INT:
             ty = self.TY_INT
@@ -929,6 +929,11 @@
             resumedescr = ResumeGuardCopiedExcDescr()
         else:
             resumedescr = ResumeGuardExcDescr()
+    elif opnum == rop.GUARD_COMPATIBLE:
+        if copied_guard:
+            import pdb; pdb.set_trace()
+        else:
+            resumedescr = GuardCompatibleDescr()
     else:
         if copied_guard:
             resumedescr = ResumeGuardCopiedDescr()
@@ -1078,6 +1083,50 @@
     metainterp.retrace_needed(new_trace, info)
     return None
 
+class GuardCompatibleDescr(ResumeGuardDescr):
+    """ A descr for guard_compatible. All the conditions that a value should
+    fulfil need to be attached to this descr by optimizeopt. """
+
+    def __init__(self):
+        # XXX for now - in the end this would be in assembler
+        self._checked_ptrs = []
+        self._compatibility_conditions = None
+
+    def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
+        index = intmask(self.status >> self.ST_SHIFT)
+        typetag = intmask(self.status & self.ST_TYPE_MASK)
+        assert typetag == self.TY_REF # for now
+        refval = metainterp_sd.cpu.get_value_direct(deadframe, 'r', index)
+        if self.is_compatible(metainterp_sd.cpu, refval):
+            from rpython.jit.metainterp.blackhole import resume_in_blackhole
+            # next time it'll pass XXX use new cpu thingie here
+            self._checked_ptrs.append(history.newconst(refval))
+            resume_in_blackhole(metainterp_sd, jitdriver_sd, self, deadframe)
+        else:
+            # a real failure
+            return ResumeGuardDescr.handle_fail(self, deadframe, 
metainterp_sd, jitdriver_sd)
+
+    def fake_check_against_list(self, cpu, ref):
+        # XXX should be in assembler
+        const = history.newconst(ref)
+        if self._compatibility_conditions:
+            for i in range(len(self._checked_ptrs)):
+                if const.same_constant(self._checked_ptrs[i]):
+                    return True
+        return False
+
+    def is_compatible(self, cpu, ref):
+        const = history.newconst(ref)
+        if self._compatibility_conditions:
+            for i in range(len(self._checked_ptrs)):
+                if const.same_constant(self._checked_ptrs[i]):
+                    return True
+            if self._compatibility_conditions.check_compat(cpu, ref):
+                self._checked_ptrs.append(const)
+                return True
+            return False
+        return True # no conditions, everything works
+
 # ____________________________________________________________
 
 memory_error = MemoryError()
diff --git a/rpython/jit/metainterp/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1200,6 +1200,16 @@
     opimpl_float_guard_value = _opimpl_guard_value
 
     @arguments("box", "orgpc")
+    def opimpl_ref_guard_compatible(self, box, orgpc):
+        if isinstance(box, Const):
+            return box     # no promotion needed, already a Const
+        else:
+            promoted_box = executor.constant_from_op(box)
+            self.metainterp.generate_guard(rop.GUARD_COMPATIBLE, box, 
[promoted_box],
+                                           resumepc=orgpc)
+            # importantly, there is no replace_box here!
+
+    @arguments("box", "orgpc")
     def opimpl_guard_class(self, box, orgpc):
         clsbox = self.cls_of_box(box)
         if not self.metainterp.heapcache.is_class_known(box):
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
@@ -1049,6 +1049,7 @@
     'GUARD_NOT_FORCED_2/0d/n',    # same as GUARD_NOT_FORCED, but for finish()
     'GUARD_NOT_INVALIDATED/0d/n',
     'GUARD_FUTURE_CONDITION/0d/n',
+    'GUARD_COMPATIBLE/2d/n',
     # is removable, may be patched by an optimization
     '_GUARD_LAST', # ----- end of guard operations -----
 
diff --git a/rpython/jit/metainterp/test/test_compatible.py 
b/rpython/jit/metainterp/test/test_compatible.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/metainterp/test/test_compatible.py
@@ -0,0 +1,35 @@
+from rpython.jit.metainterp.test.support import LLJitMixin
+from rpython.rlib import jit
+from rpython.rtyper.lltypesystem import lltype, rffi
+
+
+class TestCompatible(LLJitMixin):
+    def test_simple(self):
+        S = lltype.GcStruct('S', ('x', lltype.Signed))
+        p1 = lltype.malloc(S)
+        p1.x = 5
+
+        p2 = lltype.malloc(S)
+        p2.x = 5
+
+        p3 = lltype.malloc(S)
+        p3.x = 6
+        driver = jit.JitDriver(greens = [], reds = ['n', 'x'])
+        @jit.elidable_compatible()
+        def g(s):
+            return s.x
+
+        def f(n, x):
+            while n > 0:
+                driver.can_enter_jit(n=n, x=x)
+                driver.jit_merge_point(n=n, x=x)
+                n -= g(x)
+
+        def main():
+            f(100, p1)
+            f(100, p2)
+            f(100, p3)
+
+        self.meta_interp(main, [])
+        # XXX check number of bridges
+
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to