Example #1
0
    def map_power(self, expr, type_context):
        tgt_dtype = self.infer_type(expr)
        exponent_dtype = self.infer_type(expr.exponent)

        from pymbolic.primitives import is_constant, is_zero
        if is_constant(expr.exponent):
            if is_zero(expr.exponent):
                return 1
            elif is_zero(expr.exponent - 1):
                return self.rec(expr.base, type_context)
            elif is_zero(expr.exponent - 2):
                return self.rec(expr.base * expr.base, type_context)

        if exponent_dtype.is_integral():
            from loopy.codegen import SeenFunction
            func_name = (
                "loopy_pow_"
                f"{tgt_dtype.numpy_dtype}_{exponent_dtype.numpy_dtype}")

            self.codegen_state.seen_functions.add(
                SeenFunction("int_pow", func_name, (tgt_dtype, exponent_dtype),
                             (tgt_dtype, )))
            return var(func_name)(self.rec(expr.base, type_context),
                                  self.rec(expr.exponent, type_context))
        else:
            return self.rec(var("pow")(expr.base, expr.exponent), type_context)
Example #2
0
    def map_power(self, expr, type_context):
        tgt_dtype = self.infer_type(expr)
        base_dtype = self.infer_type(expr.base)
        exponent_dtype = self.infer_type(expr.exponent)

        from pymbolic.primitives import is_constant, is_zero
        if is_constant(expr.exponent):
            if is_zero(expr.exponent):
                return 1
            elif is_zero(expr.exponent - 1):
                return self.rec(expr.base, type_context)
            elif is_zero(expr.exponent - 2):
                return self.rec(expr.base * expr.base, type_context)

        if exponent_dtype.is_integral():
            from loopy.codegen import SeenFunction
            func_name = (
                "loopy_pow_"
                f"{tgt_dtype.numpy_dtype}_{exponent_dtype.numpy_dtype}")

            self.codegen_state.seen_functions.add(
                SeenFunction("int_pow", func_name, (tgt_dtype, exponent_dtype),
                             (tgt_dtype, )))
            # FIXME: This need some more callables to be registered.
            return var(func_name)(self.rec(expr.base, type_context),
                                  self.rec(expr.exponent, type_context))
        else:
            from loopy.codegen import SeenFunction
            clbl = self.codegen_state.ast_builder.known_callables["pow"]
            clbl = clbl.with_types({
                0: tgt_dtype,
                1: exponent_dtype
            }, self.codegen_state.callables_table)[0]
            self.codegen_state.seen_functions.add(
                SeenFunction(clbl.name, clbl.name_in_target,
                             (base_dtype, exponent_dtype), (tgt_dtype, )))
            return var(clbl.name_in_target)(self.rec(expr.base, type_context),
                                            self.rec(expr.exponent,
                                                     type_context))
Example #3
0
    def map_call(self, expr, enclosing_prec):
        from pymbolic.primitives import Variable
        from pymbolic.mapper.stringifier import PREC_NONE

        identifier = expr.function

        if identifier.name in ["indexof", "indexof_vec"]:
            raise LoopyError(
                "indexof, indexof_vec not yet supported in Python")

        if isinstance(identifier, Variable):
            identifier = identifier.name

        par_dtypes = tuple(
            self.type_inf_mapper(par) for par in expr.parameters)

        str_parameters = None

        mangle_result = self.kernel.mangle_function(
            identifier, par_dtypes, ast_builder=self.codegen_state.ast_builder)

        if mangle_result is None:
            raise RuntimeError(
                "function '%s' unknown--"
                "maybe you need to register a function mangler?" % identifier)

        if len(mangle_result.result_dtypes) != 1:
            raise LoopyError(
                "functions with more or fewer than one return value "
                "may not be used in an expression")

        str_parameters = [
            self.rec(par, PREC_NONE) for par, par_dtype, tgt_dtype in zip(
                expr.parameters, par_dtypes, mangle_result.arg_dtypes)
        ]

        from loopy.codegen import SeenFunction
        self.codegen_state.seen_functions.add(
            SeenFunction(identifier, mangle_result.target_name,
                         mangle_result.arg_dtypes or par_dtypes,
                         mangle_result.result_dtypes))

        return "{}({})".format(mangle_result.target_name,
                               ", ".join(str_parameters))
Example #4
0
    def emit_multiple_assignment(self, codegen_state, insn):
        ecm = codegen_state.expression_to_code_mapper

        from pymbolic.primitives import Variable
        from pymbolic.mapper.stringifier import PREC_NONE

        func_id = insn.expression.function
        parameters = insn.expression.parameters

        if isinstance(func_id, Variable):
            func_id = func_id.name

        assignee_var_descriptors = [
            codegen_state.kernel.get_var_descriptor(a)
            for a in insn.assignee_var_names()
        ]

        par_dtypes = tuple(ecm.infer_type(par) for par in parameters)

        mangle_result = codegen_state.kernel.mangle_function(
            func_id, par_dtypes)
        if mangle_result is None:
            raise RuntimeError(
                "function '%s' unknown--"
                "maybe you need to register a function mangler?" % func_id)

        assert mangle_result.arg_dtypes is not None

        from loopy.expression import dtype_to_type_context
        c_parameters = [
            ecm(par, PREC_NONE, dtype_to_type_context(self.target, tgt_dtype),
                tgt_dtype).expr for par, par_dtype, tgt_dtype in zip(
                    parameters, par_dtypes, mangle_result.arg_dtypes)
        ]

        from loopy.codegen import SeenFunction
        codegen_state.seen_functions.add(
            SeenFunction(func_id, mangle_result.target_name,
                         mangle_result.arg_dtypes))

        from pymbolic import var
        for i, (a, tgt_dtype) in enumerate(
                zip(insn.assignees[1:], mangle_result.result_dtypes[1:])):
            if tgt_dtype != ecm.infer_type(a):
                raise LoopyError("type mismatch in %d'th (1-based) left-hand "
                                 "side of instruction '%s'" % (i + 1, insn.id))
            c_parameters.append(
                # TODO Yuck: The "where-at function": &(...)
                var("&")(ecm(a, PREC_NONE,
                             dtype_to_type_context(self.target, tgt_dtype),
                             tgt_dtype).expr))

        from pymbolic import var
        result = var(mangle_result.target_name)(*c_parameters)

        # In case of no assignees, we are done
        if len(mangle_result.result_dtypes) == 0:
            from cgen import ExpressionStatement
            return ExpressionStatement(
                CExpression(self.get_c_expression_to_code_mapper(), result))

        result = ecm.wrap_in_typecast(mangle_result.result_dtypes[0],
                                      assignee_var_descriptors[0].dtype,
                                      result)

        lhs_code = ecm(insn.assignees[0], prec=PREC_NONE, type_context=None)

        from cgen import Assign
        return Assign(
            lhs_code,
            CExpression(self.get_c_expression_to_code_mapper(), result))
Example #5
0
    def map_call(self, expr, enclosing_prec, type_context):
        from pymbolic.primitives import Variable, Subscript
        from pymbolic.mapper.stringifier import PREC_NONE

        identifier = expr.function

        # {{{ implement indexof, indexof_vec

        if identifier.name in ["indexof", "indexof_vec"]:
            if len(expr.parameters) != 1:
                raise LoopyError("%s takes exactly one argument" %
                                 identifier.name)
            arg, = expr.parameters
            if not isinstance(arg, Subscript):
                raise LoopyError("argument to %s must be a subscript" %
                                 identifier.name)

            ary = self.find_array(arg)

            from loopy.kernel.array import get_access_info
            from pymbolic import evaluate
            access_info = get_access_info(
                self.kernel.target, ary, arg.index,
                lambda expr: evaluate(expr, self.codegen_state.var_subst_map),
                self.codegen_state.vectorization_info)

            from loopy.kernel.data import ImageArg
            if isinstance(ary, ImageArg):
                raise LoopyError("%s does not support images" %
                                 identifier.name)

            if identifier.name == "indexof":
                return access_info.subscripts[0]
            elif identifier.name == "indexof_vec":
                from loopy.kernel.array import VectorArrayDimTag
                ivec = None
                for iaxis, dim_tag in enumerate(ary.dim_tags):
                    if isinstance(dim_tag, VectorArrayDimTag):
                        ivec = iaxis

                if ivec is None:
                    return access_info.subscripts[0]
                else:
                    return (access_info.subscripts[0] * ary.shape[ivec] +
                            access_info.vector_index)

            else:
                raise RuntimeError("should not get here")

        # }}}

        if isinstance(identifier, Variable):
            identifier = identifier.name

        par_dtypes = tuple(self.infer_type(par) for par in expr.parameters)

        str_parameters = None

        mangle_result = self.kernel.mangle_function(
            identifier, par_dtypes, ast_builder=self.codegen_state.ast_builder)

        if mangle_result is None:
            raise RuntimeError(
                "function '%s' unknown--"
                "maybe you need to register a function mangler?" % identifier)

        if len(mangle_result.result_dtypes) != 1:
            raise LoopyError(
                "functions with more or fewer than one return value "
                "may not be used in an expression")

        if mangle_result.arg_dtypes is not None:
            str_parameters = [
                self.rec(par, PREC_NONE,
                         dtype_to_type_context(self.kernel.target, tgt_dtype),
                         tgt_dtype) for par, par_dtype, tgt_dtype in
                zip(expr.parameters, par_dtypes, mangle_result.arg_dtypes)
            ]

        else:
            # /!\ FIXME For some functions (e.g. 'sin'), it makes sense to
            # propagate the type context here. But for many others, it does
            # not. Using the inferred type as a stopgap for now.
            str_parameters = [
                self.rec(par,
                         PREC_NONE,
                         type_context=dtype_to_type_context(
                             self.kernel.target, par_dtype))
                for par, par_dtype in zip(expr.parameters, par_dtypes)
            ]

            from warnings import warn
            warn(
                "Calling function '%s' with unknown C signature--"
                "return CallMangleInfo.arg_dtypes" % identifier, LoopyWarning)

        from loopy.codegen import SeenFunction
        self.codegen_state.seen_functions.add(
            SeenFunction(identifier, mangle_result.target_name,
                         mangle_result.arg_dtypes or par_dtypes))

        return "%s(%s)" % (mangle_result.target_name,
                           ", ".join(str_parameters))
Example #6
0
 def seen_func(name):
     idt = self.kernel.index_dtype
     from loopy.codegen import SeenFunction
     self.codegen_state.seen_functions.add(
         SeenFunction(name, name, (idt, idt)))
Example #7
0
 def seen_func(name):
     from loopy.codegen import SeenFunction
     self.codegen_state.seen_functions.add(
         SeenFunction(name, f"{name}_{suffix}",
                      (result_dtype, result_dtype), (result_dtype, )))
Example #8
0
 def seen_func(name):
     from loopy.codegen import SeenFunction
     self.codegen_state.seen_functions.add(
         SeenFunction(name, "%s_%s" % (name, suffix),
                      (result_dtype, result_dtype)))