Commit 4ed665be authored by scoder's avatar scoder Committed by GitHub

Merge pull request #2469 from aguinet/fix/pythran_numpy

Pythran: verify that pythran supports called Numpy APIs
parents fb0e935a 779d5db1
...@@ -43,9 +43,10 @@ from . import Future ...@@ -43,9 +43,10 @@ from . import Future
from ..Debugging import print_call_chain from ..Debugging import print_call_chain
from .DebugFlags import debug_disposal_code, debug_temp_alloc, \ from .DebugFlags import debug_disposal_code, debug_temp_alloc, \
debug_coercion debug_coercion
from .Pythran import to_pythran, is_pythran_supported_type, is_pythran_supported_operation_type, \ from .Pythran import (to_pythran, is_pythran_supported_type, is_pythran_supported_operation_type,
is_pythran_expr, pythran_func_type, pythran_binop_type, pythran_unaryop_type, has_np_pythran, \ is_pythran_expr, pythran_func_type, pythran_binop_type, pythran_unaryop_type, has_np_pythran,
pythran_indexing_code, pythran_indexing_type, is_pythran_supported_node_or_none, pythran_type pythran_indexing_code, pythran_indexing_type, is_pythran_supported_node_or_none, pythran_type,
pythran_is_numpy_func_supported, pythran_get_func_include_file, pythran_functor)
from .PyrexTypes import PythranExpr from .PyrexTypes import PythranExpr
try: try:
...@@ -5408,7 +5409,8 @@ class SimpleCallNode(CallNode): ...@@ -5408,7 +5409,8 @@ class SimpleCallNode(CallNode):
func_type = self.function_type() func_type = self.function_type()
self.is_numpy_call_with_exprs = False self.is_numpy_call_with_exprs = False
if has_np_pythran(env) and self.function.is_numpy_attribute: if (has_np_pythran(env) and function.is_numpy_attribute and
pythran_is_numpy_func_supported(function)):
has_pythran_args = True has_pythran_args = True
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) self.arg_tuple = self.arg_tuple.analyse_types(env)
...@@ -5416,12 +5418,12 @@ class SimpleCallNode(CallNode): ...@@ -5416,12 +5418,12 @@ 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:
env.add_include_file("pythonic/numpy/%s.hpp" % self.function.attribute) env.add_include_file(pythran_get_func_include_file(function))
return NumPyMethodCallNode.from_node( return NumPyMethodCallNode.from_node(
self, self,
function=self.function, function=function,
arg_tuple=self.arg_tuple, arg_tuple=self.arg_tuple,
type=PythranExpr(pythran_func_type(self.function.attribute, self.arg_tuple.args)), type=PythranExpr(pythran_func_type(function, 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)
...@@ -5839,10 +5841,10 @@ class NumPyMethodCallNode(SimpleCallNode): ...@@ -5839,10 +5841,10 @@ class NumPyMethodCallNode(SimpleCallNode):
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){%s{}(%s)};" % (
self.result(), self.result(),
self.result(), self.result(),
self.function.attribute, pythran_functor(self.function),
", ".join(a.pythran_result() for a in args))) ", ".join(a.pythran_result() for a in args)))
......
...@@ -613,7 +613,8 @@ class TrackNumpyAttributes(VisitorTransform, SkipDeclarations): ...@@ -613,7 +613,8 @@ class TrackNumpyAttributes(VisitorTransform, SkipDeclarations):
def visit_AttributeNode(self, node): def visit_AttributeNode(self, node):
self.visitchildren(node) self.visitchildren(node)
if node.obj.is_name and node.obj.name in self.numpy_module_names: if (node.obj.is_name and node.obj.name in self.numpy_module_names) or \
node.obj.is_numpy_attribute:
node.is_numpy_attribute = True node.is_numpy_attribute = True
return node return node
......
...@@ -6,16 +6,20 @@ from .PyrexTypes import CType, CTypedefType, CStructOrUnionType ...@@ -6,16 +6,20 @@ from .PyrexTypes import CType, CTypedefType, CStructOrUnionType
import cython import cython
try:
import pythran
_pythran_available = True
except ImportError:
_pythran_available = False
# Pythran/Numpy specific operations # Pythran/Numpy specific operations
def has_np_pythran(env): def has_np_pythran(env):
while env is not None: if env is None:
directives = getattr(env, 'directives', None) return False
if directives and env.directives.get('np_pythran', False): directives = getattr(env, 'directives', None)
return True return (directives and directives.get('np_pythran', False))
env = env.outer_scope
@cython.ccall @cython.ccall
def is_pythran_supported_dtype(type_): def is_pythran_supported_dtype(type_):
...@@ -111,10 +115,32 @@ def pythran_indexing_type(type_, indices): ...@@ -111,10 +115,32 @@ def pythran_indexing_type(type_, indices):
def pythran_indexing_code(indices): def pythran_indexing_code(indices):
return _index_access(_index_code, indices) return _index_access(_index_code, indices)
def np_func_to_list(func):
if not func.is_numpy_attribute:
return []
return np_func_to_list(func.obj) + [func.attribute]
if _pythran_available:
def pythran_is_numpy_func_supported(func):
CurF = pythran.tables.MODULES['numpy']
FL = np_func_to_list(func)
for F in FL:
CurF = CurF.get(F, None)
if CurF is None:
return False
return True
else:
def pythran_is_numpy_func_supported(name):
return False
def pythran_functor(func):
func = np_func_to_list(func)
submodules = "::".join(func[:-1] + ["functor"])
return "pythonic::numpy::%s::%s" % (submodules, func[-1])
def pythran_func_type(func, args): def pythran_func_type(func, args):
args = ",".join(("std::declval<%s>()" % pythran_type(a.type) for a in args)) args = ",".join(("std::declval<%s>()" % pythran_type(a.type) for a in args))
return "decltype(pythonic::numpy::functor::%s{}(%s))" % (func, args) return "decltype(%s{}(%s))" % (pythran_functor(func), args)
@cython.ccall @cython.ccall
...@@ -168,6 +194,9 @@ def is_pythran_buffer(type_): ...@@ -168,6 +194,9 @@ def is_pythran_buffer(type_):
return (type_.is_numpy_buffer and is_pythran_supported_dtype(type_.dtype) and return (type_.is_numpy_buffer and is_pythran_supported_dtype(type_.dtype) and
type_.mode in ("c", "strided") and not type_.cast) type_.mode in ("c", "strided") and not type_.cast)
def pythran_get_func_include_file(func):
func = np_func_to_list(func)
return "pythonic/include/numpy/%s.hpp" % "/".join(func)
def include_pythran_generic(env): def include_pythran_generic(env):
# Generic files # Generic files
......
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