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