Gimple isel already handles x CMP y ? -1 : 0 when lowering vector cond operations, but this can be generalized further when the comparison forms a natural mask so that we can also handle x CMP y ? z : 0 by transforming it into (x CMP y) & z. This will, in most cases save having to load a register with the zero vector.
gcc/ChangeLog: * gimple-isel.cc (gimple_expand_vec_cond_expr): Handle x CMP y ? z : 0. --- gcc/gimple-isel.cc | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/gcc/gimple-isel.cc b/gcc/gimple-isel.cc index a8f7a0d25d0..5bf4a4eccc1 100644 --- a/gcc/gimple-isel.cc +++ b/gcc/gimple-isel.cc @@ -190,16 +190,33 @@ gimple_expand_vec_cond_expr (struct function *fun, gimple_stmt_iterator *gsi, can_compute_op0 = expand_vec_cmp_expr_p (op0a_type, op0_type, tcode); - /* Try to fold x CMP y ? -1 : 0 to x CMP y. */ + /* Try to fold x CMP y ? z : 0. */ if (can_compute_op0 - && integer_minus_onep (op1) && integer_zerop (op2) && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (TREE_TYPE (op0))) { - tree conv_op = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), op0); - gassign *new_stmt = gimple_build_assign (lhs, conv_op); - gsi_replace (gsi, new_stmt, true); - return new_stmt; + /* If Z is -1, then the result is just the comparison. */ + if (integer_minus_onep (op1)) + { + tree conv_op = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), + op0); + gassign *new_stmt = gimple_build_assign (lhs, conv_op); + gsi_replace (gsi, new_stmt, true); + return new_stmt; + } + /* Otherwise, use the comparison as a mask for Z. */ + else + { + gimple_seq stmts = NULL; + tree type = TREE_TYPE (lhs); + location_t loc = gimple_location (stmt); + tree tem0 = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, + type, op0); + tree tem1 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, + tem0, op1); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + return gimple_build_assign (lhs, tem1); + } } /* When the compare has EH we do not want to forward it when