From c14e8aea282a5e115c19d3b910d5a8cb40bb7326 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Thu, 29 Apr 2010 08:00:37 +0200 Subject: [PATCH] code cleanup for if-const dead code removal: move handling into ConstantFolding transform, where it can also replace the entire node --HG-- rename : tests/run/consts.pyx => tests/run/if_const.pyx --- Cython/Compiler/Nodes.py | 34 +++------ Cython/Compiler/Optimize.py | 30 ++++++++ tests/run/consts.pyx | 67 +----------------- tests/run/if_const.pyx | 136 ++++++++++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 91 deletions(-) create mode 100644 tests/run/if_const.pyx diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index ec8cc0d5..d4d3a556 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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 diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py index 3a2262d8..7da5a1f6 100644 --- a/Cython/Compiler/Optimize.py +++ b/Cython/Compiler/Optimize.py @@ -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 diff --git a/tests/run/consts.pyx b/tests/run/consts.pyx index 02327ad0..a465c06e 100644 --- a/tests/run/consts.pyx +++ b/tests/run/consts.pyx @@ -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 index 00000000..00c14f4d --- /dev/null +++ b/tests/run/if_const.pyx @@ -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 -- 2.26.2