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