[avr,committed] PR82931: Improve single-bit transfers between registers.

Message ID 943d7018-5b82-00d3-8451-93f830049cb7@gjlay.de
State New
Headers
Series [avr,committed] PR82931: Improve single-bit transfers between registers. |

Commit Message

Georg-Johann Lay May 25, 2023, 5:09 p.m. UTC
  Applied this patch that makes one insn more generic so it can handle
more bit positions than just 0.

Johann

--

target/82931: Make a pattern more generic to match more bit-transfers.

There is already a pattern in avr.md that matches single-bit transfers
from one register to another one, but it only handled bit 0 of 8-bit
registers.  This change makes that pattern more generic so it matches
more of similar single-bit transfers.

gcc/
	PR target/82931
	* config/avr/avr.md (*movbitqi.0): Rename to *movbit<mode>.0-6.
	Handle any bit position and use mode QISI.
	* config/avr/avr.cc (avr_rtx_costs_1) [IOR]: Return a cost
	of 2 insns for bit-transfer of respective style.

gcc/testsuite/
	PR target/82931
	* gcc.target/avr/pr82931.c: New test.
  

Patch

diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 4fa6f5309b2..31706964eb1 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -10843,6 +10843,15 @@  avr_rtx_costs_1 (rtx x, machine_mode mode, int 
outer_code,
              *total += COSTS_N_INSNS (1);
            return true;
          }
+      if (IOR == code
+          && AND == GET_CODE (XEXP (x, 0))
+          && AND == GET_CODE (XEXP (x, 1))
+          && single_zero_operand (XEXP (XEXP (x, 0), 1), mode))
+        {
+          // Open-coded bit transfer.
+          *total = COSTS_N_INSNS (2);
+          return true;
+        }
        *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
        *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, 0, speed);
        if (!CONST_INT_P (XEXP (x, 1)))
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index a79c6824fad..371965938a6 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -9096,16 +9096,20 @@  (define_insn "*movbitqi.1-6.b"
    "bst %3,0\;bld %0,%4"
    [(set_attr "length" "2")])

-;; Move bit $3.0 into bit $0.0.
-;; For bit 0, combiner generates slightly different pattern.
-(define_insn "*movbitqi.0"
-  [(set (match_operand:QI 0 "register_operand"                     "=r")
-        (ior:QI (and:QI (match_operand:QI 1 "register_operand"      "0")
-                        (match_operand:QI 2 "single_zero_operand"   "n"))
-                (and:QI (match_operand:QI 3 "register_operand"      "r")
-                        (const_int 1))))]
-  "0 == exact_log2 (~INTVAL(operands[2]) & GET_MODE_MASK (QImode))"
-  "bst %3,0\;bld %0,0"
+;; Move bit $3.x into bit $0.x.
+(define_insn "*movbit<mode>.0-6"
+  [(set (match_operand:QISI 0 "register_operand" 
"=r")
+        (ior:QISI (and:QISI (match_operand:QISI 1 "register_operand" 
"0")
+                            (match_operand:QISI 2 "single_zero_operand" 
"n"))
+                  (and:QISI (match_operand:QISI 3 "register_operand" 
"r")
+                            (match_operand:QISI 4 "single_one_operand" 
"n"))))]
+  "GET_MODE_MASK(<MODE>mode)
+   == (GET_MODE_MASK(<MODE>mode) & (INTVAL(operands[2]) ^ 
INTVAL(operands[4])))"
+  {
+    auto bitmask = GET_MODE_MASK (<MODE>mode) & UINTVAL (operands[4]);
+    operands[4] = GEN_INT (exact_log2 (bitmask));
+    return "bst %T3%T4" CR_TAB "bld %T0%T4";
+  }
    [(set_attr "length" "2")])

  ;; Move bit $2.0 into bit $0.7.
diff --git a/gcc/testsuite/gcc.target/avr/pr82931.c 
b/gcc/testsuite/gcc.target/avr/pr82931.c
new file mode 100644
index 00000000000..477284fa127
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr82931.c
@@ -0,0 +1,29 @@ 
+/* { dg-options "-Os" } */
+/* { dg-final { scan-assembler-times "bst" 4 } } */
+/* { dg-final { scan-assembler-times "bld" 4 } } */
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __UINT16_TYPE__ uint16_t;
+
+#define BitMask (1u << 14)
+#define Bit8Mask ((uint8_t) (1u << 4))
+
+void merge1_8 (uint8_t *dst, const uint8_t *src)
+{
+    *dst = (*src & Bit8Mask) | (*dst & ~ Bit8Mask);
+}
+
+void merge2_8 (uint8_t *dst, const uint8_t *src)
+{
+    *dst ^= (*dst ^ *src) & Bit8Mask;
+}
+
+void merge1_16 (uint16_t *dst, const uint16_t *src)
+{
+    *dst = (*src & BitMask) | (*dst & ~ BitMask);
+}
+
+void merge2_16 (uint16_t *dst, const uint16_t *src)
+{
+    *dst ^= (*dst ^ *src) & BitMask;
+}