Commit c3801e87 authored by Stefan Behnel's avatar Stefan Behnel

Use a dedicated ExprNode class for Pythran implemented NumPy methods to move...

Use a dedicated ExprNode class for Pythran implemented NumPy methods to move them out of the way of Python call optimisations.
parent 5ceacd69
...@@ -5403,11 +5403,13 @@ class SimpleCallNode(CallNode): ...@@ -5403,11 +5403,13 @@ class SimpleCallNode(CallNode):
has_pythran_args &= is_pythran_supported_node_or_none(arg) has_pythran_args &= is_pythran_supported_node_or_none(arg)
self.is_numpy_call_with_exprs = bool(has_pythran_args) self.is_numpy_call_with_exprs = bool(has_pythran_args)
if self.is_numpy_call_with_exprs: if self.is_numpy_call_with_exprs:
self.args = None
env.add_include_file("pythonic/numpy/%s.hpp" % self.function.attribute) env.add_include_file("pythonic/numpy/%s.hpp" % self.function.attribute)
self.type = PythranExpr(pythran_func_type(self.function.attribute, self.arg_tuple.args)) return NumPyMethodCallNode.from_node(
self.may_return_none = True self,
self.is_temp = 1 function=self.function,
arg_tuple=self.arg_tuple,
type=PythranExpr(pythran_func_type(self.function.attribute, self.arg_tuple.args)),
)
elif func_type.is_pyobject: elif func_type.is_pyobject:
self.arg_tuple = TupleNode(self.pos, args = self.args) self.arg_tuple = TupleNode(self.pos, args = self.args)
self.arg_tuple = self.arg_tuple.analyse_types(env).coerce_to_pyobject(env) self.arg_tuple = self.arg_tuple.analyse_types(env).coerce_to_pyobject(env)
...@@ -5803,11 +5805,34 @@ class SimpleCallNode(CallNode): ...@@ -5803,11 +5805,34 @@ class SimpleCallNode(CallNode):
if self.has_optional_args: if self.has_optional_args:
code.funcstate.release_temp(self.opt_arg_struct) code.funcstate.release_temp(self.opt_arg_struct)
@classmethod
def from_node(cls, node, **kwargs): class NumPyMethodCallNode(SimpleCallNode):
ret = super(SimpleCallNode, cls).from_node(node, **kwargs) # Pythran call to a NumPy function or method.
ret.is_numpy_call_with_exprs = node.is_numpy_call_with_exprs #
return ret # function ExprNode the function/method to call
# arg_tuple TupleNode the arguments as an args tuple
subexprs = ['function', 'arg_tuple']
is_temp = True
may_return_none = True
def generate_evaluation_code(self, code):
code.mark_pos(self.pos)
self.allocate_temp_result(code)
self.function.generate_evaluation_code(code)
assert self.arg_tuple.mult_factor is None
args = self.arg_tuple.args
for arg in args:
arg.generate_evaluation_code(code)
code.putln("// function evaluation code for numpy function")
code.putln("__Pyx_call_destructor(%s);" % self.result())
code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::%s{}(%s)};" % (
self.result(),
self.result(),
self.function.attribute,
", ".join(a.pythran_result() for a in args)))
class PyMethodCallNode(SimpleCallNode): class PyMethodCallNode(SimpleCallNode):
...@@ -5830,16 +5855,6 @@ class PyMethodCallNode(SimpleCallNode): ...@@ -5830,16 +5855,6 @@ class PyMethodCallNode(SimpleCallNode):
for arg in args: for arg in args:
arg.generate_evaluation_code(code) arg.generate_evaluation_code(code)
if self.is_numpy_call_with_exprs:
code.putln("// function evaluation code for numpy function")
code.putln("__Pyx_call_destructor(%s);" % self.result())
code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::%s{}(%s)};" % (
self.result(),
self.result(),
self.function.attribute,
", ".join(a.pythran_result() for a in self.arg_tuple.args)))
return
# make sure function is in temp so that we can replace the reference below if it's a method # make sure function is in temp so that we can replace the reference below if it's a method
reuse_function_temp = self.function.is_temp reuse_function_temp = self.function.is_temp
if reuse_function_temp: if reuse_function_temp:
......
...@@ -4657,6 +4657,11 @@ class FinalOptimizePhase(Visitor.CythonTransform, Visitor.NodeRefCleanupMixin): ...@@ -4657,6 +4657,11 @@ class FinalOptimizePhase(Visitor.CythonTransform, Visitor.NodeRefCleanupMixin):
node, function=function, arg_tuple=node.arg_tuple, type=node.type)) node, function=function, arg_tuple=node.arg_tuple, type=node.type))
return node return node
def visit_NumPyMethodCallNode(self, node):
# Exclude from replacement above.
self.visitchildren(node)
return node
def visit_PyTypeTestNode(self, node): def visit_PyTypeTestNode(self, node):
"""Remove tests for alternatively allowed None values from """Remove tests for alternatively allowed None values from
type tests when we know that the argument cannot be None type tests when we know that the argument cannot be None
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment