Created attachment 42574 [details] Minimum complete verifying example The attached example produces optimal code for the AVR-target: it uses the bst/bld assembler instructions. But this is only true for bit 0 (least significant) in an uint8_t type. If the same instruction sequence is used to transfer bit 1...7 less optimal code is generated. This is unlogical to some respect since the backend recognizes the special case for bit 0, so it should be possible to use the very same optimization for other bits. The same holds true if one used another datatype such as uint16_t and greater. No optimization takes place.
Should compile with -Os to reproduce the result.
Created attachment 42575 [details] Minimum complete verifying example
Created attachment 43134 [details] Valid C++ test case Confirmed for current trunk and the attached test case with $ avr-g++ pr82931.cc -Os -mmcu=avr4 -fdump-rtl-combine-details && cat pr82931.cc.265r.combine The patterns are just getting too complicated due to the involved MEMs: Failed to match this instruction: (set (zero_extract:QI (mem:QI (reg/v/f:HI 50 [ dst ]) [0 *dst_11(D)+0 S1 A8]) (const_int 1 [0x1]) (const_int 4 [0x4])) (lshiftrt:QI (reg:QI 52) (const_int 4 [0x4]))) Note that the avr BE provides zero_extract, but not with MEM operands: ;; Insert bit $2.$3 into $0.$1 (define_insn "*insv.shiftrt" [(set (zero_extract:QI (match_operand:QI 0 "register_operand" "+r") (const_int 1) (match_operand:QI 1 "const_0_to_7_operand" "n")) (any_shiftrt:QI (match_operand:QI 2 "register_operand" "r") (match_operand:QI 3 "const_0_to_7_operand" "n")))] "" "bst %2,%3\;bld %0,%1" ... Adding versions with MEM operand would explode the BEs complexity, and such patches are usually rejected because of that. Instead, insn combiner should try versions that use the MEMs as a split point and try REGs instead.
As lined out in comment #3, this is a middle-end flaw in insn combine: For merge1 it should use MEM as split-points. For merge2 it doesn't even recognize that the expression is a bit-insertion.
The master branch has been updated by Georg-Johann Lay <gjl@gcc.gnu.org>: https://gcc.gnu.org/g:ff0a6900700636ac4c7f40b88490a20d19a68db3 commit r14-1244-gff0a6900700636ac4c7f40b88490a20d19a68db3 Author: Georg-Johann Lay <avr@gjlay.de> Date: Thu May 25 19:02:34 2023 +0200 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.
The releases/gcc-13 branch has been updated by Georg-Johann Lay <gjl@gcc.gnu.org>: https://gcc.gnu.org/g:a499ab08d18eff4ca9c079cafaee0708d2bcbf20 commit r13-7377-ga499ab08d18eff4ca9c079cafaee0708d2bcbf20 Author: Georg-Johann Lay <avr@gjlay.de> Date: Thu May 25 19:02:34 2023 +0200 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.
The releases/gcc-12 branch has been updated by Georg-Johann Lay <gjl@gcc.gnu.org>: https://gcc.gnu.org/g:4d39f68b891ed2ac7aca5ef24119f50976b84c22 commit r12-9654-g4d39f68b891ed2ac7aca5ef24119f50976b84c22 Author: Georg-Johann Lay <avr@gjlay.de> Date: Thu May 25 19:02:34 2023 +0200 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.
Should work in v12.4 and v13.2+.