Halide 22.0.0 Halide compiler and libraries

Param.h
Go to the documentation of this file.
1#ifndef HALIDE_PARAM_H
2#define HALIDE_PARAM_H
3
4#include <type_traits>
5
6#include "Argument.h"
7#include "ExternFuncArgument.h"
8#include "IR.h"
9
10/** \file
11 *
12 * Classes for declaring scalar parameters to halide pipelines
13 */
14
15 namespace Halide {
16
17/** A scalar parameter to a halide pipeline. If you're jitting, this
18 * should be bound to an actual value of type T using the set method
19 * before you realize the function uses this. If you're statically
20 * compiling, this param should appear in the argument list. */
21 template<typename T = void>
22 class Param {
23 /** A reference-counted handle on the internal parameter object */
24 Parameter param;
25
26 // This is a deliberately non-existent type that allows us to compile Param<>
27 // but provide less-confusing error messages if you attempt to call get<> or set<>
28 // without explicit types.
29 struct DynamicParamType;
30
31 /** T unless T is (const) void, in which case pointer-to-useless-type.` */
32 using not_void_T = std::conditional_t<std::is_void_v<T>, DynamicParamType *, T>;
33
34 void check_name() const {
35 user_assert(param.name() != "__user_context")
36 << "Param<void*>(\"__user_context\") "
37 << "is no longer used to control whether Halide functions take explicit "
38 << "user_context arguments. Use set_custom_user_context() when jitting, "
39 << "or add Target::UserContext to the Target feature set when compiling ahead of time.";
40 }
41
42 // Allow all Param<> variants friend access to each other
43 template<typename OTHER_TYPE>
44 friend class Param;
45
46 public:
47 /** True if the Halide type is not void (or const void). */
48 static constexpr bool has_static_type = !std::is_void_v<T>;
49
50 /** Get the Halide type of T. Callers should not use the result if
51 * has_static_halide_type is false. */
52 static Type static_type() {
53 internal_assert(has_static_type);
54 return type_of<T>();
55 }
56
57 /** Construct a scalar parameter of type T with a unique
58 * auto-generated name */
59 // @{
60 Param()
61 : param(type_of<T>(), false, 0, Internal::unique_name('p')) {
62 static_assert(has_static_type, "Cannot use this ctor without an explicit type.");
63 }
64 explicit Param(Type t)
65 : param(t, false, 0, Internal::unique_name('p')) {
66 static_assert(!has_static_type, "Cannot use this ctor with an explicit type.");
67 }
68 // @}
69
70 /** Construct a scalar parameter of type T with the given name. */
71 // @{
72 explicit Param(const std::string &n)
73 : param(type_of<T>(), false, 0, n) {
74 static_assert(has_static_type, "Cannot use this ctor without an explicit type.");
75 check_name();
76 }
77 explicit Param(const char *n)
78 : param(type_of<T>(), false, 0, n) {
79 static_assert(has_static_type, "Cannot use this ctor without an explicit type.");
80 check_name();
81 }
82 Param(Type t, const std::string &n)
83 : param(t, false, 0, n) {
84 static_assert(!has_static_type, "Cannot use this ctor with an explicit type.");
85 check_name();
86 }
87 // @}
88
89 /** Construct a scalar parameter of type T an initial value of
90 * 'val'. Only triggers for non-pointer types. */
91 template<typename T2 = T, std::enable_if_t<!std::is_pointer_v<T2>> * = nullptr>
92 explicit Param(not_void_T val)
93 : param(type_of<T>(), false, 0, Internal::unique_name('p')) {
94 static_assert(has_static_type, "Cannot use this ctor without an explicit type.");
95 set<not_void_T>(val);
96 }
97
98 /** Construct a scalar parameter of type T with the given name
99 * and an initial value of 'val'. */
100 Param(const std::string &n, not_void_T val)
101 : param(type_of<T>(), false, 0, n) {
102 check_name();
103 static_assert(has_static_type, "Cannot use this ctor without an explicit type.");
104 set<not_void_T>(val);
105 }
106
107 /** Construct a scalar parameter of type T with an initial value of 'val'
108 * and a given min and max. */
109 Param(not_void_T val, const Expr &min, const Expr &max)
110 : param(type_of<T>(), false, 0, Internal::unique_name('p')) {
111 static_assert(has_static_type, "Cannot use this ctor without an explicit type.");
112 set_range(min, max);
113 set<not_void_T>(val);
114 }
115
116 /** Construct a scalar parameter of type T with the given name
117 * and an initial value of 'val' and a given min and max. */
118 Param(const std::string &n, not_void_T val, const Expr &min, const Expr &max)
119 : param(type_of<T>(), false, 0, n) {
120 static_assert(has_static_type, "Cannot use this ctor without an explicit type.");
121 check_name();
122 set_range(min, max);
123 set<not_void_T>(val);
124 }
125
126 /** Construct a Param<void> from any other Param. */
127 template<typename OTHER_TYPE, typename T2 = T, std::enable_if_t<std::is_void_v<T2>> * = nullptr>
128 Param(const Param<OTHER_TYPE> &other)
129 : param(other.param) {
130 // empty
131 }
132
133 /** Construct a Param<non-void> from a Param with matching type.
134 * (Do the check at runtime so that we can assign from Param<void> if the types are compatible.) */
135 template<typename OTHER_TYPE, typename T2 = T, std::enable_if_t<!std::is_void_v<T2>> * = nullptr>
136 Param(const Param<OTHER_TYPE> &other)
137 : param(other.param) {
138 user_assert(other.type() == type_of<T>())
139 << "Param<" << type_of<T>() << "> cannot be constructed from a Param with type " << other.type();
140 }
141
142 /** Copy a Param<void> from any other Param. */
143 template<typename OTHER_TYPE, typename T2 = T, std::enable_if_t<std::is_void_v<T2>> * = nullptr>
144 Param<T> &operator=(const Param<OTHER_TYPE> &other) {
145 param = other.param;
146 return *this;
147 }
148
149 /** Copy a Param<non-void> from a Param with matching type.
150 * (Do the check at runtime so that we can assign from Param<void> if the types are compatible.) */
151 template<typename OTHER_TYPE, typename T2 = T, std::enable_if_t<!std::is_void_v<T2>> * = nullptr>
152 Param<T> &operator=(const Param<OTHER_TYPE> &other) {
153 user_assert(other.type() == type_of<T>())
154 << "Param<" << type_of<T>() << "> cannot be copied from a Param with type " << other.type();
155 param = other.param;
156 return *this;
157 }
158
159 /** Get the name of this parameter */
160 const std::string &name() const {
161 return param.name();
162 }
163
164 /** Get the current value of this parameter. Only meaningful when jitting.
165 Asserts if type does not exactly match the Parameter's type. */
166 template<typename T2 = not_void_T>
167 HALIDE_NO_USER_CODE_INLINE T2 get() const {
168 return param.scalar<T2>();
169 }
170
171 /** Set the current value of this parameter. Only meaningful when jitting.
172 Asserts if type is not losslessly-convertible to Parameter's type. */
173 template<typename SOME_TYPE>
174 HALIDE_NO_USER_CODE_INLINE void set(const SOME_TYPE &val) {
175 if constexpr (!std::is_void_v<T>) {
176 user_assert(Internal::IsRoundtrippable<T>::value(val))
177 << "The value " << val << " cannot be losslessly converted to type " << type();
178 param.set_scalar<T>(val);
179 } else {
180
181 // Specialized version for when T = void (thus the type is only known at runtime,
182 // not compiletime). Note that this actually works fine for all Params; we specialize
183 // it just to reduce code size for the common case of T != void.
184
185#define HALIDE_HANDLE_TYPE_DISPATCH(CODE, BITS, TYPE) \
186 case halide_type_t(CODE, BITS).as_u32(): \
187 user_assert(Internal::IsRoundtrippable<TYPE>::value(val)) \
188 << "The value " << val << " cannot be losslessly converted to type " << type; \
189 param.set_scalar<TYPE>(Internal::StaticCast<TYPE>::value(val)); \
190 break;
191
192 const Type type = param.type();
193 switch (((halide_type_t)type).element_of().as_u32()) {
194 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_float, 32, float)
195 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_float, 64, double)
196 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_int, 8, int8_t)
197 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_int, 16, int16_t)
198 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_int, 32, int32_t)
199 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_int, 64, int64_t)
200 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 1, bool)
201 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 8, uint8_t)
202 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 16, uint16_t)
203 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 32, uint32_t)
204 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 64, uint64_t)
205 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_handle, 64, uint64_t) // Handle types are always set via set_scalar<uint64_t>, not set_scalar<void*>
206 default:
207 internal_error << "Unsupported type in Param::set<" << type << ">\n";
208 }
209
210#undef HALIDE_HANDLE_TYPE_DISPATCH
211 }
212 }
213
214 /** Get the halide type of the Param */
215 Type type() const {
216 return param.type();
217 }
218
219 /** Get or set the possible range of this parameter. Use undefined
220 * Exprs to mean unbounded. */
221 // @{
222 void set_range(const Expr &min, const Expr &max) {
223 set_min_value(min);
224 set_max_value(max);
225 }
226
227 void set_min_value(Expr min) {
228 if (min.defined() && min.type() != param.type()) {
229 min = Internal::Cast::make(param.type(), min);
230 }
231 param.set_min_value(min);
232 }
233
234 void set_max_value(Expr max) {
235 if (max.defined() && max.type() != param.type()) {
236 max = Internal::Cast::make(param.type(), max);
237 }
238 param.set_max_value(max);
239 }
240
241 Expr min_value() const {
242 return param.min_value();
243 }
244
245 Expr max_value() const {
246 return param.max_value();
247 }
248 // @}
249
250 template<typename SOME_TYPE>
251 HALIDE_NO_USER_CODE_INLINE void set_estimate(const SOME_TYPE &val) {
252 if constexpr (!std::is_void_v<T>) {
253 user_assert(Internal::IsRoundtrippable<T>::value(val))
254 << "The value " << val << " cannot be losslessly converted to type " << type();
255 param.set_estimate(Expr(val));
256 } else {
257
258 // Specialized version for when T = void (thus the type is only known at runtime,
259 // not compiletime). Note that this actually works fine for all Params; we specialize
260 // it just to reduce code size for the common case of T != void.
261
262#define HALIDE_HANDLE_TYPE_DISPATCH(CODE, BITS, TYPE) \
263 case halide_type_t(CODE, BITS).as_u32(): \
264 user_assert(Internal::IsRoundtrippable<TYPE>::value(val)) \
265 << "The value " << val << " cannot be losslessly converted to type " << type; \
266 param.set_estimate(Expr(Internal::StaticCast<TYPE>::value(val))); \
267 break;
268
269 const Type type = param.type();
270 switch (((halide_type_t)type).element_of().as_u32()) {
271 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_float, 32, float)
272 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_float, 64, double)
273 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_int, 8, int8_t)
274 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_int, 16, int16_t)
275 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_int, 32, int32_t)
276 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_int, 64, int64_t)
277 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 1, bool)
278 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 8, uint8_t)
279 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 16, uint16_t)
280 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 32, uint32_t)
281 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_uint, 64, uint64_t)
282 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_handle, 64, uint64_t) // Handle types are always set via set_scalar<uint64_t>, not set_scalar<void*>
283 default:
284 internal_error << "Unsupported type in Param::set<" << type << ">\n";
285 }
286
287#undef HALIDE_HANDLE_TYPE_DISPATCH
288 }
289 }
290
291 /** You can use this parameter as an expression in a halide
292 * function definition */
293 operator Expr() const {
294 return Internal::Variable::make(param.type(), name(), param);
295 }
296
297 /** Using a param as the argument to an external stage treats it
298 * as an Expr */
299 operator ExternFuncArgument() const {
300 return Expr(*this);
301 }
302
303 /** Construct the appropriate argument matching this parameter,
304 * for the purpose of generating the right type signature when
305 * statically compiling halide pipelines. */
306 operator Argument() const {
307 return Argument(name(), Argument::InputScalar, type(), 0,
308 param.get_argument_estimates());
309 }
310
311 const Parameter &parameter() const {
312 return param;
313 }
314
315 Parameter &parameter() {
316 return param;
317 }
318};
319
320/** Returns an Expr corresponding to the user context passed to
321 * the function (if any). It is rare that this function is necessary
322 * (e.g. to pass the user context to an extern function written in C). */
323 inline Expr user_context_value() {
324 return Internal::Variable::make(Handle(), "__user_context",
325 Parameter(Handle(), false, 0, "__user_context"));
326}
327
328} // namespace Halide
329
330#endif
Argument.h
Defines a type used for expressing the type signature of a generated halide pipeline.
internal_error
#define internal_error
Definition: Error.h:229
internal_assert
#define internal_assert(c)
Definition: Error.h:232
user_assert
#define user_assert(c)
Definition: Error.h:233
ExternFuncArgument.h
Defines the internal representation of a halide ExternFuncArgument.
halide_type_float
@ halide_type_float
IEEE floating point numbers.
Definition: HalideRuntime.h:483
halide_type_handle
@ halide_type_handle
opaque pointer type (void *)
Definition: HalideRuntime.h:484
halide_type_int
@ halide_type_int
signed integers
Definition: HalideRuntime.h:481
halide_type_uint
@ halide_type_uint
unsigned integers
Definition: HalideRuntime.h:482
IR.h
Subtypes for Halide expressions (Halide::Expr) and statements (Halide::Internal::Stmt)
HALIDE_HANDLE_TYPE_DISPATCH
#define HALIDE_HANDLE_TYPE_DISPATCH(CODE, BITS, TYPE)
HALIDE_NO_USER_CODE_INLINE
#define HALIDE_NO_USER_CODE_INLINE
Definition: Util.h:47
Halide::Param
A scalar parameter to a halide pipeline.
Definition: Param.h:22
Halide::Param::min_value
Expr min_value() const
Definition: Param.h:241
Halide::Param::name
const std::string & name() const
Get the name of this parameter.
Definition: Param.h:160
Halide::Param::set_range
void set_range(const Expr &min, const Expr &max)
Get or set the possible range of this parameter.
Definition: Param.h:222
Halide::Param::set_estimate
HALIDE_NO_USER_CODE_INLINE void set_estimate(const SOME_TYPE &val)
Definition: Param.h:251
Halide::Param::Param
Param(const Param< OTHER_TYPE > &other)
Construct a Param<void> from any other Param.
Definition: Param.h:128
Halide::Param::Param
Param(Type t)
Definition: Param.h:64
Halide::Param::Param
Param(const char *n)
Definition: Param.h:77
Halide::Param::set
HALIDE_NO_USER_CODE_INLINE void set(const SOME_TYPE &val)
Set the current value of this parameter.
Definition: Param.h:174
Halide::Param::set_min_value
void set_min_value(Expr min)
Definition: Param.h:227
Halide::Param::Param
Param(not_void_T val)
Construct a scalar parameter of type T an initial value of 'val'.
Definition: Param.h:92
Halide::Param::max_value
Expr max_value() const
Definition: Param.h:245
Halide::Param::parameter
const Parameter & parameter() const
Definition: Param.h:311
Halide::Param::set_max_value
void set_max_value(Expr max)
Definition: Param.h:234
Halide::Param::type
Type type() const
Get the halide type of the Param.
Definition: Param.h:215
Halide::Param::Param
Param(Type t, const std::string &n)
Definition: Param.h:82
Halide::Param::static_type
static Type static_type()
Get the Halide type of T.
Definition: Param.h:52
Halide::Param::has_static_type
static constexpr bool has_static_type
True if the Halide type is not void (or const void).
Definition: Param.h:48
Halide::Param::Param
Param(not_void_T val, const Expr &min, const Expr &max)
Construct a scalar parameter of type T with an initial value of 'val' and a given min and max.
Definition: Param.h:109
Halide::Param::Param
Param()
Construct a scalar parameter of type T with a unique auto-generated name.
Definition: Param.h:60
Halide::Param::Param
Param(const std::string &n)
Construct a scalar parameter of type T with the given name.
Definition: Param.h:72
Halide::Param::Param
Param(const std::string &n, not_void_T val, const Expr &min, const Expr &max)
Construct a scalar parameter of type T with the given name and an initial value of 'val' and a given ...
Definition: Param.h:118
Halide::Param::operator=
Param< T > & operator=(const Param< OTHER_TYPE > &other)
Copy a Param<void> from any other Param.
Definition: Param.h:144
Halide::Param::get
HALIDE_NO_USER_CODE_INLINE T2 get() const
Get the current value of this parameter.
Definition: Param.h:167
Halide::Param::parameter
Parameter & parameter()
Definition: Param.h:315
Halide::Param::Param
Param(const std::string &n, not_void_T val)
Construct a scalar parameter of type T with the given name and an initial value of 'val'.
Definition: Param.h:100
Halide::Parameter
A reference-counted handle to a parameter to a halide pipeline.
Definition: Parameter.h:40
Halide::Parameter::set_max_value
void set_max_value(const Expr &e)
Halide::Parameter::name
const std::string & name() const
Get the name of this parameter.
Halide::Parameter::max_value
Expr max_value() const
Halide::Parameter::scalar
HALIDE_NO_USER_CODE_INLINE T scalar() const
If the parameter is a scalar parameter, get its currently bound value.
Definition: Parameter.h:127
Halide::Parameter::set_min_value
void set_min_value(const Expr &e)
Get and set constraints for scalar parameters.
Halide::Parameter::min_value
Expr min_value() const
Halide::Parameter::set_scalar
HALIDE_NO_USER_CODE_INLINE void set_scalar(T val)
If the parameter is a scalar parameter, set its current value.
Definition: Parameter.h:146
Halide::Parameter::set_estimate
void set_estimate(Expr e)
Halide::Parameter::type
Type type() const
Get the type of this parameter.
Halide::Parameter::get_argument_estimates
ArgumentEstimates get_argument_estimates() const
Get the ArgumentEstimates appropriate for this Parameter.
Halide::Internal::unique_name
std::string unique_name(char prefix)
Generate a unique name starting with the given prefix.
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
Halide::LinkageType::Internal
@ Internal
Not visible externally, similar to 'static' linkage in C.
Halide::type_of
Type type_of()
Construct the halide equivalent of a C type.
Definition: Type.h:570
Halide::min
Expr min(const FuncRef &a, const FuncRef &b)
Explicit overloads of min and max for FuncRef.
Definition: Func.h:625
Halide::Handle
Type Handle(int lanes=1, const halide_handle_cplusplus_type *handle_type=nullptr)
Construct a handle type.
Definition: Type.h:564
Halide::user_context_value
Expr user_context_value()
Returns an Expr corresponding to the user context passed to the function (if any).
Definition: Param.h:323
Halide::max
Expr max(const FuncRef &a, const FuncRef &b)
Definition: Func.h:628
uint64_t
unsigned __INT64_TYPE__ uint64_t
Definition: runtime_internal.h:23
int64_t
signed __INT64_TYPE__ int64_t
Definition: runtime_internal.h:22
int32_t
signed __INT32_TYPE__ int32_t
Definition: runtime_internal.h:24
uint8_t
unsigned __INT8_TYPE__ uint8_t
Definition: runtime_internal.h:29
uint16_t
unsigned __INT16_TYPE__ uint16_t
Definition: runtime_internal.h:27
uint32_t
unsigned __INT32_TYPE__ uint32_t
Definition: runtime_internal.h:25
int16_t
signed __INT16_TYPE__ int16_t
Definition: runtime_internal.h:26
int8_t
signed __INT8_TYPE__ int8_t
Definition: runtime_internal.h:28
Halide::Argument
A struct representing an argument to a halide-generated function.
Definition: Argument.h:37
Halide::Argument::InputScalar
@ InputScalar
Definition: Argument.h:53
Halide::Expr
A fragment of Halide syntax.
Definition: Expr.h:258
Halide::Expr::type
HALIDE_ALWAYS_INLINE Type type() const
Get the type of this expression node.
Definition: Expr.h:327
Halide::ExternFuncArgument
An argument to an extern-defined Func.
Definition: ExternFuncArgument.h:17
Halide::Internal::Cast::make
static Expr make(Type t, Expr v)
Halide::Internal::IntrusivePtr::defined
HALIDE_ALWAYS_INLINE bool defined() const
Definition: IntrusivePtr.h:164
Halide::Internal::IsRoundtrippable
Definition: Util.h:453
Halide::Internal::Variable::make
static Expr make(Type type, const std::string &name)
Definition: IR.h:826
Halide::Type
Types in the halide type system.
Definition: Type.h:281
halide_type_t
A runtime tag for a type in the halide type system.
Definition: HalideRuntime.h:503