-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathIROperator.h
1848 lines (1626 loc) · 73.5 KB
/
IROperator.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef HALIDE_IR_OPERATOR_H
#define HALIDE_IR_OPERATOR_H
/** \file
*
* Defines various operator overloads and utility functions that make
* it more pleasant to work with Halide expressions.
*/
#include <cmath>
#include "Expr.h"
#include "Tuple.h"
namespace Halide {
namespace Internal {
/** Is the expression either an IntImm, a FloatImm, a StringImm, or a
* Cast of the same, or a Ramp or Broadcast of the same. Doesn't do
* any constant folding. */
bool is_const(const Expr &e);
/** Is the expression an IntImm, FloatImm of a particular value, or a
* Cast, or Broadcast of the same. */
bool is_const(const Expr &e, int64_t v);
/** If an expression is an IntImm or a Broadcast of an IntImm, return
* a pointer to its value. Otherwise returns nullptr. */
const int64_t *as_const_int(const Expr &e);
/** If an expression is a UIntImm or a Broadcast of a UIntImm, return
* a pointer to its value. Otherwise returns nullptr. */
const uint64_t *as_const_uint(const Expr &e);
/** If an expression is a FloatImm or a Broadcast of a FloatImm,
* return a pointer to its value. Otherwise returns nullptr. */
const double *as_const_float(const Expr &e);
/** Is the expression a constant integer power of two. Also returns
* log base two of the expression if it is. Only returns true for
* integer types. */
bool is_const_power_of_two_integer(const Expr &e, int *bits);
/** Is the expression a const (as defined by is_const), and also
* strictly greater than zero (in all lanes, if a vector expression) */
bool is_positive_const(const Expr &e);
/** Is the expression a const (as defined by is_const), and also
* strictly less than zero (in all lanes, if a vector expression) */
bool is_negative_const(const Expr &e);
/** Is the expression an undef */
bool is_undef(const Expr &e);
/** Is the expression a const (as defined by is_const), and also equal
* to zero (in all lanes, if a vector expression) */
bool is_const_zero(const Expr &e);
/** Is the expression a const (as defined by is_const), and also equal
* to one (in all lanes, if a vector expression) */
bool is_const_one(const Expr &e);
/** Is the statement a no-op (which we represent as either an
* undefined Stmt, or as an Evaluate node of a constant) */
bool is_no_op(const Stmt &s);
/** Does the expression
* 1) Take on the same value no matter where it appears in a Stmt, and
* 2) Evaluating it has no side-effects
*/
bool is_pure(const Expr &e);
/** Construct an immediate of the given type from any numeric C++ type. */
// @{
Expr make_const(Type t, int64_t val);
Expr make_const(Type t, uint64_t val);
Expr make_const(Type t, double val);
inline Expr make_const(Type t, int32_t val) {
return make_const(t, (int64_t)val);
}
inline Expr make_const(Type t, uint32_t val) {
return make_const(t, (uint64_t)val);
}
inline Expr make_const(Type t, int16_t val) {
return make_const(t, (int64_t)val);
}
inline Expr make_const(Type t, uint16_t val) {
return make_const(t, (uint64_t)val);
}
inline Expr make_const(Type t, int8_t val) {
return make_const(t, (int64_t)val);
}
inline Expr make_const(Type t, uint8_t val) {
return make_const(t, (uint64_t)val);
}
inline Expr make_const(Type t, bool val) {
return make_const(t, (uint64_t)val);
}
inline Expr make_const(Type t, float val) {
return make_const(t, (double)val);
}
inline Expr make_const(Type t, float16_t val) {
return make_const(t, (double)val);
}
// @}
/** Construct a unique signed_integer_overflow Expr */
Expr make_signed_integer_overflow(Type type);
/** Check if an expression is a signed_integer_overflow */
bool is_signed_integer_overflow(const Expr &expr);
/** Check if a constant value can be correctly represented as the given type. */
void check_representable(Type t, int64_t val);
/** Construct a boolean constant from a C++ boolean value.
* May also be a vector if width is given.
* It is not possible to coerce a C++ boolean to Expr because
* if we provide such a path then char objects can ambiguously
* be converted to Halide Expr or to std::string. The problem
* is that C++ does not have a real bool type - it is in fact
* close enough to char that C++ does not know how to distinguish them.
* make_bool is the explicit coercion. */
Expr make_bool(bool val, int lanes = 1);
/** Construct the representation of zero in the given type */
Expr make_zero(Type t);
/** Construct the representation of one in the given type */
Expr make_one(Type t);
/** Construct the representation of two in the given type */
Expr make_two(Type t);
/** Construct the constant boolean true. May also be a vector of
* trues, if a lanes argument is given. */
Expr const_true(int lanes = 1);
/** Construct the constant boolean false. May also be a vector of
* falses, if a lanes argument is given. */
Expr const_false(int lanes = 1);
/** Attempt to cast an expression to a smaller type while provably not
* losing information. If it can't be done, return an undefined
* Expr. */
Expr lossless_cast(Type t, Expr e);
/** Attempt to negate x without introducing new IR and without overflow.
* If it can't be done, return an undefined Expr. */
Expr lossless_negate(const Expr &x);
/** Coerce the two expressions to have the same type, using C-style
* casting rules. For the purposes of casting, a boolean type is
* UInt(1). We use the following procedure:
*
* If the types already match, do nothing.
*
* Then, if one type is a vector and the other is a scalar, the scalar
* is broadcast to match the vector width, and we continue.
*
* Then, if one type is floating-point and the other is not, the
* non-float is cast to the floating-point type, and we're done.
*
* Then, if both types are unsigned ints, the one with fewer bits is
* cast to match the one with more bits and we're done.
*
* Then, if both types are signed ints, the one with fewer bits is
* cast to match the one with more bits and we're done.
*
* Finally, if one type is an unsigned int and the other type is a signed
* int, both are cast to a signed int with the greater of the two
* bit-widths. For example, matching an Int(8) with a UInt(16) results
* in an Int(16).
*
*/
void match_types(Expr &a, Expr &b);
/** Asserts that both expressions are integer types and are either
* both signed or both unsigned. If one argument is scalar and the
* other a vector, the scalar is broadcasted to have the same number
* of lanes as the vector. If one expression is of narrower type than
* the other, it is widened to the bit width of the wider. */
void match_types_bitwise(Expr &a, Expr &b, const char *op_name);
/** Halide's vectorizable transcendentals. */
// @{
Expr halide_log(const Expr &a);
Expr halide_exp(const Expr &a);
Expr halide_erf(const Expr &a);
// @}
/** Extended exponential which produces two output values,
* each of the same precision as the input, as described in
* "The Two-Pass Softmax Algorithm" by Marat Dukhan and
* Artsiom Ablavatski [https://arxiv.org/abs/2001.04438].
*
* The first element of the returned Tuple is a psuedo-mantissa while
* the second is an exponent which is an integer. The product of the
* pseudo-mantissa and 2 raised to the returned exponent is the
* desired result e^a. For arguments up to slightly greater than
* 11629079, the pseudo-mantissa is guaranteed to be within the
* interval (-e, e). For larger arguments, the exponent result of the
* tuple may not be able to represent the exact integer necessary to
* keep the pseudo-mantissa within bounds. Thus it can become
* progressively larger in magnitude as the argument increases.
*
* Ideally this routine will maintain a degree of accuracy through the
* entire range and be able to produce results out to the end of the
* numeric range. At present neither of these properties are true due to
* the following issues:
* - Range reduction may overflow when scaling the argument.
* - Range reduction is increasingly inaccurate in reducing the value
* due to the implementation. This results in overflow in the polynomial
* evaluation.
* - Even if the above to issues were resolved, the approximation polynomial
* would have to run on values outside its intended approximation range.
*/
Tuple halide_extended_exp(const Expr &a);
/** Raise an expression to an integer power by repeatedly multiplying
* it by itself. */
Expr raise_to_integer_power(Expr a, int64_t b);
/** Split a boolean condition into vector of ANDs. If 'cond' is undefined,
* return an empty vector. */
void split_into_ands(const Expr &cond, std::vector<Expr> &result);
/** A builder to help create Exprs representing halide_buffer_t
* structs (e.g. foo.buffer) via calls to halide_buffer_init. Fill out
* the fields and then call build. The resulting Expr will be a call
* to halide_buffer_init with the struct members as arguments. If the
* buffer_memory field is undefined, it uses a call to alloca to make
* some stack memory for the buffer. If the shape_memory field is
* undefined, it similarly uses stack memory for the shape. If the
* shape_memory field is null, it uses the dim field already in the
* buffer. Other unitialized fields will take on a value of zero in
* the constructed buffer. */
struct BufferBuilder {
Expr buffer_memory, shape_memory;
Expr host, device, device_interface;
Type type;
int dimensions = 0;
std::vector<Expr> mins, extents, strides;
Expr host_dirty, device_dirty;
Expr build() const;
};
/** If e is a ramp expression with stride, default 1, return the base,
* otherwise undefined. */
Expr strided_ramp_base(const Expr &e, int stride = 1);
/** Implementations of division and mod that are specific to Halide.
* Use these implementations; do not use native C division or mod to
* simplify Halide expressions. Halide division and modulo satisify
* the Euclidean definition of division for integers a and b:
*
/code
when b != 0, (a/b)*b + a%b = a
0 <= a%b < |b|
/endcode
*
* Additionally, mod by zero returns zero, and div by zero returns
* zero. This makes mod and div total functions.
*/
// @{
template<typename T>
inline T mod_imp(T a, T b) {
Type t = type_of<T>();
if (!t.is_float() && b == 0) {
return 0;
} else if (t.is_int()) {
int64_t ia = a;
int64_t ib = b;
int64_t a_neg = ia >> 63;
int64_t b_neg = ib >> 63;
int64_t b_zero = (ib == 0) ? -1 : 0;
ia -= a_neg;
int64_t r = ia % (ib | b_zero);
r += (a_neg & ((ib ^ b_neg) + ~b_neg));
r &= ~b_zero;
return r;
} else {
return a % b;
}
}
template<typename T>
inline T div_imp(T a, T b) {
Type t = type_of<T>();
if (!t.is_float() && b == 0) {
return (T)0;
} else if (t.is_int()) {
// Do it as 64-bit
int64_t ia = a;
int64_t ib = b;
int64_t a_neg = ia >> 63;
int64_t b_neg = ib >> 63;
int64_t b_zero = (ib == 0) ? -1 : 0;
ib -= b_zero;
ia -= a_neg;
int64_t q = ia / ib;
q += a_neg & (~b_neg - b_neg);
q &= ~b_zero;
return (T)q;
} else {
return a / b;
}
}
// @}
// Special cases for float, double.
template<>
inline float mod_imp<float>(float a, float b) {
float f = a - b * (floorf(a / b));
// The remainder has the same sign as b.
return f;
}
template<>
inline double mod_imp<double>(double a, double b) {
double f = a - b * (std::floor(a / b));
return f;
}
template<>
inline float div_imp<float>(float a, float b) {
return a / b;
}
template<>
inline double div_imp<double>(double a, double b) {
return a / b;
}
/** Return an Expr that is identical to the input Expr, but with
* all calls to likely() and likely_if_innermost() removed. */
Expr remove_likelies(const Expr &e);
/** Return a Stmt that is identical to the input Stmt, but with
* all calls to likely() and likely_if_innermost() removed. */
Stmt remove_likelies(const Stmt &s);
/** Return an Expr that is identical to the input Expr, but with
* all calls to promise_clamped() and unsafe_promise_clamped() removed. */
Expr remove_promises(const Expr &e);
/** Return a Stmt that is identical to the input Stmt, but with
* all calls to promise_clamped() and unsafe_promise_clamped() removed. */
Stmt remove_promises(const Stmt &s);
/** If the expression is a tag helper call, remove it and return
* the tagged expression. If not, returns the expression. */
Expr unwrap_tags(const Expr &e);
template<typename T>
struct is_printable_arg {
static constexpr bool value = std::is_convertible<T, const char *>::value ||
std::is_convertible<T, Halide::Expr>::value;
};
template<typename... Args>
struct all_are_printable_args : meta_and<is_printable_arg<Args>...> {};
// Secondary args to print can be Exprs or const char *
inline HALIDE_NO_USER_CODE_INLINE void collect_print_args(std::vector<Expr> &args) {
}
template<typename... Args>
inline HALIDE_NO_USER_CODE_INLINE void collect_print_args(std::vector<Expr> &args, const char *arg, Args &&...more_args) {
args.emplace_back(std::string(arg));
collect_print_args(args, std::forward<Args>(more_args)...);
}
template<typename... Args>
inline HALIDE_NO_USER_CODE_INLINE void collect_print_args(std::vector<Expr> &args, Expr arg, Args &&...more_args) {
args.push_back(std::move(arg));
collect_print_args(args, std::forward<Args>(more_args)...);
}
Expr requirement_failed_error(Expr condition, const std::vector<Expr> &args);
Expr memoize_tag_helper(Expr result, const std::vector<Expr> &cache_key_values);
/** Reset the counters used for random-number seeds in random_float/int/uint.
* (Note that the counters are incremented for each call, even if a seed is passed in.)
* This is used for multitarget compilation to ensure that each subtarget gets
* the same sequence of random numbers. */
void reset_random_counters();
} // namespace Internal
/** Cast an expression to the halide type corresponding to the C++ type T. */
template<typename T>
inline Expr cast(Expr a) {
return cast(type_of<T>(), std::move(a));
}
/** Cast an expression to a new type. */
Expr cast(Type t, Expr a);
/** Return the sum of two expressions, doing any necessary type
* coercion using \ref Internal::match_types */
Expr operator+(Expr a, Expr b);
/** Add an expression and a constant integer. Coerces the type of the
* integer to match the type of the expression. Errors if the integer
* cannot be represented in the type of the expression. */
// @{
Expr operator+(Expr a, int b);
/** Add a constant integer and an expression. Coerces the type of the
* integer to match the type of the expression. Errors if the integer
* cannot be represented in the type of the expression. */
Expr operator+(int a, Expr b);
/** Modify the first expression to be the sum of two expressions,
* without changing its type. This casts the second argument to match
* the type of the first. */
Expr &operator+=(Expr &a, Expr b);
/** Return the difference of two expressions, doing any necessary type
* coercion using \ref Internal::match_types */
Expr operator-(Expr a, Expr b);
/** Subtracts a constant integer from an expression. Coerces the type of the
* integer to match the type of the expression. Errors if the integer
* cannot be represented in the type of the expression. */
Expr operator-(Expr a, int b);
/** Subtracts an expression from a constant integer. Coerces the type
* of the integer to match the type of the expression. Errors if the
* integer cannot be represented in the type of the expression. */
Expr operator-(int a, Expr b);
/** Return the negative of the argument. Does no type casting, so more
* formally: return that number which when added to the original,
* yields zero of the same type. For unsigned integers the negative is
* still an unsigned integer. E.g. in UInt(8), the negative of 56 is
* 200, because 56 + 200 == 0 */
Expr operator-(Expr a);
/** Modify the first expression to be the difference of two expressions,
* without changing its type. This casts the second argument to match
* the type of the first. */
Expr &operator-=(Expr &a, Expr b);
/** Return the product of two expressions, doing any necessary type
* coercion using \ref Internal::match_types */
Expr operator*(Expr a, Expr b);
/** Multiply an expression and a constant integer. Coerces the type of the
* integer to match the type of the expression. Errors if the integer
* cannot be represented in the type of the expression. */
Expr operator*(Expr a, int b);
/** Multiply a constant integer and an expression. Coerces the type of
* the integer to match the type of the expression. Errors if the
* integer cannot be represented in the type of the expression. */
Expr operator*(int a, Expr b);
/** Modify the first expression to be the product of two expressions,
* without changing its type. This casts the second argument to match
* the type of the first. */
Expr &operator*=(Expr &a, Expr b);
/** Return the ratio of two expressions, doing any necessary type
* coercion using \ref Internal::match_types. Note that integer
* division in Halide is not the same as integer division in C-like
* languages in two ways.
*
* First, signed integer division in Halide rounds according to the
* sign of the denominator. This means towards minus infinity for
* positive denominators, and towards positive infinity for negative
* denominators. This is unlike C, which rounds towards zero. This
* decision ensures that upsampling expressions like f(x/2, y/2) don't
* have funny discontinuities when x and y cross zero.
*
* Second, division by zero returns zero instead of faulting. For
* types where overflow is defined behavior, division of the largest
* negative signed integer by -1 returns the larged negative signed
* integer for the type (i.e. it wraps). This ensures that a division
* operation can never have a side-effect, which is helpful in Halide
* because scheduling directives can expand the domain of computation
* of a Func, potentially introducing new zero-division.
*/
Expr operator/(Expr a, Expr b);
/** Modify the first expression to be the ratio of two expressions,
* without changing its type. This casts the second argument to match
* the type of the first. Note that signed integer division in Halide
* rounds towards minus infinity, unlike C, which rounds towards
* zero. */
Expr &operator/=(Expr &a, Expr b);
/** Divides an expression by a constant integer. Coerces the type
* of the integer to match the type of the expression. Errors if the
* integer cannot be represented in the type of the expression. */
Expr operator/(Expr a, int b);
/** Divides a constant integer by an expression. Coerces the type
* of the integer to match the type of the expression. Errors if the
* integer cannot be represented in the type of the expression. */
Expr operator/(int a, Expr b);
/** Return the first argument reduced modulo the second, doing any
* necessary type coercion using \ref Internal::match_types. There are
* two key differences between C-like languages and Halide for the
* modulo operation, which complement the way division works.
*
* First, the result is never negative, so x % 2 is always zero or
* one, unlike in C-like languages. x % -2 is equivalent, and is also
* always zero or one. Second, mod by zero evaluates to zero (unlike
* in C, where it faults). This makes modulo, like division, a
* side-effect-free operation. */
Expr operator%(Expr a, Expr b);
/** Mods an expression by a constant integer. Coerces the type
* of the integer to match the type of the expression. Errors if the
* integer cannot be represented in the type of the expression. */
Expr operator%(Expr a, int b);
/** Mods a constant integer by an expression. Coerces the type
* of the integer to match the type of the expression. Errors if the
* integer cannot be represented in the type of the expression. */
Expr operator%(int a, Expr b);
/** Return a boolean expression that tests whether the first argument
* is greater than the second, after doing any necessary type coercion
* using \ref Internal::match_types */
Expr operator>(Expr a, Expr b);
/** Return a boolean expression that tests whether an expression is
* greater than a constant integer. Coerces the integer to the type of
* the expression. Errors if the integer is not representable in that
* type. */
Expr operator>(Expr a, int b);
/** Return a boolean expression that tests whether a constant integer is
* greater than an expression. Coerces the integer to the type of
* the expression. Errors if the integer is not representable in that
* type. */
Expr operator>(int a, Expr b);
/** Return a boolean expression that tests whether the first argument
* is less than the second, after doing any necessary type coercion
* using \ref Internal::match_types */
Expr operator<(Expr a, Expr b);
/** Return a boolean expression that tests whether an expression is
* less than a constant integer. Coerces the integer to the type of
* the expression. Errors if the integer is not representable in that
* type. */
Expr operator<(Expr a, int b);
/** Return a boolean expression that tests whether a constant integer is
* less than an expression. Coerces the integer to the type of
* the expression. Errors if the integer is not representable in that
* type. */
Expr operator<(int a, Expr b);
/** Return a boolean expression that tests whether the first argument
* is less than or equal to the second, after doing any necessary type
* coercion using \ref Internal::match_types */
Expr operator<=(Expr a, Expr b);
/** Return a boolean expression that tests whether an expression is
* less than or equal to a constant integer. Coerces the integer to
* the type of the expression. Errors if the integer is not
* representable in that type. */
Expr operator<=(Expr a, int b);
/** Return a boolean expression that tests whether a constant integer
* is less than or equal to an expression. Coerces the integer to the
* type of the expression. Errors if the integer is not representable
* in that type. */
Expr operator<=(int a, Expr b);
/** Return a boolean expression that tests whether the first argument
* is greater than or equal to the second, after doing any necessary
* type coercion using \ref Internal::match_types */
Expr operator>=(Expr a, Expr b);
/** Return a boolean expression that tests whether an expression is
* greater than or equal to a constant integer. Coerces the integer to
* the type of the expression. Errors if the integer is not
* representable in that type. */
Expr operator>=(const Expr &a, int b);
/** Return a boolean expression that tests whether a constant integer
* is greater than or equal to an expression. Coerces the integer to the
* type of the expression. Errors if the integer is not representable
* in that type. */
Expr operator>=(int a, const Expr &b);
/** Return a boolean expression that tests whether the first argument
* is equal to the second, after doing any necessary type coercion
* using \ref Internal::match_types */
Expr operator==(Expr a, Expr b);
/** Return a boolean expression that tests whether an expression is
* equal to a constant integer. Coerces the integer to the type of the
* expression. Errors if the integer is not representable in that
* type. */
Expr operator==(Expr a, int b);
/** Return a boolean expression that tests whether a constant integer
* is equal to an expression. Coerces the integer to the type of the
* expression. Errors if the integer is not representable in that
* type. */
Expr operator==(int a, Expr b);
/** Return a boolean expression that tests whether the first argument
* is not equal to the second, after doing any necessary type coercion
* using \ref Internal::match_types */
Expr operator!=(Expr a, Expr b);
/** Return a boolean expression that tests whether an expression is
* not equal to a constant integer. Coerces the integer to the type of
* the expression. Errors if the integer is not representable in that
* type. */
Expr operator!=(Expr a, int b);
/** Return a boolean expression that tests whether a constant integer
* is not equal to an expression. Coerces the integer to the type of
* the expression. Errors if the integer is not representable in that
* type. */
Expr operator!=(int a, Expr b);
/** Returns the logical and of the two arguments */
Expr operator&&(Expr a, Expr b);
/** Logical and of an Expr and a bool. Either returns the Expr or an
* Expr representing false, depending on the bool. */
// @{
Expr operator&&(Expr a, bool b);
Expr operator&&(bool a, Expr b);
// @}
/** Returns the logical or of the two arguments */
Expr operator||(Expr a, Expr b);
/** Logical or of an Expr and a bool. Either returns the Expr or an
* Expr representing true, depending on the bool. */
// @{
Expr operator||(Expr a, bool b);
Expr operator||(bool a, Expr b);
// @}
/** Returns the logical not the argument */
Expr operator!(Expr a);
/** Returns an expression representing the greater of the two
* arguments, after doing any necessary type coercion using
* \ref Internal::match_types. Vectorizes cleanly on most platforms
* (with the exception of integer types on x86 without SSE4). */
Expr max(Expr a, Expr b);
/** Returns an expression representing the greater of an expression
* and a constant integer. The integer is coerced to the type of the
* expression. Errors if the integer is not representable as that
* type. Vectorizes cleanly on most platforms (with the exception of
* integer types on x86 without SSE4). */
Expr max(Expr a, int b);
/** Returns an expression representing the greater of a constant
* integer and an expression. The integer is coerced to the type of
* the expression. Errors if the integer is not representable as that
* type. Vectorizes cleanly on most platforms (with the exception of
* integer types on x86 without SSE4). */
Expr max(int a, Expr b);
inline Expr max(float a, Expr b) {
return max(Expr(a), std::move(b));
}
inline Expr max(Expr a, float b) {
return max(std::move(a), Expr(b));
}
/** Returns an expression representing the greater of an expressions
* vector, after doing any necessary type coersion using
* \ref Internal::match_types. Vectorizes cleanly on most platforms
* (with the exception of integer types on x86 without SSE4).
* The expressions are folded from right ie. max(.., max(.., ..)).
* The arguments can be any mix of types but must all be convertible to Expr. */
template<typename A, typename B, typename C, typename... Rest,
typename std::enable_if<Halide::Internal::all_are_convertible<Expr, Rest...>::value>::type * = nullptr>
inline Expr max(A &&a, B &&b, C &&c, Rest &&...rest) {
return max(std::forward<A>(a), max(std::forward<B>(b), std::forward<C>(c), std::forward<Rest>(rest)...));
}
Expr min(Expr a, Expr b);
/** Returns an expression representing the lesser of an expression
* and a constant integer. The integer is coerced to the type of the
* expression. Errors if the integer is not representable as that
* type. Vectorizes cleanly on most platforms (with the exception of
* integer types on x86 without SSE4). */
Expr min(Expr a, int b);
/** Returns an expression representing the lesser of a constant
* integer and an expression. The integer is coerced to the type of
* the expression. Errors if the integer is not representable as that
* type. Vectorizes cleanly on most platforms (with the exception of
* integer types on x86 without SSE4). */
Expr min(int a, Expr b);
inline Expr min(float a, Expr b) {
return min(Expr(a), std::move(b));
}
inline Expr min(Expr a, float b) {
return min(std::move(a), Expr(b));
}
/** Returns an expression representing the lesser of an expressions
* vector, after doing any necessary type coersion using
* \ref Internal::match_types. Vectorizes cleanly on most platforms
* (with the exception of integer types on x86 without SSE4).
* The expressions are folded from right ie. min(.., min(.., ..)).
* The arguments can be any mix of types but must all be convertible to Expr. */
template<typename A, typename B, typename C, typename... Rest,
typename std::enable_if<Halide::Internal::all_are_convertible<Expr, Rest...>::value>::type * = nullptr>
inline Expr min(A &&a, B &&b, C &&c, Rest &&...rest) {
return min(std::forward<A>(a), min(std::forward<B>(b), std::forward<C>(c), std::forward<Rest>(rest)...));
}
/** Operators on floats treats those floats as Exprs. Making these
* explicit prevents implicit float->int casts that might otherwise
* occur. */
// @{
inline Expr operator+(Expr a, float b) {
return std::move(a) + Expr(b);
}
inline Expr operator+(float a, Expr b) {
return Expr(a) + std::move(b);
}
inline Expr operator-(Expr a, float b) {
return std::move(a) - Expr(b);
}
inline Expr operator-(float a, Expr b) {
return Expr(a) - std::move(b);
}
inline Expr operator*(Expr a, float b) {
return std::move(a) * Expr(b);
}
inline Expr operator*(float a, Expr b) {
return Expr(a) * std::move(b);
}
inline Expr operator/(Expr a, float b) {
return std::move(a) / Expr(b);
}
inline Expr operator/(float a, Expr b) {
return Expr(a) / std::move(b);
}
inline Expr operator%(Expr a, float b) {
return std::move(a) % Expr(b);
}
inline Expr operator%(float a, Expr b) {
return Expr(a) % std::move(b);
}
inline Expr operator>(Expr a, float b) {
return std::move(a) > Expr(b);
}
inline Expr operator>(float a, Expr b) {
return Expr(a) > std::move(b);
}
inline Expr operator<(Expr a, float b) {
return std::move(a) < Expr(b);
}
inline Expr operator<(float a, Expr b) {
return Expr(a) < std::move(b);
}
inline Expr operator>=(Expr a, float b) {
return std::move(a) >= Expr(b);
}
inline Expr operator>=(float a, Expr b) {
return Expr(a) >= std::move(b);
}
inline Expr operator<=(Expr a, float b) {
return std::move(a) <= Expr(b);
}
inline Expr operator<=(float a, Expr b) {
return Expr(a) <= std::move(b);
}
inline Expr operator==(Expr a, float b) {
return std::move(a) == Expr(b);
}
inline Expr operator==(float a, Expr b) {
return Expr(a) == std::move(b);
}
inline Expr operator!=(Expr a, float b) {
return std::move(a) != Expr(b);
}
inline Expr operator!=(float a, Expr b) {
return Expr(a) != std::move(b);
}
// @}
/** Clamps an expression to lie within the given bounds. The bounds
* are type-cast to match the expression. Vectorizes as well as min/max. */
Expr clamp(Expr a, const Expr &min_val, const Expr &max_val);
/** Returns the absolute value of a signed integer or floating-point
* expression. Vectorizes cleanly. Unlike in C, abs of a signed
* integer returns an unsigned integer of the same bit width. This
* means that abs of the most negative integer doesn't overflow. */
Expr abs(Expr a);
/** Return the absolute difference between two values. Vectorizes
* cleanly. Returns an unsigned value of the same bit width. There are
* various ways to write this yourself, but they contain numerous
* gotchas and don't always compile to good code, so use this
* instead. */
Expr absd(Expr a, Expr b);
/** Returns an expression similar to the ternary operator in C, except
* that it always evaluates all arguments. If the first argument is
* true, then return the second, else return the third. Typically
* vectorizes cleanly, but benefits from SSE41 or newer on x86. */
Expr select(Expr condition, Expr true_value, Expr false_value);
/** A multi-way variant of select similar to a switch statement in C,
* which can accept multiple conditions and values in pairs. Evaluates
* to the first value for which the condition is true. Returns the
* final value if all conditions are false. */
template<typename... Args,
typename std::enable_if<Halide::Internal::all_are_convertible<Expr, Args...>::value>::type * = nullptr>
inline Expr select(Expr c0, Expr v0, Expr c1, Expr v1, Args &&...args) {
return select(std::move(c0), std::move(v0), select(std::move(c1), std::move(v1), std::forward<Args>(args)...));
}
/** Equivalent of ternary select(), but taking/returning tuples. If the condition is
* a Tuple, it must match the size of the true and false Tuples. */
// @{
HALIDE_ATTRIBUTE_DEPRECATED("tuple_select has been deprecated. Use select instead (which now works for Tuples)")
Tuple tuple_select(const Tuple &condition, const Tuple &true_value, const Tuple &false_value);
HALIDE_ATTRIBUTE_DEPRECATED("tuple_select has been deprecated. Use select instead (which now works for Tuples)")
Tuple tuple_select(const Expr &condition, const Tuple &true_value, const Tuple &false_value);
Tuple select(const Tuple &condition, const Tuple &true_value, const Tuple &false_value);
Tuple select(const Expr &condition, const Tuple &true_value, const Tuple &false_value);
// @}
/** Equivalent of multiway select(), but taking/returning tuples. If the condition is
* a Tuple, it must match the size of the true and false Tuples. */
// @{
template<typename... Args>
HALIDE_ATTRIBUTE_DEPRECATED("tuple_select has been deprecated. Use select instead (which now works for Tuples)")
inline Tuple tuple_select(const Tuple &c0, const Tuple &v0, const Tuple &c1, const Tuple &v1, Args &&...args) {
return tuple_select(c0, v0, tuple_select(c1, v1, std::forward<Args>(args)...));
}
template<typename... Args>
HALIDE_ATTRIBUTE_DEPRECATED("tuple_select has been deprecated. Use select instead (which now works for Tuples)")
inline Tuple tuple_select(const Expr &c0, const Tuple &v0, const Expr &c1, const Tuple &v1, Args &&...args) {
return tuple_select(c0, v0, tuple_select(c1, v1, std::forward<Args>(args)...));
}
template<typename... Args>
inline Tuple select(const Tuple &c0, const Tuple &v0, const Tuple &c1, const Tuple &v1, Args &&...args) {
return select(c0, v0, select(c1, v1, std::forward<Args>(args)...));
}
template<typename... Args>
inline Tuple select(const Expr &c0, const Tuple &v0, const Expr &c1, const Tuple &v1, Args &&...args) {
return select(c0, v0, select(c1, v1, std::forward<Args>(args)...));
}
// @}
/** select applied to FuncRefs (e.g. select(x < 100, f(x), g(x))) is assumed to
* return an Expr. A runtime error is produced if this is applied to
* tuple-valued Funcs. In that case you should explicitly cast the second and
* third args to Tuple to remove the ambiguity. */
// @{
Expr select(const Expr &condition, const FuncRef &true_value, const FuncRef &false_value);
template<typename... Args>
inline Expr select(const Expr &c0, const FuncRef &v0, const Expr &c1, const FuncRef &v1, Args &&...args) {
return select(c0, v0, select(c1, v1, std::forward<Args>(args)...));
}
// @}
/** Oftentimes we want to pack a list of expressions with the same type
* into a channel dimension, e.g.,
* img(x, y, c) = select(c == 0, 100, // Red
* c == 1, 50, // Green
* 25); // Blue
* This is tedious when the list is long. The following function
* provide convinent syntax that allow one to write:
* img(x, y, c) = mux(c, {100, 50, 25});
*
* As with the select equivalent, if the first argument (the index) is
* out of range, the expression evaluates to the last value.
*/
// @{
Expr mux(const Expr &id, const std::initializer_list<Expr> &values);
Expr mux(const Expr &id, const std::vector<Expr> &values);
Expr mux(const Expr &id, const Tuple &values);
Expr mux(const Expr &id, const std::initializer_list<FuncRef> &values);
Tuple mux(const Expr &id, const std::initializer_list<Tuple> &values);
Tuple mux(const Expr &id, const std::vector<Tuple> &values);
// @}
/** Return the sine of a floating-point expression. If the argument is
* not floating-point, it is cast to Float(32). Does not vectorize
* well. */
Expr sin(Expr x);
/** Return the arcsine of a floating-point expression. If the argument
* is not floating-point, it is cast to Float(32). Does not vectorize
* well. */
Expr asin(Expr x);
/** Return the cosine of a floating-point expression. If the argument
* is not floating-point, it is cast to Float(32). Does not vectorize
* well. */
Expr cos(Expr x);
/** Return the arccosine of a floating-point expression. If the
* argument is not floating-point, it is cast to Float(32). Does not
* vectorize well. */
Expr acos(Expr x);
/** Return the tangent of a floating-point expression. If the argument
* is not floating-point, it is cast to Float(32). Does not vectorize
* well. */
Expr tan(Expr x);
/** Return the arctangent of a floating-point expression. If the
* argument is not floating-point, it is cast to Float(32). Does not
* vectorize well. */
Expr atan(Expr x);
/** Return the angle of a floating-point gradient. If the argument is
* not floating-point, it is cast to Float(32). Does not vectorize
* well. */
Expr atan2(Expr y, Expr x);
/** Return the hyperbolic sine of a floating-point expression. If the
* argument is not floating-point, it is cast to Float(32). Does not
* vectorize well. */
Expr sinh(Expr x);
/** Return the hyperbolic arcsinhe of a floating-point expression. If
* the argument is not floating-point, it is cast to Float(32). Does
* not vectorize well. */
Expr asinh(Expr x);
/** Return the hyperbolic cosine of a floating-point expression. If
* the argument is not floating-point, it is cast to Float(32). Does
* not vectorize well. */
Expr cosh(Expr x);
/** Return the hyperbolic arccosine of a floating-point expression.
* If the argument is not floating-point, it is cast to
* Float(32). Does not vectorize well. */
Expr acosh(Expr x);
/** Return the hyperbolic tangent of a floating-point expression. If
* the argument is not floating-point, it is cast to Float(32). Does
* not vectorize well. */
Expr tanh(Expr x);
/** Return the hyperbolic arctangent of a floating-point expression.
* If the argument is not floating-point, it is cast to
* Float(32). Does not vectorize well. */
Expr atanh(Expr x);
/** Return the square root of a floating-point expression. If the
* argument is not floating-point, it is cast to Float(32). Typically
* vectorizes cleanly. */
Expr sqrt(Expr x);
/** Return the square root of the sum of the squares of two
* floating-point expressions. If the argument is not floating-point,
* it is cast to Float(32). Vectorizes cleanly. */
Expr hypot(const Expr &x, const Expr &y);
/** Return the exponential of a floating-point expression. If the
* argument is not floating-point, it is cast to Float(32). For
* Float(64) arguments, this calls the system exp function, and does
* not vectorize well. For Float(32) arguments, this function is
* vectorizable, does the right thing for extremely small or extremely
* large inputs, and is accurate up to the last bit of the
* mantissa. Vectorizes cleanly. */
Expr exp(Expr x);
/** Return the logarithm of a floating-point expression. If the
* argument is not floating-point, it is cast to Float(32). For
* Float(64) arguments, this calls the system log function, and does
* not vectorize well. For Float(32) arguments, this function is
* vectorizable, does the right thing for inputs <= 0 (returns -inf or
* nan), and is accurate up to the last bit of the
* mantissa. Vectorizes cleanly. */
Expr log(Expr x);
/** Return one floating point expression raised to the power of
* another. The type of the result is given by the type of the first
* argument. If the first argument is not a floating-point type, it is
* cast to Float(32). For Float(32), cleanly vectorizable, and
* accurate up to the last few bits of the mantissa. Gets worse when
* approaching overflow. Vectorizes cleanly. */
Expr pow(Expr x, Expr y);
/** Evaluate the error function erf. Only available for
* Float(32). Accurate up to the last three bits of the
* mantissa. Vectorizes cleanly. */
Expr erf(const Expr &x);