Halide 19.0.0
Halide compiler and libraries
Loading...
Searching...
No Matches
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"
8#include "IR.h"
9
10/** \file
11 *
12 * Classes for declaring scalar parameters to halide pipelines
13 */
14
15namespace 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. */
21template<typename T = void>
22class 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 = typename std::conditional<std::is_void<T>::value, DynamicParamType *, T>::type;
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
46public:
47 /** True if the Halide type is not void (or const void). */
48 static constexpr bool has_static_type = !std::is_void<T>::value;
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() {
54 return type_of<T>();
55 }
56
57 /** Construct a scalar parameter of type T with a unique
58 * auto-generated name */
59 // @{
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, typename std::enable_if<!std::is_pointer<T2>::value>::type * = 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, typename std::enable_if<std::is_void<T2>::value>::type * = nullptr>
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, typename std::enable_if<!std::is_void<T2>::value>::type * = nullptr>
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, typename std::enable_if<std::is_void<T2>::value>::type * = nullptr>
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, typename std::enable_if<!std::is_void<T2>::value>::type * = nullptr>
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>
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<T>::value) {
177 << "The value " << val << " cannot be losslessly converted to type " << type();
178 param.set_scalar<T>(val);
179 } else {
180 // clang-format off
181
182 // Specialized version for when T = void (thus the type is only known at runtime,
183 // not compiletime). Note that this actually works fine for all Params; we specialize
184 // it just to reduce code size for the common case of T != void.
185
186 #define HALIDE_HANDLE_TYPE_DISPATCH(CODE, BITS, TYPE) \
187 case halide_type_t(CODE, BITS).as_u32(): \
188 user_assert(Internal::IsRoundtrippable<TYPE>::value(val)) \
189 << "The value " << val << " cannot be losslessly converted to type " << type; \
190 param.set_scalar<TYPE>(Internal::StaticCast<TYPE>::value(val)); \
191 break;
192
193 const Type type = param.type();
194 switch (((halide_type_t)type).element_of().as_u32()) {
206 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_handle, 64, uint64_t) // Handle types are always set via set_scalar<uint64_t>, not set_scalar<void*>
207 default:
208 internal_error << "Unsupported type in Param::set<" << type << ">\n";
209 }
210
211 #undef HALIDE_HANDLE_TYPE_DISPATCH
212
213 // clang-format on
214 }
215 }
216
217 /** Get the halide type of the Param */
218 Type type() const {
219 return param.type();
220 }
221
222 /** Get or set the possible range of this parameter. Use undefined
223 * Exprs to mean unbounded. */
224 // @{
225 void set_range(const Expr &min, const Expr &max) {
226 set_min_value(min);
227 set_max_value(max);
228 }
229
230 void set_min_value(Expr min) {
231 if (min.defined() && min.type() != param.type()) {
232 min = Internal::Cast::make(param.type(), min);
233 }
234 param.set_min_value(min);
235 }
236
237 void set_max_value(Expr max) {
238 if (max.defined() && max.type() != param.type()) {
239 max = Internal::Cast::make(param.type(), max);
240 }
241 param.set_max_value(max);
242 }
243
244 Expr min_value() const {
245 return param.min_value();
246 }
247
248 Expr max_value() const {
249 return param.max_value();
250 }
251 // @}
252
253 template<typename SOME_TYPE>
254 HALIDE_NO_USER_CODE_INLINE void set_estimate(const SOME_TYPE &val) {
255 if constexpr (!std::is_void<T>::value) {
257 << "The value " << val << " cannot be losslessly converted to type " << type();
258 param.set_estimate(Expr(val));
259 } else {
260 // clang-format off
261
262 // Specialized version for when T = void (thus the type is only known at runtime,
263 // not compiletime). Note that this actually works fine for all Params; we specialize
264 // it just to reduce code size for the common case of T != void.
265
266 #define HALIDE_HANDLE_TYPE_DISPATCH(CODE, BITS, TYPE) \
267 case halide_type_t(CODE, BITS).as_u32(): \
268 user_assert(Internal::IsRoundtrippable<TYPE>::value(val)) \
269 << "The value " << val << " cannot be losslessly converted to type " << type; \
270 param.set_estimate(Expr(Internal::StaticCast<TYPE>::value(val))); \
271 break;
272
273 const Type type = param.type();
274 switch (((halide_type_t)type).element_of().as_u32()) {
286 HALIDE_HANDLE_TYPE_DISPATCH(halide_type_handle, 64, uint64_t) // Handle types are always set via set_scalar<uint64_t>, not set_scalar<void*>
287 default:
288 internal_error << "Unsupported type in Param::set<" << type << ">\n";
289 }
290
291 #undef HALIDE_HANDLE_TYPE_DISPATCH
292
293 // clang-format on
294 }
295 }
296
297 /** You can use this parameter as an expression in a halide
298 * function definition */
299 operator Expr() const {
300 return Internal::Variable::make(param.type(), name(), param);
301 }
302
303 /** Using a param as the argument to an external stage treats it
304 * as an Expr */
305 operator ExternFuncArgument() const {
306 return Expr(*this);
307 }
308
309 /** Construct the appropriate argument matching this parameter,
310 * for the purpose of generating the right type signature when
311 * statically compiling halide pipelines. */
312 operator Argument() const {
313 return Argument(name(), Argument::InputScalar, type(), 0,
314 param.get_argument_estimates());
315 }
316
317 const Parameter &parameter() const {
318 return param;
319 }
320
322 return param;
323 }
324};
325
326/** Returns an Expr corresponding to the user context passed to
327 * the function (if any). It is rare that this function is necessary
328 * (e.g. to pass the user context to an extern function written in C). */
330 return Internal::Variable::make(Handle(), "__user_context",
331 Parameter(Handle(), false, 0, "__user_context"));
332}
333
334} // namespace Halide
335
336#endif
Defines a type used for expressing the type signature of a generated halide pipeline.
#define internal_error
Definition Errors.h:23
#define internal_assert(c)
Definition Errors.h:19
Defines the internal representation of a halide ExternFuncArgument.
@ halide_type_float
IEEE floating point numbers.
@ halide_type_handle
opaque pointer type (void *)
@ halide_type_int
signed integers
@ halide_type_uint
unsigned integers
Subtypes for Halide expressions (Halide::Expr) and statements (Halide::Internal::Stmt)
#define HALIDE_HANDLE_TYPE_DISPATCH(CODE, BITS, TYPE)
#define HALIDE_NO_USER_CODE_INLINE
Definition Util.h:47
A scalar parameter to a halide pipeline.
Definition Param.h:22
Expr min_value() const
Definition Param.h:244
const std::string & name() const
Get the name of this parameter.
Definition Param.h:160
void set_range(const Expr &min, const Expr &max)
Get or set the possible range of this parameter.
Definition Param.h:225
HALIDE_NO_USER_CODE_INLINE void set_estimate(const SOME_TYPE &val)
Definition Param.h:254
Param(const Param< OTHER_TYPE > &other)
Construct a Param<void> from any other Param.
Definition Param.h:128
Param(Type t)
Definition Param.h:64
Param(const char *n)
Definition Param.h:77
HALIDE_NO_USER_CODE_INLINE void set(const SOME_TYPE &val)
Set the current value of this parameter.
Definition Param.h:174
void set_min_value(Expr min)
Definition Param.h:230
Param(not_void_T val)
Construct a scalar parameter of type T an initial value of 'val'.
Definition Param.h:92
Expr max_value() const
Definition Param.h:248
const Parameter & parameter() const
Definition Param.h:317
void set_max_value(Expr max)
Definition Param.h:237
Type type() const
Get the halide type of the Param.
Definition Param.h:218
Param(Type t, const std::string &n)
Definition Param.h:82
static Type static_type()
Get the Halide type of T.
Definition Param.h:52
static constexpr bool has_static_type
True if the Halide type is not void (or const void).
Definition Param.h:48
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
Param()
Construct a scalar parameter of type T with a unique auto-generated name.
Definition Param.h:60
Param(const std::string &n)
Construct a scalar parameter of type T with the given name.
Definition Param.h:72
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
Param< T > & operator=(const Param< OTHER_TYPE > &other)
Copy a Param<void> from any other Param.
Definition Param.h:144
HALIDE_NO_USER_CODE_INLINE T2 get() const
Get the current value of this parameter.
Definition Param.h:167
Parameter & parameter()
Definition Param.h:321
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
A reference-counted handle to a parameter to a halide pipeline.
Definition Parameter.h:40
void set_max_value(const Expr &e)
const std::string & name() const
Get the name of this parameter.
Expr max_value() const
HALIDE_NO_USER_CODE_INLINE T scalar() const
If the parameter is a scalar parameter, get its currently bound value.
Definition Parameter.h:127
void set_min_value(const Expr &e)
Get and set constraints for scalar parameters.
Expr min_value() const
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
void set_estimate(Expr e)
Type type() const
Get the type of this parameter.
ArgumentEstimates get_argument_estimates() const
Get the ArgumentEstimates appropriate for this Parameter.
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
@ Internal
Not visible externally, similar to 'static' linkage in C.
Type type_of()
Construct the halide equivalent of a C type.
Definition Type.h:572
Type Handle(int lanes=1, const halide_handle_cplusplus_type *handle_type=nullptr)
Construct a handle type.
Definition Type.h:566
Expr user_context_value()
Returns an Expr corresponding to the user context passed to the function (if any).
Definition Param.h:329
unsigned __INT64_TYPE__ uint64_t
signed __INT64_TYPE__ int64_t
signed __INT32_TYPE__ int32_t
unsigned __INT8_TYPE__ uint8_t
unsigned __INT16_TYPE__ uint16_t
unsigned __INT32_TYPE__ uint32_t
signed __INT16_TYPE__ int16_t
signed __INT8_TYPE__ int8_t
A struct representing an argument to a halide-generated function.
Definition Argument.h:37
A fragment of Halide syntax.
Definition Expr.h:258
An argument to an extern-defined Func.
static Expr make(Type t, Expr v)
static Expr make(Type type, const std::string &name)
Definition IR.h:785
Types in the halide type system.
Definition Type.h:283
A runtime tag for a type in the halide type system.
#define user_assert(c)
Definition test.h:10