This patch refactors the AArch64 SVE vector-compare helpers so that callers
can supply the predicate that should govern the comparison.  Existing callers
keep their current all-true behaviour, but the helpers no longer assume all
lanes are active.

That is a small mechanical change, but it is the backend hook needed by the
following conditional vector compare implementation.  The middle end can now
pass the mask captured by COND_VEC_CMP or COND_LEN_VEC_CMP all the way to the
target compare expander.

For example:

  void f (int *__restrict a, int *__restrict b, int *__restrict c,
          int *__restrict d)
  {
    for (int i = 0; i < 1024; ++i)
      if (c[i] != 0 && a[i] < b[i])
        d[i] = a[i];
  }

Old GIMPLE/code generation carried this as separate compare and mask
operations, so the target had to rediscover that the second compare was
governed by the first mask:

  mask0 = vect_c != 0;
  mask1 = vect_a < vect_b;
  mask2 = mask0 & mask1;

With this branch and aarch64-none-elf-gcc, SVE receives the governing
predicate directly and emits the second compare under that predicate:

  cmpne   p7.s, p7/z, z29.s, #0
  ld1w    z31.s, p7/z, [x0, x4, lsl 2]
  ld1w    z30.s, p7/z, [x1, x4, lsl 2]
  cmplt   p7.s, p7/z, z31.s, z30.s
  st1w    z31.s, p7, [x3, x4, lsl 2]

The key point in the new code is the second compare: it is explicitly
performed under p7 rather than under an implicit ptrue.  That is exactly the
information carried by the conditional compare IFN.

Bootstrapped Regtested on aarch64-none-linux-gnu,
arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
-m32, -m64 and no issues.

-O3, profiled, profiled -O3 and -O3 -LTO bootstrap tested and no issues.

 Also SPECCPU 2017 and SPECCPU 2026 tested.

OK for master?

Thanks,
Tamar

gcc/ChangeLog:

        * config/aarch64/aarch64-protos.h: Update SVE compare prototypes.
        (aarch64_expand_sve_vec_cmp_int): Add governing predicate parameter.
        (aarch64_expand_sve_vec_cmp_float): Likewise.
        * config/aarch64/aarch64.cc (aarch64_sve_emit_int_cmp): Accept a
        governing predicate.
        (aarch64_convert_sve_data_to_pred): Pass the predicate through.
        (aarch64_expand_sve_vec_cmp_int): Likewise.
        (aarch64_expand_sve_vec_cmp_float): Likewise.

---
diff --git a/gcc/config/aarch64/aarch64-protos.h 
b/gcc/config/aarch64/aarch64-protos.h
index 
4d882ce90ae2ea50b9b33a380af7a6f1d0bc27a5..4d38e65f9c41d7e201f8300893552640e19e7942
 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -1136,8 +1136,10 @@ bool aarch64_gen_adjusted_ldpstp (rtx *, bool, 
machine_mode, RTX_CODE);
 void aarch64_finish_ldpstp_peephole (rtx *, bool,
                                     enum rtx_code = (enum rtx_code)0);
 
-void aarch64_expand_sve_vec_cmp_int (rtx, rtx_code, rtx, rtx);
-void aarch64_expand_sve_vec_cmp_float (rtx, rtx_code, rtx, rtx);
+void aarch64_expand_sve_vec_cmp_int (rtx, rtx_code, rtx, rtx,
+                                    rtx = NULL_RTX);
+void aarch64_expand_sve_vec_cmp_float (rtx, rtx_code, rtx, rtx,
+                                      rtx = NULL_RTX);
 
 bool aarch64_prepare_sve_int_fma (rtx *, rtx_code);
 bool aarch64_prepare_sve_cond_int_fma (rtx *, rtx_code);
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 
b5239681addf09ab245ba885fff58cf61eef4f0e..dfb045b2afe71ea5fc8837760ebabebebffd6909
 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -4337,7 +4337,8 @@ aarch64_sve_emit_masked_fp_pred (machine_mode data_mode, 
rtx pred)
 
 static rtx
 aarch64_sve_emit_int_cmp (rtx target, machine_mode pred_mode, rtx_code cmp,
-                         machine_mode data_mode, rtx op1, rtx op2)
+                         machine_mode data_mode, rtx op1, rtx op2,
+                         rtx pred)
 {
   auto src_pred_mode = aarch64_sve_pred_mode (data_mode);
   insn_code icode;
@@ -4347,8 +4348,13 @@ aarch64_sve_emit_int_cmp (rtx target, machine_mode 
pred_mode, rtx_code cmp,
     icode = code_for_aarch64_pred_cmp_acle (cmp, data_mode);
   expand_operand ops[5];
   create_output_operand (&ops[0], target, pred_mode);
-  create_input_operand (&ops[1], CONSTM1_RTX (src_pred_mode), src_pred_mode);
-  create_integer_operand (&ops[2], SVE_KNOWN_PTRUE);
+  bool known_ptrue_p = !pred;
+  if (known_ptrue_p)
+    pred = CONSTM1_RTX (src_pred_mode);
+  create_input_operand (&ops[1], pred, src_pred_mode);
+  create_integer_operand (&ops[2], (known_ptrue_p
+                                   ? SVE_KNOWN_PTRUE
+                                   : SVE_MAYBE_NOT_PTRUE));
   create_input_operand (&ops[3], op1, data_mode);
   create_input_operand (&ops[4], op2, data_mode);
   expand_insn (icode, 5, ops);
@@ -4363,7 +4369,7 @@ aarch64_convert_sve_data_to_pred (rtx target, rtx src)
 {
   machine_mode src_mode = GET_MODE (src);
   return aarch64_sve_emit_int_cmp (target, VNx16BImode, NE, src_mode,
-                                  src, CONST0_RTX (src_mode));
+                                  src, CONST0_RTX (src_mode), NULL_RTX);
 }
 
 /* Return the assembly token for svprfop value PRFOP.  */
@@ -28997,15 +29003,19 @@ aarch64_reverse_mask (machine_mode mode, unsigned int 
nunits)
 
 /* Expand an SVE integer comparison using the SVE equivalent of:
 
-     (set TARGET (CODE OP0 OP1)).  */
+     (set TARGET (CODE OP0 OP1)).
+
+   If PRED is nonnull, use it as the governing predicate instead of an
+   all-true predicate.  */
 
 void
-aarch64_expand_sve_vec_cmp_int (rtx target, rtx_code code, rtx op0, rtx op1)
+aarch64_expand_sve_vec_cmp_int (rtx target, rtx_code code, rtx op0, rtx op1,
+                               rtx pred)
 {
   machine_mode pred_mode = GET_MODE (target);
   machine_mode data_mode = GET_MODE (op0);
   rtx res = aarch64_sve_emit_int_cmp (target, pred_mode, code, data_mode,
-                                     op0, op1);
+                                     op0, op1, pred);
   if (!rtx_equal_p (target, res))
     emit_move_insn (target, res);
 }
@@ -29097,14 +29107,19 @@ aarch64_emit_sve_invert_fp_cond (rtx target, rtx_code 
code, rtx pred,
      (set TARGET (CODE OP0 OP1)).  */
 
 void
-aarch64_expand_sve_vec_cmp_float (rtx target, rtx_code code, rtx op0, rtx op1)
+aarch64_expand_sve_vec_cmp_float (rtx target, rtx_code code, rtx op0, rtx op1,
+                                 rtx pred)
 {
   machine_mode data_mode = GET_MODE (op0);
-  rtx pred = aarch64_sve_fp_pred (data_mode, nullptr);
+  bool pred_supplied_p = pred != NULL_RTX;
+  if (!pred)
+    pred = aarch64_sve_fp_pred (data_mode, nullptr);
 
   /* The governing and destination modes.  */
   machine_mode pred_mode = GET_MODE (pred);
   machine_mode target_mode = GET_MODE (target);
+  if (!aarch64_simd_reg_or_zero (op1, data_mode))
+    op1 = force_reg (data_mode, op1);
 
   /* For partial vector modes, the choice of predicate mode depends
      on whether we need to suppress exceptions for inactive elements.
@@ -29117,7 +29132,7 @@ aarch64_expand_sve_vec_cmp_float (rtx target, rtx_code 
code, rtx op0, rtx op1)
      If we don't need to suppress exceptions, the predicate mode matches
      the container size, PRED_MODE == TARGET_MODE, and the predicate is
      thus a ptrue wrt both TARGET_MODE and PRED_MODE.  */
-  bool known_ptrue_p = pred_mode == target_mode;
+  bool known_ptrue_p = !pred_supplied_p && pred_mode == target_mode;
   switch (code)
     {
     case UNORDERED:
@@ -29163,7 +29178,7 @@ aarch64_expand_sve_vec_cmp_float (rtx target, rtx_code 
code, rtx op0, rtx op1)
          aarch64_emit_sve_fp_cond (uo_tmp, UNORDERED,
                                    pred, known_ptrue_p, op0, op1);
 
-         /* Invert the result.  Governered by PRED so that we only
+         /* Invert the result.  Governed by PRED so that we only
             flip the active bits.  */
          rtx ordered = gen_reg_rtx (pred_mode);
          uo_tmp = gen_lowpart (pred_mode, uo_tmp);


-- 
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 4d882ce90ae2ea50b9b33a380af7a6f1d0bc27a5..4d38e65f9c41d7e201f8300893552640e19e7942 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -1136,8 +1136,10 @@ bool aarch64_gen_adjusted_ldpstp (rtx *, bool, machine_mode, RTX_CODE);
 void aarch64_finish_ldpstp_peephole (rtx *, bool,
 				     enum rtx_code = (enum rtx_code)0);
 
-void aarch64_expand_sve_vec_cmp_int (rtx, rtx_code, rtx, rtx);
-void aarch64_expand_sve_vec_cmp_float (rtx, rtx_code, rtx, rtx);
+void aarch64_expand_sve_vec_cmp_int (rtx, rtx_code, rtx, rtx,
+				     rtx = NULL_RTX);
+void aarch64_expand_sve_vec_cmp_float (rtx, rtx_code, rtx, rtx,
+				       rtx = NULL_RTX);
 
 bool aarch64_prepare_sve_int_fma (rtx *, rtx_code);
 bool aarch64_prepare_sve_cond_int_fma (rtx *, rtx_code);
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index b5239681addf09ab245ba885fff58cf61eef4f0e..dfb045b2afe71ea5fc8837760ebabebebffd6909 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -4337,7 +4337,8 @@ aarch64_sve_emit_masked_fp_pred (machine_mode data_mode, rtx pred)
 
 static rtx
 aarch64_sve_emit_int_cmp (rtx target, machine_mode pred_mode, rtx_code cmp,
-			  machine_mode data_mode, rtx op1, rtx op2)
+			  machine_mode data_mode, rtx op1, rtx op2,
+			  rtx pred)
 {
   auto src_pred_mode = aarch64_sve_pred_mode (data_mode);
   insn_code icode;
@@ -4347,8 +4348,13 @@ aarch64_sve_emit_int_cmp (rtx target, machine_mode pred_mode, rtx_code cmp,
     icode = code_for_aarch64_pred_cmp_acle (cmp, data_mode);
   expand_operand ops[5];
   create_output_operand (&ops[0], target, pred_mode);
-  create_input_operand (&ops[1], CONSTM1_RTX (src_pred_mode), src_pred_mode);
-  create_integer_operand (&ops[2], SVE_KNOWN_PTRUE);
+  bool known_ptrue_p = !pred;
+  if (known_ptrue_p)
+    pred = CONSTM1_RTX (src_pred_mode);
+  create_input_operand (&ops[1], pred, src_pred_mode);
+  create_integer_operand (&ops[2], (known_ptrue_p
+				    ? SVE_KNOWN_PTRUE
+				    : SVE_MAYBE_NOT_PTRUE));
   create_input_operand (&ops[3], op1, data_mode);
   create_input_operand (&ops[4], op2, data_mode);
   expand_insn (icode, 5, ops);
@@ -4363,7 +4369,7 @@ aarch64_convert_sve_data_to_pred (rtx target, rtx src)
 {
   machine_mode src_mode = GET_MODE (src);
   return aarch64_sve_emit_int_cmp (target, VNx16BImode, NE, src_mode,
-				   src, CONST0_RTX (src_mode));
+				   src, CONST0_RTX (src_mode), NULL_RTX);
 }
 
 /* Return the assembly token for svprfop value PRFOP.  */
@@ -28997,15 +29003,19 @@ aarch64_reverse_mask (machine_mode mode, unsigned int nunits)
 
 /* Expand an SVE integer comparison using the SVE equivalent of:
 
-     (set TARGET (CODE OP0 OP1)).  */
+     (set TARGET (CODE OP0 OP1)).
+
+   If PRED is nonnull, use it as the governing predicate instead of an
+   all-true predicate.  */
 
 void
-aarch64_expand_sve_vec_cmp_int (rtx target, rtx_code code, rtx op0, rtx op1)
+aarch64_expand_sve_vec_cmp_int (rtx target, rtx_code code, rtx op0, rtx op1,
+				rtx pred)
 {
   machine_mode pred_mode = GET_MODE (target);
   machine_mode data_mode = GET_MODE (op0);
   rtx res = aarch64_sve_emit_int_cmp (target, pred_mode, code, data_mode,
-				      op0, op1);
+				      op0, op1, pred);
   if (!rtx_equal_p (target, res))
     emit_move_insn (target, res);
 }
@@ -29097,14 +29107,19 @@ aarch64_emit_sve_invert_fp_cond (rtx target, rtx_code code, rtx pred,
      (set TARGET (CODE OP0 OP1)).  */
 
 void
-aarch64_expand_sve_vec_cmp_float (rtx target, rtx_code code, rtx op0, rtx op1)
+aarch64_expand_sve_vec_cmp_float (rtx target, rtx_code code, rtx op0, rtx op1,
+				  rtx pred)
 {
   machine_mode data_mode = GET_MODE (op0);
-  rtx pred = aarch64_sve_fp_pred (data_mode, nullptr);
+  bool pred_supplied_p = pred != NULL_RTX;
+  if (!pred)
+    pred = aarch64_sve_fp_pred (data_mode, nullptr);
 
   /* The governing and destination modes.  */
   machine_mode pred_mode = GET_MODE (pred);
   machine_mode target_mode = GET_MODE (target);
+  if (!aarch64_simd_reg_or_zero (op1, data_mode))
+    op1 = force_reg (data_mode, op1);
 
   /* For partial vector modes, the choice of predicate mode depends
      on whether we need to suppress exceptions for inactive elements.
@@ -29117,7 +29132,7 @@ aarch64_expand_sve_vec_cmp_float (rtx target, rtx_code code, rtx op0, rtx op1)
      If we don't need to suppress exceptions, the predicate mode matches
      the container size, PRED_MODE == TARGET_MODE, and the predicate is
      thus a ptrue wrt both TARGET_MODE and PRED_MODE.  */
-  bool known_ptrue_p = pred_mode == target_mode;
+  bool known_ptrue_p = !pred_supplied_p && pred_mode == target_mode;
   switch (code)
     {
     case UNORDERED:
@@ -29163,7 +29178,7 @@ aarch64_expand_sve_vec_cmp_float (rtx target, rtx_code code, rtx op0, rtx op1)
 	  aarch64_emit_sve_fp_cond (uo_tmp, UNORDERED,
 				    pred, known_ptrue_p, op0, op1);
 
-	  /* Invert the result.  Governered by PRED so that we only
+	  /* Invert the result.  Governed by PRED so that we only
 	     flip the active bits.  */
 	  rtx ordered = gen_reg_rtx (pred_mode);
 	  uo_tmp = gen_lowpart (pred_mode, uo_tmp);

Reply via email to