Halide  14.0.0
Halide compiler and libraries
Generator.h
Go to the documentation of this file.
1 #ifndef HALIDE_GENERATOR_H_
2 #define HALIDE_GENERATOR_H_
3 
4 /** \file
5  *
6  * Generator is a class used to encapsulate the building of Funcs in user
7  * pipelines. A Generator is agnostic to JIT vs AOT compilation; it can be used for
8  * either purpose, but is especially convenient to use for AOT compilation.
9  *
10  * A Generator explicitly declares the Inputs and Outputs associated for a given
11  * pipeline, and (optionally) separates the code for constructing the outputs from the code from
12  * scheduling them. For instance:
13  *
14  * \code
15  * class Blur : public Generator<Blur> {
16  * public:
17  * Input<Func> input{"input", UInt(16), 2};
18  * Output<Func> output{"output", UInt(16), 2};
19  * void generate() {
20  * blur_x(x, y) = (input(x, y) + input(x+1, y) + input(x+2, y))/3;
21  * blur_y(x, y) = (blur_x(x, y) + blur_x(x, y+1) + blur_x(x, y+2))/3;
22  * output(x, y) = blur(x, y);
23  * }
24  * void schedule() {
25  * blur_y.split(y, y, yi, 8).parallel(y).vectorize(x, 8);
26  * blur_x.store_at(blur_y, y).compute_at(blur_y, yi).vectorize(x, 8);
27  * }
28  * private:
29  * Var x, y, xi, yi;
30  * Func blur_x, blur_y;
31  * };
32  * \endcode
33  *
34  * Halide can compile a Generator into the correct pipeline by introspecting these
35  * values and constructing an appropriate signature based on them.
36  *
37  * A Generator provides implementations of two methods:
38  *
39  * - generate(), which must fill in all Output Func(s); it may optionally also do scheduling
40  * if no schedule() method is present.
41  * - schedule(), which (if present) should contain all scheduling code.
42  *
43  * Inputs can be any C++ scalar type:
44  *
45  * \code
46  * Input<float> radius{"radius"};
47  * Input<int32_t> increment{"increment"};
48  * \endcode
49  *
50  * An Input<Func> is (essentially) like an ImageParam, except that it may (or may
51  * not) not be backed by an actual buffer, and thus has no defined extents.
52  *
53  * \code
54  * Input<Func> input{"input", Float(32), 2};
55  * \endcode
56  *
57  * You can optionally make the type and/or dimensions of Input<Func> unspecified,
58  * in which case the value is simply inferred from the actual Funcs passed to them.
59  * Of course, if you specify an explicit Type or Dimension, we still require the
60  * input Func to match, or a compilation error results.
61  *
62  * \code
63  * Input<Func> input{ "input", 3 }; // require 3-dimensional Func,
64  * // but leave Type unspecified
65  * \endcode
66  *
67  * A Generator must explicitly list the output(s) it produces:
68  *
69  * \code
70  * Output<Func> output{"output", Float(32), 2};
71  * \endcode
72  *
73  * You can specify an output that returns a Tuple by specifying a list of Types:
74  *
75  * \code
76  * class Tupler : Generator<Tupler> {
77  * Input<Func> input{"input", Int(32), 2};
78  * Output<Func> output{"output", {Float(32), UInt(8)}, 2};
79  * void generate() {
80  * Var x, y;
81  * Expr a = cast<float>(input(x, y));
82  * Expr b = cast<uint8_t>(input(x, y));
83  * output(x, y) = Tuple(a, b);
84  * }
85  * };
86  * \endcode
87  *
88  * You can also specify Output<X> for any scalar type (except for Handle types);
89  * this is merely syntactic sugar on top of a zero-dimensional Func, but can be
90  * quite handy, especially when used with multiple outputs:
91  *
92  * \code
93  * Output<float> sum{"sum"}; // equivalent to Output<Func> {"sum", Float(32), 0}
94  * \endcode
95  *
96  * As with Input<Func>, you can optionally make the type and/or dimensions of an
97  * Output<Func> unspecified; any unspecified types must be resolved via an
98  * implicit GeneratorParam in order to use top-level compilation.
99  *
100  * You can also declare an *array* of Input or Output, by using an array type
101  * as the type parameter:
102  *
103  * \code
104  * // Takes exactly 3 images and outputs exactly 3 sums.
105  * class SumRowsAndColumns : Generator<SumRowsAndColumns> {
106  * Input<Func[3]> inputs{"inputs", Float(32), 2};
107  * Input<int32_t[2]> extents{"extents"};
108  * Output<Func[3]> sums{"sums", Float(32), 1};
109  * void generate() {
110  * assert(inputs.size() == sums.size());
111  * // assume all inputs are same extent
112  * Expr width = extent[0];
113  * Expr height = extent[1];
114  * for (size_t i = 0; i < inputs.size(); ++i) {
115  * RDom r(0, width, 0, height);
116  * sums[i]() = 0.f;
117  * sums[i]() += inputs[i](r.x, r.y);
118  * }
119  * }
120  * };
121  * \endcode
122  *
123  * You can also leave array size unspecified, with some caveats:
124  * - For ahead-of-time compilation, Inputs must have a concrete size specified
125  * via a GeneratorParam at build time (e.g., pyramid.size=3)
126  * - For JIT compilation via a Stub, Inputs array sizes will be inferred
127  * from the vector passed.
128  * - For ahead-of-time compilation, Outputs may specify a concrete size
129  * via a GeneratorParam at build time (e.g., pyramid.size=3), or the
130  * size can be specified via a resize() method.
131  *
132  * \code
133  * class Pyramid : public Generator<Pyramid> {
134  * public:
135  * GeneratorParam<int32_t> levels{"levels", 10};
136  * Input<Func> input{ "input", Float(32), 2 };
137  * Output<Func[]> pyramid{ "pyramid", Float(32), 2 };
138  * void generate() {
139  * pyramid.resize(levels);
140  * pyramid[0](x, y) = input(x, y);
141  * for (int i = 1; i < pyramid.size(); i++) {
142  * pyramid[i](x, y) = (pyramid[i-1](2*x, 2*y) +
143  * pyramid[i-1](2*x+1, 2*y) +
144  * pyramid[i-1](2*x, 2*y+1) +
145  * pyramid[i-1](2*x+1, 2*y+1))/4;
146  * }
147  * }
148  * };
149  * \endcode
150  *
151  * A Generator can also be customized via compile-time parameters (GeneratorParams),
152  * which affect code generation.
153  *
154  * GeneratorParams, Inputs, and Outputs are (by convention) always
155  * public and always declared at the top of the Generator class, in the order
156  *
157  * \code
158  * GeneratorParam(s)
159  * Input<Func>(s)
160  * Input<non-Func>(s)
161  * Output<Func>(s)
162  * \endcode
163  *
164  * Note that the Inputs and Outputs will appear in the C function call in the order
165  * they are declared. All Input<Func> and Output<Func> are represented as halide_buffer_t;
166  * all other Input<> are the appropriate C++ scalar type. (GeneratorParams are
167  * always referenced by name, not position, so their order is irrelevant.)
168  *
169  * All Inputs and Outputs must have explicit names, and all such names must match
170  * the regex [A-Za-z][A-Za-z_0-9]* (i.e., essentially a C/C++ variable name, with
171  * some extra restrictions on underscore use). By convention, the name should match
172  * the member-variable name.
173  *
174  * You can dynamically add Inputs and Outputs to your Generator via adding a
175  * configure() method; if present, it will be called before generate(). It can
176  * examine GeneratorParams but it may not examine predeclared Inputs or Outputs;
177  * the only thing it should do is call add_input<>() and/or add_output<>(), or call
178  * set_type()/set_dimensions()/set_array_size() on an Input or Output with an unspecified type.
179  * Added inputs will be appended (in order) after predeclared Inputs but before
180  * any Outputs; added outputs will be appended after predeclared Outputs.
181  *
182  * Note that the pointers returned by add_input() and add_output() are owned
183  * by the Generator and will remain valid for the Generator's lifetime; user code
184  * should not attempt to delete or free them.
185  *
186  * \code
187  * class MultiSum : public Generator<MultiSum> {
188  * public:
189  * GeneratorParam<int32_t> input_count{"input_count", 10};
190  * Output<Func> output{ "output", Float(32), 2 };
191  *
192  * void configure() {
193  * for (int i = 0; i < input_count; ++i) {
194  * extra_inputs.push_back(
195  * add_input<Func>("input_" + std::to_string(i), Float(32), 2);
196  * }
197  * }
198  *
199  * void generate() {
200  * Expr sum = 0.f;
201  * for (int i = 0; i < input_count; ++i) {
202  * sum += (*extra_inputs)[i](x, y);
203  * }
204  * output(x, y) = sum;
205  * }
206  * private:
207  * std::vector<Input<Func>* extra_inputs;
208  * };
209  * \endcode
210  *
211  * All Generators have three GeneratorParams that are implicitly provided
212  * by the base class:
213  *
214  * GeneratorParam<Target> target{"target", Target()};
215  * GeneratorParam<bool> auto_schedule{"auto_schedule", false};
216  * GeneratorParam<MachineParams> machine_params{"machine_params", MachineParams::generic()};
217  *
218  * - 'target' is the Halide::Target for which the Generator is producing code.
219  * It is read-only during the Generator's lifetime, and must not be modified;
220  * its value should always be filled in by the calling code: either the Halide
221  * build system (for ahead-of-time compilation), or ordinary C++ code
222  * (for JIT compilation).
223  * - 'auto_schedule' indicates whether the auto-scheduler should be run for this
224  * Generator:
225  * - if 'false', the Generator should schedule its Funcs as it sees fit.
226  * - if 'true', the Generator should only provide estimate()s for its Funcs,
227  * and not call any other scheduling methods.
228  * - 'machine_params' is only used if auto_schedule is true; it is ignored
229  * if auto_schedule is false. It provides details about the machine architecture
230  * being targeted which may be used to enhance the automatically-generated
231  * schedule.
232  *
233  * Generators are added to a global registry to simplify AOT build mechanics; this
234  * is done by simply using the HALIDE_REGISTER_GENERATOR macro at global scope:
235  *
236  * \code
237  * HALIDE_REGISTER_GENERATOR(ExampleGen, jit_example)
238  * \endcode
239  *
240  * The registered name of the Generator is provided must match the same rules as
241  * Input names, above.
242  *
243  * Note that the class name of the generated Stub class will match the registered
244  * name by default; if you want to vary it (typically, to include namespaces),
245  * you can add it as an optional third argument:
246  *
247  * \code
248  * HALIDE_REGISTER_GENERATOR(ExampleGen, jit_example, SomeNamespace::JitExampleStub)
249  * \endcode
250  *
251  * Note that a Generator is always executed with a specific Target assigned to it,
252  * that you can access via the get_target() method. (You should *not* use the
253  * global get_target_from_environment(), etc. methods provided in Target.h)
254  *
255  * (Note that there are older variations of Generator that differ from what's
256  * documented above; these are still supported but not described here. See
257  * https://github.com/halide/Halide/wiki/Old-Generator-Documentation for
258  * more information.)
259  */
260 
261 #include <algorithm>
262 #include <functional>
263 #include <iterator>
264 #include <limits>
265 #include <memory>
266 #include <mutex>
267 #include <set>
268 #include <sstream>
269 #include <string>
270 #include <type_traits>
271 #include <utility>
272 #include <vector>
273 
274 #include "ExternalCode.h"
275 #include "Func.h"
276 #include "ImageParam.h"
277 #include "Introspection.h"
278 #include "ObjectInstanceRegistry.h"
279 #include "Target.h"
280 
281 #if !(__cplusplus >= 201703L || _MSVC_LANG >= 201703L)
282 #error "Halide requires C++17 or later; please upgrade your compiler."
283 #endif
284 
285 namespace Halide {
286 namespace Internal {
287 
289 
290 class ValueTracker;
291 
292 std::vector<Expr> parameter_constraints(const Parameter &p);
293 
294 template<typename T>
295 HALIDE_NO_USER_CODE_INLINE std::string enum_to_string(const std::map<std::string, T> &enum_map, const T &t) {
296  for (const auto &key_value : enum_map) {
297  if (t == key_value.second) {
298  return key_value.first;
299  }
300  }
301  user_error << "Enumeration value not found.\n";
302  return "";
303 }
304 
305 template<typename T>
306 T enum_from_string(const std::map<std::string, T> &enum_map, const std::string &s) {
307  auto it = enum_map.find(s);
308  user_assert(it != enum_map.end()) << "Enumeration value not found: " << s << "\n";
309  return it->second;
310 }
311 
312 extern const std::map<std::string, Halide::Type> &get_halide_type_enum_map();
313 inline std::string halide_type_to_enum_string(const Type &t) {
315 }
316 
317 // Convert a Halide Type into a string representation of its C source.
318 // e.g., Int(32) -> "Halide::Int(32)"
319 std::string halide_type_to_c_source(const Type &t);
320 
321 // Convert a Halide Type into a string representation of its C Source.
322 // e.g., Int(32) -> "int32_t"
323 std::string halide_type_to_c_type(const Type &t);
324 
325 /** generate_filter_main() is a convenient wrapper for GeneratorRegistry::create() +
326  * compile_to_files(); it can be trivially wrapped by a "real" main() to produce a
327  * command-line utility for ahead-of-time filter compilation. */
328 int generate_filter_main(int argc, char **argv, std::ostream &cerr);
329 
330 // select_type<> is to std::conditional as switch is to if:
331 // it allows a multiway compile-time type definition via the form
332 //
333 // select_type<cond<condition1, type1>,
334 // cond<condition2, type2>,
335 // ....
336 // cond<conditionN, typeN>>::type
337 //
338 // Note that the conditions are evaluated in order; the first evaluating to true
339 // is chosen.
340 //
341 // Note that if no conditions evaluate to true, the resulting type is illegal
342 // and will produce a compilation error. (You can provide a default by simply
343 // using cond<true, SomeType> as the final entry.)
344 template<bool B, typename T>
345 struct cond {
346  static constexpr bool value = B;
347  using type = T;
348 };
349 
350 template<typename First, typename... Rest>
351 struct select_type : std::conditional<First::value, typename First::type, typename select_type<Rest...>::type> {};
352 
353 template<typename First>
354 struct select_type<First> { using type = typename std::conditional<First::value, typename First::type, void>::type; };
355 
356 class GeneratorBase;
357 class GeneratorParamInfo;
358 
360 public:
361  explicit GeneratorParamBase(const std::string &name);
363 
364  inline const std::string &name() const {
365  return name_;
366  }
367 
368  // overload the set() function to call the right virtual method based on type.
369  // This allows us to attempt to set a GeneratorParam via a
370  // plain C++ type, even if we don't know the specific templated
371  // subclass. Attempting to set the wrong type will assert.
372  // Notice that there is no typed setter for Enums, for obvious reasons;
373  // setting enums in an unknown type must fallback to using set_from_string.
374  //
375  // It's always a bit iffy to use macros for this, but IMHO it clarifies the situation here.
376 #define HALIDE_GENERATOR_PARAM_TYPED_SETTER(TYPE) \
377  virtual void set(const TYPE &new_value) = 0;
378 
394 
395 #undef HALIDE_GENERATOR_PARAM_TYPED_SETTER
396 
397  // Add overloads for string and char*
398  void set(const std::string &new_value) {
399  set_from_string(new_value);
400  }
401  void set(const char *new_value) {
402  set_from_string(std::string(new_value));
403  }
404 
405 protected:
406  friend class GeneratorBase;
407  friend class GeneratorParamInfo;
408  friend class StubEmitter;
409 
410  void check_value_readable() const;
411  void check_value_writable() const;
412 
413  // All GeneratorParams are settable from string.
414  virtual void set_from_string(const std::string &value_string) = 0;
415 
416  virtual std::string call_to_string(const std::string &v) const = 0;
417  virtual std::string get_c_type() const = 0;
418 
419  virtual std::string get_type_decls() const {
420  return "";
421  }
422 
423  virtual std::string get_default_value() const = 0;
424 
425  virtual bool is_synthetic_param() const {
426  return false;
427  }
428 
429  virtual bool is_looplevel_param() const {
430  return false;
431  }
432 
433  void fail_wrong_type(const char *type);
434 
435 private:
436  const std::string name_;
437 
438  // Generator which owns this GeneratorParam. Note that this will be null
439  // initially; the GeneratorBase itself will set this field when it initially
440  // builds its info about params. However, since it (generally) isn't
441  // appropriate for GeneratorParam<> to be declared outside of a Generator,
442  // all reasonable non-testing code should expect this to be non-null.
443  GeneratorBase *generator{nullptr};
444 
445 public:
450 };
451 
452 // This is strictly some syntactic sugar to suppress certain compiler warnings.
453 template<typename FROM, typename TO>
454 struct Convert {
455  template<typename TO2 = TO, typename std::enable_if<!std::is_same<TO2, bool>::value>::type * = nullptr>
456  inline static TO2 value(const FROM &from) {
457  return static_cast<TO2>(from);
458  }
459 
460  template<typename TO2 = TO, typename std::enable_if<std::is_same<TO2, bool>::value>::type * = nullptr>
461  inline static TO2 value(const FROM &from) {
462  return from != 0;
463  }
464 };
465 
466 template<typename T>
468 public:
469  using type = T;
470 
471  GeneratorParamImpl(const std::string &name, const T &value)
473  }
474 
475  T value() const {
476  this->check_value_readable();
477  return value_;
478  }
479 
480  operator T() const {
481  return this->value();
482  }
483 
484  operator Expr() const {
485  return make_const(type_of<T>(), this->value());
486  }
487 
488 #define HALIDE_GENERATOR_PARAM_TYPED_SETTER(TYPE) \
489  void set(const TYPE &new_value) override { \
490  typed_setter_impl<TYPE>(new_value, #TYPE); \
491  }
492 
508 
509 #undef HALIDE_GENERATOR_PARAM_TYPED_SETTER
510 
511  // Overload for std::string.
512  void set(const std::string &new_value) {
514  value_ = new_value;
515  }
516 
517 protected:
518  virtual void set_impl(const T &new_value) {
520  value_ = new_value;
521  }
522 
523  // Needs to be protected to allow GeneratorParam<LoopLevel>::set() override
525 
526 private:
527  // If FROM->T is not legal, fail
528  template<typename FROM, typename std::enable_if<
529  !std::is_convertible<FROM, T>::value>::type * = nullptr>
530  HALIDE_ALWAYS_INLINE void typed_setter_impl(const FROM &, const char *msg) {
531  fail_wrong_type(msg);
532  }
533 
534  // If FROM and T are identical, just assign
535  template<typename FROM, typename std::enable_if<
536  std::is_same<FROM, T>::value>::type * = nullptr>
537  HALIDE_ALWAYS_INLINE void typed_setter_impl(const FROM &value, const char *msg) {
539  value_ = value;
540  }
541 
542  // If both FROM->T and T->FROM are legal, ensure it's lossless
543  template<typename FROM, typename std::enable_if<
544  !std::is_same<FROM, T>::value &&
545  std::is_convertible<FROM, T>::value &&
546  std::is_convertible<T, FROM>::value>::type * = nullptr>
547  HALIDE_ALWAYS_INLINE void typed_setter_impl(const FROM &value, const char *msg) {
549  const T t = Convert<FROM, T>::value(value);
550  const FROM value2 = Convert<T, FROM>::value(t);
551  if (value2 != value) {
552  fail_wrong_type(msg);
553  }
554  value_ = t;
555  }
556 
557  // If FROM->T is legal but T->FROM is not, just assign
558  template<typename FROM, typename std::enable_if<
559  !std::is_same<FROM, T>::value &&
560  std::is_convertible<FROM, T>::value &&
561  !std::is_convertible<T, FROM>::value>::type * = nullptr>
562  HALIDE_ALWAYS_INLINE void typed_setter_impl(const FROM &value, const char *msg) {
564  value_ = value;
565  }
566 };
567 
568 // Stubs for type-specific implementations of GeneratorParam, to avoid
569 // many complex enable_if<> statements that were formerly spread through the
570 // implementation. Note that not all of these need to be templated classes,
571 // (e.g. for GeneratorParam_Target, T == Target always), but are declared
572 // that way for symmetry of declaration.
573 template<typename T>
575 public:
576  GeneratorParam_Target(const std::string &name, const T &value)
577  : GeneratorParamImpl<T>(name, value) {
578  }
579 
580  void set_from_string(const std::string &new_value_string) override {
581  this->set(Target(new_value_string));
582  }
583 
584  std::string get_default_value() const override {
585  return this->value().to_string();
586  }
587 
588  std::string call_to_string(const std::string &v) const override {
589  std::ostringstream oss;
590  oss << v << ".to_string()";
591  return oss.str();
592  }
593 
594  std::string get_c_type() const override {
595  return "Target";
596  }
597 };
598 
599 template<typename T>
601 public:
602  GeneratorParam_MachineParams(const std::string &name, const T &value)
603  : GeneratorParamImpl<T>(name, value) {
604  }
605 
606  void set_from_string(const std::string &new_value_string) override {
607  this->set(MachineParams(new_value_string));
608  }
609 
610  std::string get_default_value() const override {
611  return this->value().to_string();
612  }
613 
614  std::string call_to_string(const std::string &v) const override {
615  std::ostringstream oss;
616  oss << v << ".to_string()";
617  return oss.str();
618  }
619 
620  std::string get_c_type() const override {
621  return "MachineParams";
622  }
623 };
624 
625 class GeneratorParam_LoopLevel : public GeneratorParamImpl<LoopLevel> {
626 public:
627  GeneratorParam_LoopLevel(const std::string &name, const LoopLevel &value)
629  }
630 
632 
633  void set(const LoopLevel &value) override {
634  // Don't call check_value_writable(): It's OK to set a LoopLevel after generate().
635  // check_value_writable();
636 
637  // This looks odd, but is deliberate:
638 
639  // First, mutate the existing contents to match the value passed in,
640  // so that any existing usage of the LoopLevel now uses the newer value.
641  // (Strictly speaking, this is really only necessary if this method
642  // is called after generate(): before generate(), there is no usage
643  // to be concerned with.)
644  value_.set(value);
645 
646  // Then, reset the value itself so that it points to the same LoopLevelContents
647  // as the value passed in. (Strictly speaking, this is really only
648  // useful if this method is called before generate(): afterwards, it's
649  // too late to alter the code to refer to a different LoopLevelContents.)
650  value_ = value;
651  }
652 
653  void set_from_string(const std::string &new_value_string) override {
654  if (new_value_string == "root") {
655  this->set(LoopLevel::root());
656  } else if (new_value_string == "inlined") {
657  this->set(LoopLevel::inlined());
658  } else {
659  user_error << "Unable to parse " << this->name() << ": " << new_value_string;
660  }
661  }
662 
663  std::string get_default_value() const override {
664  // This is dodgy but safe in this case: we want to
665  // see what the value of our LoopLevel is *right now*,
666  // so we make a copy and lock the copy so we can inspect it.
667  // (Note that ordinarily this is a bad idea, since LoopLevels
668  // can be mutated later on; however, this method is only
669  // called by the Generator infrastructure, on LoopLevels that
670  // will never be mutated, so this is really just an elaborate way
671  // to avoid runtime assertions.)
672  LoopLevel copy;
673  copy.set(this->value());
674  copy.lock();
675  if (copy.is_inlined()) {
676  return "LoopLevel::inlined()";
677  } else if (copy.is_root()) {
678  return "LoopLevel::root()";
679  } else {
681  return "";
682  }
683  }
684 
685  std::string call_to_string(const std::string &v) const override {
687  return std::string();
688  }
689 
690  std::string get_c_type() const override {
691  return "LoopLevel";
692  }
693 
694  bool is_looplevel_param() const override {
695  return true;
696  }
697 };
698 
699 template<typename T>
701 public:
702  GeneratorParam_Arithmetic(const std::string &name,
703  const T &value,
704  const T &min = std::numeric_limits<T>::lowest(),
705  const T &max = std::numeric_limits<T>::max())
706  : GeneratorParamImpl<T>(name, value), min(min), max(max) {
707  // call set() to ensure value is clamped to min/max
708  this->set(value);
709  }
710 
711  void set_impl(const T &new_value) override {
712  user_assert(new_value >= min && new_value <= max) << "Value out of range: " << new_value;
714  }
715 
716  void set_from_string(const std::string &new_value_string) override {
717  std::istringstream iss(new_value_string);
718  T t;
719  // All one-byte ints int8 and uint8 should be parsed as integers, not chars --
720  // including 'char' itself. (Note that sizeof(bool) is often-but-not-always-1,
721  // so be sure to exclude that case.)
722  if (sizeof(T) == sizeof(char) && !std::is_same<T, bool>::value) {
723  int i;
724  iss >> i;
725  t = (T)i;
726  } else {
727  iss >> t;
728  }
729  user_assert(!iss.fail() && iss.get() == EOF) << "Unable to parse: " << new_value_string;
730  this->set(t);
731  }
732 
733  std::string get_default_value() const override {
734  std::ostringstream oss;
735  oss << this->value();
736  if (std::is_same<T, float>::value) {
737  // If the constant has no decimal point ("1")
738  // we must append one before appending "f"
739  if (oss.str().find('.') == std::string::npos) {
740  oss << ".";
741  }
742  oss << "f";
743  }
744  return oss.str();
745  }
746 
747  std::string call_to_string(const std::string &v) const override {
748  std::ostringstream oss;
749  oss << "std::to_string(" << v << ")";
750  return oss.str();
751  }
752 
753  std::string get_c_type() const override {
754  std::ostringstream oss;
755  if (std::is_same<T, float>::value) {
756  return "float";
757  } else if (std::is_same<T, double>::value) {
758  return "double";
759  } else if (std::is_integral<T>::value) {
760  if (std::is_unsigned<T>::value) {
761  oss << "u";
762  }
763  oss << "int" << (sizeof(T) * 8) << "_t";
764  return oss.str();
765  } else {
766  user_error << "Unknown arithmetic type\n";
767  return "";
768  }
769  }
770 
771 private:
772  const T min, max;
773 };
774 
775 template<typename T>
777 public:
778  GeneratorParam_Bool(const std::string &name, const T &value)
780  }
781 
782  void set_from_string(const std::string &new_value_string) override {
783  bool v = false;
784  if (new_value_string == "true" || new_value_string == "True") {
785  v = true;
786  } else if (new_value_string == "false" || new_value_string == "False") {
787  v = false;
788  } else {
789  user_assert(false) << "Unable to parse bool: " << new_value_string;
790  }
791  this->set(v);
792  }
793 
794  std::string get_default_value() const override {
795  return this->value() ? "true" : "false";
796  }
797 
798  std::string call_to_string(const std::string &v) const override {
799  std::ostringstream oss;
800  oss << "std::string((" << v << ") ? \"true\" : \"false\")";
801  return oss.str();
802  }
803 
804  std::string get_c_type() const override {
805  return "bool";
806  }
807 };
808 
809 template<typename T>
811 public:
812  GeneratorParam_Enum(const std::string &name, const T &value, const std::map<std::string, T> &enum_map)
813  : GeneratorParamImpl<T>(name, value), enum_map(enum_map) {
814  }
815 
816  // define a "set" that takes our specific enum (but don't hide the inherited virtual functions)
818 
819  template<typename T2 = T, typename std::enable_if<!std::is_same<T2, Type>::value>::type * = nullptr>
820  void set(const T &e) {
821  this->set_impl(e);
822  }
823 
824  void set_from_string(const std::string &new_value_string) override {
825  auto it = enum_map.find(new_value_string);
826  user_assert(it != enum_map.end()) << "Enumeration value not found: " << new_value_string;
827  this->set_impl(it->second);
828  }
829 
830  std::string call_to_string(const std::string &v) const override {
831  return "Enum_" + this->name() + "_map().at(" + v + ")";
832  }
833 
834  std::string get_c_type() const override {
835  return "Enum_" + this->name();
836  }
837 
838  std::string get_default_value() const override {
839  return "Enum_" + this->name() + "::" + enum_to_string(enum_map, this->value());
840  }
841 
842  std::string get_type_decls() const override {
843  std::ostringstream oss;
844  oss << "enum class Enum_" << this->name() << " {\n";
845  for (auto key_value : enum_map) {
846  oss << " " << key_value.first << ",\n";
847  }
848  oss << "};\n";
849  oss << "\n";
850 
851  // TODO: since we generate the enums, we could probably just use a vector (or array!) rather than a map,
852  // since we can ensure that the enum values are a nice tight range.
853  oss << "inline HALIDE_NO_USER_CODE_INLINE const std::map<Enum_" << this->name() << ", std::string>& Enum_" << this->name() << "_map() {\n";
854  oss << " static const std::map<Enum_" << this->name() << ", std::string> m = {\n";
855  for (auto key_value : enum_map) {
856  oss << " { Enum_" << this->name() << "::" << key_value.first << ", \"" << key_value.first << "\"},\n";
857  }
858  oss << " };\n";
859  oss << " return m;\n";
860  oss << "};\n";
861  return oss.str();
862  }
863 
864 private:
865  const std::map<std::string, T> enum_map;
866 };
867 
868 template<typename T>
870 public:
871  GeneratorParam_Type(const std::string &name, const T &value)
873  }
874 
875  std::string call_to_string(const std::string &v) const override {
876  return "Halide::Internal::halide_type_to_enum_string(" + v + ")";
877  }
878 
879  std::string get_c_type() const override {
880  return "Type";
881  }
882 
883  std::string get_default_value() const override {
884  return halide_type_to_c_source(this->value());
885  }
886 
887  std::string get_type_decls() const override {
888  return "";
889  }
890 };
891 
892 template<typename T>
894 public:
895  GeneratorParam_String(const std::string &name, const std::string &value)
896  : GeneratorParamImpl<T>(name, value) {
897  }
898  void set_from_string(const std::string &new_value_string) override {
899  this->set(new_value_string);
900  }
901 
902  std::string get_default_value() const override {
903  return "\"" + this->value() + "\"";
904  }
905 
906  std::string call_to_string(const std::string &v) const override {
907  return v;
908  }
909 
910  std::string get_c_type() const override {
911  return "std::string";
912  }
913 };
914 
915 template<typename T>
917  typename select_type<
926 
927 } // namespace Internal
928 
929 /** GeneratorParam is a templated class that can be used to modify the behavior
930  * of the Generator at code-generation time. GeneratorParams are commonly
931  * specified in build files (e.g. Makefile) to customize the behavior of
932  * a given Generator, thus they have a very constrained set of types to allow
933  * for efficient specification via command-line flags. A GeneratorParam can be:
934  * - any float or int type.
935  * - bool
936  * - enum
937  * - Halide::Target
938  * - Halide::Type
939  * - std::string
940  * Please don't use std::string unless there's no way to do what you want with some
941  * other type; in particular, don't use this if you can use enum instead.
942  * All GeneratorParams have a default value. Arithmetic types can also
943  * optionally specify min and max. Enum types must specify a string-to-value
944  * map.
945  *
946  * Halide::Type is treated as though it were an enum, with the mappings:
947  *
948  * "int8" Halide::Int(8)
949  * "int16" Halide::Int(16)
950  * "int32" Halide::Int(32)
951  * "uint8" Halide::UInt(8)
952  * "uint16" Halide::UInt(16)
953  * "uint32" Halide::UInt(32)
954  * "float32" Halide::Float(32)
955  * "float64" Halide::Float(64)
956  *
957  * No vector Types are currently supported by this mapping.
958  *
959  */
960 template<typename T>
962 public:
963  template<typename T2 = T, typename std::enable_if<!std::is_same<T2, std::string>::value>::type * = nullptr>
964  GeneratorParam(const std::string &name, const T &value)
965  : Internal::GeneratorParamImplBase<T>(name, value) {
966  }
967 
968  GeneratorParam(const std::string &name, const T &value, const T &min, const T &max)
969  : Internal::GeneratorParamImplBase<T>(name, value, min, max) {
970  }
971 
972  GeneratorParam(const std::string &name, const T &value, const std::map<std::string, T> &enum_map)
973  : Internal::GeneratorParamImplBase<T>(name, value, enum_map) {
974  }
975 
976  GeneratorParam(const std::string &name, const std::string &value)
977  : Internal::GeneratorParamImplBase<T>(name, value) {
978  }
979 };
980 
981 /** Addition between GeneratorParam<T> and any type that supports operator+ with T.
982  * Returns type of underlying operator+. */
983 // @{
984 template<typename Other, typename T>
985 auto operator+(const Other &a, const GeneratorParam<T> &b) -> decltype(a + (T)b) {
986  return a + (T)b;
987 }
988 template<typename Other, typename T>
989 auto operator+(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a + b) {
990  return (T)a + b;
991 }
992 // @}
993 
994 /** Subtraction between GeneratorParam<T> and any type that supports operator- with T.
995  * Returns type of underlying operator-. */
996 // @{
997 template<typename Other, typename T>
998 auto operator-(const Other &a, const GeneratorParam<T> &b) -> decltype(a - (T)b) {
999  return a - (T)b;
1000 }
1001 template<typename Other, typename T>
1002 auto operator-(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a - b) {
1003  return (T)a - b;
1004 }
1005 // @}
1006 
1007 /** Multiplication between GeneratorParam<T> and any type that supports operator* with T.
1008  * Returns type of underlying operator*. */
1009 // @{
1010 template<typename Other, typename T>
1011 auto operator*(const Other &a, const GeneratorParam<T> &b) -> decltype(a * (T)b) {
1012  return a * (T)b;
1013 }
1014 template<typename Other, typename T>
1015 auto operator*(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a * b) {
1016  return (T)a * b;
1017 }
1018 // @}
1019 
1020 /** Division between GeneratorParam<T> and any type that supports operator/ with T.
1021  * Returns type of underlying operator/. */
1022 // @{
1023 template<typename Other, typename T>
1024 auto operator/(const Other &a, const GeneratorParam<T> &b) -> decltype(a / (T)b) {
1025  return a / (T)b;
1026 }
1027 template<typename Other, typename T>
1028 auto operator/(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a / b) {
1029  return (T)a / b;
1030 }
1031 // @}
1032 
1033 /** Modulo between GeneratorParam<T> and any type that supports operator% with T.
1034  * Returns type of underlying operator%. */
1035 // @{
1036 template<typename Other, typename T>
1037 auto operator%(const Other &a, const GeneratorParam<T> &b) -> decltype(a % (T)b) {
1038  return a % (T)b;
1039 }
1040 template<typename Other, typename T>
1041 auto operator%(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a % b) {
1042  return (T)a % b;
1043 }
1044 // @}
1045 
1046 /** Greater than comparison between GeneratorParam<T> and any type that supports operator> with T.
1047  * Returns type of underlying operator>. */
1048 // @{
1049 template<typename Other, typename T>
1050 auto operator>(const Other &a, const GeneratorParam<T> &b) -> decltype(a > (T)b) {
1051  return a > (T)b;
1052 }
1053 template<typename Other, typename T>
1054 auto operator>(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a > b) {
1055  return (T)a > b;
1056 }
1057 // @}
1058 
1059 /** Less than comparison between GeneratorParam<T> and any type that supports operator< with T.
1060  * Returns type of underlying operator<. */
1061 // @{
1062 template<typename Other, typename T>
1063 auto operator<(const Other &a, const GeneratorParam<T> &b) -> decltype(a < (T)b) {
1064  return a < (T)b;
1065 }
1066 template<typename Other, typename T>
1067 auto operator<(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a < b) {
1068  return (T)a < b;
1069 }
1070 // @}
1071 
1072 /** Greater than or equal comparison between GeneratorParam<T> and any type that supports operator>= with T.
1073  * Returns type of underlying operator>=. */
1074 // @{
1075 template<typename Other, typename T>
1076 auto operator>=(const Other &a, const GeneratorParam<T> &b) -> decltype(a >= (T)b) {
1077  return a >= (T)b;
1078 }
1079 template<typename Other, typename T>
1080 auto operator>=(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a >= b) {
1081  return (T)a >= b;
1082 }
1083 // @}
1084 
1085 /** Less than or equal comparison between GeneratorParam<T> and any type that supports operator<= with T.
1086  * Returns type of underlying operator<=. */
1087 // @{
1088 template<typename Other, typename T>
1089 auto operator<=(const Other &a, const GeneratorParam<T> &b) -> decltype(a <= (T)b) {
1090  return a <= (T)b;
1091 }
1092 template<typename Other, typename T>
1093 auto operator<=(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a <= b) {
1094  return (T)a <= b;
1095 }
1096 // @}
1097 
1098 /** Equality comparison between GeneratorParam<T> and any type that supports operator== with T.
1099  * Returns type of underlying operator==. */
1100 // @{
1101 template<typename Other, typename T>
1102 auto operator==(const Other &a, const GeneratorParam<T> &b) -> decltype(a == (T)b) {
1103  return a == (T)b;
1104 }
1105 template<typename Other, typename T>
1106 auto operator==(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a == b) {
1107  return (T)a == b;
1108 }
1109 // @}
1110 
1111 /** Inequality comparison between between GeneratorParam<T> and any type that supports operator!= with T.
1112  * Returns type of underlying operator!=. */
1113 // @{
1114 template<typename Other, typename T>
1115 auto operator!=(const Other &a, const GeneratorParam<T> &b) -> decltype(a != (T)b) {
1116  return a != (T)b;
1117 }
1118 template<typename Other, typename T>
1119 auto operator!=(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a != b) {
1120  return (T)a != b;
1121 }
1122 // @}
1123 
1124 /** Logical and between between GeneratorParam<T> and any type that supports operator&& with T.
1125  * Returns type of underlying operator&&. */
1126 // @{
1127 template<typename Other, typename T>
1128 auto operator&&(const Other &a, const GeneratorParam<T> &b) -> decltype(a && (T)b) {
1129  return a && (T)b;
1130 }
1131 template<typename Other, typename T>
1132 auto operator&&(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a && b) {
1133  return (T)a && b;
1134 }
1135 template<typename T>
1136 auto operator&&(const GeneratorParam<T> &a, const GeneratorParam<T> &b) -> decltype((T)a && (T)b) {
1137  return (T)a && (T)b;
1138 }
1139 // @}
1140 
1141 /** Logical or between between GeneratorParam<T> and any type that supports operator|| with T.
1142  * Returns type of underlying operator||. */
1143 // @{
1144 template<typename Other, typename T>
1145 auto operator||(const Other &a, const GeneratorParam<T> &b) -> decltype(a || (T)b) {
1146  return a || (T)b;
1147 }
1148 template<typename Other, typename T>
1149 auto operator||(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a || b) {
1150  return (T)a || b;
1151 }
1152 template<typename T>
1153 auto operator||(const GeneratorParam<T> &a, const GeneratorParam<T> &b) -> decltype((T)a || (T)b) {
1154  return (T)a || (T)b;
1155 }
1156 // @}
1157 
1158 /* min and max are tricky as the language support for these is in the std
1159  * namespace. In order to make this work, forwarding functions are used that
1160  * are declared in a namespace that has std::min and std::max in scope.
1161  */
1162 namespace Internal {
1163 namespace GeneratorMinMax {
1164 
1165 using std::max;
1166 using std::min;
1167 
1168 template<typename Other, typename T>
1169 auto min_forward(const Other &a, const GeneratorParam<T> &b) -> decltype(min(a, (T)b)) {
1170  return min(a, (T)b);
1171 }
1172 template<typename Other, typename T>
1173 auto min_forward(const GeneratorParam<T> &a, const Other &b) -> decltype(min((T)a, b)) {
1174  return min((T)a, b);
1175 }
1176 
1177 template<typename Other, typename T>
1178 auto max_forward(const Other &a, const GeneratorParam<T> &b) -> decltype(max(a, (T)b)) {
1179  return max(a, (T)b);
1180 }
1181 template<typename Other, typename T>
1182 auto max_forward(const GeneratorParam<T> &a, const Other &b) -> decltype(max((T)a, b)) {
1183  return max((T)a, b);
1184 }
1185 
1186 } // namespace GeneratorMinMax
1187 } // namespace Internal
1188 
1189 /** Compute minimum between GeneratorParam<T> and any type that supports min with T.
1190  * Will automatically import std::min. Returns type of underlying min call. */
1191 // @{
1192 template<typename Other, typename T>
1193 auto min(const Other &a, const GeneratorParam<T> &b) -> decltype(Internal::GeneratorMinMax::min_forward(a, b)) {
1195 }
1196 template<typename Other, typename T>
1197 auto min(const GeneratorParam<T> &a, const Other &b) -> decltype(Internal::GeneratorMinMax::min_forward(a, b)) {
1199 }
1200 // @}
1201 
1202 /** Compute the maximum value between GeneratorParam<T> and any type that supports max with T.
1203  * Will automatically import std::max. Returns type of underlying max call. */
1204 // @{
1205 template<typename Other, typename T>
1206 auto max(const Other &a, const GeneratorParam<T> &b) -> decltype(Internal::GeneratorMinMax::max_forward(a, b)) {
1208 }
1209 template<typename Other, typename T>
1210 auto max(const GeneratorParam<T> &a, const Other &b) -> decltype(Internal::GeneratorMinMax::max_forward(a, b)) {
1212 }
1213 // @}
1214 
1215 /** Not operator for GeneratorParam */
1216 template<typename T>
1217 auto operator!(const GeneratorParam<T> &a) -> decltype(!(T)a) {
1218  return !(T)a;
1219 }
1220 
1221 namespace Internal {
1222 
1223 template<typename T2>
1224 class GeneratorInput_Buffer;
1225 
1226 enum class IOKind { Scalar,
1227  Function,
1228  Buffer };
1229 
1230 /**
1231  * StubInputBuffer is the placeholder that a Stub uses when it requires
1232  * a Buffer for an input (rather than merely a Func or Expr). It is constructed
1233  * to allow only two possible sorts of input:
1234  * -- Assignment of an Input<Buffer<>>, with compatible type and dimensions,
1235  * essentially allowing us to pipe a parameter from an enclosing Generator to an internal Stub.
1236  * -- Assignment of a Buffer<>, with compatible type and dimensions,
1237  * causing the Input<Buffer<>> to become a precompiled buffer in the generated code.
1238  */
1241  friend class StubInput;
1242  template<typename T2>
1244 
1245  Parameter parameter_;
1246 
1248  : parameter_(p) {
1249  // Create an empty 1-element buffer with the right runtime typing and dimensions,
1250  // which we'll use only to pass to can_convert_from() to verify this
1251  // Parameter is compatible with our constraints.
1252  Buffer<> other(p.type(), nullptr, std::vector<int>(p.dimensions(), 1));
1254  }
1255 
1256  template<typename T2, int D2>
1257  HALIDE_NO_USER_CODE_INLINE static Parameter parameter_from_buffer(const Buffer<T2, D2> &b) {
1258  internal_assert(b.defined());
1260  Parameter p(b.type(), true, b.dimensions());
1261  p.set_buffer(b);
1262  return p;
1263  }
1264 
1265 public:
1266  StubInputBuffer() = default;
1267 
1268  // *not* explicit -- this ctor should only be used when you want
1269  // to pass a literal Buffer<> for a Stub Input; this Buffer<> will be
1270  // compiled into the Generator's product, rather than becoming
1271  // a runtime Parameter.
1272  template<typename T2, int D2>
1274  : parameter_(parameter_from_buffer(b)) {
1275  }
1276 };
1277 
1279 protected:
1281  std::shared_ptr<GeneratorBase> generator;
1282 
1283  void check_scheduled(const char *m) const;
1285 
1287  explicit StubOutputBufferBase(const Func &f, const std::shared_ptr<GeneratorBase> &generator);
1288 
1289 public:
1290  Realization realize(std::vector<int32_t> sizes);
1291 
1292  template<typename... Args>
1293  Realization realize(Args &&...args) {
1294  check_scheduled("realize");
1295  return f.realize(std::forward<Args>(args)..., get_target());
1296  }
1297 
1298  template<typename Dst>
1299  void realize(Dst dst) {
1300  check_scheduled("realize");
1301  f.realize(dst, get_target());
1302  }
1303 };
1304 
1305 /**
1306  * StubOutputBuffer is the placeholder that a Stub uses when it requires
1307  * a Buffer for an output (rather than merely a Func). It is constructed
1308  * to allow only two possible sorts of things:
1309  * -- Assignment to an Output<Buffer<>>, with compatible type and dimensions,
1310  * essentially allowing us to pipe a parameter from the result of a Stub to an
1311  * enclosing Generator
1312  * -- Realization into a Buffer<>; this is useful only in JIT compilation modes
1313  * (and shouldn't be usable otherwise)
1314  *
1315  * It is deliberate that StubOutputBuffer is not (easily) convertible to Func.
1316  */
1317 template<typename T = void>
1319  template<typename T2>
1321  friend class GeneratorStub;
1322  explicit StubOutputBuffer(const Func &f, const std::shared_ptr<GeneratorBase> &generator)
1324  }
1325 
1326 public:
1327  StubOutputBuffer() = default;
1328 };
1329 
1330 // This is a union-like class that allows for convenient initialization of Stub Inputs
1331 // via initializer-list syntax; it is only used in situations where the
1332 // downstream consumer will be able to explicitly check that each value is
1333 // of the expected/required kind.
1334 class StubInput {
1335  const IOKind kind_;
1336  // Exactly one of the following fields should be defined:
1337  const Parameter parameter_;
1338  const Func func_;
1339  const Expr expr_;
1340 
1341 public:
1342  // *not* explicit.
1343  template<typename T2>
1345  : kind_(IOKind::Buffer), parameter_(b.parameter_), func_(), expr_() {
1346  }
1347  StubInput(const Func &f)
1348  : kind_(IOKind::Function), parameter_(), func_(f), expr_() {
1349  }
1350  StubInput(const Expr &e)
1351  : kind_(IOKind::Scalar), parameter_(), func_(), expr_(e) {
1352  }
1353 
1354 private:
1355  friend class GeneratorInputBase;
1356 
1357  IOKind kind() const {
1358  return kind_;
1359  }
1360 
1361  Parameter parameter() const {
1362  internal_assert(kind_ == IOKind::Buffer);
1363  return parameter_;
1364  }
1365 
1366  Func func() const {
1368  return func_;
1369  }
1370 
1371  Expr expr() const {
1372  internal_assert(kind_ == IOKind::Scalar);
1373  return expr_;
1374  }
1375 };
1376 
1377 /** GIOBase is the base class for all GeneratorInput<> and GeneratorOutput<>
1378  * instantiations; it is not part of the public API and should never be
1379  * used directly by user code.
1380  *
1381  * Every GIOBase instance can be either a single value or an array-of-values;
1382  * each of these values can be an Expr or a Func. (Note that for an
1383  * array-of-values, the types/dimensions of all values in the array must match.)
1384  *
1385  * A GIOBase can have multiple Types, in which case it represents a Tuple.
1386  * (Note that Tuples are currently only supported for GeneratorOutput, but
1387  * it is likely that GeneratorInput will be extended to support Tuple as well.)
1388  *
1389  * The array-size, type(s), and dimensions can all be left "unspecified" at
1390  * creation time, in which case they may assume values provided by a Stub.
1391  * (It is important to note that attempting to use a GIOBase with unspecified
1392  * values will assert-fail; you must ensure that all unspecified values are
1393  * filled in prior to use.)
1394  */
1395 class GIOBase {
1396 public:
1397  bool array_size_defined() const;
1398  size_t array_size() const;
1399  virtual bool is_array() const;
1400 
1401  const std::string &name() const;
1402  IOKind kind() const;
1403 
1404  bool types_defined() const;
1405  const std::vector<Type> &types() const;
1406  Type type() const;
1407 
1408  bool dims_defined() const;
1409  int dims() const;
1410 
1411  const std::vector<Func> &funcs() const;
1412  const std::vector<Expr> &exprs() const;
1413 
1414  virtual ~GIOBase() = default;
1415 
1416  void set_type(const Type &type);
1418  void set_array_size(int size);
1419 
1420 protected:
1422  const std::string &name,
1423  IOKind kind,
1424  const std::vector<Type> &types,
1425  int dims);
1426 
1427  friend class GeneratorBase;
1428  friend class GeneratorParamInfo;
1429 
1430  mutable int array_size_; // always 1 if is_array() == false.
1431  // -1 if is_array() == true but unspecified.
1432 
1433  const std::string name_;
1434  const IOKind kind_;
1435  mutable std::vector<Type> types_; // empty if type is unspecified
1436  mutable int dims_; // -1 if dim is unspecified
1437 
1438  // Exactly one of these will have nonzero length
1439  std::vector<Func> funcs_;
1440  std::vector<Expr> exprs_;
1441 
1442  // Generator which owns this Input or Output. Note that this will be null
1443  // initially; the GeneratorBase itself will set this field when it initially
1444  // builds its info about params. However, since it isn't
1445  // appropriate for Input<> or Output<> to be declared outside of a Generator,
1446  // all reasonable non-testing code should expect this to be non-null.
1448 
1449  std::string array_name(size_t i) const;
1450 
1451  virtual void verify_internals();
1452 
1453  void check_matching_array_size(size_t size) const;
1454  void check_matching_types(const std::vector<Type> &t) const;
1455  void check_matching_dims(int d) const;
1456 
1457  template<typename ElemType>
1458  const std::vector<ElemType> &get_values() const;
1459 
1460  void check_gio_access() const;
1461 
1462  virtual void check_value_writable() const = 0;
1463 
1464  virtual const char *input_or_output() const = 0;
1465 
1466 private:
1467  template<typename T>
1469 
1470 public:
1471  GIOBase(const GIOBase &) = delete;
1472  GIOBase &operator=(const GIOBase &) = delete;
1473  GIOBase(GIOBase &&) = delete;
1474  GIOBase &operator=(GIOBase &&) = delete;
1475 };
1476 
1477 template<>
1478 inline const std::vector<Expr> &GIOBase::get_values<Expr>() const {
1479  return exprs();
1480 }
1481 
1482 template<>
1483 inline const std::vector<Func> &GIOBase::get_values<Func>() const {
1484  return funcs();
1485 }
1486 
1487 class GeneratorInputBase : public GIOBase {
1488 protected:
1490  const std::string &name,
1491  IOKind kind,
1492  const std::vector<Type> &t,
1493  int d);
1494 
1495  GeneratorInputBase(const std::string &name, IOKind kind, const std::vector<Type> &t, int d);
1496 
1497  friend class GeneratorBase;
1498  friend class GeneratorParamInfo;
1499 
1500  std::vector<Parameter> parameters_;
1501 
1503 
1505  void set_inputs(const std::vector<StubInput> &inputs);
1506 
1507  virtual void set_def_min_max();
1508 
1509  void verify_internals() override;
1510 
1511  friend class StubEmitter;
1512 
1513  virtual std::string get_c_type() const = 0;
1514 
1515  void check_value_writable() const override;
1516 
1517  const char *input_or_output() const override {
1518  return "Input";
1519  }
1520 
1521  void set_estimate_impl(const Var &var, const Expr &min, const Expr &extent);
1522  void set_estimates_impl(const Region &estimates);
1523 
1524 public:
1526 };
1527 
1528 template<typename T, typename ValueType>
1530 protected:
1531  using TBase = typename std::remove_all_extents<T>::type;
1532 
1533  bool is_array() const override {
1534  return std::is_array<T>::value;
1535  }
1536 
1537  template<typename T2 = T, typename std::enable_if<
1538  // Only allow T2 not-an-array
1539  !std::is_array<T2>::value>::type * = nullptr>
1540  GeneratorInputImpl(const std::string &name, IOKind kind, const std::vector<Type> &t, int d)
1541  : GeneratorInputBase(name, kind, t, d) {
1542  }
1543 
1544  template<typename T2 = T, typename std::enable_if<
1545  // Only allow T2[kSomeConst]
1546  std::is_array<T2>::value && std::rank<T2>::value == 1 && (std::extent<T2, 0>::value > 0)>::type * = nullptr>
1547  GeneratorInputImpl(const std::string &name, IOKind kind, const std::vector<Type> &t, int d)
1548  : GeneratorInputBase(std::extent<T2, 0>::value, name, kind, t, d) {
1549  }
1550 
1551  template<typename T2 = T, typename std::enable_if<
1552  // Only allow T2[]
1553  std::is_array<T2>::value && std::rank<T2>::value == 1 && std::extent<T2, 0>::value == 0>::type * = nullptr>
1554  GeneratorInputImpl(const std::string &name, IOKind kind, const std::vector<Type> &t, int d)
1555  : GeneratorInputBase(-1, name, kind, t, d) {
1556  }
1557 
1558 public:
1559  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1560  size_t size() const {
1561  this->check_gio_access();
1562  return get_values<ValueType>().size();
1563  }
1564 
1565  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1566  const ValueType &operator[](size_t i) const {
1567  this->check_gio_access();
1568  return get_values<ValueType>()[i];
1569  }
1570 
1571  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1572  const ValueType &at(size_t i) const {
1573  this->check_gio_access();
1574  return get_values<ValueType>().at(i);
1575  }
1576 
1577  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1578  typename std::vector<ValueType>::const_iterator begin() const {
1579  this->check_gio_access();
1580  return get_values<ValueType>().begin();
1581  }
1582 
1583  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1584  typename std::vector<ValueType>::const_iterator end() const {
1585  this->check_gio_access();
1586  return get_values<ValueType>().end();
1587  }
1588 };
1589 
1590 // When forwarding methods to ImageParam, Func, etc., we must take
1591 // care with the return types: many of the methods return a reference-to-self
1592 // (e.g., ImageParam&); since we create temporaries for most of these forwards,
1593 // returning a ref will crater because it refers to a now-defunct section of the
1594 // stack. Happily, simply removing the reference is solves this, since all of the
1595 // types in question satisfy the property of copies referring to the same underlying
1596 // structure (returning references is just an optimization). Since this is verbose
1597 // and used in several places, we'll use a helper macro:
1598 #define HALIDE_FORWARD_METHOD(Class, Method) \
1599  template<typename... Args> \
1600  inline auto Method(Args &&...args)->typename std::remove_reference<decltype(std::declval<Class>().Method(std::forward<Args>(args)...))>::type { \
1601  return this->template as<Class>().Method(std::forward<Args>(args)...); \
1602  }
1603 
1604 #define HALIDE_FORWARD_METHOD_CONST(Class, Method) \
1605  template<typename... Args> \
1606  inline auto Method(Args &&...args) const-> \
1607  typename std::remove_reference<decltype(std::declval<Class>().Method(std::forward<Args>(args)...))>::type { \
1608  this->check_gio_access(); \
1609  return this->template as<Class>().Method(std::forward<Args>(args)...); \
1610  }
1611 
1612 template<typename T>
1614 private:
1616 
1617 protected:
1618  using TBase = typename Super::TBase;
1619 
1620  friend class ::Halide::Func;
1621  friend class ::Halide::Stage;
1622 
1623  std::string get_c_type() const override {
1624  if (TBase::has_static_halide_type) {
1625  return "Halide::Internal::StubInputBuffer<" +
1626  halide_type_to_c_type(TBase::static_halide_type()) +
1627  ">";
1628  } else {
1629  return "Halide::Internal::StubInputBuffer<>";
1630  }
1631  }
1632 
1633  template<typename T2>
1634  inline T2 as() const {
1635  return (T2) * this;
1636  }
1637 
1638 public:
1639  explicit GeneratorInput_Buffer(const std::string &name)
1640  : Super(name, IOKind::Buffer,
1641  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
1642  TBase::has_static_dimensions ? TBase::static_dimensions() : -1) {
1643  }
1644 
1645  GeneratorInput_Buffer(const std::string &name, const Type &t, int d)
1646  : Super(name, IOKind::Buffer, {t}, d) {
1647  static_assert(!TBase::has_static_halide_type, "You can only specify a Type argument for Input<Buffer<T>> if T is void or omitted.");
1648  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Input<Buffer<T, D>> if D is -1 or omitted.");
1649  }
1650 
1651  GeneratorInput_Buffer(const std::string &name, const Type &t)
1652  : Super(name, IOKind::Buffer, {t}, -1) {
1653  static_assert(!TBase::has_static_halide_type, "You can only specify a Type argument for Input<Buffer<T>> if T is void or omitted.");
1654  }
1655 
1656  GeneratorInput_Buffer(const std::string &name, int d)
1657  : Super(name, IOKind::Buffer,
1658  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
1659  d) {
1660  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Input<Buffer<T, D>> if D is -1 or omitted.");
1661  }
1662 
1663  template<typename... Args>
1664  Expr operator()(Args &&...args) const {
1665  this->check_gio_access();
1666  return Func(*this)(std::forward<Args>(args)...);
1667  }
1668 
1669  Expr operator()(std::vector<Expr> args) const {
1670  this->check_gio_access();
1671  return Func(*this)(std::move(args));
1672  }
1673 
1674  template<typename T2>
1675  operator StubInputBuffer<T2>() const {
1676  user_assert(!this->is_array()) << "Cannot assign an array type to a non-array type for Input " << this->name();
1677  return StubInputBuffer<T2>(this->parameters_.at(0));
1678  }
1679 
1680  operator Func() const {
1681  this->check_gio_access();
1682  return this->funcs().at(0);
1683  }
1684 
1685  operator ExternFuncArgument() const {
1686  this->check_gio_access();
1687  return ExternFuncArgument(this->parameters_.at(0));
1688  }
1689 
1691  this->check_gio_access();
1692  this->set_estimate_impl(var, min, extent);
1693  return *this;
1694  }
1695 
1697  this->check_gio_access();
1698  this->set_estimates_impl(estimates);
1699  return *this;
1700  }
1701 
1702  Func in() {
1703  this->check_gio_access();
1704  return Func(*this).in();
1705  }
1706 
1707  Func in(const Func &other) {
1708  this->check_gio_access();
1709  return Func(*this).in(other);
1710  }
1711 
1712  Func in(const std::vector<Func> &others) {
1713  this->check_gio_access();
1714  return Func(*this).in(others);
1715  }
1716 
1717  operator ImageParam() const {
1718  this->check_gio_access();
1719  user_assert(!this->is_array()) << "Cannot convert an Input<Buffer<>[]> to an ImageParam; use an explicit subscript operator: " << this->name();
1720  return ImageParam(this->parameters_.at(0), Func(*this));
1721  }
1722 
1723  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1724  size_t size() const {
1725  this->check_gio_access();
1726  return this->parameters_.size();
1727  }
1728 
1729  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1730  ImageParam operator[](size_t i) const {
1731  this->check_gio_access();
1732  return ImageParam(this->parameters_.at(i), this->funcs().at(i));
1733  }
1734 
1735  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1736  ImageParam at(size_t i) const {
1737  this->check_gio_access();
1738  return ImageParam(this->parameters_.at(i), this->funcs().at(i));
1739  }
1740 
1741  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1742  typename std::vector<ImageParam>::const_iterator begin() const {
1743  user_error << "Input<Buffer<>>::begin() is not supported.";
1744  return {};
1745  }
1746 
1747  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1748  typename std::vector<ImageParam>::const_iterator end() const {
1749  user_error << "Input<Buffer<>>::end() is not supported.";
1750  return {};
1751  }
1752 
1753  /** Forward methods to the ImageParam. */
1754  // @{
1757  HALIDE_FORWARD_METHOD_CONST(ImageParam, host_alignment)
1758  HALIDE_FORWARD_METHOD(ImageParam, set_host_alignment)
1769  HALIDE_FORWARD_METHOD_CONST(ImageParam, add_trace_tag)
1770  // }@
1771 };
1772 
1773 template<typename T>
1774 class GeneratorInput_Func : public GeneratorInputImpl<T, Func> {
1775 private:
1777 
1778 protected:
1779  using TBase = typename Super::TBase;
1780 
1781  std::string get_c_type() const override {
1782  return "Func";
1783  }
1784 
1785  template<typename T2>
1786  inline T2 as() const {
1787  return (T2) * this;
1788  }
1789 
1790 public:
1791  GeneratorInput_Func(const std::string &name, const Type &t, int d)
1792  : Super(name, IOKind::Function, {t}, d) {
1793  }
1794 
1795  // unspecified type
1796  GeneratorInput_Func(const std::string &name, int d)
1797  : Super(name, IOKind::Function, {}, d) {
1798  }
1799 
1800  // unspecified dimension
1801  GeneratorInput_Func(const std::string &name, const Type &t)
1802  : Super(name, IOKind::Function, {t}, -1) {
1803  }
1804 
1805  // unspecified type & dimension
1806  explicit GeneratorInput_Func(const std::string &name)
1807  : Super(name, IOKind::Function, {}, -1) {
1808  }
1809 
1810  GeneratorInput_Func(size_t array_size, const std::string &name, const Type &t, int d)
1811  : Super(array_size, name, IOKind::Function, {t}, d) {
1812  }
1813 
1814  // unspecified type
1815  GeneratorInput_Func(size_t array_size, const std::string &name, int d)
1816  : Super(array_size, name, IOKind::Function, {}, d) {
1817  }
1818 
1819  // unspecified dimension
1820  GeneratorInput_Func(size_t array_size, const std::string &name, const Type &t)
1821  : Super(array_size, name, IOKind::Function, {t}, -1) {
1822  }
1823 
1824  // unspecified type & dimension
1825  GeneratorInput_Func(size_t array_size, const std::string &name)
1826  : Super(array_size, name, IOKind::Function, {}, -1) {
1827  }
1828 
1829  template<typename... Args>
1830  Expr operator()(Args &&...args) const {
1831  this->check_gio_access();
1832  return this->funcs().at(0)(std::forward<Args>(args)...);
1833  }
1834 
1835  Expr operator()(const std::vector<Expr> &args) const {
1836  this->check_gio_access();
1837  return this->funcs().at(0)(args);
1838  }
1839 
1840  operator Func() const {
1841  this->check_gio_access();
1842  return this->funcs().at(0);
1843  }
1844 
1845  operator ExternFuncArgument() const {
1846  this->check_gio_access();
1847  return ExternFuncArgument(this->parameters_.at(0));
1848  }
1849 
1851  this->check_gio_access();
1852  this->set_estimate_impl(var, min, extent);
1853  return *this;
1854  }
1855 
1857  this->check_gio_access();
1858  this->set_estimates_impl(estimates);
1859  return *this;
1860  }
1861 
1862  Func in() {
1863  this->check_gio_access();
1864  return Func(*this).in();
1865  }
1866 
1867  Func in(const Func &other) {
1868  this->check_gio_access();
1869  return Func(*this).in(other);
1870  }
1871 
1872  Func in(const std::vector<Func> &others) {
1873  this->check_gio_access();
1874  return Func(*this).in(others);
1875  }
1876 
1877  /** Forward const methods to the underlying Func. (Non-const methods
1878  * aren't available for Input<Func>.) */
1879  // @{
1882  HALIDE_FORWARD_METHOD_CONST(Func, has_update_definition)
1883  HALIDE_FORWARD_METHOD_CONST(Func, num_update_definitions)
1884  HALIDE_FORWARD_METHOD_CONST(Func, output_types)
1887  HALIDE_FORWARD_METHOD_CONST(Func, update_args)
1888  HALIDE_FORWARD_METHOD_CONST(Func, update_value)
1889  HALIDE_FORWARD_METHOD_CONST(Func, update_values)
1892  // }@
1893 };
1894 
1895 template<typename T>
1897 private:
1899 
1900  static_assert(std::is_same<typename std::remove_all_extents<T>::type, Expr>::value, "GeneratorInput_DynamicScalar is only legal to use with T=Expr for now");
1901 
1902 protected:
1903  std::string get_c_type() const override {
1904  return "Expr";
1905  }
1906 
1907 public:
1908  explicit GeneratorInput_DynamicScalar(const std::string &name)
1909  : Super(name, IOKind::Scalar, {}, 0) {
1910  user_assert(!std::is_array<T>::value) << "Input<Expr[]> is not allowed";
1911  }
1912 
1913  /** You can use this Input as an expression in a halide
1914  * function definition */
1915  operator Expr() const {
1916  this->check_gio_access();
1917  return this->exprs().at(0);
1918  }
1919 
1920  /** Using an Input as the argument to an external stage treats it
1921  * as an Expr */
1922  operator ExternFuncArgument() const {
1923  this->check_gio_access();
1924  return ExternFuncArgument(this->exprs().at(0));
1925  }
1926 
1927  void set_estimate(const Expr &value) {
1928  this->check_gio_access();
1929  for (Parameter &p : this->parameters_) {
1930  p.set_estimate(value);
1931  }
1932  }
1933 };
1934 
1935 template<typename T>
1937 private:
1939 
1940 protected:
1941  using TBase = typename Super::TBase;
1942 
1943  const TBase def_{TBase()};
1945 
1946  void set_def_min_max() override {
1947  for (Parameter &p : this->parameters_) {
1948  p.set_scalar<TBase>(def_);
1950  }
1951  }
1952 
1953  std::string get_c_type() const override {
1954  return "Expr";
1955  }
1956 
1957  // Expr() doesn't accept a pointer type in its ctor; add a SFINAE adapter
1958  // so that pointer (aka handle) Inputs will get cast to uint64.
1959  template<typename TBase2 = TBase, typename std::enable_if<!std::is_pointer<TBase2>::value>::type * = nullptr>
1960  static Expr TBaseToExpr(const TBase2 &value) {
1961  return cast<TBase>(Expr(value));
1962  }
1963 
1964  template<typename TBase2 = TBase, typename std::enable_if<std::is_pointer<TBase2>::value>::type * = nullptr>
1965  static Expr TBaseToExpr(const TBase2 &value) {
1966  user_assert(value == 0) << "Zero is the only legal default value for Inputs which are pointer types.\n";
1967  return Expr();
1968  }
1969 
1970 public:
1971  explicit GeneratorInput_Scalar(const std::string &name)
1972  : Super(name, IOKind::Scalar, {type_of<TBase>()}, 0), def_(static_cast<TBase>(0)), def_expr_(Expr()) {
1973  }
1974 
1975  GeneratorInput_Scalar(const std::string &name, const TBase &def)
1976  : Super(name, IOKind::Scalar, {type_of<TBase>()}, 0), def_(def), def_expr_(TBaseToExpr(def)) {
1977  }
1978 
1980  const std::string &name)
1981  : Super(array_size, name, IOKind::Scalar, {type_of<TBase>()}, 0), def_(static_cast<TBase>(0)), def_expr_(Expr()) {
1982  }
1983 
1985  const std::string &name,
1986  const TBase &def)
1987  : Super(array_size, name, IOKind::Scalar, {type_of<TBase>()}, 0), def_(def), def_expr_(TBaseToExpr(def)) {
1988  }
1989 
1990  /** You can use this Input as an expression in a halide
1991  * function definition */
1992  operator Expr() const {
1993  this->check_gio_access();
1994  return this->exprs().at(0);
1995  }
1996 
1997  /** Using an Input as the argument to an external stage treats it
1998  * as an Expr */
1999  operator ExternFuncArgument() const {
2000  this->check_gio_access();
2001  return ExternFuncArgument(this->exprs().at(0));
2002  }
2003 
2004  template<typename T2 = T, typename std::enable_if<std::is_pointer<T2>::value>::type * = nullptr>
2005  void set_estimate(const TBase &value) {
2006  this->check_gio_access();
2007  user_assert(value == nullptr) << "nullptr is the only valid estimate for Input<PointerType>";
2008  Expr e = reinterpret(type_of<T2>(), cast<uint64_t>(0));
2009  for (Parameter &p : this->parameters_) {
2010  p.set_estimate(e);
2011  }
2012  }
2013 
2014  template<typename T2 = T, typename std::enable_if<!std::is_array<T2>::value && !std::is_pointer<T2>::value>::type * = nullptr>
2015  void set_estimate(const TBase &value) {
2016  this->check_gio_access();
2017  Expr e = Expr(value);
2018  if (std::is_same<T2, bool>::value) {
2019  e = cast<bool>(e);
2020  }
2021  for (Parameter &p : this->parameters_) {
2022  p.set_estimate(e);
2023  }
2024  }
2025 
2026  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2027  void set_estimate(size_t index, const TBase &value) {
2028  this->check_gio_access();
2029  Expr e = Expr(value);
2030  if (std::is_same<T2, bool>::value) {
2031  e = cast<bool>(e);
2032  }
2033  this->parameters_.at(index).set_estimate(e);
2034  }
2035 };
2036 
2037 template<typename T>
2039 private:
2041 
2042 protected:
2043  using TBase = typename Super::TBase;
2044 
2045  const Expr min_, max_;
2046 
2047  void set_def_min_max() override {
2049  // Don't set min/max for bool
2050  if (!std::is_same<TBase, bool>::value) {
2051  for (Parameter &p : this->parameters_) {
2052  if (min_.defined()) {
2053  p.set_min_value(min_);
2054  }
2055  if (max_.defined()) {
2056  p.set_max_value(max_);
2057  }
2058  }
2059  }
2060  }
2061 
2062 public:
2063  explicit GeneratorInput_Arithmetic(const std::string &name)
2064  : Super(name), min_(Expr()), max_(Expr()) {
2065  }
2066 
2067  GeneratorInput_Arithmetic(const std::string &name,
2068  const TBase &def)
2069  : Super(name, def), min_(Expr()), max_(Expr()) {
2070  }
2071 
2073  const std::string &name)
2074  : Super(array_size, name), min_(Expr()), max_(Expr()) {
2075  }
2076 
2078  const std::string &name,
2079  const TBase &def)
2080  : Super(array_size, name, def), min_(Expr()), max_(Expr()) {
2081  }
2082 
2083  GeneratorInput_Arithmetic(const std::string &name,
2084  const TBase &def,
2085  const TBase &min,
2086  const TBase &max)
2087  : Super(name, def), min_(min), max_(max) {
2088  }
2089 
2091  const std::string &name,
2092  const TBase &def,
2093  const TBase &min,
2094  const TBase &max)
2095  : Super(array_size, name, def), min_(min), max_(max) {
2096  }
2097 };
2098 
2099 template<typename>
2100 struct type_sink { typedef void type; };
2101 
2102 template<typename T2, typename = void>
2103 struct has_static_halide_type_method : std::false_type {};
2104 
2105 template<typename T2>
2106 struct has_static_halide_type_method<T2, typename type_sink<decltype(T2::static_halide_type())>::type> : std::true_type {};
2107 
2108 template<typename T, typename TBase = typename std::remove_all_extents<T>::type>
2110  typename select_type<
2116 
2117 } // namespace Internal
2118 
2119 template<typename T>
2121 private:
2123 
2124 protected:
2125  using TBase = typename Super::TBase;
2126 
2127  // Trick to avoid ambiguous ctor between Func-with-dim and int-with-default-value;
2128  // since we can't use std::enable_if on ctors, define the argument to be one that
2129  // can only be properly resolved for TBase=Func.
2130  struct Unused;
2132  typename Internal::select_type<
2136 
2137 public:
2138  // Mark all of these explicit (not just single-arg versions) so that
2139  // we disallow copy-list-initialization form (i.e., Input foo{"foo"} is ok,
2140  // but Input foo = {"foo"} is not).
2141  explicit GeneratorInput(const std::string &name)
2142  : Super(name) {
2143  }
2144 
2145  explicit GeneratorInput(const std::string &name, const TBase &def)
2146  : Super(name, def) {
2147  }
2148 
2149  explicit GeneratorInput(size_t array_size, const std::string &name, const TBase &def)
2150  : Super(array_size, name, def) {
2151  }
2152 
2153  explicit GeneratorInput(const std::string &name,
2154  const TBase &def, const TBase &min, const TBase &max)
2155  : Super(name, def, min, max) {
2156  }
2157 
2158  explicit GeneratorInput(size_t array_size, const std::string &name,
2159  const TBase &def, const TBase &min, const TBase &max)
2160  : Super(array_size, name, def, min, max) {
2161  }
2162 
2163  explicit GeneratorInput(const std::string &name, const Type &t, int d)
2164  : Super(name, t, d) {
2165  }
2166 
2167  explicit GeneratorInput(const std::string &name, const Type &t)
2168  : Super(name, t) {
2169  }
2170 
2171  // Avoid ambiguity between Func-with-dim and int-with-default
2172  explicit GeneratorInput(const std::string &name, IntIfNonScalar d)
2173  : Super(name, d) {
2174  }
2175 
2176  explicit GeneratorInput(size_t array_size, const std::string &name, const Type &t, int d)
2177  : Super(array_size, name, t, d) {
2178  }
2179 
2180  explicit GeneratorInput(size_t array_size, const std::string &name, const Type &t)
2181  : Super(array_size, name, t) {
2182  }
2183 
2184  // Avoid ambiguity between Func-with-dim and int-with-default
2185  // template <typename T2 = T, typename std::enable_if<std::is_same<TBase, Func>::value>::type * = nullptr>
2186  explicit GeneratorInput(size_t array_size, const std::string &name, IntIfNonScalar d)
2187  : Super(array_size, name, d) {
2188  }
2189 
2190  explicit GeneratorInput(size_t array_size, const std::string &name)
2191  : Super(array_size, name) {
2192  }
2193 };
2194 
2195 namespace Internal {
2196 
2198 protected:
2199  template<typename T2, typename std::enable_if<std::is_same<T2, Func>::value>::type * = nullptr>
2201  static_assert(std::is_same<T2, Func>::value, "Only Func allowed here");
2203  internal_assert(exprs_.empty());
2204  user_assert(funcs_.size() == 1) << "Use [] to access individual Funcs in Output<Func[]>";
2205  return funcs_[0];
2206  }
2207 
2208 public:
2209  /** Forward schedule-related methods to the underlying Func. */
2210  // @{
2211  HALIDE_FORWARD_METHOD(Func, add_trace_tag)
2212  HALIDE_FORWARD_METHOD(Func, align_bounds)
2213  HALIDE_FORWARD_METHOD(Func, align_extent)
2214  HALIDE_FORWARD_METHOD(Func, align_storage)
2216  HALIDE_FORWARD_METHOD(Func, bound)
2217  HALIDE_FORWARD_METHOD(Func, bound_extent)
2218  HALIDE_FORWARD_METHOD(Func, compute_at)
2219  HALIDE_FORWARD_METHOD(Func, compute_inline)
2220  HALIDE_FORWARD_METHOD(Func, compute_root)
2221  HALIDE_FORWARD_METHOD(Func, compute_with)
2222  HALIDE_FORWARD_METHOD(Func, copy_to_device)
2223  HALIDE_FORWARD_METHOD(Func, copy_to_host)
2224  HALIDE_FORWARD_METHOD(Func, define_extern)
2226  HALIDE_FORWARD_METHOD(Func, fold_storage)
2229  HALIDE_FORWARD_METHOD(Func, gpu_blocks)
2230  HALIDE_FORWARD_METHOD(Func, gpu_single_thread)
2231  HALIDE_FORWARD_METHOD(Func, gpu_threads)
2232  HALIDE_FORWARD_METHOD(Func, gpu_tile)
2233  HALIDE_FORWARD_METHOD_CONST(Func, has_update_definition)
2234  HALIDE_FORWARD_METHOD(Func, hexagon)
2236  HALIDE_FORWARD_METHOD(Func, memoize)
2237  HALIDE_FORWARD_METHOD_CONST(Func, num_update_definitions)
2238  HALIDE_FORWARD_METHOD_CONST(Func, output_types)
2240  HALIDE_FORWARD_METHOD(Func, parallel)
2241  HALIDE_FORWARD_METHOD(Func, prefetch)
2243  HALIDE_FORWARD_METHOD(Func, rename)
2244  HALIDE_FORWARD_METHOD(Func, reorder)
2245  HALIDE_FORWARD_METHOD(Func, reorder_storage)
2247  HALIDE_FORWARD_METHOD(Func, serial)
2248  HALIDE_FORWARD_METHOD(Func, set_estimate)
2249  HALIDE_FORWARD_METHOD(Func, specialize)
2250  HALIDE_FORWARD_METHOD(Func, specialize_fail)
2251  HALIDE_FORWARD_METHOD(Func, split)
2252  HALIDE_FORWARD_METHOD(Func, store_at)
2253  HALIDE_FORWARD_METHOD(Func, store_root)
2255  HALIDE_FORWARD_METHOD(Func, trace_stores)
2256  HALIDE_FORWARD_METHOD(Func, unroll)
2257  HALIDE_FORWARD_METHOD(Func, update)
2258  HALIDE_FORWARD_METHOD_CONST(Func, update_args)
2259  HALIDE_FORWARD_METHOD_CONST(Func, update_value)
2260  HALIDE_FORWARD_METHOD_CONST(Func, update_values)
2263  HALIDE_FORWARD_METHOD(Func, vectorize)
2264  // }@
2265 
2266 #undef HALIDE_OUTPUT_FORWARD
2267 #undef HALIDE_OUTPUT_FORWARD_CONST
2268 
2269 protected:
2271  const std::string &name,
2272  IOKind kind,
2273  const std::vector<Type> &t,
2274  int d);
2275 
2276  GeneratorOutputBase(const std::string &name,
2277  IOKind kind,
2278  const std::vector<Type> &t,
2279  int d);
2280 
2281  friend class GeneratorBase;
2282  friend class StubEmitter;
2283 
2285  void resize(size_t size);
2286 
2287  virtual std::string get_c_type() const {
2288  return "Func";
2289  }
2290 
2291  void check_value_writable() const override;
2292 
2293  const char *input_or_output() const override {
2294  return "Output";
2295  }
2296 
2297 public:
2299 };
2300 
2301 template<typename T>
2303 protected:
2304  using TBase = typename std::remove_all_extents<T>::type;
2305  using ValueType = Func;
2306 
2307  bool is_array() const override {
2308  return std::is_array<T>::value;
2309  }
2310 
2311  template<typename T2 = T, typename std::enable_if<
2312  // Only allow T2 not-an-array
2313  !std::is_array<T2>::value>::type * = nullptr>
2314  GeneratorOutputImpl(const std::string &name, IOKind kind, const std::vector<Type> &t, int d)
2315  : GeneratorOutputBase(name, kind, t, d) {
2316  }
2317 
2318  template<typename T2 = T, typename std::enable_if<
2319  // Only allow T2[kSomeConst]
2320  std::is_array<T2>::value && std::rank<T2>::value == 1 && (std::extent<T2, 0>::value > 0)>::type * = nullptr>
2321  GeneratorOutputImpl(const std::string &name, IOKind kind, const std::vector<Type> &t, int d)
2322  : GeneratorOutputBase(std::extent<T2, 0>::value, name, kind, t, d) {
2323  }
2324 
2325  template<typename T2 = T, typename std::enable_if<
2326  // Only allow T2[]
2327  std::is_array<T2>::value && std::rank<T2>::value == 1 && std::extent<T2, 0>::value == 0>::type * = nullptr>
2328  GeneratorOutputImpl(const std::string &name, IOKind kind, const std::vector<Type> &t, int d)
2329  : GeneratorOutputBase(-1, name, kind, t, d) {
2330  }
2331 
2332 public:
2333  template<typename... Args, typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2334  FuncRef operator()(Args &&...args) const {
2335  this->check_gio_access();
2336  return get_values<ValueType>().at(0)(std::forward<Args>(args)...);
2337  }
2338 
2339  template<typename ExprOrVar, typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2340  FuncRef operator()(std::vector<ExprOrVar> args) const {
2341  this->check_gio_access();
2342  return get_values<ValueType>().at(0)(args);
2343  }
2344 
2345  template<typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2346  operator Func() const {
2347  this->check_gio_access();
2348  return get_values<ValueType>().at(0);
2349  }
2350 
2351  template<typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2352  operator Stage() const {
2353  this->check_gio_access();
2354  return get_values<ValueType>().at(0);
2355  }
2356 
2357  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2358  size_t size() const {
2359  this->check_gio_access();
2360  return get_values<ValueType>().size();
2361  }
2362 
2363  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2364  const ValueType &operator[](size_t i) const {
2365  this->check_gio_access();
2366  return get_values<ValueType>()[i];
2367  }
2368 
2369  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2370  const ValueType &at(size_t i) const {
2371  this->check_gio_access();
2372  return get_values<ValueType>().at(i);
2373  }
2374 
2375  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2376  typename std::vector<ValueType>::const_iterator begin() const {
2377  this->check_gio_access();
2378  return get_values<ValueType>().begin();
2379  }
2380 
2381  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2382  typename std::vector<ValueType>::const_iterator end() const {
2383  this->check_gio_access();
2384  return get_values<ValueType>().end();
2385  }
2386 
2387  template<typename T2 = T, typename std::enable_if<
2388  // Only allow T2[]
2389  std::is_array<T2>::value && std::rank<T2>::value == 1 && std::extent<T2, 0>::value == 0>::type * = nullptr>
2390  void resize(size_t size) {
2391  this->check_gio_access();
2393  }
2394 };
2395 
2396 template<typename T>
2398 private:
2399  using Super = GeneratorOutputImpl<T>;
2400 
2401  HALIDE_NO_USER_CODE_INLINE void assign_from_func(const Func &f) {
2402  this->check_value_writable();
2403 
2404  internal_assert(f.defined());
2405 
2406  if (this->types_defined()) {
2407  const auto &my_types = this->types();
2408  user_assert(my_types.size() == f.output_types().size())
2409  << "Cannot assign Func \"" << f.name()
2410  << "\" to Output \"" << this->name() << "\"\n"
2411  << "Output " << this->name()
2412  << " is declared to have " << my_types.size() << " tuple elements"
2413  << " but Func " << f.name()
2414  << " has " << f.output_types().size() << " tuple elements.\n";
2415  for (size_t i = 0; i < my_types.size(); i++) {
2416  user_assert(my_types[i] == f.output_types().at(i))
2417  << "Cannot assign Func \"" << f.name()
2418  << "\" to Output \"" << this->name() << "\"\n"
2419  << (my_types.size() > 1 ? "In tuple element " + std::to_string(i) + ", " : "")
2420  << "Output " << this->name()
2421  << " has declared type " << my_types[i]
2422  << " but Func " << f.name()
2423  << " has type " << f.output_types().at(i) << "\n";
2424  }
2425  }
2426  if (this->dims_defined()) {
2427  user_assert(f.dimensions() == this->dims())
2428  << "Cannot assign Func \"" << f.name()
2429  << "\" to Output \"" << this->name() << "\"\n"
2430  << "Output " << this->name()
2431  << " has declared dimensionality " << this->dims()
2432  << " but Func " << f.name()
2433  << " has dimensionality " << f.dimensions() << "\n";
2434  }
2435 
2436  internal_assert(this->exprs_.empty() && this->funcs_.size() == 1);
2437  user_assert(!this->funcs_.at(0).defined());
2438  this->funcs_[0] = f;
2439  }
2440 
2441 protected:
2442  using TBase = typename Super::TBase;
2443 
2444  explicit GeneratorOutput_Buffer(const std::string &name)
2445  : Super(name, IOKind::Buffer,
2446  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
2447  TBase::has_static_dimensions ? TBase::static_dimensions() : -1) {
2448  }
2449 
2450  GeneratorOutput_Buffer(const std::string &name, const std::vector<Type> &t, int d)
2451  : Super(name, IOKind::Buffer, t, d) {
2452  internal_assert(!t.empty());
2453  internal_assert(d != -1);
2454  static_assert(!TBase::has_static_halide_type, "You can only specify a Type argument for Output<Buffer<T, D>> if T is void or omitted.");
2455  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Output<Buffer<T, D>> if D is -1 or omitted.");
2456  }
2457 
2458  GeneratorOutput_Buffer(const std::string &name, const std::vector<Type> &t)
2459  : Super(name, IOKind::Buffer, t, -1) {
2460  internal_assert(!t.empty());
2461  static_assert(!TBase::has_static_halide_type, "You can only specify a Type argument for Output<Buffer<T, D>> if T is void or omitted.");
2462  }
2463 
2464  GeneratorOutput_Buffer(const std::string &name, int d)
2465  : Super(name, IOKind::Buffer,
2466  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
2467  d) {
2468  internal_assert(d != -1);
2469  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Output<Buffer<T, D>> if D is -1 or omitted.");
2470  }
2471 
2472  GeneratorOutput_Buffer(size_t array_size, const std::string &name)
2474  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
2475  TBase::has_static_dimensions ? TBase::static_dimensions() : -1) {
2476  }
2477 
2478  GeneratorOutput_Buffer(size_t array_size, const std::string &name, const std::vector<Type> &t, int d)
2479  : Super(array_size, name, IOKind::Buffer, t, d) {
2480  internal_assert(!t.empty());
2481  internal_assert(d != -1);
2482  static_assert(!TBase::has_static_halide_type, "You can only specify a Type argument for Output<Buffer<T, D>> if T is void or omitted.");
2483  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Output<Buffer<T, D>> if D is -1 or omitted.");
2484  }
2485 
2486  GeneratorOutput_Buffer(size_t array_size, const std::string &name, const std::vector<Type> &t)
2487  : Super(array_size, name, IOKind::Buffer, t, -1) {
2488  internal_assert(!t.empty());
2489  static_assert(!TBase::has_static_halide_type, "You can only specify a Type argument for Output<Buffer<T, D>> if T is void or omitted.");
2490  }
2491 
2492  GeneratorOutput_Buffer(size_t array_size, const std::string &name, int d)
2494  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
2495  d) {
2496  internal_assert(d != -1);
2497  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Output<Buffer<T, D>> if D is -1 or omitted.");
2498  }
2499 
2500  HALIDE_NO_USER_CODE_INLINE std::string get_c_type() const override {
2501  if (TBase::has_static_halide_type) {
2502  return "Halide::Internal::StubOutputBuffer<" +
2503  halide_type_to_c_type(TBase::static_halide_type()) +
2504  ">";
2505  } else {
2506  return "Halide::Internal::StubOutputBuffer<>";
2507  }
2508  }
2509 
2510  template<typename T2, typename std::enable_if<!std::is_same<T2, Func>::value>::type * = nullptr>
2512  return (T2) * this;
2513  }
2514 
2515 public:
2516  // Allow assignment from a Buffer<> to an Output<Buffer<>>;
2517  // this allows us to use a statically-compiled buffer inside a Generator
2518  // to assign to an output.
2519  // TODO: This used to take the buffer as a const ref. This no longer works as
2520  // using it in a Pipeline might change the dev field so it is currently
2521  // not considered const. We should consider how this really ought to work.
2522  template<typename T2, int D2>
2524  this->check_gio_access();
2525  this->check_value_writable();
2526 
2527  user_assert(T::can_convert_from(buffer))
2528  << "Cannot assign to the Output \"" << this->name()
2529  << "\": the expression is not convertible to the same Buffer type and/or dimensions.\n";
2530 
2531  if (this->types_defined()) {
2532  user_assert(Type(buffer.type()) == this->type())
2533  << "Output " << this->name() << " should have type=" << this->type() << " but saw type=" << Type(buffer.type()) << "\n";
2534  }
2535  if (this->dims_defined()) {
2536  user_assert(buffer.dimensions() == this->dims())
2537  << "Output " << this->name() << " should have dim=" << this->dims() << " but saw dim=" << buffer.dimensions() << "\n";
2538  }
2539 
2540  internal_assert(this->exprs_.empty() && this->funcs_.size() == 1);
2541  user_assert(!this->funcs_.at(0).defined());
2542  this->funcs_.at(0)(_) = buffer(_);
2543 
2544  return *this;
2545  }
2546 
2547  // Allow assignment from a StubOutputBuffer to an Output<Buffer>;
2548  // this allows us to pipeline the results of a Stub to the results
2549  // of the enclosing Generator.
2550  template<typename T2>
2552  this->check_gio_access();
2553  assign_from_func(stub_output_buffer.f);
2554  return *this;
2555  }
2556 
2557  // Allow assignment from a Func to an Output<Buffer>;
2558  // this allows us to use helper functions that return a plain Func
2559  // to simply set the output(s) without needing a wrapper Func.
2561  this->check_gio_access();
2562  assign_from_func(f);
2563  return *this;
2564  }
2565 
2566  operator OutputImageParam() const {
2567  this->check_gio_access();
2568  user_assert(!this->is_array()) << "Cannot convert an Output<Buffer<>[]> to an ImageParam; use an explicit subscript operator: " << this->name();
2569  internal_assert(this->exprs_.empty() && this->funcs_.size() == 1);
2570  return this->funcs_.at(0).output_buffer();
2571  }
2572 
2573  // Forward set_estimates() to Func (rather than OutputImageParam) so that it can
2574  // handle Tuple-valued outputs correctly.
2576  user_assert(!this->is_array()) << "Cannot call set_estimates() on an array Output; use an explicit subscript operator: " << this->name();
2577  internal_assert(this->exprs_.empty() && this->funcs_.size() == 1);
2578  this->funcs_.at(0).set_estimates(estimates);
2579  return *this;
2580  }
2581 
2582  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2583  const Func &operator[](size_t i) const {
2584  this->check_gio_access();
2585  return this->template get_values<Func>()[i];
2586  }
2587 
2588  // Allow Output<Buffer[]>.compute_root() (or other scheduling directive that requires nonconst)
2589  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2590  Func operator[](size_t i) {
2591  this->check_gio_access();
2592  return this->template get_values<Func>()[i];
2593  }
2594 
2595  /** Forward methods to the OutputImageParam. */
2596  // @{
2600  HALIDE_FORWARD_METHOD(OutputImageParam, set_host_alignment)
2610  // }@
2611 };
2612 
2613 template<typename T>
2615 private:
2616  using Super = GeneratorOutputImpl<T>;
2617 
2618  HALIDE_NO_USER_CODE_INLINE Func &get_assignable_func_ref(size_t i) {
2619  internal_assert(this->exprs_.empty() && this->funcs_.size() > i);
2620  return this->funcs_.at(i);
2621  }
2622 
2623 protected:
2624  using TBase = typename Super::TBase;
2625 
2626  explicit GeneratorOutput_Func(const std::string &name)
2627  : Super(name, IOKind::Function, std::vector<Type>{}, -1) {
2628  }
2629 
2630  GeneratorOutput_Func(const std::string &name, const std::vector<Type> &t, int d)
2631  : Super(name, IOKind::Function, t, d) {
2632  }
2633 
2634  GeneratorOutput_Func(const std::string &name, const std::vector<Type> &t)
2635  : Super(name, IOKind::Function, t, -1) {
2636  }
2637 
2638  GeneratorOutput_Func(const std::string &name, int d)
2639  : Super(name, IOKind::Function, {}, d) {
2640  }
2641 
2642  GeneratorOutput_Func(size_t array_size, const std::string &name, const std::vector<Type> &t, int d)
2643  : Super(array_size, name, IOKind::Function, t, d) {
2644  }
2645 
2646 public:
2647  // Allow Output<Func> = Func
2648  template<typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2650  this->check_gio_access();
2651  this->check_value_writable();
2652 
2653  // Don't bother verifying the Func type, dimensions, etc., here:
2654  // That's done later, when we produce the pipeline.
2655  get_assignable_func_ref(0) = f;
2656  return *this;
2657  }
2658 
2659  // Allow Output<Func[]> = Func
2660  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2661  Func &operator[](size_t i) {
2662  this->check_gio_access();
2663  this->check_value_writable();
2664  return get_assignable_func_ref(i);
2665  }
2666 
2667  // Allow Func = Output<Func[]>
2668  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2669  const Func &operator[](size_t i) const {
2670  this->check_gio_access();
2671  return Super::operator[](i);
2672  }
2673 
2674  GeneratorOutput_Func<T> &set_estimate(const Var &var, const Expr &min, const Expr &extent) {
2675  this->check_gio_access();
2676  internal_assert(this->exprs_.empty() && !this->funcs_.empty());
2677  for (Func &f : this->funcs_) {
2678  f.set_estimate(var, min, extent);
2679  }
2680  return *this;
2681  }
2682 
2684  this->check_gio_access();
2685  internal_assert(this->exprs_.empty() && !this->funcs_.empty());
2686  for (Func &f : this->funcs_) {
2687  f.set_estimates(estimates);
2688  }
2689  return *this;
2690  }
2691 };
2692 
2693 template<typename T>
2695 private:
2696  using Super = GeneratorOutputImpl<T>;
2697 
2698 protected:
2699  using TBase = typename Super::TBase;
2700 
2701  explicit GeneratorOutput_Arithmetic(const std::string &name)
2702  : Super(name, IOKind::Function, {type_of<TBase>()}, 0) {
2703  }
2704 
2705  GeneratorOutput_Arithmetic(size_t array_size, const std::string &name)
2706  : Super(array_size, name, IOKind::Function, {type_of<TBase>()}, 0) {
2707  }
2708 };
2709 
2710 template<typename T, typename TBase = typename std::remove_all_extents<T>::type>
2712  typename select_type<
2716 
2717 } // namespace Internal
2718 
2719 template<typename T>
2721 private:
2723 
2724 protected:
2725  using TBase = typename Super::TBase;
2726 
2727 public:
2728  // Mark all of these explicit (not just single-arg versions) so that
2729  // we disallow copy-list-initialization form (i.e., Output foo{"foo"} is ok,
2730  // but Output foo = {"foo"} is not).
2731  explicit GeneratorOutput(const std::string &name)
2732  : Super(name) {
2733  }
2734 
2735  explicit GeneratorOutput(const char *name)
2736  : GeneratorOutput(std::string(name)) {
2737  }
2738 
2739  explicit GeneratorOutput(size_t array_size, const std::string &name)
2740  : Super(array_size, name) {
2741  }
2742 
2743  explicit GeneratorOutput(const std::string &name, int d)
2744  : Super(name, d) {
2745  }
2746 
2747  explicit GeneratorOutput(const std::string &name, const Type &t)
2748  : Super(name, {t}) {
2749  }
2750 
2751  explicit GeneratorOutput(const std::string &name, const std::vector<Type> &t)
2752  : Super(name, t) {
2753  }
2754 
2755  explicit GeneratorOutput(const std::string &name, const Type &t, int d)
2756  : Super(name, {t}, d) {
2757  }
2758 
2759  explicit GeneratorOutput(const std::string &name, const std::vector<Type> &t, int d)
2760  : Super(name, t, d) {
2761  }
2762 
2763  explicit GeneratorOutput(size_t array_size, const std::string &name, int d)
2764  : Super(array_size, name, d) {
2765  }
2766 
2767  explicit GeneratorOutput(size_t array_size, const std::string &name, const Type &t)
2768  : Super(array_size, name, {t}) {
2769  }
2770 
2771  explicit GeneratorOutput(size_t array_size, const std::string &name, const std::vector<Type> &t)
2772  : Super(array_size, name, t) {
2773  }
2774 
2775  explicit GeneratorOutput(size_t array_size, const std::string &name, const Type &t, int d)
2776  : Super(array_size, name, {t}, d) {
2777  }
2778 
2779  explicit GeneratorOutput(size_t array_size, const std::string &name, const std::vector<Type> &t, int d)
2780  : Super(array_size, name, t, d) {
2781  }
2782 
2783  // TODO: This used to take the buffer as a const ref. This no longer works as
2784  // using it in a Pipeline might change the dev field so it is currently
2785  // not considered const. We should consider how this really ought to work.
2786  template<typename T2, int D2>
2788  Super::operator=(buffer);
2789  return *this;
2790  }
2791 
2792  template<typename T2>
2794  Super::operator=(stub_output_buffer);
2795  return *this;
2796  }
2797 
2799  Super::operator=(f);
2800  return *this;
2801  }
2802 };
2803 
2804 namespace Internal {
2805 
2806 template<typename T>
2807 T parse_scalar(const std::string &value) {
2808  std::istringstream iss(value);
2809  T t;
2810  iss >> t;
2811  user_assert(!iss.fail() && iss.get() == EOF) << "Unable to parse: " << value;
2812  return t;
2813 }
2814 
2815 std::vector<Type> parse_halide_type_list(const std::string &types);
2816 
2818  Dim,
2819  ArraySize };
2820 
2821 // This is a type of GeneratorParam used internally to create 'synthetic' params
2822 // (e.g. image.type, image.dim); it is not possible for user code to instantiate it.
2823 template<typename T>
2825 public:
2826  void set_from_string(const std::string &new_value_string) override {
2827  // If error_msg is not empty, this is unsettable:
2828  // display error_msg as a user error.
2829  if (!error_msg.empty()) {
2830  user_error << error_msg;
2831  }
2832  set_from_string_impl<T>(new_value_string);
2833  }
2834 
2835  std::string get_default_value() const override {
2837  return std::string();
2838  }
2839 
2840  std::string call_to_string(const std::string &v) const override {
2842  return std::string();
2843  }
2844 
2845  std::string get_c_type() const override {
2847  return std::string();
2848  }
2849 
2850  bool is_synthetic_param() const override {
2851  return true;
2852  }
2853 
2854 private:
2855  friend class GeneratorParamInfo;
2856 
2857  static std::unique_ptr<Internal::GeneratorParamBase> make(
2858  GeneratorBase *generator,
2859  const std::string &generator_name,
2860  const std::string &gpname,
2861  GIOBase &gio,
2862  SyntheticParamType which,
2863  bool defined) {
2864  std::string error_msg = defined ? "Cannot set the GeneratorParam " + gpname + " for " + generator_name + " because the value is explicitly specified in the C++ source." : "";
2865  return std::unique_ptr<GeneratorParam_Synthetic<T>>(
2866  new GeneratorParam_Synthetic<T>(gpname, gio, which, error_msg));
2867  }
2868 
2869  GeneratorParam_Synthetic(const std::string &name, GIOBase &gio, SyntheticParamType which, const std::string &error_msg = "")
2870  : GeneratorParamImpl<T>(name, T()), gio(gio), which(which), error_msg(error_msg) {
2871  }
2872 
2873  template<typename T2 = T, typename std::enable_if<std::is_same<T2, ::Halide::Type>::value>::type * = nullptr>
2874  void set_from_string_impl(const std::string &new_value_string) {
2876  gio.types_ = parse_halide_type_list(new_value_string);
2877  }
2878 
2879  template<typename T2 = T, typename std::enable_if<std::is_integral<T2>::value>::type * = nullptr>
2880  void set_from_string_impl(const std::string &new_value_string) {
2881  if (which == SyntheticParamType::Dim) {
2882  gio.dims_ = parse_scalar<T2>(new_value_string);
2883  } else if (which == SyntheticParamType::ArraySize) {
2884  gio.array_size_ = parse_scalar<T2>(new_value_string);
2885  } else {
2887  }
2888  }
2889 
2890  GIOBase &gio;
2891  const SyntheticParamType which;
2892  const std::string error_msg;
2893 };
2894 
2895 class GeneratorStub;
2896 
2897 } // namespace Internal
2898 
2899 /** GeneratorContext is a class that is used when using Generators (or Stubs) directly;
2900  * it is used to allow the outer context (typically, either a Generator or "top-level" code)
2901  * to specify certain information to the inner context to ensure that inner and outer
2902  * Generators are compiled in a compatible way.
2903  *
2904  * If you are using this at "top level" (e.g. with the JIT), you can construct a GeneratorContext
2905  * with a Target:
2906  * \code
2907  * auto my_stub = MyStub(
2908  * GeneratorContext(get_target_from_environment()),
2909  * // inputs
2910  * { ... },
2911  * // generator params
2912  * { ... }
2913  * );
2914  * \endcode
2915  *
2916  * Note that all Generators embed a GeneratorContext, so if you are using a Stub
2917  * from within a Generator, you can just pass 'contex()' for the GeneratorContext:
2918  * \code
2919  * struct SomeGen : Generator<SomeGen> {
2920  * void generate() {
2921  * ...
2922  * auto my_stub = MyStub(
2923  * context(), // GeneratorContext
2924  * // inputs
2925  * { ... },
2926  * // generator params
2927  * { ... }
2928  * );
2929  * ...
2930  * }
2931  * };
2932  * \endcode
2933  */
2935 public:
2937 
2938  using ExternsMap = std::map<std::string, ExternalCode>;
2939 
2940  explicit GeneratorContext(const Target &t,
2941  bool auto_schedule = false,
2942  const MachineParams &machine_params = MachineParams::generic());
2943 
2944  GeneratorContext() = default;
2949 
2950  const Target &get_target() const {
2951  return target_;
2952  }
2953  bool get_auto_schedule() const {
2954  return auto_schedule_;
2955  }
2957  return machine_params_;
2958  }
2959 
2960  template<typename T>
2961  inline std::unique_ptr<T> create() const {
2962  return T::create(*this);
2963  }
2964  template<typename T, typename... Args>
2965  inline std::unique_ptr<T> apply(const Args &...args) const {
2966  auto t = this->create<T>();
2967  t->apply(args...);
2968  return t;
2969  }
2970 
2971 private:
2972  Target target_;
2973  bool auto_schedule_ = false;
2974  MachineParams machine_params_ = MachineParams::generic();
2975  std::shared_ptr<ExternsMap> externs_map_;
2976  std::shared_ptr<Internal::ValueTracker> value_tracker_;
2977 
2978  GeneratorContext(const Target &target,
2979  bool auto_schedule,
2980  const MachineParams &machine_params,
2981  std::shared_ptr<ExternsMap> externs_map,
2982  std::shared_ptr<Internal::ValueTracker> value_tracker);
2983 };
2984 
2986  // Names in this class are only intended for use in derived classes.
2987 protected:
2988  // Import a consistent list of Halide names that can be used in
2989  // Halide generators without qualification.
3007  using Var = Halide::Var;
3008  template<typename T>
3009  static Expr cast(Expr e) {
3010  return Halide::cast<T>(e);
3011  }
3012  static inline Expr cast(Halide::Type t, Expr e) {
3013  return Halide::cast(t, std::move(e));
3014  }
3015  template<typename T>
3017  template<typename T = void, int D = -1>
3019  template<typename T>
3021  static inline Type Bool(int lanes = 1) {
3022  return Halide::Bool(lanes);
3023  }
3024  static inline Type Float(int bits, int lanes = 1) {
3025  return Halide::Float(bits, lanes);
3026  }
3027  static inline Type Int(int bits, int lanes = 1) {
3028  return Halide::Int(bits, lanes);
3029  }
3030  static inline Type UInt(int bits, int lanes = 1) {
3031  return Halide::UInt(bits, lanes);
3032  }
3033 };
3034 
3035 namespace Internal {
3036 
3037 template<typename... Args>
3038 struct NoRealizations : std::false_type {};
3039 
3040 template<>
3041 struct NoRealizations<> : std::true_type {};
3042 
3043 template<typename T, typename... Args>
3044 struct NoRealizations<T, Args...> {
3045  static const bool value = !std::is_convertible<T, Realization>::value && NoRealizations<Args...>::value;
3046 };
3047 
3048 class GeneratorStub;
3049 
3050 // Note that these functions must never return null:
3051 // if they cannot return a valid Generator, they must assert-fail.
3052 using GeneratorFactory = std::function<std::unique_ptr<GeneratorBase>(const GeneratorContext &)>;
3053 
3055  std::string string_value;
3057 
3058  StringOrLoopLevel() = default;
3059  /*not-explicit*/ StringOrLoopLevel(const char *s)
3060  : string_value(s) {
3061  }
3062  /*not-explicit*/ StringOrLoopLevel(const std::string &s)
3063  : string_value(s) {
3064  }
3065  /*not-explicit*/ StringOrLoopLevel(const LoopLevel &loop_level)
3066  : loop_level(loop_level) {
3067  }
3068 };
3069 using GeneratorParamsMap = std::map<std::string, StringOrLoopLevel>;
3070 
3072  // names used across all params, inputs, and outputs.
3073  std::set<std::string> names;
3074 
3075  // Ordered-list of non-null ptrs to GeneratorParam<> fields.
3076  std::vector<Internal::GeneratorParamBase *> filter_generator_params;
3077 
3078  // Ordered-list of non-null ptrs to Input<> fields.
3079  std::vector<Internal::GeneratorInputBase *> filter_inputs;
3080 
3081  // Ordered-list of non-null ptrs to Output<> fields; empty if old-style Generator.
3082  std::vector<Internal::GeneratorOutputBase *> filter_outputs;
3083 
3084  // list of synthetic GP's that we dynamically created; this list only exists to simplify
3085  // lifetime management, and shouldn't be accessed directly outside of our ctor/dtor,
3086  // regardless of friend access.
3087  std::vector<std::unique_ptr<Internal::GeneratorParamBase>> owned_synthetic_params;
3088 
3089  // list of dynamically-added inputs and outputs, here only for lifetime management.
3090  std::vector<std::unique_ptr<Internal::GIOBase>> owned_extras;
3091 
3092 public:
3093  friend class GeneratorBase;
3094 
3095  GeneratorParamInfo(GeneratorBase *generator, size_t size);
3096 
3097  const std::vector<Internal::GeneratorParamBase *> &generator_params() const {
3098  return filter_generator_params;
3099  }
3100  const std::vector<Internal::GeneratorInputBase *> &inputs() const {
3101  return filter_inputs;
3102  }
3103  const std::vector<Internal::GeneratorOutputBase *> &outputs() const {
3104  return filter_outputs;
3105  }
3106 };
3107 
3109 public:
3110  virtual ~GeneratorBase();
3111 
3113 
3114  /** Given a data type, return an estimate of the "natural" vector size
3115  * for that data type when compiling for the current target. */
3117  return get_target().natural_vector_size(t);
3118  }
3119 
3120  /** Given a data type, return an estimate of the "natural" vector size
3121  * for that data type when compiling for the current target. */
3122  template<typename data_t>
3123  int natural_vector_size() const {
3124  return get_target().natural_vector_size<data_t>();
3125  }
3126 
3127  void emit_cpp_stub(const std::string &stub_file_path);
3128 
3129  // Call generate() and produce a Module for the result.
3130  // If function_name is empty, generator_name() will be used for the function.
3131  Module build_module(const std::string &function_name = "",
3133 
3134  /**
3135  * Build a module that is suitable for using for gradient descent calculation in TensorFlow or PyTorch.
3136  *
3137  * Essentially:
3138  * - A new Pipeline is synthesized from the current Generator (according to the rules below)
3139  * - The new Pipeline is autoscheduled (if autoscheduling is requested, but it would be odd not to do so)
3140  * - The Pipeline is compiled to a Module and returned
3141  *
3142  * The new Pipeline is adjoint to the original; it has:
3143  * - All the same inputs as the original, in the same order
3144  * - Followed by one grad-input for each original output
3145  * - Followed by one output for each unique pairing of original-output + original-input.
3146  * (For the common case of just one original-output, this amounts to being one output for each original-input.)
3147  */
3148  Module build_gradient_module(const std::string &function_name);
3149 
3150  /**
3151  * set_inputs is a variadic wrapper around set_inputs_vector, which makes usage much simpler
3152  * in many cases, as it constructs the relevant entries for the vector for you, which
3153  * is often a bit unintuitive at present. The arguments are passed in Input<>-declaration-order,
3154  * and the types must be compatible. Array inputs are passed as std::vector<> of the relevant type.
3155  *
3156  * Note: at present, scalar input types must match *exactly*, i.e., for Input<uint8_t>, you
3157  * must pass an argument that is actually uint8_t; an argument that is int-that-will-fit-in-uint8
3158  * will assert-fail at Halide compile time.
3159  */
3160  template<typename... Args>
3161  void set_inputs(const Args &...args) {
3162  // set_inputs_vector() checks this too, but checking it here allows build_inputs() to avoid out-of-range checks.
3163  GeneratorParamInfo &pi = this->param_info();
3164  user_assert(sizeof...(args) == pi.inputs().size())
3165  << "Expected exactly " << pi.inputs().size()
3166  << " inputs but got " << sizeof...(args) << "\n";
3167  set_inputs_vector(build_inputs(std::forward_as_tuple<const Args &...>(args...), std::make_index_sequence<sizeof...(Args)>{}));
3168  }
3169 
3170  Realization realize(std::vector<int32_t> sizes) {
3171  this->check_scheduled("realize");
3172  return get_pipeline().realize(std::move(sizes), get_target());
3173  }
3174 
3175  // Only enable if none of the args are Realization; otherwise we can incorrectly
3176  // select this method instead of the Realization-as-outparam variant
3177  template<typename... Args, typename std::enable_if<NoRealizations<Args...>::value>::type * = nullptr>
3178  Realization realize(Args &&...args) {
3179  this->check_scheduled("realize");
3180  return get_pipeline().realize(std::forward<Args>(args)..., get_target());
3181  }
3182 
3184  this->check_scheduled("realize");
3186  }
3187 
3188 #ifdef HALIDE_ALLOW_GENERATOR_BUILD_METHOD
3189  // Return the Pipeline that has been built by the generate() method.
3190  // This method can only be used from a Generator that has a generate()
3191  // method (vs a build() method), and currently can only be called from
3192  // the schedule() method. (This may be relaxed in the future to allow
3193  // calling from generate() as long as all Outputs have been defined.)
3195 #else
3196  // Return the Pipeline that has been built by the generate() method.
3197  // This method can only be called from the schedule() method.
3198  // (This may be relaxed in the future to allow calling from generate() as
3199  // long as all Outputs have been defined.)
3201 #endif
3202 
3203  // Create Input<Func> with dynamic type & dimensions
3204  template<typename T,
3205  typename std::enable_if<std::is_same<T, Halide::Func>::value>::type * = nullptr>
3206  GeneratorInput<T> *add_input(const std::string &name, const Type &t, int dimensions) {
3208  auto *p = new GeneratorInput<T>(name, t, dimensions);
3209  p->generator = this;
3210  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3211  param_info_ptr->filter_inputs.push_back(p);
3212  return p;
3213  }
3214 
3215  // Create Input<Buffer> with dynamic type & dimensions
3216  template<typename T,
3217  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3218  GeneratorInput<T> *add_input(const std::string &name, const Type &t, int dimensions) {
3219  static_assert(!T::has_static_halide_type, "You can only call this version of add_input() for a Buffer<T, D> where T is void or omitted .");
3220  static_assert(!T::has_static_dimensions, "You can only call this version of add_input() for a Buffer<T, D> where D is -1 or omitted.");
3222  auto *p = new GeneratorInput<T>(name, t, dimensions);
3223  p->generator = this;
3224  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3225  param_info_ptr->filter_inputs.push_back(p);
3226  return p;
3227  }
3228 
3229  // Create Input<Buffer> with compile-time type
3230  template<typename T,
3231  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3232  GeneratorInput<T> *add_input(const std::string &name, int dimensions) {
3233  static_assert(T::has_static_halide_type, "You can only call this version of add_input() for a Buffer<T, D> where T is not void.");
3234  static_assert(!T::has_static_dimensions, "You can only call this version of add_input() for a Buffer<T, D> where D is -1 or omitted.");
3236  auto *p = new GeneratorInput<T>(name, dimensions);
3237  p->generator = this;
3238  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3239  param_info_ptr->filter_inputs.push_back(p);
3240  return p;
3241  }
3242 
3243  // Create Input<Buffer> with compile-time type & dimensions
3244  template<typename T,
3245  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3246  GeneratorInput<T> *add_input(const std::string &name) {
3247  static_assert(T::has_static_halide_type, "You can only call this version of add_input() for a Buffer<T, D> where T is not void.");
3248  static_assert(T::has_static_dimensions, "You can only call this version of add_input() for a Buffer<T, D> where D is not -1.");
3250  auto *p = new GeneratorInput<T>(name);
3251  p->generator = this;
3252  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3253  param_info_ptr->filter_inputs.push_back(p);
3254  return p;
3255  }
3256  // Create Input<scalar>
3257  template<typename T,
3258  typename std::enable_if<std::is_arithmetic<T>::value>::type * = nullptr>
3259  GeneratorInput<T> *add_input(const std::string &name) {
3261  auto *p = new GeneratorInput<T>(name);
3262  p->generator = this;
3263  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3264  param_info_ptr->filter_inputs.push_back(p);
3265  return p;
3266  }
3267  // Create Input<Expr> with dynamic type
3268  template<typename T,
3269  typename std::enable_if<std::is_same<T, Expr>::value>::type * = nullptr>
3270  GeneratorInput<T> *add_input(const std::string &name, const Type &type) {
3272  auto *p = new GeneratorInput<Expr>(name);
3273  p->generator = this;
3274  p->set_type(type);
3275  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3276  param_info_ptr->filter_inputs.push_back(p);
3277  return p;
3278  }
3279 
3280  // Create Output<Func> with dynamic type & dimensions
3281  template<typename T,
3282  typename std::enable_if<std::is_same<T, Halide::Func>::value>::type * = nullptr>
3283  GeneratorOutput<T> *add_output(const std::string &name, const Type &t, int dimensions) {
3285  auto *p = new GeneratorOutput<T>(name, t, dimensions);
3286  p->generator = this;
3287  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3288  param_info_ptr->filter_outputs.push_back(p);
3289  return p;
3290  }
3291 
3292  // Create Output<Buffer> with dynamic type & dimensions
3293  template<typename T,
3294  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3295  GeneratorOutput<T> *add_output(const std::string &name, const Type &t, int dimensions) {
3296  static_assert(!T::has_static_halide_type, "You can only call this version of add_output() for a Buffer<T, D> where T is void or omitted .");
3297  static_assert(!T::has_static_dimensions, "You can only call this version of add_output() for a Buffer<T, D> where D is -1 or omitted.");
3299  auto *p = new GeneratorOutput<T>(name, t, dimensions);
3300  p->generator = this;
3301  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3302  param_info_ptr->filter_outputs.push_back(p);
3303  return p;
3304  }
3305 
3306  // Create Output<Buffer> with compile-time type
3307  template<typename T,
3308  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3309  GeneratorOutput<T> *add_output(const std::string &name, int dimensions) {
3310  static_assert(T::has_static_halide_type, "You can only call this version of add_output() for a Buffer<T, D> where T is not void.");
3311  static_assert(!T::has_static_dimensions, "You can only call this version of add_output() for a Buffer<T, D> where D is -1 or omitted.");
3313  auto *p = new GeneratorOutput<T>(name, dimensions);
3314  p->generator = this;
3315  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3316  param_info_ptr->filter_outputs.push_back(p);
3317  return p;
3318  }
3319 
3320  // Create Output<Buffer> with compile-time type & dimensions
3321  template<typename T,
3322  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3323  GeneratorOutput<T> *add_output(const std::string &name) {
3324  static_assert(T::has_static_halide_type, "You can only call this version of add_output() for a Buffer<T, D> where T is not void.");
3325  static_assert(T::has_static_dimensions, "You can only call this version of add_output() for a Buffer<T, D> where D is not -1.");
3327  auto *p = new GeneratorOutput<T>(name);
3328  p->generator = this;
3329  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3330  param_info_ptr->filter_outputs.push_back(p);
3331  return p;
3332  }
3333 
3334  template<typename... Args>
3335  HALIDE_NO_USER_CODE_INLINE void add_requirement(Expr condition, Args &&...args) {
3336  get_pipeline().add_requirement(condition, std::forward<Args>(args)...);
3337  }
3338 
3341  }
3342 
3344 
3345 protected:
3346  GeneratorBase(size_t size, const void *introspection_helper);
3347  void set_generator_names(const std::string &registered_name, const std::string &stub_name);
3348 
3350 
3351  virtual Pipeline build_pipeline() = 0;
3352  virtual void call_configure() = 0;
3353  virtual void call_generate() = 0;
3354  virtual void call_schedule() = 0;
3355 
3356  void track_parameter_values(bool include_outputs);
3357 
3358  void pre_build();
3359  void post_build();
3366 
3367  template<typename T>
3369 
3370  template<typename T>
3372 
3373  // A Generator's creation and usage must go in a certain phase to ensure correctness;
3374  // the state machine here is advanced and checked at various points to ensure
3375  // this is the case.
3376  enum Phase {
3377  // Generator has just come into being.
3379 
3380  // Generator has had its configure() method called. (For Generators without
3381  // a configure() method, this phase will be skipped and will advance
3382  // directly to InputsSet.)
3384 
3385  // All Input<>/Param<> fields have been set. (Applicable only in JIT mode;
3386  // in AOT mode, this can be skipped, going Created->GenerateCalled directly.)
3388 
3389 #ifdef HALIDE_ALLOW_GENERATOR_BUILD_METHOD
3390  // Generator has had its generate() method called. (For Generators with
3391  // a build() method instead of generate(), this phase will be skipped
3392  // and will advance directly to ScheduleCalled.)
3394 #else
3395  // Generator has had its generate() method called.
3397 #endif
3398 
3399  // Generator has had its schedule() method (if any) called.
3401  } phase{Created};
3402 
3403  void check_exact_phase(Phase expected_phase) const;
3404  void check_min_phase(Phase expected_phase) const;
3405  void advance_phase(Phase new_phase);
3406 
3408 
3409  Target get_target() const {
3410  return target;
3411  }
3412  bool get_auto_schedule() const {
3413  return auto_schedule;
3414  }
3416  return machine_params;
3417  }
3418  /** Generators can register ExternalCode objects onto
3419  * themselves. The Generator infrastructure will arrange to have
3420  * this ExternalCode appended to the Module that is finally
3421  * compiled using the Generator. This allows encapsulating
3422  * functionality that depends on external libraries or handwritten
3423  * code for various targets. The name argument should match the
3424  * name of the ExternalCode block and is used to ensure the same
3425  * code block is not duplicated in the output. Halide does not do
3426  * anything other than to compare names for equality. To guarantee
3427  * uniqueness in public code, we suggest using a Java style
3428  * inverted domain name followed by organization specific
3429  * naming. E.g.:
3430  * com.yoyodyne.overthruster.0719acd19b66df2a9d8d628a8fefba911a0ab2b7
3431  *
3432  * See test/generator/external_code_generator.cpp for example use. */
3433  std::shared_ptr<GeneratorContext::ExternsMap> get_externs_map() const {
3434  return externs_map;
3435  }
3436 
3437  // These must remain here for legacy code that access the fields directly.
3439  GeneratorParam<bool> auto_schedule{"auto_schedule", false};
3441 
3442 private:
3444  friend class GeneratorParamBase;
3445  friend class GIOBase;
3446  friend class GeneratorInputBase;
3447  friend class GeneratorOutputBase;
3448  friend class GeneratorParamInfo;
3449  friend class GeneratorStub;
3450  friend class StubOutputBufferBase;
3451 
3452  const size_t size;
3453  std::shared_ptr<GeneratorContext::ExternsMap> externs_map;
3454  std::shared_ptr<Internal::ValueTracker> value_tracker;
3455 
3456  // Lazily-allocated-and-inited struct with info about our various Params.
3457  // Do not access directly: use the param_info() getter.
3458  std::unique_ptr<GeneratorParamInfo> param_info_ptr;
3459 
3460  bool inputs_set{false};
3461  std::string generator_registered_name, generator_stub_name;
3462  Pipeline pipeline;
3463 
3464  // Return our GeneratorParamInfo.
3465  GeneratorParamInfo &param_info();
3466 
3467  Internal::GeneratorOutputBase *find_output_by_name(const std::string &name);
3468 
3469  void check_scheduled(const char *m) const;
3470 
3471  void build_params(bool force = false);
3472 
3473  // Provide private, unimplemented, wrong-result-type methods here
3474  // so that Generators don't attempt to call the global methods
3475  // of the same name by accident: use the get_target() method instead.
3476  void get_host_target();
3479 
3480  // Return the output with the given name.
3481  // If the output is singular (a non-array), return a vector of size 1.
3482  // If no such name exists (or is non-array), assert.
3483  // This method never returns undefined Funcs.
3484  std::vector<Func> get_outputs(const std::string &n);
3485 
3486  void set_inputs_vector(const std::vector<std::vector<StubInput>> &inputs);
3487 
3488  static void check_input_is_singular(Internal::GeneratorInputBase *in);
3489  static void check_input_is_array(Internal::GeneratorInputBase *in);
3490  static void check_input_kind(Internal::GeneratorInputBase *in, Internal::IOKind kind);
3491 
3492  // Allow Buffer<> if:
3493  // -- we are assigning it to an Input<Buffer<>> (with compatible type and dimensions),
3494  // causing the Input<Buffer<>> to become a precompiled buffer in the generated code.
3495  // -- we are assigningit to an Input<Func>, in which case we just Func-wrap the Buffer<>.
3496  template<typename T, int Dims>
3497  std::vector<StubInput> build_input(size_t i, const Buffer<T, Dims> &arg) {
3498  auto *in = param_info().inputs().at(i);
3499  check_input_is_singular(in);
3500  const auto k = in->kind();
3501  if (k == Internal::IOKind::Buffer) {
3502  Halide::Buffer<> b = arg;
3503  StubInputBuffer<> sib(b);
3504  StubInput si(sib);
3505  return {si};
3506  } else if (k == Internal::IOKind::Function) {
3507  Halide::Func f(arg.name() + "_im");
3508  f(Halide::_) = arg(Halide::_);
3509  StubInput si(f);
3510  return {si};
3511  } else {
3512  check_input_kind(in, Internal::IOKind::Buffer); // just to trigger assertion
3513  return {};
3514  }
3515  }
3516 
3517  // Allow Input<Buffer<>> if:
3518  // -- we are assigning it to another Input<Buffer<>> (with compatible type and dimensions),
3519  // allowing us to simply pipe a parameter from an enclosing Generator to the Invoker.
3520  // -- we are assigningit to an Input<Func>, in which case we just Func-wrap the Input<Buffer<>>.
3521  template<typename T, int Dims>
3522  std::vector<StubInput> build_input(size_t i, const GeneratorInput<Buffer<T, Dims>> &arg) {
3523  auto *in = param_info().inputs().at(i);
3524  check_input_is_singular(in);
3525  const auto k = in->kind();
3526  if (k == Internal::IOKind::Buffer) {
3527  StubInputBuffer<> sib = arg;
3528  StubInput si(sib);
3529  return {si};
3530  } else if (k == Internal::IOKind::Function) {
3531  Halide::Func f = arg.funcs().at(0);
3532  StubInput si(f);
3533  return {si};
3534  } else {
3535  check_input_kind(in, Internal::IOKind::Buffer); // just to trigger assertion
3536  return {};
3537  }
3538  }
3539 
3540  // Allow Func iff we are assigning it to an Input<Func> (with compatible type and dimensions).
3541  std::vector<StubInput> build_input(size_t i, const Func &arg) {
3542  auto *in = param_info().inputs().at(i);
3543  check_input_kind(in, Internal::IOKind::Function);
3544  check_input_is_singular(in);
3545  const Halide::Func &f = arg;
3546  StubInput si(f);
3547  return {si};
3548  }
3549 
3550  // Allow vector<Func> iff we are assigning it to an Input<Func[]> (with compatible type and dimensions).
3551  std::vector<StubInput> build_input(size_t i, const std::vector<Func> &arg) {
3552  auto *in = param_info().inputs().at(i);
3553  check_input_kind(in, Internal::IOKind::Function);
3554  check_input_is_array(in);
3555  // My kingdom for a list comprehension...
3556  std::vector<StubInput> siv;
3557  siv.reserve(arg.size());
3558  for (const auto &f : arg) {
3559  siv.emplace_back(f);
3560  }
3561  return siv;
3562  }
3563 
3564  // Expr must be Input<Scalar>.
3565  std::vector<StubInput> build_input(size_t i, const Expr &arg) {
3566  auto *in = param_info().inputs().at(i);
3567  check_input_kind(in, Internal::IOKind::Scalar);
3568  check_input_is_singular(in);
3569  StubInput si(arg);
3570  return {si};
3571  }
3572 
3573  // (Array form)
3574  std::vector<StubInput> build_input(size_t i, const std::vector<Expr> &arg) {
3575  auto *in = param_info().inputs().at(i);
3576  check_input_kind(in, Internal::IOKind::Scalar);
3577  check_input_is_array(in);
3578  std::vector<StubInput> siv;
3579  siv.reserve(arg.size());
3580  for (const auto &value : arg) {
3581  siv.emplace_back(value);
3582  }
3583  return siv;
3584  }
3585 
3586  // Any other type must be convertible to Expr and must be associated with an Input<Scalar>.
3587  // Use is_arithmetic since some Expr conversions are explicit.
3588  template<typename T,
3589  typename std::enable_if<std::is_arithmetic<T>::value>::type * = nullptr>
3590  std::vector<StubInput> build_input(size_t i, const T &arg) {
3591  auto *in = param_info().inputs().at(i);
3592  check_input_kind(in, Internal::IOKind::Scalar);
3593  check_input_is_singular(in);
3594  // We must use an explicit Expr() ctor to preserve the type
3595  Expr e(arg);
3596  StubInput si(e);
3597  return {si};
3598  }
3599 
3600  // (Array form)
3601  template<typename T,
3602  typename std::enable_if<std::is_arithmetic<T>::value>::type * = nullptr>
3603  std::vector<StubInput> build_input(size_t i, const std::vector<T> &arg) {
3604  auto *in = param_info().inputs().at(i);
3605  check_input_kind(in, Internal::IOKind::Scalar);
3606  check_input_is_array(in);
3607  std::vector<StubInput> siv;
3608  siv.reserve(arg.size());
3609  for (const auto &value : arg) {
3610  // We must use an explicit Expr() ctor to preserve the type;
3611  // otherwise, implicit conversions can downgrade (e.g.) float -> int
3612  Expr e(value);
3613  siv.emplace_back(e);
3614  }
3615  return siv;
3616  }
3617 
3618  template<typename... Args, size_t... Indices>
3619  std::vector<std::vector<StubInput>> build_inputs(const std::tuple<const Args &...> &t, std::index_sequence<Indices...>) {
3620  return {build_input(Indices, std::get<Indices>(t))...};
3621  }
3622 
3623 public:
3624  GeneratorBase(const GeneratorBase &) = delete;
3626  GeneratorBase(GeneratorBase &&that) = delete;
3628 };
3629 
3631 public:
3632  static void register_factory(const std::string &name, GeneratorFactory generator_factory);
3633  static void unregister_factory(const std::string &name);
3634  static std::vector<std::string> enumerate();
3635  // Note that this method will never return null:
3636  // if it cannot return a valid Generator, it should assert-fail.
3637  static std::unique_ptr<GeneratorBase> create(const std::string &name,
3638  const Halide::GeneratorContext &context);
3639 
3640 private:
3641  using GeneratorFactoryMap = std::map<const std::string, GeneratorFactory>;
3642 
3643  GeneratorFactoryMap factories;
3644  std::mutex mutex;
3645 
3646  static GeneratorRegistry &get_registry();
3647 
3648  GeneratorRegistry() = default;
3649 
3650 public:
3655 };
3656 
3657 } // namespace Internal
3658 
3659 template<class T>
3661 protected:
3663  : Internal::GeneratorBase(sizeof(T),
3664  Internal::Introspection::get_introspection_helper<T>()) {
3665  }
3666 
3667 public:
3668  static std::unique_ptr<T> create(const Halide::GeneratorContext &context) {
3669  // We must have an object of type T (not merely GeneratorBase) to call a protected method,
3670  // because CRTP is a weird beast.
3671  auto g = std::make_unique<T>();
3672  g->init_from_context(context);
3673  return g;
3674  }
3675 
3676  // This is public but intended only for use by the HALIDE_REGISTER_GENERATOR() macro.
3677  static std::unique_ptr<T> create(const Halide::GeneratorContext &context,
3678  const std::string &registered_name,
3679  const std::string &stub_name) {
3680  auto g = create(context);
3681  g->set_generator_names(registered_name, stub_name);
3682  return g;
3683  }
3684 
3685  template<typename... Args>
3686  void apply(const Args &...args) {
3687 #ifdef HALIDE_ALLOW_GENERATOR_BUILD_METHOD
3688 #ifndef _MSC_VER
3689  // VS2015 apparently has some SFINAE issues, so this can inappropriately
3690  // trigger there. (We'll still fail when generate() is called, just
3691  // with a less-helpful error message.)
3692  static_assert(has_generate_method<T>::value, "apply() is not supported for old-style Generators.");
3693 #endif
3694 #endif
3695  call_configure();
3696  set_inputs(args...);
3697  call_generate();
3698  call_schedule();
3699  }
3700 
3701  template<typename T2>
3702  std::unique_ptr<T2> create() const {
3703  return T2::create(context());
3704  }
3705 
3706  template<typename T2, typename... Args>
3707  inline std::unique_ptr<T2> apply(const Args &...args) const {
3708  auto t = this->create<T2>();
3709  t->apply(args...);
3710  return t;
3711  }
3712 
3713 private:
3714  // std::is_member_function_pointer will fail if there is no member of that name,
3715  // so we use a little SFINAE to detect if there are method-shaped members.
3716  template<typename>
3717  struct type_sink { typedef void type; };
3718 
3719  template<typename T2, typename = void>
3720  struct has_configure_method : std::false_type {};
3721 
3722  template<typename T2>
3723  struct has_configure_method<T2, typename type_sink<decltype(std::declval<T2>().configure())>::type> : std::true_type {};
3724 
3725  template<typename T2, typename = void>
3726  struct has_generate_method : std::false_type {};
3727 
3728  template<typename T2>
3729  struct has_generate_method<T2, typename type_sink<decltype(std::declval<T2>().generate())>::type> : std::true_type {};
3730 
3731  template<typename T2, typename = void>
3732  struct has_schedule_method : std::false_type {};
3733 
3734  template<typename T2>
3735  struct has_schedule_method<T2, typename type_sink<decltype(std::declval<T2>().schedule())>::type> : std::true_type {};
3736 
3737 #ifdef HALIDE_ALLOW_GENERATOR_BUILD_METHOD
3738  // Implementations for build_pipeline_impl(), specialized on whether we
3739  // have build() or generate()/schedule() methods.
3740 
3741  // MSVC apparently has some weirdness with the usual sfinae tricks
3742  // for detecting method-shaped things, so we can't actually use
3743  // the helpers above outside of static_assert. Instead we make as
3744  // many overloads as we can exist, and then use C++'s preference
3745  // for treating a 0 as an int rather than a double to choose one
3746  // of them.
3747  template<typename T2 = T,
3748  typename std::enable_if<!has_generate_method<T2>::value>::type * = nullptr>
3749  HALIDE_ATTRIBUTE_DEPRECATED("The build() method is deprecated for Halide Generators and will be removed entirely in future versions of Halide. Please use a generate() method with Output<> members instead.")
3750  Pipeline build_pipeline_impl(double) {
3751  static_assert(!has_configure_method<T2>::value, "The configure() method is ignored if you define a build() method; use generate() instead.");
3752  static_assert(!has_schedule_method<T2>::value, "The schedule() method is ignored if you define a build() method; use generate() instead.");
3753 
3754  user_warning << "The build() method is deprecated for Halide Generators and will be removed entirely in future versions of Halide. "
3755  << "Please use a generate() method with Output<> members instead.\n";
3756 
3757  pre_build();
3758  Pipeline p = ((T *)this)->build();
3759  post_build();
3760  return p;
3761  }
3762 
3763  template<typename T2 = T,
3764  typename = decltype(std::declval<T2>().generate())>
3765  Pipeline build_pipeline_impl(int) {
3766  // No: configure() must be called prior to this
3767  // (and in fact, prior to calling set_inputs).
3768  //
3769  // ((T *)this)->call_configure_impl(0, 0);
3770 
3771  ((T *)this)->call_generate_impl(0);
3772  ((T *)this)->call_schedule_impl(0, 0);
3773  return get_pipeline();
3774  }
3775 
3776  // Implementations for call_configure_impl(), specialized on whether we
3777  // have build() or configure()/generate()/schedule() methods.
3778 
3779  void call_configure_impl(double, double) {
3780  pre_configure();
3781  // Called as a side effect for build()-method Generators; quietly do nothing
3782  // (except for pre_configure(), to advance the phase).
3783  post_configure();
3784  }
3785 
3786  template<typename T2 = T,
3787  typename = decltype(std::declval<T2>().generate())>
3788  void call_configure_impl(double, int) {
3789  // Generator has a generate() method but no configure() method. This is ok. Just advance the phase.
3790  pre_configure();
3791  static_assert(!has_configure_method<T2>::value, "Did not expect a configure method here.");
3792  post_configure();
3793  }
3794 
3795  template<typename T2 = T,
3796  typename = decltype(std::declval<T2>().generate()),
3797  typename = decltype(std::declval<T2>().configure())>
3798  void call_configure_impl(int, int) {
3799  T *t = (T *)this;
3800  static_assert(std::is_void<decltype(t->configure())>::value, "configure() must return void");
3801  pre_configure();
3802  t->configure();
3803  post_configure();
3804  }
3805 
3806  // Implementations for call_generate_impl(), specialized on whether we
3807  // have build() or configure()/generate()/schedule() methods.
3808 
3809  void call_generate_impl(double) {
3810  user_error << "Unimplemented";
3811  }
3812 
3813  template<typename T2 = T,
3814  typename = decltype(std::declval<T2>().generate())>
3815  void call_generate_impl(int) {
3816  T *t = (T *)this;
3817  static_assert(std::is_void<decltype(t->generate())>::value, "generate() must return void");
3818  pre_generate();
3819  t->generate();
3820  post_generate();
3821  }
3822 
3823  // Implementations for call_schedule_impl(), specialized on whether we
3824  // have build() or configure()generate()/schedule() methods.
3825 
3826  void call_schedule_impl(double, double) {
3827  user_error << "Unimplemented";
3828  }
3829 
3830  template<typename T2 = T,
3831  typename = decltype(std::declval<T2>().generate())>
3832  void call_schedule_impl(double, int) {
3833  // Generator has a generate() method but no schedule() method. This is ok. Just advance the phase.
3834  pre_schedule();
3835  post_schedule();
3836  }
3837 
3838  template<typename T2 = T,
3839  typename = decltype(std::declval<T2>().generate()),
3840  typename = decltype(std::declval<T2>().schedule())>
3841  void call_schedule_impl(int, int) {
3842  T *t = (T *)this;
3843  static_assert(std::is_void<decltype(t->schedule())>::value, "schedule() must return void");
3844  pre_schedule();
3845  t->schedule();
3846  post_schedule();
3847  }
3848 #else
3849  Pipeline build_pipeline_impl() {
3850  T *t = (T *)this;
3851  // No: configure() must be called prior to this
3852  // (and in fact, prior to calling set_inputs).
3853  //
3854  // t->call_configure_impl();
3855 
3856  t->call_generate_impl();
3857  t->call_schedule_impl();
3858  return get_pipeline();
3859  }
3860 
3861  void call_configure_impl() {
3862  pre_configure();
3863  if constexpr (has_configure_method<T>::value) {
3864  T *t = (T *)this;
3865  static_assert(std::is_void<decltype(t->configure())>::value, "configure() must return void");
3866  t->configure();
3867  }
3868  post_configure();
3869  }
3870 
3871  void call_generate_impl() {
3872  pre_generate();
3873  static_assert(has_generate_method<T>::value, "Expected a generate() method here.");
3874  T *t = (T *)this;
3875  static_assert(std::is_void<decltype(t->generate())>::value, "generate() must return void");
3876  t->generate();
3877  post_generate();
3878  }
3879 
3880  void call_schedule_impl() {
3881  pre_schedule();
3882  if constexpr (has_schedule_method<T>::value) {
3883  T *t = (T *)this;
3884  static_assert(std::is_void<decltype(t->schedule())>::value, "schedule() must return void");
3885  t->schedule();
3886  }
3887  post_schedule();
3888  }
3889 #endif
3890 
3891 protected:
3892 #ifdef HALIDE_ALLOW_GENERATOR_BUILD_METHOD
3893  Pipeline build_pipeline() override {
3894  return this->build_pipeline_impl(0);
3895  }
3896 
3897  void call_configure() override {
3898  this->call_configure_impl(0, 0);
3899  }
3900 
3901  void call_generate() override {
3902  this->call_generate_impl(0);
3903  }
3904 
3905  void call_schedule() override {
3906  this->call_schedule_impl(0, 0);
3907  }
3908 #else
3910  return this->build_pipeline_impl();
3911  }
3912 
3913  void call_configure() override {
3914  this->call_configure_impl();
3915  }
3916 
3917  void call_generate() override {
3918  this->call_generate_impl();
3919  }
3920 
3921  void call_schedule() override {
3922  this->call_schedule_impl();
3923  }
3924 #endif
3925 private:
3928  friend class ::Halide::GeneratorContext;
3929 
3930 public:
3931  Generator(const Generator &) = delete;
3932  Generator &operator=(const Generator &) = delete;
3933  Generator(Generator &&that) = delete;
3934  Generator &operator=(Generator &&that) = delete;
3935 };
3936 
3937 namespace Internal {
3938 
3940 public:
3941  RegisterGenerator(const char *registered_name, GeneratorFactory generator_factory);
3942 };
3943 
3945 public:
3947  const GeneratorFactory &generator_factory);
3948 
3950  const GeneratorFactory &generator_factory,
3951  const GeneratorParamsMap &generator_params,
3952  const std::vector<std::vector<Internal::StubInput>> &inputs);
3953  std::vector<std::vector<Func>> generate(const GeneratorParamsMap &generator_params,
3954  const std::vector<std::vector<Internal::StubInput>> &inputs);
3955 
3956  // Output(s)
3957  std::vector<Func> get_outputs(const std::string &n) const {
3958  return generator->get_outputs(n);
3959  }
3960 
3961  template<typename T2>
3962  std::vector<T2> get_output_buffers(const std::string &n) const {
3963  auto v = generator->get_outputs(n);
3964  std::vector<T2> result;
3965  for (auto &o : v) {
3966  result.push_back(T2(o, generator));
3967  }
3968  return result;
3969  }
3970 
3971  static std::vector<StubInput> to_stub_input_vector(const Expr &e) {
3972  return {StubInput(e)};
3973  }
3974 
3975  static std::vector<StubInput> to_stub_input_vector(const Func &f) {
3976  return {StubInput(f)};
3977  }
3978 
3979  template<typename T = void>
3980  static std::vector<StubInput> to_stub_input_vector(const StubInputBuffer<T> &b) {
3981  return {StubInput(b)};
3982  }
3983 
3984  template<typename T>
3985  static std::vector<StubInput> to_stub_input_vector(const std::vector<T> &v) {
3986  std::vector<StubInput> r;
3987  std::copy(v.begin(), v.end(), std::back_inserter(r));
3988  return r;
3989  }
3990 
3991  struct Names {
3992  std::vector<std::string> generator_params, inputs, outputs;
3993  };
3994  Names get_names() const;
3995 
3996  std::shared_ptr<GeneratorBase> generator;
3997 };
3998 
3999 } // namespace Internal
4000 
4001 } // namespace Halide
4002 
4003 // Define this namespace at global scope so that anonymous namespaces won't
4004 // defeat our static_assert check; define a dummy type inside so we can
4005 // check for type aliasing injected by anonymous namespace usage
4007 struct halide_global_ns;
4008 };
4009 
4010 #define _HALIDE_REGISTER_GENERATOR_IMPL(GEN_CLASS_NAME, GEN_REGISTRY_NAME, FULLY_QUALIFIED_STUB_NAME) \
4011  namespace halide_register_generator { \
4012  struct halide_global_ns; \
4013  namespace GEN_REGISTRY_NAME##_ns { \
4014  std::unique_ptr<Halide::Internal::GeneratorBase> factory(const Halide::GeneratorContext &context); \
4015  std::unique_ptr<Halide::Internal::GeneratorBase> factory(const Halide::GeneratorContext &context) { \
4016  using GenType = std::remove_pointer<decltype(new GEN_CLASS_NAME)>::type; /* NOLINT(bugprone-macro-parentheses) */ \
4017  return GenType::create(context, #GEN_REGISTRY_NAME, #FULLY_QUALIFIED_STUB_NAME); \
4018  } \
4019  } \
4020  static auto reg_##GEN_REGISTRY_NAME = Halide::Internal::RegisterGenerator(#GEN_REGISTRY_NAME, GEN_REGISTRY_NAME##_ns::factory); \
4021  } \
4022  static_assert(std::is_same<::halide_register_generator::halide_global_ns, halide_register_generator::halide_global_ns>::value, \
4023  "HALIDE_REGISTER_GENERATOR must be used at global scope");
4024 
4025 #define _HALIDE_REGISTER_GENERATOR2(GEN_CLASS_NAME, GEN_REGISTRY_NAME) \
4026  _HALIDE_REGISTER_GENERATOR_IMPL(GEN_CLASS_NAME, GEN_REGISTRY_NAME, GEN_REGISTRY_NAME)
4027 
4028 #define _HALIDE_REGISTER_GENERATOR3(GEN_CLASS_NAME, GEN_REGISTRY_NAME, FULLY_QUALIFIED_STUB_NAME) \
4029  _HALIDE_REGISTER_GENERATOR_IMPL(GEN_CLASS_NAME, GEN_REGISTRY_NAME, FULLY_QUALIFIED_STUB_NAME)
4030 
4031 // MSVC has a broken implementation of variadic macros: it expands __VA_ARGS__
4032 // as a single token in argument lists (rather than multiple tokens).
4033 // Jump through some hoops to work around this.
4034 #define __HALIDE_REGISTER_ARGCOUNT_IMPL(_1, _2, _3, COUNT, ...) \
4035  COUNT
4036 
4037 #define _HALIDE_REGISTER_ARGCOUNT_IMPL(ARGS) \
4038  __HALIDE_REGISTER_ARGCOUNT_IMPL ARGS
4039 
4040 #define _HALIDE_REGISTER_ARGCOUNT(...) \
4041  _HALIDE_REGISTER_ARGCOUNT_IMPL((__VA_ARGS__, 3, 2, 1, 0))
4042 
4043 #define ___HALIDE_REGISTER_CHOOSER(COUNT) \
4044  _HALIDE_REGISTER_GENERATOR##COUNT
4045 
4046 #define __HALIDE_REGISTER_CHOOSER(COUNT) \
4047  ___HALIDE_REGISTER_CHOOSER(COUNT)
4048 
4049 #define _HALIDE_REGISTER_CHOOSER(COUNT) \
4050  __HALIDE_REGISTER_CHOOSER(COUNT)
4051 
4052 #define _HALIDE_REGISTER_GENERATOR_PASTE(A, B) \
4053  A B
4054 
4055 #define HALIDE_REGISTER_GENERATOR(...) \
4056  _HALIDE_REGISTER_GENERATOR_PASTE(_HALIDE_REGISTER_CHOOSER(_HALIDE_REGISTER_ARGCOUNT(__VA_ARGS__)), (__VA_ARGS__))
4057 
4058 // HALIDE_REGISTER_GENERATOR_ALIAS() can be used to create an an alias-with-a-particular-set-of-param-values
4059 // for a given Generator in the build system. Normally, you wouldn't want to do this;
4060 // however, some existing Halide clients have build systems that make it challenging to
4061 // specify GeneratorParams inside the build system, and this allows a somewhat simpler
4062 // customization route for them. It's highly recommended you don't use this for new code.
4063 //
4064 // The final argument is really an initializer-list of GeneratorParams, in the form
4065 // of an initializer-list for map<string, string>:
4066 //
4067 // { { "gp-name", "gp-value"} [, { "gp2-name", "gp2-value" }] }
4068 //
4069 // It is specified as a variadic template argument to allow for the fact that the embedded commas
4070 // would otherwise confuse the preprocessor; since (in this case) all we're going to do is
4071 // pass it thru as-is, this is fine (and even MSVC's 'broken' __VA_ARGS__ should be OK here).
4072 #define HALIDE_REGISTER_GENERATOR_ALIAS(GEN_REGISTRY_NAME, ORIGINAL_REGISTRY_NAME, ...) \
4073  namespace halide_register_generator { \
4074  struct halide_global_ns; \
4075  namespace ORIGINAL_REGISTRY_NAME##_ns { \
4076  std::unique_ptr<Halide::Internal::GeneratorBase> factory(const Halide::GeneratorContext &context); \
4077  } \
4078  namespace GEN_REGISTRY_NAME##_ns { \
4079  std::unique_ptr<Halide::Internal::GeneratorBase> factory(const Halide::GeneratorContext &context); \
4080  std::unique_ptr<Halide::Internal::GeneratorBase> factory(const Halide::GeneratorContext &context) { \
4081  auto g = ORIGINAL_REGISTRY_NAME##_ns::factory(context); \
4082  g->set_generator_param_values(__VA_ARGS__); \
4083  return g; \
4084  } \
4085  } \
4086  static auto reg_##GEN_REGISTRY_NAME = Halide::Internal::RegisterGenerator(#GEN_REGISTRY_NAME, GEN_REGISTRY_NAME##_ns::factory); \
4087  } \
4088  static_assert(std::is_same<::halide_register_generator::halide_global_ns, halide_register_generator::halide_global_ns>::value, \
4089  "HALIDE_REGISTER_GENERATOR_ALIAS must be used at global scope");
4090 
4091 #endif // HALIDE_GENERATOR_H_
#define internal_error
Definition: Errors.h:23
#define user_error
Definition: Errors.h:7
#define user_warning
Definition: Errors.h:11
#define internal_assert(c)
Definition: Errors.h:19
#define user_assert(c)
Definition: Errors.h:15
Defines Func - the front-end handle on a halide function, and related classes.
#define HALIDE_GENERATOR_PARAM_TYPED_SETTER(TYPE)
Definition: Generator.h:488
#define HALIDE_FORWARD_METHOD(Class, Method)
Definition: Generator.h:1598
#define HALIDE_FORWARD_METHOD_CONST(Class, Method)
Definition: Generator.h:1604
#define HALIDE_ALWAYS_INLINE
Definition: HalideRuntime.h:38
Classes for declaring image parameters to halide pipelines.
Defines methods for introspecting in C++.
Provides a single global registry of Generators, GeneratorParams, and Params indexed by this pointer.
Defines the structure that describes a Halide target.
#define HALIDE_NO_USER_CODE_INLINE
Definition: Util.h:45
A Halide::Buffer is a named shared reference to a Halide::Runtime::Buffer.
Definition: Buffer.h:120
Type type() const
Definition: Buffer.h:531
bool defined() const
Check if this Buffer refers to an existing Buffer.
Definition: Buffer.h:379
const std::string & name() const
Definition: Buffer.h:365
Helper class for identifying purpose of an Expr passed to memoize.
Definition: Func.h:688
A halide function.
Definition: Func.h:703
bool defined() const
Does this function have at least a pure definition.
int dimensions() const
The dimensionality (number of arguments) of this function.
Realization realize(std::vector< int32_t > sizes={}, const Target &target=Target(), const ParamMap &param_map=ParamMap::empty_map())
Evaluate this function over some rectangular domain and return the resulting buffer or buffers.
const std::string & name() const
The name of this function, either given during construction, or automatically generated.
const std::vector< Type > & output_types() const
Get the types of the outputs of this Func.
Func in(const Func &f)
Creates and returns a new identity Func that wraps this Func.
A fragment of front-end syntax of the form f(x, y, z), where x, y, z are Vars or Exprs.
Definition: Func.h:494
GeneratorContext is a class that is used when using Generators (or Stubs) directly; it is used to all...
Definition: Generator.h:2934
std::map< std::string, ExternalCode > ExternsMap
Definition: Generator.h:2938
std::unique_ptr< T > apply(const Args &...args) const
Definition: Generator.h:2965
const MachineParams & get_machine_params() const
Definition: Generator.h:2956
GeneratorContext & operator=(const GeneratorContext &)=default
const Target & get_target() const
Definition: Generator.h:2950
GeneratorContext & operator=(GeneratorContext &&)=default
std::unique_ptr< T > create() const
Definition: Generator.h:2961
bool get_auto_schedule() const
Definition: Generator.h:2953
GeneratorContext(const Target &t, bool auto_schedule=false, const MachineParams &machine_params=MachineParams::generic())
GeneratorContext(const GeneratorContext &)=default
GeneratorContext(GeneratorContext &&)=default
void call_generate() override
Definition: Generator.h:3917
Generator(Generator &&that)=delete
void call_schedule() override
Definition: Generator.h:3921
std::unique_ptr< T2 > create() const
Definition: Generator.h:3702
static std::unique_ptr< T > create(const Halide::GeneratorContext &context)
Definition: Generator.h:3668
Generator & operator=(Generator &&that)=delete
Generator & operator=(const Generator &)=delete
void apply(const Args &...args)
Definition: Generator.h:3686
static std::unique_ptr< T > create(const Halide::GeneratorContext &context, const std::string &registered_name, const std::string &stub_name)
Definition: Generator.h:3677
void call_configure() override
Definition: Generator.h:3913
std::unique_ptr< T2 > apply(const Args &...args) const
Definition: Generator.h:3707
Pipeline build_pipeline() override
Definition: Generator.h:3909
Generator(const Generator &)=delete
typename Internal::select_type< Internal::cond< Internal::has_static_halide_type_method< TBase >::value, int >, Internal::cond< std::is_same< TBase, Func >::value, int >, Internal::cond< true, Unused > >::type IntIfNonScalar
Definition: Generator.h:2135
GeneratorInput(size_t array_size, const std::string &name, const Type &t)
Definition: Generator.h:2180
GeneratorInput(const std::string &name, const TBase &def)
Definition: Generator.h:2145
GeneratorInput(const std::string &name, const TBase &def, const TBase &min, const TBase &max)
Definition: Generator.h:2153
typename Super::TBase TBase
Definition: Generator.h:2125
GeneratorInput(size_t array_size, const std::string &name, const TBase &def, const TBase &min, const TBase &max)
Definition: Generator.h:2158
GeneratorInput(size_t array_size, const std::string &name, IntIfNonScalar d)
Definition: Generator.h:2186
GeneratorInput(const std::string &name, const Type &t)
Definition: Generator.h:2167
GeneratorInput(size_t array_size, const std::string &name)
Definition: Generator.h:2190
GeneratorInput(size_t array_size, const std::string &name, const Type &t, int d)
Definition: Generator.h:2176
GeneratorInput(const std::string &name)
Definition: Generator.h:2141
GeneratorInput(const std::string &name, const Type &t, int d)
Definition: Generator.h:2163
GeneratorInput(size_t array_size, const std::string &name, const TBase &def)
Definition: Generator.h:2149
GeneratorInput(const std::string &name, IntIfNonScalar d)
Definition: Generator.h:2172
GeneratorOutput< T > & operator=(Buffer< T2, D2 > &buffer)
Definition: Generator.h:2787
typename Super::TBase TBase
Definition: Generator.h:2725
GeneratorOutput(const std::string &name)
Definition: Generator.h:2731
GeneratorOutput(const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2759
GeneratorOutput(const char *name)
Definition: Generator.h:2735
GeneratorOutput(const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2751
GeneratorOutput(size_t array_size, const std::string &name, int d)
Definition: Generator.h:2763
GeneratorOutput(size_t array_size, const std::string &name, const Type &t, int d)
Definition: Generator.h:2775
GeneratorOutput(const std::string &name, const Type &t, int d)
Definition: Generator.h:2755
GeneratorOutput< T > & operator=(const Internal::StubOutputBuffer< T2 > &stub_output_buffer)
Definition: Generator.h:2793
GeneratorOutput(size_t array_size, const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2779
GeneratorOutput(const std::string &name, int d)
Definition: Generator.h:2743
GeneratorOutput(size_t array_size, const std::string &name)
Definition: Generator.h:2739
GeneratorOutput(const std::string &name, const Type &t)
Definition: Generator.h:2747
GeneratorOutput(size_t array_size, const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2771
GeneratorOutput(size_t array_size, const std::string &name, const Type &t)
Definition: Generator.h:2767
GeneratorOutput< T > & operator=(const Func &f)
Definition: Generator.h:2798
GeneratorParam is a templated class that can be used to modify the behavior of the Generator at code-...
Definition: Generator.h:961
GeneratorParam(const std::string &name, const std::string &value)
Definition: Generator.h:976
GeneratorParam(const std::string &name, const T &value, const T &min, const T &max)
Definition: Generator.h:968
GeneratorParam(const std::string &name, const T &value)
Definition: Generator.h:964
GeneratorParam(const std::string &name, const T &value, const std::map< std::string, T > &enum_map)
Definition: Generator.h:972
An Image parameter to a halide pipeline.
Definition: ImageParam.h:23
A reference-counted handle to Halide's internal representation of a function.
Definition: Function.h:38
GIOBase is the base class for all GeneratorInput<> and GeneratorOutput<> instantiations; it is not pa...
Definition: Generator.h:1395
size_t array_size() const
const std::vector< Func > & funcs() const
GIOBase & operator=(const GIOBase &)=delete
void check_matching_dims(int d) const
GIOBase(size_t array_size, const std::string &name, IOKind kind, const std::vector< Type > &types, int dims)
bool array_size_defined() const
virtual const char * input_or_output() const =0
GIOBase & operator=(GIOBase &&)=delete
std::vector< Type > types_
Definition: Generator.h:1435
const std::vector< ElemType > & get_values() const
void check_matching_types(const std::vector< Type > &t) const
const std::vector< Type > & types() const
std::string array_name(size_t i) const
virtual void check_value_writable() const =0
GIOBase(const GIOBase &)=delete
void check_matching_array_size(size_t size) const
const std::vector< Expr > & exprs() const
GIOBase(GIOBase &&)=delete
void check_gio_access() const
void set_dimensions(int dims)
void set_array_size(int size)
std::vector< Func > funcs_
Definition: Generator.h:1439
const std::string name_
Definition: Generator.h:1433
const std::string & name() const
virtual bool is_array() const
virtual void verify_internals()
virtual ~GIOBase()=default
std::vector< Expr > exprs_
Definition: Generator.h:1440
void set_type(const Type &type)
GeneratorBase * generator
Definition: Generator.h:1447
GeneratorParam< Target > target
Definition: Generator.h:3438
GeneratorInput< T > * add_input(const std::string &name, const Type &t, int dimensions)
Definition: Generator.h:3206
GeneratorBase(size_t size, const void *introspection_helper)
HALIDE_NO_USER_CODE_INLINE void add_requirement(Expr condition, Args &&...args)
Definition: Generator.h:3335
GeneratorInput< T > * add_input(const std::string &name)
Definition: Generator.h:3246
Realization realize(Args &&...args)
Definition: Generator.h:3178
Module build_module(const std::string &function_name="", LinkageType linkage_type=LinkageType::ExternalPlusMetadata)
GeneratorBase(const GeneratorBase &)=delete
void init_from_context(const Halide::GeneratorContext &context)
GeneratorInput< T > * add_input(const std::string &name, const Type &type)
Definition: Generator.h:3270
int natural_vector_size() const
Given a data type, return an estimate of the "natural" vector size for that data type when compiling ...
Definition: Generator.h:3123
GeneratorInput< T > * add_input(const std::string &name, int dimensions)
Definition: Generator.h:3232
GeneratorParam< bool > auto_schedule
Definition: Generator.h:3439
void check_exact_phase(Phase expected_phase) const
void check_min_phase(Phase expected_phase) const
void realize(Realization r)
Definition: Generator.h:3183
enum Halide::Internal::GeneratorBase::Phase Created
void set_generator_names(const std::string &registered_name, const std::string &stub_name)
Realization realize(std::vector< int32_t > sizes)
Definition: Generator.h:3170
std::shared_ptr< GeneratorContext::ExternsMap > get_externs_map() const
Generators can register ExternalCode objects onto themselves.
Definition: Generator.h:3433
GeneratorOutput< T > * add_output(const std::string &name, const Type &t, int dimensions)
Definition: Generator.h:3283
Module build_gradient_module(const std::string &function_name)
Build a module that is suitable for using for gradient descent calculation in TensorFlow or PyTorch.
GeneratorBase(GeneratorBase &&that)=delete
GeneratorOutput< T > * add_output(const std::string &name)
Definition: Generator.h:3323
MachineParams get_machine_params() const
Definition: Generator.h:3415
GeneratorBase & operator=(const GeneratorBase &)=delete
GeneratorOutput< T > * add_output(const std::string &name, int dimensions)
Definition: Generator.h:3309
GeneratorContext context() const
void emit_cpp_stub(const std::string &stub_file_path)
virtual Pipeline build_pipeline()=0
void set_inputs(const Args &...args)
set_inputs is a variadic wrapper around set_inputs_vector, which makes usage much simpler in many cas...
Definition: Generator.h:3161
void set_generator_param_values(const GeneratorParamsMap &params)
int natural_vector_size(Halide::Type t) const
Given a data type, return an estimate of the "natural" vector size for that data type when compiling ...
Definition: Generator.h:3116
void track_parameter_values(bool include_outputs)
void advance_phase(Phase new_phase)
GeneratorParam< MachineParams > machine_params
Definition: Generator.h:3440
GeneratorBase & operator=(GeneratorBase &&that)=delete
GeneratorInput_Arithmetic(size_t array_size, const std::string &name)
Definition: Generator.h:2072
GeneratorInput_Arithmetic(const std::string &name, const TBase &def, const TBase &min, const TBase &max)
Definition: Generator.h:2083
GeneratorInput_Arithmetic(size_t array_size, const std::string &name, const TBase &def)
Definition: Generator.h:2077
GeneratorInput_Arithmetic(const std::string &name)
Definition: Generator.h:2063
GeneratorInput_Arithmetic(size_t array_size, const std::string &name, const TBase &def, const TBase &min, const TBase &max)
Definition: Generator.h:2090
GeneratorInput_Arithmetic(const std::string &name, const TBase &def)
Definition: Generator.h:2067
std::vector< ImageParam >::const_iterator begin() const
Definition: Generator.h:1742
std::string get_c_type() const override
Definition: Generator.h:1623
GeneratorInput_Buffer< T > & set_estimate(Var var, Expr min, Expr extent)
Definition: Generator.h:1690
GeneratorInput_Buffer(const std::string &name, const Type &t)
Definition: Generator.h:1651
GeneratorInput_Buffer(const std::string &name)
Definition: Generator.h:1639
GeneratorInput_Buffer(const std::string &name, const Type &t, int d)
Definition: Generator.h:1645
Expr operator()(std::vector< Expr > args) const
Definition: Generator.h:1669
std::vector< ImageParam >::const_iterator end() const
Definition: Generator.h:1748
Expr operator()(Args &&...args) const
Definition: Generator.h:1664
Func in(const std::vector< Func > &others)
Definition: Generator.h:1712
GeneratorInput_Buffer< T > & set_estimates(const Region &estimates)
Definition: Generator.h:1696
ImageParam operator[](size_t i) const
Definition: Generator.h:1730
ImageParam at(size_t i) const
Definition: Generator.h:1736
GeneratorInput_Buffer(const std::string &name, int d)
Definition: Generator.h:1656
std::string get_c_type() const override
Definition: Generator.h:1903
GeneratorInput_DynamicScalar(const std::string &name)
Definition: Generator.h:1908
GeneratorInput_Func(size_t array_size, const std::string &name, int d)
Definition: Generator.h:1815
Expr operator()(Args &&...args) const
Definition: Generator.h:1830
Func in(const std::vector< Func > &others)
Definition: Generator.h:1872
GeneratorInput_Func(size_t array_size, const std::string &name, const Type &t, int d)
Definition: Generator.h:1810
GeneratorInput_Func< T > & set_estimate(Var var, Expr min, Expr extent)
Definition: Generator.h:1850
GeneratorInput_Func(const std::string &name, int d)
Definition: Generator.h:1796
GeneratorInput_Func(const std::string &name, const Type &t)
Definition: Generator.h:1801
GeneratorInput_Func< T > & set_estimates(const Region &estimates)
Definition: Generator.h:1856
GeneratorInput_Func(size_t array_size, const std::string &name, const Type &t)
Definition: Generator.h:1820
Expr operator()(const std::vector< Expr > &args) const
Definition: Generator.h:1835
Func in(const Func &other)
Definition: Generator.h:1867
std::string get_c_type() const override
Definition: Generator.h:1781
GeneratorInput_Func(const std::string &name, const Type &t, int d)
Definition: Generator.h:1791
GeneratorInput_Func(const std::string &name)
Definition: Generator.h:1806
GeneratorInput_Func(size_t array_size, const std::string &name)
Definition: Generator.h:1825
GeneratorInput_Scalar(size_t array_size, const std::string &name)
Definition: Generator.h:1979
static Expr TBaseToExpr(const TBase2 &value)
Definition: Generator.h:1960
void set_estimate(const TBase &value)
Definition: Generator.h:2005
void set_estimate(size_t index, const TBase &value)
Definition: Generator.h:2027
GeneratorInput_Scalar(size_t array_size, const std::string &name, const TBase &def)
Definition: Generator.h:1984
GeneratorInput_Scalar(const std::string &name)
Definition: Generator.h:1971
GeneratorInput_Scalar(const std::string &name, const TBase &def)
Definition: Generator.h:1975
std::string get_c_type() const override
Definition: Generator.h:1953
GeneratorInputBase(const std::string &name, IOKind kind, const std::vector< Type > &t, int d)
const char * input_or_output() const override
Definition: Generator.h:1517
void set_inputs(const std::vector< StubInput > &inputs)
virtual std::string get_c_type() const =0
void set_estimate_impl(const Var &var, const Expr &min, const Expr &extent)
std::vector< Parameter > parameters_
Definition: Generator.h:1500
GeneratorInputBase(size_t array_size, const std::string &name, IOKind kind, const std::vector< Type > &t, int d)
void set_estimates_impl(const Region &estimates)
void check_value_writable() const override
bool is_array() const override
Definition: Generator.h:1533
std::vector< ValueType >::const_iterator end() const
Definition: Generator.h:1584
const ValueType & operator[](size_t i) const
Definition: Generator.h:1566
std::vector< ValueType >::const_iterator begin() const
Definition: Generator.h:1578
const ValueType & at(size_t i) const
Definition: Generator.h:1572
typename std::remove_all_extents< T >::type TBase
Definition: Generator.h:1531
GeneratorInputImpl(const std::string &name, IOKind kind, const std::vector< Type > &t, int d)
Definition: Generator.h:1540
GeneratorOutput_Arithmetic(const std::string &name)
Definition: Generator.h:2701
GeneratorOutput_Arithmetic(size_t array_size, const std::string &name)
Definition: Generator.h:2705
GeneratorOutput_Buffer(const std::string &name, int d)
Definition: Generator.h:2464
GeneratorOutput_Buffer(size_t array_size, const std::string &name)
Definition: Generator.h:2472
GeneratorOutput_Buffer(size_t array_size, const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2478
GeneratorOutput_Buffer< T > & set_estimates(const Region &estimates)
Definition: Generator.h:2575
GeneratorOutput_Buffer(const std::string &name)
Definition: Generator.h:2444
GeneratorOutput_Buffer< T > & operator=(const Func &f)
Definition: Generator.h:2560
HALIDE_NO_USER_CODE_INLINE std::string get_c_type() const override
Definition: Generator.h:2500
GeneratorOutput_Buffer< T > & operator=(const StubOutputBuffer< T2 > &stub_output_buffer)
Definition: Generator.h:2551
const Func & operator[](size_t i) const
Definition: Generator.h:2583
HALIDE_NO_USER_CODE_INLINE T2 as() const
Definition: Generator.h:2511
GeneratorOutput_Buffer(const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2458
GeneratorOutput_Buffer(size_t array_size, const std::string &name, int d)
Definition: Generator.h:2492
HALIDE_NO_USER_CODE_INLINE GeneratorOutput_Buffer< T > & operator=(Buffer< T2, D2 > &buffer)
Definition: Generator.h:2523
GeneratorOutput_Buffer(size_t array_size, const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2486
GeneratorOutput_Buffer(const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2450
GeneratorOutput_Func< T > & set_estimate(const Var &var, const Expr &min, const Expr &extent)
Definition: Generator.h:2674
GeneratorOutput_Func(const std::string &name)
Definition: Generator.h:2626
GeneratorOutput_Func(const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2630
GeneratorOutput_Func(size_t array_size, const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2642
GeneratorOutput_Func< T > & set_estimates(const Region &estimates)
Definition: Generator.h:2683
GeneratorOutput_Func(const std::string &name, int d)
Definition: Generator.h:2638
GeneratorOutput_Func< T > & operator=(const Func &f)
Definition: Generator.h:2649
const Func & operator[](size_t i) const
Definition: Generator.h:2669
GeneratorOutput_Func(const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2634
GeneratorOutputBase(size_t array_size, const std::string &name, IOKind kind, const std::vector< Type > &t, int d)
Forward schedule-related methods to the underlying Func.
GeneratorOutputBase(const std::string &name, IOKind kind, const std::vector< Type > &t, int d)
virtual std::string get_c_type() const
Definition: Generator.h:2287
HALIDE_NO_USER_CODE_INLINE T2 as() const
Definition: Generator.h:2200
const char * input_or_output() const override
Definition: Generator.h:2293
void check_value_writable() const override
GeneratorOutputImpl(const std::string &name, IOKind kind, const std::vector< Type > &t, int d)
Definition: Generator.h:2314
std::vector< ValueType >::const_iterator begin() const
Definition: Generator.h:2376
const ValueType & at(size_t i) const
Definition: Generator.h:2370
const ValueType & operator[](size_t i) const
Definition: Generator.h:2364
bool is_array() const override
Definition: Generator.h:2307
std::vector< ValueType >::const_iterator end() const
Definition: Generator.h:2382
FuncRef operator()(std::vector< ExprOrVar > args) const
Definition: Generator.h:2340
typename std::remove_all_extents< T >::type TBase
Definition: Generator.h:2304
FuncRef operator()(Args &&...args) const
Definition: Generator.h:2334
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:716
std::string get_c_type() const override
Definition: Generator.h:753
GeneratorParam_Arithmetic(const std::string &name, const T &value, const T &min=std::numeric_limits< T >::lowest(), const T &max=std::numeric_limits< T >::max())
Definition: Generator.h:702
std::string get_default_value() const override
Definition: Generator.h:733
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:747
void set_impl(const T &new_value) override
Definition: Generator.h:711
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:782
std::string get_default_value() const override
Definition: Generator.h:794
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:798
GeneratorParam_Bool(const std::string &name, const T &value)
Definition: Generator.h:778
std::string get_c_type() const override
Definition: Generator.h:804
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:830
std::string get_default_value() const override
Definition: Generator.h:838
GeneratorParam_Enum(const std::string &name, const T &value, const std::map< std::string, T > &enum_map)
Definition: Generator.h:812
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:824
std::string get_c_type() const override
Definition: Generator.h:834
std::string get_type_decls() const override
Definition: Generator.h:842
GeneratorParam_LoopLevel(const std::string &name, const LoopLevel &value)
Definition: Generator.h:627
std::string get_c_type() const override
Definition: Generator.h:690
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:685
bool is_looplevel_param() const override
Definition: Generator.h:694
void set(const LoopLevel &value) override
Definition: Generator.h:633
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:653
std::string get_default_value() const override
Definition: Generator.h:663
GeneratorParam_MachineParams(const std::string &name, const T &value)
Definition: Generator.h:602
std::string get_c_type() const override
Definition: Generator.h:620
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:614
std::string get_default_value() const override
Definition: Generator.h:610
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:606
GeneratorParam_String(const std::string &name, const std::string &value)
Definition: Generator.h:895
std::string get_c_type() const override
Definition: Generator.h:910
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:898
std::string get_default_value() const override
Definition: Generator.h:902
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:906
bool is_synthetic_param() const override
Definition: Generator.h:2850
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:2840
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:2826
std::string get_default_value() const override
Definition: Generator.h:2835
std::string get_c_type() const override
Definition: Generator.h:2845
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:580
GeneratorParam_Target(const std::string &name, const T &value)
Definition: Generator.h:576
std::string get_c_type() const override
Definition: Generator.h:594
std::string get_default_value() const override
Definition: Generator.h:584
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:588
std::string get_type_decls() const override
Definition: Generator.h:887
std::string get_c_type() const override
Definition: Generator.h:879
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:875
std::string get_default_value() const override
Definition: Generator.h:883
GeneratorParam_Type(const std::string &name, const T &value)
Definition: Generator.h:871
const std::string & name() const
Definition: Generator.h:364
virtual bool is_synthetic_param() const
Definition: Generator.h:425
GeneratorParamBase(GeneratorParamBase &&)=delete
GeneratorParamBase & operator=(const GeneratorParamBase &)=delete
virtual std::string call_to_string(const std::string &v) const =0
void fail_wrong_type(const char *type)
GeneratorParamBase & operator=(GeneratorParamBase &&)=delete
virtual std::string get_type_decls() const
Definition: Generator.h:419
GeneratorParamBase(const std::string &name)
virtual std::string get_default_value() const =0
void set(const std::string &new_value)
Definition: Generator.h:398
GeneratorParamBase(const GeneratorParamBase &)=delete
virtual std::string get_c_type() const =0
virtual bool is_looplevel_param() const
Definition: Generator.h:429
virtual void set_from_string(const std::string &value_string)=0
void set(const char *new_value)
Definition: Generator.h:401
void set(const std::string &new_value)
Definition: Generator.h:512
GeneratorParamImpl(const std::string &name, const T &value)
Definition: Generator.h:471
virtual void set_impl(const T &new_value)
Definition: Generator.h:518
const std::vector< Internal::GeneratorParamBase * > & generator_params() const
Definition: Generator.h:3097
const std::vector< Internal::GeneratorInputBase * > & inputs() const
Definition: Generator.h:3100
GeneratorParamInfo(GeneratorBase *generator, size_t size)
const std::vector< Internal::GeneratorOutputBase * > & outputs() const
Definition: Generator.h:3103
GeneratorRegistry & operator=(const GeneratorRegistry &)=delete
GeneratorRegistry(const GeneratorRegistry &)=delete
static std::unique_ptr< GeneratorBase > create(const std::string &name, const Halide::GeneratorContext &context)
GeneratorRegistry(GeneratorRegistry &&that)=delete
GeneratorRegistry & operator=(GeneratorRegistry &&that)=delete
static std::vector< std::string > enumerate()
static void register_factory(const std::string &name, GeneratorFactory generator_factory)
static void unregister_factory(const std::string &name)
static std::vector< StubInput > to_stub_input_vector(const Expr &e)
Definition: Generator.h:3971
std::vector< std::vector< Func > > generate(const GeneratorParamsMap &generator_params, const std::vector< std::vector< Internal::StubInput >> &inputs)
GeneratorStub(const GeneratorContext &context, const GeneratorFactory &generator_factory, const GeneratorParamsMap &generator_params, const std::vector< std::vector< Internal::StubInput >> &inputs)
std::vector< Func > get_outputs(const std::string &n) const
Definition: Generator.h:3957
static std::vector< StubInput > to_stub_input_vector(const Func &f)
Definition: Generator.h:3975
std::shared_ptr< GeneratorBase > generator
Definition: Generator.h:3996
GeneratorStub(const GeneratorContext &context, const GeneratorFactory &generator_factory)
static std::vector< StubInput > to_stub_input_vector(const StubInputBuffer< T > &b)
Definition: Generator.h:3980
std::vector< T2 > get_output_buffers(const std::string &n) const
Definition: Generator.h:3962
static std::vector< StubInput > to_stub_input_vector(const std::vector< T > &v)
Definition: Generator.h:3985
A reference-counted handle to a parameter to a halide pipeline.
Definition: Parameter.h:28
void set_buffer(const Buffer< void > &b)
If the parameter is a buffer parameter, set its current value.
HALIDE_NO_USER_CODE_INLINE void set_scalar(T val)
If the parameter is a scalar parameter, set its current value.
Definition: Parameter.h:90
void set_default_value(const Expr &e)
Get and set the default values for scalar parameters.
Type type() const
Get the type of this parameter.
void set_min_value(const Expr &e)
Get and set constraints for scalar parameters.
int dimensions() const
Get the dimensionality of this parameter.
void set_max_value(const Expr &e)
RegisterGenerator(const char *registered_name, GeneratorFactory generator_factory)
StubInputBuffer is the placeholder that a Stub uses when it requires a Buffer for an input (rather th...
Definition: Generator.h:1240
StubInputBuffer(const Buffer< T2, D2 > &b)
Definition: Generator.h:1273
StubInput(const StubInputBuffer< T2 > &b)
Definition: Generator.h:1344
StubInput(const Expr &e)
Definition: Generator.h:1350
StubInput(const Func &f)
Definition: Generator.h:1347
Realization realize(Args &&...args)
Definition: Generator.h:1293
StubOutputBufferBase(const Func &f, const std::shared_ptr< GeneratorBase > &generator)
std::shared_ptr< GeneratorBase > generator
Definition: Generator.h:1281
void check_scheduled(const char *m) const
Realization realize(std::vector< int32_t > sizes)
StubOutputBuffer is the placeholder that a Stub uses when it requires a Buffer for an output (rather ...
Definition: Generator.h:1318
A reference to a site in a Halide statement at the top of the body of a particular for loop.
Definition: Schedule.h:176
static LoopLevel root()
Construct a special LoopLevel value which represents the location outside of all for loops.
static LoopLevel inlined()
Construct a special LoopLevel value that implies that a function should be inlined away.
void set(const LoopLevel &other)
Mutate our contents to match the contents of 'other'.
bool is_root() const
bool is_inlined() const
LoopLevel & lock()
A halide module.
Definition: Module.h:172
Halide::Target Target
Definition: Generator.h:3004
static Type Bool(int lanes=1)
Definition: Generator.h:3021
static Expr cast(Expr e)
Definition: Generator.h:3009
static Expr cast(Halide::Type t, Expr e)
Definition: Generator.h:3012
static Type UInt(int bits, int lanes=1)
Definition: Generator.h:3030
static Type Int(int bits, int lanes=1)
Definition: Generator.h:3027
static Type Float(int bits, int lanes=1)
Definition: Generator.h:3024
Halide::Pipeline Pipeline
Definition: Generator.h:2999
A handle on the output buffer of a pipeline.
A scalar parameter to a halide pipeline.
Definition: Param.h:22
A class representing a Halide pipeline.
Definition: Pipeline.h:99
void add_requirement(const Expr &condition, std::vector< Expr > &error)
Add a top-level precondition to the generated pipeline, expressed as a boolean Expr.
void trace_pipeline()
Generate begin_pipeline and end_pipeline tracing calls for this pipeline.
Realization realize(std::vector< int32_t > sizes={}, const Target &target=Target(), const ParamMap &param_map=ParamMap::empty_map())
See Func::realize.
A multi-dimensional domain over which to iterate.
Definition: RDom.h:193
A reduction variable represents a single dimension of a reduction domain (RDom).
Definition: RDom.h:29
A Realization is a vector of references to existing Buffer objects.
Definition: Realization.h:19
A single definition of a Func.
Definition: Func.h:70
Create a small array of Exprs for defining and calling functions with multiple outputs.
Definition: Tuple.h:18
A Halide variable, to be used when defining functions.
Definition: Var.h:19
auto max_forward(const Other &a, const GeneratorParam< T > &b) -> decltype(max(a,(T) b))
Definition: Generator.h:1178
auto min_forward(const Other &a, const GeneratorParam< T > &b) -> decltype(min(a,(T) b))
Definition: Generator.h:1169
const void * get_introspection_helper()
Return the address of a global with type T *.
Definition: Introspection.h:50
std::string halide_type_to_enum_string(const Type &t)
Definition: Generator.h:313
typename select_type< cond< std::is_same< T, Target >::value, GeneratorParam_Target< T > >, cond< std::is_same< T, MachineParams >::value, GeneratorParam_MachineParams< T > >, cond< std::is_same< T, LoopLevel >::value, GeneratorParam_LoopLevel >, cond< std::is_same< T, std::string >::value, GeneratorParam_String< T > >, cond< std::is_same< T, Type >::value, GeneratorParam_Type< T > >, cond< std::is_same< T, bool >::value, GeneratorParam_Bool< T > >, cond< std::is_arithmetic< T >::value, GeneratorParam_Arithmetic< T > >, cond< std::is_enum< T >::value, GeneratorParam_Enum< T > >>::type GeneratorParamImplBase
Definition: Generator.h:925
Expr make_const(Type t, int64_t val)
Construct an immediate of the given type from any numeric C++ type.
std::string halide_type_to_c_source(const Type &t)
std::function< std::unique_ptr< GeneratorBase >(const GeneratorContext &)> GeneratorFactory
Definition: Generator.h:3052
std::vector< Type > parse_halide_type_list(const std::string &types)
HALIDE_NO_USER_CODE_INLINE std::string enum_to_string(const std::map< std::string, T > &enum_map, const T &t)
Definition: Generator.h:295
std::map< std::string, StringOrLoopLevel > GeneratorParamsMap
Definition: Generator.h:3069
std::string halide_type_to_c_type(const Type &t)
std::vector< Expr > parameter_constraints(const Parameter &p)
std::string print_loop_nest(const std::vector< Function > &output_funcs)
Emit some simple pseudocode that shows the structure of the loop nest specified by this pipeline's sc...
typename select_type< cond< has_static_halide_type_method< TBase >::value, GeneratorOutput_Buffer< T > >, cond< std::is_same< TBase, Func >::value, GeneratorOutput_Func< T > >, cond< std::is_arithmetic< TBase >::value, GeneratorOutput_Arithmetic< T > >>::type GeneratorOutputImplBase
Definition: Generator.h:2715
typename select_type< cond< has_static_halide_type_method< TBase >::value, GeneratorInput_Buffer< T > >, cond< std::is_same< TBase, Func >::value, GeneratorInput_Func< T > >, cond< std::is_arithmetic< TBase >::value, GeneratorInput_Arithmetic< T > >, cond< std::is_scalar< TBase >::value, GeneratorInput_Scalar< T > >, cond< std::is_same< TBase, Expr >::value, GeneratorInput_DynamicScalar< T > >>::type GeneratorInputImplBase
Definition: Generator.h:2115
int generate_filter_main(int argc, char **argv, std::ostream &cerr)
generate_filter_main() is a convenient wrapper for GeneratorRegistry::create() + compile_to_files(); ...
T parse_scalar(const std::string &value)
Definition: Generator.h:2807
const std::map< std::string, Halide::Type > & get_halide_type_enum_map()
T enum_from_string(const std::map< std::string, T > &enum_map, const std::string &s)
Definition: Generator.h:306
constexpr int AnyDims
Definition: HalideBuffer.h:113
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
auto operator>=(const Other &a, const GeneratorParam< T > &b) -> decltype(a >=(T) b)
Greater than or equal comparison between GeneratorParam<T> and any type that supports operator>= with...
Definition: Generator.h:1076
Target get_host_target()
Return the target corresponding to the host machine.
Type UInt(int bits, int lanes=1)
Constructing an unsigned integer type.
Definition: Type.h:521
Expr reinterpret(Type t, Expr e)
Reinterpret the bits of one value as another type.
Type Float(int bits, int lanes=1)
Construct a floating-point type.
Definition: Type.h:526
auto operator==(const Other &a, const GeneratorParam< T > &b) -> decltype(a==(T) b)
Equality comparison between GeneratorParam<T> and any type that supports operator== with T.
Definition: Generator.h:1102
LinkageType
Type of linkage a function in a lowered Halide module can have.
Definition: Module.h:84
@ ExternalPlusMetadata
Visible externally. Argument metadata and an argv wrapper are also generated.
@ Internal
Not visible externally, similar to 'static' linkage in C.
class HALIDE_ATTRIBUTE_DEPRECATED("Use OutputFileType instead of Output") Output
Definition: Module.h:46
auto operator<(const Other &a, const GeneratorParam< T > &b) -> decltype(a<(T) b)
Less than comparison between GeneratorParam<T> and any type that supports operator< with T.
Definition: Generator.h:1063
auto operator*(const Other &a, const GeneratorParam< T > &b) -> decltype(a *(T) b)
Multiplication between GeneratorParam<T> and any type that supports operator* with T.
Definition: Generator.h:1011
auto operator||(const Other &a, const GeneratorParam< T > &b) -> decltype(a||(T) b)
Logical or between between GeneratorParam<T> and any type that supports operator|| with T.
Definition: Generator.h:1145
PrefetchBoundStrategy
Different ways to handle accesses outside the original extents in a prefetch.
auto min(const GeneratorParam< T > &a, const Other &b) -> decltype(Internal::GeneratorMinMax::min_forward(a, b))
Definition: Generator.h:1197
auto operator-(const Other &a, const GeneratorParam< T > &b) -> decltype(a -(T) b)
Subtraction between GeneratorParam<T> and any type that supports operator- with T.
Definition: Generator.h:998
Expr cast(Expr a)
Cast an expression to the halide type corresponding to the C++ type T.
Definition: IROperator.h:392
auto operator!(const GeneratorParam< T > &a) -> decltype(!(T) a)
Not operator for GeneratorParam.
Definition: Generator.h:1217
TailStrategy
Different ways to handle a tail case in a split when the factor does not provably divide the extent.
Definition: Schedule.h:32
Type Int(int bits, int lanes=1)
Constructing a signed integer type.
Definition: Type.h:516
auto operator+(const Other &a, const GeneratorParam< T > &b) -> decltype(a+(T) b)
Addition between GeneratorParam<T> and any type that supports operator+ with T.
Definition: Generator.h:985
Expr min(const FuncRef &a, const FuncRef &b)
Explicit overloads of min and max for FuncRef.
Definition: Func.h:600
auto operator&&(const Other &a, const GeneratorParam< T > &b) -> decltype(a &&(T) b)
Logical and between between GeneratorParam<T> and any type that supports operator&& with T.
Definition: Generator.h:1128
auto operator%(const Other &a, const GeneratorParam< T > &b) -> decltype(a %(T) b)
Modulo between GeneratorParam<T> and any type that supports operator% with T.
Definition: Generator.h:1037
NameMangling
An enum to specify calling convention for extern stages.
Definition: Function.h:24
Target get_jit_target_from_environment()
Return the target that Halide will use for jit-compilation.
auto operator<=(const Other &a, const GeneratorParam< T > &b) -> decltype(a<=(T) b)
Less than or equal comparison between GeneratorParam<T> and any type that supports operator<= with T.
Definition: Generator.h:1089
Target get_target_from_environment()
Return the target that Halide will use.
auto operator>(const Other &a, const GeneratorParam< T > &b) -> decltype(a >(T) b)
Greater than comparison between GeneratorParam<T> and any type that supports operator> with T.
Definition: Generator.h:1050
auto operator!=(const Other &a, const GeneratorParam< T > &b) -> decltype(a !=(T) b)
Inequality comparison between between GeneratorParam<T> and any type that supports operator!...
Definition: Generator.h:1115
Type Bool(int lanes=1)
Construct a boolean type.
Definition: Type.h:536
std::vector< Range > Region
A multi-dimensional box.
Definition: Expr.h:343
auto operator/(const Other &a, const GeneratorParam< T > &b) -> decltype(a/(T) b)
Division between GeneratorParam<T> and any type that supports operator/ with T.
Definition: Generator.h:1024
Expr max(const FuncRef &a, const FuncRef &b)
Definition: Func.h:603
auto max(const GeneratorParam< T > &a, const Other &b) -> decltype(Internal::GeneratorMinMax::max_forward(a, b))
Definition: Generator.h:1210
MemoryType
An enum describing different address spaces to be used with Func::store_in.
Definition: Expr.h:346
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 fragment of Halide syntax.
Definition: Expr.h:256
An argument to an extern-defined Func.
static TO2 value(const FROM &from)
Definition: Generator.h:456
std::vector< std::string > inputs
Definition: Generator.h:3992
std::vector< std::string > outputs
Definition: Generator.h:3992
std::vector< std::string > generator_params
Definition: Generator.h:3992
HALIDE_ALWAYS_INLINE bool defined() const
Definition: IntrusivePtr.h:161
StringOrLoopLevel(const LoopLevel &loop_level)
Definition: Generator.h:3065
StringOrLoopLevel(const std::string &s)
Definition: Generator.h:3062
static constexpr bool value
Definition: Generator.h:346
typename std::conditional< First::value, typename First::type, void >::type type
Definition: Generator.h:354
A struct representing the machine parameters to generate the auto-scheduled code for.
Definition: Pipeline.h:33
static MachineParams generic()
Default machine parameters for generic CPU architecture.
A struct representing a target machine and os to generate code for.
Definition: Target.h:19
int natural_vector_size(const Halide::Type &t) const
Given a data type, return an estimate of the "natural" vector size for that data type when compiling ...
Types in the halide type system.
Definition: Type.h:266