http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02186.html
Richard Henderson wrote: > On 07/25/2011 10:30 AM, Georg-Johann Lay wrote: >> PR target/29560 >> * config/avr/avr.md: Add peephole2 to map ashlhi3 to ashlqi3 if >> high part of shift target is unused. > > Ok. > > r~ Here is a more complete version that transforms earlier and increases the number of cases covered. Moreover, the original peep2 is not fully correct because it maps a 16-bit shift to a 8-bit one. The correct mapping is (set (match_dup 2) (subreg:QI (ashift:HI (zero_extend:HI (match_dup 2)) (match_dup 1)) 0)) instead of (set (match_dup 2) (ashift:QI (match_dup 2) (match_dup 1))) I don't think it makes a difference that late in the compilation process, yet I prefer correct semantics. The new iterators are already seen in the widening multiply patch. Ok? Johann PR target/29560 * config/avr/avr.md (any_extend): New code interator. (extend_prefix): New code attribute. (*ashl<extend_prefix>qihiqi3): New insns. (*ashl<extend_prefix>qihiqi3.mem): New insn-and-splits. (*ashlhiqi3): New insn-and-split. Add peephole2 to map ashlhi3 to ashlqi3 if high part of shift target is unused.
Index: config/avr/avr.md =================================================================== --- config/avr/avr.md (revision 176624) +++ config/avr/avr.md (working copy) @@ -132,6 +132,15 @@ (define_mode_iterator QIDI [(QI "") (HI (define_mode_iterator HIDI [(HI "") (SI "") (DI "")]) (define_mode_iterator HISI [(HI "") (SI "")]) +;; Define code iterators +(define_code_iterator any_extend [sign_extend zero_extend]) + +;; Define code attributes +(define_code_attr extend_prefix + [(sign_extend "s") + (zero_extend "u")]) + + ;;======================================================================== ;; The following is used by nonlocal_goto and setjmp. ;; The receiver pattern will create no instructions since internally @@ -1993,6 +2002,89 @@ (define_insn "ashlhi3" [(set_attr "length" "6,0,2,2,4,10,10") (set_attr "cc" "clobber,none,set_n,clobber,set_n,clobber,clobber")]) + +;; Insn like the following are generated when (implicitly) extending 8-bit shifts +;; like char1 = char2 << char3. Only the low-byte is needed in that situation. +;; The output is the same as of *ashlqi3. Don't, however, map this to *ashlqi3 +;; to preserve the semantics of ashift:HI which is different to ashift:QI. + +;; "*ashluqihiqi3" +;; "*ashlsqihiqi3" +(define_insn "*ashl<extend_prefix>qihiqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (subreg:QI (ashift:HI (any_extend:HI (match_operand:QI 1 "register_operand" "0")) + (match_operand:QI 2 "register_operand" "r")) + 0))] + "" + { + return ashlqi3_out (insn, operands, NULL); + } + [(set_attr "length" "5") + (set_attr "cc" "clobber")]) + +;; Map to above. + +;; "*ashluqihiqi3.mem" +;; "*ashlsqihiqi3.mem" +(define_insn_and_split "*ashl<extend_prefix>qihiqi3.mem" + [(set (match_operand:QI 0 "memory_operand" "=m") + (subreg:QI (ashift:HI (any_extend:HI (match_operand:QI 1 "register_operand" "r")) + (match_operand:QI 2 "register_operand" "r")) + 0))] + "!reload_completed" + { gcc_unreachable(); } + "&& 1" + [(set (match_dup 3) + (subreg:QI (ashift:HI (any_extend:HI (match_dup 1)) + (match_dup 2)) 0)) + (set (match_dup 0) + (match_dup 3))] + { + operands[3] = force_reg (QImode, operands[0]); + }) + +;; Ditto. + +(define_insn_and_split "*ashlhiqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r") + (subreg:QI (ashift:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" "r")) 0))] + "!reload_completed" + { gcc_unreachable(); } + "&& 1" + [(set (match_dup 4) + (subreg:QI (ashift:HI (zero_extend:HI (match_dup 3)) + (match_dup 2)) 0)) + (set (match_dup 0) + (match_dup 4))] + { + operands[3] = simplify_gen_subreg (QImode, operands[1], HImode, 0); + operands[4] = force_reg (QImode, operands[0]); + }) + +;; High part of 16-bit shift is unused after the instruction: +;; No need to compute it, map to 8-bit shift. + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (ashift:HI (match_dup 0) + (match_operand:QI 1 "register_operand" "")))] + "" + [(set (match_dup 2) + (subreg:QI (ashift:HI (zero_extend:HI (match_dup 2)) + (match_dup 1)) + 0)) + (clobber (match_dup 3))] + { + operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 1); + + if (!peep2_reg_dead_p (1, operands[3])) + FAIL; + + operands[2] = simplify_gen_subreg (QImode, operands[0], HImode, 0); + }) + + (define_insn "ashlsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") (ashift:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")