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 ;-)

Jeff
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.

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index b39b858acac..d8c8f6b5079 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 0b10842d176..c7b010d6220 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -14464,6 +14464,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 154b49d55c5..209d9be96a8 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -1724,26 +1724,11 @@ (define_insn "smax<mode>3"
 (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