From: juewang <[email protected]>

Handle conditional arithmetic wrapped in a sign or zero extension when
the unchanged value is known to have the same extension.  Query the
promoted lowpart directly instead of searching for its definition.

gcc/ChangeLog:

        * ifcvt.cc (noce_cond_arith_operation): New function.
        (noce_operand_known_extended_p): New function.
        (noce_try_cond_arith): Handle arithmetic operations wrapped in an
        extension.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/pr122769.c: Add the branch cost and restrict the
        test to compatible optimization options.
        * gcc.target/riscv/zicond-conditional-add-extend.c: New test.
---
 gcc/ifcvt.cc                                  | 70 ++++++++++++++++++-
 gcc/testsuite/gcc.target/riscv/pr122769.c     |  3 +-
 .../riscv/zicond-conditional-add-extend.c     | 23 ++++++
 3 files changed, 92 insertions(+), 4 deletions(-)
 create mode 100644 
gcc/testsuite/gcc.target/riscv/zicond-conditional-add-extend.c

diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index add276ceb9b..9927605385a 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -3370,6 +3370,41 @@ noce_try_sign_mask (struct noce_if_info *if_info)
   return true;
 }
 
+/* Return the arithmetic operation in X, looking through an extension.  */
+
+static rtx
+noce_cond_arith_operation (rtx x)
+{
+  enum rtx_code code = GET_CODE (x);
+  if (code == SIGN_EXTEND || code == ZERO_EXTEND)
+    x = XEXP (x, 0);
+
+  return noce_cond_zero_binary_op_supported (x) ? x : NULL_RTX;
+}
+
+/* Return true if X contains an EXT_CODE extension from its mode to
+   OUTER_MODE.  */
+
+static bool
+noce_operand_known_extended_p (rtx x, machine_mode outer_mode,
+                              enum rtx_code ext_code)
+{
+  machine_mode inner_mode = GET_MODE (x);
+  unsigned int precision = GET_MODE_PRECISION (outer_mode).to_constant ();
+  unsigned int inner_precision
+    = GET_MODE_PRECISION (inner_mode).to_constant ();
+  if (ext_code == SIGN_EXTEND)
+    return (num_sign_bit_copies (x, outer_mode)
+           > precision - inner_precision);
+
+  if (ext_code == ZERO_EXTEND)
+    return (HWI_COMPUTABLE_MODE_P (outer_mode)
+           && (nonzero_bits (x, outer_mode)
+               & ~GET_MODE_MASK (inner_mode)) == 0);
+
+  return false;
+}
+
 /*  Helper function to return REG itself,
     otherwise NULL_RTX for other RTX_CODE.  */
 
@@ -3412,7 +3447,7 @@ get_base_reg_or_constant (rtx exp)
 static int
 noce_try_cond_arith (struct noce_if_info *if_info)
 {
-  rtx target, a, b, a_op0, a_op1;
+  rtx target, a, b, a_op0, a_op1, outer_a;
   rtx cond = if_info->cond;
   rtx_code code = GET_CODE (cond);
   rtx_insn *seq;
@@ -3431,9 +3466,11 @@ noce_try_cond_arith (struct noce_if_info *if_info)
 
   a = copy_rtx (if_info->a);
   b = copy_rtx (if_info->b);
+  rtx a_arith = noce_cond_arith_operation (a);
+  rtx b_arith = noce_cond_arith_operation (b);
 
   /* Canonicalize x = y : (y op z) to x = (y op z) : y.  */
-  if (REG_P (a) && noce_cond_zero_binary_op_supported (b))
+  if (REG_P (a) && b_arith)
     {
       if (if_info->rev_cond)
        {
@@ -3443,17 +3480,28 @@ noce_try_cond_arith (struct noce_if_info *if_info)
       else
        code = reversed_comparison_code (cond, if_info->jump);
       std::swap (a, b);
+      a_arith = b_arith;
     }
 
   /* Check if x = (y op z) : y is supported by czero based ifcvt.  */
-  else if (!(noce_cond_zero_binary_op_supported (a) && REG_P (b)))
+  else if (!(a_arith && REG_P (b)))
     goto fail;
 
   if (code == UNKNOWN)
     goto fail;
 
+  outer_a = a == a_arith ? NULL_RTX : a;
+  a = a_arith;
   op = GET_CODE (a);
 
+  /* EXTEND (y op z) : y is valid only when Y already contains the same
+     extension of its lowpart.  AND uses a different transformation.  */
+  if (outer_a
+      && (op == AND
+         || GET_MODE (outer_a) != mode
+         || !SCALAR_INT_MODE_P (GET_MODE (a))))
+    goto fail;
+
   /* Canonicalize x = (z op y) : y to x = (y op z) : y */
   a_op1 = get_base_reg_or_constant (XEXP (a, 1));
   if (a_op1 && rtx_equal_p (a_op1, b) && COMMUTATIVE_ARITH_P (a))
@@ -3470,6 +3518,14 @@ noce_try_cond_arith (struct noce_if_info *if_info)
   if (!(a_op0 && rtx_equal_p (a_op0, b)))
     goto fail;
 
+  if (outer_a
+      && (!SUBREG_P (XEXP (a, 0))
+         || !subreg_lowpart_p (XEXP (a, 0))
+         || GET_MODE (SUBREG_REG (XEXP (a, 0))) != mode
+         || !noce_operand_known_extended_p (XEXP (a, 0), mode,
+                                             GET_CODE (outer_a))))
+    goto fail;
+
   start_sequence ();
 
   if (CONST_INT_P (XEXP (a, 1)))
@@ -3509,6 +3565,14 @@ noce_try_cond_arith (struct noce_if_info *if_info)
       gcc_assert (target);
     }
 
+  if (outer_a)
+    {
+      XEXP (a, 1) = target;
+      noce_emit_move_insn (if_info->x, outer_a);
+      target = if_info->x;
+      goto success;
+    }
+
   /* For AND, try `cond ? z : -1` to see if that is cheaper or the same cost.
      In some cases it will be cheaper to produce the -1 rather than the 0 
case.  */
   if (op == AND)
diff --git a/gcc/testsuite/gcc.target/riscv/pr122769.c 
b/gcc/testsuite/gcc.target/riscv/pr122769.c
index 0f7e19ca504..6e3d0d37e4e 100644
--- a/gcc/testsuite/gcc.target/riscv/pr122769.c
+++ b/gcc/testsuite/gcc.target/riscv/pr122769.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -march=rv64gc_zbs_zicond -mabi=lp64d" { target rv64} } */
+/* { dg-options "-O2 -march=rv64gc_zbs_zicond -mabi=lp64d -mbranch-cost=4" { 
target rv64} } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-Os" "-Oz" "-Og" "-flto" } } 
*/
 
 /* Elide a short forward branch and generate a czero instead.  */
 
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-conditional-add-extend.c 
b/gcc/testsuite/gcc.target/riscv/zicond-conditional-add-extend.c
new file mode 100644
index 00000000000..dd74a40e99a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-conditional-add-extend.c
@@ -0,0 +1,23 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-options "-O2 -march=rv64gc_zicond -mabi=lp64d -mbranch-cost=4" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Os" "-Oz" "-Og" "-funroll-loops" 
} } */
+
+unsigned int
+xz_loop (unsigned int pos, unsigned int cur_match, unsigned int depth,
+        unsigned int cyclic_pos, unsigned int cyclic_size,
+        const unsigned int *son, const unsigned char *cur)
+{
+  unsigned int sum = 0;
+  while (depth-- != 0)
+    {
+      unsigned int delta = pos - cur_match;
+      const unsigned char *pb = cur - delta;
+      cur_match = son[cyclic_pos - delta
+                     + (delta > cyclic_pos ? cyclic_size : 0)];
+      sum += cur_match + pb[0] + cur[0];
+    }
+  return sum;
+}
+
+/* { dg-final { scan-assembler-times {\tczero\.(eqz|nez)\t} 1 } } */
+/* { dg-final { scan-assembler-not {\tbgeu\t} } } */
-- 
2.34.1

Reply via email to