#ifndef HALIDE_FUNCTION_H
#define HALIDE_FUNCTION_H
/** \file
* Defines the internal representation of a halide function and related classes
*/
#include "Expr.h"
#include "IntrusivePtr.h"
#include "Parameter.h"
#include "Schedule.h"
#include "Reduction.h"
#include "Definition.h"
#include "Buffer.h"
#include <map>
namespace Halide {
namespace Internal {
struct FunctionContents;
}
/** An argument to an extern-defined Func. May be a Function, Buffer,
* ImageParam or Expr. */
struct ExternFuncArgument {
enum ArgType {UndefinedArg = 0, FuncArg, BufferArg, ExprArg, ImageParamArg};
ArgType arg_type;
Internal::IntrusivePtr<Internal::FunctionContents> func;
Buffer<> buffer;
Expr expr;
Internal::Parameter image_param;
ExternFuncArgument(Internal::IntrusivePtr<Internal::FunctionContents> f): arg_type(FuncArg), func(f) {}
template<typename T>
ExternFuncArgument(Buffer<T> b): arg_type(BufferArg), buffer(b) {}
ExternFuncArgument(Expr e): arg_type(ExprArg), expr(e) {}
ExternFuncArgument(int e): arg_type(ExprArg), expr(e) {}
ExternFuncArgument(float e): arg_type(ExprArg), expr(e) {}
ExternFuncArgument(Internal::Parameter p) : arg_type(ImageParamArg), image_param(p) {
// Scalar params come in via the Expr constructor.
internal_assert(p.is_buffer());
}
ExternFuncArgument() : arg_type(UndefinedArg) {}
bool is_func() const {return arg_type == FuncArg;}
bool is_expr() const {return arg_type == ExprArg;}
bool is_buffer() const {return arg_type == BufferArg;}
bool is_image_param() const {return arg_type == ImageParamArg;}
bool defined() const {return arg_type != UndefinedArg;}
};
/** An enum to specify calling convention for extern stages. */
enum class NameMangling {
Default, ///< Match whatever is specified in the Target
C, ///< No name mangling
CPlusPlus, ///< C++ name mangling
};
namespace Internal {
/** A reference-counted handle to Halide's internal representation of
* a function. Similar to a front-end Func object, but with no
* syntactic sugar to help with definitions. */
class Function {
IntrusivePtr<FunctionContents> contents;
public:
/** This lets you use a Function as a key in a map of the form
* map<Function, Foo, Function::Compare> */
struct Compare {
bool operator()(const Function &a, const Function &b) const {
internal_assert(a.contents.defined() && b.contents.defined());
return a.contents < b.contents;
}
};
/** Construct a new function with no definitions and no name. This
* constructor only exists so that you can make vectors of
* functions, etc.
*/
EXPORT Function();
/** Construct a new function with the given name */
EXPORT explicit Function(const std::string &n);
/** Construct a Function from an existing FunctionContents pointer. Must be non-null */
EXPORT explicit Function(const IntrusivePtr<FunctionContents> &);
/** Get a handle on the halide function contents that this Function
* represents. */
IntrusivePtr<FunctionContents> get_contents() const {
return contents;
}
/** Deep copy this Function into 'copy'. It recursively deep copies all called
* functions, schedules, update definitions, extern func arguments, specializations,
* and reduction domains. This method does not deep-copy the Parameter objects.
* This method also takes a map of <old Function, deep-copied version> as input
* and would use the deep-copied Function from the map if exists instead of
* creating a new deep-copy to avoid creating deep-copies of the same Function
* multiple times.
*/
EXPORT void deep_copy(Function ©, std::map<Function, Function, Compare> &copied_map) const;
/** Add a pure definition to this function. It may not already
* have a definition. All the free variables in 'value' must
* appear in the args list. 'value' must not depend on any
* reduction domain */
EXPORT void define(const std::vector<std::string> &args, std::vector<Expr> values);
/** Add an update definition to this function. It must already
* have a pure definition but not an update definition, and the
* length of args must match the length of args used in the pure
* definition. 'value' must depend on some reduction domain, and
* may contain variables from that domain as well as pure
* variables. Any pure variables must also appear as Variables in
* the args array, and they must have the same name as the pure
* definition's argument in the same index. */
EXPORT void define_update(const std::vector<Expr> &args, std::vector<Expr> values);
/** Accept a visitor to visit all of the definitions and arguments
* of this function. */
EXPORT void accept(IRVisitor *visitor) const;
/** Get the name of the function. */
EXPORT const std::string &name() const;
/** Get a mutable handle to the init definition. */
EXPORT Definition &definition();
/** Get the init definition. */
EXPORT const Definition &definition() const;
/** Get the pure arguments. */
EXPORT const std::vector<std::string> args() const;
/** Get the dimensionality. */
EXPORT int dimensions() const;
/** Get the number of outputs. */
int outputs() const {
return (int)output_types().size();
}
/** Get the types of the outputs. */
EXPORT const std::vector<Type> &output_types() const;
/** Get the right-hand-side of the pure definition. */
EXPORT const std::vector<Expr> &values() const;
/** Does this function have a pure definition? */
EXPORT bool has_pure_definition() const;
/** Does this function *only* have a pure definition? */
bool is_pure() const {
return (has_pure_definition() &&
!has_update_definition() &&
!has_extern_definition());
}
/** Is it legal to inline this function? */
EXPORT bool can_be_inlined() const;
/** Get a handle to the schedule for the purpose of modifying
* it. */
EXPORT Schedule &schedule();
/** Get a const handle to the schedule for inspecting it. */
EXPORT const Schedule &schedule() const;
/** Get a handle on the output buffer used for setting constraints
* on it. */
EXPORT const std::vector<Parameter> &output_buffers() const;
/** Get a mutable handle to the schedule for the update
* stage. */
EXPORT Schedule &update_schedule(int idx = 0);
/** Get a mutable handle to this function's update definition at
* index 'idx'. */
EXPORT Definition &update(int idx = 0);
/** Get a const reference to this function's update definition at
* index 'idx'. */
EXPORT const Definition &update(int idx = 0) const;
/** Get a const reference to this function's update definitions. */
EXPORT const std::vector<Definition> &updates() const;
/** Does this function have an update definition? */
EXPORT bool has_update_definition() const;
/** Check if the function has an extern definition. */
EXPORT bool has_extern_definition() const;
/** Get the name mangling specified for the extern definition. */
EXPORT NameMangling extern_definition_name_mangling() const;
/** Make a call node to the extern definition. An error if the
* function has no extern definition. */
EXPORT Expr make_call_to_extern_definition(const std::vector<Expr> &args,
const Target &t) const;
/** Check if the extern function being called expects the legacy
* buffer_t type. */
EXPORT bool extern_definition_uses_old_buffer_t() const;
/** Add an external definition of this Func. */
EXPORT void define_extern(const std::string &function_name,
const std::vector<ExternFuncArgument> &args,
const std::vector<Type> &types,
int dimensionality,
NameMangling mangling,
bool uses_old_buffer_t);
/** Retrive the arguments of the extern definition. */
EXPORT const std::vector<ExternFuncArgument> &extern_arguments() const;
/** Get the name of the extern function called for an extern
* definition. */
EXPORT const std::string &extern_function_name() const;
/** Test for equality of identity. */
bool same_as(const Function &other) const {
return contents.same_as(other.contents);
}
/** Get a const handle to the debug filename. */
EXPORT const std::string &debug_file() const;
/** Get a handle to the debug filename. */
EXPORT std::string &debug_file();
/** Use an an extern argument to another function. */
operator ExternFuncArgument() const {
return ExternFuncArgument(contents);
}
/** Tracing calls and accessors, passed down from the Func
* equivalents. */
// @{
EXPORT void trace_loads();
EXPORT void trace_stores();
EXPORT void trace_realizations();
EXPORT bool is_tracing_loads() const;
EXPORT bool is_tracing_stores() const;
EXPORT bool is_tracing_realizations() const;
// @}
/** Mark function as frozen, which means it cannot accept new
* definitions. */
EXPORT void freeze();
/** Check if a function has been frozen. If so, it is an error to
* add new definitions. */
EXPORT bool frozen() const;
/** Mark calls of this function by 'f' to be replaced with its wrapper
* during the lowering stage. If the string 'f' is empty, it means replace
* all calls to this function by all other functions (excluding itself) in
* the pipeline with the wrapper. This will also freeze 'wrapper' to prevent
* user from updating the values of the Function it wraps via the wrapper.
* See \ref Func::in for more details. */
// @{
EXPORT void add_wrapper(const std::string &f, Function &wrapper);
EXPORT const std::map<std::string, IntrusivePtr<Internal::FunctionContents>> &wrappers() const;
// @}
/** Replace every call to Functions in 'substitutions' keys by all Exprs
* referenced in this Function to call to their substitute Functions (i.e.
* the corresponding values in 'substitutions' map). */
// @{
EXPORT Function &substitute_calls(const std::map<Function, Function, Compare> &substitutions);
EXPORT Function &substitute_calls(const Function &orig, const Function &substitute);
// @}
/** Find all Vars that are placeholders for ScheduleParams and substitute in
* the corresponding constant value. */
EXPORT Function &substitute_schedule_param_exprs();
};
}}
#endif