diff options
| author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
|---|---|---|
| committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
| commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
| tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/tools/cython/Cython/Compiler/Pythran.py | |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/Pythran.py')
| -rw-r--r-- | contrib/tools/cython/Cython/Compiler/Pythran.py | 227 | 
1 files changed, 227 insertions, 0 deletions
| diff --git a/contrib/tools/cython/Cython/Compiler/Pythran.py b/contrib/tools/cython/Cython/Compiler/Pythran.py new file mode 100644 index 00000000000..c02704a918c --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Pythran.py @@ -0,0 +1,227 @@ +# cython: language_level=3 + +from __future__ import absolute_import + +from .PyrexTypes import CType, CTypedefType, CStructOrUnionType + +import cython + +try: +    import pythran +    pythran_is_pre_0_9 = tuple(map(int, pythran.__version__.split('.')[0:2])) < (0, 9) +    pythran_is_pre_0_9_6 = tuple(map(int, pythran.__version__.split('.')[0:3])) < (0, 9, 6) +except ImportError: +    pythran = None +    pythran_is_pre_0_9 = True +    pythran_is_pre_0_9_6 = True + +if pythran_is_pre_0_9_6: +    pythran_builtins = '__builtin__' +else: +    pythran_builtins = 'builtins' + + +# Pythran/Numpy specific operations + +def has_np_pythran(env): +    if env is None: +        return False +    directives = getattr(env, 'directives', None) +    return (directives and directives.get('np_pythran', False)) + +def is_pythran_supported_dtype(type_): +    if isinstance(type_, CTypedefType): +        return is_pythran_supported_type(type_.typedef_base_type) +    return type_.is_numeric + + +def pythran_type(Ty, ptype="ndarray"): +    if Ty.is_buffer: +        ndim,dtype = Ty.ndim, Ty.dtype +        if isinstance(dtype, CStructOrUnionType): +            ctype = dtype.cname +        elif isinstance(dtype, CType): +            ctype = dtype.sign_and_name() +        elif isinstance(dtype, CTypedefType): +            ctype = dtype.typedef_cname +        else: +            raise ValueError("unsupported type %s!" % dtype) +        if pythran_is_pre_0_9: +            return "pythonic::types::%s<%s,%d>" % (ptype,ctype, ndim) +        else: +            return "pythonic::types::%s<%s,pythonic::types::pshape<%s>>" % (ptype,ctype, ",".join(("long",)*ndim)) +    if Ty.is_pythran_expr: +        return Ty.pythran_type +    #if Ty.is_none: +    #    return "decltype(pythonic::builtins::None)" +    if Ty.is_numeric: +        return Ty.sign_and_name() +    raise ValueError("unsupported pythran type %s (%s)" % (Ty, type(Ty))) + + +def type_remove_ref(ty): +    return "typename std::remove_reference<%s>::type" % ty + + +def pythran_binop_type(op, tA, tB): +    if op == '**': +        return 'decltype(pythonic::numpy::functor::power{}(std::declval<%s>(), std::declval<%s>()))' % ( +            pythran_type(tA), pythran_type(tB)) +    else: +        return "decltype(std::declval<%s>() %s std::declval<%s>())" % ( +            pythran_type(tA), op, pythran_type(tB)) + + +def pythran_unaryop_type(op, type_): +    return "decltype(%sstd::declval<%s>())" % ( +        op, pythran_type(type_)) + + +def _index_access(index_code, indices): +    indexing = ",".join([index_code(idx) for idx in indices]) +    return ('[%s]' if len(indices) == 1 else '(%s)') % indexing + + +def _index_type_code(index_with_type): +    idx, index_type = index_with_type +    if idx.is_slice: +        n = 2 + int(not idx.step.is_none) +        return "pythonic::%s::functor::slice{}(%s)" % ( +            pythran_builtins, +            ",".join(["0"]*n)) +    elif index_type.is_int: +        return "std::declval<%s>()" % index_type.sign_and_name() +    elif index_type.is_pythran_expr: +        return "std::declval<%s>()" % index_type.pythran_type +    raise ValueError("unsupported indexing type %s!" % index_type) + + +def _index_code(idx): +    if idx.is_slice: +        values = idx.start, idx.stop, idx.step +        if idx.step.is_none: +            func = "contiguous_slice" +            values = values[:2] +        else: +            func = "slice" +        return "pythonic::types::%s(%s)" % ( +            func, ",".join((v.pythran_result() for v in values))) +    elif idx.type.is_int: +        return to_pythran(idx) +    elif idx.type.is_pythran_expr: +        return idx.pythran_result() +    raise ValueError("unsupported indexing type %s" % idx.type) + + +def pythran_indexing_type(type_, indices): +    return type_remove_ref("decltype(std::declval<%s>()%s)" % ( +        pythran_type(type_), +        _index_access(_index_type_code, indices), +    )) + + +def pythran_indexing_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 is None: +    def pythran_is_numpy_func_supported(name): +        return False +else: +    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 + +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): +    args = ",".join(("std::declval<%s>()" % pythran_type(a.type) for a in args)) +    return "decltype(%s{}(%s))" % (pythran_functor(func), args) + + +def to_pythran(op, ptype=None): +    op_type = op.type +    if op_type.is_int: +        # Make sure that integer literals always have exactly the type that the templates expect. +        return op_type.cast_code(op.result()) +    if is_type(op_type, ["is_pythran_expr", "is_numeric", "is_float", "is_complex"]): +        return op.result() +    if op.is_none: +        return "pythonic::%s::None" % pythran_builtins +    if ptype is None: +        ptype = pythran_type(op_type) + +    assert op.type.is_pyobject +    return "from_python<%s>(%s)" % (ptype, op.py_result()) + + +def is_type(type_, types): +    for attr in types: +        if getattr(type_, attr, False): +            return True +    return False + + +def is_pythran_supported_node_or_none(node): +    return node.is_none or is_pythran_supported_type(node.type) + + +def is_pythran_supported_type(type_): +    pythran_supported = ( +        "is_pythran_expr", "is_int", "is_numeric", "is_float", "is_none", "is_complex") +    return is_type(type_, pythran_supported) or is_pythran_expr(type_) + + +def is_pythran_supported_operation_type(type_): +    pythran_supported = ( +        "is_pythran_expr", "is_int", "is_numeric", "is_float", "is_complex") +    return is_type(type_,pythran_supported) or is_pythran_expr(type_) + + +def is_pythran_expr(type_): +    return type_.is_pythran_expr + + +def is_pythran_buffer(type_): +    return (type_.is_numpy_buffer and is_pythran_supported_dtype(type_.dtype) and +            type_.mode in ("c", "strided") and not type_.cast) + +def pythran_get_func_include_file(func): +    func = np_func_to_list(func) +    return "pythonic/numpy/%s.hpp" % "/".join(func) + +def include_pythran_generic(env): +    # Generic files +    env.add_include_file("pythonic/core.hpp") +    env.add_include_file("pythonic/python/core.hpp") +    env.add_include_file("pythonic/types/bool.hpp") +    env.add_include_file("pythonic/types/ndarray.hpp") +    env.add_include_file("pythonic/numpy/power.hpp") +    env.add_include_file("pythonic/%s/slice.hpp" % pythran_builtins) +    env.add_include_file("<new>")  # for placement new + +    for i in (8, 16, 32, 64): +        env.add_include_file("pythonic/types/uint%d.hpp" % i) +        env.add_include_file("pythonic/types/int%d.hpp" % i) +    for t in ("float", "float32", "float64", "set", "slice", "tuple", "int", +              "complex", "complex64", "complex128"): +        env.add_include_file("pythonic/types/%s.hpp" % t) | 
