[pypy-commit] pypy default: Detect and special-case in the JIT the greater-than kind of comparisons

arigo noreply at buildbot.pypy.org
Mon Sep 1 12:04:09 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r73265:8b404466566d
Date: 2014-09-01 12:03 +0200
http://bitbucket.org/pypy/pypy/changeset/8b404466566d/

Log:	Detect and special-case in the JIT the greater-than kind of
	comparisons between two single characters (or unichars).

diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -36,6 +36,7 @@
     OS_STREQ_NONNULL_CHAR       = 29   # s1 == char  (assert s1!=NULL)
     OS_STREQ_CHECKNULL_CHAR     = 30   # s1!=NULL and s1==char
     OS_STREQ_LENGTHOK           = 31   # s1 == s2    (assert len(s1)==len(s2))
+    OS_STR_CMP                  = 32   # "stroruni.cmp"
     #
     OS_UNI_CONCAT               = 42   #
     OS_UNI_SLICE                = 43   #
@@ -47,6 +48,7 @@
     OS_UNIEQ_NONNULL_CHAR       = 49   #   (must be the same amount as for
     OS_UNIEQ_CHECKNULL_CHAR     = 50   #   STR, in the same order)
     OS_UNIEQ_LENGTHOK           = 51   #
+    OS_UNI_CMP                  = 52
     _OS_offset_uni              = OS_UNI_CONCAT - OS_STR_CONCAT
     #
     OS_LIBFFI_CALL              = 62
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1767,6 +1767,7 @@
             dict = {"stroruni.concat": EffectInfo.OS_STR_CONCAT,
                     "stroruni.slice":  EffectInfo.OS_STR_SLICE,
                     "stroruni.equal":  EffectInfo.OS_STR_EQUAL,
+                    "stroruni.cmp":    EffectInfo.OS_STR_CMP,
                     "stroruni.copy_string_to_raw": EffectInfo.OS_STR_COPY_TO_RAW,
                     }
             CHR = lltype.Char
@@ -1774,6 +1775,7 @@
             dict = {"stroruni.concat": EffectInfo.OS_UNI_CONCAT,
                     "stroruni.slice":  EffectInfo.OS_UNI_SLICE,
                     "stroruni.equal":  EffectInfo.OS_UNI_EQUAL,
+                    "stroruni.cmp":    EffectInfo.OS_UNI_CMP,
                     "stroruni.copy_string_to_raw": EffectInfo.OS_UNI_COPY_TO_RAW
                     }
             CHR = lltype.UniChar
diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py
--- a/rpython/jit/metainterp/optimizeopt/vstring.py
+++ b/rpython/jit/metainterp/optimizeopt/vstring.py
@@ -733,6 +733,25 @@
             return True
         return False
 
+    def opt_call_stroruni_STR_CMP(self, op, mode):
+        v1 = self.getvalue(op.getarg(1))
+        v2 = self.getvalue(op.getarg(2))
+        l1box = v1.getstrlen(None, mode, None)
+        l2box = v2.getstrlen(None, mode, None)
+        if (l1box is not None and l2box is not None and
+            isinstance(l1box, ConstInt) and
+            isinstance(l2box, ConstInt) and
+            l1box.value == l2box.value == 1):
+            # comparing two single chars
+            vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode)
+            vchar2 = self.strgetitem(v2, optimizer.CVAL_ZERO, mode)
+            seo = self.optimizer.send_extra_operation
+            seo(ResOperation(rop.INT_SUB, [vchar1.force_box(self),
+                                           vchar2.force_box(self)],
+                             op.result))
+            return True
+        return False
+
     def opt_call_SHRINK_ARRAY(self, op):
         v1 = self.getvalue(op.getarg(1))
         v2 = self.getvalue(op.getarg(2))
diff --git a/rpython/jit/metainterp/test/test_string.py b/rpython/jit/metainterp/test/test_string.py
--- a/rpython/jit/metainterp/test/test_string.py
+++ b/rpython/jit/metainterp/test/test_string.py
@@ -846,6 +846,27 @@
             'jump': 1, 'guard_true': 2, 'int_ge': 2, 'int_add': 2, 'int_sub': 2
         })
 
+    def test_compare_single_char_for_ordering(self):
+        jitdriver = JitDriver(reds=['result', 'n'], greens=[])
+        _str = self._str
+        constant1 = _str("abcdefghij")
+
+        def cmpstr(x, y):
+            return x > _str(y)
+
+        def f(n):
+            cmpstr(_str("abc"), "def")  # force x and y to be annot as strings
+            result = 0
+            while n >= 0:
+                jitdriver.jit_merge_point(n=n, result=result)
+                c = constant1[n]
+                result += cmpstr(c, "c")
+                n -= 1
+            return result
+
+        res = self.meta_interp(f, [9])
+        assert res == f(9)
+        self.check_resops(newstr=0, newunicode=0, call=0)
 
 
 class TestLLtype(StringTests, LLJitMixin):
diff --git a/rpython/rtyper/lltypesystem/rstr.py b/rpython/rtyper/lltypesystem/rstr.py
--- a/rpython/rtyper/lltypesystem/rstr.py
+++ b/rpython/rtyper/lltypesystem/rstr.py
@@ -531,6 +531,7 @@
                 return diff
             i += 1
         return len1 - len2
+    ll_strcmp.oopspec = 'stroruni.cmp(s1, s2)'
 
     @jit.elidable
     def ll_streq(s1, s2):


More information about the pypy-commit mailing list