Left shift overflow guards.
authorRobert Bradshaw <robertwb@gmail.com>
Thu, 25 Oct 2012 07:11:07 +0000 (00:11 -0700)
committerRobert Bradshaw <robertwb@gmail.com>
Thu, 25 Oct 2012 07:11:07 +0000 (00:11 -0700)
Cython/Compiler/ExprNodes.py
Cython/Compiler/PyrexTypes.py
Cython/Utility/Overflow.c
tests/run/overflow_check.pxi

index 762ef26..031811f 100755 (executable)
@@ -8011,10 +8011,10 @@ class NumBinopNode(BinopNode):
             return
         if self.type.is_complex:
             self.infix = False
-        if self.type.is_int and env.directives['overflowcheck'] and self.operator in ('+', '-', '*'):
+        if self.type.is_int and env.directives['overflowcheck'] and self.operator in self.overflow_op_names:
             self.overflow_check = True
             self.func = self.type.overflow_check_binop(
-                self.op_names[self.operator],
+                self.overflow_op_names[self.operator],
                 env,
                 const_rhs = self.operand2.has_constant_result())
             self.is_temp = True
@@ -8118,10 +8118,11 @@ class NumBinopNode(BinopNode):
         "**":       "PyNumber_Power"
     }
     
-    op_names = {
+    overflow_op_names = {
        "+":  "add",
        "-":  "sub",
        "*":  "mul",
+       "<<":  "lshift",
     }
 
 class IntBinopNode(NumBinopNode):
index c0a51c0..308fa30 100755 (executable)
@@ -403,14 +403,17 @@ class CTypedefType(BaseType):
         return self.typedef_base_type.create_from_py_utility_code(env)
 
     def overflow_check_binop(self, binop, env, const_rhs=False):
-        if const_rhs:
-            binop += "_const"
         env.use_utility_code(UtilityCode.load("Common", "Overflow.c"))
         type = self.declaration_code("")
         name = self.specialization_name()
-        _load_overflow_base(env)
-        env.use_utility_code(TempitaUtilityCode.load("SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name}))
-        env.use_utility_code(TempitaUtilityCode.load("Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop}))
+        if binop == "lshift":
+            env.use_utility_code(TempitaUtilityCode.load("LeftShift", "Overflow.c", context={'TYPE': type, 'NAME': name}))
+        else:
+            if const_rhs:
+                binop += "_const"
+            _load_overflow_base(env)
+            env.use_utility_code(TempitaUtilityCode.load("SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name}))
+            env.use_utility_code(TempitaUtilityCode.load("Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop}))
         return "__Pyx_%s_%s_checking_overflow" % (binop, name)
 
     def error_condition(self, result_code):
@@ -1563,19 +1566,22 @@ class CIntType(CNumericType):
         env.use_utility_code(UtilityCode.load("Common", "Overflow.c"))
         type = self.declaration_code("")
         name = self.specialization_name()
-        if const_rhs:
-            binop += "_const"
-        if type in ('int', 'long', 'long long'):
-            env.use_utility_code(TempitaUtilityCode.load("BaseCaseSigned", "Overflow.c", context={'INT': type, 'NAME': name}))
-        elif type in ('unsigned int', 'unsigned long', 'unsigned long long'):
-            env.use_utility_code(TempitaUtilityCode.load("BaseCaseUnsigned", "Overflow.c", context={'UINT': type, 'NAME': name}))
-        elif self.rank <= 1:
-            # sizeof(short) < sizeof(int)
-            return "__Pyx_%s_%s_no_overflow" % (binop, name)
+        if binop == "lshift":
+            env.use_utility_code(TempitaUtilityCode.load("LeftShift", "Overflow.c", context={'TYPE': type, 'NAME': name}))
         else:
-            _load_overflow_base(env)
-            env.use_utility_code(TempitaUtilityCode.load("SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name}))
-            env.use_utility_code(TempitaUtilityCode.load("Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop}))
+            if const_rhs:
+                binop += "_const"
+            if type in ('int', 'long', 'long long'):
+                env.use_utility_code(TempitaUtilityCode.load("BaseCaseSigned", "Overflow.c", context={'INT': type, 'NAME': name}))
+            elif type in ('unsigned int', 'unsigned long', 'unsigned long long'):
+                env.use_utility_code(TempitaUtilityCode.load("BaseCaseUnsigned", "Overflow.c", context={'UINT': type, 'NAME': name}))
+            elif self.rank <= 1:
+                # sizeof(short) < sizeof(int)
+                return "__Pyx_%s_%s_no_overflow" % (binop, name)
+            else:
+                _load_overflow_base(env)
+                env.use_utility_code(TempitaUtilityCode.load("SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name}))
+                env.use_utility_code(TempitaUtilityCode.load("Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop}))
         return "__Pyx_%s_%s_checking_overflow" % (binop, name)
 
 def _load_overflow_base(env):
index 2b2f850..23b44a9 100644 (file)
@@ -268,3 +268,12 @@ static CYTHON_INLINE {{TYPE}} __Pyx_{{BINOP}}_{{NAME}}_checking_overflow({{TYPE}
         }
     }
 }
+
+/////////////// LeftShift.proto ///////////////
+
+static CYTHON_INLINE {{TYPE}} __Pyx_lshift_{{NAME}}_checking_overflow({{TYPE}} a, {{TYPE}} b, int *overflow) {
+    *overflow |= (b < 0) | (b > (8 * sizeof({{TYPE}}))) | (a > (__PYX_MAX({{TYPE}}) >> b));
+    return a << b;
+}
+#define __Pyx_lshift_const_{{NAME}}_checking_overflow __Pyx_lshift_{{NAME}}_checking_overflow
+
index 9a6936b..1bf9610 100644 (file)
@@ -206,3 +206,19 @@ def test_mul_const(INT a):
     True
     """
     return int(a * <INT>100)
+
+@cython.overflowcheck(True)
+def test_lshift(INT a, int b):
+    """
+    >>> test_lshift(1, 10)
+    1024
+    >>> expect_overflow(test_lshift, 1, 100)
+    >>> expect_overflow(test_lshift, max_value, 1)
+    >>> test_lshift(max_value, 0) == max_value
+    True
+    
+    >>> check(test_lshift, operator.lshift, 10, 15)
+    >>> check(test_lshift, operator.lshift, 10, 30)
+    >>> check(test_lshift, operator.lshift, 100, 60)
+    """
+    return int(a << b)