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