blob: 2342ba93dab574a0888109868990896f736dd6af [file] [log] [blame]
from mypyc.ops import (
int_rprimitive, bool_rprimitive, float_rprimitive, object_rprimitive, short_int_rprimitive,
RType, OpDescription,
ERR_NEVER, ERR_MAGIC,
)
from mypyc.ops_primitive import (
name_ref_op, binary_op, unary_op, func_op, custom_op,
simple_emit,
call_emit,
)
# These int constructors produce object_rprimitives that then need to be unboxed
# I guess unboxing ourselves would save a check and branch though?
# For ordinary calls to int() we use a name_ref to the type
name_ref_op('builtins.int',
result_type=object_rprimitive,
error_kind=ERR_NEVER,
emit=simple_emit('{dest} = (PyObject *)&PyLong_Type;'),
is_borrowed=True)
# Convert from a float. We could do a bit better directly.
func_op(
name='builtins.int',
arg_types=[float_rprimitive],
result_type=object_rprimitive,
error_kind=ERR_MAGIC,
emit=call_emit('CPyLong_FromFloat'),
priority=1)
def int_binary_op(op: str, c_func_name: str,
result_type: RType = int_rprimitive,
error_kind: int = ERR_NEVER) -> None:
binary_op(op=op,
arg_types=[int_rprimitive, int_rprimitive],
result_type=result_type,
error_kind=error_kind,
format_str='{dest} = {args[0]} %s {args[1]} :: int' % op,
emit=call_emit(c_func_name))
def int_compare_op(op: str, c_func_name: str) -> None:
int_binary_op(op, c_func_name, bool_rprimitive)
# Generate a straight compare if we know both sides are short
binary_op(op=op,
arg_types=[short_int_rprimitive, short_int_rprimitive],
result_type=bool_rprimitive,
error_kind=ERR_NEVER,
format_str='{dest} = {args[0]} %s {args[1]} :: short_int' % op,
emit=simple_emit(
'{dest} = (Py_ssize_t){args[0]} %s (Py_ssize_t){args[1]};' % op),
priority=2)
int_binary_op('+', 'CPyTagged_Add')
int_binary_op('-', 'CPyTagged_Subtract')
int_binary_op('*', 'CPyTagged_Multiply')
# Divide and remainder we honestly propagate errors from because they
# can raise ZeroDivisionError
int_binary_op('//', 'CPyTagged_FloorDivide', error_kind=ERR_MAGIC)
int_binary_op('%', 'CPyTagged_Remainder', error_kind=ERR_MAGIC)
# this should work because assignment operators are parsed differently
# and the code in genops that handles it does the assignment
# regardless of whether or not the operator works in place anyway
int_binary_op('+=', 'CPyTagged_Add')
int_binary_op('-=', 'CPyTagged_Subtract')
int_binary_op('*=', 'CPyTagged_Multiply')
int_binary_op('//=', 'CPyTagged_FloorDivide', error_kind=ERR_MAGIC)
int_binary_op('%=', 'CPyTagged_Remainder', error_kind=ERR_MAGIC)
int_compare_op('==', 'CPyTagged_IsEq')
int_compare_op('!=', 'CPyTagged_IsNe')
int_compare_op('<', 'CPyTagged_IsLt')
int_compare_op('<=', 'CPyTagged_IsLe')
int_compare_op('>', 'CPyTagged_IsGt')
int_compare_op('>=', 'CPyTagged_IsGe')
unsafe_short_add = custom_op(
arg_types=[int_rprimitive, int_rprimitive],
result_type=short_int_rprimitive,
error_kind=ERR_NEVER,
format_str='{dest} = {args[0]} + {args[1]} :: short_int',
emit=simple_emit('{dest} = {args[0]} + {args[1]};'))
def int_unary_op(op: str, c_func_name: str) -> OpDescription:
return unary_op(op=op,
arg_type=int_rprimitive,
result_type=int_rprimitive,
error_kind=ERR_NEVER,
format_str='{dest} = %s{args[0]} :: int' % op,
emit=call_emit(c_func_name))
int_neg_op = int_unary_op('-', 'CPyTagged_Negate')