code cleanup for if-const dead code removal: move handling into ConstantFolding trans...
authorStefan Behnel <scoder@users.berlios.de>
Thu, 29 Apr 2010 06:00:37 +0000 (08:00 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Thu, 29 Apr 2010 06:00:37 +0000 (08:00 +0200)
--HG--
rename : tests/run/consts.pyx => tests/run/if_const.pyx

Cython/Compiler/Nodes.py
Cython/Compiler/Optimize.py
tests/run/consts.pyx
tests/run/if_const.pyx [new file with mode: 0644]

index ec8cc0d5e7c27846398ca970f9dbdbf63e6689ad..d4d3a556a00cbc3b09c67fdb009b5819db124bb3 100644 (file)
@@ -3880,34 +3880,16 @@ class IfStatNode(StatNode):
         if self.else_clause:
             self.else_clause.analyse_expressions(env)
 
-        # eliminate dead code based on constant condition results
-        if_clauses = []
-        condition_result = None
-        for if_clause in self.if_clauses:
-            condition_result = if_clause.get_constant_condition_result()
-            if condition_result != False:
-                if_clauses.append(if_clause)
-                if condition_result == True:
-                    # other conditions can no longer apply
-                    self.else_clause = None
-                    break
-        self.if_clauses = if_clauses
-        # FIXME: if only one active code body is left here, we can
-        # replace the whole node
-
     def generate_execution_code(self, code):
         code.mark_pos(self.pos)
-        if self.if_clauses:
-            end_label = code.new_label()
-            for if_clause in self.if_clauses:
-                if_clause.generate_execution_code(code, end_label)
-            if self.else_clause:
-                code.putln("/*else*/ {")
-                self.else_clause.generate_execution_code(code)
-                code.putln("}")
-            code.put_label(end_label)
-        elif self.else_clause:
+        end_label = code.new_label()
+        for if_clause in self.if_clauses:
+            if_clause.generate_execution_code(code, end_label)
+        if self.else_clause:
+            code.putln("/*else*/ {")
             self.else_clause.generate_execution_code(code)
+            code.putln("}")
+        code.put_label(end_label)
 
     def annotate(self, code):
         for if_clause in self.if_clauses:
@@ -3938,7 +3920,7 @@ class IfClauseNode(Node):
 
     def get_constant_condition_result(self):
         if self.condition.has_constant_result():
-            return self.condition.constant_result
+            return bool(self.condition.constant_result)
         else:
             return None
 
index 3a2262d8c35d6b3dcf166775d1121517bfcfa4f9..7da5a1f6cb0bc5f1e2aa589e268e9994ab58173e 100644 (file)
@@ -2570,6 +2570,36 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
         #new_node = new_node.coerce_to(node.type, self.current_scope)
         return new_node
 
+    def visit_PrimaryCmpNode(self, node):
+        self._calculate_const(node)
+        if node.constant_result is ExprNodes.not_a_constant:
+            return node
+        bool_result = bool(node.constant_result)
+        return ExprNodes.BoolNode(node.pos, value=bool_result,
+                                  constant_result=bool_result)
+
+    def visit_IfStatNode(self, node):
+        self.visitchildren(node)
+        # eliminate dead code based on constant condition results
+        if_clauses = []
+        condition_result = None
+        for if_clause in node.if_clauses:
+            condition_result = if_clause.get_constant_condition_result()
+            # condition_result is True, False or None (unknown)
+            if condition_result != False:
+                if_clauses.append(if_clause)
+                if condition_result == True:
+                    # other conditions can no longer apply
+                    node.else_clause = None
+                    break
+        if not if_clauses:
+            return node.else_clause # if None, deletes the node completely
+        elif len(if_clauses) == 1 and condition_result == True:
+            return if_clauses[0].body
+        else:
+            node.if_clauses = if_clauses
+            return node
+
     # in the future, other nodes can have their own handler method here
     # that can replace them with a constant result node
 
index 02327ad04aa87a6c29db4640efbd0b13fac7884a..a465c06ede4b12034037cd66e64f1cb0c4b72cd1 100644 (file)
@@ -67,6 +67,7 @@ def arithm():
     """
     return 9*2+3*8//6-10
 
+@cython.test_fail_if_path_exists("//BinopNode")
 def parameters():
     """
     >>> parameters() == _func(-1 -2, - (-3+4), 1*2*3)
@@ -74,6 +75,7 @@ def parameters():
     """
     return _func(-1 -2, - (-3+4), 1*2*3)
 
+@cython.test_fail_if_path_exists("//BinopNode")
 def lists():
     """
     >>> lists() == [1,2,3] + [4,5,6]
@@ -81,75 +83,10 @@ def lists():
     """
     return [1,2,3] + [4,5,6]
 
-def int_bool_result():
-    """
-    >>> int_bool_result()
-    True
-    """
-    if 5:
-        return True
-    else:
-        return False
-
-@cython.test_fail_if_path_exists("//PrimaryCmpNode")
-def if_compare_true():
-    """
-    >>> if_compare_true()
-    True
-    """
-    if 0 == 0:
-        return True
-    else:
-        return False
-
-@cython.test_fail_if_path_exists("//PrimaryCmpNode")
-def if_compare_false():
-    """
-    >>> if_compare_false()
-    False
-    """
-    if 0 == 1 or 1 == 0:
-        return True
-    else:
-        return False
-
 @cython.test_fail_if_path_exists("//PrimaryCmpNode")
-def if_compare_cascaded():
-    """
-    >>> if_compare_cascaded()
-    True
-    """
-    if 0 < 1 < 2 < 3:
-        return True
-    else:
-        return False
-
-@cython.test_fail_if_path_exists("//CoerceToBooleanNode",
-                                 "//ListNode")
-def list_bool_result():
-    """
-    >>> list_bool_result()
-    True
-    """
-    if [1,2,3]:
-        return True
-    else:
-        return False
-
 def compile_time_DEF():
     """
     >>> compile_time_DEF()
     (1, False, True, True, False)
     """
     return INT_VAL, INT_VAL == 0, INT_VAL != 0, INT_VAL == 1, INT_VAL != 1
-
-@cython.test_fail_if_path_exists("//PrimaryCmpNode")
-def compile_time_DEF_if():
-    """
-    >>> compile_time_DEF_if()
-    True
-    """
-    if INT_VAL != 0:
-        return True
-    else:
-        return False
diff --git a/tests/run/if_const.pyx b/tests/run/if_const.pyx
new file mode 100644 (file)
index 0000000..00c14f4
--- /dev/null
@@ -0,0 +1,136 @@
+
+cimport cython
+
+DEF INT_VAL = 1
+
+def int_bool_result():
+    """
+    >>> int_bool_result()
+    True
+    """
+    if 5:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//PrimaryCmpNode",
+                                 "//IfStatNode")
+def if_compare_true():
+    """
+    >>> if_compare_true()
+    True
+    """
+    if 0 == 0:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//PrimaryCmpNode",
+                                 "//IfStatNode")
+def if_compare_false():
+    """
+    >>> if_compare_false()
+    False
+    """
+    if 0 == 1:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//PrimaryCmpNode",
+                                 "//IfStatNode")
+def if_compare_or_true():
+    """
+    >>> if_compare_or_true()
+    True
+    """
+    if 0 == 1 or 1 == 1:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//PrimaryCmpNode",
+                                 "//IfStatNode")
+def if_compare_or_false():
+    """
+    >>> if_compare_or_false()
+    False
+    """
+    if 0 == 1 or 1 == 0:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//PrimaryCmpNode",
+                                 "//IfStatNode")
+def if_compare_and_true():
+    """
+    >>> if_compare_and_true()
+    True
+    """
+    if 0 == 0 and 1 == 1:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//PrimaryCmpNode",
+                                 "//IfStatNode")
+def if_compare_and_false():
+    """
+    >>> if_compare_and_false()
+    False
+    """
+    if 1 == 1 and 1 == 0:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//PrimaryCmpNode",
+                                 "//IfStatNode")
+def if_compare_cascaded():
+    """
+    >>> if_compare_cascaded()
+    True
+    """
+    if 0 < 1 < 2 < 3:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//CoerceToBooleanNode",
+                                 "//ListNode",
+                                 "//IfStatNode")
+def list_bool_result_true():
+    """
+    >>> list_bool_result_true()
+    True
+    """
+    if [1,2,3]:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//CoerceToBooleanNode",
+                                 "//ListNode",
+                                 "//IfStatNode")
+def list_bool_result_false():
+    """
+    >>> list_bool_result_false()
+    False
+    """
+    if []:
+        return True
+    else:
+        return False
+
+@cython.test_fail_if_path_exists("//PrimaryCmpNode",
+                                 "//IfStatNode")
+def compile_time_DEF_if():
+    """
+    >>> compile_time_DEF_if()
+    True
+    """
+    if INT_VAL != 0:
+        return True
+    else:
+        return False