summaryrefslogtreecommitdiff
path: root/gcc/config/avr/avr.md
diff options
context:
space:
mode:
authorgjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4>2012-09-28 08:21:06 +0000
committergjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4>2012-09-28 08:21:06 +0000
commitbe6d882390769629554b0fcbb13475d1514d251b (patch)
treecb5b381dedfa92278ef86432edd69d0a6e334ac4 /gcc/config/avr/avr.md
parent451b892902582da3f435b6e93611ab4276354960 (diff)
downloadgcc-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.md201
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)