From a499ab08d18eff4ca9c079cafaee0708d2bcbf20 Mon Sep 17 00:00:00 2001 From: Georg-Johann Lay Date: Thu, 25 May 2023 19:02:34 +0200 Subject: [PATCH] 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.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. --- gcc/config/avr/avr.cc | 9 ++++++++ gcc/config/avr/avr.md | 24 ++++++++++++--------- gcc/testsuite/gcc.target/avr/pr82931.c | 29 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gcc.target/avr/pr82931.c diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 5410c194953..eff2ca78566 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -10844,6 +10844,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 5ca3b51dd56..0153976ec37 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -9097,16 +9097,20 @@ "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.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) + == (GET_MODE_MASK(mode) & (INTVAL(operands[2]) ^ INTVAL(operands[4])))" + { + auto bitmask = GET_MODE_MASK (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; +}