From a60c780156bc7d862ff240f73c18a3108dfe95b5 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Wed, 25 Mar 2009 19:10:09 -0700 Subject: [PATCH] cdivision pragma as specified for CEP 516 --- Cython/Compiler/ExprNodes.py | 100 +++++++++++++++++++++++++------- Cython/Compiler/Options.py | 16 ++--- tests/run/cdivision_CEP_516.pyx | 14 +++++ 3 files changed, 102 insertions(+), 28 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 7599d16c..5c998ebe 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -4229,14 +4229,27 @@ class MulNode(NumBinopNode): return NumBinopNode.is_py_operation(self) -class FloorDivNode(NumBinopNode): - # '//' operator. +class DivNode(NumBinopNode): + # '/' or '//' operator. + + def generate_evaluation_code(self, code): + self.cdivision = (code.globalstate.directives['cdivision'] + or not self.type.signed + or self.type.is_float) + if not self.cdivision: + code.globalstate.use_utility_code(div_utility_code.specialize(self.type)) + NumBinopNode.generate_evaluation_code(self, code) def calculate_result_code(self): - return "(%s %s %s)" % ( - self.operand1.result(), - "/", # c division is by default floor-div - self.operand2.result()) + if self.cdivision: + return "(%s / %s)" % ( + self.operand1.result(), + self.operand2.result()) + else: + return "__Pyx_div_%s(%s, %s)" % ( + self.type.specalization_name(), + self.operand1.result(), + self.operand2.result()) class ModNode(NumBinopNode): @@ -4247,15 +4260,31 @@ class ModNode(NumBinopNode): or self.operand2.type.is_string or NumBinopNode.is_py_operation(self)) + def generate_evaluation_code(self, code): + self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed + if not self.cdivision: + math_h_modifier = getattr(self.type, 'math_h_modifier', '__Pyx_INT') + if self.type.is_int: + code.globalstate.use_utility_code(mod_int_helper_macro) + code.globalstate.use_utility_code(mod_utility_code.specialize(self.type, math_h_modifier=math_h_modifier)) + NumBinopNode.generate_evaluation_code(self, code) + def calculate_result_code(self): - if self.operand1.type.is_float or self.operand2.type.is_float: - return "fmod(%s, %s)" % ( - self.operand1.result(), - self.operand2.result()) + if self.cdivision: + if self.type.is_float: + return "fmod%s(%s, %s)" % ( + self.type.math_h_modifier, + self.operand1.result(), + self.operand2.result()) + else: + return "(%s %% %s)" % ( + self.operand1.result(), + self.operand2.result()) else: - return "(%s %% %s)" % ( - self.operand1.result(), - self.operand2.result()) + return "__Pyx_mod_%s(%s, %s)" % ( + self.type.specalization_name(), + self.operand1.result(), + self.operand2.result()) class PowNode(NumBinopNode): # '**' operator. @@ -4852,20 +4881,20 @@ class CascadedCmpNode(Node, CmpNode): binop_node_classes = { - "or": BoolBinopNode, - "and": BoolBinopNode, + "or": BoolBinopNode, + "and": BoolBinopNode, "|": IntBinopNode, "^": IntBinopNode, "&": IntBinopNode, - "<<": IntBinopNode, - ">>": IntBinopNode, + "<<": IntBinopNode, + ">>": IntBinopNode, "+": AddNode, "-": SubNode, "*": MulNode, - "/": NumBinopNode, - "//": FloorDivNode, + "/": DivNode, + "//": DivNode, "%": ModNode, - "**": PowNode + "**": PowNode } def binop_node(pos, operator, operand1, operand2): @@ -5639,3 +5668,34 @@ static INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) { return t; } """) + +# ------------------------------ Division ------------------------------------ + +# This is so we can treat floating point and integer mod simultaneously. +mod_int_helper_macro = UtilityCode(proto=""" +#define fmod__Pyx_INT(a, b) ((a) % (b)) +""") + +mod_utility_code = UtilityCode( +proto=""" +static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */ +""", +impl=""" +static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) { + %(type)s res = fmod%(math_h_modifier)s(a, b); + res += (res * b < 0) * b; + return res; +} +""") + +div_utility_code = UtilityCode( +proto=""" +static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s, %(type)s); /* proto */ +""", +impl=""" +static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) { + %(type)s res = a / b; + res -= (res < 0); + return res; +} +""") diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index 84b692b0..de14a810 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -55,22 +55,22 @@ c_line_in_traceback = 1 # Declare pragmas -option_types = { - 'boundscheck' : bool, - 'nonecheck' : bool, - 'embedsignature' : bool, - 'locals' : dict, - 'auto_cpdef': bool, -} - option_defaults = { 'boundscheck' : True, 'nonecheck' : False, 'embedsignature' : False, 'locals' : {}, 'auto_cpdef': False, + 'cdivision': True, # Will be False in 0.12 } +# Override types possibilities above, if needed +option_types = { } + +for key, val in option_defaults.items(): + if key not in option_types: + option_types[key] = type(val) + def parse_option_value(name, value): """ Parses value as an option value for the given name and returns diff --git a/tests/run/cdivision_CEP_516.pyx b/tests/run/cdivision_CEP_516.pyx index ecb66a22..163fc2b3 100644 --- a/tests/run/cdivision_CEP_516.pyx +++ b/tests/run/cdivision_CEP_516.pyx @@ -18,6 +18,11 @@ True [7.0, -7.0, -7.0, 7.0] >>> [mod_double_c(a, b) for a, b in v] [7.0, -7.0, -7.0, 7.0] + +>>> [div_int_py(a, b) for a, b in v] +[1, -2, 1, -2] +>>> [div_int_c(a, b) for a, b in v] +[1, -1, 1, -1] """ cimport cython @@ -50,3 +55,12 @@ def mod_float_c(float a, float b): def mod_double_c(double a, double b): return a % b + +@cython.cdivision(False) +def div_int_py(int a, int b): + return a // b + +@cython.cdivision(True) +def div_int_c(int a, int b): + return a // b + -- 2.26.2