Halide 22.0.0 Halide compiler and libraries

Simplify_Internal.h
Go to the documentation of this file.
1#ifndef HALIDE_SIMPLIFY_VISITORS_H
2#define HALIDE_SIMPLIFY_VISITORS_H
3
4/** \file
5 * The simplifier is separated into multiple compilation units with
6 * this single shared header to speed up the build. This file is not
7 * exported in Halide.h. */
8
9#include "Bounds.h"
10#include "ConstantInterval.h"
11#include "IRMatch.h"
12#include "IRPrinter.h"
13#include "IRVisitor.h"
14#include "Scope.h"
15
16// Because this file is only included by the simplify methods and
17// doesn't go into Halide.h, we're free to use any old names for our
18// macros.
19
20#define LOG_EXPR_MUTATIONS 0
21#define LOG_STMT_MUTATIONS 0
22
23// On old compilers, some visitors would use large stack frames,
24// because they use expression templates that generate large numbers
25// of temporary objects when they are built and matched against. If we
26// wrap the expressions that imply lots of temporaries in a lambda, we
27// can get these large frames out of the recursive path.
28#define EVAL_IN_LAMBDA(x) (([&]() HALIDE_NEVER_INLINE { return (x); })())
29
30namespace Halide {
31namespace Internal {
32
33 class Simplify : public VariadicVisitor<Simplify, Expr, Stmt> {
34 using Super = VariadicVisitor<Simplify, Expr, Stmt>;
35
36public:
37 Simplify(const Scope<Interval> *bi, const Scope<ModulusRemainder> *ai);
38
39 struct ExprInfo {
40 // We track constant integer bounds when they exist
41 ConstantInterval bounds;
42 // And the alignment of integer variables
43 ModulusRemainder alignment;
44
45 void trim_bounds_using_alignment() {
46 if (alignment.modulus == 0) {
47 bounds = ConstantInterval::single_point(alignment.remainder);
48 } else if (alignment.modulus > 1) {
49 if (bounds.min_defined) {
50 int64_t adjustment;
51 bool no_overflow = sub_with_overflow(64, alignment.remainder, mod_imp(bounds.min, alignment.modulus), &adjustment);
52 adjustment = mod_imp(adjustment, alignment.modulus);
53 int64_t new_min;
54 no_overflow &= add_with_overflow(64, bounds.min, adjustment, &new_min);
55 if (no_overflow) {
56 bounds.min = new_min;
57 }
58 }
59 if (bounds.max_defined) {
60 int64_t adjustment;
61 bool no_overflow = sub_with_overflow(64, mod_imp(bounds.max, alignment.modulus), alignment.remainder, &adjustment);
62 adjustment = mod_imp(adjustment, alignment.modulus);
63 int64_t new_max;
64 no_overflow &= sub_with_overflow(64, bounds.max, adjustment, &new_max);
65 if (no_overflow) {
66 bounds.max = new_max;
67 }
68 }
69 }
70
71 if (bounds.is_single_point()) {
72 alignment.modulus = 0;
73 alignment.remainder = bounds.min;
74 }
75
76 if (bounds.is_bounded() && bounds.min > bounds.max) {
77 // Impossible, we must be in unreachable code. TODO: surface
78 // this to the simplify instance's in_unreachable flag.
79 bounds.max = bounds.min;
80 }
81 }
82
83 uint64_t largest_power_of_two_factor(uint64_t x) const {
84 // Consider the bits of x from MSB to LSB. Say there are three
85 // trailing zeros, and the four high bits are unknown:
86 // a b c d 1 0 0 0
87 // The largest power of two factor of a number is the trailing bits
88 // up to and including the first 1. In this example that's 1000
89 // (i.e. 8).
90 // Negating is flipping the bits and adding one. First we flip:
91 // ~a ~b ~c ~d 0 1 1 1
92 // Then we add one:
93 // ~a ~b ~c ~d 1 0 0 0
94 // If we bitwise and this with the original, the unknown bits cancel
95 // out, and we get left with just the largest power of two
96 // factor. If we want a mask of the trailing zeros instead, we can
97 // just subtract one.
98 return x & -x;
99 }
100
101 void cast_to(Type t) {
102 if ((!t.is_int() && !t.is_uint()) || (t.is_int() && t.bits() >= 32)) {
103 return;
104 }
105
106 // We've just done some infinite-integer operation on a bounded
107 // integer type, and we need to project the bounds and alignment
108 // back in-range.
109
110 if (!t.can_represent(bounds)) {
111 if (t.bits() >= 64) {
112 // Just preserve any power-of-two factor in the modulus. When
113 // alignment.modulus == 0, the value is some positive constant
114 // representable as any 64-bit integer type, so there's no
115 // wraparound.
116 if (alignment.modulus > 0) {
117 alignment.modulus = largest_power_of_two_factor(alignment.modulus);
118 alignment.remainder &= alignment.modulus - 1;
119 }
120 } else {
121 // A narrowing integer cast that could possibly overflow adds
122 // some unknown multiple of 2^bits
123 alignment = alignment + ModulusRemainder(((int64_t)1 << t.bits()), 0);
124 }
125 }
126
127 // Truncate the bounds to the new type.
128 bounds.cast_to(t);
129 }
130
131 // Mix in existing knowledge about this Expr
132 void intersect(const ExprInfo &other) {
133 if (bounds < other.bounds || other.bounds < bounds) {
134 // Impossible. We must be in unreachable code. TODO: It might
135 // be nice to surface this to the simplify instance's
136 // in_unreachable flag, but we'd have to be sure that it's going
137 // to be caught at the right place.
138 return;
139 }
140 bounds = ConstantInterval::make_intersection(bounds, other.bounds);
141 alignment = ModulusRemainder::intersect(alignment, other.alignment);
142 trim_bounds_using_alignment();
143 }
144
145 // An alternative representation for information about integers is that
146 // certain bits have known values in the 2s complement
147 // representation. This is a useful form for analyzing bitwise ops, so
148 // we provide conversions to and from that representation. For narrow
149 // types, this represent what the bits would be if they were sign or
150 // zero-extended to 64 bits, so for uints the high bits are known to be
151 // zero, and for ints it depends on whether or not we knew the high bit
152 // to begin with.
153 struct BitsKnown {
154 // A mask which is 1 where we know the value of that bit
155 uint64_t mask;
156 // The actual value of the known bits
157 uint64_t value;
158
159 uint64_t known_zeros() const {
160 return mask & ~value;
161 }
162
163 uint64_t known_ones() const {
164 return mask & value;
165 }
166
167 bool all_bits_known() const {
168 return mask == (uint64_t)(-1);
169 }
170
171 BitsKnown operator&(const BitsKnown &other) const {
172 // Where either has known zeros, we have known zeros in the result
173 uint64_t zeros = known_zeros() | other.known_zeros();
174 // Where both have a known one, we have a known one in the result
175 uint64_t ones = known_ones() & other.known_ones();
176 return {zeros | ones, ones};
177 }
178
179 BitsKnown operator|(const BitsKnown &other) const {
180 // Where either has known ones, we have known ones in the result
181 uint64_t ones = known_ones() | other.known_ones();
182 // Where both have a known zero, we have a known zero in the result.
183 uint64_t zeros = known_zeros() & other.known_zeros();
184 return {zeros | ones, ones};
185 }
186
187 BitsKnown operator^(const BitsKnown &other) const {
188 // Unlike & and |, we need to know both bits to know anything.
189 uint64_t new_mask = mask & other.mask;
190 return {new_mask, (value ^ other.value) & new_mask};
191 }
192 };
193
194 BitsKnown to_bits_known(const Type &type) const;
195 void from_bits_known(BitsKnown known, const Type &type);
196 };
197
198 HALIDE_ALWAYS_INLINE
199 void clear_expr_info(ExprInfo *info) {
200 if (info) {
201 *info = ExprInfo{};
202 }
203 }
204
205 void set_expr_info_to_constant(ExprInfo *info, int64_t c) const {
206 if (info) {
207 info->bounds = ConstantInterval::single_point(c);
208 info->alignment = ModulusRemainder{0, c};
209 }
210 }
211
212 int64_t normalize_constant(const Type &t, int64_t c) {
213 // If this is supposed to be an int32, but the constant is not
214 // representable as an int32, we have a problem, because the Halide
215 // simplifier is unsound with respect to int32 overflow (see
216 // https://github.com/halide/Halide/issues/3245).
217
218 // It's tempting to just say we return a signed_integer_overflow, for
219 // which we know nothing, but if we're in this function we're making a
220 // constant, so we clearly decided not to do that in the caller. Is this
221 // a bug in the caller? No, this intentionally happens when
222 // constant-folding narrowing casts, and changing that behavior to
223 // return signed_integer_overflow breaks a bunch of real code, because
224 // unfortunately that's how people express wrapping casts to int32. We
225 // could return an ExprInfo that says "I know nothing", but we're also
226 // returning a constant Expr, so the next mutation is just going to
227 // infer everything there is to infer about a constant. The best we can
228 // do at this point is just wrap to the right number of bits.
229 int dropped_bits = 64 - t.bits();
230 if (t.is_int()) {
231 c <<= dropped_bits;
232 c >>= dropped_bits; // sign-extend
233 } else if (t.is_uint()) {
234 // For uints, normalization is considerably less problematic
235 c <<= dropped_bits;
236 c = (int64_t)(((uint64_t)c >> dropped_bits)); // zero-extend
237 }
238 return c;
239 }
240
241 // We never want to return make_const anything in the simplifier without
242 // also setting the ExprInfo, so shadow the global make_const.
243 Expr make_const(const Type &t, int64_t c, ExprInfo *info) {
244 c = normalize_constant(t, c);
245 set_expr_info_to_constant(info, c);
246 return Halide::Internal::make_const(t, c);
247 }
248
249 Expr make_const(const Type &t, uint64_t c, ExprInfo *info) {
250 c = normalize_constant(t, c);
251
252 if ((int64_t)c >= 0) {
253 // This is representable as an int64_t
254 set_expr_info_to_constant(info, (int64_t)c);
255 } else if (info) {
256 // If it's not representable as an int64, we can't express
257 // everything we know about it in ExprInfo.
258 // We can say that it's big:
259 info->bounds = ConstantInterval::bounded_below(INT64_MAX);
260 // And we can say what we know about the bottom 62 bits (2^62 is the
261 // largest power of two we can represent as an int64_t):
262 int64_t modulus = (int64_t)1 << 62;
263 info->alignment = {modulus, (int64_t)c & (modulus - 1)};
264 }
265 return Halide::Internal::make_const(t, c);
266 }
267
268 HALIDE_ALWAYS_INLINE
269 Expr make_const(const Type &t, double c, ExprInfo *info) {
270 // We don't currently track information about floats
271 return Halide::Internal::make_const(t, c);
272 }
273
274 HALIDE_ALWAYS_INLINE
275 Expr const_false(int lanes, ExprInfo *info) {
276 return make_const(UInt(1, lanes), (int64_t)0, info);
277 }
278
279 HALIDE_ALWAYS_INLINE
280 Expr const_true(int lanes, ExprInfo *info) {
281 return make_const(UInt(1, lanes), (int64_t)1, info);
282 }
283
284#if (LOG_EXPR_MUTATIONS || LOG_STMT_MUTATIONS)
285 int debug_indent = 0;
286#endif
287
288#if LOG_EXPR_MUTATIONS
289 Expr mutate(const Expr &e, ExprInfo *b) {
290 internal_assert(debug_indent >= 0);
291 const std::string spaces(debug_indent, ' ');
292 debug(1) << spaces << "Simplifying Expr: " << e << "\n";
293 debug_indent++;
294 Expr new_e = Super::dispatch(e, b);
295 debug_indent--;
296 if (!new_e.same_as(e)) {
297 debug(1)
298 << spaces << "Before: " << e << "\n"
299 << spaces << "After: " << new_e << "\n";
300 if (b) {
301 debug(1)
302 << spaces << "Bounds: " << b->bounds << " " << b->alignment << "\n";
303 if (auto i = as_const_int(new_e)) {
304 internal_assert(b->bounds.contains(*i))
305 << e << "\n"
306 << new_e << "\n"
307 << b->bounds;
308 } else if (auto i = as_const_uint(new_e)) {
309 internal_assert(b->bounds.contains(*i))
310 << e << "\n"
311 << new_e << "\n"
312 << b->bounds;
313 }
314 if (new_e.type().is_uint() &&
315 new_e.type().bits() < 64 &&
316 !is_signed_integer_overflow(new_e)) {
317 internal_assert(b->bounds.min_defined && b->bounds.min >= 0)
318 << e << "\n"
319 << new_e << "\n"
320 << b->bounds;
321 }
322 }
323 }
324 internal_assert(e.type() == new_e.type());
325 return new_e;
326 }
327
328#else
329 HALIDE_ALWAYS_INLINE
330 Expr mutate(const Expr &e, ExprInfo *b) {
331 // This gets inlined into every call to mutate, so do not add any code here.
332 return Super::dispatch(e, b);
333 }
334#endif
335
336#if LOG_STMT_MUTATIONS
337 Stmt mutate(const Stmt &s) {
338 const std::string spaces(debug_indent, ' ');
339 debug(1) << spaces << "Simplifying Stmt: " << s << "\n";
340 debug_indent++;
341 Stmt new_s = Super::dispatch(s);
342 debug_indent--;
343 if (!new_s.same_as(s)) {
344 debug(1)
345 << spaces << "Before: " << s << "\n"
346 << spaces << "After: " << new_s << "\n";
347 }
348 return new_s;
349 }
350#else
351 Stmt mutate(const Stmt &s) {
352 return Super::dispatch(s);
353 }
354#endif
355
356 // Returns true iff t is an integral type where overflow is undefined
357 HALIDE_ALWAYS_INLINE
358 bool no_overflow_int(Type t) {
359 return t.is_int() && t.bits() >= 32;
360 }
361
362 HALIDE_ALWAYS_INLINE
363 bool no_overflow_scalar_int(Type t) {
364 return t.is_scalar() && no_overflow_int(t);
365 }
366
367 // Returns true iff t does not have a well defined overflow behavior.
368 HALIDE_ALWAYS_INLINE
369 bool no_overflow(Type t) {
370 return t.is_float() || no_overflow_int(t);
371 }
372
373 struct VarInfo {
374 Expr replacement;
375 int old_uses, new_uses;
376 };
377
378 // Tracked for all let vars
379 Scope<VarInfo> var_info;
380
381 // Only tracked for integer let vars
382 Scope<ExprInfo> bounds_and_alignment_info;
383
384 // Symbols used by rewrite rules
385 IRMatcher::Wild<0> x;
386 IRMatcher::Wild<1> y;
387 IRMatcher::Wild<2> z;
388 IRMatcher::Wild<3> w;
389 IRMatcher::Wild<4> u;
390 IRMatcher::Wild<5> v;
391 IRMatcher::WildConst<0> c0;
392 IRMatcher::WildConst<1> c1;
393 IRMatcher::WildConst<2> c2;
394 IRMatcher::WildConst<3> c3;
395 IRMatcher::WildConst<4> c4;
396 IRMatcher::WildConst<5> c5;
397
398 // Tracks whether or not we're inside a vector loop. Certain
399 // transformations are not a good idea if the code is to be
400 // vectorized.
401 bool in_vector_loop = false;
402
403 // Tracks whether or not the current IR is unconditionally unreachable.
404 bool in_unreachable = false;
405
406 // If we encounter a reference to a buffer (a Load, Store, Call,
407 // or Provide), there's an implicit dependence on some associated
408 // symbols.
409 void found_buffer_reference(const std::string &name, size_t dimensions = 0);
410
411 // Put the args to a commutative op in a canonical order
412 HALIDE_ALWAYS_INLINE
413 bool should_commute(const Expr &a, const Expr &b) {
414 if (a.node_type() < b.node_type()) {
415 return true;
416 }
417 if (a.node_type() > b.node_type()) {
418 return false;
419 }
420
421 if (a.node_type() == IRNodeType::Variable) {
422 const Variable *va = a.as<Variable>();
423 const Variable *vb = b.as<Variable>();
424 return va->name.compare(vb->name) > 0;
425 }
426
427 return false;
428 }
429
430 std::set<Expr, IRDeepCompare> truths, falsehoods;
431
432 struct ScopedFact {
433 Simplify *simplify;
434
435 std::vector<const Variable *> pop_list;
436 std::vector<const Variable *> bounds_pop_list;
437 std::set<Expr, IRDeepCompare> truths, falsehoods;
438
439 void learn_false(const Expr &fact);
440 void learn_true(const Expr &fact);
441 void learn_upper_bound(const Variable *v, int64_t val);
442 void learn_lower_bound(const Variable *v, int64_t val);
443
444 // Replace exprs known to be truths or falsehoods with const_true or const_false.
445 Expr substitute_facts(const Expr &e);
446 Stmt substitute_facts(const Stmt &s);
447
448 ScopedFact(Simplify *s)
449 : simplify(s) {
450 }
451 ~ScopedFact();
452
453 // allow move but not copy
454 ScopedFact(const ScopedFact &that) = delete;
455 ScopedFact(ScopedFact &&that) = default;
456 };
457
458 // Tell the simplifier to learn from and exploit a boolean
459 // condition, over the lifetime of the returned object.
460 ScopedFact scoped_truth(const Expr &fact) {
461 ScopedFact f(this);
462 f.learn_true(fact);
463 return f;
464 }
465
466 // Tell the simplifier to assume a boolean condition is false over
467 // the lifetime of the returned object.
468 ScopedFact scoped_falsehood(const Expr &fact) {
469 ScopedFact f(this);
470 f.learn_false(fact);
471 return f;
472 }
473
474 Stmt mutate_let_body(const Stmt &s, ExprInfo *) {
475 return mutate(s);
476 }
477 Expr mutate_let_body(const Expr &e, ExprInfo *info) {
478 return mutate(e, info);
479 }
480
481 template<typename T, typename Body>
482 Body simplify_let(const T *op, ExprInfo *info);
483
484 Expr visit(const IntImm *op, ExprInfo *info);
485 Expr visit(const UIntImm *op, ExprInfo *info);
486 Expr visit(const FloatImm *op, ExprInfo *info);
487 Expr visit(const StringImm *op, ExprInfo *info);
488 Expr visit(const Broadcast *op, ExprInfo *info);
489 Expr visit(const Cast *op, ExprInfo *info);
490 Expr visit(const Reinterpret *op, ExprInfo *info);
491 Expr visit(const Variable *op, ExprInfo *info);
492 Expr visit(const Add *op, ExprInfo *info);
493 Expr visit(const Sub *op, ExprInfo *info);
494 Expr visit(const Mul *op, ExprInfo *info);
495 Expr visit(const Div *op, ExprInfo *info);
496 Expr visit(const Mod *op, ExprInfo *info);
497 Expr visit(const Min *op, ExprInfo *info);
498 Expr visit(const Max *op, ExprInfo *info);
499 Expr visit(const EQ *op, ExprInfo *info);
500 Expr visit(const NE *op, ExprInfo *info);
501 Expr visit(const LT *op, ExprInfo *info);
502 Expr visit(const LE *op, ExprInfo *info);
503 Expr visit(const GT *op, ExprInfo *info);
504 Expr visit(const GE *op, ExprInfo *info);
505 Expr visit(const And *op, ExprInfo *info);
506 Expr visit(const Or *op, ExprInfo *info);
507 Expr visit(const Not *op, ExprInfo *info);
508 Expr visit(const Select *op, ExprInfo *info);
509 Expr visit(const Ramp *op, ExprInfo *info);
510 Stmt visit(const IfThenElse *op);
511 Expr visit(const Load *op, ExprInfo *info);
512 Expr visit(const Call *op, ExprInfo *info);
513 Expr visit(const Shuffle *op, ExprInfo *info);
514 Expr visit(const VectorReduce *op, ExprInfo *info);
515 Expr visit(const Let *op, ExprInfo *info);
516 Stmt visit(const LetStmt *op);
517 Stmt visit(const AssertStmt *op);
518 Stmt visit(const For *op);
519 Stmt visit(const Provide *op);
520 Stmt visit(const Store *op);
521 Stmt visit(const Allocate *op);
522 Stmt visit(const Evaluate *op);
523 Stmt visit(const ProducerConsumer *op);
524 Stmt visit(const Block *op);
525 Stmt visit(const Realize *op);
526 Stmt visit(const Prefetch *op);
527 Stmt visit(const Free *op);
528 Stmt visit(const Acquire *op);
529 Stmt visit(const Fork *op);
530 Stmt visit(const Atomic *op);
531 Stmt visit(const HoistedStorage *op);
532
533 std::pair<std::vector<Expr>, bool> mutate_with_changes(const std::vector<Expr> &old_exprs);
534};
535
536} // namespace Internal
537} // namespace Halide
538
539#endif
Bounds.h
Methods for computing the upper and lower bounds of an expression, and the regions of a function read...
ConstantInterval.h
Defines the ConstantInterval class, and operators on it.
debug
#define debug(n)
For optional debugging during codegen, use the debug macro as follows:
Definition: Debug.h:52
internal_assert
#define internal_assert(c)
Definition: Error.h:232
HALIDE_ALWAYS_INLINE
#define HALIDE_ALWAYS_INLINE
Definition: HalideRuntime.h:49
IRMatch.h
Defines a method to match a fragment of IR against a pattern containing wildcards.
IRPrinter.h
This header file defines operators that let you dump a Halide expression, statement,...
IRVisitor.h
Defines the base class for things that recursively walk over the IR.
Scope.h
Defines the Scope class, which is used for keeping track of names in a scope while traversing IR.
Halide::Internal::Scope
A common pattern when traversing Halide IR is that you need to keep track of stuff when you find a Le...
Definition: Scope.h:94
Halide::Internal::Simplify
Definition: Simplify_Internal.h:33
Halide::Internal::Simplify::visit
Stmt visit(const HoistedStorage *op)
Halide::Internal::Simplify::const_false
HALIDE_ALWAYS_INLINE Expr const_false(int lanes, ExprInfo *info)
Definition: Simplify_Internal.h:275
Halide::Internal::Simplify::visit
Expr visit(const LE *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Stmt visit(const ProducerConsumer *op)
Halide::Internal::Simplify::mutate
HALIDE_ALWAYS_INLINE Expr mutate(const Expr &e, ExprInfo *b)
Definition: Simplify_Internal.h:330
Halide::Internal::Simplify::z
IRMatcher::Wild< 2 > z
Definition: Simplify_Internal.h:387
Halide::Internal::Simplify::bounds_and_alignment_info
Scope< ExprInfo > bounds_and_alignment_info
Definition: Simplify_Internal.h:382
Halide::Internal::Simplify::clear_expr_info
HALIDE_ALWAYS_INLINE void clear_expr_info(ExprInfo *info)
Definition: Simplify_Internal.h:199
Halide::Internal::Simplify::visit
Expr visit(const Variable *op, ExprInfo *info)
Halide::Internal::Simplify::c5
IRMatcher::WildConst< 5 > c5
Definition: Simplify_Internal.h:396
Halide::Internal::Simplify::found_buffer_reference
void found_buffer_reference(const std::string &name, size_t dimensions=0)
Halide::Internal::Simplify::visit
Stmt visit(const Block *op)
Halide::Internal::Simplify::visit
Expr visit(const Load *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Expr visit(const Cast *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Stmt visit(const AssertStmt *op)
Halide::Internal::Simplify::u
IRMatcher::Wild< 4 > u
Definition: Simplify_Internal.h:389
Halide::Internal::Simplify::mutate
Stmt mutate(const Stmt &s)
Definition: Simplify_Internal.h:351
Halide::Internal::Simplify::visit
Stmt visit(const Evaluate *op)
Halide::Internal::Simplify::visit
Expr visit(const Let *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Expr visit(const LT *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Expr visit(const Ramp *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Stmt visit(const Prefetch *op)
Halide::Internal::Simplify::no_overflow
HALIDE_ALWAYS_INLINE bool no_overflow(Type t)
Definition: Simplify_Internal.h:369
Halide::Internal::Simplify::c1
IRMatcher::WildConst< 1 > c1
Definition: Simplify_Internal.h:392
Halide::Internal::Simplify::visit
Expr visit(const Shuffle *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Stmt visit(const IfThenElse *op)
Halide::Internal::Simplify::visit
Expr visit(const Mod *op, ExprInfo *info)
Halide::Internal::Simplify::v
IRMatcher::Wild< 5 > v
Definition: Simplify_Internal.h:390
Halide::Internal::Simplify::c0
IRMatcher::WildConst< 0 > c0
Definition: Simplify_Internal.h:391
Halide::Internal::Simplify::y
IRMatcher::Wild< 1 > y
Definition: Simplify_Internal.h:386
Halide::Internal::Simplify::in_unreachable
bool in_unreachable
Definition: Simplify_Internal.h:404
Halide::Internal::Simplify::scoped_truth
ScopedFact scoped_truth(const Expr &fact)
Definition: Simplify_Internal.h:460
Halide::Internal::Simplify::c3
IRMatcher::WildConst< 3 > c3
Definition: Simplify_Internal.h:394
Halide::Internal::Simplify::visit
Expr visit(const UIntImm *op, ExprInfo *info)
Halide::Internal::Simplify::const_true
HALIDE_ALWAYS_INLINE Expr const_true(int lanes, ExprInfo *info)
Definition: Simplify_Internal.h:280
Halide::Internal::Simplify::visit
Expr visit(const Add *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Expr visit(const Max *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Expr visit(const Mul *op, ExprInfo *info)
Halide::Internal::Simplify::c2
IRMatcher::WildConst< 2 > c2
Definition: Simplify_Internal.h:393
Halide::Internal::Simplify::visit
Expr visit(const StringImm *op, ExprInfo *info)
Halide::Internal::Simplify::in_vector_loop
bool in_vector_loop
Definition: Simplify_Internal.h:401
Halide::Internal::Simplify::var_info
Scope< VarInfo > var_info
Definition: Simplify_Internal.h:379
Halide::Internal::Simplify::visit
Expr visit(const VectorReduce *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Expr visit(const Min *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Expr visit(const Reinterpret *op, ExprInfo *info)
Halide::Internal::Simplify::w
IRMatcher::Wild< 3 > w
Definition: Simplify_Internal.h:388
Halide::Internal::Simplify::make_const
HALIDE_ALWAYS_INLINE Expr make_const(const Type &t, double c, ExprInfo *info)
Definition: Simplify_Internal.h:269
Halide::Internal::Simplify::visit
Expr visit(const NE *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Stmt visit(const For *op)
Halide::Internal::Simplify::visit
Expr visit(const Select *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Stmt visit(const Atomic *op)
Halide::Internal::Simplify::visit
Expr visit(const Div *op, ExprInfo *info)
Halide::Internal::Simplify::make_const
Expr make_const(const Type &t, int64_t c, ExprInfo *info)
Definition: Simplify_Internal.h:243
Halide::Internal::Simplify::visit
Expr visit(const GE *op, ExprInfo *info)
Halide::Internal::Simplify::normalize_constant
int64_t normalize_constant(const Type &t, int64_t c)
Definition: Simplify_Internal.h:212
Halide::Internal::Simplify::visit
Stmt visit(const Provide *op)
Halide::Internal::Simplify::visit
Expr visit(const Not *op, ExprInfo *info)
Halide::Internal::Simplify::simplify_let
Body simplify_let(const T *op, ExprInfo *info)
Halide::Internal::Simplify::mutate_let_body
Expr mutate_let_body(const Expr &e, ExprInfo *info)
Definition: Simplify_Internal.h:477
Halide::Internal::Simplify::Simplify
Simplify(const Scope< Interval > *bi, const Scope< ModulusRemainder > *ai)
Halide::Internal::Simplify::visit
Expr visit(const Or *op, ExprInfo *info)
Halide::Internal::Simplify::x
IRMatcher::Wild< 0 > x
Definition: Simplify_Internal.h:385
Halide::Internal::Simplify::visit
Expr visit(const FloatImm *op, ExprInfo *info)
Halide::Internal::Simplify::mutate_let_body
Stmt mutate_let_body(const Stmt &s, ExprInfo *)
Definition: Simplify_Internal.h:474
Halide::Internal::Simplify::visit
Stmt visit(const Acquire *op)
Halide::Internal::Simplify::set_expr_info_to_constant
void set_expr_info_to_constant(ExprInfo *info, int64_t c) const
Definition: Simplify_Internal.h:205
Halide::Internal::Simplify::visit
Stmt visit(const Fork *op)
Halide::Internal::Simplify::no_overflow_int
HALIDE_ALWAYS_INLINE bool no_overflow_int(Type t)
Definition: Simplify_Internal.h:358
Halide::Internal::Simplify::truths
std::set< Expr, IRDeepCompare > truths
Definition: Simplify_Internal.h:430
Halide::Internal::Simplify::scoped_falsehood
ScopedFact scoped_falsehood(const Expr &fact)
Definition: Simplify_Internal.h:468
Halide::Internal::Simplify::should_commute
HALIDE_ALWAYS_INLINE bool should_commute(const Expr &a, const Expr &b)
Definition: Simplify_Internal.h:413
Halide::Internal::Simplify::visit
Expr visit(const Broadcast *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Expr visit(const Sub *op, ExprInfo *info)
Halide::Internal::Simplify::mutate_with_changes
std::pair< std::vector< Expr >, bool > mutate_with_changes(const std::vector< Expr > &old_exprs)
Halide::Internal::Simplify::visit
Stmt visit(const Store *op)
Halide::Internal::Simplify::visit
Expr visit(const GT *op, ExprInfo *info)
Halide::Internal::Simplify::no_overflow_scalar_int
HALIDE_ALWAYS_INLINE bool no_overflow_scalar_int(Type t)
Definition: Simplify_Internal.h:363
Halide::Internal::Simplify::make_const
Expr make_const(const Type &t, uint64_t c, ExprInfo *info)
Definition: Simplify_Internal.h:249
Halide::Internal::Simplify::visit
Stmt visit(const Free *op)
Halide::Internal::Simplify::c4
IRMatcher::WildConst< 4 > c4
Definition: Simplify_Internal.h:395
Halide::Internal::Simplify::visit
Expr visit(const Call *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Stmt visit(const Allocate *op)
Halide::Internal::Simplify::visit
Stmt visit(const Realize *op)
Halide::Internal::Simplify::visit
Expr visit(const EQ *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Stmt visit(const LetStmt *op)
Halide::Internal::Simplify::falsehoods
std::set< Expr, IRDeepCompare > falsehoods
Definition: Simplify_Internal.h:430
Halide::Internal::Simplify::visit
Expr visit(const IntImm *op, ExprInfo *info)
Halide::Internal::Simplify::visit
Expr visit(const And *op, ExprInfo *info)
Halide::Internal::VariadicVisitor
A visitor/mutator capable of passing arbitrary arguments to the visit methods using CRTP and returnin...
Definition: IRVisitor.h:350
Halide::Internal::VariadicVisitor< Simplify, Expr, Stmt >::dispatch
HALIDE_ALWAYS_INLINE Stmt dispatch(const Stmt &s, Args &&...args)
Definition: IRVisitor.h:524
Halide::Internal::as_const_int
std::optional< int64_t > as_const_int(const Expr &e)
If an expression is an IntImm or a Broadcast of an IntImm, return a its value.
Halide::Internal::as_const_uint
std::optional< uint64_t > as_const_uint(const Expr &e)
If an expression is a UIntImm or a Broadcast of a UIntImm, return its value.
Halide::Internal::make_const
Expr make_const(Type t, int64_t val)
Construct an immediate of the given type from any numeric C++ type.
Halide::Internal::is_signed_integer_overflow
bool is_signed_integer_overflow(const Expr &expr)
Check if an expression is a signed_integer_overflow.
Halide::Internal::mod_imp
T mod_imp(T a, T b)
Implementations of division and mod that are specific to Halide.
Definition: IROperator.h:257
Halide::Internal::add_with_overflow
HALIDE_MUST_USE_RESULT bool add_with_overflow(int bits, int64_t a, int64_t b, int64_t *result)
Routines to perform arithmetic on signed types without triggering signed overflow.
Halide::Internal::sub_with_overflow
HALIDE_MUST_USE_RESULT bool sub_with_overflow(int bits, int64_t a, int64_t b, int64_t *result)
Halide::Internal::IRNodeType::Variable
@ Variable
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
Halide::UInt
Type UInt(int bits, int lanes=1)
Constructing an unsigned integer type.
Definition: Type.h:544
uint64_t
unsigned __INT64_TYPE__ uint64_t
Definition: runtime_internal.h:23
int64_t
signed __INT64_TYPE__ int64_t
Definition: runtime_internal.h:22
Halide::Expr
A fragment of Halide syntax.
Definition: Expr.h:258
Halide::Expr::type
HALIDE_ALWAYS_INLINE Type type() const
Get the type of this expression node.
Definition: Expr.h:327
Halide::Internal::Acquire
Definition: IR.h:886
Halide::Internal::Add
The sum of two expressions.
Definition: IR.h:66
Halide::Internal::Allocate
Allocate a scratch area called with the given name, type, and size.
Definition: IR.h:381
Halide::Internal::And
Logical and - are both expressions true.
Definition: IR.h:185
Halide::Internal::AssertStmt
If the 'condition' is false, then evaluate and return the message, which should be a call to an error...
Definition: IR.h:304
Halide::Internal::Atomic
Lock all the Store nodes in the body statement.
Definition: IR.h:1008
Halide::Internal::Block
A sequence of statements to be executed in-order.
Definition: IR.h:452
Halide::Internal::Broadcast
A vector with 'lanes' elements, in which every element is 'value'.
Definition: IR.h:269
Halide::Internal::Call
A function call.
Definition: IR.h:500
Halide::Internal::Cast
The actual IR nodes begin here.
Definition: IR.h:40
Halide::Internal::ConstantInterval
A class to represent ranges of integers.
Definition: ConstantInterval.h:18
Halide::Internal::ConstantInterval::min
int64_t min
The lower and upper bound of the interval.
Definition: ConstantInterval.h:21
Halide::Internal::ConstantInterval::is_bounded
bool is_bounded() const
Does the interval have a finite upper and lower bound.
Halide::Internal::ConstantInterval::make_intersection
static ConstantInterval make_intersection(const ConstantInterval &a, const ConstantInterval &b)
Construct the largest interval contained within two intervals.
Halide::Internal::ConstantInterval::bounded_below
static ConstantInterval bounded_below(int64_t min)
Construct intervals bounded above or below.
Halide::Internal::ConstantInterval::max_defined
bool max_defined
Definition: ConstantInterval.h:22
Halide::Internal::ConstantInterval::is_single_point
bool is_single_point() const
Is the interval just a single value (min == max)
Halide::Internal::ConstantInterval::max
int64_t max
Definition: ConstantInterval.h:21
Halide::Internal::ConstantInterval::cast_to
void cast_to(const Type &t)
Track what happens if a constant integer interval is forced to fit into a concrete integer type.
Halide::Internal::ConstantInterval::min_defined
bool min_defined
Definition: ConstantInterval.h:22
Halide::Internal::ConstantInterval::single_point
static ConstantInterval single_point(int64_t x)
Construct an interval representing a single point.
Halide::Internal::Div
The ratio of two expressions.
Definition: IR.h:93
Halide::Internal::EQ
Is the first expression equal to the second.
Definition: IR.h:131
Halide::Internal::Evaluate
Evaluate and discard an expression, presumably because it has some side-effect.
Definition: IR.h:486
Halide::Internal::FloatImm
Floating point constants.
Definition: Expr.h:236
Halide::Internal::For
A for loop.
Definition: IR.h:858
Halide::Internal::Fork
A pair of statements executed concurrently.
Definition: IR.h:467
Halide::Internal::Free
Free the resources associated with the given buffer.
Definition: IR.h:423
Halide::Internal::GE
Is the first expression greater than or equal to the second.
Definition: IR.h:176
Halide::Internal::GT
Is the first expression greater than the second.
Definition: IR.h:167
Halide::Internal::HoistedStorage
Represents a location where storage will be hoisted to for a Func / Realize node with a given name.
Definition: IR.h:992
Halide::Internal::IRHandle::as
const T * as() const
Downcast this ir node to its actual type (e.g.
Definition: Expr.h:205
Halide::Internal::IRHandle::node_type
IRNodeType node_type() const
Definition: Expr.h:212
Halide::Internal::IRMatcher::WildConst< 0 >
Halide::Internal::IRMatcher::Wild< 0 >
Halide::Internal::IfThenElse
An if-then-else block.
Definition: IR.h:476
Halide::Internal::IntImm
Integer constants.
Definition: Expr.h:218
Halide::Internal::IntrusivePtr::same_as
HALIDE_ALWAYS_INLINE bool same_as(const IntrusivePtr &other) const
Definition: IntrusivePtr.h:171
Halide::Internal::LE
Is the first expression less than or equal to the second.
Definition: IR.h:158
Halide::Internal::LT
Is the first expression less than the second.
Definition: IR.h:149
Halide::Internal::Let
A let expression, like you might find in a functional language.
Definition: IR.h:281
Halide::Internal::LetStmt
The statement form of a let node.
Definition: IR.h:292
Halide::Internal::Load
Load a value from a named symbol if predicate is true.
Definition: IR.h:227
Halide::Internal::Max
The greater of two values.
Definition: IR.h:122
Halide::Internal::Min
The lesser of two values.
Definition: IR.h:113
Halide::Internal::Mod
The remainder of a / b.
Definition: IR.h:104
Halide::Internal::ModulusRemainder
The result of modulus_remainder analysis.
Definition: ModulusRemainder.h:33
Halide::Internal::ModulusRemainder::remainder
int64_t remainder
Definition: ModulusRemainder.h:39
Halide::Internal::ModulusRemainder::intersect
static ModulusRemainder intersect(const ModulusRemainder &a, const ModulusRemainder &b)
Halide::Internal::ModulusRemainder::modulus
int64_t modulus
Definition: ModulusRemainder.h:39
Halide::Internal::Mul
The product of two expressions.
Definition: IR.h:84
Halide::Internal::NE
Is the first expression not equal to the second.
Definition: IR.h:140
Halide::Internal::Not
Logical not - true if the expression false.
Definition: IR.h:203
Halide::Internal::Or
Logical or - is at least one of the expression true.
Definition: IR.h:194
Halide::Internal::Prefetch
Represent a multi-dimensional region of a Func or an ImageParam that needs to be prefetched.
Definition: IR.h:970
Halide::Internal::ProducerConsumer
This node is a helpful annotation to do with permissions.
Definition: IR.h:325
Halide::Internal::Provide
This defines the value of a function at a multi-dimensional location.
Definition: IR.h:364
Halide::Internal::Ramp
A linear ramp vector node.
Definition: IR.h:257
Halide::Internal::Realize
Allocate a multi-dimensional buffer of the given type and size.
Definition: IR.h:437
Halide::Internal::Reinterpret
Reinterpret value as another type, without affecting any of the bits (on little-endian systems).
Definition: IR.h:57
Halide::Internal::Select
A ternary operator.
Definition: IR.h:214
Halide::Internal::Shuffle
Construct a new vector by taking elements from another sequence of vectors.
Definition: IR.h:898
Halide::Internal::Simplify::ExprInfo::BitsKnown
Definition: Simplify_Internal.h:153
Halide::Internal::Simplify::ExprInfo::BitsKnown::operator&
BitsKnown operator&(const BitsKnown &other) const
Definition: Simplify_Internal.h:171
Halide::Internal::Simplify::ExprInfo::BitsKnown::all_bits_known
bool all_bits_known() const
Definition: Simplify_Internal.h:167
Halide::Internal::Simplify::ExprInfo::BitsKnown::known_zeros
uint64_t known_zeros() const
Definition: Simplify_Internal.h:159
Halide::Internal::Simplify::ExprInfo::BitsKnown::known_ones
uint64_t known_ones() const
Definition: Simplify_Internal.h:163
Halide::Internal::Simplify::ExprInfo::BitsKnown::operator|
BitsKnown operator|(const BitsKnown &other) const
Definition: Simplify_Internal.h:179
Halide::Internal::Simplify::ExprInfo::BitsKnown::operator^
BitsKnown operator^(const BitsKnown &other) const
Definition: Simplify_Internal.h:187
Halide::Internal::Simplify::ExprInfo::BitsKnown::value
uint64_t value
Definition: Simplify_Internal.h:157
Halide::Internal::Simplify::ExprInfo::BitsKnown::mask
uint64_t mask
Definition: Simplify_Internal.h:155
Halide::Internal::Simplify::ExprInfo
Definition: Simplify_Internal.h:39
Halide::Internal::Simplify::ExprInfo::largest_power_of_two_factor
uint64_t largest_power_of_two_factor(uint64_t x) const
Definition: Simplify_Internal.h:83
Halide::Internal::Simplify::ExprInfo::intersect
void intersect(const ExprInfo &other)
Definition: Simplify_Internal.h:132
Halide::Internal::Simplify::ExprInfo::bounds
ConstantInterval bounds
Definition: Simplify_Internal.h:41
Halide::Internal::Simplify::ExprInfo::trim_bounds_using_alignment
void trim_bounds_using_alignment()
Definition: Simplify_Internal.h:45
Halide::Internal::Simplify::ExprInfo::alignment
ModulusRemainder alignment
Definition: Simplify_Internal.h:43
Halide::Internal::Simplify::ExprInfo::from_bits_known
void from_bits_known(BitsKnown known, const Type &type)
Halide::Internal::Simplify::ExprInfo::cast_to
void cast_to(Type t)
Definition: Simplify_Internal.h:101
Halide::Internal::Simplify::ExprInfo::to_bits_known
BitsKnown to_bits_known(const Type &type) const
Halide::Internal::Simplify::ScopedFact
Definition: Simplify_Internal.h:432
Halide::Internal::Simplify::ScopedFact::ScopedFact
ScopedFact(ScopedFact &&that)=default
Halide::Internal::Simplify::ScopedFact::learn_true
void learn_true(const Expr &fact)
Halide::Internal::Simplify::ScopedFact::learn_false
void learn_false(const Expr &fact)
Halide::Internal::Simplify::ScopedFact::bounds_pop_list
std::vector< const Variable * > bounds_pop_list
Definition: Simplify_Internal.h:436
Halide::Internal::Simplify::ScopedFact::ScopedFact
ScopedFact(const ScopedFact &that)=delete
Halide::Internal::Simplify::ScopedFact::truths
std::set< Expr, IRDeepCompare > truths
Definition: Simplify_Internal.h:437
Halide::Internal::Simplify::ScopedFact::pop_list
std::vector< const Variable * > pop_list
Definition: Simplify_Internal.h:435
Halide::Internal::Simplify::ScopedFact::learn_lower_bound
void learn_lower_bound(const Variable *v, int64_t val)
Halide::Internal::Simplify::ScopedFact::falsehoods
std::set< Expr, IRDeepCompare > falsehoods
Definition: Simplify_Internal.h:437
Halide::Internal::Simplify::ScopedFact::substitute_facts
Expr substitute_facts(const Expr &e)
Halide::Internal::Simplify::ScopedFact::ScopedFact
ScopedFact(Simplify *s)
Definition: Simplify_Internal.h:448
Halide::Internal::Simplify::ScopedFact::simplify
Simplify * simplify
Definition: Simplify_Internal.h:433
Halide::Internal::Simplify::ScopedFact::substitute_facts
Stmt substitute_facts(const Stmt &s)
Halide::Internal::Simplify::ScopedFact::~ScopedFact
~ScopedFact()
Halide::Internal::Simplify::ScopedFact::learn_upper_bound
void learn_upper_bound(const Variable *v, int64_t val)
Halide::Internal::Simplify::VarInfo
Definition: Simplify_Internal.h:373
Halide::Internal::Simplify::VarInfo::replacement
Expr replacement
Definition: Simplify_Internal.h:374
Halide::Internal::Simplify::VarInfo::old_uses
int old_uses
Definition: Simplify_Internal.h:375
Halide::Internal::Simplify::VarInfo::new_uses
int new_uses
Definition: Simplify_Internal.h:375
Halide::Internal::Stmt
A reference-counted handle to a statement node.
Definition: Expr.h:427
Halide::Internal::Store
Store a 'value' to the buffer called 'name' at a given 'index' if 'predicate' is true.
Definition: IR.h:343
Halide::Internal::StringImm
String constants.
Definition: Expr.h:245
Halide::Internal::Sub
The difference of two expressions.
Definition: IR.h:75
Halide::Internal::UIntImm
Unsigned integer constants.
Definition: Expr.h:227
Halide::Internal::Variable
A named variable.
Definition: IR.h:813
Halide::Internal::Variable::name
std::string name
Definition: IR.h:814
Halide::Internal::VectorReduce
Horizontally reduce a vector to a scalar or narrower vector using the given commutative and associati...
Definition: IR.h:1026
Halide::Type
Types in the halide type system.
Definition: Type.h:281
Halide::Type::is_int
HALIDE_ALWAYS_INLINE bool is_int() const
Is this type a signed integer type?
Definition: Type.h:433
Halide::Type::is_uint
HALIDE_ALWAYS_INLINE bool is_uint() const
Is this type an unsigned integer type?
Definition: Type.h:439
Halide::Type::bits
HALIDE_ALWAYS_INLINE int bits() const
Return the bit size of a single element of this type.
Definition: Type.h:347
Halide::Type::can_represent
bool can_represent(Type other) const
Can this type represent all values of another type?
Halide::Type::is_scalar
HALIDE_ALWAYS_INLINE bool is_scalar() const
Is this type a scalar type? (lanes() == 1).
Definition: Type.h:415
Halide::Type::is_float
HALIDE_ALWAYS_INLINE bool is_float() const
Is this type a floating point type (float or double).
Definition: Type.h:421