diff --git a/gcc/match.pd b/gcc/match.pd index 39da61bf117a6eb2924fc8a6473fb37ddadd60e9..7b8f50410acfd0afafc5606e972cfc4e125d3a5d 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -3577,6 +3577,25 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (cond (le @0 integer_zerop@1) (negate@2 @0) integer_zerop@1) (max @2 @1)) +/* (a & ((c `op` d) - 1)) | (b & ~((c `op` d) - 1)) -> c `op` d ? a : b. */ +(for op (simple_comparison) + (simplify + (bit_xor:c + (convert2? @0) + (bit_and:c + (convert2? (bit_xor:c @1 @0)) + (convert3? (negate (convert? (op@4 @2 @3)))))) + /* Alternative form, where some canonicalization were not done due to the + arguments being signed. */ + (if (INTEGRAL_TYPE_P (type) && tree_zero_one_valued_p (@4)) + (convert:type (cond @4 @1 @0)))) + (simplify + (bit_ior:c + (mult:c @0 (convert (convert2? (op@4 @2 @3)))) + (bit_and:c @1 (convert (plus:c integer_minus_onep (convert (op@4 @2 @3)))))) + (if (INTEGRAL_TYPE_P (type) && tree_zero_one_valued_p (@4)) + (cond @4 @0 @1)))) + /* Simplifications of shift and rotates. */ (for rotate (lrotate rrotate) diff --git a/gcc/testsuite/gcc.dg/select_cond_1.c b/gcc/testsuite/gcc.dg/select_cond_1.c new file mode 100644 index 0000000000000000000000000000000000000000..9eb9959baafe5fffeec24e4e3ae656f8fcfe943c --- /dev/null +++ b/gcc/testsuite/gcc.dg/select_cond_1.c @@ -0,0 +1,97 @@ +/* { dg-do run } */ +/* { dg-additional-options "-O2 -std=c99 -fdump-tree-optimized -save-temps" } */ + +#include + +__attribute__((noipa, noinline)) +uint32_t min1_32u(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + uint32_t result; + uint32_t m = (a >= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t max1_32u(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + uint32_t result; + uint32_t m = (a <= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min2_32u(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + uint32_t result; + uint32_t m = (a > b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t max2_32u(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + uint32_t result; + uint32_t m = (a < b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min3_32u(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + uint32_t result; + uint32_t m = (a == b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t max3_32u(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + uint32_t result; + uint32_t m = (a != b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +/* { dg-final { scan-tree-dump-times {_[0-9]+ \? c_[0-9]+\(D\) : d_[0-9]+\(D\)} 6 "optimized" } } */ + +extern void abort (); + +int main () { + + if (min1_32u (3, 5, 7 , 8) != 7) + abort (); + + if (max1_32u (3, 5, 7 , 8) != 8) + abort (); + + if (min1_32u (5, 3, 7 , 8) != 8) + abort (); + + if (max1_32u (5, 3, 7 , 8) != 7) + abort (); + + if (min2_32u (3, 5, 7 , 8) != 7) + abort (); + + if (max2_32u (3, 5, 7 , 8) != 8) + abort (); + + if (min2_32u (5, 3, 7 , 8) != 8) + abort (); + + if (max2_32u (5, 3, 7 , 8) != 7) + abort (); + + if (min3_32u (3, 5, 7 , 8) != 7) + abort (); + + if (max3_32u (3, 5, 7 , 8) != 8) + abort (); + + if (min3_32u (5, 3, 7 , 8) != 7) + abort (); + + if (max3_32u (5, 3, 7 , 8) != 8) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/select_cond_2.c b/gcc/testsuite/gcc.dg/select_cond_2.c new file mode 100644 index 0000000000000000000000000000000000000000..623b2272ee7b4b00130d5e9fb8c781dbc5d4189e --- /dev/null +++ b/gcc/testsuite/gcc.dg/select_cond_2.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-additional-options "-O2 -std=c99 -fdump-tree-optimized -save-temps" } */ + +#include + +__attribute__((noipa, noinline)) +uint32_t min1_32u(uint32_t a, uint32_t b) { + uint32_t result; + uint32_t m = (a >= b) - 1; + result = (a & m) | (b & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t max1_32u(uint32_t a, uint32_t b) { + uint32_t result; + uint32_t m = (a <= b) - 1; + result = (a & m) | (b & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min2_32u(uint32_t a, uint32_t b) { + uint32_t result; + uint32_t m = (a > b) - 1; + result = (a & m) | (b & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t max2_32u(uint32_t a, uint32_t b) { + uint32_t result; + uint32_t m = (a < b) - 1; + result = (a & m) | (b & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min3_32u(uint32_t a, uint32_t b) { + uint32_t result; + uint32_t m = (a == b) - 1; + result = (a & m) | (b & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t max3_32u(uint32_t a, uint32_t b) { + uint32_t result; + uint32_t m = (a != b) - 1; + result = (a & m) | (b & ~m); + return result; +} + +/* { dg-final { scan-tree-dump-not {_[0-9]+ \? c_[0-9]+\(D\) : d_[0-9]+\(D\)} "optimized" } } */ +/* { dg-final { scan-tree-dump-times {MIN_EXPR} 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times {MAX_EXPR} 2 "optimized" } } */ + +extern void abort (); + +int main () { + + if (min1_32u (7 , 8) != 7) + abort (); + + if (max1_32u (7 , 8) != 8) + abort (); + + if (min1_32u (7 , 8) != 7) + abort (); + + if (max1_32u (7, 8) != 8) + abort (); + + if (min2_32u (7 , 8) != 7) + abort (); + + if (max2_32u (7 , 8) != 8) + abort (); + + if (min2_32u (7 , 8) != 7) + abort (); + + if (max2_32u (7 , 8) != 8) + abort (); + + if (min3_32u (7 , 8) != 7) + abort (); + + if (max3_32u (7 , 8) != 8) + abort (); + + if (min3_32u (7 , 8) != 7) + abort (); + + if (max3_32u (7 , 8) != 8) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/select_cond_3.c b/gcc/testsuite/gcc.dg/select_cond_3.c new file mode 100644 index 0000000000000000000000000000000000000000..754e73b121ce360564481b1fa7e1dd4fb27642a3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/select_cond_3.c @@ -0,0 +1,101 @@ +/* { dg-do run } */ +/* { dg-additional-options "-O2 -std=c99 -fdump-tree-optimized -save-temps" } */ + +#include + +__attribute__((noipa, noinline)) +int32_t min1_32u1(int32_t a, int32_t b, int32_t c, int32_t d) { + uint32_t result; + uint32_t m = (a >= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min1_32u2(uint32_t a, uint32_t b, int32_t c, int32_t d) { + uint32_t result; + uint32_t m = (a >= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min1_32u3(uint32_t a, uint32_t b, uint32_t c, int32_t d) { + uint32_t result; + uint32_t m = (a >= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min1_32u4(uint32_t a, uint32_t b, int32_t c, uint32_t d) { + uint32_t result; + uint32_t m = (a >= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min1_32u5(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + uint32_t result; + uint32_t m = (a >= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min1_32u6(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + uint32_t result; + int32_t m = (a >= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min1_32u7(uint8_t a, uint16_t b, uint32_t c, uint32_t d) { + uint32_t result; + int32_t m = (a >= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +__attribute__((noipa, noinline)) +uint32_t min1_32u8(uint32_t a, uint64_t b, uint32_t c, uint32_t d) { + uint32_t result; + int32_t m = (a >= b) - 1; + result = (c & m) | (d & ~m); + return result; +} + +/* { dg-final { scan-tree-dump-times {_[0-9]+ \? c[^ ]+ : d[^ ]+;} 8 "optimized" } } */ + +extern void abort (); + +int main () { + + if (min1_32u1 (3, 5, 7 , 8) != 7) + abort (); + + if (min1_32u2 (3, 5, 7 , 8) != 7) + abort (); + + if (min1_32u3 (3, 5, 7 , 8) != 7) + abort (); + + if (min1_32u4 (3, 5, 7 , 8) != 7) + abort (); + + if (min1_32u5 (3, 5, 7 , 8) != 7) + abort (); + + if (min1_32u6 (3, 5, 7 , 8) != 7) + abort (); + + if (min1_32u7 (3, 5, 7 , 8) != 7) + abort (); + + if (min1_32u8 (3, 5, 7 , 8) != 7) + abort (); + + return 0; +}