diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2011-09-23 17:06:44 +0000 |
---|---|---|
committer | Georg-Johann Lay <gjl@gcc.gnu.org> | 2011-09-23 17:06:44 +0000 |
commit | a7c0acd01953a277a4bb42d03de572c586a42b5e (patch) | |
tree | f6a6167d5f26e759d125375ed7918c126367394f /gcc | |
parent | 590245153a345410c79f16df7c58660ff91df05e (diff) | |
download | gcc-a7c0acd01953a277a4bb42d03de572c586a42b5e.zip gcc-a7c0acd01953a277a4bb42d03de572c586a42b5e.tar.gz gcc-a7c0acd01953a277a4bb42d03de572c586a42b5e.tar.bz2 |
re PR target/50447 ([avr] Better support of AND, OR, XOR and PLUS with constant integers for 16- and 32-bit values)
* config/avr/avr.md (adjust_len): Add alternatives "tsthi",
"tstsi", "compare".
(*cmpqi_sign_extend): Use s8_operand.
(*cmphi, *cmpsi): Rewrite using avr_out_compare.
* config/avr/avr-protos.h (compare_diff_p, compare_eq_p): Remove
prototypes.
(out_tsthi, out_tstsi): Remove prototypes.
(avr_out_tsthi, avr_out_tstsi): New prototypes.
* config/avr/avr.c (out_tsthi, out_tstsi): Remove functions.
(avr_asm_len): Negative length now sets *plen to -length.
(compare_sign_p): Return bool instead of int.
(compare_diff_p, compare_eq_p): Ditto and make static.
(avr_out_tsthi): New function.
(avr_out_tstsi): New function.
(avr_out_compare): New function.
(adjust_insn_length): Handle ADJUST_LEN_TSTHI, ADJUST_LEN_TSTSI,
ADJUST_LEN_COMPARE.
PR target/50447
From-SVN: r179124
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/config/avr/avr-protos.h | 7 | ||||
-rw-r--r-- | gcc/config/avr/avr.c | 210 | ||||
-rw-r--r-- | gcc/config/avr/avr.md | 153 |
4 files changed, 232 insertions, 159 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b631bf2..c0223e4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,6 +1,27 @@ 2011-09-23 Georg-Johann Lay <avr@gjlay.de> PR target/50447 + * config/avr/avr.md (adjust_len): Add alternatives "tsthi", + "tstsi", "compare". + (*cmpqi_sign_extend): Use s8_operand. + (*cmphi, *cmpsi): Rewrite using avr_out_compare. + * config/avr/avr-protos.h (compare_diff_p, compare_eq_p): Remove + prototypes. + (out_tsthi, out_tstsi): Remove prototypes. + (avr_out_tsthi, avr_out_tstsi): New prototypes. + * config/avr/avr.c (out_tsthi, out_tstsi): Remove functions. + (avr_asm_len): Negative length now sets *plen to -length. + (compare_sign_p): Return bool instead of int. + (compare_diff_p, compare_eq_p): Ditto and make static. + (avr_out_tsthi): New function. + (avr_out_tstsi): New function. + (avr_out_compare): New function. + (adjust_insn_length): Handle ADJUST_LEN_TSTHI, ADJUST_LEN_TSTSI, + ADJUST_LEN_COMPARE. + +2011-09-23 Georg-Johann Lay <avr@gjlay.de> + + PR target/50447 * config/avr/avr.md: (adjust_len): Add alternative "out_plus". (addsi3): Rewrite using QI scratch register. Adjust text peepholes using plus:SI. diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index c6673e4..2fa8ce1 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -47,7 +47,6 @@ extern void init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, #ifdef RTX_CODE extern void asm_output_external_libcall (FILE *file, rtx symref); -extern int compare_diff_p (rtx insn); extern const char *output_movqi (rtx insn, rtx operands[], int *l); extern const char *output_movhi (rtx insn, rtx operands[], int *l); extern const char *out_movqi_r_mr (rtx insn, rtx op[], int *l); @@ -57,8 +56,9 @@ extern const char *out_movhi_mr_r (rtx insn, rtx op[], int *l); extern const char *out_movsi_r_mr (rtx insn, rtx op[], int *l); extern const char *out_movsi_mr_r (rtx insn, rtx op[], int *l); extern const char *output_movsisf (rtx insn, rtx operands[], int *l); -extern const char *out_tstsi (rtx insn, rtx src, int *l); -extern const char *out_tsthi (rtx insn, rtx src, int *l); +extern const char *avr_out_tstsi (rtx, rtx*, int*); +extern const char *avr_out_tsthi (rtx, rtx*, int*); +extern const char *avr_out_compare (rtx, rtx*, int*); extern const char *ret_cond_branch (rtx x, int len, int reverse); extern const char *ashlqi3_out (rtx insn, rtx operands[], int *len); @@ -103,7 +103,6 @@ extern void final_prescan_insn (rtx insn, rtx *operand, int num_operands); extern int avr_simplify_comparison_p (enum machine_mode mode, RTX_CODE op, rtx x); extern RTX_CODE avr_normalize_condition (RTX_CODE condition); -extern int compare_eq_p (rtx insn); extern void out_shift_with_cnt (const char *templ, rtx insn, rtx operands[], int *len, int t_len); extern rtx avr_incoming_return_addr_rtx (void); diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 1682aa0..16d5361 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -69,9 +69,7 @@ static const char *ptrreg_to_str (int); static const char *cond_string (enum rtx_code); static int avr_num_arg_regs (enum machine_mode, const_tree); -static RTX_CODE compare_condition (rtx insn); static rtx avr_legitimize_address (rtx, rtx, enum machine_mode); -static int compare_sign_p (rtx insn); static tree avr_handle_progmem_attribute (tree *, tree, tree, int, bool *); static tree avr_handle_fndecl_attribute (tree *, tree, tree, int, bool *); static tree avr_handle_fntype_attribute (tree *, tree, tree, int, bool *); @@ -1291,7 +1289,8 @@ avr_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) by OPERANDS. This is just forwarding to output_asm_insn. If PLEN != NULL: - Add N_WORDS to *PLEN. + If N_WORDS >= 0 Add N_WORDS to *PLEN. + If N_WORDS < 0 Set *PLEN to -N_WORDS. Don't output anything. */ @@ -1304,7 +1303,10 @@ avr_asm_len (const char* tpl, rtx* operands, int* plen, int n_words) } else { - *plen += n_words; + if (n_words < 0) + *plen = -n_words; + else + *plen += n_words; } } @@ -3052,28 +3054,30 @@ compare_condition (rtx insn) return UNKNOWN; } -/* Returns nonzero if INSN is a tst insn that only tests the sign. */ -static int +/* Returns true iff INSN is a tst insn that only tests the sign. */ + +static bool compare_sign_p (rtx insn) { RTX_CODE cond = compare_condition (insn); return (cond == GE || cond == LT); } -/* Returns nonzero if the next insn is a JUMP_INSN with a condition + +/* Returns true iff the next insn is a JUMP_INSN with a condition that needs to be swapped (GT, GTU, LE, LEU). */ -int +static bool compare_diff_p (rtx insn) { RTX_CODE cond = compare_condition (insn); return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0; } -/* Returns nonzero if INSN is a compare insn with the EQ or NE condition. */ +/* Returns true iff INSN is a compare insn with the EQ or NE condition. */ -int +static bool compare_eq_p (rtx insn) { RTX_CODE cond = compare_condition (insn); @@ -3081,56 +3085,173 @@ compare_eq_p (rtx insn) } +/* Output compare instruction + + compare (XOP[0], XOP[1]) + + for an HI/SI register XOP[0] and an integer XOP[1]. Return "". + XOP[2] is an 8-bit scratch register as needed. + + PLEN == NULL: Output instructions. + PLEN != NULL: Set *PLEN to the length (in words) of the sequence. + Don't output anything. */ + +const char* +avr_out_compare (rtx insn, rtx *xop, int *plen) +{ + /* Register to compare and value to compare against. */ + rtx xreg = xop[0]; + rtx xval = xop[1]; + + /* MODE of the comparison. */ + enum machine_mode mode = GET_MODE (xreg); + + /* Number of bytes to operate on. */ + int i, n_bytes = GET_MODE_SIZE (mode); + + /* Value (0..0xff) held in clobber register xop[2] or -1 if unknown. */ + int clobber_val = -1; + + gcc_assert (REG_P (xreg) + && CONST_INT_P (xval)); + + if (plen) + *plen = 0; + + for (i = 0; i < n_bytes; i++) + { + /* We compare byte-wise. */ + rtx reg8 = simplify_gen_subreg (QImode, xreg, mode, i); + rtx xval8 = simplify_gen_subreg (QImode, xval, mode, i); + + /* 8-bit value to compare with this byte. */ + unsigned int val8 = UINTVAL (xval8) & GET_MODE_MASK (QImode); + + /* Registers R16..R31 can operate with immediate. */ + bool ld_reg_p = test_hard_reg_class (LD_REGS, reg8); + + xop[0] = reg8; + xop[1] = gen_int_mode (val8, QImode); + + /* Word registers >= R24 can use SBIW/ADIW with 0..63. */ + + if (i == 0 + && test_hard_reg_class (ADDW_REGS, reg8)) + { + int val16 = trunc_int_for_mode (INTVAL (xval), HImode); + + if (IN_RANGE (val16, 0, 63) + && (val8 == 0 + || reg_unused_after (insn, xreg))) + { + avr_asm_len ("sbiw %0,%1", xop, plen, 1); + i++; + continue; + } + + if (n_bytes == 2 + && IN_RANGE (val16, -63, -1) + && compare_eq_p (insn) + && reg_unused_after (insn, xreg)) + { + avr_asm_len ("adiw %0,%n1", xop, plen, 1); + break; + } + } + + /* Comparing against 0 is easy. */ + + if (val8 == 0) + { + avr_asm_len (i == 0 + ? "cp %0,__zero_reg__" + : "cpc %0,__zero_reg__", xop, plen, 1); + continue; + } + + /* Upper registers can compare and subtract-with-carry immediates. + Notice that compare instructions do the same as respective subtract + instruction; the only difference is that comparisons don't write + the result back to the target register. */ + + if (ld_reg_p) + { + if (i == 0) + { + avr_asm_len ("cpi %0,%1", xop, plen, 1); + continue; + } + else if (reg_unused_after (insn, xreg)) + { + avr_asm_len ("sbci %0,%1", xop, plen, 1); + continue; + } + } + + /* Must load the value into the scratch register. */ + + gcc_assert (REG_P (xop[2])); + + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", xop, plen, 1); + clobber_val = (int) val8; + + avr_asm_len (i == 0 + ? "cp %0,%2" + : "cpc %0,%2", xop, plen, 1); + } + + return ""; +} + + /* Output test instruction for HImode. */ -const char * -out_tsthi (rtx insn, rtx op, int *l) +const char* +avr_out_tsthi (rtx insn, rtx *op, int *plen) { if (compare_sign_p (insn)) { - if (l) *l = 1; - return AS1 (tst,%B0); + avr_asm_len ("tst %B0", op, plen, -1); } - if (reg_unused_after (insn, op) - && compare_eq_p (insn)) + else if (reg_unused_after (insn, op[0]) + && compare_eq_p (insn)) { /* Faster than sbiw if we can clobber the operand. */ - if (l) *l = 1; - return "or %A0,%B0"; + avr_asm_len ("or %A0,%B0", op, plen, -1); } - if (test_hard_reg_class (ADDW_REGS, op)) + else { - if (l) *l = 1; - return AS2 (sbiw,%0,0); + avr_out_compare (insn, op, plen); } - if (l) *l = 2; - return (AS2 (cp,%A0,__zero_reg__) CR_TAB - AS2 (cpc,%B0,__zero_reg__)); + + return ""; } /* Output test instruction for SImode. */ -const char * -out_tstsi (rtx insn, rtx op, int *l) +const char* +avr_out_tstsi (rtx insn, rtx *op, int *plen) { if (compare_sign_p (insn)) { - if (l) *l = 1; - return AS1 (tst,%D0); + avr_asm_len ("tst %D0", op, plen, -1); } - if (test_hard_reg_class (ADDW_REGS, op)) + else if (reg_unused_after (insn, op[0]) + && compare_eq_p (insn)) { - if (l) *l = 3; - return (AS2 (sbiw,%A0,0) CR_TAB - AS2 (cpc,%C0,__zero_reg__) CR_TAB - AS2 (cpc,%D0,__zero_reg__)); + /* Faster than sbiw if we can clobber the operand. */ + avr_asm_len ("or %A0,%B0" CR_TAB + "or %A0,%C0" CR_TAB + "or %A0,%D0", op, plen, -3); + } + else + { + avr_out_compare (insn, op, plen); } - if (l) *l = 4; - return (AS2 (cp,%A0,__zero_reg__) CR_TAB - AS2 (cpc,%B0,__zero_reg__) CR_TAB - AS2 (cpc,%C0,__zero_reg__) CR_TAB - AS2 (cpc,%D0,__zero_reg__)); + + return ""; } @@ -5016,6 +5137,10 @@ adjust_insn_length (rtx insn, int len) avr_out_plus (op, &len); break; + case ADJUST_LEN_TSTHI: avr_out_tsthi (insn, op, &len); break; + case ADJUST_LEN_TSTSI: avr_out_tstsi (insn, op, &len); break; + case ADJUST_LEN_COMPARE: avr_out_compare (insn, op, &len); break; + default: gcc_unreachable(); } @@ -5051,15 +5176,6 @@ adjust_insn_length (rtx insn, int len) break; } } - else if (op[0] == cc0_rtx && REG_P (op[1])) - { - switch (GET_MODE (op[1])) - { - case HImode: out_tsthi (insn, op[1], &len); break; - case SImode: out_tstsi (insn, op[1], &len); break; - default: break; - } - } } set = single_set (insn); if (set) diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 8e78ca6..06e0039 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -136,7 +136,7 @@ ;; Otherwise do special processing depending on the attribute. (define_attr "adjust_len" - "yes,no,reload_in32,out_bitop,out_plus" + "yes,no,reload_in32,out_bitop,out_plus,tsthi,tstsi,compare" (const_string "yes")) ;; Define mode iterators @@ -3344,125 +3344,62 @@ (define_insn "*cmpqi_sign_extend" [(set (cc0) - (compare (sign_extend:HI - (match_operand:QI 0 "register_operand" "d")) - (match_operand:HI 1 "const_int_operand" "n")))] - "INTVAL (operands[1]) >= -128 && INTVAL (operands[1]) <= 127" + (compare (sign_extend:HI (match_operand:QI 0 "register_operand" "d")) + (match_operand:HI 1 "s8_operand" "n")))] + "" "cpi %0,lo8(%1)" [(set_attr "cc" "compare") (set_attr "length" "1")]) (define_insn "*cmphi" [(set (cc0) - (compare (match_operand:HI 0 "register_operand" "!w,r,r,d,d,r,r") - (match_operand:HI 1 "nonmemory_operand" "L,L,r,M,i,M,i"))) - (clobber (match_scratch:QI 2 "=X,X,X,X,&d,&d,&d"))] + (compare (match_operand:HI 0 "register_operand" "!w,r,r,d ,r ,d,r") + (match_operand:HI 1 "nonmemory_operand" "L ,L,r,s ,s ,M,n"))) + (clobber (match_scratch:QI 2 "=X ,X,X,&d,&d ,X,&d"))] "" - "*{ - switch (which_alternative) - { - case 0: case 1: - return out_tsthi (insn, operands[0], NULL); - - case 2: - return (AS2 (cp,%A0,%A1) CR_TAB - AS2 (cpc,%B0,%B1)); - case 3: - if (reg_unused_after (insn, operands[0]) - && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 63 - && test_hard_reg_class (ADDW_REGS, operands[0])) - return AS2 (sbiw,%0,%1); - else - return (AS2 (cpi,%0,%1) CR_TAB - AS2 (cpc,%B0,__zero_reg__)); - case 4: - if (reg_unused_after (insn, operands[0])) - return (AS2 (subi,%0,lo8(%1)) CR_TAB - AS2 (sbci,%B0,hi8(%1))); - else - return (AS2 (ldi, %2,hi8(%1)) CR_TAB - AS2 (cpi, %A0,lo8(%1)) CR_TAB - AS2 (cpc, %B0,%2)); - case 5: - return (AS2 (ldi, %2,lo8(%1)) CR_TAB - AS2 (cp, %A0,%2) CR_TAB - AS2 (cpc, %B0,__zero_reg__)); - - case 6: - return (AS2 (ldi, %2,lo8(%1)) CR_TAB - AS2 (cp, %A0,%2) CR_TAB - AS2 (ldi, %2,hi8(%1)) CR_TAB - AS2 (cpc, %B0,%2)); - } - return \"bug\"; -}" - [(set_attr "cc" "compare,compare,compare,compare,compare,compare,compare") - (set_attr "length" "1,2,2,2,3,3,4")]) + { + switch (which_alternative) + { + case 0: + case 1: + return avr_out_tsthi (insn, operands, NULL); + + case 2: + return "cp %A0,%A1\;cpc %B0,%B1"; + + case 3: + return reg_unused_after (insn, operands[0]) + ? "subi %A0,lo8(%1)\;sbci %B0,hi8(%1)" + : "ldi %2,hi8(%1)\;cpi %A0,lo8(%1)\;cpc %B0,%2"; + + case 4: + return "ldi %2,lo8(%1)\;cp %A0,%2\;ldi %2,hi8(%1)\;cpc %B0,%2"; + } + + return avr_out_compare (insn, operands, NULL); + } + [(set_attr "cc" "compare") + (set_attr "length" "1,2,2,3,4,2,4") + (set_attr "adjust_len" "tsthi,tsthi,no,no,no,compare,compare")]) (define_insn "*cmpsi" [(set (cc0) - (compare (match_operand:SI 0 "register_operand" "r,r,d,d,r,r") - (match_operand:SI 1 "nonmemory_operand" "L,r,M,i,M,i"))) - (clobber (match_scratch:QI 2 "=X,X,X,&d,&d,&d"))] + (compare (match_operand:SI 0 "register_operand" "r,r ,d,r ,r") + (match_operand:SI 1 "nonmemory_operand" "L,r ,M,M ,n"))) + (clobber (match_scratch:QI 2 "=X,X ,X,&d,&d"))] "" - "*{ - switch (which_alternative) - { - case 0: - return out_tstsi (insn, operands[0], NULL); - - case 1: - return (AS2 (cp,%A0,%A1) CR_TAB - AS2 (cpc,%B0,%B1) CR_TAB - AS2 (cpc,%C0,%C1) CR_TAB - AS2 (cpc,%D0,%D1)); - case 2: - if (reg_unused_after (insn, operands[0]) - && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 63 - && test_hard_reg_class (ADDW_REGS, operands[0])) - return (AS2 (sbiw,%0,%1) CR_TAB - AS2 (cpc,%C0,__zero_reg__) CR_TAB - AS2 (cpc,%D0,__zero_reg__)); - else - return (AS2 (cpi,%A0,lo8(%1)) CR_TAB - AS2 (cpc,%B0,__zero_reg__) CR_TAB - AS2 (cpc,%C0,__zero_reg__) CR_TAB - AS2 (cpc,%D0,__zero_reg__)); - case 3: - if (reg_unused_after (insn, operands[0])) - return (AS2 (subi,%A0,lo8(%1)) CR_TAB - AS2 (sbci,%B0,hi8(%1)) CR_TAB - AS2 (sbci,%C0,hlo8(%1)) CR_TAB - AS2 (sbci,%D0,hhi8(%1))); - else - return (AS2 (cpi, %A0,lo8(%1)) CR_TAB - AS2 (ldi, %2,hi8(%1)) CR_TAB - AS2 (cpc, %B0,%2) CR_TAB - AS2 (ldi, %2,hlo8(%1)) CR_TAB - AS2 (cpc, %C0,%2) CR_TAB - AS2 (ldi, %2,hhi8(%1)) CR_TAB - AS2 (cpc, %D0,%2)); - case 4: - return (AS2 (ldi,%2,lo8(%1)) CR_TAB - AS2 (cp,%A0,%2) CR_TAB - AS2 (cpc,%B0,__zero_reg__) CR_TAB - AS2 (cpc,%C0,__zero_reg__) CR_TAB - AS2 (cpc,%D0,__zero_reg__)); - case 5: - return (AS2 (ldi, %2,lo8(%1)) CR_TAB - AS2 (cp, %A0,%2) CR_TAB - AS2 (ldi, %2,hi8(%1)) CR_TAB - AS2 (cpc, %B0,%2) CR_TAB - AS2 (ldi, %2,hlo8(%1)) CR_TAB - AS2 (cpc, %C0,%2) CR_TAB - AS2 (ldi, %2,hhi8(%1)) CR_TAB - AS2 (cpc, %D0,%2)); - } - return \"bug\"; -}" - [(set_attr "cc" "compare,compare,compare,compare,compare,compare") - (set_attr "length" "4,4,4,7,5,8")]) + { + if (0 == which_alternative) + return avr_out_tstsi (insn, operands, NULL); + else if (1 == which_alternative) + return "cp %A0,%A1\;cpc %B0,%B1\;cpc %C0,%C1\;cpc %D0,%D1"; + + return avr_out_compare (insn, operands, NULL); + } + [(set_attr "cc" "compare") + (set_attr "length" "4,4,4,5,8") + (set_attr "adjust_len" "tstsi,no,compare,compare,compare")]) ;; ---------------------------------------------------------------------- |