This is an optimization patch that implements extzv for 1-bit extracts. The nice thing is that AVR can do this easily with a BLD/CLR/BST sequence, without putting pressure on d-regs and without the requirement of source being in the same register as destination.
extzv can also be seen in conjunction with zero_extend which, without this patch, will lead to a 16-bit loop just to get one bit from a position with a known offset. So there are two splits to split the high-part away. Tested without regression. Johann PR target/33049 * config/avr/avr.md (extzv): New expander. (*extzv, *extzv.qihi1, *extzv.qihi2): New insn-and-split.
Index: config/avr/avr.md =================================================================== --- config/avr/avr.md (revision 175201) +++ config/avr/avr.md (working copy) @@ -3540,3 +3540,75 @@ (define_insn_and_split "*ior<mode>qi.byt int byteno = INTVAL(operands[2]) / BITS_PER_UNIT; operands[4] = simplify_gen_subreg (QImode, operands[0], <MODE>mode, byteno); }) + +(define_expand "extzv" + [(set (match_operand:QI 0 "register_operand" "") + (zero_extract:QI (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "const1_operand" "") + (match_operand:QI 3 "const_0_to_7_operand" "")))] + "" + "") + +(define_insn_and_split "*extzv" + [(set (match_operand:QI 0 "register_operand" "=*d,*d,*d,r") + (zero_extract:QI (match_operand:QI 1 "register_operand" "0,r,0,r") + (const_int 1) + (match_operand:QI 2 "const_0_to_7_operand" "L,L,P,n")))] + "" + "@ + andi %0,1 + mov %0,%1\;andi %0,1 + lsr %0\;andi %0,1 + bst %1,%2\;clr %0\;bld %0,0" + "reload_completed + && INTVAL (operands[2]) == 4 + && REGNO (operands[0]) == REGNO (operands[1]) + && REGNO (operands[0]) >= 16" + [(set (match_dup 0) + (rotate:QI (match_dup 0) + (const_int 4))) + (set (match_dup 0) + (and:QI (match_dup 0) + (const_int 1)))] + "" + [(set_attr "length" "1,2,2,3") + (set_attr "cc" "set_zn,set_zn,set_zn,clobber")]) + +(define_insn_and_split "*extzv.qihi1" + [(set (match_operand:HI 0 "register_operand" "=*d,*d,*d,r") + (zero_extract:HI (match_operand:QI 1 "register_operand" "0,r,0,r") + (const_int 1) + (match_operand:QI 2 "const_0_to_7_operand" "L,L,P,n")))] + "" + "#" + "" + [(set (match_dup 3) + (zero_extract:QI (match_dup 1) + (const_int 1) + (match_dup 2))) + (set (match_dup 4) + (const_int 0))] + { + operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 0); + operands[4] = simplify_gen_subreg (QImode, operands[0], HImode, 1); + }) + +(define_insn_and_split "*extzv.qihi2" + [(set (match_operand:HI 0 "register_operand" "=*d,*d,*d,r") + (zero_extend:HI + (zero_extract:QI (match_operand:QI 1 "register_operand" "0,r,0,r") + (const_int 1) + (match_operand:QI 2 "const_0_to_7_operand" "L,L,P,n"))))] + "" + "#" + "" + [(set (match_dup 3) + (zero_extract:QI (match_dup 1) + (const_int 1) + (match_dup 2))) + (set (match_dup 4) + (const_int 0))] + { + operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 0); + operands[4] = simplify_gen_subreg (QImode, operands[0], HImode, 1); + })