https://gcc.gnu.org/g:874f4c164749f1ed5b60ddf1d4533c8f4ba627a1

commit r16-40-g874f4c164749f1ed5b60ddf1d4533c8f4ba627a1
Author: Jeff Law <j...@ventanamicro.com>
Date:   Sat Apr 19 12:30:42 2025 -0600

    [RISC-V][PR target/118410] Improve code generation for some logical ops
    
    I'm posting this on behalf of Shreya Munnangi who is working as an intern 
with
    me.  I've got her digging into prerequisites for removing mvconst_internal 
and
    would prefer she focus on that rather than our patch process at this time.
    
    --
    
    We can use the orn, xnor, andn instructions on RISC-V to improve the code
    generated logical operations when one operand is a constant C where
    synthesizing ~C is cheaper than synthesizing C.
    
    This is going to be an N -> N - 1 splitter rather than a 
define_insn_and_split.
    A define_insn_and_split can obviously work, but has multiple undesirable
    effects in general.
    
    As a result of implementing as a simple define_split we're not supporting 
AND
    at this time.  We need to clean up the mvconst_internal situation first 
after
    which supporting AND is trivial.
    
    This has been tested in Ventana's CI system as well as my tester. Obviously
    we'll wait for the pre-commit tester to run before moving forward.
    
            PR target/118410
    gcc/
            * config/riscv/bitmanip.md (logical with constant argument): New
            splitter for cases where synthesizing ~C is cheaper than 
synthesizing
            the original constant C.
    
    gcc/testsuite/
            * gcc.target/riscv/pr118410-1.c: New test.
            * gcc.target/riscv/pr118410-2.c: Likewise.
    
                Co-authored-by: Jeff Law  <j...@ventanamicro.com>

Diff:
---
 gcc/config/riscv/bitmanip.md                | 38 +++++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/pr118410-1.c |  9 +++++++
 gcc/testsuite/gcc.target/riscv/pr118410-2.c |  9 +++++++
 3 files changed, 56 insertions(+)

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 2a3884cfde01..d0919ece31f7 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -1263,3 +1263,41 @@
   expand_crc_using_clmul (<SUBX:MODE>mode, <SUBX1:MODE>mode, operands);
   DONE;
 })
+
+;; If we have an XOR/IOR with a constant operand (C) and the we can
+;; synthesize ~C more efficiently than C, then synthesize ~C and use
+;; xnor/orn instead.
+;;
+;; The same can be done for AND, but mvconst_internal's issues get in
+;; the way.  That's future work.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (any_or:X (match_operand:X 1 "register_operand")
+                 (match_operand:X 2 "const_int_operand")))
+   (clobber (match_operand:X 3 "register_operand"))]
+  "TARGET_ZBB
+   && (riscv_const_insns (operands[2], true)
+       > riscv_const_insns (GEN_INT (~INTVAL (operands[2])), true))"
+  [(const_int 0)]
+{
+  /* Get the inverted constant into the temporary register.  */
+  riscv_emit_move (operands[3], GEN_INT (~INTVAL (operands[2])));
+
+  /* For xnor, the NOT operation is in a different position.  So
+     we have to customize the split code we generate a bit.
+
+     It is expected that AND will be handled like IOR in the future.  */
+  if (<CODE> == XOR)
+    {
+      rtx x = gen_rtx_XOR (<X:MODE>mode, operands[1], operands[3]);
+      x = gen_rtx_NOT (<X:MODE>mode, x);
+      emit_insn (gen_rtx_SET (operands[0], x));
+    }
+  else
+    {
+      rtx x = gen_rtx_NOT (<X:MODE>mode, operands[3]);
+      x = gen_rtx_IOR (<X:MODE>mode, x, operands[1]);
+      emit_insn (gen_rtx_SET (operands[0], x));
+    }
+  DONE;
+})
diff --git a/gcc/testsuite/gcc.target/riscv/pr118410-1.c 
b/gcc/testsuite/gcc.target/riscv/pr118410-1.c
new file mode 100644
index 000000000000..4a8b847d4f4c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr118410-1.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+/* { dg-options "-march=rv64gcb -mabi=lp64d" { target { rv64} } } */
+/* { dg-options "-march=rv32gcb -mabi=ilp32" { target { rv32} } } */
+
+long orlow(long x) { return x | ((1L << 24) - 1); }
+
+/* { dg-final { scan-assembler-times "orn\t" 1 } } */
+/* { dg-final { scan-assembler-not "addi\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/pr118410-2.c 
b/gcc/testsuite/gcc.target/riscv/pr118410-2.c
new file mode 100644
index 000000000000..b63a1d9c4659
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr118410-2.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+/* { dg-options "-march=rv64gcb -mabi=lp64d" { target { rv64} } } */
+/* { dg-options "-march=rv32gcb -mabi=ilp32" { target { rv32} } } */
+
+long xorlow(long x) { return x ^ ((1L << 24) - 1); }
+
+/* { dg-final { scan-assembler-times "xnor\t" 1 } } */
+/* { dg-final { scan-assembler-not "addi\t" } } */

Reply via email to