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