Halide
Type.h
Go to the documentation of this file.
1 #ifndef HALIDE_TYPE_H
2 #define HALIDE_TYPE_H
3 
4 #include <stdint.h>
6 #include "Error.h"
7 #include "Util.h"
8 #include "Float16.h"
9 
10 /** \file
11  * Defines halide types
12  */
13 
14 /** A set of types to represent a C++ function signature. This allows
15  * two things. First, proper prototypes can be provided for Halide
16  * generated functions, giving better compile time type
17  * checking. Second, C++ name mangling can be done to provide link
18  * time type checking for both Halide generated functions and calls
19  * from Halide to external functions.
20  *
21  * These are intended to be constexpr producable, but we don't depend
22  * on C++11 yet. In C++14, it is possible these will be replaced with
23  * introspection/reflection facilities.
24  *
25  * halide_handle_traits has to go outside the Halide namespace due to template
26  * resolution rules. TODO(zalman): Do all types need to be in global namespace?
27  */
28  //@{
29 
30 /** A structure to represent the (unscoped) name of a C++ composite type for use
31  * as a single argument (or return value) in a function signature.
32  *
33  * Currently does not support the restrict qualifier, references, or
34  * r-value references. These features cannot be used in extern
35  * function calls from Halide or in the generated function from
36  * Halide, but their applicability seems limited anyway.
37  */
39  /// An enum to indicate whether a C++ type is non-composite, a struct, class, or union
40  enum CPPTypeType {
41  Simple, ///< "int"
42  Struct, ///< "struct Foo"
43  Class, ///< "class Foo"
44  Union, ///< "union Foo"
45  Enum, ///< "enum Foo"
46  } cpp_type_type; // Note: order is reflected in map_to_name table in CPlusPlusMangle.cpp
47 
48  std::string name;
49 
50  halide_cplusplus_type_name(CPPTypeType cpp_type_type, const std::string &name)
51  : cpp_type_type(cpp_type_type), name(name) {
52  }
53 
54  bool operator==(const halide_cplusplus_type_name &rhs) const {
55  return cpp_type_type == rhs.cpp_type_type &&
56  name == rhs.name;
57  }
58 
59  bool operator!=(const halide_cplusplus_type_name &rhs) const {
60  return !(*this == rhs);
61  }
62 
63  bool operator<(const halide_cplusplus_type_name &rhs) const {
64  return cpp_type_type < rhs.cpp_type_type ||
65  (cpp_type_type == rhs.cpp_type_type &&
66  name < rhs.name);
67  }
68 };
69 
70 /** A structure to represent the fully scoped name of a C++ composite
71  * type for use in generating function signatures that use that type.
72  *
73  * This is intended to be a constexpr usable type, but we don't depend
74  * on C++11 yet. In C++14, it is possible this will be replaced with
75  * introspection/reflection facilities.
76  */
79  std::vector<std::string> namespaces;
80  std::vector<halide_cplusplus_type_name> enclosing_types;
81 
82  /// One set of modifiers on a type.
83  /// The const/volatile/restrict propertises are "inside" the pointer property.
84  enum Modifier : uint8_t {
85  Const = 1 << 0, ///< Bitmask flag for "const"
86  Volatile = 1 << 1, ///< Bitmask flag for "volatile"
87  Restrict = 1 << 2, ///< Bitmask flag for "restrict"
88  Pointer = 1 << 3, ///< Bitmask flag for a pointer "*"
89  };
90 
91  /// Qualifiers and indirections on type. 0 is innermost.
92  std::vector<uint8_t> cpp_type_modifiers;
93 
94  /// References are separate because they only occur at the outermost level.
95  /// No modifiers are needed for references as they are not allowed to apply
96  /// to the reference itself. (This isn't true for restrict, but that is a C++
97  /// extension anyway.) If modifiers are needed, the last entry in the above
98  /// array would be the modifers for the reference.
100  NotReference = 0,
101  LValueReference = 1, // "&"
102  RValueReference = 2, // "&&"
103  };
105 
107  const std::vector<std::string> &namespaces = { },
108  const std::vector<halide_cplusplus_type_name> &enclosing_types = { },
109  const std::vector<uint8_t> &modifiers = { },
110  ReferenceType reference_type = NotReference)
111  : inner_name(inner_name),
112  namespaces(namespaces),
113  enclosing_types(enclosing_types),
114  cpp_type_modifiers(modifiers),
115  reference_type(reference_type) {}
116 };
117 //@}
118 
119 template<typename T>
121  static const bool known_type = false;
122 };
123 
124 #define HALIDE_DECLARE_EXTERN_TYPE(TypeType, Type) \
125  template<> struct halide_c_type_to_name<Type> { \
126  static const bool known_type = true; \
127  static halide_cplusplus_type_name name() { \
128  return { halide_cplusplus_type_name::TypeType, #Type}; \
129  } \
130  }
131 
132 #define HALIDE_DECLARE_EXTERN_SIMPLE_TYPE(T) HALIDE_DECLARE_EXTERN_TYPE(Simple, T)
133 #define HALIDE_DECLARE_EXTERN_STRUCT_TYPE(T) HALIDE_DECLARE_EXTERN_TYPE(Struct, T)
134 #define HALIDE_DECLARE_EXTERN_CLASS_TYPE(T) HALIDE_DECLARE_EXTERN_TYPE(Class, T)
135 #define HALIDE_DECLARE_EXTERN_UNION_TYPE(T) HALIDE_DECLARE_EXTERN_TYPE(Union, T)
136 
153 
154 // You can make arbitrary user-defined types be "Known" using the
155 // macro above. This is useful for making Param<> arguments for
156 // Generators type safe. e.g.,
157 //
158 // struct MyFunStruct { ... };
159 //
160 // ...
161 //
162 // HALIDE_DECLARE_EXTERN_STRUCT_TYPE(MyFunStruct);
163 //
164 // ...
165 //
166 // class MyGenerator : public Generator<MyGenerator> {
167 // Param<const MyFunStruct *> my_struct_ptr;
168 // ...
169 // };
170 
171 
172 // Default case (should be only Unknown types, since we specialize for Known types below).
173 // We require that all unknown types be pointers, and translate them all to void*
174 // (preserving const-ness and volatile-ness).
175 template<typename T, bool KnownType>
177  static const halide_handle_cplusplus_type *type_info(bool is_ptr,
179  static_assert(!KnownType, "Only unknown types handled here");
180  internal_assert(is_ptr) << "Unknown types must be pointers";
181  internal_assert(ref_type == halide_handle_cplusplus_type::NotReference) << "Unknown types must not be references";
182  static const halide_handle_cplusplus_type the_info{
184  {},
185  {},
186  {
188  (std::is_const<T>::value ? halide_handle_cplusplus_type::Const : 0) |
189  (std::is_volatile<T>::value ? halide_handle_cplusplus_type::Volatile : 0))
190  },
192  };
193  return &the_info;
194  }
195 };
196 
197 // Known types
198 template<typename T>
200 
201  static const halide_handle_cplusplus_type make_info(bool is_ptr,
203  halide_handle_cplusplus_type the_info = {
205  {},
206  {},
207  {
209  (std::is_const<T>::value ? halide_handle_cplusplus_type::Const : 0) |
210  (std::is_volatile<T>::value ? halide_handle_cplusplus_type::Volatile : 0))
211  },
212  ref_type
213  };
214  // Pull off any namespaces
215  the_info.inner_name.name =
217  the_info.namespaces);
218  return the_info;
219  }
220 
221  static const halide_handle_cplusplus_type *type_info(bool is_ptr,
223  static const halide_handle_cplusplus_type the_info = make_info(is_ptr, ref_type);
224  return &the_info;
225  }
226 };
227 
228 /** A type traits template to provide a halide_handle_cplusplus_type
229  * value from a C++ type.
230  *
231  * Note the type represented is implicitly a pointer.
232  *
233  * A NULL pointer of type halide_handle_traits represents "void *".
234  * This is chosen for compactness or representation as Type is a very
235  * widely used data structure.
236  */
237 template<typename T>
239  // NULL here means "void *". This trait must return a pointer to a
240  // global structure. I.e. it should never be freed.
241  inline static const halide_handle_cplusplus_type *type_info() { return nullptr; }
242 };
243 
244 template<typename T>
245 struct halide_handle_traits<T *> {
246  inline static const halide_handle_cplusplus_type *type_info() {
248  }
249 };
250 
251 template<typename T>
252 struct halide_handle_traits<T &> {
253  inline static const halide_handle_cplusplus_type *type_info() {
255  }
256 };
257 
258 template<typename T>
259 struct halide_handle_traits<T &&> {
260  inline static const halide_handle_cplusplus_type *type_info() {
262  }
263 };
264 
265 template<>
266 struct halide_handle_traits<const char *> {
267  inline static const halide_handle_cplusplus_type *type_info() {
268  static const halide_handle_cplusplus_type the_info{
272  return &the_info;
273  }
274 };
275 
276 namespace Halide {
277 
278 struct Expr;
279 
280 /** Types in the halide type system. They can be ints, unsigned ints,
281  * or floats of various bit-widths (the 'bits' field). They can also
282  * be vectors of the same (by setting the 'lanes' field to something
283  * larger than one). Front-end code shouldn't use vector
284  * types. Instead vectorize a function. */
285 struct Type {
286  private:
287  halide_type_t type;
288 
289  public:
290  /** Aliases for halide_type_code_t values for legacy compatibility
291  * and to match the Halide internal C++ style. */
292  // @{
297  // @}
298 
299  /** The number of bytes required to store a single scalar value of this type. Ignores vector lanes. */
300  int bytes() const {return (bits() + 7) / 8;}
301 
302  // Default ctor initializes everything to predictable-but-unlikely values
303  Type() : type(Handle, 0, 0), handle_type(nullptr) {}
304 
305 
306  /** Construct a runtime representation of a Halide type from:
307  * code: The fundamental type from an enum.
308  * bits: The bit size of one element.
309  * lanes: The number of vector elements in the type. */
310  Type(halide_type_code_t code, int bits, int lanes, const halide_handle_cplusplus_type *handle_type = nullptr)
311  : type(code, (uint8_t)bits, (uint16_t)lanes), handle_type(handle_type) {
312  }
313 
314  /** Trivial copy constructor. */
315  Type(const Type &that) = default;
316 
317  /** Type is a wrapper around halide_type_t with more methods for use
318  * inside the compiler. This simply constructs the wrapper around
319  * the runtime value. */
320  Type(const halide_type_t &that, const halide_handle_cplusplus_type *handle_type = nullptr)
321  : type(that), handle_type(handle_type) {}
322 
323  /** Unwrap the runtime halide_type_t for use in runtime calls, etc.
324  * Representation is exactly equivalent. */
325  operator halide_type_t() const { return type; }
326 
327  /** Return the underlying data type of an element as an enum value. */
328  halide_type_code_t code() const { return (halide_type_code_t)type.code; }
329 
330  /** Return the bit size of a single element of this type. */
331  int bits() const { return type.bits; }
332 
333  /** Return the number of vector elements in this type. */
334  int lanes() const { return type.lanes; }
335 
336  /** Return Type with same number of bits and lanes, but new_code for a type code. */
338  return Type(new_code, bits(), lanes(),
339  (new_code == code()) ? handle_type : nullptr);
340  }
341 
342  /** Return Type with same type code and lanes, but new_bits for the number of bits. */
343  Type with_bits(int new_bits) const {
344  return Type(code(), new_bits, lanes(),
345  (new_bits == bits()) ? handle_type : nullptr);
346  }
347 
348  /** Return Type with same type code and number of bits,
349  * but new_lanes for the number of vector lanes. */
350  Type with_lanes(int new_lanes) const {
351  return Type(code(), bits(), new_lanes, handle_type);
352  }
353 
354  /** Type to be printed when declaring handles of this type. */
356 
357  /** Is this type boolean (represented as UInt(1))? */
358  bool is_bool() const {return code() == UInt && bits() == 1;}
359 
360  /** Is this type a vector type? (lanes() != 1).
361  * TODO(abadams): Decide what to do for lanes() == 0. */
362  bool is_vector() const {return lanes() != 1;}
363 
364  /** Is this type a scalar type? (lanes() == 1).
365  * TODO(abadams): Decide what to do for lanes() == 0. */
366  bool is_scalar() const {return lanes() == 1;}
367 
368  /** Is this type a floating point type (float or double). */
369  bool is_float() const {return code() == Float;}
370 
371  /** Is this type a signed integer type? */
372  bool is_int() const {return code() == Int;}
373 
374  /** Is this type an unsigned integer type? */
375  bool is_uint() const {return code() == UInt;}
376 
377  /** Is this type an opaque handle type (void *) */
378  bool is_handle() const {return code() == Handle;}
379 
380  /** Check that the type name of two handles matches. */
381  EXPORT bool same_handle_type(const Type &other) const;
382 
383  /** Compare two types for equality */
384  bool operator==(const Type &other) const {
385  return code() == other.code() && bits() == other.bits() && lanes() == other.lanes() &&
386  (code() != Handle || same_handle_type(other));
387  }
388 
389  /** Compare two types for inequality */
390  bool operator!=(const Type &other) const {
391  return code() != other.code() || bits() != other.bits() || lanes() != other.lanes() ||
392  (code() == Handle && !same_handle_type(other));
393  }
394 
395  /** Compare ordering of two types so they can be used in certain containers and algorithms */
396  bool operator<(const Type &other) const {
397  return code() < other.code() || (code() == other.code() &&
398  (bits() < other.bits() || (bits() == other.bits() &&
399  (lanes() < other.lanes() || (lanes() == other.lanes() &&
400  (code() == Handle && handle_type < other.handle_type))))));
401  }
402 
403  /** Produce the scalar type (that of a single element) of this vector type */
404  Type element_of() const {
405  return with_lanes(1);
406  }
407 
408  /** Can this type represent all values of another type? */
409  EXPORT bool can_represent(Type other) const;
410 
411  /** Can this type represent a particular constant? */
412  // @{
413  EXPORT bool can_represent(double x) const;
414  EXPORT bool can_represent(int64_t x) const;
415  EXPORT bool can_represent(uint64_t x) const;
416  // @}
417 
418  /** Check if an integer constant value is the maximum or minimum
419  * representable value for this type. */
420  // @{
421  EXPORT bool is_max(uint64_t) const;
422  EXPORT bool is_max(int64_t) const;
423  EXPORT bool is_min(uint64_t) const;
424  EXPORT bool is_min(int64_t) const;
425  // @}
426 
427  /** Return an expression which is the maximum value of this type.
428  * Returns infinity for types which can represent it. */
429  EXPORT Expr max() const;
430 
431  /** Return an expression which is the minimum value of this type.
432  * Returns -infinity for types which can represent it. */
433  EXPORT Expr min() const;
434 };
435 
436 /** Constructing a signed integer type */
437 inline Type Int(int bits, int lanes = 1) {
438  return Type(Type::Int, bits, lanes);
439 }
440 
441 /** Constructing an unsigned integer type */
442 inline Type UInt(int bits, int lanes = 1) {
443  return Type(Type::UInt, bits, lanes);
444 }
445 
446 /** Construct a floating-point type */
447 inline Type Float(int bits, int lanes = 1) {
448  return Type(Type::Float, bits, lanes);
449 }
450 
451 /** Construct a boolean type */
452 inline Type Bool(int lanes = 1) {
453  return UInt(1, lanes);
454 }
455 
456 /** Construct a handle type */
457 inline Type Handle(int lanes = 1, const halide_handle_cplusplus_type *handle_type = nullptr) {
458  return Type(Type::Handle, 64, lanes, handle_type);
459 }
460 
461 /** Construct the halide equivalent of a C type */
462 template<typename T>
463 inline Type type_of() {
464  return Type(halide_type_of<T>(), halide_handle_traits<T>::type_info());
465 }
466 
467 } // namespace Halide
468 
469 #endif
Various utility functions used internally Halide.
bool operator==(const Type &other) const
Compare two types for equality.
Definition: Type.h:384
static const halide_handle_cplusplus_type * type_info()
Definition: Type.h:241
bool is_int() const
Is this type a signed integer type?
Definition: Type.h:372
A fragment of Halide syntax.
Definition: Expr.h:276
#define HALIDE_DECLARE_EXTERN_STRUCT_TYPE(T)
Definition: Type.h:133
A type traits template to provide a halide_handle_cplusplus_type value from a C++ type...
Definition: Type.h:238
CPPTypeType
An enum to indicate whether a C++ type is non-composite, a struct, class, or union.
Definition: Type.h:40
bool is_uint() const
Is this type an unsigned integer type?
Definition: Type.h:375
Bitmask flag for "const".
Definition: Type.h:85
int bytes() const
The number of bytes required to store a single scalar value of this type.
Definition: Type.h:300
bool is_handle() const
Is this type an opaque handle type (void *)
Definition: Type.h:378
floating point numbers
signed __INT8_TYPE__ int8_t
Type Handle(int lanes=1, const halide_handle_cplusplus_type *handle_type=nullptr)
Construct a handle type.
Definition: Type.h:457
bool operator<(const halide_cplusplus_type_name &rhs) const
Definition: Type.h:63
Modifier
One set of modifiers on a type.
Definition: Type.h:84
std::vector< std::string > namespaces
Definition: Type.h:79
bool is_vector() const
Is this type a vector type? (lanes() != 1).
Definition: Type.h:362
static const halide_handle_cplusplus_type * type_info(bool is_ptr, halide_handle_cplusplus_type::ReferenceType ref_type)
Definition: Type.h:221
static const halide_handle_cplusplus_type * type_info()
Definition: Type.h:260
Defines methods for manipulating and analyzing boolean expressions.
Type element_of() const
Produce the scalar type (that of a single element) of this vector type.
Definition: Type.h:404
unsigned __INT8_TYPE__ uint8_t
std::string name
Definition: Type.h:48
bool operator<(const Type &other) const
Compare ordering of two types so they can be used in certain containers and algorithms.
Definition: Type.h:396
unsigned integers
Type with_code(halide_type_code_t new_code) const
Return Type with same number of bits and lanes, but new_code for a type code.
Definition: Type.h:337
Expr min(FuncRef a, FuncRef b)
Explicit overloads of min and max for FuncRef.
Definition: Func.h:418
Bitmask flag for a pointer "*".
Definition: Type.h:88
Type with_lanes(int new_lanes) const
Return Type with same type code and number of bits, but new_lanes for the number of vector lanes...
Definition: Type.h:350
bool operator!=(const Type &other) const
Compare two types for inequality.
Definition: Type.h:390
bool operator==(const halide_cplusplus_type_name &rhs) const
Definition: Type.h:54
Type with_bits(int new_bits) const
Return Type with same type code and lanes, but new_bits for the number of bits.
Definition: Type.h:343
halide_cplusplus_type_name(CPPTypeType cpp_type_type, const std::string &name)
Definition: Type.h:50
#define HALIDE_DECLARE_EXTERN_SIMPLE_TYPE(T)
Definition: Type.h:132
bool is_bool() const
Is this type boolean (represented as UInt(1))?
Definition: Type.h:358
static const halide_handle_cplusplus_type * type_info()
Definition: Type.h:253
halide_type_code_t code() const
Return the underlying data type of an element as an enum value.
Definition: Type.h:328
A structure to represent the fully scoped name of a C++ composite type for use in generating function...
Definition: Type.h:77
bool is_float() const
Is this type a floating point type (float or double).
Definition: Type.h:369
Set a custom malloc and free for halide to use.
const halide_handle_cplusplus_type * handle_type
Type to be printed when declaring handles of this type.
Definition: Type.h:355
Each GPU API provides a halide_device_interface_t struct pointing to the code that manages device all...
#define internal_assert(c)
Definition: Error.h:140
std::vector< halide_cplusplus_type_name > enclosing_types
Definition: Type.h:80
opaque pointer type (void *)
unsigned __INT32_TYPE__ uint32_t
static const halide_handle_cplusplus_type * type_info()
Definition: Type.h:267
static const halide_handle_cplusplus_type * type_info()
Definition: Type.h:246
std::vector< uint8_t > cpp_type_modifiers
Qualifiers and indirections on type. 0 is innermost.
Definition: Type.h:92
EXPORT std::string extract_namespaces(const std::string &name, std::vector< std::string > &namespaces)
Returns base name and fills in namespaces, outermost one first in vector.
Type(const halide_type_t &that, const halide_handle_cplusplus_type *handle_type=nullptr)
Type is a wrapper around halide_type_t with more methods for use inside the compiler.
Definition: Type.h:320
signed __INT64_TYPE__ int64_t
Type Bool(int lanes=1)
Construct a boolean type.
Definition: Type.h:452
static const halide_handle_cplusplus_type make_info(bool is_ptr, halide_handle_cplusplus_type::ReferenceType ref_type)
Definition: Type.h:201
Bitmask flag for "volatile".
Definition: Type.h:86
A runtime tag for a type in the halide type system.
halide_cplusplus_type_name inner_name
Definition: Type.h:78
ReferenceType reference_type
Definition: Type.h:104
Type(halide_type_code_t code, int bits, int lanes, const halide_handle_cplusplus_type *handle_type=nullptr)
Construct a runtime representation of a Halide type from: code: The fundamental type from an enum...
Definition: Type.h:310
Type UInt(int bits, int lanes=1)
Constructing an unsigned integer type.
Definition: Type.h:442
bool is_scalar() const
Is this type a scalar type? (lanes() == 1).
Definition: Type.h:366
unsigned __INT16_TYPE__ uint16_t
Types in the halide type system.
Definition: Type.h:285
static const halide_handle_cplusplus_type * type_info(bool is_ptr, halide_handle_cplusplus_type::ReferenceType ref_type)
Definition: Type.h:177
halide_type_code_t
Types in the halide type system.
ReferenceType
References are separate because they only occur at the outermost level.
Definition: Type.h:99
int bits() const
Return the bit size of a single element of this type.
Definition: Type.h:331
#define EXPORT
Definition: Util.h:30
enum halide_cplusplus_type_name::CPPTypeType cpp_type_type
A set of types to represent a C++ function signature.
Definition: Type.h:38
The raw representation of an image passed around by generated Halide code.
unsigned __INT64_TYPE__ uint64_t
int lanes() const
Return the number of vector elements in this type.
Definition: Type.h:334
halide_handle_cplusplus_type(const halide_cplusplus_type_name &inner_name, const std::vector< std::string > &namespaces={ }, const std::vector< halide_cplusplus_type_name > &enclosing_types={ }, const std::vector< uint8_t > &modifiers={ }, ReferenceType reference_type=NotReference)
Definition: Type.h:106
Type type_of()
Construct the halide equivalent of a C type.
Definition: Type.h:463
Expr max(FuncRef a, FuncRef b)
Explicit overloads of min and max for FuncRef.
Definition: Func.h:419
signed __INT32_TYPE__ int32_t
signed integers
Type Int(int bits, int lanes=1)
Constructing a signed integer type.
Definition: Type.h:437
signed __INT16_TYPE__ int16_t
Type Float(int bits, int lanes=1)
Construct a floating-point type.
Definition: Type.h:447
bool operator!=(const halide_cplusplus_type_name &rhs) const
Definition: Type.h:59