Halide 21.0.0
Halide compiler and libraries
Loading...
Searching...
No Matches
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
33class Simplify : public VariadicVisitor<Simplify, Expr, Stmt> {
35
36public:
37 Simplify(bool r, const Scope<Interval> *bi, const Scope<ModulusRemainder> *ai);
38
39 struct ExprInfo {
40 // We track constant integer bounds when they exist
42 // And the alignment of integer variables
44
46 if (alignment.modulus == 0) {
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
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) {
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 }
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
156 // The actual value of the known bits
158
160 return mask & ~value;
161 }
162
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
200 if (info) {
201 *info = ExprInfo{};
202 }
203 }
204
206 if (info) {
208 info->alignment = ModulusRemainder{0, c};
209 }
210 }
211
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);
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
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
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
275 Expr const_false(int lanes, ExprInfo *info) {
276 return make_const(UInt(1, lanes), (int64_t)0, info);
277 }
278
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 &&
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
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
357
358 // Returns true iff t is an integral type where overflow is undefined
361 return t.is_int() && t.bits() >= 32;
362 }
363
366 return t.is_scalar() && no_overflow_int(t);
367 }
368
369 // Returns true iff t does not have a well defined overflow behavior.
372 return t.is_float() || no_overflow_int(t);
373 }
374
379
380 // Tracked for all let vars
382
383 // Only tracked for integer let vars
385
386 // Symbols used by rewrite rules
399
400 // Tracks whether or not we're inside a vector loop. Certain
401 // transformations are not a good idea if the code is to be
402 // vectorized.
403 bool in_vector_loop = false;
404
405 // Tracks whether or not the current IR is unconditionally unreachable.
406 bool in_unreachable = false;
407
408 // If we encounter a reference to a buffer (a Load, Store, Call,
409 // or Provide), there's an implicit dependence on some associated
410 // symbols.
411 void found_buffer_reference(const std::string &name, size_t dimensions = 0);
412
413 // Put the args to a commutative op in a canonical order
415 bool should_commute(const Expr &a, const Expr &b) {
416 if (a.node_type() < b.node_type()) {
417 return true;
418 }
419 if (a.node_type() > b.node_type()) {
420 return false;
421 }
422
423 if (a.node_type() == IRNodeType::Variable) {
424 const Variable *va = a.as<Variable>();
425 const Variable *vb = b.as<Variable>();
426 return va->name.compare(vb->name) > 0;
427 }
428
429 return false;
430 }
431
432 std::set<Expr, IRDeepCompare> truths, falsehoods;
433
434 struct ScopedFact {
436
437 std::vector<const Variable *> pop_list;
438 std::vector<const Variable *> bounds_pop_list;
439 std::set<Expr, IRDeepCompare> truths, falsehoods;
440
441 void learn_false(const Expr &fact);
442 void learn_true(const Expr &fact);
445
446 // Replace exprs known to be truths or falsehoods with const_true or const_false.
449
451 : simplify(s) {
452 }
454
455 // allow move but not copy
456 ScopedFact(const ScopedFact &that) = delete;
457 ScopedFact(ScopedFact &&that) = default;
458 };
459
460 // Tell the simplifier to learn from and exploit a boolean
461 // condition, over the lifetime of the returned object.
463 ScopedFact f(this);
464 f.learn_true(fact);
465 return f;
466 }
467
468 // Tell the simplifier to assume a boolean condition is false over
469 // the lifetime of the returned object.
471 ScopedFact f(this);
472 f.learn_false(fact);
473 return f;
474 }
475
477 return mutate(s);
478 }
480 return mutate(e, info);
481 }
482
483 template<typename T, typename Body>
484 Body simplify_let(const T *op, ExprInfo *info);
485
486 Expr visit(const IntImm *op, ExprInfo *info);
487 Expr visit(const UIntImm *op, ExprInfo *info);
488 Expr visit(const FloatImm *op, ExprInfo *info);
489 Expr visit(const StringImm *op, ExprInfo *info);
490 Expr visit(const Broadcast *op, ExprInfo *info);
491 Expr visit(const Cast *op, ExprInfo *info);
492 Expr visit(const Reinterpret *op, ExprInfo *info);
493 Expr visit(const Variable *op, ExprInfo *info);
494 Expr visit(const Add *op, ExprInfo *info);
495 Expr visit(const Sub *op, ExprInfo *info);
496 Expr visit(const Mul *op, ExprInfo *info);
497 Expr visit(const Div *op, ExprInfo *info);
498 Expr visit(const Mod *op, ExprInfo *info);
499 Expr visit(const Min *op, ExprInfo *info);
500 Expr visit(const Max *op, ExprInfo *info);
501 Expr visit(const EQ *op, ExprInfo *info);
502 Expr visit(const NE *op, ExprInfo *info);
503 Expr visit(const LT *op, ExprInfo *info);
504 Expr visit(const LE *op, ExprInfo *info);
505 Expr visit(const GT *op, ExprInfo *info);
506 Expr visit(const GE *op, ExprInfo *info);
507 Expr visit(const And *op, ExprInfo *info);
508 Expr visit(const Or *op, ExprInfo *info);
509 Expr visit(const Not *op, ExprInfo *info);
510 Expr visit(const Select *op, ExprInfo *info);
511 Expr visit(const Ramp *op, ExprInfo *info);
513 Expr visit(const Load *op, ExprInfo *info);
514 Expr visit(const Call *op, ExprInfo *info);
515 Expr visit(const Shuffle *op, ExprInfo *info);
516 Expr visit(const VectorReduce *op, ExprInfo *info);
517 Expr visit(const Let *op, ExprInfo *info);
518 Stmt visit(const LetStmt *op);
520 Stmt visit(const For *op);
521 Stmt visit(const Provide *op);
522 Stmt visit(const Store *op);
523 Stmt visit(const Allocate *op);
524 Stmt visit(const Evaluate *op);
526 Stmt visit(const Block *op);
527 Stmt visit(const Realize *op);
528 Stmt visit(const Prefetch *op);
529 Stmt visit(const Free *op);
530 Stmt visit(const Acquire *op);
531 Stmt visit(const Fork *op);
532 Stmt visit(const Atomic *op);
534
535 std::pair<std::vector<Expr>, bool> mutate_with_changes(const std::vector<Expr> &old_exprs);
536};
537
538} // namespace Internal
539} // namespace Halide
540
541#endif
Methods for computing the upper and lower bounds of an expression, and the regions of a function read...
Defines the ConstantInterval class, and operators on it.
#define debug(n)
For optional debugging during codegen, use the debug macro as follows:
Definition Debug.h:52
#define internal_assert(c)
Definition Error.h:218
#define HALIDE_ALWAYS_INLINE
Defines a method to match a fragment of IR against a pattern containing wildcards.
This header file defines operators that let you dump a Halide expression, statement,...
Defines the base class for things that recursively walk over the IR.
Defines the Scope class, which is used for keeping track of names in a scope while traversing IR.
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
Stmt visit(const HoistedStorage *op)
HALIDE_ALWAYS_INLINE Expr const_false(int lanes, ExprInfo *info)
Expr visit(const LE *op, ExprInfo *info)
Stmt visit(const ProducerConsumer *op)
HALIDE_ALWAYS_INLINE Expr mutate(const Expr &e, ExprInfo *b)
Scope< ExprInfo > bounds_and_alignment_info
HALIDE_ALWAYS_INLINE void clear_expr_info(ExprInfo *info)
Expr visit(const Variable *op, ExprInfo *info)
IRMatcher::WildConst< 5 > c5
void found_buffer_reference(const std::string &name, size_t dimensions=0)
Stmt visit(const Block *op)
Expr visit(const Load *op, ExprInfo *info)
Expr visit(const Cast *op, ExprInfo *info)
Stmt visit(const AssertStmt *op)
Stmt visit(const Evaluate *op)
Expr visit(const Let *op, ExprInfo *info)
Expr visit(const LT *op, ExprInfo *info)
Simplify(bool r, const Scope< Interval > *bi, const Scope< ModulusRemainder > *ai)
Expr visit(const Ramp *op, ExprInfo *info)
Stmt visit(const Prefetch *op)
HALIDE_ALWAYS_INLINE bool no_overflow(Type t)
IRMatcher::WildConst< 1 > c1
Expr visit(const Shuffle *op, ExprInfo *info)
Stmt visit(const IfThenElse *op)
Expr visit(const Mod *op, ExprInfo *info)
IRMatcher::WildConst< 0 > c0
ScopedFact scoped_truth(const Expr &fact)
IRMatcher::WildConst< 3 > c3
Expr visit(const UIntImm *op, ExprInfo *info)
HALIDE_ALWAYS_INLINE Expr const_true(int lanes, ExprInfo *info)
Expr visit(const Add *op, ExprInfo *info)
Expr visit(const Max *op, ExprInfo *info)
Expr visit(const Mul *op, ExprInfo *info)
IRMatcher::WildConst< 2 > c2
Expr visit(const StringImm *op, ExprInfo *info)
Expr visit(const VectorReduce *op, ExprInfo *info)
Expr visit(const Min *op, ExprInfo *info)
Expr visit(const Reinterpret *op, ExprInfo *info)
HALIDE_ALWAYS_INLINE Expr make_const(const Type &t, double c, ExprInfo *info)
Expr visit(const NE *op, ExprInfo *info)
Stmt visit(const For *op)
Expr visit(const Select *op, ExprInfo *info)
Stmt visit(const Atomic *op)
Expr visit(const Div *op, ExprInfo *info)
Expr make_const(const Type &t, int64_t c, ExprInfo *info)
Expr visit(const GE *op, ExprInfo *info)
int64_t normalize_constant(const Type &t, int64_t c)
Stmt visit(const Provide *op)
Expr visit(const Not *op, ExprInfo *info)
Body simplify_let(const T *op, ExprInfo *info)
Expr mutate_let_body(const Expr &e, ExprInfo *info)
Expr visit(const Or *op, ExprInfo *info)
Expr visit(const FloatImm *op, ExprInfo *info)
Stmt mutate_let_body(const Stmt &s, ExprInfo *)
Stmt visit(const Acquire *op)
void set_expr_info_to_constant(ExprInfo *info, int64_t c) const
Stmt visit(const Fork *op)
HALIDE_ALWAYS_INLINE bool no_overflow_int(Type t)
std::set< Expr, IRDeepCompare > truths
ScopedFact scoped_falsehood(const Expr &fact)
HALIDE_ALWAYS_INLINE bool should_commute(const Expr &a, const Expr &b)
Expr visit(const Broadcast *op, ExprInfo *info)
Expr visit(const Sub *op, ExprInfo *info)
std::pair< std::vector< Expr >, bool > mutate_with_changes(const std::vector< Expr > &old_exprs)
Stmt visit(const Store *op)
Expr visit(const GT *op, ExprInfo *info)
HALIDE_ALWAYS_INLINE bool no_overflow_scalar_int(Type t)
Expr make_const(const Type &t, uint64_t c, ExprInfo *info)
Stmt visit(const Free *op)
IRMatcher::WildConst< 4 > c4
Expr visit(const Call *op, ExprInfo *info)
Stmt visit(const Allocate *op)
Stmt visit(const Realize *op)
Expr visit(const EQ *op, ExprInfo *info)
Stmt visit(const LetStmt *op)
std::set< Expr, IRDeepCompare > falsehoods
Expr visit(const IntImm *op, ExprInfo *info)
Expr visit(const And *op, ExprInfo *info)
A visitor/mutator capable of passing arbitrary arguments to the visit methods using CRTP and returnin...
Definition IRVisitor.h:163
HALIDE_ALWAYS_INLINE Stmt dispatch(const Stmt &s, Args &&...args)
Definition IRVisitor.h:337
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.
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.
Expr make_const(Type t, int64_t val)
Construct an immediate of the given type from any numeric C++ type.
bool is_signed_integer_overflow(const Expr &expr)
Check if an expression is a signed_integer_overflow.
T mod_imp(T a, T b)
Implementations of division and mod that are specific to Halide.
Definition IROperator.h:257
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_MUST_USE_RESULT bool sub_with_overflow(int bits, int64_t a, int64_t b, int64_t *result)
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Type UInt(int bits, int lanes=1)
Constructing an unsigned integer type.
Definition Type.h:546
unsigned __INT64_TYPE__ uint64_t
signed __INT64_TYPE__ int64_t
A fragment of Halide syntax.
Definition Expr.h:258
HALIDE_ALWAYS_INLINE Type type() const
Get the type of this expression node.
Definition Expr.h:327
The sum of two expressions.
Definition IR.h:56
Allocate a scratch area called with the given name, type, and size.
Definition IR.h:371
Logical and - are both expressions true.
Definition IR.h:175
If the 'condition' is false, then evaluate and return the message, which should be a call to an error...
Definition IR.h:294
Lock all the Store nodes in the body statement.
Definition IR.h:994
A sequence of statements to be executed in-order.
Definition IR.h:442
A vector with 'lanes' elements, in which every element is 'value'.
Definition IR.h:259
A function call.
Definition IR.h:490
The actual IR nodes begin here.
Definition IR.h:30
A class to represent ranges of integers.
static ConstantInterval make_intersection(const ConstantInterval &a, const ConstantInterval &b)
Construct the largest interval contained within two intervals.
static ConstantInterval bounded_below(int64_t min)
Construct intervals bounded above or below.
static ConstantInterval single_point(int64_t x)
Construct an interval representing a single point.
The ratio of two expressions.
Definition IR.h:83
Is the first expression equal to the second.
Definition IR.h:121
Evaluate and discard an expression, presumably because it has some side-effect.
Definition IR.h:476
Floating point constants.
Definition Expr.h:236
A for loop.
Definition IR.h:848
A pair of statements executed concurrently.
Definition IR.h:457
Free the resources associated with the given buffer.
Definition IR.h:413
Is the first expression greater than or equal to the second.
Definition IR.h:166
Is the first expression greater than the second.
Definition IR.h:157
Represents a location where storage will be hoisted to for a Func / Realize node with a given name.
Definition IR.h:978
const T * as() const
Downcast this ir node to its actual type (e.g.
Definition Expr.h:205
IRNodeType node_type() const
Definition Expr.h:212
An if-then-else block.
Definition IR.h:466
Integer constants.
Definition Expr.h:218
HALIDE_ALWAYS_INLINE bool same_as(const IntrusivePtr &other) const
Is the first expression less than or equal to the second.
Definition IR.h:148
Is the first expression less than the second.
Definition IR.h:139
A let expression, like you might find in a functional language.
Definition IR.h:271
The statement form of a let node.
Definition IR.h:282
Load a value from a named symbol if predicate is true.
Definition IR.h:217
The greater of two values.
Definition IR.h:112
The lesser of two values.
Definition IR.h:103
The remainder of a / b.
Definition IR.h:94
The result of modulus_remainder analysis.
static ModulusRemainder intersect(const ModulusRemainder &a, const ModulusRemainder &b)
The product of two expressions.
Definition IR.h:74
Is the first expression not equal to the second.
Definition IR.h:130
Logical not - true if the expression false.
Definition IR.h:193
Logical or - is at least one of the expression true.
Definition IR.h:184
Represent a multi-dimensional region of a Func or an ImageParam that needs to be prefetched.
Definition IR.h:956
This node is a helpful annotation to do with permissions.
Definition IR.h:315
This defines the value of a function at a multi-dimensional location.
Definition IR.h:354
A linear ramp vector node.
Definition IR.h:247
Allocate a multi-dimensional buffer of the given type and size.
Definition IR.h:427
Reinterpret value as another type, without affecting any of the bits (on little-endian systems).
Definition IR.h:47
A ternary operator.
Definition IR.h:204
Construct a new vector by taking elements from another sequence of vectors.
Definition IR.h:884
BitsKnown operator&(const BitsKnown &other) const
BitsKnown operator|(const BitsKnown &other) const
BitsKnown operator^(const BitsKnown &other) const
uint64_t largest_power_of_two_factor(uint64_t x) const
void intersect(const ExprInfo &other)
void from_bits_known(BitsKnown known, const Type &type)
BitsKnown to_bits_known(const Type &type) const
ScopedFact(ScopedFact &&that)=default
void learn_false(const Expr &fact)
std::vector< const Variable * > bounds_pop_list
ScopedFact(const ScopedFact &that)=delete
std::set< Expr, IRDeepCompare > truths
std::vector< const Variable * > pop_list
void learn_lower_bound(const Variable *v, int64_t val)
std::set< Expr, IRDeepCompare > falsehoods
void learn_upper_bound(const Variable *v, int64_t val)
A reference-counted handle to a statement node.
Definition Expr.h:427
Store a 'value' to the buffer called 'name' at a given 'index' if 'predicate' is true.
Definition IR.h:333
String constants.
Definition Expr.h:245
The difference of two expressions.
Definition IR.h:65
Unsigned integer constants.
Definition Expr.h:227
A named variable.
Definition IR.h:801
std::string name
Definition IR.h:802
Horizontally reduce a vector to a scalar or narrower vector using the given commutative and associati...
Definition IR.h:1012
HALIDE_ALWAYS_INLINE bool is_int() const
Is this type a signed integer type?
Definition Type.h:435
HALIDE_ALWAYS_INLINE bool is_uint() const
Is this type an unsigned integer type?
Definition Type.h:441
HALIDE_ALWAYS_INLINE int bits() const
Return the bit size of a single element of this type.
Definition Type.h:349
bool can_represent(Type other) const
Can this type represent all values of another type?
HALIDE_ALWAYS_INLINE bool is_scalar() const
Is this type a scalar type?
Definition Type.h:417
HALIDE_ALWAYS_INLINE bool is_float() const
Is this type a floating point type (float or double).
Definition Type.h:423