diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2011-10-19 14:59:00 +0000 |
---|---|---|
committer | Georg-Johann Lay <gjl@gcc.gnu.org> | 2011-10-19 14:59:00 +0000 |
commit | 2f47b8d3be24beae7974234c972aaae5612aae4e (patch) | |
tree | 7616f34c079ed92da41678645c99eca03752a6aa /gcc | |
parent | dd46054a5f6243d441fc1564de173a858ea4e3d4 (diff) | |
download | gcc-2f47b8d3be24beae7974234c972aaae5612aae4e.zip gcc-2f47b8d3be24beae7974234c972aaae5612aae4e.tar.gz gcc-2f47b8d3be24beae7974234c972aaae5612aae4e.tar.bz2 |
re PR target/50447 ([avr] Better support of AND, OR, XOR and PLUS with constant integers for 16- and 32-bit values)
PR target/50447
* config/avr/avr.md (cc): New alternative out_plus_noclobber.
(adjust_len): Ditto.
(addhi3): Don't pipe through short; use gen_int_mode instead.
Prior to reload, expand to gen_addhi3_clobber.
(*addhi3): Use avr_out_plus_noclobber if applicable, use
out_plus_noclobber in cc and adjust_len attribute.
(addhi3_clobber): 2 new RTL peepholes.
(addhi3_clobber): New insn.
* config/avr/avr-protos.h: (avr_out_plus_noclobber): New prototype.
* config/avr/avr.c (avr_out_plus_noclobber): New function.
(notice_update_cc): Handle CC_OUT_PLUS_NOCLOBBER.
(avr_out_plus_1): Tweak if only MSB is +/-1 and other bytes are 0.
Set cc0 to set_zn for adiw on 16-bit values.
(adjust_insn_length): Handle ADJUST_LEN_OUT_PLUS_NOCLOBBER.
(expand_epilogue): No need to add 0 to frame_pointer_rtx.
From-SVN: r180193
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/config/avr/avr-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/avr/avr.c | 46 | ||||
-rw-r--r-- | gcc/config/avr/avr.md | 120 |
4 files changed, 152 insertions, 34 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e9b48b6..c77d7e8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2011-10-19 Georg-Johann Lay <avr@gjlay.de> + + PR target/50447 + * config/avr/avr.md (cc): New alternative out_plus_noclobber. + (adjust_len): Ditto. + (addhi3): Don't pipe through short; use gen_int_mode instead. + Prior to reload, expand to gen_addhi3_clobber. + (*addhi3): Use avr_out_plus_noclobber if applicable, use + out_plus_noclobber in cc and adjust_len attribute. + (addhi3_clobber): 2 new RTL peepholes. + (addhi3_clobber): New insn. + * config/avr/avr-protos.h: (avr_out_plus_noclobber): New prototype. + * config/avr/avr.c (avr_out_plus_noclobber): New function. + (notice_update_cc): Handle CC_OUT_PLUS_NOCLOBBER. + (avr_out_plus_1): Tweak if only MSB is +/-1 and other bytes are 0. + Set cc0 to set_zn for adiw on 16-bit values. + (adjust_insn_length): Handle ADJUST_LEN_OUT_PLUS_NOCLOBBER. + (expand_epilogue): No need to add 0 to frame_pointer_rtx. + 2011-10-19 Richard Guenther <rguenther@suse.de> PR middle-end/50780 diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index a799fb2..dd8ba3a 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -83,6 +83,7 @@ extern void avr_output_addr_vec_elt (FILE *stream, int value); extern const char *avr_out_sbxx_branch (rtx insn, rtx operands[]); extern const char* avr_out_bitop (rtx, rtx*, int*); extern const char* avr_out_plus (rtx*, int*, int*); +extern const char* avr_out_plus_noclobber (rtx*, int*, int*); extern const char* avr_out_addto_sp (rtx*, int*); extern bool avr_popcount_each_byte (rtx, int, int); diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index c0ce6f9ac..94bc30a 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -1051,9 +1051,10 @@ expand_epilogue (bool sibcall_p) if (frame_pointer_needed) { /* Get rid of frame. */ - emit_move_insn(frame_pointer_rtx, - gen_rtx_PLUS (HImode, frame_pointer_rtx, - gen_int_mode (size, HImode))); + if (size) + emit_move_insn (frame_pointer_rtx, + gen_rtx_PLUS (HImode, frame_pointer_rtx, + gen_int_mode (size, HImode))); } else { @@ -1682,14 +1683,19 @@ notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn) break; case CC_OUT_PLUS: + case CC_OUT_PLUS_NOCLOBBER: { rtx *op = recog_data.operand; int len_dummy, icc; /* Extract insn's operands. */ extract_constrain_insn_cached (insn); + + if (CC_OUT_PLUS == cc) + avr_out_plus (op, &len_dummy, &icc); + else + avr_out_plus_noclobber (op, &len_dummy, &icc); - avr_out_plus (op, &len_dummy, &icc); cc = (enum attr_cc) icc; break; @@ -4773,7 +4779,8 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc) /* Value to add. There are two ways to add VAL: R += VAL and R -= -VAL. */ rtx xval = xop[2]; - /* Addition does not set cc0 in a usable way. */ + /* Except in the case of ADIW with 16-bit register (see below) + addition does not set cc0 in a usable way. */ *pcc = (MINUS == code) ? CC_SET_CZN : CC_CLOBBER; @@ -4821,6 +4828,9 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc) started = true; avr_asm_len (code == PLUS ? "adiw %0,%1" : "sbiw %0,%1", op, plen, 1); + + if (n_bytes == 2 && PLUS == code) + *pcc = CC_SET_ZN; } i++; @@ -4836,6 +4846,14 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc) op, plen, 1); continue; } + else if ((val8 == 1 || val8 == 0xff) + && !started + && i == n_bytes - 1) + { + avr_asm_len ((code == PLUS) ^ (val8 == 1) ? "dec %0" : "inc %0", + op, plen, 1); + break; + } switch (code) { @@ -4924,6 +4942,22 @@ avr_out_plus (rtx *xop, int *plen, int *pcc) } +/* Same as above but XOP has just 3 entries. + Supply a dummy 4th operand. */ + +const char* +avr_out_plus_noclobber (rtx *xop, int *plen, int *pcc) +{ + rtx op[4]; + + op[0] = xop[0]; + op[1] = xop[1]; + op[2] = xop[2]; + op[3] = NULL_RTX; + + return avr_out_plus (op, plen, pcc); +} + /* Output bit operation (IOR, AND, XOR) with register XOP[0] and compile time constant XOP[2]: @@ -5308,6 +5342,8 @@ adjust_insn_length (rtx insn, int len) case ADJUST_LEN_OUT_BITOP: avr_out_bitop (insn, op, &len); break; case ADJUST_LEN_OUT_PLUS: avr_out_plus (op, &len, NULL); break; + case ADJUST_LEN_OUT_PLUS_NOCLOBBER: + avr_out_plus_noclobber (op, &len, NULL); break; case ADJUST_LEN_ADDTO_SP: avr_out_addto_sp (op, &len); break; diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index aafdc55..35d4bdc 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -78,7 +78,7 @@ ;; Condition code settings. (define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber, - out_plus" + out_plus, out_plus_noclobber" (const_string "none")) (define_attr "type" "branch,branch1,arith,xcall" @@ -125,7 +125,8 @@ ;; Otherwise do special processing depending on the attribute. (define_attr "adjust_len" - "out_bitop, out_plus, addto_sp, tsthi, tstsi, compare, call, + "out_bitop, out_plus, out_plus_noclobber, addto_sp, + tsthi, tstsi, compare, call, mov8, mov16, mov32, reload_in16, reload_in32, ashlqi, ashrqi, lshrqi, ashlhi, ashrhi, lshrhi, @@ -759,14 +760,22 @@ (plus:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "nonmemory_operand" "")))] "" - " -{ - if (GET_CODE (operands[2]) == CONST_INT) - { - short tmp = INTVAL (operands[2]); - operands[2] = GEN_INT(tmp); - } -}") + { + if (CONST_INT_P (operands[2])) + { + operands[2] = gen_int_mode (INTVAL (operands[2]), HImode); + + if (can_create_pseudo_p() + && !stack_register_operand (operands[0], HImode) + && !stack_register_operand (operands[1], HImode) + && !d_register_operand (operands[0], HImode) + && !d_register_operand (operands[1], HImode)) + { + emit_insn (gen_addhi3_clobber (operands[0], operands[1], operands[2])); + DONE; + } + } + }) (define_insn "*addhi3_zero_extend" @@ -803,20 +812,77 @@ (set_attr "adjust_len" "addto_sp")]) (define_insn "*addhi3" - [(set (match_operand:HI 0 "register_operand" "=r,!w,!w,d,r,r") - (plus:HI - (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0") - (match_operand:HI 2 "nonmemory_operand" "r,I,J,i,P,N")))] + [(set (match_operand:HI 0 "register_operand" "=r,d,d") + (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0") + (match_operand:HI 2 "nonmemory_operand" "r,s,n")))] "" - "@ - add %A0,%A2\;adc %B0,%B2 - adiw %A0,%2 - sbiw %A0,%n2 - subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2)) - sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__ - sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__" - [(set_attr "length" "2,1,1,2,3,3") - (set_attr "cc" "set_n,set_czn,set_czn,set_czn,set_n,set_n")]) + { + static const char * const asm_code[] = + { + "add %A0,%A2\;adc %B0,%B2", + "subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))", + "" + }; + + if (*asm_code[which_alternative]) + return asm_code[which_alternative]; + + return avr_out_plus_noclobber (operands, NULL, NULL); + } + [(set_attr "length" "2,2,2") + (set_attr "adjust_len" "*,*,out_plus_noclobber") + (set_attr "cc" "set_n,set_czn,out_plus_noclobber")]) + +;; Adding a constant to NO_LD_REGS might have lead to a reload of +;; that constant to LD_REGS. We don't add a scratch to *addhi3 +;; itself because that insn is special to reload. + +(define_peephole2 ; addhi3_clobber + [(set (match_operand:HI 0 "d_register_operand" "") + (match_operand:HI 1 "const_int_operand" "")) + (set (match_operand:HI 2 "l_register_operand" "") + (plus:HI (match_dup 2) + (match_dup 0)))] + "peep2_reg_dead_p (2, operands[0])" + [(parallel [(set (match_dup 2) + (plus:HI (match_dup 2) + (match_dup 1))) + (clobber (match_dup 3))])] + { + operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 0); + }) + +;; Same, but with reload to NO_LD_REGS +;; Combine *reload_inhi with *addhi3 + +(define_peephole2 ; addhi3_clobber + [(parallel [(set (match_operand:HI 0 "l_register_operand" "") + (match_operand:HI 1 "const_int_operand" "")) + (clobber (match_operand:QI 2 "d_register_operand" ""))]) + (set (match_operand:HI 3 "l_register_operand" "") + (plus:HI (match_dup 3) + (match_dup 0)))] + "peep2_reg_dead_p (2, operands[0])" + [(parallel [(set (match_dup 3) + (plus:HI (match_dup 3) + (match_dup 1))) + (clobber (match_dup 2))])]) + +(define_insn "addhi3_clobber" + [(set (match_operand:HI 0 "register_operand" "=d,l") + (plus:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "const_int_operand" "n,n"))) + (clobber (match_scratch:QI 3 "=X,&d"))] + "" + { + gcc_assert (REGNO (operands[0]) == REGNO (operands[1])); + + return avr_out_plus (operands, NULL, NULL); + } + [(set_attr "length" "4") + (set_attr "adjust_len" "out_plus") + (set_attr "cc" "out_plus")]) + (define_insn "addsi3" [(set (match_operand:SI 0 "register_operand" "=r,d ,d,r") @@ -3606,12 +3672,8 @@ (if_then_else (match_test "!AVR_HAVE_JMP_CALL") (const_int 1) (const_int 2)) - (if_then_else (and (ge (minus (pc) - (match_dup 0)) - (const_int -2047)) - (le (minus (pc) - (match_dup 0)) - (const_int 2047))) + (if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -2047)) + (le (minus (pc) (match_dup 0)) (const_int 2047))) (const_int 1) (const_int 2)))) (set_attr "cc" "none")]) |