Pythran.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. # cython: language_level=3
  2. from __future__ import absolute_import
  3. from .PyrexTypes import CType, CTypedefType, CStructOrUnionType
  4. import cython
  5. try:
  6. import pythran
  7. pythran_is_pre_0_9 = tuple(map(int, pythran.__version__.split('.')[0:2])) < (0, 9)
  8. pythran_is_pre_0_9_6 = tuple(map(int, pythran.__version__.split('.')[0:3])) < (0, 9, 6)
  9. except ImportError:
  10. pythran = None
  11. pythran_is_pre_0_9 = True
  12. pythran_is_pre_0_9_6 = True
  13. if pythran_is_pre_0_9_6:
  14. pythran_builtins = '__builtin__'
  15. else:
  16. pythran_builtins = 'builtins'
  17. # Pythran/Numpy specific operations
  18. def has_np_pythran(env):
  19. if env is None:
  20. return False
  21. directives = getattr(env, 'directives', None)
  22. return (directives and directives.get('np_pythran', False))
  23. @cython.ccall
  24. def is_pythran_supported_dtype(type_):
  25. if isinstance(type_, CTypedefType):
  26. return is_pythran_supported_type(type_.typedef_base_type)
  27. return type_.is_numeric
  28. def pythran_type(Ty, ptype="ndarray"):
  29. if Ty.is_buffer:
  30. ndim,dtype = Ty.ndim, Ty.dtype
  31. if isinstance(dtype, CStructOrUnionType):
  32. ctype = dtype.cname
  33. elif isinstance(dtype, CType):
  34. ctype = dtype.sign_and_name()
  35. elif isinstance(dtype, CTypedefType):
  36. ctype = dtype.typedef_cname
  37. else:
  38. raise ValueError("unsupported type %s!" % dtype)
  39. if pythran_is_pre_0_9:
  40. return "pythonic::types::%s<%s,%d>" % (ptype,ctype, ndim)
  41. else:
  42. return "pythonic::types::%s<%s,pythonic::types::pshape<%s>>" % (ptype,ctype, ",".join(("long",)*ndim))
  43. if Ty.is_pythran_expr:
  44. return Ty.pythran_type
  45. #if Ty.is_none:
  46. # return "decltype(pythonic::builtins::None)"
  47. if Ty.is_numeric:
  48. return Ty.sign_and_name()
  49. raise ValueError("unsupported pythran type %s (%s)" % (Ty, type(Ty)))
  50. @cython.cfunc
  51. def type_remove_ref(ty):
  52. return "typename std::remove_reference<%s>::type" % ty
  53. def pythran_binop_type(op, tA, tB):
  54. if op == '**':
  55. return 'decltype(pythonic::numpy::functor::power{}(std::declval<%s>(), std::declval<%s>()))' % (
  56. pythran_type(tA), pythran_type(tB))
  57. else:
  58. return "decltype(std::declval<%s>() %s std::declval<%s>())" % (
  59. pythran_type(tA), op, pythran_type(tB))
  60. def pythran_unaryop_type(op, type_):
  61. return "decltype(%sstd::declval<%s>())" % (
  62. op, pythran_type(type_))
  63. @cython.cfunc
  64. def _index_access(index_code, indices):
  65. indexing = ",".join([index_code(idx) for idx in indices])
  66. return ('[%s]' if len(indices) == 1 else '(%s)') % indexing
  67. def _index_type_code(index_with_type):
  68. idx, index_type = index_with_type
  69. if idx.is_slice:
  70. n = 2 + int(not idx.step.is_none)
  71. return "pythonic::%s::functor::slice{}(%s)" % (
  72. pythran_builtins,
  73. ",".join(["0"]*n))
  74. elif index_type.is_int:
  75. return "std::declval<%s>()" % index_type.sign_and_name()
  76. elif index_type.is_pythran_expr:
  77. return "std::declval<%s>()" % index_type.pythran_type
  78. raise ValueError("unsupported indexing type %s!" % index_type)
  79. def _index_code(idx):
  80. if idx.is_slice:
  81. values = idx.start, idx.stop, idx.step
  82. if idx.step.is_none:
  83. func = "contiguous_slice"
  84. values = values[:2]
  85. else:
  86. func = "slice"
  87. return "pythonic::types::%s(%s)" % (
  88. func, ",".join((v.pythran_result() for v in values)))
  89. elif idx.type.is_int:
  90. return to_pythran(idx)
  91. elif idx.type.is_pythran_expr:
  92. return idx.pythran_result()
  93. raise ValueError("unsupported indexing type %s" % idx.type)
  94. def pythran_indexing_type(type_, indices):
  95. return type_remove_ref("decltype(std::declval<%s>()%s)" % (
  96. pythran_type(type_),
  97. _index_access(_index_type_code, indices),
  98. ))
  99. def pythran_indexing_code(indices):
  100. return _index_access(_index_code, indices)
  101. def np_func_to_list(func):
  102. if not func.is_numpy_attribute:
  103. return []
  104. return np_func_to_list(func.obj) + [func.attribute]
  105. if pythran is None:
  106. def pythran_is_numpy_func_supported(name):
  107. return False
  108. else:
  109. def pythran_is_numpy_func_supported(func):
  110. CurF = pythran.tables.MODULES['numpy']
  111. FL = np_func_to_list(func)
  112. for F in FL:
  113. CurF = CurF.get(F, None)
  114. if CurF is None:
  115. return False
  116. return True
  117. def pythran_functor(func):
  118. func = np_func_to_list(func)
  119. submodules = "::".join(func[:-1] + ["functor"])
  120. return "pythonic::numpy::%s::%s" % (submodules, func[-1])
  121. def pythran_func_type(func, args):
  122. args = ",".join(("std::declval<%s>()" % pythran_type(a.type) for a in args))
  123. return "decltype(%s{}(%s))" % (pythran_functor(func), args)
  124. @cython.ccall
  125. def to_pythran(op, ptype=None):
  126. op_type = op.type
  127. if op_type.is_int:
  128. # Make sure that integer literals always have exactly the type that the templates expect.
  129. return op_type.cast_code(op.result())
  130. if is_type(op_type, ["is_pythran_expr", "is_numeric", "is_float", "is_complex"]):
  131. return op.result()
  132. if op.is_none:
  133. return "pythonic::%s::None" % pythran_builtins
  134. if ptype is None:
  135. ptype = pythran_type(op_type)
  136. assert op.type.is_pyobject
  137. return "from_python<%s>(%s)" % (ptype, op.py_result())
  138. @cython.cfunc
  139. def is_type(type_, types):
  140. for attr in types:
  141. if getattr(type_, attr, False):
  142. return True
  143. return False
  144. def is_pythran_supported_node_or_none(node):
  145. return node.is_none or is_pythran_supported_type(node.type)
  146. @cython.ccall
  147. def is_pythran_supported_type(type_):
  148. pythran_supported = (
  149. "is_pythran_expr", "is_int", "is_numeric", "is_float", "is_none", "is_complex")
  150. return is_type(type_, pythran_supported) or is_pythran_expr(type_)
  151. def is_pythran_supported_operation_type(type_):
  152. pythran_supported = (
  153. "is_pythran_expr", "is_int", "is_numeric", "is_float", "is_complex")
  154. return is_type(type_,pythran_supported) or is_pythran_expr(type_)
  155. @cython.ccall
  156. def is_pythran_expr(type_):
  157. return type_.is_pythran_expr
  158. def is_pythran_buffer(type_):
  159. return (type_.is_numpy_buffer and is_pythran_supported_dtype(type_.dtype) and
  160. type_.mode in ("c", "strided") and not type_.cast)
  161. def pythran_get_func_include_file(func):
  162. func = np_func_to_list(func)
  163. return "pythonic/numpy/%s.hpp" % "/".join(func)
  164. def include_pythran_generic(env):
  165. # Generic files
  166. env.add_include_file("pythonic/core.hpp")
  167. env.add_include_file("pythonic/python/core.hpp")
  168. env.add_include_file("pythonic/types/bool.hpp")
  169. env.add_include_file("pythonic/types/ndarray.hpp")
  170. env.add_include_file("pythonic/numpy/power.hpp")
  171. env.add_include_file("pythonic/%s/slice.hpp" % pythran_builtins)
  172. env.add_include_file("<new>") # for placement new
  173. for i in (8, 16, 32, 64):
  174. env.add_include_file("pythonic/types/uint%d.hpp" % i)
  175. env.add_include_file("pythonic/types/int%d.hpp" % i)
  176. for t in ("float", "float32", "float64", "set", "slice", "tuple", "int",
  177. "complex", "complex64", "complex128"):
  178. env.add_include_file("pythonic/types/%s.hpp" % t)