diff options
author | gjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-09-28 08:21:06 +0000 |
---|---|---|
committer | gjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-09-28 08:21:06 +0000 |
commit | be6d882390769629554b0fcbb13475d1514d251b (patch) | |
tree | cb5b381dedfa92278ef86432edd69d0a6e334ac4 /gcc/config/avr/avr.md | |
parent | 451b892902582da3f435b6e93611ab4276354960 (diff) | |
download | gcc-be6d882390769629554b0fcbb13475d1514d251b.tar.gz |
PR rtl-optimization/52543
* config/avr/avr.c (avr_mode_dependent_address_p): Return true for
all non-generic address spaces.
(TARGET_SECONDARY_RELOAD): New hook define to...
(avr_secondary_reload): ...this new static function.
* config/avr/avr.md (reload_in<mode>): New insns.
Undo r185605 (mostly):
* config/avr/avr-protos.h (avr_load_lpm): Remove.
* config/avr/avr.c (avr_load_libgcc_p): Don't restrict to __flash loads.
(avr_out_lpm): Also handle loads > 1 byte.
(avr_load_lpm): Remove.
(avr_find_unused_d_reg): New static function.
(avr_out_lpm_no_lpmx): New static function.
(adjust_insn_length): Remove ADJUST_LEN_LOAD_LPM.
* config/avr/avr.md (unspec): Remove UNSPEC_LPM.
(load_<mode>_libgcc): Use MEM instead of UNSPEC_LPM.
(load_<mode>, load_<mode>_clobber): Remove.
(mov<mode>): For multi-byte move from non-generic
16-bit address spaces: Expand to *mov<mode> again.
(load<mode>_libgcc): New expander.
(split-lpmx): Remove split.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@191820 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/avr/avr.md')
-rw-r--r-- | gcc/config/avr/avr.md | 201 |
1 files changed, 96 insertions, 105 deletions
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index b86f9b639df..334064337cd 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -63,7 +63,6 @@ [UNSPEC_STRLEN UNSPEC_MOVMEM UNSPEC_INDEX_JMP - UNSPEC_LPM UNSPEC_FMUL UNSPEC_FMULS UNSPEC_FMULSU @@ -142,7 +141,7 @@ tsthi, tstpsi, tstsi, compare, compare64, call, mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32, ufract, sfract, - xload, movmem, load_lpm, + xload, movmem, ashlqi, ashrqi, lshrqi, ashlhi, ashrhi, lshrhi, ashlsi, ashrsi, lshrsi, @@ -393,60 +392,57 @@ ;;======================================================================== ;; Move stuff around -;; Represent a load from __flash that needs libgcc support as UNSPEC. -;; This is legal because we read from non-changing memory. -;; For rationale see the FIXME below. - -;; "load_psi_libgcc" -;; "load_si_libgcc" -;; "load_sf_libgcc" -(define_insn "load_<mode>_libgcc" - [(set (reg:MOVMODE 22) - (unspec:MOVMODE [(reg:HI REG_Z)] - UNSPEC_LPM))] - "" - { - rtx n_bytes = GEN_INT (GET_MODE_SIZE (<MODE>mode)); - output_asm_insn ("%~call __load_%0", &n_bytes); - return ""; - } - [(set_attr "type" "xcall") - (set_attr "cc" "clobber")]) - - -;; Similar for inline reads from flash. We use UNSPEC instead -;; of MEM for the same reason as above: PR52543. -;; $1 contains the memory segment. - -(define_insn "load_<mode>" - [(set (match_operand:MOVMODE 0 "register_operand" "=r") - (unspec:MOVMODE [(reg:HI REG_Z) - (match_operand:QI 1 "reg_or_0_operand" "rL")] - UNSPEC_LPM))] - "(CONST_INT_P (operands[1]) && AVR_HAVE_LPMX) - || (REG_P (operands[1]) && AVR_HAVE_ELPMX)" +;; Secondary input reload from non-generic 16-bit address spaces +(define_insn "reload_in<mode>" + [(set (match_operand:MOVMODE 0 "register_operand" "=r") + (match_operand:MOVMODE 1 "memory_operand" "m")) + (clobber (match_operand:QI 2 "d_register_operand" "=d"))] + "MEM_P (operands[1]) + && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[1]))" { - return avr_load_lpm (insn, operands, NULL); + return output_movqi (insn, operands, NULL); } - [(set_attr "adjust_len" "load_lpm") + [(set_attr "adjust_len" "mov8") (set_attr "cc" "clobber")]) -;; Similar to above for the complementary situation when there is no [E]LPMx. -;; Clobber Z in that case. +;; "loadqi_libgcc" +;; "loadhi_libgcc" +;; "loadpsi_libgcc" +;; "loadsi_libgcc" +;; "loadsf_libgcc" +(define_expand "load<mode>_libgcc" + [(set (match_dup 3) + (match_dup 2)) + (set (reg:MOVMODE 22) + (match_operand:MOVMODE 1 "memory_operand" "")) + (set (match_operand:MOVMODE 0 "register_operand" "") + (reg:MOVMODE 22))] + "avr_load_libgcc_p (operands[1])" + { + operands[3] = gen_rtx_REG (HImode, REG_Z); + operands[2] = force_operand (XEXP (operands[1], 0), NULL_RTX); + operands[1] = replace_equiv_address (operands[1], operands[3]); + set_mem_addr_space (operands[1], ADDR_SPACE_FLASH); + }) -(define_insn "load_<mode>_clobber" - [(set (match_operand:MOVMODE 0 "register_operand" "=r") - (unspec:MOVMODE [(reg:HI REG_Z) - (match_operand:QI 1 "reg_or_0_operand" "rL")] - UNSPEC_LPM)) - (clobber (reg:HI REG_Z))] - "!((CONST_INT_P (operands[1]) && AVR_HAVE_LPMX) - || (REG_P (operands[1]) && AVR_HAVE_ELPMX))" +;; "load_qi_libgcc" +;; "load_hi_libgcc" +;; "load_psi_libgcc" +;; "load_si_libgcc" +;; "load_sf_libgcc" +(define_insn "load_<mode>_libgcc" + [(set (reg:MOVMODE 22) + (match_operand:MOVMODE 0 "memory_operand" "m,m"))] + "avr_load_libgcc_p (operands[0]) + && REG_P (XEXP (operands[0], 0)) + && REG_Z == REGNO (XEXP (operands[0], 0))" { - return avr_load_lpm (insn, operands, NULL); + operands[0] = GEN_INT (GET_MODE_SIZE (<MODE>mode)); + return "%~call __load_%0"; } - [(set_attr "adjust_len" "load_lpm") + [(set_attr "length" "1,2") + (set_attr "isa" "rjmp,jmp") (set_attr "cc" "clobber")]) @@ -464,6 +460,10 @@ "&& 1" [(clobber (const_int 0))] { + /* ; Split away the high part of the address. GCC's register allocator + ; in not able to allocate segment registers and reload the resulting + ; expressions. Notice that no address register can hold a PSImode. */ + rtx insn, addr = XEXP (operands[1], 0); rtx hi8 = gen_reg_rtx (QImode); rtx reg_z = gen_rtx_REG (HImode, REG_Z); @@ -583,72 +583,29 @@ operands[1] = src = copy_to_mode_reg (<MODE>mode, src); } - if (avr_mem_memx_p (src)) - { - rtx addr = XEXP (src, 0); - - if (!REG_P (addr)) - src = replace_equiv_address (src, copy_to_mode_reg (PSImode, addr)); - - if (!avr_xload_libgcc_p (<MODE>mode)) - /* ; No <mode> here because gen_xload8<mode>_A only iterates over ALL1. - ; insn-emit does not depend on the mode, it' all about operands. */ - emit_insn (gen_xload8qi_A (dest, src)); - else - emit_insn (gen_xload<mode>_A (dest, src)); - - DONE; - } + if (avr_mem_memx_p (src)) + { + rtx addr = XEXP (src, 0); - /* For old devices without LPMx, prefer __flash loads per libcall. */ + if (!REG_P (addr)) + src = replace_equiv_address (src, copy_to_mode_reg (PSImode, addr)); - if (avr_load_libgcc_p (src)) - { - emit_move_insn (gen_rtx_REG (Pmode, REG_Z), - force_reg (Pmode, XEXP (src, 0))); + if (!avr_xload_libgcc_p (<MODE>mode)) + /* ; No <mode> here because gen_xload8<mode>_A only iterates over ALL1. + ; insn-emit does not depend on the mode, it's all about operands. */ + emit_insn (gen_xload8qi_A (dest, src)); + else + emit_insn (gen_xload<mode>_A (dest, src)); - emit_insn (gen_load_<mode>_libgcc ()); - emit_move_insn (dest, gen_rtx_REG (<MODE>mode, 22)); DONE; } - /* ; FIXME: Hack around PR rtl-optimization/52543. - ; lower-subreg.c splits loads from the 16-bit address spaces which - ; causes code bloat because each load need his setting of RAMPZ. - ; Moreover, the split will happen in such a way that the loads don't - ; take advantage of POST_INC addressing. Thus, we use UNSPEC to - ; represent these loads instead. Notice that this is legitimate - ; because the memory content does not change: Loads from the same - ; address will yield the same value. - ; POST_INC addressing would make the addresses mode_dependent and could - ; work around that PR, too. However, notice that it is *not* legitimate - ; to expand to POST_INC at expand time: The following passes assert - ; that pre-/post-modify addressing is introduced by .auto_inc_dec and - ; does not exist before that pass. */ - - if (avr_mem_flash_p (src) - && (GET_MODE_SIZE (<MODE>mode) > 1 - || MEM_ADDR_SPACE (src) != ADDR_SPACE_FLASH)) + if (avr_load_libgcc_p (src)) { - rtx xsegment = GEN_INT (avr_addrspace[MEM_ADDR_SPACE (src)].segment); - if (!AVR_HAVE_ELPM) - xsegment = const0_rtx; - if (xsegment != const0_rtx) - xsegment = force_reg (QImode, xsegment); - - emit_move_insn (gen_rtx_REG (Pmode, REG_Z), - force_reg (Pmode, XEXP (src, 0))); - - if ((CONST_INT_P (xsegment) && AVR_HAVE_LPMX) - || (REG_P (xsegment) && AVR_HAVE_ELPMX)) - emit_insn (gen_load_<mode> (dest, xsegment)); - else - emit_insn (gen_load_<mode>_clobber (dest, xsegment)); + /* For the small devices, do loads per libgcc call. */ + emit_insn (gen_load<mode>_libgcc (dest, src)); DONE; } - - /* ; The only address-space for which we use plain MEM and reload - ; machinery are 1-byte loads from __flash. */ }) ;;======================================================================== @@ -798,6 +755,40 @@ operands[5] = gen_rtx_REG (HImode, REGNO (operands[3])); }) +;; For LPM loads from AS1 we split +;; R = *Z +;; to +;; R = *Z++ +;; Z = Z - sizeof (R) +;; +;; so that the second instruction can be optimized out. + +(define_split ; "split-lpmx" + [(set (match_operand:HISI 0 "register_operand" "") + (match_operand:HISI 1 "memory_operand" ""))] + "reload_completed + && AVR_HAVE_LPMX" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 3) + (plus:HI (match_dup 3) + (match_dup 4)))] + { + rtx addr = XEXP (operands[1], 0); + + if (!avr_mem_flash_p (operands[1]) + || !REG_P (addr) + || reg_overlap_mentioned_p (addr, operands[0])) + { + FAIL; + } + + operands[2] = replace_equiv_address (operands[1], + gen_rtx_POST_INC (Pmode, addr)); + operands[3] = addr; + operands[4] = gen_int_mode (-GET_MODE_SIZE (<MODE>mode), HImode); + }) + ;;========================================================================== ;; xpointer move (24 bit) |