diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2011-10-11 18:28:49 +0000 |
---|---|---|
committer | Georg-Johann Lay <gjl@gcc.gnu.org> | 2011-10-11 18:28:49 +0000 |
commit | 05058b6e31ec87bb08cb9457b22080afbd2c4723 (patch) | |
tree | 014074a311e4c9e316bbded0457287a7e8b7df50 /gcc/config/avr | |
parent | a4474a3854f4fec4bfccad91706f95a6737e6a79 (diff) | |
download | gcc-05058b6e31ec87bb08cb9457b22080afbd2c4723.zip gcc-05058b6e31ec87bb08cb9457b22080afbd2c4723.tar.gz gcc-05058b6e31ec87bb08cb9457b22080afbd2c4723.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): Add out_plus attribute alternative.
(addsi3): Use it. Adapt avr_out_plus to new prototype. Use
avr_out_plus for all CONST_INT addends.
* config/avr/avr-protos.h (avr_out_plus): Change prototype.
* config/avr/avr.c (notice_update_cc): Call avr_out_plus on
CC_OUT_PLUS.
(avr_out_plus_1): Change prototype and report effect on cc0.
(avr_out_plus): Ditto.
(adjust_insn_length): Adapt call to avr_out_plus to new prototype.
From-SVN: r179816
Diffstat (limited to 'gcc/config/avr')
-rw-r--r-- | gcc/config/avr/avr-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/avr/avr.c | 76 | ||||
-rw-r--r-- | gcc/config/avr/avr.md | 29 |
3 files changed, 80 insertions, 27 deletions
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index a2a5dd0..06e412c 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -82,7 +82,7 @@ extern void avr_output_bld (rtx operands[], int bit_nr); 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*); +extern const char* avr_out_plus (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 d8cc84a..afc3d61 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -1630,9 +1630,37 @@ void notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn) { rtx set; + enum attr_cc cc = get_attr_cc (insn); - switch (get_attr_cc (insn)) + switch (cc) { + default: + break; + + case CC_OUT_PLUS: + { + rtx *op = recog_data.operand; + int len_dummy, icc; + + /* Extract insn's operands. */ + extract_constrain_insn_cached (insn); + + avr_out_plus (op, &len_dummy, &icc); + cc = (enum attr_cc) icc; + + break; + } + } + + switch (cc) + { + default: + /* Special values like CC_OUT_PLUS from above have been + mapped to "standard" CC_* values so we never come here. */ + + gcc_unreachable(); + break; + case CC_NONE: /* Insn does not affect CC at all. */ break; @@ -4673,10 +4701,11 @@ lshrsi3_out (rtx insn, rtx operands[], int *len) addition; otherwise, set *PLEN to the length of the instruction sequence (in words) printed with PLEN == NULL. XOP[3] is an 8-bit scratch register. CODE == PLUS: perform addition by using ADD instructions. - CODE == MINUS: perform addition by using SUB instructions. */ + CODE == MINUS: perform addition by using SUB instructions. + Set *PCC to effect on cc0 according to respective CC_* insn attribute. */ static void -avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code) +avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc) { /* MODE of the operation. */ enum machine_mode mode = GET_MODE (xop[0]); @@ -4700,6 +4729,10 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code) /* 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. */ + + *pcc = (MINUS == code) ? CC_SET_CZN : CC_CLOBBER; + if (MINUS == code) xval = gen_int_mode (-UINTVAL (xval), mode); @@ -4722,6 +4755,11 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code) op[0] = reg8; op[1] = GEN_INT (val8); + + /* To get usable cc0 no low-bytes must have been skipped. */ + + if (i && !started) + *pcc = CC_CLOBBER; if (!started && i % 2 == 0 && test_hard_reg_class (ADDW_REGS, reg8)) @@ -4794,6 +4832,11 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code) started = true; } /* for all sub-bytes */ + + /* No output doesn't change cc0. */ + + if (plen && *plen == 0) + *pcc = CC_NONE; } @@ -4803,24 +4846,35 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code) and return "". If PLEN == NULL, print assembler instructions to perform the addition; otherwise, set *PLEN to the length of the instruction sequence (in - words) printed with PLEN == NULL. */ + words) printed with PLEN == NULL. + If PCC != 0 then set *PCC to the the instruction sequence's effect on the + condition code (with respect to XOP[0]). */ const char* -avr_out_plus (rtx *xop, int *plen) +avr_out_plus (rtx *xop, int *plen, int *pcc) { int len_plus, len_minus; + int cc_plus, cc_minus, cc_dummy; + if (!pcc) + pcc = &cc_dummy; + /* Work out if XOP[0] += XOP[2] is better or XOP[0] -= -XOP[2]. */ - avr_out_plus_1 (xop, &len_plus, PLUS); - avr_out_plus_1 (xop, &len_minus, MINUS); + avr_out_plus_1 (xop, &len_plus, PLUS, &cc_plus); + avr_out_plus_1 (xop, &len_minus, MINUS, &cc_minus); + /* Prefer MINUS over PLUS if size is equal because it sets cc0. */ + if (plen) - *plen = (len_minus <= len_plus) ? len_minus : len_plus; + { + *plen = (len_minus <= len_plus) ? len_minus : len_plus; + *pcc = (len_minus <= len_plus) ? cc_minus : cc_plus; + } else if (len_minus <= len_plus) - avr_out_plus_1 (xop, NULL, MINUS); + avr_out_plus_1 (xop, NULL, MINUS, pcc); else - avr_out_plus_1 (xop, NULL, PLUS); + avr_out_plus_1 (xop, NULL, PLUS, pcc); return ""; } @@ -5209,7 +5263,7 @@ 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); break; + case ADJUST_LEN_OUT_PLUS: avr_out_plus (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 23541bf..b7fe770 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -77,7 +77,8 @@ (include "constraints.md") ;; Condition code settings. -(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber" +(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber, + out_plus" (const_string "none")) (define_attr "type" "branch,branch1,arith,xcall" @@ -786,30 +787,28 @@ (set_attr "cc" "set_n,set_czn,set_czn,set_czn,set_n,set_n")]) (define_insn "addsi3" - [(set (match_operand:SI 0 "register_operand" "=r,!w,!w,d,l,l ,d,r") - (plus:SI (match_operand:SI 1 "register_operand" "%0,0 ,0 ,0,0,0 ,0,0") - (match_operand:SI 2 "nonmemory_operand" "r,I ,J ,s,P,N ,n,n"))) - (clobber (match_scratch:QI 3 "=X,X ,X ,X,X,X ,X,&d"))] + [(set (match_operand:SI 0 "register_operand" "=r,d ,d,r") + (plus:SI (match_operand:SI 1 "register_operand" "%0,0 ,0,0") + (match_operand:SI 2 "nonmemory_operand" "r,s ,n,n"))) + (clobber (match_scratch:QI 3 "=X,X ,X,&d"))] "" { static const char * const asm_code[] = { "add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2", - "adiw %0,%2\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__", - "sbiw %0,%n2\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__", "subi %0,lo8(-(%2))\;sbci %B0,hi8(-(%2))\;sbci %C0,hlo8(-(%2))\;sbci %D0,hhi8(-(%2))", - "sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__", - "sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__" + "", + "" }; - if (which_alternative >= (signed) (sizeof (asm_code) / sizeof (*asm_code))) - return avr_out_plus (operands, NULL); + if (*asm_code[which_alternative]) + return asm_code [which_alternative]; - return asm_code [which_alternative]; + return avr_out_plus (operands, NULL, NULL); } - [(set_attr "length" "4,3,3,4,5,5,8,8") - (set_attr "adjust_len" "*,*,*,*,*,*,out_plus,out_plus") - (set_attr "cc" "set_n,set_n,set_czn,set_czn,set_n,set_n,clobber,clobber")]) + [(set_attr "length" "4,4,4,8") + (set_attr "adjust_len" "*,*,out_plus,out_plus") + (set_attr "cc" "set_n,set_czn,out_plus,out_plus")]) (define_insn "*addsi3_zero_extend" [(set (match_operand:SI 0 "register_operand" "=r") |