diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc index 4f4ec81c8d4b6937ade3141a14c695b67c874c35..0ee083f290d12104969f1b335dc33917c97b4808 100644 --- a/gcc/fold-const.cc +++ b/gcc/fold-const.cc @@ -7212,7 +7212,9 @@ fold_binary_op_with_conditional_arg (location_t loc, } /* Check that we have simplified at least one of the branches. */ - if (!TREE_CONSTANT (arg) && !TREE_CONSTANT (lhs) && !TREE_CONSTANT (rhs)) + if ((!TREE_CONSTANT (arg) && !TREE_CONSTANT (lhs) && !TREE_CONSTANT (rhs)) + || (TREE_CONSTANT (arg) && TREE_CODE (lhs) == TREE_CODE (rhs) + && !TREE_CONSTANT (lhs))) return NULL_TREE; return fold_build3_loc (loc, cond_code, type, test, lhs, rhs); diff --git a/gcc/match.pd b/gcc/match.pd index b225d36dc758f1581502c8d03761544bfd499c01..b61ed70e69b881a49177f10f20c1f92712bb8665 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -4318,6 +4318,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (op @3 (vec_cond:s @0 @1 @2)) (vec_cond @0 (op! @3 @1) (op! @3 @2)))) +/* Float out binary operations from branches if they can't be folded. + Fold (a ? (b op c) : (d op c)) --> (op (a ? b : d) c). */ +(for op (plus mult min max bit_and bit_ior bit_xor minus lshift rshift rdiv + trunc_div ceil_div floor_div round_div trunc_mod ceil_mod floor_mod + round_mod) + (simplify + (cond @0 (op @1 @2) (op @3 @2)) + (if (!FLOAT_TYPE_P (type) || !(HONOR_NANS (@1) && flag_trapping_math)) + (op (cond @0 @1 @3) @2)))) + #if GIMPLE (match (nop_atomic_bit_test_and_p @0 @1 @4) (bit_and (convert?@4 (ATOMIC_FETCH_OR_XOR_N @2 INTEGER_CST@0 @3)) diff --git a/gcc/testsuite/gcc.target/aarch64/if-compare_3.c b/gcc/testsuite/gcc.target/aarch64/if-compare_3.c new file mode 100644 index 0000000000000000000000000000000000000000..1d97da5c0d6454175881c219927471a567a6f0c7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/if-compare_3.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O3 -std=c99" } */ +/* { dg-final { check-function-bodies "**" "" "" { target { le } } } } */ + +/* +**zoo: +** cmp w0, w1 +** csel w0, w3, w2, le +** ret +*/ +int zoo (int a, int b, int c, int d) +{ + return a > b ? c : d; +} + +/* +**zoo1: +** cmp w0, w1 +** csel w0, w3, w2, le +** and w0, w0, 1 +** ret +*/ +int zoo1 (int a, int b, int c, int d) +{ + return (a > b ? c : d) & 1; +} + diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index b19710392940cf469de52d006603ae1e3deb6b76..aaf1b29da5c598add25dad2c38b828eaa89c49ce 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -4244,7 +4244,9 @@ verify_gimple_assign_ternary (gassign *stmt) return true; } - if (!is_gimple_val (rhs1) + /* In a COND_EXPR the rhs1 is the condition and thus isn't + a gimple value by definition. */ + if ((!is_gimple_val (rhs1) && rhs_code != COND_EXPR) || !is_gimple_val (rhs2) || !is_gimple_val (rhs3)) {