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