[pypy-commit] pypy default: Specialize str.{start, end}swith for char values at the RPython level, this makes long(), and inevitably other stuff generate considerably saner code.
alex_gaynor
noreply at buildbot.pypy.org
Mon Jul 11 23:58:33 CEST 2011
Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch:
Changeset: r45473:740fc1da78ad
Date: 2011-07-11 14:58 -0700
http://bitbucket.org/pypy/pypy/changeset/740fc1da78ad/
Log: Specialize str.{start,end}swith for char values at the RPython
level, this makes long(), and inevitably other stuff generate
considerably saner code.
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -16,27 +16,92 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i14 = int_lt(i6, i9)
- guard_true(i14, descr=<Guard42>)
+ guard_true(i14, descr=...)
+ guard_not_invalidated(descr=...)
i15 = int_mod(i6, i10)
i17 = int_rshift(i15, 63)
i18 = int_and(i10, i17)
i19 = int_add(i15, i18)
i21 = int_lt(i19, 0)
- guard_false(i21, descr=<Guard43>)
+ guard_false(i21, descr=...)
i22 = int_ge(i19, i10)
- guard_false(i22, descr=<Guard44>)
+ guard_false(i22, descr=...)
i23 = strgetitem(p11, i19)
i24 = int_ge(i19, i12)
- guard_false(i24, descr=<Guard45>)
+ guard_false(i24, descr=...)
i25 = unicodegetitem(p13, i19)
- guard_not_invalidated(descr=<Guard46>)
p27 = newstr(1)
strsetitem(p27, 0, i23)
p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=<GcPtrCallDescr>)
- guard_no_exception(descr=<Guard47>)
+ guard_no_exception(descr=...)
i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=<SignedCallDescr>)
- guard_true(i32, descr=<Guard48>)
+ guard_true(i32, descr=...)
i34 = int_add(i6, 1)
--TICK--
jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=<Loop4>)
+ """)
+
+ def test_long(self):
+ def main(n):
+ import string
+ i = 1
+ while i < n:
+ i += int(long(string.digits[i % len(string.digits)], 16))
+ return i
+
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i11 = int_lt(i6, i7)
+ guard_true(i11, descr=...)
+ guard_not_invalidated(descr=...)
+ i13 = int_eq(i6, -9223372036854775808)
+ guard_false(i13, descr=...)
+ i15 = int_mod(i6, i8)
+ i17 = int_rshift(i15, 63)
+ i18 = int_and(i8, i17)
+ i19 = int_add(i15, i18)
+ i21 = int_lt(i19, 0)
+ guard_false(i21, descr=...)
+ i22 = int_ge(i19, i8)
+ guard_false(i22, descr=...)
+ i23 = strgetitem(p10, i19)
+ p25 = newstr(1)
+ strsetitem(p25, 0, i23)
+ p28 = call(ConstClass(strip_spaces), p25, descr=<GcPtrCallDescr>)
+ guard_no_exception(descr=...)
+ i29 = strlen(p28)
+ i30 = int_is_true(i29)
+ guard_true(i30, descr=...)
+ i32 = int_sub(i29, 1)
+ i33 = strgetitem(p28, i32)
+ i35 = int_eq(i33, 108)
+ guard_false(i35, descr=...)
+ i37 = int_eq(i33, 76)
+ guard_false(i37, descr=...)
+ i39 = strgetitem(p28, 0)
+ i41 = int_eq(i39, 45)
+ guard_false(i41, descr=...)
+ i43 = int_eq(i39, 43)
+ guard_false(i43, descr=...)
+ i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=<BoolCallDescr>)
+ guard_false(i43, descr=...)
+ i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=<BoolCallDescr>)
+ guard_false(i46, descr=...)
+ p51 = new_with_vtable(21136408)
+ setfield_gc(p51, p28, descr=<GcPtrFieldDescr .*NumberStringParser.inst_literal .*>)
+ setfield_gc(p51, ConstPtr(ptr51), descr=<GcPtrFieldDescr pypy.objspace.std.strutil.NumberStringParser.inst_fname .*>)
+ setfield_gc(p51, 1, descr=<SignedFieldDescr .*NumberStringParser.inst_sign .*>)
+ setfield_gc(p51, 16, descr=<SignedFieldDescr .*NumberStringParser.inst_base .*>)
+ setfield_gc(p51, p28, descr=<GcPtrFieldDescr .*NumberStringParser.inst_s .*>)
+ setfield_gc(p51, i29, descr=<SignedFieldDescr .*NumberStringParser.inst_n .*>)
+ p55 = call(ConstClass(parse_digit_string), p51, descr=<GcPtrCallDescr>)
+ guard_no_exception(descr=...)
+ i57 = call(ConstClass(rbigint.toint), p55, descr=<SignedCallDescr>)
+ guard_no_exception(descr=...)
+ i58 = int_add_ovf(i6, i57)
+ guard_no_overflow(descr=...)
+ --TICK--
+ jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=<Loop4>)
""")
\ No newline at end of file
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
@@ -486,6 +486,11 @@
return True
+ def ll_startswith_char(s, ch):
+ if not len(s.chars):
+ return False
+ return s.chars[0] == ch
+
@elidable
def ll_endswith(s1, s2):
len1 = len(s1.chars)
@@ -503,6 +508,11 @@
return True
+ def ll_endswith_char(s, ch):
+ if not len(s.chars):
+ return False
+ return s.chars[len(s.chars) - 1] == ch
+
@elidable
def ll_find_char(s, ch, start, end):
i = start
diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py
--- a/pypy/rpython/ootypesystem/ootype.py
+++ b/pypy/rpython/ootypesystem/ootype.py
@@ -433,7 +433,9 @@
"ll_streq": Meth([self.SELFTYPE_T], Bool),
"ll_strcmp": Meth([self.SELFTYPE_T], Signed),
"ll_startswith": Meth([self.SELFTYPE_T], Bool),
+ "ll_startswith_char": Meth([self.CHAR], Bool),
"ll_endswith": Meth([self.SELFTYPE_T], Bool),
+ "ll_endswith_char": Meth([self.CHAR], Bool),
"ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed),
"ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed),
"ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed),
@@ -1429,10 +1431,18 @@
# NOT_RPYTHON
return self._str.startswith(s._str)
+ def ll_startswith_char(self, s):
+ # NOT_RPYTHON
+ return self._str.startswith(s)
+
def ll_endswith(self, s):
# NOT_RPYTHON
return self._str.endswith(s._str)
+ def ll_endswith_char(self, s):
+ # NOT_RPYTHON
+ return self._str.endswith(s)
+
def ll_find(self, s, start, end):
# NOT_RPYTHON
if start > len(self._str): # workaround to cope with corner case
diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py
--- a/pypy/rpython/rstr.py
+++ b/pypy/rpython/rstr.py
@@ -81,16 +81,30 @@
return super(AbstractStringRepr, self).rtype_is_true(hop)
def rtype_method_startswith(self, hop):
- str1_repr, str2_repr = self._str_reprs(hop)
- v_str, v_value = hop.inputargs(str1_repr, str2_repr)
+ str1_repr = hop.args_r[0].repr
+ str2_repr = hop.args_r[1]
+ v_str = hop.inputarg(str1_repr, arg=0)
+ if str2_repr == str2_repr.char_repr:
+ v_value = hop.inputarg(str2_repr.char_repr, arg=1)
+ fn = self.ll.ll_startswith_char
+ else:
+ v_value = hop.inputarg(str2_repr, arg=1)
+ fn = self.ll.ll_startswith
hop.exception_cannot_occur()
- return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value)
+ return hop.gendirectcall(fn, v_str, v_value)
def rtype_method_endswith(self, hop):
- str1_repr, str2_repr = self._str_reprs(hop)
- v_str, v_value = hop.inputargs(str1_repr, str2_repr)
+ str1_repr = hop.args_r[0].repr
+ str2_repr = hop.args_r[1]
+ v_str = hop.inputarg(str1_repr, arg=0)
+ if str2_repr == str2_repr.char_repr:
+ v_value = hop.inputarg(str2_repr.char_repr, arg=1)
+ fn = self.ll.ll_endswith_char
+ else:
+ v_value = hop.inputarg(str2_repr, arg=1)
+ fn = self.ll.ll_endswith
hop.exception_cannot_occur()
- return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value)
+ return hop.gendirectcall(fn, v_str, v_value)
def rtype_method_find(self, hop, reverse=False):
# XXX binaryop
diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py
--- a/pypy/rpython/test/test_rstr.py
+++ b/pypy/rpython/test/test_rstr.py
@@ -227,6 +227,15 @@
res = self.interpret(fn, [i,j])
assert res is fn(i, j)
+ def test_startswith_char(self):
+ const = self.const
+ def fn(i):
+ s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')]
+ return s[i].startswith('o')
+ for i in range(10):
+ res = self.interpret(fn, [i])
+ assert res == fn(i)
+
def test_endswith(self):
const = self.const
def fn(i, j):
@@ -238,6 +247,15 @@
res = self.interpret(fn, [i,j])
assert res is fn(i, j)
+ def test_endswith_char(self):
+ const = self.const
+ def fn(i):
+ s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')]
+ return s[i].endswith('e')
+ for i in range(10):
+ res = self.interpret(fn, [i])
+ assert res == fn(i)
+
def test_find(self):
const = self.const
def fn(i, j):
More information about the pypy-commit
mailing list