From 245434dc15417a9907965078a6f0a95a7537f6cd Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Thu, 27 May 2010 08:34:58 +0200 Subject: [PATCH] drop sum(genexpr) into plain C code when the result is C typed --- Cython/Compiler/ExprNodes.py | 12 +++++++++++- Cython/Compiler/Optimize.py | 4 ++-- tests/run/inlined_generator_expressions.pyx | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index d1561447..3267022f 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -4037,10 +4037,13 @@ class GeneratorExpressionNode(ScopedExprNode): class InlinedGeneratorExpressionNode(GeneratorExpressionNode): # An inlined generator expression for which the result is - # calculated inside of the loop. + # calculated inside of the loop. This will only be created by + # transforms when replacing builtin calls on generator + # expressions. # # loop ForStatNode the for-loop, not containing any YieldExprNodes # result_node ResultRefNode the reference to the result value temp + # orig_func String the name of the builtin function this node replaces child_attrs = ["loop"] @@ -4048,6 +4051,13 @@ class InlinedGeneratorExpressionNode(GeneratorExpressionNode): self.type = self.result_node.type self.is_temp = True + def coerce_to(self, dst_type, env): + if self.orig_func == 'sum' and dst_type.is_numeric: + # we can optimise by dropping the aggregation variable into C + self.result_node.type = self.type = dst_type + return self + return GeneratorExpressionNode.coerce_to(self, dst_type, env) + def generate_result_code(self, code): self.result_node.result_code = self.result() self.loop.generate_execution_code(code) diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py index ad89d1ba..b8e9f747 100644 --- a/Cython/Compiler/Optimize.py +++ b/Cython/Compiler/Optimize.py @@ -1186,7 +1186,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): return ExprNodes.InlinedGeneratorExpressionNode( gen_expr_node.pos, loop = loop_node, result_node = result_ref, - expr_scope = gen_expr_node.expr_scope) + expr_scope = gen_expr_node.expr_scope, orig_func = is_any and 'any' or 'all') def _handle_simple_function_sum(self, node, pos_args): """Transform sum(genexpr) into an equivalent inlined aggregation loop. @@ -1230,7 +1230,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): return ExprNodes.InlinedGeneratorExpressionNode( gen_expr_node.pos, loop = exec_code, result_node = result_ref, - expr_scope = gen_expr_node.expr_scope) + expr_scope = gen_expr_node.expr_scope, orig_func = 'sum') # specific handlers for general call nodes diff --git a/tests/run/inlined_generator_expressions.pyx b/tests/run/inlined_generator_expressions.pyx index 4b6864c4..0787c2eb 100644 --- a/tests/run/inlined_generator_expressions.pyx +++ b/tests/run/inlined_generator_expressions.pyx @@ -15,6 +15,20 @@ def range_sum(int N): result = sum(i for i in range(N)) return result +@cython.test_assert_path_exists('//ForFromStatNode', + "//InlinedGeneratorExpressionNode") +@cython.test_fail_if_path_exists('//SimpleCallNode', + '//ForInStatNode') +def range_sum_typed(int N): + """ + >>> sum(range(10)) + 45 + >>> range_sum_typed(10) + 45 + """ + cdef int result = sum(i for i in range(N)) + return result + @cython.test_assert_path_exists('//ForFromStatNode', "//InlinedGeneratorExpressionNode") @cython.test_fail_if_path_exists('//SimpleCallNode', -- 2.26.2