Halide  20.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 two GeneratorParams that are implicitly provided
212  * by the base class:
213  *
214  * GeneratorParam<Target> target{"target", Target()};
215  * GeneratorParam<AutoschedulerParams> autoscheduler{"autoscheduler", {}}
216  *
217  * - 'target' is the Halide::Target for which the Generator is producing code.
218  * It is read-only during the Generator's lifetime, and must not be modified;
219  * its value should always be filled in by the calling code: either the Halide
220  * build system (for ahead-of-time compilation), or ordinary C++ code
221  * (for JIT compilation).
222  * - 'autoscheduler' is a string-to-string map that is used to indicates whether
223  * and how an auto-scheduler should be run for this Generator:
224  * - if empty, the Generator should schedule its Funcs as it sees fit; no autoscheduler will be run.
225  * - if the 'name' key is set, it should be one of the known autoschedulers
226  * provided with this release of Halide, which will be used to schedule
227  * the Funcs in the Generator. In this case, the Generator should only
228  * provide estimate()s for its Funcs, and not call any other scheduling methods.
229  * - Other keys may be specified in the params, on a per-autoscheduler
230  * basis, to optimize or enhance the automatically-generated schedule.
231  * See documentation for each autoscheduler for options.
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 "AbstractGenerator.h"
275 #include "Func.h"
276 #include "ImageParam.h"
277 #include "ObjectInstanceRegistry.h"
278 #include "Target.h"
279 
280 #if !(__cplusplus >= 201703L || _MSVC_LANG >= 201703L)
281 #error "Halide requires C++17 or later; please upgrade your compiler."
282 #endif
283 
284 namespace Halide {
285 
286 class GeneratorContext;
287 
288 namespace Internal {
289 
291 
292 class GeneratorBase;
293 
294 std::vector<Expr> parameter_constraints(const Parameter &p);
295 
296 template<typename T>
297 HALIDE_NO_USER_CODE_INLINE std::string enum_to_string(const std::map<std::string, T> &enum_map, const T &t) {
298  for (const auto &key_value : enum_map) {
299  if (t == key_value.second) {
300  return key_value.first;
301  }
302  }
303  user_error << "Enumeration value not found.\n";
304  return "";
305 }
306 
307 template<typename T>
308 T enum_from_string(const std::map<std::string, T> &enum_map, const std::string &s) {
309  auto it = enum_map.find(s);
310  user_assert(it != enum_map.end()) << "Enumeration value not found: " << s << "\n";
311  return it->second;
312 }
313 
314 extern const std::map<std::string, Halide::Type> &get_halide_type_enum_map();
315 inline std::string halide_type_to_enum_string(const Type &t) {
317 }
318 
319 // Convert a Halide Type into a string representation of its C source.
320 // e.g., Int(32) -> "Halide::Int(32)"
321 std::string halide_type_to_c_source(const Type &t);
322 
323 // Convert a Halide Type into a string representation of its C Source.
324 // e.g., Int(32) -> "int32_t"
325 std::string halide_type_to_c_type(const Type &t);
326 
327 /** GeneratorFactoryProvider provides a way to customize the Generators
328  * that are visible to generate_filter_main (which otherwise would just
329  * look at the global registry of C++ Generators). */
331 public:
333  virtual ~GeneratorFactoryProvider() = default;
334 
335  /** Return a list of all registered Generators that are available for use
336  * with the create() method. */
337  virtual std::vector<std::string> enumerate() const = 0;
338 
339  /** Create an instance of the Generator that is registered under the given
340  * name. If the name isn't one returned by enumerate(), return nullptr
341  * rather than assert-fail; caller must check for a valid result. */
342  virtual AbstractGeneratorPtr create(const std::string &name,
343  const Halide::GeneratorContext &context) const = 0;
344 
349 };
350 
351 /** Return a GeneratorFactoryProvider that knows about all the currently-registered C++ Generators. */
353 
354 /** generate_filter_main() is a convenient wrapper for GeneratorRegistry::create() +
355  * compile_to_files(); it can be trivially wrapped by a "real" main() to produce a
356  * command-line utility for ahead-of-time filter compilation. */
357 int generate_filter_main(int argc, char **argv);
358 
359 /** This overload of generate_filter_main lets you provide your own provider for how to enumerate and/or create
360  * the generators based on registration name; this is useful if you want to re-use the
361  * 'main' logic but avoid the global Generator registry (e.g. for bindings in languages
362  * other than C++). */
363 int generate_filter_main(int argc, char **argv, const GeneratorFactoryProvider &generator_factory_provider);
364 
365 // select_type<> is to std::conditional as switch is to if:
366 // it allows a multiway compile-time type definition via the form
367 //
368 // select_type<cond<condition1, type1>,
369 // cond<condition2, type2>,
370 // ....
371 // cond<conditionN, typeN>>::type
372 //
373 // Note that the conditions are evaluated in order; the first evaluating to true
374 // is chosen.
375 //
376 // Note that if no conditions evaluate to true, the resulting type is illegal
377 // and will produce a compilation error. (You can provide a default by simply
378 // using cond<true, SomeType> as the final entry.)
379 template<bool B, typename T>
380 struct cond {
381  static constexpr bool value = B;
382  using type = T;
383 };
384 
385 template<typename First, typename... Rest>
386 struct select_type : std::conditional<First::value, typename First::type, typename select_type<Rest...>::type> {};
387 
388 template<typename First>
389 struct select_type<First> {
390  using type = typename std::conditional<First::value, typename First::type, void>::type;
391 };
392 
393 class GeneratorParamInfo;
394 
396 public:
397  explicit GeneratorParamBase(const std::string &name);
399 
400  const std::string &name() const {
401  return name_;
402  }
403 
404  // overload the set() function to call the right virtual method based on type.
405  // This allows us to attempt to set a GeneratorParam via a
406  // plain C++ type, even if we don't know the specific templated
407  // subclass. Attempting to set the wrong type will assert.
408  // Notice that there is no typed setter for Enums, for obvious reasons;
409  // setting enums in an unknown type must fallback to using set_from_string.
410  //
411  // It's always a bit iffy to use macros for this, but IMHO it clarifies the situation here.
412 #define HALIDE_GENERATOR_PARAM_TYPED_SETTER(TYPE) \
413  virtual void set(const TYPE &new_value) = 0;
414 
430 
431 #undef HALIDE_GENERATOR_PARAM_TYPED_SETTER
432 
433  // Add overloads for string and char*
434  void set(const std::string &new_value) {
435  set_from_string(new_value);
436  }
437  void set(const char *new_value) {
438  set_from_string(std::string(new_value));
439  }
440 
441 protected:
442  friend class GeneratorBase;
443  friend class GeneratorParamInfo;
444  friend class StubEmitter;
445 
446  void check_value_readable() const;
447  void check_value_writable() const;
448 
449  // All GeneratorParams are settable from string.
450  virtual void set_from_string(const std::string &value_string) = 0;
451 
452  virtual std::string call_to_string(const std::string &v) const = 0;
453  virtual std::string get_c_type() const = 0;
454 
455  virtual std::string get_type_decls() const {
456  return "";
457  }
458 
459  virtual std::string get_default_value() const = 0;
460 
461  virtual bool is_synthetic_param() const {
462  return false;
463  }
464 
465  virtual bool is_looplevel_param() const {
466  return false;
467  }
468 
469  void fail_wrong_type(const char *type);
470 
471 private:
472  const std::string name_;
473 
474  // Generator which owns this GeneratorParam. Note that this will be null
475  // initially; the GeneratorBase itself will set this field when it initially
476  // builds its info about params. However, since it (generally) isn't
477  // appropriate for GeneratorParam<> to be declared outside of a Generator,
478  // all reasonable non-testing code should expect this to be non-null.
479  GeneratorBase *generator{nullptr};
480 
481 public:
486 };
487 
488 // This is strictly some syntactic sugar to suppress certain compiler warnings.
489 template<typename FROM, typename TO>
490 struct Convert {
491  template<typename TO2 = TO, typename std::enable_if<!std::is_same<TO2, bool>::value>::type * = nullptr>
492  static TO2 value(const FROM &from) {
493  return static_cast<TO2>(from);
494  }
495 
496  template<typename TO2 = TO, typename std::enable_if<std::is_same<TO2, bool>::value>::type * = nullptr>
497  static TO2 value(const FROM &from) {
498  return from != 0;
499  }
500 };
501 
502 template<typename T>
504 public:
505  using type = T;
506 
507  GeneratorParamImpl(const std::string &name, const T &value)
509  }
510 
511  T value() const {
512  this->check_value_readable();
513  return value_;
514  }
515 
516  operator T() const {
517  return this->value();
518  }
519 
520  operator Expr() const {
521  return make_const(type_of<T>(), this->value());
522  }
523 
524 #define HALIDE_GENERATOR_PARAM_TYPED_SETTER(TYPE) \
525  void set(const TYPE &new_value) override { \
526  typed_setter_impl<TYPE>(new_value, #TYPE); \
527  }
528 
541  HALIDE_GENERATOR_PARAM_TYPED_SETTER(AutoschedulerParams)
544 
545 #undef HALIDE_GENERATOR_PARAM_TYPED_SETTER
546 
547  // Overload for std::string.
548  void set(const std::string &new_value) {
550  value_ = new_value;
551  }
552 
553 protected:
554  virtual void set_impl(const T &new_value) {
556  value_ = new_value;
557  }
558 
559  // Needs to be protected to allow GeneratorParam<LoopLevel>::set() override
561 
562 private:
563  // If FROM->T is not legal, fail
564  template<typename FROM, typename std::enable_if<
565  !std::is_convertible<FROM, T>::value>::type * = nullptr>
566  HALIDE_ALWAYS_INLINE void typed_setter_impl(const FROM &, const char *msg) {
567  fail_wrong_type(msg);
568  }
569 
570  // If FROM and T are identical, just assign
571  template<typename FROM, typename std::enable_if<
572  std::is_same<FROM, T>::value>::type * = nullptr>
573  HALIDE_ALWAYS_INLINE void typed_setter_impl(const FROM &value, const char *msg) {
575  value_ = value;
576  }
577 
578  // If both FROM->T and T->FROM are legal, ensure it's lossless
579  template<typename FROM, typename std::enable_if<
580  !std::is_same<FROM, T>::value &&
581  std::is_convertible<FROM, T>::value &&
582  std::is_convertible<T, FROM>::value>::type * = nullptr>
583  HALIDE_ALWAYS_INLINE void typed_setter_impl(const FROM &value, const char *msg) {
585  const T t = Convert<FROM, T>::value(value);
586  const FROM value2 = Convert<T, FROM>::value(t);
587  if (value2 != value) {
588  fail_wrong_type(msg);
589  }
590  value_ = t;
591  }
592 
593  // If FROM->T is legal but T->FROM is not, just assign
594  template<typename FROM, typename std::enable_if<
595  !std::is_same<FROM, T>::value &&
596  std::is_convertible<FROM, T>::value &&
597  !std::is_convertible<T, FROM>::value>::type * = nullptr>
598  HALIDE_ALWAYS_INLINE void typed_setter_impl(const FROM &value, const char *msg) {
600  value_ = value;
601  }
602 };
603 
604 // Stubs for type-specific implementations of GeneratorParam, to avoid
605 // many complex enable_if<> statements that were formerly spread through the
606 // implementation. Note that not all of these need to be templated classes,
607 // (e.g. for GeneratorParam_Target, T == Target always), but are declared
608 // that way for symmetry of declaration.
609 template<typename T>
611 public:
612  GeneratorParam_Target(const std::string &name, const T &value)
613  : GeneratorParamImpl<T>(name, value) {
614  }
615 
616  void set_from_string(const std::string &new_value_string) override {
617  this->set(Target(new_value_string));
618  }
619 
620  std::string get_default_value() const override {
621  return this->value().to_string();
622  }
623 
624  std::string call_to_string(const std::string &v) const override {
625  std::ostringstream oss;
626  oss << v << ".to_string()";
627  return oss.str();
628  }
629 
630  std::string get_c_type() const override {
631  return "Target";
632  }
633 };
634 
635 class GeneratorParam_AutoSchedulerParams : public GeneratorParamImpl<AutoschedulerParams> {
636 public:
638 
639  void set_from_string(const std::string &new_value_string) override;
640  std::string get_default_value() const override;
641  std::string call_to_string(const std::string &v) const override;
642  std::string get_c_type() const override;
643 
644 private:
645  friend class GeneratorBase;
646 
647  bool try_set(const std::string &key, const std::string &value);
648 };
649 
650 class GeneratorParam_LoopLevel : public GeneratorParamImpl<LoopLevel> {
651 public:
652  GeneratorParam_LoopLevel(const std::string &name, const LoopLevel &value)
654  }
655 
657 
658  void set(const LoopLevel &value) override {
659  // Don't call check_value_writable(): It's OK to set a LoopLevel after generate().
660  // check_value_writable();
661 
662  // This looks odd, but is deliberate:
663 
664  // First, mutate the existing contents to match the value passed in,
665  // so that any existing usage of the LoopLevel now uses the newer value.
666  // (Strictly speaking, this is really only necessary if this method
667  // is called after generate(): before generate(), there is no usage
668  // to be concerned with.)
669  value_.set(value);
670 
671  // Then, reset the value itself so that it points to the same LoopLevelContents
672  // as the value passed in. (Strictly speaking, this is really only
673  // useful if this method is called before generate(): afterwards, it's
674  // too late to alter the code to refer to a different LoopLevelContents.)
675  value_ = value;
676  }
677 
678  void set_from_string(const std::string &new_value_string) override {
679  if (new_value_string == "root") {
680  this->set(LoopLevel::root());
681  } else if (new_value_string == "inlined") {
682  this->set(LoopLevel::inlined());
683  } else {
684  user_error << "Unable to parse " << this->name() << ": " << new_value_string;
685  }
686  }
687 
688  std::string get_default_value() const override {
689  // This is dodgy but safe in this case: we want to
690  // see what the value of our LoopLevel is *right now*,
691  // so we make a copy and lock the copy so we can inspect it.
692  // (Note that ordinarily this is a bad idea, since LoopLevels
693  // can be mutated later on; however, this method is only
694  // called by the Generator infrastructure, on LoopLevels that
695  // will never be mutated, so this is really just an elaborate way
696  // to avoid runtime assertions.)
697  LoopLevel copy;
698  copy.set(this->value());
699  copy.lock();
700  if (copy.is_inlined()) {
701  return "LoopLevel::inlined()";
702  } else if (copy.is_root()) {
703  return "LoopLevel::root()";
704  } else {
706  return "";
707  }
708  }
709 
710  std::string call_to_string(const std::string &v) const override {
712  return std::string();
713  }
714 
715  std::string get_c_type() const override {
716  return "LoopLevel";
717  }
718 
719  bool is_looplevel_param() const override {
720  return true;
721  }
722 };
723 
724 template<typename T>
726 public:
727  GeneratorParam_Arithmetic(const std::string &name,
728  const T &value,
729  const T &min = std::numeric_limits<T>::lowest(),
730  const T &max = std::numeric_limits<T>::max())
731  : GeneratorParamImpl<T>(name, value), min(min), max(max) {
732  // call set() to ensure value is clamped to min/max
733  this->set(value);
734  }
735 
736  void set_impl(const T &new_value) override {
737  user_assert(new_value >= min && new_value <= max) << "Value out of range: " << new_value;
739  }
740 
741  void set_from_string(const std::string &new_value_string) override {
742  std::istringstream iss(new_value_string);
743  T t;
744  // All one-byte ints int8 and uint8 should be parsed as integers, not chars --
745  // including 'char' itself. (Note that sizeof(bool) is often-but-not-always-1,
746  // so be sure to exclude that case.)
747  if (sizeof(T) == sizeof(char) && !std::is_same<T, bool>::value) {
748  int i;
749  iss >> i;
750  t = (T)i;
751  } else {
752  iss >> t;
753  }
754  user_assert(!iss.fail() && iss.get() == EOF) << "Unable to parse: " << new_value_string;
755  this->set(t);
756  }
757 
758  std::string get_default_value() const override {
759  std::ostringstream oss;
760  oss << this->value();
761  if (std::is_same<T, float>::value) {
762  // If the constant has no decimal point ("1")
763  // we must append one before appending "f"
764  if (oss.str().find('.') == std::string::npos) {
765  oss << ".";
766  }
767  oss << "f";
768  }
769  return oss.str();
770  }
771 
772  std::string call_to_string(const std::string &v) const override {
773  std::ostringstream oss;
774  oss << "std::to_string(" << v << ")";
775  return oss.str();
776  }
777 
778  std::string get_c_type() const override {
779  std::ostringstream oss;
780  if (std::is_same<T, float>::value) {
781  return "float";
782  } else if (std::is_same<T, double>::value) {
783  return "double";
784  } else if (std::is_integral<T>::value) {
785  if (std::is_unsigned<T>::value) {
786  oss << "u";
787  }
788  oss << "int" << (sizeof(T) * 8) << "_t";
789  return oss.str();
790  } else {
791  user_error << "Unknown arithmetic type\n";
792  return "";
793  }
794  }
795 
796 private:
797  const T min, max;
798 };
799 
800 template<typename T>
802 public:
803  GeneratorParam_Bool(const std::string &name, const T &value)
805  }
806 
807  void set_from_string(const std::string &new_value_string) override {
808  bool v = false;
809  if (new_value_string == "true" || new_value_string == "True") {
810  v = true;
811  } else if (new_value_string == "false" || new_value_string == "False") {
812  v = false;
813  } else {
814  user_assert(false) << "Unable to parse bool: " << new_value_string;
815  }
816  this->set(v);
817  }
818 
819  std::string get_default_value() const override {
820  return this->value() ? "true" : "false";
821  }
822 
823  std::string call_to_string(const std::string &v) const override {
824  std::ostringstream oss;
825  oss << "std::string((" << v << ") ? \"true\" : \"false\")";
826  return oss.str();
827  }
828 
829  std::string get_c_type() const override {
830  return "bool";
831  }
832 };
833 
834 template<typename T>
836 public:
837  GeneratorParam_Enum(const std::string &name, const T &value, const std::map<std::string, T> &enum_map)
838  : GeneratorParamImpl<T>(name, value), enum_map(enum_map) {
839  }
840 
841  // define a "set" that takes our specific enum (but don't hide the inherited virtual functions)
843 
844  template<typename T2 = T, typename std::enable_if<!std::is_same<T2, Type>::value>::type * = nullptr>
845  void set(const T &e) {
846  this->set_impl(e);
847  }
848 
849  void set_from_string(const std::string &new_value_string) override {
850  auto it = enum_map.find(new_value_string);
851  user_assert(it != enum_map.end()) << "Enumeration value not found: " << new_value_string;
852  this->set_impl(it->second);
853  }
854 
855  std::string call_to_string(const std::string &v) const override {
856  return "Enum_" + this->name() + "_map().at(" + v + ")";
857  }
858 
859  std::string get_c_type() const override {
860  return "Enum_" + this->name();
861  }
862 
863  std::string get_default_value() const override {
864  return "Enum_" + this->name() + "::" + enum_to_string(enum_map, this->value());
865  }
866 
867  std::string get_type_decls() const override {
868  std::ostringstream oss;
869  oss << "enum class Enum_" << this->name() << " {\n";
870  for (auto key_value : enum_map) {
871  oss << " " << key_value.first << ",\n";
872  }
873  oss << "};\n";
874  oss << "\n";
875 
876  // TODO: since we generate the enums, we could probably just use a vector (or array!) rather than a map,
877  // since we can ensure that the enum values are a nice tight range.
878  oss << "inline HALIDE_NO_USER_CODE_INLINE const std::map<Enum_" << this->name() << ", std::string>& Enum_" << this->name() << "_map() {\n";
879  oss << " static const std::map<Enum_" << this->name() << ", std::string> m = {\n";
880  for (auto key_value : enum_map) {
881  oss << " { Enum_" << this->name() << "::" << key_value.first << ", \"" << key_value.first << "\"},\n";
882  }
883  oss << " };\n";
884  oss << " return m;\n";
885  oss << "};\n";
886  return oss.str();
887  }
888 
889 private:
890  const std::map<std::string, T> enum_map;
891 };
892 
893 template<typename T>
895 public:
896  GeneratorParam_Type(const std::string &name, const T &value)
898  }
899 
900  std::string call_to_string(const std::string &v) const override {
901  return "Halide::Internal::halide_type_to_enum_string(" + v + ")";
902  }
903 
904  std::string get_c_type() const override {
905  return "Type";
906  }
907 
908  std::string get_default_value() const override {
909  return halide_type_to_c_source(this->value());
910  }
911 
912  std::string get_type_decls() const override {
913  return "";
914  }
915 };
916 
917 template<typename T>
919 public:
920  GeneratorParam_String(const std::string &name, const std::string &value)
921  : GeneratorParamImpl<T>(name, value) {
922  }
923  void set_from_string(const std::string &new_value_string) override {
924  this->set(new_value_string);
925  }
926 
927  std::string get_default_value() const override {
928  return "\"" + this->value() + "\"";
929  }
930 
931  std::string call_to_string(const std::string &v) const override {
932  return v;
933  }
934 
935  std::string get_c_type() const override {
936  return "std::string";
937  }
938 };
939 
940 template<typename T>
942  typename select_type<
950 
951 } // namespace Internal
952 
953 /** GeneratorParam is a templated class that can be used to modify the behavior
954  * of the Generator at code-generation time. GeneratorParams are commonly
955  * specified in build files (e.g. Makefile) to customize the behavior of
956  * a given Generator, thus they have a very constrained set of types to allow
957  * for efficient specification via command-line flags. A GeneratorParam can be:
958  * - any float or int type.
959  * - bool
960  * - enum
961  * - Halide::Target
962  * - Halide::Type
963  * - std::string
964  * Please don't use std::string unless there's no way to do what you want with some
965  * other type; in particular, don't use this if you can use enum instead.
966  * All GeneratorParams have a default value. Arithmetic types can also
967  * optionally specify min and max. Enum types must specify a string-to-value
968  * map.
969  *
970  * Halide::Type is treated as though it were an enum, with the mappings:
971  *
972  * "int8" Halide::Int(8)
973  * "int16" Halide::Int(16)
974  * "int32" Halide::Int(32)
975  * "int64" Halide::Int(64)
976  * "uint8" Halide::UInt(8)
977  * "uint16" Halide::UInt(16)
978  * "uint32" Halide::UInt(32)
979  * "uint64" Halide::UInt(64)
980  * "float16" Halide::Float(16)
981  * "float32" Halide::Float(32)
982  * "float64" Halide::Float(64)
983  * "bfloat16" Halide::BFloat(16)
984  *
985  * No vector Types are currently supported by this mapping.
986  *
987  */
988 template<typename T>
990 public:
991  template<typename T2 = T, typename std::enable_if<!std::is_same<T2, std::string>::value>::type * = nullptr>
992  GeneratorParam(const std::string &name, const T &value)
993  : Internal::GeneratorParamImplBase<T>(name, value) {
994  }
995 
996  GeneratorParam(const std::string &name, const T &value, const T &min, const T &max)
997  : Internal::GeneratorParamImplBase<T>(name, value, min, max) {
998  }
999 
1000  GeneratorParam(const std::string &name, const T &value, const std::map<std::string, T> &enum_map)
1001  : Internal::GeneratorParamImplBase<T>(name, value, enum_map) {
1002  }
1003 
1004  GeneratorParam(const std::string &name, const std::string &value)
1005  : Internal::GeneratorParamImplBase<T>(name, value) {
1006  }
1007 };
1008 
1009 /** Addition between GeneratorParam<T> and any type that supports operator+ with T.
1010  * Returns type of underlying operator+. */
1011 // @{
1012 template<typename Other, typename T>
1013 auto operator+(const Other &a, const GeneratorParam<T> &b) -> decltype(a + (T)b) {
1014  return a + (T)b;
1015 }
1016 template<typename Other, typename T>
1017 auto operator+(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a + b) {
1018  return (T)a + b;
1019 }
1020 // @}
1021 
1022 /** Subtraction between GeneratorParam<T> and any type that supports operator- with T.
1023  * Returns type of underlying operator-. */
1024 // @{
1025 template<typename Other, typename T>
1026 auto operator-(const Other &a, const GeneratorParam<T> &b) -> decltype(a - (T)b) {
1027  return a - (T)b;
1028 }
1029 template<typename Other, typename T>
1030 auto operator-(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a - b) {
1031  return (T)a - b;
1032 }
1033 // @}
1034 
1035 /** Multiplication between GeneratorParam<T> and any type that supports operator* with T.
1036  * Returns type of underlying operator*. */
1037 // @{
1038 template<typename Other, typename T>
1039 auto operator*(const Other &a, const GeneratorParam<T> &b) -> decltype(a * (T)b) {
1040  return a * (T)b;
1041 }
1042 template<typename Other, typename T>
1043 auto operator*(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a * b) {
1044  return (T)a * b;
1045 }
1046 // @}
1047 
1048 /** Division between GeneratorParam<T> and any type that supports operator/ with T.
1049  * Returns type of underlying operator/. */
1050 // @{
1051 template<typename Other, typename T>
1052 auto operator/(const Other &a, const GeneratorParam<T> &b) -> decltype(a / (T)b) {
1053  return a / (T)b;
1054 }
1055 template<typename Other, typename T>
1056 auto operator/(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a / b) {
1057  return (T)a / b;
1058 }
1059 // @}
1060 
1061 /** Modulo between GeneratorParam<T> and any type that supports operator% with T.
1062  * Returns type of underlying operator%. */
1063 // @{
1064 template<typename Other, typename T>
1065 auto operator%(const Other &a, const GeneratorParam<T> &b) -> decltype(a % (T)b) {
1066  return a % (T)b;
1067 }
1068 template<typename Other, typename T>
1069 auto operator%(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a % b) {
1070  return (T)a % b;
1071 }
1072 // @}
1073 
1074 /** Greater than comparison between GeneratorParam<T> and any type that supports operator> with T.
1075  * Returns type of underlying operator>. */
1076 // @{
1077 template<typename Other, typename T>
1078 auto operator>(const Other &a, const GeneratorParam<T> &b) -> decltype(a > (T)b) {
1079  return a > (T)b;
1080 }
1081 template<typename Other, typename T>
1082 auto operator>(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a > b) {
1083  return (T)a > b;
1084 }
1085 // @}
1086 
1087 /** Less than comparison between GeneratorParam<T> and any type that supports operator< with T.
1088  * Returns type of underlying operator<. */
1089 // @{
1090 template<typename Other, typename T>
1091 auto operator<(const Other &a, const GeneratorParam<T> &b) -> decltype(a < (T)b) {
1092  return a < (T)b;
1093 }
1094 template<typename Other, typename T>
1095 auto operator<(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a < b) {
1096  return (T)a < b;
1097 }
1098 // @}
1099 
1100 /** Greater than or equal comparison between GeneratorParam<T> and any type that supports operator>= with T.
1101  * Returns type of underlying operator>=. */
1102 // @{
1103 template<typename Other, typename T>
1104 auto operator>=(const Other &a, const GeneratorParam<T> &b) -> decltype(a >= (T)b) {
1105  return a >= (T)b;
1106 }
1107 template<typename Other, typename T>
1108 auto operator>=(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a >= b) {
1109  return (T)a >= b;
1110 }
1111 // @}
1112 
1113 /** Less than or equal comparison between GeneratorParam<T> and any type that supports operator<= with T.
1114  * Returns type of underlying operator<=. */
1115 // @{
1116 template<typename Other, typename T>
1117 auto operator<=(const Other &a, const GeneratorParam<T> &b) -> decltype(a <= (T)b) {
1118  return a <= (T)b;
1119 }
1120 template<typename Other, typename T>
1121 auto operator<=(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a <= b) {
1122  return (T)a <= b;
1123 }
1124 // @}
1125 
1126 /** Equality comparison between GeneratorParam<T> and any type that supports operator== with T.
1127  * Returns type of underlying operator==. */
1128 // @{
1129 template<typename Other, typename T>
1130 auto operator==(const Other &a, const GeneratorParam<T> &b) -> decltype(a == (T)b) {
1131  return a == (T)b;
1132 }
1133 template<typename Other, typename T>
1134 auto operator==(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a == b) {
1135  return (T)a == b;
1136 }
1137 // @}
1138 
1139 /** Inequality comparison between between GeneratorParam<T> and any type that supports operator!= with T.
1140  * Returns type of underlying operator!=. */
1141 // @{
1142 template<typename Other, typename T>
1143 auto operator!=(const Other &a, const GeneratorParam<T> &b) -> decltype(a != (T)b) {
1144  return a != (T)b;
1145 }
1146 template<typename Other, typename T>
1147 auto operator!=(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a != b) {
1148  return (T)a != b;
1149 }
1150 // @}
1151 
1152 /** Logical and between between GeneratorParam<T> and any type that supports operator&& with T.
1153  * Returns type of underlying operator&&. */
1154 // @{
1155 template<typename Other, typename T>
1156 auto operator&&(const Other &a, const GeneratorParam<T> &b) -> decltype(a && (T)b) {
1157  return a && (T)b;
1158 }
1159 template<typename Other, typename T>
1160 auto operator&&(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a && b) {
1161  return (T)a && b;
1162 }
1163 template<typename T>
1164 auto operator&&(const GeneratorParam<T> &a, const GeneratorParam<T> &b) -> decltype((T)a && (T)b) {
1165  return (T)a && (T)b;
1166 }
1167 // @}
1168 
1169 /** Logical or between between GeneratorParam<T> and any type that supports operator|| with T.
1170  * Returns type of underlying operator||. */
1171 // @{
1172 template<typename Other, typename T>
1173 auto operator||(const Other &a, const GeneratorParam<T> &b) -> decltype(a || (T)b) {
1174  return a || (T)b;
1175 }
1176 template<typename Other, typename T>
1177 auto operator||(const GeneratorParam<T> &a, const Other &b) -> decltype((T)a || b) {
1178  return (T)a || b;
1179 }
1180 template<typename T>
1181 auto operator||(const GeneratorParam<T> &a, const GeneratorParam<T> &b) -> decltype((T)a || (T)b) {
1182  return (T)a || (T)b;
1183 }
1184 // @}
1185 
1186 /* min and max are tricky as the language support for these is in the std
1187  * namespace. In order to make this work, forwarding functions are used that
1188  * are declared in a namespace that has std::min and std::max in scope.
1189  */
1190 namespace Internal {
1191 namespace GeneratorMinMax {
1192 
1193 using std::max;
1194 using std::min;
1195 
1196 template<typename Other, typename T>
1197 auto min_forward(const Other &a, const GeneratorParam<T> &b) -> decltype(min(a, (T)b)) {
1198  return min(a, (T)b);
1199 }
1200 template<typename Other, typename T>
1201 auto min_forward(const GeneratorParam<T> &a, const Other &b) -> decltype(min((T)a, b)) {
1202  return min((T)a, b);
1203 }
1204 
1205 template<typename Other, typename T>
1206 auto max_forward(const Other &a, const GeneratorParam<T> &b) -> decltype(max(a, (T)b)) {
1207  return max(a, (T)b);
1208 }
1209 template<typename Other, typename T>
1210 auto max_forward(const GeneratorParam<T> &a, const Other &b) -> decltype(max((T)a, b)) {
1211  return max((T)a, b);
1212 }
1213 
1214 } // namespace GeneratorMinMax
1215 } // namespace Internal
1216 
1217 /** Compute minimum between GeneratorParam<T> and any type that supports min with T.
1218  * Will automatically import std::min. Returns type of underlying min call. */
1219 // @{
1220 template<typename Other, typename T>
1221 auto min(const Other &a, const GeneratorParam<T> &b) -> decltype(Internal::GeneratorMinMax::min_forward(a, b)) {
1223 }
1224 template<typename Other, typename T>
1225 auto min(const GeneratorParam<T> &a, const Other &b) -> decltype(Internal::GeneratorMinMax::min_forward(a, b)) {
1227 }
1228 // @}
1229 
1230 /** Compute the maximum value between GeneratorParam<T> and any type that supports max with T.
1231  * Will automatically import std::max. Returns type of underlying max call. */
1232 // @{
1233 template<typename Other, typename T>
1234 auto max(const Other &a, const GeneratorParam<T> &b) -> decltype(Internal::GeneratorMinMax::max_forward(a, b)) {
1236 }
1237 template<typename Other, typename T>
1238 auto max(const GeneratorParam<T> &a, const Other &b) -> decltype(Internal::GeneratorMinMax::max_forward(a, b)) {
1240 }
1241 // @}
1242 
1243 /** Not operator for GeneratorParam */
1244 template<typename T>
1245 auto operator!(const GeneratorParam<T> &a) -> decltype(!(T)a) {
1246  return !(T)a;
1247 }
1248 
1249 namespace Internal {
1250 
1251 template<typename T2>
1252 class GeneratorInput_Buffer;
1253 
1254 /**
1255  * StubInputBuffer is the placeholder that a Stub uses when it requires
1256  * a Buffer for an input (rather than merely a Func or Expr). It is constructed
1257  * to allow only two possible sorts of input:
1258  * -- Assignment of an Input<Buffer<>>, with compatible type and dimensions,
1259  * essentially allowing us to pipe a parameter from an enclosing Generator to an internal Stub.
1260  * -- Assignment of a Buffer<>, with compatible type and dimensions,
1261  * causing the Input<Buffer<>> to become a precompiled buffer in the generated code.
1262  */
1265  friend class StubInput;
1266  template<typename T2>
1268  template<typename T2, int D2>
1269  friend class StubInputBuffer;
1270 
1271  Parameter parameter_;
1272 
1274  : parameter_(p) {
1275  // Create an empty 1-element buffer with the right runtime typing and dimensions,
1276  // which we'll use only to pass to can_convert_from() to verify this
1277  // Parameter is compatible with our constraints.
1278  Buffer<> other(p.type(), nullptr, std::vector<int>(p.dimensions(), 1));
1280  }
1281 
1282  template<typename T2, int D2>
1283  HALIDE_NO_USER_CODE_INLINE static Parameter parameter_from_buffer(const Buffer<T2, D2> &b) {
1284  internal_assert(b.defined());
1286  Parameter p(b.type(), true, b.dimensions());
1287  p.set_buffer(b);
1288  return p;
1289  }
1290 
1291 public:
1292  StubInputBuffer() = default;
1293 
1294  // *not* explicit -- this ctor should only be used when you want
1295  // to pass a literal Buffer<> for a Stub Input; this Buffer<> will be
1296  // compiled into the Generator's product, rather than becoming
1297  // a runtime Parameter.
1298  template<typename T2, int D2>
1300  : parameter_(parameter_from_buffer(b)) {
1301  }
1302 
1303  template<typename T2>
1304  static std::vector<Parameter> to_parameter_vector(const StubInputBuffer<T2> &t) {
1305  return {t.parameter_};
1306  }
1307 
1308  template<typename T2>
1309  static std::vector<Parameter> to_parameter_vector(const std::vector<StubInputBuffer<T2>> &v) {
1310  std::vector<Parameter> r;
1311  r.reserve(v.size());
1312  for (const auto &s : v) {
1313  r.push_back(s.parameter_);
1314  }
1315  return r;
1316  }
1317 };
1318 
1319 class AbstractGenerator;
1320 
1322 protected:
1324  std::shared_ptr<AbstractGenerator> generator;
1325 
1327 
1329  explicit StubOutputBufferBase(const Func &f, const std::shared_ptr<AbstractGenerator> &generator);
1330 
1331 public:
1332  Realization realize(std::vector<int32_t> sizes);
1333 
1334  template<typename... Args>
1335  Realization realize(Args &&...args) {
1336  return f.realize(std::forward<Args>(args)..., get_target());
1337  }
1338 
1339  template<typename Dst>
1340  void realize(Dst dst) {
1341  f.realize(dst, get_target());
1342  }
1343 };
1344 
1345 /**
1346  * StubOutputBuffer is the placeholder that a Stub uses when it requires
1347  * a Buffer for an output (rather than merely a Func). It is constructed
1348  * to allow only two possible sorts of things:
1349  * -- Assignment to an Output<Buffer<>>, with compatible type and dimensions,
1350  * essentially allowing us to pipe a parameter from the result of a Stub to an
1351  * enclosing Generator
1352  * -- Realization into a Buffer<>; this is useful only in JIT compilation modes
1353  * (and shouldn't be usable otherwise)
1354  *
1355  * It is deliberate that StubOutputBuffer is not (easily) convertible to Func.
1356  */
1357 template<typename T = void>
1359  template<typename T2>
1361  explicit StubOutputBuffer(const Func &fn, const std::shared_ptr<AbstractGenerator> &gen)
1362  : StubOutputBufferBase(fn, gen) {
1363  }
1364 
1365 public:
1366  StubOutputBuffer() = default;
1367 
1368  static std::vector<StubOutputBuffer<T>> to_output_buffers(const std::vector<Func> &v,
1369  const std::shared_ptr<AbstractGenerator> &gen) {
1370  std::vector<StubOutputBuffer<T>> result;
1371  for (const Func &f : v) {
1372  result.push_back(StubOutputBuffer<T>(f, gen));
1373  }
1374  return result;
1375  }
1376 };
1377 
1378 // This is a union-like class that allows for convenient initialization of Stub Inputs
1379 // via initializer-list syntax; it is only used in situations where the
1380 // downstream consumer will be able to explicitly check that each value is
1381 // of the expected/required kind.
1382 class StubInput {
1383  const ArgInfoKind kind_;
1384  // Exactly one of the following fields should be defined:
1385  const Parameter parameter_;
1386  const Func func_;
1387  const Expr expr_;
1388 
1389 public:
1390  // *not* explicit.
1391  template<typename T2>
1393  : kind_(ArgInfoKind::Buffer), parameter_(b.parameter_), func_(), expr_() {
1394  }
1396  : kind_(ArgInfoKind::Buffer), parameter_(p), func_(), expr_() {
1397  }
1398  StubInput(const Func &f)
1399  : kind_(ArgInfoKind::Function), parameter_(), func_(f), expr_() {
1400  }
1401  StubInput(const Expr &e)
1402  : kind_(ArgInfoKind::Scalar), parameter_(), func_(), expr_(e) {
1403  }
1404 
1405  ArgInfoKind kind() const {
1406  return kind_;
1407  }
1408 
1411  return parameter_;
1412  }
1413 
1414  Func func() const {
1416  return func_;
1417  }
1418 
1419  Expr expr() const {
1421  return expr_;
1422  }
1423 };
1424 
1425 /** GIOBase is the base class for all GeneratorInput<> and GeneratorOutput<>
1426  * instantiations; it is not part of the public API and should never be
1427  * used directly by user code.
1428  *
1429  * Every GIOBase instance can be either a single value or an array-of-values;
1430  * each of these values can be an Expr or a Func. (Note that for an
1431  * array-of-values, the types/dimensions of all values in the array must match.)
1432  *
1433  * A GIOBase can have multiple Types, in which case it represents a Tuple.
1434  * (Note that Tuples are currently only supported for GeneratorOutput, but
1435  * it is likely that GeneratorInput will be extended to support Tuple as well.)
1436  *
1437  * The array-size, type(s), and dimensions can all be left "unspecified" at
1438  * creation time, in which case they may assume values provided by a Stub.
1439  * (It is important to note that attempting to use a GIOBase with unspecified
1440  * values will assert-fail; you must ensure that all unspecified values are
1441  * filled in prior to use.)
1442  */
1443 class GIOBase {
1444 public:
1445  virtual ~GIOBase() = default;
1446 
1447  // These should only be called from configure() methods.
1448  // TODO: find a way to enforce this. Better yet, find a way to remove these.
1449  void set_type(const Type &type);
1451  void set_array_size(int size);
1452 
1453 protected:
1454  bool array_size_defined() const;
1455  size_t array_size() const;
1456  virtual bool is_array() const;
1457 
1458  const std::string &name() const;
1460 
1461  bool gio_types_defined() const;
1462  const std::vector<Type> &gio_types() const;
1463  Type gio_type() const;
1464 
1465  bool dims_defined() const;
1466  int dims() const;
1467 
1468  const std::vector<Func> &funcs() const;
1469  const std::vector<Expr> &exprs() const;
1470 
1472  const std::string &name,
1473  ArgInfoKind kind,
1474  const std::vector<Type> &types,
1475  int dims);
1476 
1477  friend class GeneratorBase;
1478  friend class GeneratorParamInfo;
1479 
1480  mutable int array_size_; // always 1 if is_array() == false.
1481  // -1 if is_array() == true but unspecified.
1482 
1483  const std::string name_;
1485  mutable std::vector<Type> types_; // empty if type is unspecified
1486  mutable int dims_; // -1 if dim is unspecified
1487 
1488  // Exactly one of these will have nonzero length
1489  std::vector<Func> funcs_;
1490  std::vector<Expr> exprs_;
1491 
1492  // Generator which owns this Input or Output. Note that this will be null
1493  // initially; the GeneratorBase itself will set this field when it initially
1494  // builds its info about params. However, since it isn't
1495  // appropriate for Input<> or Output<> to be declared outside of a Generator,
1496  // all reasonable non-testing code should expect this to be non-null.
1498 
1499  std::string array_name(size_t i) const;
1500 
1501  virtual void verify_internals();
1502 
1503  void check_matching_array_size(size_t size) const;
1504  void check_matching_types(const std::vector<Type> &t) const;
1505  void check_matching_dims(int d) const;
1506 
1507  template<typename ElemType>
1508  const std::vector<ElemType> &get_values() const;
1509 
1510  void check_gio_access() const;
1511 
1512  virtual void check_value_writable() const = 0;
1513 
1514  virtual const char *input_or_output() const = 0;
1515 
1516 private:
1517  template<typename T>
1519  friend class GeneratorStub;
1520 
1521 public:
1522  GIOBase(const GIOBase &) = delete;
1523  GIOBase &operator=(const GIOBase &) = delete;
1524  GIOBase(GIOBase &&) = delete;
1525  GIOBase &operator=(GIOBase &&) = delete;
1526 };
1527 
1528 template<>
1529 inline const std::vector<Expr> &GIOBase::get_values<Expr>() const {
1530  return exprs();
1531 }
1532 
1533 template<>
1534 inline const std::vector<Func> &GIOBase::get_values<Func>() const {
1535  return funcs();
1536 }
1537 
1538 class GeneratorInputBase : public GIOBase {
1539 protected:
1541  const std::string &name,
1542  ArgInfoKind kind,
1543  const std::vector<Type> &t,
1544  int d);
1545 
1546  GeneratorInputBase(const std::string &name, ArgInfoKind kind, const std::vector<Type> &t, int d);
1547 
1548  friend class GeneratorBase;
1549  friend class GeneratorParamInfo;
1550 
1551  std::vector<Parameter> parameters_;
1552 
1554 
1556  void set_inputs(const std::vector<StubInput> &inputs);
1557  bool inputs_set = false;
1558 
1559  virtual void set_def_min_max();
1560 
1561  void verify_internals() override;
1562 
1563  friend class StubEmitter;
1564 
1565  virtual std::string get_c_type() const = 0;
1566 
1567  void check_value_writable() const override;
1568 
1569  const char *input_or_output() const override {
1570  return "Input";
1571  }
1572 
1573  void set_estimate_impl(const Var &var, const Expr &min, const Expr &extent);
1574  void set_estimates_impl(const Region &estimates);
1575 
1576 public:
1578 };
1579 
1580 template<typename T, typename ValueType>
1582 protected:
1583  using TBase = typename std::remove_all_extents<T>::type;
1584 
1585  bool is_array() const override {
1586  return std::is_array<T>::value;
1587  }
1588 
1589  template<typename T2 = T, typename std::enable_if<
1590  // Only allow T2 not-an-array
1591  !std::is_array<T2>::value>::type * = nullptr>
1592  GeneratorInputImpl(const std::string &name, ArgInfoKind kind, const std::vector<Type> &t, int d)
1593  : GeneratorInputBase(name, kind, t, d) {
1594  }
1595 
1596  template<typename T2 = T, typename std::enable_if<
1597  // Only allow T2[kSomeConst]
1598  std::is_array<T2>::value && std::rank<T2>::value == 1 && (std::extent<T2, 0>::value > 0)>::type * = nullptr>
1599  GeneratorInputImpl(const std::string &name, ArgInfoKind kind, const std::vector<Type> &t, int d)
1600  : GeneratorInputBase(std::extent<T2, 0>::value, name, kind, t, d) {
1601  }
1602 
1603  template<typename T2 = T, typename std::enable_if<
1604  // Only allow T2[]
1605  std::is_array<T2>::value && std::rank<T2>::value == 1 && std::extent<T2, 0>::value == 0>::type * = nullptr>
1606  GeneratorInputImpl(const std::string &name, ArgInfoKind kind, const std::vector<Type> &t, int d)
1607  : GeneratorInputBase(-1, name, kind, t, d) {
1608  }
1609 
1610 public:
1611  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1612  size_t size() const {
1613  this->check_gio_access();
1614  return get_values<ValueType>().size();
1615  }
1616 
1617  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1618  const ValueType &operator[](size_t i) const {
1619  this->check_gio_access();
1620  return get_values<ValueType>()[i];
1621  }
1622 
1623  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1624  const ValueType &at(size_t i) const {
1625  this->check_gio_access();
1626  return get_values<ValueType>().at(i);
1627  }
1628 
1629  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1630  typename std::vector<ValueType>::const_iterator begin() const {
1631  this->check_gio_access();
1632  return get_values<ValueType>().begin();
1633  }
1634 
1635  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1636  typename std::vector<ValueType>::const_iterator end() const {
1637  this->check_gio_access();
1638  return get_values<ValueType>().end();
1639  }
1640 };
1641 
1642 // When forwarding methods to ImageParam, Func, etc., we must take
1643 // care with the return types: many of the methods return a reference-to-self
1644 // (e.g., ImageParam&); since we create temporaries for most of these forwards,
1645 // returning a ref will crater because it refers to a now-defunct section of the
1646 // stack. Happily, simply removing the reference is solves this, since all of the
1647 // types in question satisfy the property of copies referring to the same underlying
1648 // structure (returning references is just an optimization). Since this is verbose
1649 // and used in several places, we'll use a helper macro:
1650 #define HALIDE_FORWARD_METHOD(Class, Method) \
1651  template<typename... Args> \
1652  inline auto Method(Args &&...args) -> typename std::remove_reference<decltype(std::declval<Class>().Method(std::forward<Args>(args)...))>::type { \
1653  return this->template as<Class>().Method(std::forward<Args>(args)...); \
1654  }
1655 
1656 #define HALIDE_FORWARD_METHOD_CONST(Class, Method) \
1657  template<typename... Args> \
1658  inline auto Method(Args &&...args) const -> \
1659  typename std::remove_reference<decltype(std::declval<Class>().Method(std::forward<Args>(args)...))>::type { \
1660  this->check_gio_access(); \
1661  return this->template as<Class>().Method(std::forward<Args>(args)...); \
1662  }
1663 
1664 template<typename T>
1666 private:
1668 
1669 protected:
1670  using TBase = typename Super::TBase;
1671 
1672  friend class ::Halide::Func;
1673  friend class ::Halide::Stage;
1674 
1675  std::string get_c_type() const override {
1676  if (TBase::has_static_halide_type) {
1677  return "Halide::Internal::StubInputBuffer<" +
1678  halide_type_to_c_type(TBase::static_halide_type()) +
1679  ">";
1680  } else {
1681  return "Halide::Internal::StubInputBuffer<>";
1682  }
1683  }
1684 
1685  template<typename T2>
1686  T2 as() const {
1687  return (T2) * this;
1688  }
1689 
1690 public:
1691  explicit GeneratorInput_Buffer(const std::string &name)
1693  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
1694  TBase::has_static_dimensions ? TBase::static_dimensions() : -1) {
1695  }
1696 
1697  GeneratorInput_Buffer(const std::string &name, const Type &t, int d)
1698  : Super(name, ArgInfoKind::Buffer, {t}, d) {
1699  static_assert(!TBase::has_static_halide_type, "You can only specify a Type argument for Input<Buffer<T>> if T is void or omitted.");
1700  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Input<Buffer<T, D>> if D is -1 or omitted.");
1701  }
1702 
1703  GeneratorInput_Buffer(const std::string &name, const Type &t)
1704  : Super(name, ArgInfoKind::Buffer, {t}, -1) {
1705  static_assert(!TBase::has_static_halide_type, "You can only specify a Type argument for Input<Buffer<T>> if T is void or omitted.");
1706  }
1707 
1708  GeneratorInput_Buffer(const std::string &name, int d)
1710  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
1711  d) {
1712  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Input<Buffer<T, D>> if D is -1 or omitted.");
1713  }
1714 
1715  template<typename... Args>
1716  Expr operator()(Args &&...args) const {
1717  this->check_gio_access();
1718  return Func(*this)(std::forward<Args>(args)...);
1719  }
1720 
1721  Expr operator()(std::vector<Expr> args) const {
1722  this->check_gio_access();
1723  return Func(*this)(std::move(args));
1724  }
1725 
1726  template<typename T2>
1727  operator StubInputBuffer<T2>() const {
1728  user_assert(!this->is_array()) << "Cannot assign an array type to a non-array type for Input " << this->name();
1729  return StubInputBuffer<T2>(this->parameters_.at(0));
1730  }
1731 
1732  operator Func() const {
1733  this->check_gio_access();
1734  return this->funcs().at(0);
1735  }
1736 
1737  operator ExternFuncArgument() const {
1738  this->check_gio_access();
1739  return ExternFuncArgument(this->parameters_.at(0));
1740  }
1741 
1743  this->check_gio_access();
1744  this->set_estimate_impl(var, min, extent);
1745  return *this;
1746  }
1747 
1749  this->check_gio_access();
1750  this->set_estimates_impl(estimates);
1751  return *this;
1752  }
1753 
1754  Func in() {
1755  this->check_gio_access();
1756  return Func(*this).in();
1757  }
1758 
1759  Func in(const Func &other) {
1760  this->check_gio_access();
1761  return Func(*this).in(other);
1762  }
1763 
1764  Func in(const std::vector<Func> &others) {
1765  this->check_gio_access();
1766  return Func(*this).in(others);
1767  }
1768 
1769  operator ImageParam() const {
1770  this->check_gio_access();
1771  user_assert(!this->is_array()) << "Cannot convert an Input<Buffer<>[]> to an ImageParam; use an explicit subscript operator: " << this->name();
1772  return ImageParam(this->parameters_.at(0), Func(*this));
1773  }
1774 
1775  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1776  size_t size() const {
1777  this->check_gio_access();
1778  return this->parameters_.size();
1779  }
1780 
1781  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1782  ImageParam operator[](size_t i) const {
1783  this->check_gio_access();
1784  return ImageParam(this->parameters_.at(i), this->funcs().at(i));
1785  }
1786 
1787  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1788  ImageParam at(size_t i) const {
1789  this->check_gio_access();
1790  return ImageParam(this->parameters_.at(i), this->funcs().at(i));
1791  }
1792 
1793  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1794  typename std::vector<ImageParam>::const_iterator begin() const {
1795  user_error << "Input<Buffer<>>::begin() is not supported.";
1796  return {};
1797  }
1798 
1799  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
1800  typename std::vector<ImageParam>::const_iterator end() const {
1801  user_error << "Input<Buffer<>>::end() is not supported.";
1802  return {};
1803  }
1804 
1805  /** Forward methods to the ImageParam. */
1806  // @{
1809  HALIDE_FORWARD_METHOD_CONST(ImageParam, host_alignment)
1810  HALIDE_FORWARD_METHOD(ImageParam, set_host_alignment)
1821  HALIDE_FORWARD_METHOD_CONST(ImageParam, add_trace_tag)
1823  // }@
1824 };
1825 
1826 template<typename T>
1827 class GeneratorInput_Func : public GeneratorInputImpl<T, Func> {
1828 private:
1830 
1831 protected:
1832  using TBase = typename Super::TBase;
1833 
1834  std::string get_c_type() const override {
1835  return "Func";
1836  }
1837 
1838  template<typename T2>
1839  T2 as() const {
1840  return (T2) * this;
1841  }
1842 
1843 public:
1844  GeneratorInput_Func(const std::string &name, const Type &t, int d)
1845  : Super(name, ArgInfoKind::Function, {t}, d) {
1846  }
1847 
1848  // unspecified type
1849  GeneratorInput_Func(const std::string &name, int d)
1850  : Super(name, ArgInfoKind::Function, {}, d) {
1851  }
1852 
1853  // unspecified dimension
1854  GeneratorInput_Func(const std::string &name, const Type &t)
1855  : Super(name, ArgInfoKind::Function, {t}, -1) {
1856  }
1857 
1858  // unspecified type & dimension
1859  explicit GeneratorInput_Func(const std::string &name)
1860  : Super(name, ArgInfoKind::Function, {}, -1) {
1861  }
1862 
1863  GeneratorInput_Func(size_t array_size, const std::string &name, const Type &t, int d)
1864  : Super(array_size, name, ArgInfoKind::Function, {t}, d) {
1865  }
1866 
1867  // unspecified type
1868  GeneratorInput_Func(size_t array_size, const std::string &name, int d)
1869  : Super(array_size, name, ArgInfoKind::Function, {}, d) {
1870  }
1871 
1872  // unspecified dimension
1873  GeneratorInput_Func(size_t array_size, const std::string &name, const Type &t)
1874  : Super(array_size, name, ArgInfoKind::Function, {t}, -1) {
1875  }
1876 
1877  // unspecified type & dimension
1878  GeneratorInput_Func(size_t array_size, const std::string &name)
1879  : Super(array_size, name, ArgInfoKind::Function, {}, -1) {
1880  }
1881 
1882  template<typename... Args>
1883  Expr operator()(Args &&...args) const {
1884  this->check_gio_access();
1885  return this->funcs().at(0)(std::forward<Args>(args)...);
1886  }
1887 
1888  Expr operator()(const std::vector<Expr> &args) const {
1889  this->check_gio_access();
1890  return this->funcs().at(0)(args);
1891  }
1892 
1893  operator Func() const {
1894  this->check_gio_access();
1895  return this->funcs().at(0);
1896  }
1897 
1898  operator ExternFuncArgument() const {
1899  this->check_gio_access();
1900  return ExternFuncArgument(this->parameters_.at(0));
1901  }
1902 
1904  this->check_gio_access();
1905  this->set_estimate_impl(var, min, extent);
1906  return *this;
1907  }
1908 
1910  this->check_gio_access();
1911  this->set_estimates_impl(estimates);
1912  return *this;
1913  }
1914 
1915  Func in() {
1916  this->check_gio_access();
1917  return Func(*this).in();
1918  }
1919 
1920  Func in(const Func &other) {
1921  this->check_gio_access();
1922  return Func(*this).in(other);
1923  }
1924 
1925  Func in(const std::vector<Func> &others) {
1926  this->check_gio_access();
1927  return Func(*this).in(others);
1928  }
1929 
1930  /** Forward const methods to the underlying Func. (Non-const methods
1931  * aren't available for Input<Func>.) */
1932  // @{
1935  HALIDE_FORWARD_METHOD_CONST(Func, dimensions)
1936  HALIDE_FORWARD_METHOD_CONST(Func, has_update_definition)
1937  HALIDE_FORWARD_METHOD_CONST(Func, num_update_definitions)
1942  HALIDE_FORWARD_METHOD_CONST(Func, update_args)
1943  HALIDE_FORWARD_METHOD_CONST(Func, update_value)
1944  HALIDE_FORWARD_METHOD_CONST(Func, update_values)
1947  // }@
1948 };
1949 
1950 template<typename T>
1952 private:
1954 
1955  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");
1956 
1957 protected:
1958  std::string get_c_type() const override {
1959  return "Expr";
1960  }
1961 
1962 public:
1963  explicit GeneratorInput_DynamicScalar(const std::string &name)
1964  : Super(name, ArgInfoKind::Scalar, {}, 0) {
1965  user_assert(!std::is_array<T>::value) << "Input<Expr[]> is not allowed";
1966  }
1967 
1968  /** You can use this Input as an expression in a halide
1969  * function definition */
1970  operator Expr() const {
1971  this->check_gio_access();
1972  return this->exprs().at(0);
1973  }
1974 
1975  /** Using an Input as the argument to an external stage treats it
1976  * as an Expr */
1977  operator ExternFuncArgument() const {
1978  this->check_gio_access();
1979  return ExternFuncArgument(this->exprs().at(0));
1980  }
1981 
1982  void set_estimate(const Expr &value) {
1983  this->check_gio_access();
1984  for (Parameter &p : this->parameters_) {
1985  p.set_estimate(value);
1986  }
1987  }
1988 
1989  Type type() const {
1990  return Expr(*this).type();
1991  }
1992 };
1993 
1994 template<typename T>
1996 private:
1998 
1999 protected:
2000  using TBase = typename Super::TBase;
2001 
2002  const TBase def_{TBase()};
2004 
2005  void set_def_min_max() override {
2006  for (Parameter &p : this->parameters_) {
2007  // No: we want to leave the Parameter unset here.
2008  // p.set_scalar<TBase>(def_);
2010  }
2011  }
2012 
2013  std::string get_c_type() const override {
2014  return "Expr";
2015  }
2016 
2017  // Expr() doesn't accept a pointer type in its ctor; add a SFINAE adapter
2018  // so that pointer (aka handle) Inputs will get cast to uint64.
2019  template<typename TBase2 = TBase, typename std::enable_if<!std::is_pointer<TBase2>::value>::type * = nullptr>
2020  static Expr TBaseToExpr(const TBase2 &value) {
2021  return cast<TBase>(Expr(value));
2022  }
2023 
2024  template<typename TBase2 = TBase, typename std::enable_if<std::is_pointer<TBase2>::value>::type * = nullptr>
2025  static Expr TBaseToExpr(const TBase2 &value) {
2026  user_assert(value == 0) << "Zero is the only legal default value for Inputs which are pointer types.\n";
2027  return Expr();
2028  }
2029 
2030 public:
2031  explicit GeneratorInput_Scalar(const std::string &name)
2032  : Super(name, ArgInfoKind::Scalar, {type_of<TBase>()}, 0), def_(static_cast<TBase>(0)), def_expr_(Expr()) {
2033  }
2034 
2035  GeneratorInput_Scalar(const std::string &name, const TBase &def)
2036  : Super(name, ArgInfoKind::Scalar, {type_of<TBase>()}, 0), def_(def), def_expr_(TBaseToExpr(def)) {
2037  }
2038 
2040  const std::string &name)
2041  : Super(array_size, name, ArgInfoKind::Scalar, {type_of<TBase>()}, 0), def_(static_cast<TBase>(0)), def_expr_(Expr()) {
2042  }
2043 
2045  const std::string &name,
2046  const TBase &def)
2047  : Super(array_size, name, ArgInfoKind::Scalar, {type_of<TBase>()}, 0), def_(def), def_expr_(TBaseToExpr(def)) {
2048  }
2049 
2050  /** You can use this Input as an expression in a halide
2051  * function definition */
2052  operator Expr() const {
2053  this->check_gio_access();
2054  return this->exprs().at(0);
2055  }
2056 
2057  /** Using an Input as the argument to an external stage treats it
2058  * as an Expr */
2059  operator ExternFuncArgument() const {
2060  this->check_gio_access();
2061  return ExternFuncArgument(this->exprs().at(0));
2062  }
2063 
2064  template<typename T2 = T, typename std::enable_if<std::is_pointer<T2>::value>::type * = nullptr>
2065  void set_estimate(const TBase &value) {
2066  this->check_gio_access();
2067  user_assert(value == nullptr) << "nullptr is the only valid estimate for Input<PointerType>";
2068  Expr e = reinterpret(type_of<T2>(), cast<uint64_t>(0));
2069  for (Parameter &p : this->parameters_) {
2070  p.set_estimate(e);
2071  }
2072  }
2073 
2074  template<typename T2 = T, typename std::enable_if<!std::is_array<T2>::value && !std::is_pointer<T2>::value>::type * = nullptr>
2075  void set_estimate(const TBase &value) {
2076  this->check_gio_access();
2077  Expr e = Expr(value);
2078  if (std::is_same<T2, bool>::value) {
2079  e = cast<bool>(e);
2080  }
2081  for (Parameter &p : this->parameters_) {
2082  p.set_estimate(e);
2083  }
2084  }
2085 
2086  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2087  void set_estimate(size_t index, const TBase &value) {
2088  this->check_gio_access();
2089  Expr e = Expr(value);
2090  if (std::is_same<T2, bool>::value) {
2091  e = cast<bool>(e);
2092  }
2093  this->parameters_.at(index).set_estimate(e);
2094  }
2095 
2096  Type type() const {
2097  return Expr(*this).type();
2098  }
2099 };
2100 
2101 template<typename T>
2103 private:
2105 
2106 protected:
2107  using TBase = typename Super::TBase;
2108 
2109  const Expr min_, max_;
2110 
2111  void set_def_min_max() override {
2113  // Don't set min/max for bool
2114  if (!std::is_same<TBase, bool>::value) {
2115  for (Parameter &p : this->parameters_) {
2116  if (min_.defined()) {
2117  p.set_min_value(min_);
2118  }
2119  if (max_.defined()) {
2120  p.set_max_value(max_);
2121  }
2122  }
2123  }
2124  }
2125 
2126 public:
2127  explicit GeneratorInput_Arithmetic(const std::string &name)
2128  : Super(name), min_(Expr()), max_(Expr()) {
2129  }
2130 
2131  GeneratorInput_Arithmetic(const std::string &name,
2132  const TBase &def)
2133  : Super(name, def), min_(Expr()), max_(Expr()) {
2134  }
2135 
2137  const std::string &name)
2138  : Super(array_size, name), min_(Expr()), max_(Expr()) {
2139  }
2140 
2142  const std::string &name,
2143  const TBase &def)
2144  : Super(array_size, name, def), min_(Expr()), max_(Expr()) {
2145  }
2146 
2147  GeneratorInput_Arithmetic(const std::string &name,
2148  const TBase &def,
2149  const TBase &min,
2150  const TBase &max)
2151  : Super(name, def), min_(min), max_(max) {
2152  }
2153 
2155  const std::string &name,
2156  const TBase &def,
2157  const TBase &min,
2158  const TBase &max)
2159  : Super(array_size, name, def), min_(min), max_(max) {
2160  }
2161 };
2162 
2163 template<typename>
2164 struct type_sink {
2165  typedef void type;
2166 };
2167 
2168 template<typename T2, typename = void>
2169 struct has_static_halide_type_method : std::false_type {};
2170 
2171 template<typename T2>
2172 struct has_static_halide_type_method<T2, typename type_sink<decltype(T2::static_halide_type())>::type> : std::true_type {};
2173 
2174 template<typename T, typename TBase = typename std::remove_all_extents<T>::type>
2176  typename select_type<
2182 
2183 } // namespace Internal
2184 
2185 template<typename T>
2187 private:
2189 
2190 protected:
2191  using TBase = typename Super::TBase;
2192 
2193  // Trick to avoid ambiguous ctor between Func-with-dim and int-with-default-value;
2194  // since we can't use std::enable_if on ctors, define the argument to be one that
2195  // can only be properly resolved for TBase=Func.
2196  struct Unused;
2198  typename Internal::select_type<
2202 
2203 public:
2204  // Mark all of these explicit (not just single-arg versions) so that
2205  // we disallow copy-list-initialization form (i.e., Input foo{"foo"} is ok,
2206  // but Input foo = {"foo"} is not).
2207  explicit GeneratorInput(const std::string &name)
2208  : Super(name) {
2209  }
2210 
2211  explicit GeneratorInput(const std::string &name, const TBase &def)
2212  : Super(name, def) {
2213  }
2214 
2215  explicit GeneratorInput(size_t array_size, const std::string &name, const TBase &def)
2216  : Super(array_size, name, def) {
2217  }
2218 
2219  explicit GeneratorInput(const std::string &name,
2220  const TBase &def, const TBase &min, const TBase &max)
2221  : Super(name, def, min, max) {
2222  }
2223 
2224  explicit GeneratorInput(size_t array_size, const std::string &name,
2225  const TBase &def, const TBase &min, const TBase &max)
2226  : Super(array_size, name, def, min, max) {
2227  }
2228 
2229  explicit GeneratorInput(const std::string &name, const Type &t, int d)
2230  : Super(name, t, d) {
2231  }
2232 
2233  explicit GeneratorInput(const std::string &name, const Type &t)
2234  : Super(name, t) {
2235  }
2236 
2237  // Avoid ambiguity between Func-with-dim and int-with-default
2238  explicit GeneratorInput(const std::string &name, IntIfNonScalar d)
2239  : Super(name, d) {
2240  }
2241 
2242  explicit GeneratorInput(size_t array_size, const std::string &name, const Type &t, int d)
2243  : Super(array_size, name, t, d) {
2244  }
2245 
2246  explicit GeneratorInput(size_t array_size, const std::string &name, const Type &t)
2247  : Super(array_size, name, t) {
2248  }
2249 
2250  // Avoid ambiguity between Func-with-dim and int-with-default
2251  // template <typename T2 = T, typename std::enable_if<std::is_same<TBase, Func>::value>::type * = nullptr>
2252  explicit GeneratorInput(size_t array_size, const std::string &name, IntIfNonScalar d)
2253  : Super(array_size, name, d) {
2254  }
2255 
2256  explicit GeneratorInput(size_t array_size, const std::string &name)
2257  : Super(array_size, name) {
2258  }
2259 };
2260 
2261 namespace Internal {
2262 
2264 protected:
2265  template<typename T2, typename std::enable_if<std::is_same<T2, Func>::value>::type * = nullptr>
2267  static_assert(std::is_same<T2, Func>::value, "Only Func allowed here");
2269  internal_assert(exprs_.empty());
2270  user_assert(!funcs_.empty()) << "No funcs_ are defined yet";
2271  user_assert(funcs_.size() == 1) << "Use [] to access individual Funcs in Output<Func[]>";
2272  return funcs_[0];
2273  }
2274 
2275 public:
2276  /** Forward schedule-related methods to the underlying Func. */
2277  // @{
2278  HALIDE_FORWARD_METHOD(Func, add_trace_tag)
2279  HALIDE_FORWARD_METHOD(Func, align_bounds)
2280  HALIDE_FORWARD_METHOD(Func, align_extent)
2281  HALIDE_FORWARD_METHOD(Func, align_storage)
2282  HALIDE_FORWARD_METHOD(Func, always_partition)
2283  HALIDE_FORWARD_METHOD(Func, always_partition_all)
2285  HALIDE_FORWARD_METHOD(Func, bound)
2286  HALIDE_FORWARD_METHOD(Func, bound_extent)
2287  HALIDE_FORWARD_METHOD(Func, compute_at)
2288  HALIDE_FORWARD_METHOD(Func, compute_inline)
2289  HALIDE_FORWARD_METHOD(Func, compute_root)
2290  HALIDE_FORWARD_METHOD(Func, compute_with)
2291  HALIDE_FORWARD_METHOD(Func, copy_to_device)
2292  HALIDE_FORWARD_METHOD(Func, copy_to_host)
2293  HALIDE_FORWARD_METHOD(Func, define_extern)
2295  HALIDE_FORWARD_METHOD_CONST(Func, dimensions)
2296  HALIDE_FORWARD_METHOD(Func, fold_storage)
2299  HALIDE_FORWARD_METHOD(Func, gpu_blocks)
2300  HALIDE_FORWARD_METHOD(Func, gpu_single_thread)
2301  HALIDE_FORWARD_METHOD(Func, gpu_threads)
2302  HALIDE_FORWARD_METHOD(Func, gpu_tile)
2303  HALIDE_FORWARD_METHOD_CONST(Func, has_update_definition)
2304  HALIDE_FORWARD_METHOD(Func, hexagon)
2306  HALIDE_FORWARD_METHOD(Func, memoize)
2307  HALIDE_FORWARD_METHOD(Func, never_partition)
2308  HALIDE_FORWARD_METHOD(Func, never_partition_all)
2309  HALIDE_FORWARD_METHOD_CONST(Func, num_update_definitions)
2311  HALIDE_FORWARD_METHOD(Func, parallel)
2312  HALIDE_FORWARD_METHOD(Func, partition)
2313  HALIDE_FORWARD_METHOD(Func, prefetch)
2315  HALIDE_FORWARD_METHOD(Func, rename)
2316  HALIDE_FORWARD_METHOD(Func, reorder)
2317  HALIDE_FORWARD_METHOD(Func, reorder_storage)
2319  HALIDE_FORWARD_METHOD(Func, serial)
2320  HALIDE_FORWARD_METHOD(Func, set_estimate)
2321  HALIDE_FORWARD_METHOD(Func, specialize)
2322  HALIDE_FORWARD_METHOD(Func, specialize_fail)
2323  HALIDE_FORWARD_METHOD(Func, split)
2324  HALIDE_FORWARD_METHOD(Func, store_at)
2325  HALIDE_FORWARD_METHOD(Func, store_root)
2327  HALIDE_FORWARD_METHOD(Func, trace_stores)
2330  HALIDE_FORWARD_METHOD(Func, unroll)
2331  HALIDE_FORWARD_METHOD(Func, update)
2332  HALIDE_FORWARD_METHOD_CONST(Func, update_args)
2333  HALIDE_FORWARD_METHOD_CONST(Func, update_value)
2334  HALIDE_FORWARD_METHOD_CONST(Func, update_values)
2337  HALIDE_FORWARD_METHOD(Func, vectorize)
2338 
2339  // }@
2340 
2341 #undef HALIDE_OUTPUT_FORWARD
2342 #undef HALIDE_OUTPUT_FORWARD_CONST
2343 
2344 protected:
2346  const std::string &name,
2347  ArgInfoKind kind,
2348  const std::vector<Type> &t,
2349  int d);
2350 
2351  GeneratorOutputBase(const std::string &name,
2352  ArgInfoKind kind,
2353  const std::vector<Type> &t,
2354  int d);
2355 
2356  friend class GeneratorBase;
2357  friend class StubEmitter;
2358 
2360  void resize(size_t size);
2361 
2362  virtual std::string get_c_type() const {
2363  return "Func";
2364  }
2365 
2366  void check_value_writable() const override;
2367 
2368  const char *input_or_output() const override {
2369  return "Output";
2370  }
2371 
2372 public:
2374 };
2375 
2376 template<typename T>
2378 protected:
2379  using TBase = typename std::remove_all_extents<T>::type;
2380  using ValueType = Func;
2381 
2382  bool is_array() const override {
2383  return std::is_array<T>::value;
2384  }
2385 
2386  template<typename T2 = T, typename std::enable_if<
2387  // Only allow T2 not-an-array
2388  !std::is_array<T2>::value>::type * = nullptr>
2389  GeneratorOutputImpl(const std::string &name, ArgInfoKind kind, const std::vector<Type> &t, int d)
2390  : GeneratorOutputBase(name, kind, t, d) {
2391  }
2392 
2393  template<typename T2 = T, typename std::enable_if<
2394  // Only allow T2[kSomeConst]
2395  std::is_array<T2>::value && std::rank<T2>::value == 1 && (std::extent<T2, 0>::value > 0)>::type * = nullptr>
2396  GeneratorOutputImpl(const std::string &name, ArgInfoKind kind, const std::vector<Type> &t, int d)
2397  : GeneratorOutputBase(std::extent<T2, 0>::value, name, kind, t, d) {
2398  }
2399 
2400  template<typename T2 = T, typename std::enable_if<
2401  // Only allow T2[]
2402  std::is_array<T2>::value && std::rank<T2>::value == 1 && std::extent<T2, 0>::value == 0>::type * = nullptr>
2403  GeneratorOutputImpl(const std::string &name, ArgInfoKind kind, const std::vector<Type> &t, int d)
2404  : GeneratorOutputBase(-1, name, kind, t, d) {
2405  }
2406 
2407 public:
2408  template<typename... Args, typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2409  FuncRef operator()(Args &&...args) const {
2410  this->check_gio_access();
2411  return get_values<ValueType>().at(0)(std::forward<Args>(args)...);
2412  }
2413 
2414  template<typename ExprOrVar, typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2415  FuncRef operator()(std::vector<ExprOrVar> args) const {
2416  this->check_gio_access();
2417  return get_values<ValueType>().at(0)(args);
2418  }
2419 
2420  template<typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2421  operator Func() const {
2422  this->check_gio_access();
2423  return get_values<ValueType>().at(0);
2424  }
2425 
2426  template<typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2427  operator Stage() const {
2428  this->check_gio_access();
2429  return get_values<ValueType>().at(0);
2430  }
2431 
2432  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2433  size_t size() const {
2434  this->check_gio_access();
2435  return get_values<ValueType>().size();
2436  }
2437 
2438  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2439  const ValueType &operator[](size_t i) const {
2440  this->check_gio_access();
2441  return get_values<ValueType>()[i];
2442  }
2443 
2444  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2445  const ValueType &at(size_t i) const {
2446  this->check_gio_access();
2447  return get_values<ValueType>().at(i);
2448  }
2449 
2450  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2451  typename std::vector<ValueType>::const_iterator begin() const {
2452  this->check_gio_access();
2453  return get_values<ValueType>().begin();
2454  }
2455 
2456  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2457  typename std::vector<ValueType>::const_iterator end() const {
2458  this->check_gio_access();
2459  return get_values<ValueType>().end();
2460  }
2461 
2462  template<typename T2 = T, typename std::enable_if<
2463  // Only allow T2[]
2464  std::is_array<T2>::value && std::rank<T2>::value == 1 && std::extent<T2, 0>::value == 0>::type * = nullptr>
2465  void resize(size_t size) {
2466  this->check_gio_access();
2468  }
2469 };
2470 
2471 template<typename T>
2473 private:
2474  using Super = GeneratorOutputImpl<T>;
2475 
2476  HALIDE_NO_USER_CODE_INLINE void assign_from_func(const Func &f) {
2477  this->check_value_writable();
2478 
2479  internal_assert(f.defined());
2480 
2481  if (this->gio_types_defined()) {
2482  const auto &my_types = this->gio_types();
2483  user_assert(my_types.size() == f.types().size())
2484  << "Cannot assign Func \"" << f.name()
2485  << "\" to Output \"" << this->name() << "\"\n"
2486  << "Output " << this->name()
2487  << " is declared to have " << my_types.size() << " tuple elements"
2488  << " but Func " << f.name()
2489  << " has " << f.types().size() << " tuple elements.\n";
2490  for (size_t i = 0; i < my_types.size(); i++) {
2491  user_assert(my_types[i] == f.types().at(i))
2492  << "Cannot assign Func \"" << f.name()
2493  << "\" to Output \"" << this->name() << "\"\n"
2494  << (my_types.size() > 1 ? "In tuple element " + std::to_string(i) + ", " : "")
2495  << "Output " << this->name()
2496  << " has declared type " << my_types[i]
2497  << " but Func " << f.name()
2498  << " has type " << f.types().at(i) << "\n";
2499  }
2500  }
2501  if (this->dims_defined()) {
2502  user_assert(f.dimensions() == this->dims())
2503  << "Cannot assign Func \"" << f.name()
2504  << "\" to Output \"" << this->name() << "\"\n"
2505  << "Output " << this->name()
2506  << " has declared dimensionality " << this->dims()
2507  << " but Func " << f.name()
2508  << " has dimensionality " << f.dimensions() << "\n";
2509  }
2510 
2511  internal_assert(this->exprs_.empty() && this->funcs_.size() == 1);
2512  user_assert(!this->funcs_.at(0).defined());
2513  this->funcs_[0] = f;
2514  }
2515 
2516 protected:
2517  using TBase = typename Super::TBase;
2518 
2519  explicit GeneratorOutput_Buffer(const std::string &name)
2521  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
2522  TBase::has_static_dimensions ? TBase::static_dimensions() : -1) {
2523  }
2524 
2525  GeneratorOutput_Buffer(const std::string &name, const std::vector<Type> &t, int d)
2526  : Super(name, ArgInfoKind::Buffer, t, d) {
2527  internal_assert(!t.empty());
2528  internal_assert(d != -1);
2529  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.");
2530  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Output<Buffer<T, D>> if D is -1 or omitted.");
2531  }
2532 
2533  GeneratorOutput_Buffer(const std::string &name, const std::vector<Type> &t)
2534  : Super(name, ArgInfoKind::Buffer, t, -1) {
2535  internal_assert(!t.empty());
2536  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.");
2537  }
2538 
2539  GeneratorOutput_Buffer(const std::string &name, int d)
2541  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
2542  d) {
2543  internal_assert(d != -1);
2544  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Output<Buffer<T, D>> if D is -1 or omitted.");
2545  }
2546 
2547  GeneratorOutput_Buffer(size_t array_size, const std::string &name)
2549  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
2550  TBase::has_static_dimensions ? TBase::static_dimensions() : -1) {
2551  }
2552 
2553  GeneratorOutput_Buffer(size_t array_size, const std::string &name, const std::vector<Type> &t, int d)
2554  : Super(array_size, name, ArgInfoKind::Buffer, t, d) {
2555  internal_assert(!t.empty());
2556  internal_assert(d != -1);
2557  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.");
2558  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Output<Buffer<T, D>> if D is -1 or omitted.");
2559  }
2560 
2561  GeneratorOutput_Buffer(size_t array_size, const std::string &name, const std::vector<Type> &t)
2562  : Super(array_size, name, ArgInfoKind::Buffer, t, -1) {
2563  internal_assert(!t.empty());
2564  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.");
2565  }
2566 
2567  GeneratorOutput_Buffer(size_t array_size, const std::string &name, int d)
2569  TBase::has_static_halide_type ? std::vector<Type>{TBase::static_halide_type()} : std::vector<Type>{},
2570  d) {
2571  internal_assert(d != -1);
2572  static_assert(!TBase::has_static_dimensions, "You can only specify a dimension argument for Output<Buffer<T, D>> if D is -1 or omitted.");
2573  }
2574 
2575  HALIDE_NO_USER_CODE_INLINE std::string get_c_type() const override {
2576  if (TBase::has_static_halide_type) {
2577  return "Halide::Internal::StubOutputBuffer<" +
2578  halide_type_to_c_type(TBase::static_halide_type()) +
2579  ">";
2580  } else {
2581  return "Halide::Internal::StubOutputBuffer<>";
2582  }
2583  }
2584 
2585  template<typename T2, typename std::enable_if<!std::is_same<T2, Func>::value>::type * = nullptr>
2587  return (T2) * this;
2588  }
2589 
2590 public:
2591  // Allow assignment from a Buffer<> to an Output<Buffer<>>;
2592  // this allows us to use a statically-compiled buffer inside a Generator
2593  // to assign to an output.
2594  // TODO: This used to take the buffer as a const ref. This no longer works as
2595  // using it in a Pipeline might change the dev field so it is currently
2596  // not considered const. We should consider how this really ought to work.
2597  template<typename T2, int D2>
2599  this->check_gio_access();
2600  this->check_value_writable();
2601 
2602  user_assert(T::can_convert_from(buffer))
2603  << "Cannot assign to the Output \"" << this->name()
2604  << "\": the expression is not convertible to the same Buffer type and/or dimensions.\n";
2605 
2606  if (this->gio_types_defined()) {
2607  user_assert(Type(buffer.type()) == this->gio_type())
2608  << "Output " << this->name() << " should have type=" << this->gio_type() << " but saw type=" << Type(buffer.type()) << "\n";
2609  }
2610  if (this->dims_defined()) {
2611  user_assert(buffer.dimensions() == this->dims())
2612  << "Output " << this->name() << " should have dim=" << this->dims() << " but saw dim=" << buffer.dimensions() << "\n";
2613  }
2614 
2615  internal_assert(this->exprs_.empty() && this->funcs_.size() == 1);
2616  user_assert(!this->funcs_.at(0).defined());
2617  this->funcs_.at(0)(_) = buffer(_);
2618 
2619  return *this;
2620  }
2621 
2622  // Allow assignment from a StubOutputBuffer to an Output<Buffer>;
2623  // this allows us to pipeline the results of a Stub to the results
2624  // of the enclosing Generator.
2625  template<typename T2>
2627  this->check_gio_access();
2628  assign_from_func(stub_output_buffer.f);
2629  return *this;
2630  }
2631 
2632  // Allow assignment from a Func to an Output<Buffer>;
2633  // this allows us to use helper functions that return a plain Func
2634  // to simply set the output(s) without needing a wrapper Func.
2636  this->check_gio_access();
2637  assign_from_func(f);
2638  return *this;
2639  }
2640 
2641  operator OutputImageParam() const {
2642  this->check_gio_access();
2643  user_assert(!this->is_array()) << "Cannot convert an Output<Buffer<>[]> to an ImageParam; use an explicit subscript operator: " << this->name();
2644  internal_assert(this->exprs_.empty() && this->funcs_.size() == 1);
2645  return this->funcs_.at(0).output_buffer();
2646  }
2647 
2648  // Forward set_estimates() to Func (rather than OutputImageParam) so that it can
2649  // handle Tuple-valued outputs correctly.
2651  user_assert(!this->is_array()) << "Cannot call set_estimates() on an array Output; use an explicit subscript operator: " << this->name();
2652  internal_assert(this->exprs_.empty() && this->funcs_.size() == 1);
2653  this->funcs_.at(0).set_estimates(estimates);
2654  return *this;
2655  }
2656 
2657  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2658  const Func &operator[](size_t i) const {
2659  this->check_gio_access();
2660  return this->template get_values<Func>()[i];
2661  }
2662 
2663  // Allow Output<Buffer[]>.compute_root() (or other scheduling directive that requires nonconst)
2664  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2665  Func operator[](size_t i) {
2666  this->check_gio_access();
2667  return this->template get_values<Func>()[i];
2668  }
2669 
2670  /** Forward methods to the OutputImageParam. */
2671  // @{
2675  HALIDE_FORWARD_METHOD(OutputImageParam, set_host_alignment)
2685  // }@
2686 };
2687 
2688 template<typename T>
2690 private:
2691  using Super = GeneratorOutputImpl<T>;
2692 
2693  HALIDE_NO_USER_CODE_INLINE Func &get_assignable_func_ref(size_t i) {
2694  internal_assert(this->exprs_.empty() && this->funcs_.size() > i);
2695  return this->funcs_.at(i);
2696  }
2697 
2698 protected:
2699  using TBase = typename Super::TBase;
2700 
2701  explicit GeneratorOutput_Func(const std::string &name)
2702  : Super(name, ArgInfoKind::Function, std::vector<Type>{}, -1) {
2703  }
2704 
2705  GeneratorOutput_Func(const std::string &name, const std::vector<Type> &t, int d)
2706  : Super(name, ArgInfoKind::Function, t, d) {
2707  }
2708 
2709  GeneratorOutput_Func(const std::string &name, const std::vector<Type> &t)
2710  : Super(name, ArgInfoKind::Function, t, -1) {
2711  }
2712 
2713  GeneratorOutput_Func(const std::string &name, int d)
2714  : Super(name, ArgInfoKind::Function, {}, d) {
2715  }
2716 
2717  GeneratorOutput_Func(size_t array_size, const std::string &name, const std::vector<Type> &t, int d)
2718  : Super(array_size, name, ArgInfoKind::Function, t, d) {
2719  }
2720 
2721 public:
2722  // Allow Output<Func> = Func
2723  template<typename T2 = T, typename std::enable_if<!std::is_array<T2>::value>::type * = nullptr>
2725  this->check_gio_access();
2726  this->check_value_writable();
2727 
2728  // Don't bother verifying the Func type, dimensions, etc., here:
2729  // That's done later, when we produce the pipeline.
2730  get_assignable_func_ref(0) = f;
2731  return *this;
2732  }
2733 
2734  // Allow Output<Func[]> = Func
2735  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2736  Func &operator[](size_t i) {
2737  this->check_gio_access();
2738  this->check_value_writable();
2739  return get_assignable_func_ref(i);
2740  }
2741 
2742  // Allow Func = Output<Func[]>
2743  template<typename T2 = T, typename std::enable_if<std::is_array<T2>::value>::type * = nullptr>
2744  const Func &operator[](size_t i) const {
2745  this->check_gio_access();
2746  return Super::operator[](i);
2747  }
2748 
2749  GeneratorOutput_Func<T> &set_estimate(const Var &var, const Expr &min, const Expr &extent) {
2750  this->check_gio_access();
2751  internal_assert(this->exprs_.empty() && !this->funcs_.empty());
2752  for (Func &f : this->funcs_) {
2753  f.set_estimate(var, min, extent);
2754  }
2755  return *this;
2756  }
2757 
2759  this->check_gio_access();
2760  internal_assert(this->exprs_.empty() && !this->funcs_.empty());
2761  for (Func &f : this->funcs_) {
2762  f.set_estimates(estimates);
2763  }
2764  return *this;
2765  }
2766 };
2767 
2768 template<typename T>
2770 private:
2771  using Super = GeneratorOutputImpl<T>;
2772 
2773 protected:
2774  using TBase = typename Super::TBase;
2775 
2776  explicit GeneratorOutput_Arithmetic(const std::string &name)
2777  : Super(name, ArgInfoKind::Function, {type_of<TBase>()}, 0) {
2778  }
2779 
2780  GeneratorOutput_Arithmetic(size_t array_size, const std::string &name)
2781  : Super(array_size, name, ArgInfoKind::Function, {type_of<TBase>()}, 0) {
2782  }
2783 };
2784 
2785 template<typename T, typename TBase = typename std::remove_all_extents<T>::type>
2787  typename select_type<
2791 
2792 } // namespace Internal
2793 
2794 template<typename T>
2796 private:
2798 
2799 protected:
2800  using TBase = typename Super::TBase;
2801 
2802 public:
2803  // Mark all of these explicit (not just single-arg versions) so that
2804  // we disallow copy-list-initialization form (i.e., Output foo{"foo"} is ok,
2805  // but Output foo = {"foo"} is not).
2806  explicit GeneratorOutput(const std::string &name)
2807  : Super(name) {
2808  }
2809 
2810  explicit GeneratorOutput(const char *name)
2811  : GeneratorOutput(std::string(name)) {
2812  }
2813 
2814  explicit GeneratorOutput(size_t array_size, const std::string &name)
2815  : Super(array_size, name) {
2816  }
2817 
2818  explicit GeneratorOutput(const std::string &name, int d)
2819  : Super(name, d) {
2820  }
2821 
2822  explicit GeneratorOutput(const std::string &name, const Type &t)
2823  : Super(name, {t}) {
2824  }
2825 
2826  explicit GeneratorOutput(const std::string &name, const std::vector<Type> &t)
2827  : Super(name, t) {
2828  }
2829 
2830  explicit GeneratorOutput(const std::string &name, const Type &t, int d)
2831  : Super(name, {t}, d) {
2832  }
2833 
2834  explicit GeneratorOutput(const std::string &name, const std::vector<Type> &t, int d)
2835  : Super(name, t, d) {
2836  }
2837 
2838  explicit GeneratorOutput(size_t array_size, const std::string &name, int d)
2839  : Super(array_size, name, d) {
2840  }
2841 
2842  explicit GeneratorOutput(size_t array_size, const std::string &name, const Type &t)
2843  : Super(array_size, name, {t}) {
2844  }
2845 
2846  explicit GeneratorOutput(size_t array_size, const std::string &name, const std::vector<Type> &t)
2847  : Super(array_size, name, t) {
2848  }
2849 
2850  explicit GeneratorOutput(size_t array_size, const std::string &name, const Type &t, int d)
2851  : Super(array_size, name, {t}, d) {
2852  }
2853 
2854  explicit GeneratorOutput(size_t array_size, const std::string &name, const std::vector<Type> &t, int d)
2855  : Super(array_size, name, t, d) {
2856  }
2857 
2858  // TODO: This used to take the buffer as a const ref. This no longer works as
2859  // using it in a Pipeline might change the dev field so it is currently
2860  // not considered const. We should consider how this really ought to work.
2861  template<typename T2, int D2>
2863  Super::operator=(buffer);
2864  return *this;
2865  }
2866 
2867  template<typename T2>
2869  Super::operator=(stub_output_buffer);
2870  return *this;
2871  }
2872 
2874  Super::operator=(f);
2875  return *this;
2876  }
2877 };
2878 
2879 namespace Internal {
2880 
2881 template<typename T>
2882 T parse_scalar(const std::string &value) {
2883  std::istringstream iss(value);
2884  T t;
2885  iss >> t;
2886  user_assert(!iss.fail() && iss.get() == EOF) << "Unable to parse: " << value;
2887  return t;
2888 }
2889 
2890 std::vector<Type> parse_halide_type_list(const std::string &types);
2891 
2893  Dim,
2894  ArraySize };
2895 
2896 // This is a type of GeneratorParam used internally to create 'synthetic' params
2897 // (e.g. image.type, image.dim); it is not possible for user code to instantiate it.
2898 template<typename T>
2900 public:
2901  void set_from_string(const std::string &new_value_string) override {
2902  // If error_msg is not empty, this is unsettable:
2903  // display error_msg as a user error.
2904  if (!error_msg.empty()) {
2905  user_error << error_msg;
2906  }
2907  set_from_string_impl<T>(new_value_string);
2908  }
2909 
2910  std::string get_default_value() const override {
2912  return std::string();
2913  }
2914 
2915  std::string call_to_string(const std::string &v) const override {
2917  return std::string();
2918  }
2919 
2920  std::string get_c_type() const override {
2922  return std::string();
2923  }
2924 
2925  bool is_synthetic_param() const override {
2926  return true;
2927  }
2928 
2929 private:
2930  friend class GeneratorParamInfo;
2931 
2932  static std::unique_ptr<Internal::GeneratorParamBase> make(
2933  GeneratorBase *generator,
2934  const std::string &generator_name,
2935  const std::string &gpname,
2936  GIOBase &gio,
2937  SyntheticParamType which,
2938  bool defined) {
2939  std::string error_msg = defined ? "Cannot set the GeneratorParam " + gpname + " for " + generator_name + " because the value is explicitly specified in the C++ source." : "";
2940  return std::unique_ptr<GeneratorParam_Synthetic<T>>(
2941  new GeneratorParam_Synthetic<T>(gpname, gio, which, error_msg));
2942  }
2943 
2944  GeneratorParam_Synthetic(const std::string &name, GIOBase &gio, SyntheticParamType which, const std::string &error_msg = "")
2945  : GeneratorParamImpl<T>(name, T()), gio(gio), which(which), error_msg(error_msg) {
2946  }
2947 
2948  template<typename T2 = T, typename std::enable_if<std::is_same<T2, ::Halide::Type>::value>::type * = nullptr>
2949  void set_from_string_impl(const std::string &new_value_string) {
2951  gio.types_ = parse_halide_type_list(new_value_string);
2952  }
2953 
2954  template<typename T2 = T, typename std::enable_if<std::is_integral<T2>::value>::type * = nullptr>
2955  void set_from_string_impl(const std::string &new_value_string) {
2956  if (which == SyntheticParamType::Dim) {
2957  gio.dims_ = parse_scalar<T2>(new_value_string);
2958  } else if (which == SyntheticParamType::ArraySize) {
2959  gio.array_size_ = parse_scalar<T2>(new_value_string);
2960  } else {
2962  }
2963  }
2964 
2965  GIOBase &gio;
2966  const SyntheticParamType which;
2967  const std::string error_msg;
2968 };
2969 
2970 } // namespace Internal
2971 
2972 /** GeneratorContext is a class that is used when using Generators (or Stubs) directly;
2973  * it is used to allow the outer context (typically, either a Generator or "top-level" code)
2974  * to specify certain information to the inner context to ensure that inner and outer
2975  * Generators are compiled in a compatible way.
2976  *
2977  * If you are using this at "top level" (e.g. with the JIT), you can construct a GeneratorContext
2978  * with a Target:
2979  * \code
2980  * auto my_stub = MyStub(
2981  * GeneratorContext(get_target_from_environment()),
2982  * // inputs
2983  * { ... },
2984  * // generator params
2985  * { ... }
2986  * );
2987  * \endcode
2988  *
2989  * Note that all Generators embed a GeneratorContext, so if you are using a Stub
2990  * from within a Generator, you can just pass 'context()' for the GeneratorContext:
2991  * \code
2992  * struct SomeGen : Generator<SomeGen> {
2993  * void generate() {
2994  * ...
2995  * auto my_stub = MyStub(
2996  * context(), // GeneratorContext
2997  * // inputs
2998  * { ... },
2999  * // generator params
3000  * { ... }
3001  * );
3002  * ...
3003  * }
3004  * };
3005  * \endcode
3006  */
3008 public:
3010 
3011  explicit GeneratorContext(const Target &t);
3012  explicit GeneratorContext(const Target &t,
3014 
3015  GeneratorContext() = default;
3020 
3021  const Target &target() const {
3022  return target_;
3023  }
3025  return autoscheduler_params_;
3026  }
3027 
3028  // Return a copy of this GeneratorContext that uses the given Target.
3029  // This method is rarely needed; it's really provided as a convenience
3030  // for use with init_from_context().
3032 
3033  template<typename T>
3034  std::unique_ptr<T> create() const {
3035  return T::create(*this);
3036  }
3037  template<typename T, typename... Args>
3038  std::unique_ptr<T> apply(const Args &...args) const {
3039  auto t = this->create<T>();
3040  t->apply(args...);
3041  return t;
3042  }
3043 
3044 private:
3045  Target target_;
3046  AutoschedulerParams autoscheduler_params_;
3047 };
3048 
3050  // Names in this class are only intended for use in derived classes.
3051 protected:
3052  // Import a consistent list of Halide names that can be used in
3053  // Halide generators without qualification.
3072  using Var = Halide::Var;
3073  template<typename T>
3074  static Expr cast(Expr e) {
3075  return Halide::cast<T>(e);
3076  }
3077  static Expr cast(Halide::Type t, Expr e) {
3078  return Halide::cast(t, std::move(e));
3079  }
3080  template<typename T>
3082  template<typename T = void, int D = -1>
3084  template<typename T>
3086  static Type Bool(int lanes = 1) {
3087  return Halide::Bool(lanes);
3088  }
3089  static Type Float(int bits, int lanes = 1) {
3090  return Halide::Float(bits, lanes);
3091  }
3092  static Type Int(int bits, int lanes = 1) {
3093  return Halide::Int(bits, lanes);
3094  }
3095  static Type UInt(int bits, int lanes = 1) {
3096  return Halide::UInt(bits, lanes);
3097  }
3098 };
3099 
3100 namespace Internal {
3101 
3102 template<typename... Args>
3103 struct NoRealizations : std::false_type {};
3104 
3105 template<>
3106 struct NoRealizations<> : std::true_type {};
3107 
3108 template<typename T, typename... Args>
3109 struct NoRealizations<T, Args...> {
3110  static const bool value = !std::is_convertible<T, Realization>::value && NoRealizations<Args...>::value;
3111 };
3112 
3113 // Note that these functions must never return null:
3114 // if they cannot return a valid Generator, they must assert-fail.
3115 using GeneratorFactory = std::function<AbstractGeneratorPtr(const GeneratorContext &context)>;
3116 
3118  // names used across all params, inputs, and outputs.
3119  std::set<std::string> names;
3120 
3121  // Ordered-list of non-null ptrs to GeneratorParam<> fields.
3122  std::vector<Internal::GeneratorParamBase *> filter_generator_params;
3123 
3124  // Ordered-list of non-null ptrs to Input<> fields.
3125  std::vector<Internal::GeneratorInputBase *> filter_inputs;
3126 
3127  // Ordered-list of non-null ptrs to Output<> fields; empty if old-style Generator.
3128  std::vector<Internal::GeneratorOutputBase *> filter_outputs;
3129 
3130  // list of synthetic GP's that we dynamically created; this list only exists to simplify
3131  // lifetime management, and shouldn't be accessed directly outside of our ctor/dtor,
3132  // regardless of friend access.
3133  std::vector<std::unique_ptr<Internal::GeneratorParamBase>> owned_synthetic_params;
3134 
3135  // list of dynamically-added inputs and outputs, here only for lifetime management.
3136  std::vector<std::unique_ptr<Internal::GIOBase>> owned_extras;
3137 
3138 public:
3139  friend class GeneratorBase;
3140 
3141  GeneratorParamInfo(GeneratorBase *generator, size_t size);
3142 
3143  const std::vector<Internal::GeneratorParamBase *> &generator_params() const {
3144  return filter_generator_params;
3145  }
3146  const std::vector<Internal::GeneratorInputBase *> &inputs() const {
3147  return filter_inputs;
3148  }
3149  const std::vector<Internal::GeneratorOutputBase *> &outputs() const {
3150  return filter_outputs;
3151  }
3152 };
3153 
3155 public:
3156  ~GeneratorBase() override;
3157 
3158  /** Given a data type, return an estimate of the "natural" vector size
3159  * for that data type when compiling for the current target. */
3161  return get_target().natural_vector_size(t);
3162  }
3163 
3164  /** Given a data type, return an estimate of the "natural" vector size
3165  * for that data type when compiling for the current target. */
3166  template<typename data_t>
3167  int natural_vector_size() const {
3168  return get_target().natural_vector_size<data_t>();
3169  }
3170 
3171  /**
3172  * set_inputs is a variadic wrapper around set_inputs_vector, which makes usage much simpler
3173  * in many cases, as it constructs the relevant entries for the vector for you, which
3174  * is often a bit unintuitive at present. The arguments are passed in Input<>-declaration-order,
3175  * and the types must be compatible. Array inputs are passed as std::vector<> of the relevant type.
3176  *
3177  * Note: at present, scalar input types must match *exactly*, i.e., for Input<uint8_t>, you
3178  * must pass an argument that is actually uint8_t; an argument that is int-that-will-fit-in-uint8
3179  * will assert-fail at Halide compile time.
3180  */
3181  template<typename... Args>
3182  void set_inputs(const Args &...args) {
3183  // set_inputs_vector() checks this too, but checking it here allows build_inputs() to avoid out-of-range checks.
3184  GeneratorParamInfo &pi = this->param_info();
3185  user_assert(sizeof...(args) == pi.inputs().size())
3186  << "Expected exactly " << pi.inputs().size()
3187  << " inputs but got " << sizeof...(args) << "\n";
3188  set_inputs_vector(build_inputs(std::forward_as_tuple<const Args &...>(args...), std::make_index_sequence<sizeof...(Args)>{}));
3189  }
3190 
3191  Realization realize(std::vector<int32_t> sizes) {
3192  this->check_scheduled("realize");
3193  return get_pipeline().realize(std::move(sizes), get_target());
3194  }
3195 
3196  // Only enable if none of the args are Realization; otherwise we can incorrectly
3197  // select this method instead of the Realization-as-outparam variant
3198  template<typename... Args, typename std::enable_if<NoRealizations<Args...>::value>::type * = nullptr>
3199  Realization realize(Args &&...args) {
3200  this->check_scheduled("realize");
3201  return get_pipeline().realize(std::forward<Args>(args)..., get_target());
3202  }
3203 
3205  this->check_scheduled("realize");
3207  }
3208 
3209  // Return the Pipeline that has been built by the generate() method.
3210  // This method can only be called from the schedule() method.
3211  // (This may be relaxed in the future to allow calling from generate() as
3212  // long as all Outputs have been defined.)
3214 
3215  // Create Input<Func> with dynamic type & dimensions
3216  template<typename T,
3217  typename std::enable_if<std::is_same<T, Halide::Func>::value>::type * = nullptr>
3218  GeneratorInput<T> *add_input(const std::string &name, const Type &t, int dimensions) {
3220  auto *p = new GeneratorInput<T>(name, t, dimensions);
3221  p->generator = this;
3222  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3223  param_info_ptr->filter_inputs.push_back(p);
3224  return p;
3225  }
3226 
3227  // Create Input<Buffer> with dynamic type & dimensions
3228  template<typename T,
3229  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3230  GeneratorInput<T> *add_input(const std::string &name, const Type &t, int dimensions) {
3231  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 .");
3232  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.");
3234  auto *p = new GeneratorInput<T>(name, t, dimensions);
3235  p->generator = this;
3236  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3237  param_info_ptr->filter_inputs.push_back(p);
3238  return p;
3239  }
3240 
3241  // Create Input<Buffer> with compile-time type
3242  template<typename T,
3243  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3244  GeneratorInput<T> *add_input(const std::string &name, int dimensions) {
3245  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.");
3246  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.");
3248  auto *p = new GeneratorInput<T>(name, dimensions);
3249  p->generator = this;
3250  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3251  param_info_ptr->filter_inputs.push_back(p);
3252  return p;
3253  }
3254 
3255  // Create Input<Buffer> with compile-time type & dimensions
3256  template<typename T,
3257  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3258  GeneratorInput<T> *add_input(const std::string &name) {
3259  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.");
3260  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.");
3262  auto *p = new GeneratorInput<T>(name);
3263  p->generator = this;
3264  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3265  param_info_ptr->filter_inputs.push_back(p);
3266  return p;
3267  }
3268  // Create Input<scalar>
3269  template<typename T,
3270  typename std::enable_if<std::is_arithmetic<T>::value>::type * = nullptr>
3271  GeneratorInput<T> *add_input(const std::string &name) {
3273  auto *p = new GeneratorInput<T>(name);
3274  p->generator = this;
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  // Create Input<Expr> with dynamic type
3280  template<typename T,
3281  typename std::enable_if<std::is_same<T, Expr>::value>::type * = nullptr>
3282  GeneratorInput<T> *add_input(const std::string &name, const Type &type) {
3284  auto *p = new GeneratorInput<Expr>(name);
3285  p->generator = this;
3286  p->set_type(type);
3287  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3288  param_info_ptr->filter_inputs.push_back(p);
3289  return p;
3290  }
3291 
3292  // Create Output<Func> with dynamic type & dimensions
3293  template<typename T,
3294  typename std::enable_if<std::is_same<T, Halide::Func>::value>::type * = nullptr>
3295  GeneratorOutput<T> *add_output(const std::string &name, const Type &t, int dimensions) {
3297  auto *p = new GeneratorOutput<T>(name, t, dimensions);
3298  p->generator = this;
3299  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3300  param_info_ptr->filter_outputs.push_back(p);
3301  return p;
3302  }
3303 
3304  // Create Output<Buffer> with dynamic type & dimensions
3305  template<typename T,
3306  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3307  GeneratorOutput<T> *add_output(const std::string &name, const Type &t, int dimensions) {
3308  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 .");
3309  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.");
3311  auto *p = new GeneratorOutput<T>(name, t, dimensions);
3312  p->generator = this;
3313  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3314  param_info_ptr->filter_outputs.push_back(p);
3315  return p;
3316  }
3317 
3318  // Create Output<Buffer> with compile-time type
3319  template<typename T,
3320  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3321  GeneratorOutput<T> *add_output(const std::string &name, int dimensions) {
3322  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.");
3323  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.");
3325  auto *p = new GeneratorOutput<T>(name, dimensions);
3326  p->generator = this;
3327  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3328  param_info_ptr->filter_outputs.push_back(p);
3329  return p;
3330  }
3331 
3332  // Create Output<Buffer> with compile-time type & dimensions
3333  template<typename T,
3334  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, Halide::Func>::value>::type * = nullptr>
3335  GeneratorOutput<T> *add_output(const std::string &name) {
3336  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.");
3337  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.");
3339  auto *p = new GeneratorOutput<T>(name);
3340  p->generator = this;
3341  param_info_ptr->owned_extras.push_back(std::unique_ptr<Internal::GIOBase>(p));
3342  param_info_ptr->filter_outputs.push_back(p);
3343  return p;
3344  }
3345 
3346  void add_requirement(const Expr &condition, const std::vector<Expr> &error_args);
3347 
3348  template<typename... Args,
3349  typename = typename std::enable_if<Internal::all_are_printable_args<Args...>::value>::type>
3350  HALIDE_NO_USER_CODE_INLINE void add_requirement(const Expr &condition, Args &&...error_args) {
3351  std::vector<Expr> collected_args;
3352  Internal::collect_print_args(collected_args, std::forward<Args>(error_args)...);
3353  add_requirement(condition, collected_args);
3354  }
3355 
3358  }
3359 
3360 protected:
3361  GeneratorBase(size_t size);
3362  void set_generator_names(const std::string &registered_name, const std::string &stub_name);
3363 
3364  // Note that it is explicitly legal to override init_from_context(), so that you can (say)
3365  // create a modified context with a different Target (eg with features enabled or disabled), but...
3366  //
3367  // *** WARNING ***
3368  //
3369  // Modifying the context here can be fraught with subtle hazards, especially when used
3370  // in conjunction with compiling to multitarget output. Adding or removing Feature
3371  // flags could break your build (if you are lucky), or cause subtle runtime failures (if unlucky)...
3372  //
3373  // e.g. in the latter case, say you decided to enable AVX512_SapphireRapids as an experiment,
3374  // and override init_from_context() to do just that. You'd end up being crashy on pre-AVX512
3375  // hardware, because the code that Halide injects to do runtime CPU feature detection at runtime
3376  // doesn't know it needs to do the runtime detection for this flag.
3377  //
3378  // Even if you are using multitarget output, using this as a 'hook' to enable or disable Features
3379  // can produce hard-to-maintain code in the long term: Halide has dozens of feature flags now,
3380  // many of which are orthogonal to each other and/or specific to a certain architecture
3381  // (or sub-architecture). The interaction between 'orthogonal' flags like this is essentially
3382  // Undefined Behavior (e.g. if I enable the SSE41 Feature on a Target where arch = RISCV, what happens?
3383  // Is it ignored? Does it fail to compile? Something else?). The point here is that adding Features
3384  // here may end up eventually getting added to a Target you didn't anticipate and have adverse consequences.
3385  //
3386  // With all that in mind, here are some guidelines we think will make long-term code maintenance
3387  // less painful for you:
3388  //
3389  // - Override this method *only* for temporary debugging purposes; e.g. if you
3390  // need to add the `profile` feature to a specific Generator, but your build system doesn't easily
3391  // let you specify per-Generator target features, this is the right tool for the job.
3392  //
3393  // - If your build system makes it infeasible to customize the build Target in a reasonable way,
3394  // it may be appropriate to permanently override this method to enable specific Features for
3395  // specific Generators (e.g., enabling `strict_float` is a likely example). In that case,
3396  // we would suggest:
3397  //
3398  // - *NEVER* change the arch/bits/os of the Target.
3399  // - Only add Features; don't remove Features.
3400  // - For Features that are architecture-specific, always check the arch/bits/os
3401  // of the Target to be sure it's what you expect... e.g. if you are enabling
3402  // AVX512, only do so if compiling for an x86-64 Target. Even if your code
3403  // doesn't target any other architecture at the present time, Future You will be
3404  // happier.
3405  // - If you mutate a target conditionally based on the incoming target, try to do so
3406  // so based only on the Target's arch/bits/os, and not at the Features set on the target.
3407  // If examining Features is unavoidable (e.g. enable $FOO only if $BAR is enabled),
3408  // do so as conservatively as possible, and always validate that the rest of the Target
3409  // is sensible for what you are doing.
3410  //
3411  // Furthermore, if you override this, please don't try to directly set the `target` (etc) GeneratorParams
3412  // directly; instead, construct the new GeneratorContext you want and call the superclass
3413  // implementation of init_from_context.
3414  //
3415  // TL;DR: overrides to this method should probably never be checked in to your source control system
3416  // (rather, the override should be temporary and local, for experimentation). If you must check in
3417  // overrides to this method, be paranoid that the Target you get could be something you don't expect.
3418  //
3420 
3421  virtual void call_configure() = 0;
3422  virtual void call_generate() = 0;
3423  virtual void call_schedule() = 0;
3424 
3425  void pre_build();
3426  void post_build();
3433 
3434  template<typename T>
3436 
3437  template<typename T>
3439 
3440  // A Generator's creation and usage must go in a certain phase to ensure correctness;
3441  // the state machine here is advanced and checked at various points to ensure
3442  // this is the case.
3443  enum Phase {
3444  // Generator has just come into being.
3446 
3447  // Generator has had its configure() method called. (For Generators without
3448  // a configure() method, this phase will be skipped and will advance
3449  // directly to InputsSet.)
3451 
3452  // All Input<>/Param<> fields have been set. (Applicable only in JIT mode;
3453  // in AOT mode, this can be skipped, going Created->GenerateCalled directly.)
3455 
3456  // Generator has had its generate() method called.
3458 
3459  // Generator has had its schedule() method (if any) called.
3461  } phase{Created};
3462 
3463  void check_exact_phase(Phase expected_phase) const;
3464  void check_min_phase(Phase expected_phase) const;
3465  void advance_phase(Phase new_phase);
3466 
3468 
3469  Target get_target() const {
3470  return target;
3471  }
3472  bool using_autoscheduler() const {
3473  return !autoscheduler_.value().name.empty();
3474  }
3475 
3476  // These must remain here for legacy code that access the fields directly.
3479 
3480 private:
3482  friend class GeneratorParamBase;
3483  friend class GIOBase;
3484  friend class GeneratorInputBase;
3485  friend class GeneratorOutputBase;
3486  friend class GeneratorParamInfo;
3487  friend class StubOutputBufferBase;
3488 
3489  const size_t size;
3490 
3491  // Lazily-allocated-and-inited struct with info about our various Params.
3492  // Do not access directly: use the param_info() getter.
3493  std::unique_ptr<GeneratorParamInfo> param_info_ptr;
3494 
3495  std::string generator_registered_name, generator_stub_name;
3496  Pipeline pipeline;
3497 
3498  struct Requirement {
3499  Expr condition;
3500  std::vector<Expr> error_args;
3501  };
3502  std::vector<Requirement> requirements;
3503 
3504  // Return our GeneratorParamInfo.
3505  GeneratorParamInfo &param_info();
3506 
3507  template<typename T>
3508  T *find_by_name(const std::string &name, const std::vector<T *> &v) {
3509  for (T *t : v) {
3510  if (t->name() == name) {
3511  return t;
3512  }
3513  }
3514  return nullptr;
3515  }
3516 
3517  Internal::GeneratorInputBase *find_input_by_name(const std::string &name);
3518  Internal::GeneratorOutputBase *find_output_by_name(const std::string &name);
3519 
3520  void check_scheduled(const char *m) const;
3521 
3522  void build_params(bool force = false);
3523 
3524  // Provide private, unimplemented, wrong-result-type methods here
3525  // so that Generators don't attempt to call the global methods
3526  // of the same name by accident: use the get_target() method instead.
3527  void get_host_target();
3528  void get_jit_target_from_environment();
3529  void get_target_from_environment();
3530 
3531  void set_inputs_vector(const std::vector<std::vector<StubInput>> &inputs);
3532 
3533  static void check_input_is_singular(Internal::GeneratorInputBase *in);
3534  static void check_input_is_array(Internal::GeneratorInputBase *in);
3535  static void check_input_kind(Internal::GeneratorInputBase *in, Internal::ArgInfoKind kind);
3536 
3537  // Allow Buffer<> if:
3538  // -- we are assigning it to an Input<Buffer<>> (with compatible type and dimensions),
3539  // causing the Input<Buffer<>> to become a precompiled buffer in the generated code.
3540  // -- we are assigningit to an Input<Func>, in which case we just Func-wrap the Buffer<>.
3541  template<typename T, int Dims>
3542  std::vector<StubInput> build_input(size_t i, const Buffer<T, Dims> &arg) {
3543  auto *in = param_info().inputs().at(i);
3544  check_input_is_singular(in);
3545  const auto k = in->kind();
3546  if (k == Internal::ArgInfoKind::Buffer) {
3547  Halide::Buffer<> b = arg;
3548  StubInputBuffer<> sib(b);
3549  StubInput si(sib);
3550  return {si};
3551  } else if (k == Internal::ArgInfoKind::Function) {
3552  Halide::Func f(arg.name() + "_im");
3553  f(Halide::_) = arg(Halide::_);
3554  StubInput si(f);
3555  return {si};
3556  } else {
3557  check_input_kind(in, Internal::ArgInfoKind::Buffer); // just to trigger assertion
3558  return {};
3559  }
3560  }
3561 
3562  // Allow Input<Buffer<>> if:
3563  // -- we are assigning it to another Input<Buffer<>> (with compatible type and dimensions),
3564  // allowing us to simply pipe a parameter from an enclosing Generator to the Invoker.
3565  // -- we are assigningit to an Input<Func>, in which case we just Func-wrap the Input<Buffer<>>.
3566  template<typename T, int Dims>
3567  std::vector<StubInput> build_input(size_t i, const GeneratorInput<Buffer<T, Dims>> &arg) {
3568  auto *in = param_info().inputs().at(i);
3569  check_input_is_singular(in);
3570  const auto k = in->kind();
3571  if (k == Internal::ArgInfoKind::Buffer) {
3572  StubInputBuffer<> sib = arg;
3573  StubInput si(sib);
3574  return {si};
3575  } else if (k == Internal::ArgInfoKind::Function) {
3576  Halide::Func f = arg.funcs().at(0);
3577  StubInput si(f);
3578  return {si};
3579  } else {
3580  check_input_kind(in, Internal::ArgInfoKind::Buffer); // just to trigger assertion
3581  return {};
3582  }
3583  }
3584 
3585  // Allow Func iff we are assigning it to an Input<Func> (with compatible type and dimensions).
3586  std::vector<StubInput> build_input(size_t i, const Func &arg) {
3587  auto *in = param_info().inputs().at(i);
3588  check_input_kind(in, Internal::ArgInfoKind::Function);
3589  check_input_is_singular(in);
3590  const Halide::Func &f = arg;
3591  StubInput si(f);
3592  return {si};
3593  }
3594 
3595  // Allow vector<Func> iff we are assigning it to an Input<Func[]> (with compatible type and dimensions).
3596  std::vector<StubInput> build_input(size_t i, const std::vector<Func> &arg) {
3597  auto *in = param_info().inputs().at(i);
3598  check_input_kind(in, Internal::ArgInfoKind::Function);
3599  check_input_is_array(in);
3600  // My kingdom for a list comprehension...
3601  std::vector<StubInput> siv;
3602  siv.reserve(arg.size());
3603  for (const auto &f : arg) {
3604  siv.emplace_back(f);
3605  }
3606  return siv;
3607  }
3608 
3609  // Expr must be Input<Scalar>.
3610  std::vector<StubInput> build_input(size_t i, const Expr &arg) {
3611  auto *in = param_info().inputs().at(i);
3612  check_input_kind(in, Internal::ArgInfoKind::Scalar);
3613  check_input_is_singular(in);
3614  StubInput si(arg);
3615  return {si};
3616  }
3617 
3618  // (Array form)
3619  std::vector<StubInput> build_input(size_t i, const std::vector<Expr> &arg) {
3620  auto *in = param_info().inputs().at(i);
3621  check_input_kind(in, Internal::ArgInfoKind::Scalar);
3622  check_input_is_array(in);
3623  std::vector<StubInput> siv;
3624  siv.reserve(arg.size());
3625  for (const auto &value : arg) {
3626  siv.emplace_back(value);
3627  }
3628  return siv;
3629  }
3630 
3631  // Any other type must be convertible to Expr and must be associated with an Input<Scalar>.
3632  // Use is_arithmetic since some Expr conversions are explicit.
3633  template<typename T,
3634  typename std::enable_if<std::is_arithmetic<T>::value>::type * = nullptr>
3635  std::vector<StubInput> build_input(size_t i, const T &arg) {
3636  auto *in = param_info().inputs().at(i);
3637  check_input_kind(in, Internal::ArgInfoKind::Scalar);
3638  check_input_is_singular(in);
3639  // We must use an explicit Expr() ctor to preserve the type
3640  Expr e(arg);
3641  StubInput si(e);
3642  return {si};
3643  }
3644 
3645  // (Array form)
3646  template<typename T,
3647  typename std::enable_if<std::is_arithmetic<T>::value>::type * = nullptr>
3648  std::vector<StubInput> build_input(size_t i, const std::vector<T> &arg) {
3649  auto *in = param_info().inputs().at(i);
3650  check_input_kind(in, Internal::ArgInfoKind::Scalar);
3651  check_input_is_array(in);
3652  std::vector<StubInput> siv;
3653  siv.reserve(arg.size());
3654  for (const auto &value : arg) {
3655  // We must use an explicit Expr() ctor to preserve the type;
3656  // otherwise, implicit conversions can downgrade (e.g.) float -> int
3657  Expr e(value);
3658  siv.emplace_back(e);
3659  }
3660  return siv;
3661  }
3662 
3663  template<typename... Args, size_t... Indices>
3664  std::vector<std::vector<StubInput>> build_inputs(const std::tuple<const Args &...> &t, std::index_sequence<Indices...>) {
3665  return {build_input(Indices, std::get<Indices>(t))...};
3666  }
3667 
3668  // Note that this deliberately ignores inputs/outputs with multiple array values
3669  // (ie, one name per input or output, regardless of array_size())
3670  template<typename T>
3671  static void get_arguments(std::vector<AbstractGenerator::ArgInfo> &args, ArgInfoDirection dir, const T &t) {
3672  for (auto *e : t) {
3673  args.push_back({e->name(),
3674  dir,
3675  e->kind(),
3676  e->gio_types_defined() ? e->gio_types() : std::vector<Type>{},
3677  e->dims_defined() ? e->dims() : 0});
3678  }
3679  }
3680 
3681 public:
3682  // AbstractGenerator methods
3683  std::string name() override;
3684  GeneratorContext context() const override;
3685  std::vector<ArgInfo> arginfos() override;
3687 
3688  void set_generatorparam_value(const std::string &name, const std::string &value) override;
3689  void set_generatorparam_value(const std::string &name, const LoopLevel &loop_level) override;
3690 
3691  std::vector<Parameter> input_parameter(const std::string &name) override;
3692  std::vector<Func> output_func(const std::string &name) override;
3693 
3694  // This is overridden in the concrete Generator<> subclass.
3695  // Pipeline build_pipeline() override;
3696 
3697  void bind_input(const std::string &name, const std::vector<Parameter> &v) override;
3698  void bind_input(const std::string &name, const std::vector<Func> &v) override;
3699  void bind_input(const std::string &name, const std::vector<Expr> &v) override;
3700 
3701  bool emit_cpp_stub(const std::string &stub_file_path) override;
3702  bool emit_hlpipe(const std::string &hlpipe_file_path) override;
3703 
3704  GeneratorBase(const GeneratorBase &) = delete;
3706  GeneratorBase(GeneratorBase &&that) = delete;
3708 };
3709 
3711 public:
3712  static void register_factory(const std::string &name, GeneratorFactory generator_factory);
3713  static void unregister_factory(const std::string &name);
3714  static std::vector<std::string> enumerate();
3715  // This method returns nullptr if it cannot return a valid Generator;
3716  // the caller is responsible for checking the result.
3717  static AbstractGeneratorPtr create(const std::string &name,
3718  const Halide::GeneratorContext &context);
3719 
3720 private:
3721  using GeneratorFactoryMap = std::map<const std::string, GeneratorFactory>;
3722 
3723  GeneratorFactoryMap factories;
3724  std::mutex mutex;
3725 
3726  static GeneratorRegistry &get_registry();
3727 
3728  GeneratorRegistry() = default;
3729 
3730 public:
3735 };
3736 
3737 } // namespace Internal
3738 
3739 template<class T>
3741 protected:
3743  : Internal::GeneratorBase(sizeof(T)) {
3744  }
3745 
3746 public:
3747  static std::unique_ptr<T> create(const Halide::GeneratorContext &context) {
3748  // We must have an object of type T (not merely GeneratorBase) to call a protected method,
3749  // because CRTP is a weird beast.
3750  auto g = std::make_unique<T>();
3751  g->init_from_context(context);
3752  return g;
3753  }
3754 
3755  // This is public but intended only for use by the HALIDE_REGISTER_GENERATOR() macro.
3756  static std::unique_ptr<T> create(const Halide::GeneratorContext &context,
3757  const std::string &registered_name,
3758  const std::string &stub_name) {
3759  auto g = create(context);
3760  g->set_generator_names(registered_name, stub_name);
3761  return g;
3762  }
3763 
3764  template<typename... Args>
3765  void apply(const Args &...args) {
3766  call_configure();
3767  set_inputs(args...);
3768  call_generate();
3769  call_schedule();
3770  }
3771 
3772  template<typename T2>
3773  std::unique_ptr<T2> create() const {
3774  return T2::create(context());
3775  }
3776 
3777  template<typename T2, typename... Args>
3778  std::unique_ptr<T2> apply(const Args &...args) const {
3779  auto t = this->create<T2>();
3780  t->apply(args...);
3781  return t;
3782  }
3783 
3784 private:
3785  // std::is_member_function_pointer will fail if there is no member of that name,
3786  // so we use a little SFINAE to detect if there are method-shaped members.
3787  template<typename>
3788  struct type_sink {
3789  typedef void type;
3790  };
3791 
3792  template<typename T2, typename = void>
3793  struct has_configure_method : std::false_type {};
3794 
3795  template<typename T2>
3796  struct has_configure_method<T2, typename type_sink<decltype(std::declval<T2>().configure())>::type> : std::true_type {};
3797 
3798  template<typename T2, typename = void>
3799  struct has_generate_method : std::false_type {};
3800 
3801  template<typename T2>
3802  struct has_generate_method<T2, typename type_sink<decltype(std::declval<T2>().generate())>::type> : std::true_type {};
3803 
3804  template<typename T2, typename = void>
3805  struct has_schedule_method : std::false_type {};
3806 
3807  template<typename T2>
3808  struct has_schedule_method<T2, typename type_sink<decltype(std::declval<T2>().schedule())>::type> : std::true_type {};
3809 
3810  Pipeline build_pipeline_impl() {
3811  T *t = (T *)this;
3812  // No: configure() must be called prior to this
3813  // (and in fact, prior to calling set_inputs).
3814  //
3815  // t->call_configure_impl();
3816 
3817  t->call_generate_impl();
3818  t->call_schedule_impl();
3819  return get_pipeline();
3820  }
3821 
3822  void call_configure_impl() {
3823  pre_configure();
3824  if constexpr (has_configure_method<T>::value) {
3825  T *t = (T *)this;
3826  static_assert(std::is_void<decltype(t->configure())>::value, "configure() must return void");
3827  t->configure();
3828  }
3829  post_configure();
3830  }
3831 
3832  void call_generate_impl() {
3833  pre_generate();
3834  static_assert(has_generate_method<T>::value, "Expected a generate() method here.");
3835  T *t = (T *)this;
3836  static_assert(std::is_void<decltype(t->generate())>::value, "generate() must return void");
3837  t->generate();
3838  post_generate();
3839  }
3840 
3841  void call_schedule_impl() {
3842  pre_schedule();
3843  if constexpr (has_schedule_method<T>::value) {
3844  T *t = (T *)this;
3845  static_assert(std::is_void<decltype(t->schedule())>::value, "schedule() must return void");
3846  t->schedule();
3847  }
3848  post_schedule();
3849  }
3850 
3851 protected:
3854  return this->build_pipeline_impl();
3855  }
3856 
3857  void call_configure() override {
3858  this->call_configure_impl();
3859  }
3860 
3861  void call_generate() override {
3862  this->call_generate_impl();
3863  }
3864 
3865  void call_schedule() override {
3866  this->call_schedule_impl();
3867  }
3868 
3869 private:
3872  friend class ::Halide::GeneratorContext;
3873 
3874 public:
3875  Generator(const Generator &) = delete;
3876  Generator &operator=(const Generator &) = delete;
3877  Generator(Generator &&that) = delete;
3878  Generator &operator=(Generator &&that) = delete;
3879 };
3880 
3881 namespace Internal {
3882 
3884 public:
3885  RegisterGenerator(const char *registered_name, GeneratorFactory generator_factory);
3886 };
3887 
3888 // -----------------------------
3889 
3890 /** ExecuteGeneratorArgs is the set of arguments to execute_generator().
3891  */
3893  // Output directory for all files generated. Must not be empty.
3894  std::string output_dir;
3895 
3896  // Type(s) of outputs to produce. Must not be empty.
3897  std::set<OutputFileType> output_types;
3898 
3899  // Target(s) to use when generating. Must not be empty.
3900  // If list contains multiple entries, a multitarget output will be produced.
3901  std::vector<Target> targets;
3902 
3903  // When generating multitarget output, use these as the suffixes for each Target
3904  // specified by the targets field. If empty, the canonical string form of
3905  // each Target will be used. If nonempty, it must be the same length as the
3906  // targets vector.
3907  std::vector<std::string> suffixes;
3908 
3909  // Name of the generator to execute (or empty if none, e.g. if generating a runtime)
3910  // Must be one recognized by the specified GeneratorFactoryProvider.
3911  std::string generator_name;
3912 
3913  // Name to use for the generated function. May include C++ namespaces,
3914  // e.g. "HalideTest::AnotherNamespace::cxx_mangling". If empty, use `generator_name`.
3915  std::string function_name;
3916 
3917  // Base filename for all outputs (differentated by file extension).
3918  // If empty, use `function_name` (ignoring any C++ namespaces).
3919  std::string file_base_name;
3920 
3921  // The name of a standalone runtime to generate. Only honors EMIT_OPTIONS 'o'
3922  // and 'static_library'. When multiple targets are specified, it picks a
3923  // runtime that is compatible with all of the targets, or fails if it cannot
3924  // find one. Flags across all of the targets that do not affect runtime code
3925  // generation, such as `no_asserts` and `no_runtime`, are ignored.
3926  std::string runtime_name;
3927 
3928  // The mode in which to build the Generator.
3929  enum BuildMode {
3930  // Build it as written.
3932 
3933  // Build a version suitable for using for gradient descent calculation.
3936 
3937  // The fn that will produce Generator(s) from the name specified.
3938  // (Note that `generator_name` is the only value that will ever be passed
3939  // for name here; it is provided for ease of interoperation with existing code.)
3940  //
3941  // If null, the default global registry of Generators will be used.
3942  using CreateGeneratorFn = std::function<AbstractGeneratorPtr(const std::string &name, const GeneratorContext &context)>;
3944 
3945  // Values to substitute for GeneratorParams in the selected Generator.
3946  // Should not contain `target`.
3947  //
3948  // If any of the generator param names specified in this map are unknown
3949  // to the Generator created, an error will occur.
3951 
3952  // Compiler Logger to use, for diagnostic work. If null, don't do any logging.
3954 
3955  // If true, log the path of all output files to stdout.
3956  bool log_outputs = false;
3957 };
3958 
3959 /**
3960  * Execute a Generator for AOT compilation -- this provides the implementation of
3961  * the command-line Generator interface `generate_filter_main()`, but with a structured
3962  * API that is more suitable for calling directly from code (vs command line).
3963  */
3965 
3966 // -----------------------------
3967 
3968 } // namespace Internal
3969 
3970 /** Create a Generator from the currently-registered Generators, use it to create a Callable.
3971  * Any GeneratorParams specified will be applied to the Generator before compilation.
3972  * If the name isn't registered, assert-fail. */
3973 // @{
3975  const std::string &name,
3976  const GeneratorParamsMap &generator_params = {});
3978  const std::string &name,
3979  const GeneratorParamsMap &generator_params = {});
3980 // @}
3981 
3982 } // namespace Halide
3983 
3984 // Define this namespace at global scope so that anonymous namespaces won't
3985 // defeat our static_assert check; define a dummy type inside so we can
3986 // check for type aliasing injected by anonymous namespace usage
3988 struct halide_global_ns;
3989 };
3990 
3991 #define _HALIDE_REGISTER_GENERATOR_IMPL(GEN_CLASS_NAME, GEN_REGISTRY_NAME, FULLY_QUALIFIED_STUB_NAME) \
3992  namespace halide_register_generator { \
3993  struct halide_global_ns; \
3994  namespace GEN_REGISTRY_NAME##_ns { \
3995  std::unique_ptr<Halide::Internal::AbstractGenerator> factory(const Halide::GeneratorContext &context); \
3996  std::unique_ptr<Halide::Internal::AbstractGenerator> factory(const Halide::GeneratorContext &context) { \
3997  using GenType = std::remove_pointer<decltype(new GEN_CLASS_NAME)>::type; /* NOLINT(bugprone-macro-parentheses) */ \
3998  return GenType::create(context, #GEN_REGISTRY_NAME, #FULLY_QUALIFIED_STUB_NAME); \
3999  } \
4000  } \
4001  namespace { \
4002  auto reg_##GEN_REGISTRY_NAME = Halide::Internal::RegisterGenerator(#GEN_REGISTRY_NAME, GEN_REGISTRY_NAME##_ns::factory); \
4003  } \
4004  } \
4005  static_assert(std::is_same<::halide_register_generator::halide_global_ns, halide_register_generator::halide_global_ns>::value, \
4006  "HALIDE_REGISTER_GENERATOR must be used at global scope");
4007 
4008 #define _HALIDE_REGISTER_GENERATOR2(GEN_CLASS_NAME, GEN_REGISTRY_NAME) \
4009  _HALIDE_REGISTER_GENERATOR_IMPL(GEN_CLASS_NAME, GEN_REGISTRY_NAME, GEN_REGISTRY_NAME)
4010 
4011 #define _HALIDE_REGISTER_GENERATOR3(GEN_CLASS_NAME, GEN_REGISTRY_NAME, FULLY_QUALIFIED_STUB_NAME) \
4012  _HALIDE_REGISTER_GENERATOR_IMPL(GEN_CLASS_NAME, GEN_REGISTRY_NAME, FULLY_QUALIFIED_STUB_NAME)
4013 
4014 // MSVC has a broken implementation of variadic macros: it expands __VA_ARGS__
4015 // as a single token in argument lists (rather than multiple tokens).
4016 // Jump through some hoops to work around this.
4017 #define __HALIDE_REGISTER_ARGCOUNT_IMPL(_1, _2, _3, COUNT, ...) \
4018  COUNT
4019 
4020 #define _HALIDE_REGISTER_ARGCOUNT_IMPL(ARGS) \
4021  __HALIDE_REGISTER_ARGCOUNT_IMPL ARGS
4022 
4023 #define _HALIDE_REGISTER_ARGCOUNT(...) \
4024  _HALIDE_REGISTER_ARGCOUNT_IMPL((__VA_ARGS__, 3, 2, 1, 0))
4025 
4026 #define ___HALIDE_REGISTER_CHOOSER(COUNT) \
4027  _HALIDE_REGISTER_GENERATOR##COUNT
4028 
4029 #define __HALIDE_REGISTER_CHOOSER(COUNT) \
4030  ___HALIDE_REGISTER_CHOOSER(COUNT)
4031 
4032 #define _HALIDE_REGISTER_CHOOSER(COUNT) \
4033  __HALIDE_REGISTER_CHOOSER(COUNT)
4034 
4035 #define _HALIDE_REGISTER_GENERATOR_PASTE(A, B) \
4036  A B
4037 
4038 #define HALIDE_REGISTER_GENERATOR(...) \
4039  _HALIDE_REGISTER_GENERATOR_PASTE(_HALIDE_REGISTER_CHOOSER(_HALIDE_REGISTER_ARGCOUNT(__VA_ARGS__)), (__VA_ARGS__))
4040 
4041 // HALIDE_REGISTER_GENERATOR_ALIAS() can be used to create an an alias-with-a-particular-set-of-param-values
4042 // for a given Generator in the build system. Normally, you wouldn't want to do this;
4043 // however, some existing Halide clients have build systems that make it challenging to
4044 // specify GeneratorParams inside the build system, and this allows a somewhat simpler
4045 // customization route for them. It's highly recommended you don't use this for new code.
4046 //
4047 // The final argument is really an initializer-list of GeneratorParams, in the form
4048 // of an initializer-list for map<string, string>:
4049 //
4050 // { { "gp-name", "gp-value"} [, { "gp2-name", "gp2-value" }] }
4051 //
4052 // It is specified as a variadic template argument to allow for the fact that the embedded commas
4053 // would otherwise confuse the preprocessor; since (in this case) all we're going to do is
4054 // pass it thru as-is, this is fine (and even MSVC's 'broken' __VA_ARGS__ should be OK here).
4055 #define HALIDE_REGISTER_GENERATOR_ALIAS(GEN_REGISTRY_NAME, ORIGINAL_REGISTRY_NAME, ...) \
4056  namespace halide_register_generator { \
4057  struct halide_global_ns; \
4058  namespace ORIGINAL_REGISTRY_NAME##_ns { \
4059  std::unique_ptr<Halide::Internal::AbstractGenerator> factory(const Halide::GeneratorContext &context); \
4060  } \
4061  namespace GEN_REGISTRY_NAME##_ns { \
4062  std::unique_ptr<Halide::Internal::AbstractGenerator> factory(const Halide::GeneratorContext &context) { \
4063  auto g = ORIGINAL_REGISTRY_NAME##_ns::factory(context); \
4064  const Halide::GeneratorParamsMap m = __VA_ARGS__; \
4065  g->set_generatorparam_values(m); \
4066  return g; \
4067  } \
4068  } \
4069  namespace { \
4070  auto reg_##GEN_REGISTRY_NAME = Halide::Internal::RegisterGenerator(#GEN_REGISTRY_NAME, GEN_REGISTRY_NAME##_ns::factory); \
4071  } \
4072  } \
4073  static_assert(std::is_same<::halide_register_generator::halide_global_ns, halide_register_generator::halide_global_ns>::value, \
4074  "HALIDE_REGISTER_GENERATOR_ALIAS must be used at global scope");
4075 
4076 // The HALIDE_GENERATOR_PYSTUB macro is used to produce "PyStubs" -- i.e., CPython wrappers to let a C++ Generator
4077 // be called from Python. It shouldn't be necessary to use by anything but the build system in most cases.
4078 
4079 #define HALIDE_GENERATOR_PYSTUB(GEN_REGISTRY_NAME, MODULE_NAME) \
4080  static_assert(PY_MAJOR_VERSION >= 3, "Python bindings for Halide require Python 3+"); \
4081  extern "C" PyObject *_halide_pystub_impl(const char *module_name, const Halide::Internal::GeneratorFactory &factory); \
4082  namespace halide_register_generator::GEN_REGISTRY_NAME##_ns { \
4083  extern std::unique_ptr<Halide::Internal::AbstractGenerator> factory(const Halide::GeneratorContext &context); \
4084  } \
4085  extern "C" HALIDE_EXPORT_SYMBOL PyObject *PyInit_##MODULE_NAME() { \
4086  const auto factory = halide_register_generator::GEN_REGISTRY_NAME##_ns::factory; \
4087  return _halide_pystub_impl(#MODULE_NAME, factory); \
4088  }
4089 
4090 #endif // HALIDE_GENERATOR_H_
#define internal_error
Definition: Errors.h:23
#define user_error
Definition: Errors.h:7
#define internal_assert(c)
Definition: Errors.h:19
Defines Func - the front-end handle on a halide function, and related classes.
#define HALIDE_GENERATOR_PARAM_TYPED_SETTER(TYPE)
Definition: Generator.h:524
#define HALIDE_FORWARD_METHOD(Class, Method)
Definition: Generator.h:1650
#define HALIDE_FORWARD_METHOD_CONST(Class, Method)
Definition: Generator.h:1656
#define HALIDE_ALWAYS_INLINE
Definition: HalideRuntime.h:49
Classes for declaring image parameters to halide pipelines.
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:47
A Halide::Buffer is a named shared reference to a Halide::Runtime::Buffer.
Definition: Buffer.h:122
Type type() const
Definition: Buffer.h:533
bool defined() const
Check if this Buffer refers to an existing Buffer.
Definition: Buffer.h:381
Helper class for identifying purpose of an Expr passed to memoize.
Definition: Func.h:685
A halide function.
Definition: Func.h:700
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())
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 > & types() const
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:491
GeneratorContext is a class that is used when using Generators (or Stubs) directly; it is used to all...
Definition: Generator.h:3007
std::unique_ptr< T > apply(const Args &...args) const
Definition: Generator.h:3038
GeneratorContext & operator=(const GeneratorContext &)=default
const AutoschedulerParams & autoscheduler_params() const
Definition: Generator.h:3024
GeneratorContext with_target(const Target &t) const
GeneratorContext(const Target &t)
GeneratorContext & operator=(GeneratorContext &&)=default
std::unique_ptr< T > create() const
Definition: Generator.h:3034
const Target & target() const
Definition: Generator.h:3021
GeneratorContext(const Target &t, const AutoschedulerParams &autoscheduler_params)
GeneratorContext(const GeneratorContext &)=default
GeneratorContext(GeneratorContext &&)=default
void call_generate() override
Definition: Generator.h:3861
Generator(Generator &&that)=delete
void call_schedule() override
Definition: Generator.h:3865
std::unique_ptr< T2 > create() const
Definition: Generator.h:3773
static std::unique_ptr< T > create(const Halide::GeneratorContext &context)
Definition: Generator.h:3747
Generator & operator=(Generator &&that)=delete
Generator & operator=(const Generator &)=delete
void apply(const Args &...args)
Definition: Generator.h:3765
static std::unique_ptr< T > create(const Halide::GeneratorContext &context, const std::string &registered_name, const std::string &stub_name)
Definition: Generator.h:3756
void call_configure() override
Definition: Generator.h:3857
std::unique_ptr< T2 > apply(const Args &...args) const
Definition: Generator.h:3778
Pipeline build_pipeline() override
Build and return the Pipeline for this AbstractGenerator.
Definition: Generator.h:3852
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:2201
GeneratorInput(size_t array_size, const std::string &name, const Type &t)
Definition: Generator.h:2246
GeneratorInput(const std::string &name, const TBase &def)
Definition: Generator.h:2211
GeneratorInput(const std::string &name, const TBase &def, const TBase &min, const TBase &max)
Definition: Generator.h:2219
typename Super::TBase TBase
Definition: Generator.h:2191
GeneratorInput(size_t array_size, const std::string &name, const TBase &def, const TBase &min, const TBase &max)
Definition: Generator.h:2224
GeneratorInput(size_t array_size, const std::string &name, IntIfNonScalar d)
Definition: Generator.h:2252
GeneratorInput(const std::string &name, const Type &t)
Definition: Generator.h:2233
GeneratorInput(size_t array_size, const std::string &name)
Definition: Generator.h:2256
GeneratorInput(size_t array_size, const std::string &name, const Type &t, int d)
Definition: Generator.h:2242
GeneratorInput(const std::string &name)
Definition: Generator.h:2207
GeneratorInput(const std::string &name, const Type &t, int d)
Definition: Generator.h:2229
GeneratorInput(size_t array_size, const std::string &name, const TBase &def)
Definition: Generator.h:2215
GeneratorInput(const std::string &name, IntIfNonScalar d)
Definition: Generator.h:2238
GeneratorOutput< T > & operator=(Buffer< T2, D2 > &buffer)
Definition: Generator.h:2862
typename Super::TBase TBase
Definition: Generator.h:2800
GeneratorOutput(const std::string &name)
Definition: Generator.h:2806
GeneratorOutput(const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2834
GeneratorOutput(const char *name)
Definition: Generator.h:2810
GeneratorOutput(const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2826
GeneratorOutput(size_t array_size, const std::string &name, int d)
Definition: Generator.h:2838
GeneratorOutput(size_t array_size, const std::string &name, const Type &t, int d)
Definition: Generator.h:2850
GeneratorOutput(const std::string &name, const Type &t, int d)
Definition: Generator.h:2830
GeneratorOutput< T > & operator=(const Internal::StubOutputBuffer< T2 > &stub_output_buffer)
Definition: Generator.h:2868
GeneratorOutput(size_t array_size, const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2854
GeneratorOutput(const std::string &name, int d)
Definition: Generator.h:2818
GeneratorOutput(size_t array_size, const std::string &name)
Definition: Generator.h:2814
GeneratorOutput(const std::string &name, const Type &t)
Definition: Generator.h:2822
GeneratorOutput(size_t array_size, const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2846
GeneratorOutput(size_t array_size, const std::string &name, const Type &t)
Definition: Generator.h:2842
GeneratorOutput< T > & operator=(const Func &f)
Definition: Generator.h:2873
GeneratorParam is a templated class that can be used to modify the behavior of the Generator at code-...
Definition: Generator.h:989
GeneratorParam(const std::string &name, const std::string &value)
Definition: Generator.h:1004
GeneratorParam(const std::string &name, const T &value, const T &min, const T &max)
Definition: Generator.h:996
GeneratorParam(const std::string &name, const T &value)
Definition: Generator.h:992
GeneratorParam(const std::string &name, const T &value, const std::map< std::string, T > &enum_map)
Definition: Generator.h:1000
An Image parameter to a halide pipeline.
Definition: ImageParam.h:23
AbstractGenerator is an ABC that defines the API a Generator must provide to work with the existing G...
A reference-counted handle to Halide's internal representation of a function.
Definition: Function.h:39
GIOBase is the base class for all GeneratorInput<> and GeneratorOutput<> instantiations; it is not pa...
Definition: Generator.h:1443
size_t array_size() const
const std::vector< Func > & funcs() const
GIOBase(size_t array_size, const std::string &name, ArgInfoKind kind, const std::vector< Type > &types, int dims)
GIOBase & operator=(const GIOBase &)=delete
void check_matching_dims(int d) const
ArgInfoKind kind() const
bool array_size_defined() const
virtual const char * input_or_output() const =0
const std::vector< Type > & gio_types() const
GIOBase & operator=(GIOBase &&)=delete
std::vector< Type > types_
Definition: Generator.h:1485
const std::vector< ElemType > & get_values() const
void check_matching_types(const std::vector< Type > &t) 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
friend class GeneratorStub
Definition: Generator.h:1519
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:1489
const std::string name_
Definition: Generator.h:1483
const std::string & name() const
const ArgInfoKind kind_
Definition: Generator.h:1484
virtual bool is_array() const
virtual void verify_internals()
virtual ~GIOBase()=default
std::vector< Expr > exprs_
Definition: Generator.h:1490
void set_type(const Type &type)
bool gio_types_defined() const
GeneratorBase * generator
Definition: Generator.h:1497
GeneratorContext context() const override
Return the Target and autoscheduler info that this Generator was created with.
std::string name() override
Return the name of this Generator.
bool allow_out_of_order_inputs_and_outputs() const override
By default, a Generator must declare all Inputs before all Outputs.
GeneratorParam< Target > target
Definition: Generator.h:3477
GeneratorInput< T > * add_input(const std::string &name, const Type &t, int dimensions)
Definition: Generator.h:3218
void bind_input(const std::string &name, const std::vector< Parameter > &v) override
Rebind a specified Input to refer to the given piece of IR, replacing the default ImageParam / Param ...
void bind_input(const std::string &name, const std::vector< Func > &v) override
GeneratorInput< T > * add_input(const std::string &name)
Definition: Generator.h:3258
void bind_input(const std::string &name, const std::vector< Expr > &v) override
bool emit_hlpipe(const std::string &hlpipe_file_path) override
Emit a Serialized Halide Pipeline (.hlpipe) file to the given path.
Realization realize(Args &&...args)
Definition: Generator.h:3199
GeneratorBase(const GeneratorBase &)=delete
GeneratorInput< T > * add_input(const std::string &name, const Type &type)
Definition: Generator.h:3282
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:3167
GeneratorInput< T > * add_input(const std::string &name, int dimensions)
Definition: Generator.h:3244
virtual void init_from_context(const Halide::GeneratorContext &context)
void check_exact_phase(Phase expected_phase) const
void set_generatorparam_value(const std::string &name, const LoopLevel &loop_level) override
void check_min_phase(Phase expected_phase) const
void realize(Realization r)
Definition: Generator.h:3204
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:3191
GeneratorOutput< T > * add_output(const std::string &name, const Type &t, int dimensions)
Definition: Generator.h:3295
std::vector< Func > output_func(const std::string &name) override
Given the name of an output, return the Func(s) for that output.
void set_generatorparam_value(const std::string &name, const std::string &value) override
Set the value for a specific GeneratorParam for an AbstractGenerator instance.
GeneratorBase(GeneratorBase &&that)=delete
GeneratorOutput< T > * add_output(const std::string &name)
Definition: Generator.h:3335
GeneratorBase & operator=(const GeneratorBase &)=delete
GeneratorOutput< T > * add_output(const std::string &name, int dimensions)
Definition: Generator.h:3321
bool emit_cpp_stub(const std::string &stub_file_path) override
Emit a Generator Stub (.stub.h) file to the given path.
std::vector< ArgInfo > arginfos() override
Return a list of all the ArgInfos for this generator.
std::vector< Parameter > input_parameter(const std::string &name) override
Given the name of an input, return the Parameter(s) for that input.
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:3182
GeneratorParam_AutoSchedulerParams autoscheduler_
Definition: Generator.h:3478
HALIDE_NO_USER_CODE_INLINE void add_requirement(const Expr &condition, Args &&...error_args)
Definition: Generator.h:3350
void add_requirement(const Expr &condition, const std::vector< Expr > &error_args)
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:3160
void advance_phase(Phase new_phase)
GeneratorBase & operator=(GeneratorBase &&that)=delete
GeneratorFactoryProvider provides a way to customize the Generators that are visible to generate_filt...
Definition: Generator.h:330
virtual AbstractGeneratorPtr create(const std::string &name, const Halide::GeneratorContext &context) const =0
Create an instance of the Generator that is registered under the given name.
GeneratorFactoryProvider(const GeneratorFactoryProvider &)=delete
GeneratorFactoryProvider & operator=(GeneratorFactoryProvider &&)=delete
virtual std::vector< std::string > enumerate() const =0
Return a list of all registered Generators that are available for use with the create() method.
GeneratorFactoryProvider & operator=(const GeneratorFactoryProvider &)=delete
GeneratorFactoryProvider(GeneratorFactoryProvider &&)=delete
GeneratorInput_Arithmetic(size_t array_size, const std::string &name)
Definition: Generator.h:2136
GeneratorInput_Arithmetic(const std::string &name, const TBase &def, const TBase &min, const TBase &max)
Definition: Generator.h:2147
GeneratorInput_Arithmetic(size_t array_size, const std::string &name, const TBase &def)
Definition: Generator.h:2141
GeneratorInput_Arithmetic(const std::string &name)
Definition: Generator.h:2127
GeneratorInput_Arithmetic(size_t array_size, const std::string &name, const TBase &def, const TBase &min, const TBase &max)
Definition: Generator.h:2154
GeneratorInput_Arithmetic(const std::string &name, const TBase &def)
Definition: Generator.h:2131
std::vector< ImageParam >::const_iterator begin() const
Definition: Generator.h:1794
std::string get_c_type() const override
Definition: Generator.h:1675
GeneratorInput_Buffer< T > & set_estimate(Var var, Expr min, Expr extent)
Definition: Generator.h:1742
GeneratorInput_Buffer(const std::string &name, const Type &t)
Definition: Generator.h:1703
GeneratorInput_Buffer(const std::string &name)
Definition: Generator.h:1691
GeneratorInput_Buffer(const std::string &name, const Type &t, int d)
Definition: Generator.h:1697
Expr operator()(std::vector< Expr > args) const
Definition: Generator.h:1721
std::vector< ImageParam >::const_iterator end() const
Definition: Generator.h:1800
Expr operator()(Args &&...args) const
Definition: Generator.h:1716
Func in(const std::vector< Func > &others)
Definition: Generator.h:1764
GeneratorInput_Buffer< T > & set_estimates(const Region &estimates)
Definition: Generator.h:1748
ImageParam operator[](size_t i) const
Definition: Generator.h:1782
ImageParam at(size_t i) const
Definition: Generator.h:1788
GeneratorInput_Buffer(const std::string &name, int d)
Definition: Generator.h:1708
std::string get_c_type() const override
Definition: Generator.h:1958
GeneratorInput_DynamicScalar(const std::string &name)
Definition: Generator.h:1963
GeneratorInput_Func(size_t array_size, const std::string &name, int d)
Definition: Generator.h:1868
Expr operator()(Args &&...args) const
Definition: Generator.h:1883
Func in(const std::vector< Func > &others)
Definition: Generator.h:1925
GeneratorInput_Func(size_t array_size, const std::string &name, const Type &t, int d)
Definition: Generator.h:1863
GeneratorInput_Func< T > & set_estimate(Var var, Expr min, Expr extent)
Definition: Generator.h:1903
GeneratorInput_Func(const std::string &name, int d)
Definition: Generator.h:1849
GeneratorInput_Func(const std::string &name, const Type &t)
Definition: Generator.h:1854
GeneratorInput_Func< T > & set_estimates(const Region &estimates)
Definition: Generator.h:1909
GeneratorInput_Func(size_t array_size, const std::string &name, const Type &t)
Definition: Generator.h:1873
Expr operator()(const std::vector< Expr > &args) const
Definition: Generator.h:1888
Func in(const Func &other)
Definition: Generator.h:1920
std::string get_c_type() const override
Definition: Generator.h:1834
GeneratorInput_Func(const std::string &name, const Type &t, int d)
Definition: Generator.h:1844
GeneratorInput_Func(const std::string &name)
Definition: Generator.h:1859
GeneratorInput_Func(size_t array_size, const std::string &name)
Definition: Generator.h:1878
GeneratorInput_Scalar(size_t array_size, const std::string &name)
Definition: Generator.h:2039
static Expr TBaseToExpr(const TBase2 &value)
Definition: Generator.h:2020
void set_estimate(const TBase &value)
Definition: Generator.h:2065
void set_estimate(size_t index, const TBase &value)
Definition: Generator.h:2087
GeneratorInput_Scalar(size_t array_size, const std::string &name, const TBase &def)
Definition: Generator.h:2044
GeneratorInput_Scalar(const std::string &name)
Definition: Generator.h:2031
GeneratorInput_Scalar(const std::string &name, const TBase &def)
Definition: Generator.h:2035
std::string get_c_type() const override
Definition: Generator.h:2013
const char * input_or_output() const override
Definition: Generator.h:1569
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:1551
GeneratorInputBase(const std::string &name, ArgInfoKind kind, const std::vector< Type > &t, int d)
void set_estimates_impl(const Region &estimates)
void check_value_writable() const override
GeneratorInputBase(size_t array_size, const std::string &name, ArgInfoKind kind, const std::vector< Type > &t, int d)
bool is_array() const override
Definition: Generator.h:1585
std::vector< ValueType >::const_iterator end() const
Definition: Generator.h:1636
const ValueType & operator[](size_t i) const
Definition: Generator.h:1618
std::vector< ValueType >::const_iterator begin() const
Definition: Generator.h:1630
GeneratorInputImpl(const std::string &name, ArgInfoKind kind, const std::vector< Type > &t, int d)
Definition: Generator.h:1592
const ValueType & at(size_t i) const
Definition: Generator.h:1624
typename std::remove_all_extents< T >::type TBase
Definition: Generator.h:1583
GeneratorOutput_Arithmetic(const std::string &name)
Definition: Generator.h:2776
GeneratorOutput_Arithmetic(size_t array_size, const std::string &name)
Definition: Generator.h:2780
GeneratorOutput_Buffer(const std::string &name, int d)
Definition: Generator.h:2539
GeneratorOutput_Buffer(size_t array_size, const std::string &name)
Definition: Generator.h:2547
GeneratorOutput_Buffer(size_t array_size, const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2553
GeneratorOutput_Buffer< T > & set_estimates(const Region &estimates)
Definition: Generator.h:2650
GeneratorOutput_Buffer(const std::string &name)
Definition: Generator.h:2519
GeneratorOutput_Buffer< T > & operator=(const Func &f)
Definition: Generator.h:2635
HALIDE_NO_USER_CODE_INLINE std::string get_c_type() const override
Definition: Generator.h:2575
GeneratorOutput_Buffer< T > & operator=(const StubOutputBuffer< T2 > &stub_output_buffer)
Definition: Generator.h:2626
const Func & operator[](size_t i) const
Definition: Generator.h:2658
HALIDE_NO_USER_CODE_INLINE T2 as() const
Definition: Generator.h:2586
GeneratorOutput_Buffer(const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2533
GeneratorOutput_Buffer(size_t array_size, const std::string &name, int d)
Definition: Generator.h:2567
HALIDE_NO_USER_CODE_INLINE GeneratorOutput_Buffer< T > & operator=(Buffer< T2, D2 > &buffer)
Definition: Generator.h:2598
GeneratorOutput_Buffer(size_t array_size, const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2561
GeneratorOutput_Buffer(const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2525
GeneratorOutput_Func< T > & set_estimate(const Var &var, const Expr &min, const Expr &extent)
Definition: Generator.h:2749
GeneratorOutput_Func(const std::string &name)
Definition: Generator.h:2701
GeneratorOutput_Func(const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2705
GeneratorOutput_Func(size_t array_size, const std::string &name, const std::vector< Type > &t, int d)
Definition: Generator.h:2717
GeneratorOutput_Func< T > & set_estimates(const Region &estimates)
Definition: Generator.h:2758
GeneratorOutput_Func(const std::string &name, int d)
Definition: Generator.h:2713
GeneratorOutput_Func< T > & operator=(const Func &f)
Definition: Generator.h:2724
const Func & operator[](size_t i) const
Definition: Generator.h:2744
GeneratorOutput_Func(const std::string &name, const std::vector< Type > &t)
Definition: Generator.h:2709
GeneratorOutputBase(const std::string &name, ArgInfoKind kind, const std::vector< Type > &t, int d)
virtual std::string get_c_type() const
Definition: Generator.h:2362
HALIDE_NO_USER_CODE_INLINE T2 as() const
Definition: Generator.h:2266
const char * input_or_output() const override
Definition: Generator.h:2368
void check_value_writable() const override
GeneratorOutputBase(size_t array_size, const std::string &name, ArgInfoKind kind, const std::vector< Type > &t, int d)
Forward schedule-related methods to the underlying Func.
GeneratorOutputImpl(const std::string &name, ArgInfoKind kind, const std::vector< Type > &t, int d)
Definition: Generator.h:2389
std::vector< ValueType >::const_iterator begin() const
Definition: Generator.h:2451
const ValueType & at(size_t i) const
Definition: Generator.h:2445
const ValueType & operator[](size_t i) const
Definition: Generator.h:2439
bool is_array() const override
Definition: Generator.h:2382
std::vector< ValueType >::const_iterator end() const
Definition: Generator.h:2457
FuncRef operator()(std::vector< ExprOrVar > args) const
Definition: Generator.h:2415
typename std::remove_all_extents< T >::type TBase
Definition: Generator.h:2379
FuncRef operator()(Args &&...args) const
Definition: Generator.h:2409
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:741
std::string get_c_type() const override
Definition: Generator.h:778
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:727
std::string get_default_value() const override
Definition: Generator.h:758
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:772
void set_impl(const T &new_value) override
Definition: Generator.h:736
void set_from_string(const std::string &new_value_string) override
std::string call_to_string(const std::string &v) const override
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:807
std::string get_default_value() const override
Definition: Generator.h:819
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:823
GeneratorParam_Bool(const std::string &name, const T &value)
Definition: Generator.h:803
std::string get_c_type() const override
Definition: Generator.h:829
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:855
std::string get_default_value() const override
Definition: Generator.h:863
GeneratorParam_Enum(const std::string &name, const T &value, const std::map< std::string, T > &enum_map)
Definition: Generator.h:837
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:849
std::string get_c_type() const override
Definition: Generator.h:859
std::string get_type_decls() const override
Definition: Generator.h:867
GeneratorParam_LoopLevel(const std::string &name, const LoopLevel &value)
Definition: Generator.h:652
std::string get_c_type() const override
Definition: Generator.h:715
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:710
bool is_looplevel_param() const override
Definition: Generator.h:719
void set(const LoopLevel &value) override
Definition: Generator.h:658
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:678
std::string get_default_value() const override
Definition: Generator.h:688
GeneratorParam_String(const std::string &name, const std::string &value)
Definition: Generator.h:920
std::string get_c_type() const override
Definition: Generator.h:935
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:923
std::string get_default_value() const override
Definition: Generator.h:927
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:931
bool is_synthetic_param() const override
Definition: Generator.h:2925
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:2915
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:2901
std::string get_default_value() const override
Definition: Generator.h:2910
std::string get_c_type() const override
Definition: Generator.h:2920
void set_from_string(const std::string &new_value_string) override
Definition: Generator.h:616
GeneratorParam_Target(const std::string &name, const T &value)
Definition: Generator.h:612
std::string get_c_type() const override
Definition: Generator.h:630
std::string get_default_value() const override
Definition: Generator.h:620
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:624
std::string get_type_decls() const override
Definition: Generator.h:912
std::string get_c_type() const override
Definition: Generator.h:904
std::string call_to_string(const std::string &v) const override
Definition: Generator.h:900
std::string get_default_value() const override
Definition: Generator.h:908
GeneratorParam_Type(const std::string &name, const T &value)
Definition: Generator.h:896
const std::string & name() const
Definition: Generator.h:400
virtual bool is_synthetic_param() const
Definition: Generator.h:461
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:455
GeneratorParamBase(const std::string &name)
virtual std::string get_default_value() const =0
void set(const std::string &new_value)
Definition: Generator.h:434
GeneratorParamBase(const GeneratorParamBase &)=delete
virtual std::string get_c_type() const =0
virtual bool is_looplevel_param() const
Definition: Generator.h:465
virtual void set_from_string(const std::string &value_string)=0
void set(const char *new_value)
Definition: Generator.h:437
void set(const std::string &new_value)
Definition: Generator.h:548
GeneratorParamImpl(const std::string &name, const T &value)
Definition: Generator.h:507
virtual void set_impl(const T &new_value)
Definition: Generator.h:554
const std::vector< Internal::GeneratorParamBase * > & generator_params() const
Definition: Generator.h:3143
const std::vector< Internal::GeneratorInputBase * > & inputs() const
Definition: Generator.h:3146
GeneratorParamInfo(GeneratorBase *generator, size_t size)
const std::vector< Internal::GeneratorOutputBase * > & outputs() const
Definition: Generator.h:3149
GeneratorRegistry & operator=(const GeneratorRegistry &)=delete
GeneratorRegistry(const GeneratorRegistry &)=delete
static AbstractGeneratorPtr 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)
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:1264
StubInputBuffer(const Buffer< T2, D2 > &b)
Definition: Generator.h:1299
static std::vector< Parameter > to_parameter_vector(const StubInputBuffer< T2 > &t)
Definition: Generator.h:1304
static std::vector< Parameter > to_parameter_vector(const std::vector< StubInputBuffer< T2 >> &v)
Definition: Generator.h:1309
ArgInfoKind kind() const
Definition: Generator.h:1405
StubInput(const StubInputBuffer< T2 > &b)
Definition: Generator.h:1392
StubInput(const Parameter &p)
Definition: Generator.h:1395
Parameter parameter() const
Definition: Generator.h:1409
StubInput(const Expr &e)
Definition: Generator.h:1401
StubInput(const Func &f)
Definition: Generator.h:1398
std::shared_ptr< AbstractGenerator > generator
Definition: Generator.h:1324
Realization realize(Args &&...args)
Definition: Generator.h:1335
StubOutputBufferBase(const Func &f, const std::shared_ptr< AbstractGenerator > &generator)
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:1358
static std::vector< StubOutputBuffer< T > > to_output_buffers(const std::vector< Func > &v, const std::shared_ptr< AbstractGenerator > &gen)
Definition: Generator.h:1368
A reference to a site in a Halide statement at the top of the body of a particular for loop.
Definition: Schedule.h:203
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()
Halide::Target Target
Definition: Generator.h:3069
static Type Bool(int lanes=1)
Definition: Generator.h:3086
static Expr cast(Expr e)
Definition: Generator.h:3074
static Expr cast(Halide::Type t, Expr e)
Definition: Generator.h:3077
static Type UInt(int bits, int lanes=1)
Definition: Generator.h:3095
static Type Int(int bits, int lanes=1)
Definition: Generator.h:3092
static Type Float(int bits, int lanes=1)
Definition: Generator.h:3089
Halide::Pipeline Pipeline
Definition: Generator.h:3064
A handle on the output buffer of a pipeline.
A scalar parameter to a halide pipeline.
Definition: Param.h:22
A reference-counted handle to a parameter to a halide pipeline.
Definition: Parameter.h:40
void set_default_value(const Expr &e)
Get and set the default values for scalar parameters.
int dimensions() const
Get the dimensionality of this parameter.
void set_max_value(const Expr &e)
void set_buffer(const Buffer< void > &b)
If the parameter is a buffer parameter, set its current value.
void set_min_value(const Expr &e)
Get and set constraints for scalar parameters.
void set_estimate(Expr e)
Type type() const
Get the type of this parameter.
A class representing a Halide pipeline.
Definition: Pipeline.h:107
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())
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:69
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:1206
auto min_forward(const Other &a, const GeneratorParam< T > &b) -> decltype(min(a,(T) b))
Definition: Generator.h:1197
std::function< AbstractGeneratorPtr(const GeneratorContext &context)> GeneratorFactory
Definition: Generator.h:3115
int generate_filter_main(int argc, char **argv)
generate_filter_main() is a convenient wrapper for GeneratorRegistry::create() + compile_to_files(); ...
const GeneratorFactoryProvider & get_registered_generators()
Return a GeneratorFactoryProvider that knows about all the currently-registered C++ Generators.
std::string halide_type_to_enum_string(const Type &t)
Definition: Generator.h:315
ConstantInterval min(const ConstantInterval &a, const ConstantInterval &b)
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)
ConstantInterval max(const ConstantInterval &a, const ConstantInterval &b)
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:297
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:2790
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:2181
typename select_type< cond< std::is_same< T, Target >::value, GeneratorParam_Target< 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:949
std::unique_ptr< AbstractGenerator > AbstractGeneratorPtr
void execute_generator(const ExecuteGeneratorArgs &args)
Execute a Generator for AOT compilation – this provides the implementation of the command-line Genera...
HALIDE_NO_USER_CODE_INLINE void collect_print_args(std::vector< Expr > &args)
Definition: IROperator.h:348
T parse_scalar(const std::string &value)
Definition: Generator.h:2882
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:308
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:1104
Type UInt(int bits, int lanes=1)
Constructing an unsigned integer type.
Definition: Type.h:546
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:551
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:1130
@ Internal
Not visible externally, similar to 'static' linkage in C.
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:1091
std::map< std::string, std::string > GeneratorParamsMap
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:1039
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:1173
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:1225
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:1026
auto operator!(const GeneratorParam< T > &a) -> decltype(!(T) a)
Not operator for GeneratorParam.
Definition: Generator.h:1245
TailStrategy
Different ways to handle a tail case in a split when the factor does not provably divide the extent.
Definition: Schedule.h:33
std::function< std::unique_ptr< Internal::CompilerLogger >(const std::string &fn_name, const Target &target)> CompilerLoggerFactory
Definition: Module.h:243
Type Int(int bits, int lanes=1)
Constructing a signed integer type.
Definition: Type.h:541
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:1013
Callable create_callable_from_generator(const GeneratorContext &context, const std::string &name, const GeneratorParamsMap &generator_params={})
Create a Generator from the currently-registered Generators, use it to create a Callable.
Expr min(const FuncRef &a, const FuncRef &b)
Explicit overloads of min and max for FuncRef.
Definition: Func.h:597
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:1156
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:1065
NameMangling
An enum to specify calling convention for extern stages.
Definition: Function.h:26
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:1117
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:1078
constexpr int AnyDims
Definition: Buffer.h:11
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:1143
Internal::ConstantInterval cast(Type t, const Internal::ConstantInterval &a)
Cast operators for ConstantIntervals.
Type Bool(int lanes=1)
Construct a boolean type.
Definition: Type.h:561
std::vector< Range > Region
A multi-dimensional box.
Definition: Expr.h:350
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:1052
Expr max(const FuncRef &a, const FuncRef &b)
Definition: Func.h:600
auto max(const GeneratorParam< T > &a, const Other &b) -> decltype(Internal::GeneratorMinMax::max_forward(a, b))
Definition: Generator.h:1238
MemoryType
An enum describing different address spaces to be used with Func::store_in.
Definition: Expr.h:353
Partition
Different ways to handle loops with a potentially optimizable boundary conditions.
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
Special the Autoscheduler to be used (if any), along with arbitrary additional arguments specific to ...
Definition: Pipeline.h:48
A fragment of Halide syntax.
Definition: Expr.h:258
HALIDE_ALWAYS_INLINE Type type() const
Get the type of this expression node.
Definition: Expr.h:327
An argument to an extern-defined Func.
static TO2 value(const FROM &from)
Definition: Generator.h:492
ExecuteGeneratorArgs is the set of arguments to execute_generator().
Definition: Generator.h:3892
CompilerLoggerFactory compiler_logger_factory
Definition: Generator.h:3953
enum Halide::Internal::ExecuteGeneratorArgs::BuildMode build_mode
std::set< OutputFileType > output_types
Definition: Generator.h:3897
std::vector< std::string > suffixes
Definition: Generator.h:3907
std::function< AbstractGeneratorPtr(const std::string &name, const GeneratorContext &context)> CreateGeneratorFn
Definition: Generator.h:3942
HALIDE_ALWAYS_INLINE bool defined() const
Definition: IntrusivePtr.h:164
static constexpr bool value
Definition: Generator.h:381
typename std::conditional< First::value, typename First::type, void >::type type
Definition: Generator.h:390
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:283
#define user_assert(c)
Definition: test.h:10