better integer handling in constant folding, including type promotion
authorStefan Behnel <scoder@users.berlios.de>
Fri, 12 Nov 2010 22:03:10 +0000 (23:03 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Fri, 12 Nov 2010 22:03:10 +0000 (23:03 +0100)
Cython/Compiler/Optimize.py
tests/run/int_literals.pyx

index 460b6024ef3fc9ec1c51c1fff7223f37bcfb274c..9e4c66ef57f419a15d4d9043ea4e3575799e460c 100644 (file)
@@ -2984,29 +2984,36 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
         except AttributeError:
             return node
 
-        if type1 is type2:
-            new_node = node.operand1
-        else:
+        if type1.is_numeric and type2.is_numeric:
             widest_type = PyrexTypes.widest_numeric_type(type1, type2)
-            if type(node.operand1) is type(node.operand2):
-                new_node = node.operand1
-                new_node.type = widest_type
-            elif type1 is widest_type:
-                new_node = node.operand1
-            elif type2 is widest_type:
-                new_node = node.operand2
+        else:
+            widest_type = PyrexTypes.py_object_type
+        target_class = self._widest_node_class(node.operand1, node.operand2)
+        if target_class is None:
+            return node
+        elif target_class is ExprNodes.IntNode:
+            unsigned = getattr(node.operand1, 'unsigned', '') and \
+                       getattr(node.operand2, 'unsigned', '')
+            longness = "LL"[:max(len(getattr(node.operand1, 'longness', '')),
+                                 len(getattr(node.operand2, 'longness', '')))]
+            new_node = ExprNodes.IntNode(pos=node.pos,
+                                         unsigned = unsigned, longness = longness,
+                                         value = str(node.constant_result),
+                                         constant_result = node.constant_result)
+            # IntNode is smart about the type it chooses, so we just
+            # make sure we were not smarter this time
+            if widest_type.is_pyobject or new_node.type.is_pyobject:
+                new_node.type = PyrexTypes.py_object_type
             else:
-                target_class = self._widest_node_class(
-                    node.operand1, node.operand2)
-                if target_class is None:
-                    return node
-                new_node = target_class(pos=node.pos, type = widest_type)
-
-        new_node.constant_result = node.constant_result
-        if isinstance(node, ExprNodes.BoolNode):
-            new_node.value = node.constant_result
+                new_node.type = PyrexTypes.widest_numeric_type(widest_type, new_node.type)
         else:
-            new_node.value = str(node.constant_result)
+            if isinstance(node, ExprNodes.BoolNode):
+                node_value = node.constant_result
+            else:
+                node_value = str(node.constant_result)
+            new_node = target_class(pos=node.pos, type = widest_type,
+                                    value = node_value,
+                                    constant_result = node.constant_result)
         return new_node
 
     def visit_PrimaryCmpNode(self, node):
index b5aa67cb8224b5ea64edd26972fa129a3de9cf48..511aef5c2401149cdb4e056481001f0c874ed42f 100644 (file)
@@ -3,11 +3,18 @@ __doc__ = u"""
 (1, 1L, -1L, 18446744073709551615L)
 >>> py_longs()
 (1, 1L, 100000000000000000000000000000000L, -100000000000000000000000000000000L)
+
+>>> py_huge_calculated_long()
+1606938044258990275541962092341162602522202993782792835301376L
+>>> py_huge_computation_small_result_neg()
+(-2535301200456458802993406410752L, -2535301200456458802993406410752L)
 """
 
-import sys
+cimport cython
 from cython cimport typeof
 
+import sys
+
 if sys.version_info[0] >= 3:
     __doc__ = __doc__.replace(u'L', u'')
 
@@ -27,6 +34,25 @@ def c_longs():
 def py_longs():
     return 1, 1L, 100000000000000000000000000000000, -100000000000000000000000000000000
 
+@cython.test_fail_if_path_exists("//NumBinopNode", "//IntBinopNode")
+@cython.test_assert_path_exists("//ReturnStatNode/IntNode")
+def py_huge_calculated_long():
+    return 1 << 200
+
+@cython.test_fail_if_path_exists("//NumBinopNode", "//IntBinopNode")
+@cython.test_assert_path_exists("//ReturnStatNode/IntNode")
+def py_huge_computation_small_result():
+    """
+    >>> py_huge_computation_small_result()
+    2
+    """
+    return (1 << 200) >> 199
+
+@cython.test_fail_if_path_exists("//NumBinopNode", "//IntBinopNode")
+#@cython.test_assert_path_exists("//ReturnStatNode/IntNode")
+def py_huge_computation_small_result_neg():
+    return -(2 ** 101), (-2) ** 101
+
 def large_literal():
     """
     >>> type(large_literal()) is int