Commit b74716a2 authored by scoder's avatar scoder Committed by GitHub

Merge pull request #2188 from scoder/faster_int_comparison

Further optimise int/float comparison
parents 440c51b2 55cdc9f0
......@@ -3159,21 +3159,17 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
may_return_none=True,
utility_code=load_c_utility('py_dict_pop'))
Pyx_PyInt_BinopInt_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
Pyx_BinopInt_func_types = dict(
((ctype, ret_type), PyrexTypes.CFuncType(
ret_type, [
PyrexTypes.CFuncTypeArg("op1", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("op2", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("intval", PyrexTypes.c_long_type, None),
PyrexTypes.CFuncTypeArg("cval", ctype, None),
PyrexTypes.CFuncTypeArg("inplace", PyrexTypes.c_bint_type, None),
])
Pyx_PyFloat_BinopInt_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("op1", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("op2", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("fval", PyrexTypes.c_double_type, None),
PyrexTypes.CFuncTypeArg("inplace", PyrexTypes.c_bint_type, None),
])
], exception_value=None if ret_type.is_pyobject else ret_type.exception_value))
for ctype in (PyrexTypes.c_long_type, PyrexTypes.c_double_type)
for ret_type in (PyrexTypes.py_object_type, PyrexTypes.c_bint_type)
)
def _handle_simple_method_object___add__(self, node, function, args, is_unbound_method):
return self._optimise_num_binop('Add', node, function, args, is_unbound_method)
......@@ -3184,7 +3180,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
def _handle_simple_method_object___eq__(self, node, function, args, is_unbound_method):
return self._optimise_num_binop('Eq', node, function, args, is_unbound_method)
def _handle_simple_method_object___neq__(self, node, function, args, is_unbound_method):
def _handle_simple_method_object___ne__(self, node, function, args, is_unbound_method):
return self._optimise_num_binop('Ne', node, function, args, is_unbound_method)
def _handle_simple_method_object___and__(self, node, function, args, is_unbound_method):
......@@ -3253,7 +3249,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
def _handle_simple_method_float___eq__(self, node, function, args, is_unbound_method):
return self._optimise_num_binop('Eq', node, function, args, is_unbound_method)
def _handle_simple_method_float___neq__(self, node, function, args, is_unbound_method):
def _handle_simple_method_float___ne__(self, node, function, args, is_unbound_method):
return self._optimise_num_binop('Ne', node, function, args, is_unbound_method)
def _optimise_num_binop(self, operator, node, function, args, is_unbound_method):
......@@ -3262,7 +3258,15 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
"""
if len(args) != 2:
return node
if not node.type.is_pyobject:
if node.type.is_pyobject:
if operator in ('Eq', 'Ne'):
ret_type = PyrexTypes.c_bint_type
else:
ret_type = PyrexTypes.py_object_type
elif node.type is PyrexTypes.c_bint_type and operator in ('Eq', 'Ne'):
ret_type = PyrexTypes.c_bint_type
else:
return node
# When adding IntNode/FloatNode to something else, assume other operand is also numeric.
......@@ -3285,6 +3289,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
return node
is_float = isinstance(numval, ExprNodes.FloatNode)
num_type = PyrexTypes.c_double_type if is_float else PyrexTypes.c_long_type
if is_float:
if operator not in ('Add', 'Subtract', 'Remainder', 'TrueDivide', 'Divide', 'Eq', 'Ne'):
return node
......@@ -3292,27 +3297,38 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
# mixed old-/new-style division is not currently optimised for integers
return node
elif abs(numval.constant_result) > 2**30:
# Cut off at an integer border that is still safe for all operations.
return node
args = list(args)
args.append((ExprNodes.FloatNode if is_float else ExprNodes.IntNode)(
numval.pos, value=numval.value, constant_result=numval.constant_result,
type=PyrexTypes.c_double_type if is_float else PyrexTypes.c_long_type))
type=num_type))
inplace = node.inplace if isinstance(node, ExprNodes.NumBinopNode) else False
args.append(ExprNodes.BoolNode(node.pos, value=inplace, constant_result=inplace))
utility_code = TempitaUtilityCode.load_cached(
"PyFloatBinop" if is_float else "PyIntBinop", "Optimize.c",
context=dict(op=operator, order=arg_order))
"PyFloatBinop" if is_float else "PyIntCompare" if operator in ('Eq', 'Ne') else "PyIntBinop",
"Optimize.c",
context=dict(op=operator, order=arg_order, ret_type=ret_type))
return self._substitute_method_call(
node, function, "__Pyx_Py%s_%s%s" % ('Float' if is_float else 'Int', operator, arg_order),
self.Pyx_PyFloat_BinopInt_func_type if is_float else self.Pyx_PyInt_BinopInt_func_type,
call_node = self._substitute_method_call(
node, function,
"__Pyx_Py%s_%s%s%s" % (
'Float' if is_float else 'Int',
'' if ret_type.is_pyobject else 'Bool',
operator,
arg_order),
self.Pyx_BinopInt_func_types[(num_type, ret_type)],
'__%s__' % operator[:3].lower(), is_unbound_method, args,
may_return_none=True,
with_none_check=False,
utility_code=utility_code)
if node.type.is_pyobject and not ret_type.is_pyobject:
call_node = ExprNodes.CoerceToPyTypeNode(call_node, self.current_env(), node.type)
return call_node
### unicode type methods
PyUnicode_uchar_predicate_func_type = PyrexTypes.CFuncType(
......
......@@ -698,13 +698,99 @@ fallback:
}
/////////////// PyIntCompare.proto ///////////////
{{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}}
static CYTHON_INLINE {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, long intval, long inplace); /*proto*/
/////////////// PyIntCompare ///////////////
{{py: pyval, ival = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }}
{{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}}
{{py: return_true = 'Py_RETURN_TRUE' if ret_type.is_pyobject else 'return 1'}}
{{py: return_false = 'Py_RETURN_FALSE' if ret_type.is_pyobject else 'return 0'}}
{{py: slot_name = op.lower() }}
{{py: c_op = {'Eq': '==', 'Ne': '!='}[op] }}
{{py:
return_compare = (
(lambda a,b,c_op: "if ({a} {c_op} {b}) {return_true}; else {return_false};".format(
a=a, b=b, c_op=c_op, return_true=return_true, return_false=return_false))
if ret_type.is_pyobject else
(lambda a,b,c_op: "return ({a} {c_op} {b});".format(a=a, b=b, c_op=c_op))
)
}}
static CYTHON_INLINE {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED long inplace) {
if (op1 == op2) {
{{return_true if op == 'Eq' else return_false}};
}
#if PY_MAJOR_VERSION < 3
if (likely(PyInt_CheckExact({{pyval}}))) {
const long {{'a' if order == 'CObj' else 'b'}} = intval;
long {{ival}} = PyInt_AS_LONG({{pyval}});
{{return_compare('a', 'b', c_op)}}
}
#endif
#if CYTHON_USE_PYLONG_INTERNALS
if (likely(PyLong_CheckExact({{pyval}}))) {
int unequal;
unsigned long uintval;
Py_ssize_t size = Py_SIZE({{pyval}});
const digit* digits = ((PyLongObject*){{pyval}})->ob_digit;
if (intval == 0) {
// == 0 => Py_SIZE(pyval) == 0
{{return_compare('size', '0', c_op)}}
} else if (intval < 0) {
// < 0 => Py_SIZE(pyval) < 0
if (size >= 0)
{{return_false if op == 'Eq' else return_true}};
// both are negative => can use absolute values now.
intval = -intval;
size = -size;
} else {
// > 0 => Py_SIZE(pyval) > 0
if (size <= 0)
{{return_false if op == 'Eq' else return_true}};
}
// After checking that the sign is the same (and excluding 0), now compare the absolute values.
// When inlining, the C compiler should select exactly one line from this unrolled loop.
uintval = (unsigned long) intval;
{{for _size in range(4, 0, -1)}}
#if PyLong_SHIFT * {{_size}} < SIZEOF_LONG*8
if (uintval >> (PyLong_SHIFT * {{_size}})) {
// The C integer value is between (PyLong_BASE ** _size) and MIN(PyLong_BASE ** _size, LONG_MAX).
unequal = (size != {{_size+1}}) || (digits[0] != (uintval & (unsigned long) PyLong_MASK))
{{for _i in range(1, _size+1)}} | (digits[{{_i}}] != ((uintval >> ({{_i}} * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)){{endfor}};
} else
#endif
{{endfor}}
unequal = (size != 1) || (((unsigned long) digits[0]) != (uintval & (unsigned long) PyLong_MASK));
{{return_compare('unequal', '0', c_op)}}
}
#endif
if (PyFloat_CheckExact({{pyval}})) {
const long {{'a' if order == 'CObj' else 'b'}} = intval;
double {{ival}} = PyFloat_AS_DOUBLE({{pyval}});
{{return_compare('(double)a', '(double)b', c_op)}}
}
return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}(
PyObject_RichCompare(op1, op2, Py_{{op.upper()}}));
}
/////////////// PyIntBinop.proto ///////////////
{{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}}
#if !CYTHON_COMPILING_IN_PYPY
static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, long intval, int inplace); /*proto*/
static {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, long intval, int inplace); /*proto*/
#else
#define __Pyx_PyInt_{{op}}{{order}}(op1, op2, intval, inplace) \
{{if op in ('Eq', 'Ne')}}PyObject_RichCompare(op1, op2, Py_{{op.upper()}})
#define __Pyx_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(op1, op2, intval, inplace) \
{{if op in ('Eq', 'Ne')}}{{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}(PyObject_RichCompare(op1, op2, Py_{{op.upper()}}))
{{else}}(inplace ? PyNumber_InPlace{{op}}(op1, op2) : PyNumber_{{op}}(op1, op2))
{{endif}}
#endif
......@@ -714,6 +800,9 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, long
#if !CYTHON_COMPILING_IN_PYPY
{{py: from Cython.Utility import pylong_join }}
{{py: pyval, ival = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }}
{{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}}
{{py: return_true = 'Py_RETURN_TRUE' if ret_type.is_pyobject else 'return 1'}}
{{py: return_false = 'Py_RETURN_FALSE' if ret_type.is_pyobject else 'return 0'}}
{{py: slot_name = {'TrueDivide': 'true_divide', 'FloorDivide': 'floor_divide'}.get(op, op.lower()) }}
{{py:
c_op = {
......@@ -723,10 +812,10 @@ c_op = {
}[op]
}}
static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) {
static {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) {
{{if op in ('Eq', 'Ne')}}
if (op1 == op2) {
Py_RETURN_{{'TRUE' if op == 'Eq' else 'FALSE'}};
{{return_true if op == 'Eq' else return_false}};
}
{{endif}}
......@@ -740,9 +829,9 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
{{if op in ('Eq', 'Ne')}}
if (a {{c_op}} b) {
Py_RETURN_TRUE;
{{return_true}};
} else {
Py_RETURN_FALSE;
{{return_false}};
}
{{elif c_op in '+-'}}
// adapted from intobject.c in Py2.7:
......@@ -826,10 +915,11 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
{{if op in ('Eq', 'Ne')}}
#if PyLong_SHIFT < 30 && PyLong_SHIFT != 15
// unusual setup - your fault
default: return PyLong_Type.tp_richcompare({{'op1, op2' if order == 'ObjC' else 'op2, op1'}}, Py_{{op.upper()}});
default: return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}(
PyLong_Type.tp_richcompare({{'op1, op2' if order == 'ObjC' else 'op2, op1'}}, Py_{{op.upper()}}));
#else
// too large for the long values we allow => definitely not equal
default: Py_RETURN_{{'FALSE' if op == 'Eq' else 'TRUE'}};
default: {{return_false if op == 'Eq' else return_true}};
#endif
{{else}}
default: return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
......@@ -838,9 +928,9 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
}
{{if op in ('Eq', 'Ne')}}
if (a {{c_op}} b) {
Py_RETURN_TRUE;
{{return_true}};
} else {
Py_RETURN_FALSE;
{{return_false}};
}
{{else}}
{{if c_op == '%'}}
......@@ -912,9 +1002,9 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
double {{ival}} = PyFloat_AS_DOUBLE({{pyval}});
{{if op in ('Eq', 'Ne')}}
if ((double)a {{c_op}} (double)b) {
Py_RETURN_TRUE;
{{return_true}};
} else {
Py_RETURN_FALSE;
{{return_false}};
}
{{else}}
double result;
......@@ -928,7 +1018,8 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
{{endif}}
{{if op in ('Eq', 'Ne')}}
return PyObject_RichCompare(op1, op2, Py_{{op.upper()}});
return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}(
PyObject_RichCompare(op1, op2, Py_{{op.upper()}}));
{{else}}
return (inplace ? PyNumber_InPlace{{op}} : PyNumber_{{op}})(op1, op2);
{{endif}}
......@@ -937,11 +1028,12 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
/////////////// PyFloatBinop.proto ///////////////
{{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}}
#if !CYTHON_COMPILING_IN_PYPY
static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, double floatval, int inplace); /*proto*/
static {{c_ret_type}} __Pyx_PyFloat_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, double floatval, int inplace); /*proto*/
#else
#define __Pyx_PyFloat_{{op}}{{order}}(op1, op2, floatval, inplace) \
{{if op in ('Eq', 'Ne')}}PyObject_RichCompare(op1, op2, Py_{{op.upper()}})
#define __Pyx_PyFloat_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(op1, op2, floatval, inplace) \
{{if op in ('Eq', 'Ne')}}{{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}(PyObject_RichCompare(op1, op2, Py_{{op.upper()}}))
{{elif op == 'Divide'}}((inplace ? __Pyx_PyNumber_InPlaceDivide(op1, op2) : __Pyx_PyNumber_Divide(op1, op2)))
{{else}}(inplace ? PyNumber_InPlace{{op}}(op1, op2) : PyNumber_{{op}}(op1, op2))
{{endif}}
......@@ -951,6 +1043,9 @@ static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, dou
#if !CYTHON_COMPILING_IN_PYPY
{{py: from Cython.Utility import pylong_join }}
{{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}}
{{py: return_true = 'Py_RETURN_TRUE' if ret_type.is_pyobject else 'return 1'}}
{{py: return_false = 'Py_RETURN_FALSE' if ret_type.is_pyobject else 'return 0'}}
{{py: pyval, fval = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }}
{{py:
c_op = {
......@@ -959,13 +1054,13 @@ c_op = {
}[op]
}}
static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, double floatval, CYTHON_UNUSED int inplace) {
static {{c_ret_type}} __Pyx_PyFloat_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, double floatval, CYTHON_UNUSED int inplace) {
const double {{'a' if order == 'CObj' else 'b'}} = floatval;
double {{fval}}{{if op not in ('Eq', 'Ne')}}, result{{endif}};
{{if op in ('Eq', 'Ne')}}
if (op1 == op2) {
Py_RETURN_{{'TRUE' if op == 'Eq' else 'FALSE'}};
{{return_true if op == 'Eq' else return_false}};
}
{{endif}}
......@@ -1011,7 +1106,8 @@ static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, dou
{
#endif
{{if op in ('Eq', 'Ne')}}
return PyFloat_Type.tp_richcompare({{'op1, op2' if order == 'CObj' else 'op2, op1'}}, Py_{{op.upper()}});
return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}(
PyFloat_Type.tp_richcompare({{'op1, op2' if order == 'CObj' else 'op2, op1'}}, Py_{{op.upper()}}));
{{else}}
{{fval}} = PyLong_AsDouble({{pyval}});
if (unlikely({{fval}} == -1.0 && PyErr_Occurred())) return NULL;
......@@ -1019,7 +1115,8 @@ static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, dou
}
} else {
{{if op in ('Eq', 'Ne')}}
return PyObject_RichCompare(op1, op2, Py_{{op.upper()}});
return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}(
PyObject_RichCompare(op1, op2, Py_{{op.upper()}}));
{{elif op == 'Divide'}}
return (inplace ? __Pyx_PyNumber_InPlaceDivide(op1, op2) : __Pyx_PyNumber_Divide(op1, op2));
{{else}}
......@@ -1029,9 +1126,9 @@ static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, dou
{{if op in ('Eq', 'Ne')}}
if (a {{c_op}} b) {
Py_RETURN_TRUE;
{{return_true}};
} else {
Py_RETURN_FALSE;
{{return_false}};
}
{{else}}
// copied from floatobject.c in Py3.5:
......
......@@ -86,6 +86,7 @@ static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) {
#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None)
static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b);
static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*);
static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
#define __Pyx_PySequence_Tuple(obj) \
......@@ -285,6 +286,14 @@ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
else return PyObject_IsTrue(x);
}
static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) {
int retval;
if (unlikely(!x)) return -1;
retval = __Pyx_PyObject_IsTrue(x);
Py_DECREF(x);
return retval;
}
static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) {
#if PY_MAJOR_VERSION >= 3
if (PyLong_Check(result)) {
......
"""
Non-test that prints debug information about the current build environment.
"""
from __future__ import print_function
import sys
cdef extern from *:
"""
#ifndef PyLong_SHIFT
#define PyLong_SHIFT 0
typedef int digit;
typedef int sdigit;
#endif
#ifndef PyLong_BASE
#define PyLong_BASE 0
#endif
#ifndef PyLong_MASK
#define PyLong_MASK 0
#endif
"""
# Python runtime
cdef long PY_VERSION_HEX
# Cython config
cdef int CYTHON_COMPILING_IN_CPYTHON
cdef int CYTHON_COMPILING_IN_PYPY
cdef int CYTHON_COMPILING_IN_PYSTON
cdef int CYTHON_USE_PYLONG_INTERNALS
cdef int CYTHON_USE_PYLIST_INTERNALS
cdef int CYTHON_USE_UNICODE_INTERNALS
cdef int CYTHON_USE_UNICODE_WRITER
cdef int CYTHON_AVOID_BORROWED_REFS
cdef int CYTHON_ASSUME_SAFE_MACROS
cdef int CYTHON_UNPACK_METHODS
cdef int CYTHON_FAST_THREAD_STATE
cdef int CYTHON_FAST_PYCALL
cdef int CYTHON_PEP489_MULTI_PHASE_INIT
cdef int CYTHON_USE_TP_FINALIZE
# C and platform specifics
cdef int SIZEOF_INT
cdef int SIZEOF_LONG
cdef int SIZEOF_SIZE_T
cdef int SIZEOF_LONG_LONG
cdef int SIZEOF_VOID_P
# PyLong internals
cdef long PyLong_BASE
cdef long PyLong_MASK
cdef int PyLong_SHIFT
cdef int digit
cdef int sdigit
print(f"""Python build environment:
Python {sys.version_info}
PY_VERSION_HEX 0x{PY_VERSION_HEX:X}
CYTHON_COMPILING_IN_CPYTHON {CYTHON_COMPILING_IN_CPYTHON}
CYTHON_COMPILING_IN_PYPY {CYTHON_COMPILING_IN_PYPY}
CYTHON_COMPILING_IN_PYSTON {CYTHON_COMPILING_IN_PYSTON}
CYTHON_USE_PYLONG_INTERNALS {CYTHON_USE_PYLONG_INTERNALS}
CYTHON_USE_PYLIST_INTERNALS {CYTHON_USE_PYLIST_INTERNALS}
CYTHON_USE_UNICODE_INTERNALS {CYTHON_USE_UNICODE_INTERNALS}
CYTHON_USE_UNICODE_WRITER {CYTHON_USE_UNICODE_WRITER}
CYTHON_AVOID_BORROWED_REFS {CYTHON_AVOID_BORROWED_REFS}
CYTHON_ASSUME_SAFE_MACROS {CYTHON_ASSUME_SAFE_MACROS}
CYTHON_UNPACK_METHODS {CYTHON_UNPACK_METHODS}
CYTHON_FAST_THREAD_STATE {CYTHON_FAST_THREAD_STATE}
CYTHON_FAST_PYCALL {CYTHON_FAST_PYCALL}
CYTHON_PEP489_MULTI_PHASE_INIT {CYTHON_PEP489_MULTI_PHASE_INIT}
CYTHON_USE_TP_FINALIZE {CYTHON_USE_TP_FINALIZE}
PyLong_BASE 0x{PyLong_BASE:X}
PyLong_MASK {PyLong_MASK:X}
PyLong_SHIFT {PyLong_SHIFT}
sizeof(digit) {sizeof(digit)}
sizeof(sdigit) {sizeof(sdigit)}
SIZEOF_INT {SIZEOF_INT} ({sizeof(int)})
SIZEOF_LONG {SIZEOF_LONG} ({sizeof(long)})
SIZEOF_SIZE_T {SIZEOF_SIZE_T} ({sizeof(Py_ssize_t)}, {getattr(sys, 'maxsize', getattr(sys, 'maxint', None))})
SIZEOF_LONG_LONG {SIZEOF_LONG_LONG} ({sizeof(long long)})
SIZEOF_VOID_P {SIZEOF_VOID_P} ({sizeof(void*)})
""")
# mode: run
cimport cython
def bigint(x):
# avoid 'L' postfix in Py2.x
......@@ -10,6 +12,7 @@ def bigints(x):
print(str(x).replace('L', ''))
@cython.test_assert_path_exists('//IntBinopNode')
def or_obj(obj2, obj3):
"""
>>> or_obj(2, 3)
......@@ -19,6 +22,7 @@ def or_obj(obj2, obj3):
return obj1
@cython.test_fail_if_path_exists('//IntBinopNode')
def or_int(obj2):
"""
>>> or_int(1)
......@@ -30,6 +34,7 @@ def or_int(obj2):
return obj1
@cython.test_assert_path_exists('//IntBinopNode')
def xor_obj(obj2, obj3):
"""
>>> xor_obj(2, 3)
......@@ -39,6 +44,7 @@ def xor_obj(obj2, obj3):
return obj1
@cython.test_fail_if_path_exists('//IntBinopNode')
def xor_int(obj2):
"""
>>> xor_int(2)
......@@ -50,6 +56,7 @@ def xor_int(obj2):
return obj1
@cython.test_assert_path_exists('//IntBinopNode')
def and_obj(obj2, obj3):
"""
>>> and_obj(2, 3)
......@@ -59,6 +66,7 @@ def and_obj(obj2, obj3):
return obj1
@cython.test_fail_if_path_exists('//IntBinopNode')
def and_int(obj2):
"""
>>> and_int(1)
......@@ -70,6 +78,7 @@ def and_int(obj2):
return obj1
@cython.test_assert_path_exists('//IntBinopNode')
def lshift_obj(obj2, obj3):
"""
>>> lshift_obj(2, 3)
......@@ -79,6 +88,7 @@ def lshift_obj(obj2, obj3):
return obj1
@cython.test_assert_path_exists('//IntBinopNode')
def rshift_obj(obj2, obj3):
"""
>>> rshift_obj(2, 3)
......@@ -88,6 +98,7 @@ def rshift_obj(obj2, obj3):
return obj1
@cython.test_fail_if_path_exists('//IntBinopNode')
def rshift_int(obj2):
"""
>>> rshift_int(2)
......@@ -134,6 +145,10 @@ def rshift_int(obj2):
return obj1
@cython.test_assert_path_exists(
'//SingleAssignmentNode//IntBinopNode',
'//SingleAssignmentNode//PythonCapiCallNode',
)
def lshift_int(obj):
"""
>>> lshift_int(0)
......@@ -189,6 +204,10 @@ def lshift_int(obj):
return r1, r2, r3, r4
@cython.test_assert_path_exists(
'//IntBinopNode',
'//IntBinopNode//IntBinopNode',
)
def mixed_obj(obj2, obj3):
"""
>>> mixed_obj(2, 3)
......@@ -198,6 +217,13 @@ def mixed_obj(obj2, obj3):
return obj1
@cython.test_assert_path_exists(
'//IntBinopNode',
'//IntBinopNode//PythonCapiCallNode',
)
@cython.test_fail_if_path_exists(
'//IntBinopNode//IntBinopNode',
)
def mixed_int(obj2):
"""
>>> mixed_int(2)
......@@ -209,3 +235,244 @@ def mixed_int(obj2):
"""
obj1 = (obj2 ^ 0x10) | (obj2 & 0x01)
return obj1
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_fail_if_path_exists(
'//IntBinopNode',
'//PrimaryCmpNode',
)
def equals(obj2):
"""
>>> equals(2)
True
>>> equals(0)
False
>>> equals(-1)
False
"""
result = obj2 == 2
return result
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_fail_if_path_exists(
'//IntBinopNode',
'//PrimaryCmpNode',
)
def not_equals(obj2):
"""
>>> not_equals(2)
False
>>> not_equals(0)
True
>>> not_equals(-1)
True
"""
result = obj2 != 2
return result
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_assert_path_exists('//PrimaryCmpNode')
def equals_many(obj2):
"""
>>> equals_many(-2)
(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
>>> equals_many(0)
(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
>>> equals_many(1)
(False, True, False, False, False, False, False, False, False, False, False, False, False, False, False)
>>> equals_many(-1)
(False, False, True, False, False, False, False, False, False, False, False, False, False, False, False)
>>> equals_many(2**30)
(False, False, False, True, False, False, False, False, False, False, False, False, False, False, False)
>>> equals_many(-2**30)
(False, False, False, False, True, False, False, False, False, False, False, False, False, False, False)
>>> equals_many(2**30-1)
(False, False, False, False, False, True, False, False, False, False, False, False, False, False, False)
>>> equals_many(-2**30+1)
(False, False, False, False, False, False, True, False, False, False, False, False, False, False, False)
>>> equals_many(2**32)
(False, False, False, False, False, False, False, True, False, False, False, False, False, False, False)
>>> equals_many(-2**32)
(False, False, False, False, False, False, False, False, True, False, False, False, False, False, False)
>>> equals_many(2**45-1)
(False, False, False, False, False, False, False, False, False, True, False, False, False, False, False)
>>> equals_many(-2**45+1)
(False, False, False, False, False, False, False, False, False, False, True, False, False, False, False)
>>> equals_many(2**64)
(False, False, False, False, False, False, False, False, False, False, False, True, False, False, False)
>>> equals_many(-2**64)
(False, False, False, False, False, False, False, False, False, False, False, False, True, False, False)
>>> equals_many(2**64-1)
(False, False, False, False, False, False, False, False, False, False, False, False, False, True, False)
>>> equals_many(-2**64+1)
(False, False, False, False, False, False, False, False, False, False, False, False, False, False, True)
"""
cdef bint x, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o
a = obj2 == 0
x = 0 == obj2
assert a == x
b = obj2 == 1
x = 1 == obj2
assert b == x
c = obj2 == -1
x = -1 == obj2
assert c == x
d = obj2 == 2**30
x = 2**30 == obj2
assert d == x
e = obj2 == -2**30
x = -2**30 == obj2
assert e == x
f = obj2 == 2**30-1
x = 2**30-1 == obj2
assert f == x
g = obj2 == -2**30+1
x = -2**30+1 == obj2
assert g == x
h = obj2 == 2**32
x = 2**32 == obj2
assert h == x
i = obj2 == -2**32
x = -2**32 == obj2
assert i == x
j = obj2 == 2**45-1
x = 2**45-1 == obj2
assert j == x
k = obj2 == -2**45+1
x = -2**45+1 == obj2
assert k == x
l = obj2 == 2**64
x = 2**64 == obj2
assert l == x
m = obj2 == -2**64
x = -2**64 == obj2
assert m == x
n = obj2 == 2**64-1
x = 2**64-1 == obj2
assert n == x
o = obj2 == -2**64+1
x = -2**64+1 == obj2
assert o == x
return (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_assert_path_exists('//PrimaryCmpNode')
def not_equals_many(obj2):
"""
>>> not_equals_many(-2)
(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
>>> not_equals_many(0)
(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
>>> not_equals_many(1)
(False, True, False, False, False, False, False, False, False, False, False, False, False, False, False)
>>> not_equals_many(-1)
(False, False, True, False, False, False, False, False, False, False, False, False, False, False, False)
>>> not_equals_many(2**30)
(False, False, False, True, False, False, False, False, False, False, False, False, False, False, False)
>>> not_equals_many(-2**30)
(False, False, False, False, True, False, False, False, False, False, False, False, False, False, False)
>>> not_equals_many(2**30-1)
(False, False, False, False, False, True, False, False, False, False, False, False, False, False, False)
>>> not_equals_many(-2**30+1)
(False, False, False, False, False, False, True, False, False, False, False, False, False, False, False)
>>> not_equals_many(2**32)
(False, False, False, False, False, False, False, True, False, False, False, False, False, False, False)
>>> not_equals_many(-2**32)
(False, False, False, False, False, False, False, False, True, False, False, False, False, False, False)
>>> not_equals_many(2**45-1)
(False, False, False, False, False, False, False, False, False, True, False, False, False, False, False)
>>> not_equals_many(-2**45+1)
(False, False, False, False, False, False, False, False, False, False, True, False, False, False, False)
>>> not_equals_many(2**64)
(False, False, False, False, False, False, False, False, False, False, False, True, False, False, False)
>>> not_equals_many(-2**64)
(False, False, False, False, False, False, False, False, False, False, False, False, True, False, False)
>>> not_equals_many(2**64-1)
(False, False, False, False, False, False, False, False, False, False, False, False, False, True, False)
>>> not_equals_many(-2**64+1)
(False, False, False, False, False, False, False, False, False, False, False, False, False, False, True)
"""
cdef bint a, b, c, d, e, f, g, h, i, j, k, l, m, n, o
a = obj2 != 0
x = 0 != obj2
assert a == x
b = obj2 != 1
x = 1 != obj2
assert b == x
c = obj2 != -1
x = -1 != obj2
assert c == x
d = obj2 != 2**30
x = 2**30 != obj2
assert d == x
e = obj2 != -2**30
x = -2**30 != obj2
assert e == x
f = obj2 != 2**30-1
x = 2**30-1 != obj2
assert f == x
g = obj2 != -2**30+1
x = -2**30+1 != obj2
assert g == x
h = obj2 != 2**32
x = 2**32 != obj2
assert h == x
i = obj2 != -2**32
x = -2**32 != obj2
assert i == x
j = obj2 != 2**45-1
x = 2**45-1 != obj2
assert j == x
k = obj2 != -2**45+1
x = -2**45+1 != obj2
assert k == x
l = obj2 != 2**64
x = 2**64 != obj2
assert l == x
m = obj2 != -2**64
x = -2**64 != obj2
assert m == x
n = obj2 != 2**64-1
x = 2**64-1 != obj2
assert n == x
o = obj2 != -2**64+1
x = -2**64+1 != obj2
assert o == x
return tuple(not x for x in (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o))
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_fail_if_path_exists(
'//IntBinopNode',
'//PrimaryCmpNode',
)
def equals_zero(obj2):
"""
>>> equals_zero(2)
False
>>> equals_zero(0)
True
>>> equals_zero(-1)
False
"""
result = obj2 == 0
return result
def truthy(obj2):
"""
>>> truthy(2)
True
>>> truthy(0)
False
>>> truthy(-1)
True
"""
if obj2:
return True
else:
return False
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