This patch adds optimization of the following patterns:

   (zero_extend:M (subreg:N (not:O==M (X:Q==M)))) ->
   (xor:M (zero_extend:M (subreg:N (X:M)), 0xffff))
     ... where mask takes 0xffff bits of N mode bitsize

For the cases when X:M doesn't have any non-zero bits outside of mode N,
(zero_extend:M (subreg:N (X:M)) could be simplified to just (X:M)
and whole optimization will be:

   (zero_extend:M (subreg:N (not:M (X:M)))) ->
   (xor:M (X:M, 0xffff))

Patch targets to handle code patterns like:
   not   a0,a0
   andi  a0,a0,0xff
to be optimized to:
   xori    a0,a0,255

Change was locally tested for x86_64 and AArch64 (as most common)
and for RV-64 and MIPS-32 targets (as having an effect from this 
optimization):
no regressions for all cases.

gcc/ChangeLog:
     * simplify-rtx.cc (simplify_context::simplify_unary_operation_1):
     Simplify ZERO_EXTEND (SUBREG (NOT X)) to XOR (X, 0xff...f) when X
     doesn't have any non-zero bits outside of SUBREG mode.

gcc/testsuite/ChangeLog:
     * gcc.target/riscv/pr112398.c: New test.

Signed-off-by: Alexey Merzlyakov <alexey.merzlya...@samsung.com>
---
  gcc/simplify-rtx.cc                       | 23 +++++++++++++++++++++++
  gcc/testsuite/gcc.target/riscv/pr112398.c | 14 ++++++++++++++
  2 files changed, 37 insertions(+)
  create mode 100644 gcc/testsuite/gcc.target/riscv/pr112398.c

diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 2c04ce960ee..608ecedbcb8 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -1842,6 +1842,29 @@ simplify_context::simplify_unary_operation_1 
(rtx_code code, machine_mode mode,
            & ~GET_MODE_MASK (op_mode)) == 0)
      return SUBREG_REG (op);

+      /* Trying to optimize:
+     (zero_extend:M (subreg:N (not:M (X:M)))) ->
+     (xor:M (zero_extend:M (subreg:N (X:M)), 0xffff))
+     where mask takes 0xffff bits of N mode bitsize.
+     For the cases when X:M doesn't have any non-zero bits
+     outside of mode N, (zero_extend:M (subreg:N (X:M))
+     will be simplified to just (X:M)
+     and whole optimization will be -> (xor:M (X:M), 0xffff). */
+      if (GET_CODE (op) == SUBREG
+      && GET_CODE (XEXP (op, 0)) == NOT
+      && GET_MODE (XEXP (op, 0)) == mode
+      && GET_MODE (XEXP (XEXP (op, 0), 0)) == mode
+      && subreg_lowpart_p (op)
+      && (nonzero_bits (XEXP (XEXP (op, 0), 0), mode)
+          & ~GET_MODE_MASK (GET_MODE (XEXP (XEXP (op, 0), 0)))) == 0)
+      {
+    const uint64_t mask
+      = ~((uint64_t)~0 << GET_MODE_BITSIZE (GET_MODE (op)).coeffs[0]);
+    return simplify_gen_binary (XOR, mode,
+                    XEXP (XEXP (op, 0), 0),
+                    gen_int_mode (mask, mode));
+      }
+
  #if defined(POINTERS_EXTEND_UNSIGNED)
        /* As we do not know which address space the pointer is 
referring to,
       we can do this only if the target does not support different pointer
diff --git a/gcc/testsuite/gcc.target/riscv/pr112398.c 
b/gcc/testsuite/gcc.target/riscv/pr112398.c
new file mode 100644
index 00000000000..624a665b76c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr112398.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+#include <stdint.h>
+
+uint8_t neg_u8 (const uint8_t src)
+{
+  return ~src;
+}
+
+/* { dg-final { scan-assembler-times "xori\t" 1 } } */
+/* { dg-final { scan-assembler-not "not\t" } } */
+/* { dg-final { scan-assembler-not "andi\t" } } */
-- 
2.34.1


Reply via email to