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,22 +5805,16 @@ class SimpleCallNode(CallNode): ...@@ -5803,22 +5805,16 @@ 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):
ret = super(SimpleCallNode, cls).from_node(node, **kwargs)
ret.is_numpy_call_with_exprs = node.is_numpy_call_with_exprs
return ret
class PyMethodCallNode(SimpleCallNode): class NumPyMethodCallNode(SimpleCallNode):
# Specialised call to a (potential) PyMethodObject with non-constant argument tuple. # Pythran call to a NumPy function or method.
# Allows the self argument to be injected directly instead of repacking a tuple for it.
# #
# function ExprNode the function/method object to call # function ExprNode the function/method to call
# arg_tuple TupleNode the arguments for the args tuple # arg_tuple TupleNode the arguments as an args tuple
subexprs = ['function', 'arg_tuple'] subexprs = ['function', 'arg_tuple']
is_temp = True is_temp = True
may_return_none = True
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
code.mark_pos(self.pos) code.mark_pos(self.pos)
...@@ -5830,15 +5826,34 @@ class PyMethodCallNode(SimpleCallNode): ...@@ -5830,15 +5826,34 @@ 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("// function evaluation code for numpy function")
code.putln("__Pyx_call_destructor(%s);" % self.result()) code.putln("__Pyx_call_destructor(%s);" % self.result())
code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::%s{}(%s)};" % ( code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::%s{}(%s)};" % (
self.result(), self.result(),
self.result(), self.result(),
self.function.attribute, self.function.attribute,
", ".join(a.pythran_result() for a in self.arg_tuple.args))) ", ".join(a.pythran_result() for a in args)))
return
class PyMethodCallNode(SimpleCallNode):
# Specialised call to a (potential) PyMethodObject with non-constant argument tuple.
# Allows the self argument to be injected directly instead of repacking a tuple for it.
#
# function ExprNode the function/method object to call
# arg_tuple TupleNode the arguments for the args tuple
subexprs = ['function', 'arg_tuple']
is_temp = 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)
# 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
......
...@@ -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