[pypy-svn] pypy str-cmp-opt: Turn a call to strcmp where both strings are known lenght 1 into a subtraction.

alex_gaynor commits-noreply at bitbucket.org
Mon Mar 14 17:00:01 CET 2011


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: str-cmp-opt
Changeset: r42613:82a6054c3316
Date: 2011-03-14 11:59 -0400
http://bitbucket.org/pypy/pypy/changeset/82a6054c3316/

Log:	Turn a call to strcmp where both strings are known lenght 1 into a
	subtraction.

diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/string.py
--- a/pypy/jit/metainterp/optimizeopt/string.py
+++ b/pypy/jit/metainterp/optimizeopt/string.py
@@ -370,7 +370,7 @@
     def reconstruct_for_next_iteration(self, optimizer, valuemap):
         self.enabled = True
         return self
-    
+
     def make_vstring_plain(self, box, source_op, mode):
         vvalue = VStringPlainValue(self.optimizer, box, source_op, mode)
         self.make_equal_to(box, vvalue)
@@ -640,6 +640,27 @@
             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)
+        l2box = v2.getstrlen(None, mode)
+        if (l1box is not None and l2box is not None and
+            isinstance(l1box, ConstInt) and isinstance(l2box, ConstInt) and
+            l1box.value == 1 and l2box.value == 1):
+
+            vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode)
+            vchar2 = self.strgetitem(v2, optimizer.CVAL_ZERO, mode)
+            self.optimizer.send_extra_operation(
+                ResOperation(
+                    rop.INT_SUB, [vchar1.force_box(), vchar2.force_box()], op.result
+                )
+            )
+            return True
+        return False
+
+
     def generate_modified_call(self, oopspecindex, args, result, mode):
         oopspecindex += mode.OS_offset
         cic = self.optimizer.metainterp_sd.callinfocollection
@@ -652,7 +673,7 @@
         if not self.enabled:
             self.emit_operation(op)
             return
-            
+
         opnum = op.getopnum()
         for value, func in optimize_ops:
             if opnum == value:

diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -30,6 +30,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
     #
     OS_UNI_CONCAT               = 42   #
     OS_UNI_SLICE                = 43   #
@@ -41,6 +42,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_PREPARE           = 60
@@ -87,7 +89,7 @@
         result = object.__new__(cls)
         result.readonly_descrs_fields = readonly_descrs_fields
         if extraeffect == EffectInfo.EF_LOOPINVARIANT or \
-           extraeffect == EffectInfo.EF_PURE:            
+           extraeffect == EffectInfo.EF_PURE:
             result.write_descrs_fields = []
             result.write_descrs_arrays = []
         else:

diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/test/test_optimizeutil.py
--- a/pypy/jit/metainterp/test/test_optimizeutil.py
+++ b/pypy/jit/metainterp/test/test_optimizeutil.py
@@ -122,7 +122,8 @@
         ('streq_nonnull_char_descr',     'OS_STREQ_NONNULL_CHAR'),
         ('streq_checknull_char_descr',   'OS_STREQ_CHECKNULL_CHAR'),
         ('streq_lengthok_descr',         'OS_STREQ_LENGTHOK'),
-        ]:
+        ('strcmpdescr',                  'OS_STR_CMP'),
+    ]:
         _oopspecindex = getattr(EffectInfo, _os)
         locals()[_name] = \
             cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
@@ -165,7 +166,7 @@
 ##    def get_class_of_box(self, box):
 ##        root = box.getref(ootype.ROOT)
 ##        return ootype.classof(root)
-    
+
 ##    cpu = runner.OOtypeCPU(None)
 ##    NODE = ootype.Instance('NODE', ootype.ROOT, {})
 ##    NODE._add_fields({'value': ootype.Signed,

diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py
--- a/pypy/rpython/lltypesystem/rstr.py
+++ b/pypy/rpython/lltypesystem/rstr.py
@@ -425,6 +425,7 @@
                 return diff
             i += 1
         return len1 - len2
+    ll_strcmp.oopspec = 'stroruni.cmp(s1, s2)'
 
     @purefunction
     def ll_streq(s1, s2):

diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -1268,12 +1268,14 @@
             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,
                     }
             CHR = lltype.Char
         elif SoU.TO == rstr.UNICODE:
             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,
                     }
             CHR = lltype.UniChar
         else:

diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -5464,6 +5464,26 @@
         """
         self.optimize_strunicode_loop_extradescrs(ops, expected)
 
+    def test_str_cmp_char(self):
+        ops = """
+        [i0]
+        p0 = newstr(1)
+        strsetitem(p0, 0, i0)
+        i1 = call(0, p0, s"0", descr=strcmpdescr)
+        i2 = int_le(i1, 0)
+        guard_true(i2) []
+        jump(i0)
+        """
+        expected = """
+        [i0]
+        # ord("0")
+        i1 = int_sub(i0, 48)
+        i2 = int_le(i1, 0)
+        guard_true(i2) []
+        jump(i0)
+        """
+        self.optimize_strunicode_loop_extradescrs(ops, expected)
+
     def test_str2unicode_constant(self):
         ops = """
         []


More information about the Pypy-commit mailing list