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