Commit 2acc6660 authored by Stefan Behnel's avatar Stefan Behnel

extend PyLong optimisation to '>>' (rshift) operator

parent 259b3635
......@@ -19,8 +19,8 @@ Features added
* Adding/subtracting constant Python floats and small integers is faster.
* Binary and/or/xor operations and modulus with small constant Python integers
are faster.
* Binary and/or/xor/rshift operations and modulus with small constant Python
integers are faster.
Bugs fixed
----------
......
......@@ -2811,6 +2811,13 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
def _handle_simple_method_object___xor__(self, node, function, args, is_unbound_method):
return self._optimise_num_binop('Xor', node, function, args, is_unbound_method)
def _handle_simple_method_object___rshift__(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('Rshift', node, function, args, is_unbound_method)
def _handle_simple_method_object___mod__(self, node, function, args, is_unbound_method):
if len(args) != 2 or not isinstance(args[1], ExprNodes.IntNode):
return node
......@@ -2826,25 +2833,26 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
def _optimise_num_binop(self, operator, node, function, args, is_unbound_method):
"""
Optimise '+' / '-' operator for (likely) float or small integer operations.
Optimise math operators for (likely) float or small integer operations.
"""
if len(args) != 2:
return node
if not node.type.is_pyobject:
return node
# when adding IntNode/FloatNode to something else, assume other operand is also numeric
# When adding IntNode/FloatNode to something else, assume other operand is also numeric.
# Prefer constants on RHS as they allows better size control for some operators.
num_nodes = (ExprNodes.IntNode, ExprNodes.FloatNode)
if isinstance(args[0], num_nodes):
if args[1].type is not PyrexTypes.py_object_type:
return node
numval = args[0]
arg_order = 'CObj'
elif isinstance(args[1], num_nodes):
if isinstance(args[1], num_nodes):
if args[0].type is not PyrexTypes.py_object_type:
return node
numval = args[1]
arg_order = 'ObjC'
elif isinstance(args[0], num_nodes):
if args[1].type is not PyrexTypes.py_object_type:
return node
numval = args[0]
arg_order = 'CObj'
else:
return node
......
......@@ -494,7 +494,7 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, long
#if CYTHON_COMPILING_IN_CPYTHON
{{py: pyval, ival = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }}
{{py: c_op = {'Add': '+', 'Subtract': '-', 'Remainder': '%', 'Or': '|', 'Xor': '^', 'And': '&'}[op] }}
{{py: c_op = {'Add': '+', 'Subtract': '-', 'Remainder': '%', 'Or': '|', 'Xor': '^', 'And': '&', 'Rshift': '>>'}[op] }}
static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, int inplace) {
#if PY_MAJOR_VERSION < 3
......
# mode: run
def bigint(x):
# avoid 'L' postfix in Py2.x
print(str(x).rstrip('L'))
def or_obj(obj2, obj3):
"""
>>> or_obj(2, 3)
......@@ -79,6 +84,52 @@ def rshift_obj(obj2, obj3):
return obj1
def rshift_int(obj2):
"""
>>> rshift_int(2)
0
>>> rshift_int(27)
3
>>> (-27) >> 3
-4
>>> rshift_int(-27)
-4
>>> rshift_int(32)
4
>>> (-32) >> 3
-4
>>> rshift_int(-32)
-4
>>> (2**28) >> 3
33554432
>>> rshift_int(2**28)
33554432
>>> (-2**28) >> 3
-33554432
>>> rshift_int(-2**28)
-33554432
>>> (2**30) >> 3
134217728
>>> rshift_int(2**30)
134217728
>>> rshift_int(-2**30)
-134217728
>>> bigint((2**60) >> 3)
144115188075855872
>>> bigint(rshift_int(2**60))
144115188075855872
>>> bigint(rshift_int(-2**60))
-144115188075855872
"""
obj1 = obj2 >> 3
return obj1
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