Commit 569f1662 authored by Stefan Behnel's avatar Stefan Behnel

optimise left-shift operations with small integers

parent fcf7c0a8
......@@ -34,6 +34,8 @@ Features added
* Speed up cython.inline().
* Binary lshift operations with small constant Python integers are faster.
Bugs fixed
----------
......
......@@ -2933,6 +2933,13 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
return node
return self._optimise_num_binop('Rshift', node, function, args, is_unbound_method)
def _handle_simple_method_object___lshift__(self, node, function, args, is_unbound_method):
if len(args) != 2 or not isinstance(args[1], ExprNodes.IntNode):
return node
if not args[1].has_constant_result() or not (1 <= args[1].constant_result <= 63):
return node
return self._optimise_num_binop('Lshift', node, function, args, is_unbound_method)
def _handle_simple_method_object___mod__(self, node, function, args, is_unbound_method):
return self._optimise_num_div('Remainder', node, function, args, is_unbound_method)
......
......@@ -536,7 +536,7 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, long
{{py:
c_op = {
'Add': '+', 'Subtract': '-', 'Remainder': '%', 'TrueDivide': '/', 'FloorDivide': '/',
'Or': '|', 'Xor': '^', 'And': '&', 'Rshift': '>>',
'Or': '|', 'Xor': '^', 'And': '&', 'Rshift': '>>', 'Lshift': '<<',
'Eq': '==', 'Ne': '!=',
}[op]
}}
......@@ -593,6 +593,10 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
x = q;
}
return PyInt_FromLong(x);
{{elif op == 'Lshift'}}
if (likely(a == (a << b) >> b)) {
return PyInt_FromLong(a {{c_op}} b);
}
{{else}}
// other operations are safe, no overflow
return PyInt_FromLong(a {{c_op}} b);
......@@ -673,6 +677,12 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
}
{{else}}
x = a {{c_op}} b;
{{if op == 'Lshift'}}
if (unlikely(a != x >> b)) {
ll{{ival}} = {{ival}};
goto long_long;
}
{{endif}}
{{endif}}
return PyLong_FromLong(x);
......@@ -693,6 +703,9 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
}
{{else}}
llx = lla {{c_op}} llb;
{{if op == 'Lshift'}}
if (likely(lla == llx >> llb)) /* then execute 'return' below */
{{endif}}
{{endif}}
return PyLong_FromLongLong(llx);
{{endif}}
......
......@@ -5,6 +5,10 @@ def bigint(x):
# avoid 'L' postfix in Py2.x
print(str(x).rstrip('L'))
def bigints(x):
# avoid 'L' postfix in Py2.x
print(str(x).replace('L', ''))
def or_obj(obj2, obj3):
"""
......@@ -130,6 +134,61 @@ def rshift_int(obj2):
return obj1
def lshift_int(obj):
"""
>>> lshift_int(0)
(0, 0, 0, 0)
>>> bigints(lshift_int(1))
(8, 2147483648, 9223372036854775808, 10633823966279326983230456482242756608)
>>> bigints(lshift_int(-1))
(-8, -2147483648, -9223372036854775808, -10633823966279326983230456482242756608)
>>> bigints(lshift_int(2))
(16, 4294967296, 18446744073709551616, 21267647932558653966460912964485513216)
>>> bigints(lshift_int(27))
(216, 57982058496, 249031044995078946816, 287113247089541828547222325020554428416)
>>> (-27) << 3
-216
>>> bigints(lshift_int(-27))
(-216, -57982058496, -249031044995078946816, -287113247089541828547222325020554428416)
>>> bigints(lshift_int(32))
(256, 68719476736, 295147905179352825856, 340282366920938463463374607431768211456)
>>> (-32) << 3
-256
>>> bigints(lshift_int(-32))
(-256, -68719476736, -295147905179352825856, -340282366920938463463374607431768211456)
>>> (2**28) << 3
2147483648
>>> bigints(lshift_int(2**28))
(2147483648, 576460752303423488, 2475880078570760549798248448, 2854495385411919762116571938898990272765493248)
>>> (-2**28) << 3
-2147483648
>>> bigints(lshift_int(-2**28))
(-2147483648, -576460752303423488, -2475880078570760549798248448, -2854495385411919762116571938898990272765493248)
>>> (2**30) << 3
8589934592
>>> bigints(lshift_int(2**30))
(8589934592, 2305843009213693952, 9903520314283042199192993792, 11417981541647679048466287755595961091061972992)
>>> bigints(lshift_int(-2**30))
(-8589934592, -2305843009213693952, -9903520314283042199192993792, -11417981541647679048466287755595961091061972992)
>>> bigint((2**60) << 3)
9223372036854775808
>>> bigints(lshift_int(2**60))
(9223372036854775808, 2475880078570760549798248448, 10633823966279326983230456482242756608, 12259964326927110866866776217202473468949912977468817408)
>>> bigints(lshift_int(-2**60))
(-9223372036854775808, -2475880078570760549798248448, -10633823966279326983230456482242756608, -12259964326927110866866776217202473468949912977468817408)
"""
r1 = obj << 3
r2 = obj << 31
r3 = obj << 63
r4 = obj << 123
return r1, r2, r3, r4
def mixed_obj(obj2, obj3):
"""
>>> mixed_obj(2, 3)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment