https://gcc.gnu.org/g:4787ad29a5421b607e535beb749ad3344748c477

commit 4787ad29a5421b607e535beb749ad3344748c477
Author: Shreya Munnangi <smunnan...@ventanamicro.com>
Date:   Tue May 20 20:15:42 2025 -0600

    [RISC-V] Infrastructure of synthesizing logical AND with constant
    
    So this is the next step on the path to mvconst_internal removal and is work
    from Shreya and myself.
    
    This puts in the infrastructure to allow us to synthesize logical AND much 
like
    we're doing with logical IOR/XOR.
    
    Unlike IOR/XOR, AND has many more special cases that can be profitable. For
    example, you can use shifts to clear many bits.  You can use zero extension 
to
    clear bits, you can use rotate+andi+rotate, shift pairs, etc.
    
    So to make potential bisecting easy the plan is to drop in the work on 
logical
    AND in several steps, essentially one new case at a time.
    
    This step just puts the basics of a operation synthesis in place.  It still
    uses the same code generation strategies as we are currently using.
    
    I'd like to say this is NFC, but unfortunately that's not true.  While the 
code
    generation strategy is the same, this does indirectly introduce new 
REG_EQUAL
    notes.  Those additional notes in turn can impact how various optimizers 
behave
    in very minor ways.
    
    As usual, this has survived my tester on riscv32-elf and riscv64-elf.
    
    Waiting on pre-commit to do its thing.  And I'll start queuing up the
    additional cases we want to handle while waiting 😉
    
    gcc/
            * config/riscv/riscv-protos.h (synthesize_and): Prototype.
            * config/riscv/riscv.cc (synthesize_and): New function.
            * config/riscv/riscv.md (and<mode>3): Use it.
    
                Co-Authored-By: Jeff Law  <j...@ventanamicro.com>
    
    (cherry picked from commit 5568277c005f5edda0ce444e11abd1d5845d6ee7)

Diff:
---
 gcc/config/riscv/riscv-protos.h |  1 +
 gcc/config/riscv/riscv.cc       | 64 +++++++++++++++++++++++++++++++++++++----
 gcc/config/riscv/riscv.md       | 21 ++------------
 3 files changed, 63 insertions(+), 23 deletions(-)

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index b39b858acac8..d8c8f6b5079f 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -141,6 +141,7 @@ extern void riscv_expand_ustrunc (rtx, rtx);
 extern void riscv_expand_sstrunc (rtx, rtx);
 extern int riscv_register_move_cost (machine_mode, reg_class_t, reg_class_t);
 extern bool synthesize_ior_xor (rtx_code, rtx [3]);
+extern bool synthesize_and (rtx [3]);
 
 #ifdef RTX_CODE
 extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx, bool 
*invert_ptr = 0);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 4c5bb02754df..1a88e96d8c6f 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -14300,7 +14300,7 @@ synthesize_ior_xor (rtx_code code, rtx operands[3])
      we clear bits in IVAL.  Once IVAL is zero, then synthesis of the
      operation is complete.  */
   unsigned HOST_WIDE_INT ival = INTVAL (operands[2]);
-  
+
   /* Check if we want to use [x]ori. Then get the remaining bits
      and decrease the budget by one. */
   if ((ival & HOST_WIDE_INT_UC (0x7ff)) != 0)
@@ -14435,14 +14435,14 @@ synthesize_ior_xor (rtx_code code, rtx operands[3])
        }
     }
 
-  /* If after accounting for bseti the remaining budget has 
+  /* If after accounting for bseti the remaining budget has
      gone to less than zero, it forces the value into a
      register and performs the IOR operation.  It returns
      TRUE to the caller so the caller knows code generation
      is complete. */
   if (budget < 0)
     {
-      rtx x = force_reg (word_mode, operands[2]); 
+      rtx x = force_reg (word_mode, operands[2]);
       x = gen_rtx_fmt_ee (code, word_mode, operands[1], x);
       emit_insn (gen_rtx_SET (operands[0], x));
       return true;
@@ -14466,8 +14466,8 @@ synthesize_ior_xor (rtx_code code, rtx operands[3])
     }
 
   /* We figure out a single bit as a constant and
-     generate a CONST_INT node for that.  Then we 
-     construct the IOR node, then the SET node and 
+     generate a CONST_INT node for that.  Then we
+     construct the IOR node, then the SET node and
      emit it.  An IOR with a suitable constant that is
      a single bit will be implemented with a bseti. */
   while (ival)
@@ -14486,6 +14486,60 @@ synthesize_ior_xor (rtx_code code, rtx operands[3])
   return true;
 }
 
+/* Synthesize OPERANDS[0] = OPERANDS[1] & OPERANDS[2].
+
+    OPERANDS[0] and OPERANDS[1] will be a REG and may be the same
+    REG.
+
+    OPERANDS[2] is a CONST_INT.
+
+    Return TRUE if the operation was fully synthesized and the caller
+    need not generate additional code.  Return FALSE if the operation
+    was not synthesized and the caller is responsible for emitting the
+    proper sequence.  */
+
+bool
+synthesize_and (rtx operands[3])
+{
+  /* Trivial cases that don't need synthesis.  */
+  if (SMALL_OPERAND (INTVAL (operands[2]))
+     || (TARGET_ZBS && not_single_bit_mask_operand (operands[2], word_mode)))
+    return false;
+
+  /* If the second operand is a mode mask, emit an extension
+     insn instead.  */
+  if (CONST_INT_P (operands[2]))
+    {
+      enum machine_mode tmode = VOIDmode;
+      if (UINTVAL (operands[2]) == GET_MODE_MASK (HImode))
+       tmode = HImode;
+      else if (UINTVAL (operands[2]) == GET_MODE_MASK (SImode))
+       tmode = SImode;
+
+      if (tmode != VOIDmode)
+       {
+         rtx tmp = gen_lowpart (tmode, operands[1]);
+         emit_insn (gen_extend_insn (operands[0], tmp, word_mode, tmode, 1));
+         return true;
+       }
+    }
+
+  /* If the remaining budget has gone to less than zero, it
+     forces the value into a register and performs the AND
+     operation.  It returns TRUE to the caller so the caller
+     knows code generation is complete.
+     FIXME: This is hacked to always be enabled until the last
+     patch in the series is enabled.  */
+  if (1)
+    {
+      rtx x = force_reg (word_mode, operands[2]);
+      x = gen_rtx_AND (word_mode, operands[1], x);
+      emit_insn (gen_rtx_SET (operands[0], x));
+      return true;
+    }
+}
+
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 1a56cc858098..7f6d0bbab3eb 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -1724,26 +1724,11 @@
 (define_expand "and<mode>3"
   [(set (match_operand:X                0 "register_operand")
         (and:X (match_operand:X 1 "register_operand")
-              (match_operand:X 2 "arith_or_mode_mask_or_zbs_operand")))]
+              (match_operand:X 2 "reg_or_const_int_operand")))]
   ""
 {
-  /* If the second operand is a mode mask, emit an extension
-     insn instead.  */
-  if (CONST_INT_P (operands[2]))
-    {
-      enum machine_mode tmode = VOIDmode;
-      if (UINTVAL (operands[2]) == GET_MODE_MASK (HImode))
-       tmode = HImode;
-      else if (UINTVAL (operands[2]) == GET_MODE_MASK (SImode))
-       tmode = SImode;
-
-      if (tmode != VOIDmode)
-       {
-         rtx tmp = gen_lowpart (tmode, operands[1]);
-         emit_insn (gen_extend_insn (operands[0], tmp, <MODE>mode, tmode, 1));
-         DONE;
-       }
-    }
+  if (CONST_INT_P (operands[2]) && synthesize_and (operands))
+    DONE;
 })
 
 (define_insn "*and<mode>3"

Reply via email to