diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2011-09-21 08:21:57 +0000 |
---|---|---|
committer | Georg-Johann Lay <gjl@gcc.gnu.org> | 2011-09-21 08:21:57 +0000 |
commit | 8dab2ba518fc18d57174e2042bad1e84420169d0 (patch) | |
tree | 53c3150b00f955f3c54c3838a65b07336b394414 | |
parent | 3653988e4640f61223336d5e12c178329d659a13 (diff) | |
download | gcc-8dab2ba518fc18d57174e2042bad1e84420169d0.zip gcc-8dab2ba518fc18d57174e2042bad1e84420169d0.tar.gz gcc-8dab2ba518fc18d57174e2042bad1e84420169d0.tar.bz2 |
re PR target/50449 ([avr] Loading some 32-bit constants not optimal)
PR target/50449
PR target/50465
* config/avr/avr.md (adjust_len): New insn attribute.
(*reload_insi, *reload_insf): Use it.
(*movsi, *movsf): Use new interface of output_movsisf.
* config/avr/avr-protos.h (output_movsisf): Change prototype.
* config/avr/avr.c (output_movsisf): Ditto.
(adjust_insn_length): Use insn attribute "adjust_len" to adjust
lengths of insns *reload_insi, *reload_insf.
(output_reload_insisf_1): New static function.
(output_reload_insisf): Use it.
From-SVN: r179037
-rw-r--r-- | gcc/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/config/avr/avr-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/avr/avr.c | 188 | ||||
-rw-r--r-- | gcc/config/avr/avr.md | 17 |
4 files changed, 183 insertions, 38 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d1265fb..663319d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2011-09-21 Georg-Johann Lay <avr@gjlay.de> + + PR target/50449 + PR target/50465 + * config/avr/avr.md (adjust_len): New insn attribute. + (*reload_insi, *reload_insf): Use it. + (*movsi, *movsf): Use new interface of output_movsisf. + * config/avr/avr-protos.h (output_movsisf): Change prototype. + * config/avr/avr.c (output_movsisf): Ditto. + (adjust_insn_length): Use insn attribute "adjust_len" to adjust + lengths of insns *reload_insi, *reload_insf. + (output_reload_insisf_1): New static function. + (output_reload_insisf): Use it. + 2011-09-21 David S. Miller <davem@davemloft.net> * config/sparc/sparc.c (def_builtin): Change from macro into function. diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index ba7da70..6a0b40c 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -56,7 +56,7 @@ extern const char *out_movhi_r_mr (rtx insn, rtx op[], int *l); 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[], rtx clobber, 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 *ret_cond_branch (rtx x, int len, int reverse); diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index b69efa9..7b11ca9 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -1819,7 +1819,7 @@ avr_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode, for (regno = cum->regno; regno < cum->regno + bytes; regno++) if (fixed_regs[regno]) - error ("Register %s is needed to pass a parameter but is fixed", + warning (0,"Register %s is needed to pass a parameter but is fixed", reg_names[regno]); } @@ -2673,7 +2673,7 @@ out_movsi_mr_r (rtx insn, rtx op[], int *l) } const char * -output_movsisf (rtx insn, rtx operands[], rtx clobber_reg, int *l) +output_movsisf (rtx insn, rtx operands[], int *l) { int dummy; rtx dest = operands[0]; @@ -2719,7 +2719,7 @@ output_movsisf (rtx insn, rtx operands[], rtx clobber_reg, int *l) else if (CONST_INT_P (src) || CONST_DOUBLE_P (src)) { - return output_reload_insisf (insn, operands, clobber_reg, real_l); + return output_reload_insisf (insn, operands, NULL_RTX, real_l); } else if (CONSTANT_P (src)) { @@ -4616,8 +4616,56 @@ avr_rotate_bytes (rtx operands[]) int adjust_insn_length (rtx insn, int len) { - rtx patt = PATTERN (insn); - rtx set; + rtx patt, set; + enum attr_adjust_len adjust_len; + + /* Some complex insns don't need length adjustment and therefore + the length need not/must not be adjusted for these insns. + It is easier to state this in an insn attribute "adjust_len" than + to clutter up code here... */ + + if (-1 == recog_memoized (insn)) + { + return len; + } + + /* Read from insn attribute "adjust_len" if/how length is to be adjusted. */ + + adjust_len = get_attr_adjust_len (insn); + + if (adjust_len != ADJUST_LEN_YES) + { + rtx *op = recog_data.operand; + + if (adjust_len == ADJUST_LEN_NO) + { + /* Nothing to adjust: The length from attribute "length" is fine. */ + + return len; + } + + /* Extract insn's operands. */ + + extract_constrain_insn_cached (insn); + + /* Dispatch to right function. */ + + switch (adjust_len) + { + case ADJUST_LEN_RELOAD_IN32: + output_reload_insisf (insn, op, op[2], &len); + break; + + default: + gcc_unreachable(); + } + + return len; + } /* adjust_length != ADJUST_LEN_YES */ + + /* adjust_len == "yes": Analyse insn by hand. */ + + patt = PATTERN (insn); if (GET_CODE (patt) == SET) { @@ -4637,7 +4685,7 @@ adjust_insn_length (rtx insn, int len) break; case SImode: case SFmode: - output_movsisf (insn, op, NULL_RTX, &len); + output_movsisf (insn, op, &len); break; default: break; @@ -4708,7 +4756,8 @@ adjust_insn_length (rtx insn, int len) break; case SImode: case SFmode: - output_reload_insisf (insn, op, XEXP (op[2], 0), &len); + /* Handled by ADJUST_LEN_RELOAD_INSISF above. */ + gcc_unreachable(); break; default: break; @@ -6698,21 +6747,17 @@ output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len) } -/* Reload a SI or SF compile time constant (OP[1]) into a GPR (OP[0]). - CLOBBER_REG is a QI clobber reg needed to move vast majority of consts - into a NO_LD_REGS. If CLOBBER_REG is NULL_RTX we either don't need a - clobber reg or have to cook one up. - - LEN == NULL: Output instructions. - - LEN != NULL: Output nothing. Increment *LEN by number of words occupied - by the insns printed. - - Return "". */ +/* A helper for `output_reload_insisf'. */ +/* Set 32-bit register OP[0] to compile-time constant OP[1]. + CLOBBER_REG is a QI clobber register or NULL_RTX. + LEN == NULL: output instructions. + LEN != NULL: set *LEN to the length of the instruction sequence + (in words) printed with LEN = NULL. + If CLEAR_P is true, OP[0] had been cleard to Zero already. + If CLEAR_P is false, nothing is known about OP[0]. */ -const char * -output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, - rtx *op, rtx clobber_reg, int *len) +static void +output_reload_insisf_1 (rtx *op, rtx clobber_reg, int *len, bool clear_p) { rtx src = op[1]; rtx dest = op[0]; @@ -6787,7 +6832,12 @@ output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, if (INTVAL (lo16) == INTVAL (hi16)) { - avr_asm_len ("movw %C0,%A0", &op[0], len, 1); + if (0 != INTVAL (lo16) + || !clear_p) + { + avr_asm_len ("movw %C0,%A0", &op[0], len, 1); + } + break; } } @@ -6797,7 +6847,9 @@ output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, if (ival[n] == 0) { - avr_asm_len ("clr %0", &xdest[n], len, 1); + if (!clear_p) + avr_asm_len ("clr %0", &xdest[n], len, 1); + continue; } @@ -6837,8 +6889,18 @@ output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, if (-1 == ival[n]) { - avr_asm_len ("clr %0" CR_TAB - "dec %0", &xdest[n], len, 2); + if (!clear_p) + avr_asm_len ("clr %0", &xdest[n], len, 1); + + avr_asm_len ("dec %0", &xdest[n], len, 1); + continue; + } + else if (1 == ival[n]) + { + if (!clear_p) + avr_asm_len ("clr %0", &xdest[n], len, 1); + + avr_asm_len ("inc %0", &xdest[n], len, 1); continue; } @@ -6848,13 +6910,6 @@ output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, if (NULL_RTX == clobber_reg && single_one_operand (xval, QImode)) { - if (1 == ival[n]) - { - avr_asm_len ("clr %0" CR_TAB - "inc %0", &xdest[n], len, 2); - continue; - } - xop[0] = xdest[n]; xop[1] = GEN_INT (exact_log2 (ival[n] & GET_MODE_MASK (QImode))); @@ -6866,8 +6921,10 @@ output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, avr_asm_len ("set", xop, len, 1); } - avr_asm_len ("clr %0" CR_TAB - "bld %0,%1", xop, len, 2); + if (!clear_p) + avr_asm_len ("clr %0", xop, len, 1); + + avr_asm_len ("bld %0,%1", xop, len, 1); continue; } @@ -6890,7 +6947,68 @@ output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, { avr_asm_len ("mov %0,__tmp_reg__", &clobber_reg, len, 1); } - +} + + +/* Reload a SI or SF compile time constant OP[1] into the register OP[0]. + CLOBBER_REG is a QI clobber reg needed to move vast majority of consts + into a NO_LD_REGS register. If CLOBBER_REG is NULL_RTX we either don't + need a clobber reg or have to cook one up. + + LEN == NULL: Output instructions. + + LEN != NULL: Output nothing. Increment *LEN by number of words occupied + by the insns printed. + + Return "". */ + +const char * +output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, + rtx *op, rtx clobber_reg, int *len) +{ + gcc_assert (REG_P (op[0]) + && CONSTANT_P (op[1])); + + if (AVR_HAVE_MOVW + && !test_hard_reg_class (LD_REGS, op[0])) + { + int len_clr, len_noclr; + + /* In some cases it is better to clear the destination beforehand, e.g. + + CLR R2 CLR R3 MOVW R4,R2 INC R2 + + is shorther than + + CLR R2 INC R2 CLR R3 CLR R4 CLR R5 + + We find it too tedious to work that out in the print function. + Instead, we call the print function twice to get the lengths of + both methods and use the shortest one. */ + + output_reload_insisf_1 (op, clobber_reg, &len_clr, true); + output_reload_insisf_1 (op, clobber_reg, &len_noclr, false); + + if (len_noclr - len_clr == 4) + { + /* Default needs 4 CLR instructions: clear register beforehand. */ + + avr_asm_len ("clr %A0" CR_TAB + "clr %B0" CR_TAB + "movw %C0,%A0", &op[0], len, 3); + + output_reload_insisf_1 (op, clobber_reg, len, true); + + if (len) + *len += 3; + + return ""; + } + } + + /* Default: destination not pre-cleared. */ + + output_reload_insisf_1 (op, clobber_reg, len, false); return ""; } diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 80bb8f5..a1fcecb 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -128,6 +128,17 @@ (const_int 2))] (const_int 2))) +;; Lengths of several insns are adjusted in avr.c:adjust_insn_length(). +;; Following insn attribute tells if and how the adjustment has to be +;; done: +;; no No adjustment needed; attribute "length" is fine. +;; yes Analyse pattern in adjust_insn_length by hand. +;; Otherwise do special processing depending on the attribute. + +(define_attr "adjust_len" + "yes,no,reload_in32" + (const_string "yes")) + ;; Define mode iterators (define_mode_iterator QIHI [(QI "") (HI "")]) (define_mode_iterator QIHI2 [(QI "") (HI "")]) @@ -457,6 +468,7 @@ return output_reload_insisf (insn, operands, operands[2], NULL); } [(set_attr "length" "8") + (set_attr "adjust_len" "reload_in32") (set_attr "cc" "clobber")]) @@ -466,7 +478,7 @@ "(register_operand (operands[0],SImode) || register_operand (operands[1],SImode) || const0_rtx == operands[1])" { - return output_movsisf (insn, operands, NULL_RTX, NULL); + return output_movsisf (insn, operands, NULL); } [(set_attr "length" "4,4,8,9,4,10") (set_attr "cc" "none,set_zn,clobber,clobber,clobber,clobber")]) @@ -495,7 +507,7 @@ || register_operand (operands[1], SFmode) || operands[1] == CONST0_RTX (SFmode)" { - return output_movsisf (insn, operands, NULL_RTX, NULL); + return output_movsisf (insn, operands, NULL); } [(set_attr "length" "4,4,8,9,4,10") (set_attr "cc" "none,set_zn,clobber,clobber,clobber,clobber")]) @@ -521,6 +533,7 @@ return output_reload_insisf (insn, operands, operands[2], NULL); } [(set_attr "length" "8") + (set_attr "adjust_len" "reload_in32") (set_attr "cc" "clobber")]) ;;========================================================================= |