Commit 3fd1e31d by Georg-Johann Lay Committed by Georg-Johann Lay

re PR rtl-optimization/52543 (lower-subreg.c: code bloat of 300%-400% for multi-word memory splits)

	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.

From-SVN: r191820
parent af710874
2012-09-28 Georg-Johann Lay <avr@gjlay.de>
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.
2012-09-27 Dehao Chen <dehao@google.com> 2012-09-27 Dehao Chen <dehao@google.com>
* tree.h (tree_constructor): Remove IS_UNKNOWN_LOCATION. * tree.h (tree_constructor): Remove IS_UNKNOWN_LOCATION.
......
...@@ -75,8 +75,6 @@ extern const char *avr_out_ashlpsi3 (rtx, rtx*, int*); ...@@ -75,8 +75,6 @@ extern const char *avr_out_ashlpsi3 (rtx, rtx*, int*);
extern const char *avr_out_ashrpsi3 (rtx, rtx*, int*); extern const char *avr_out_ashrpsi3 (rtx, rtx*, int*);
extern const char *avr_out_lshrpsi3 (rtx, rtx*, int*); extern const char *avr_out_lshrpsi3 (rtx, rtx*, int*);
extern const char* avr_load_lpm (rtx, rtx*, int*);
extern bool avr_rotate_bytes (rtx operands[]); extern bool avr_rotate_bytes (rtx operands[]);
extern const char* avr_out_fract (rtx, rtx[], bool, int*); extern const char* avr_out_fract (rtx, rtx[], bool, int*);
......
...@@ -63,7 +63,6 @@ ...@@ -63,7 +63,6 @@
[UNSPEC_STRLEN [UNSPEC_STRLEN
UNSPEC_MOVMEM UNSPEC_MOVMEM
UNSPEC_INDEX_JMP UNSPEC_INDEX_JMP
UNSPEC_LPM
UNSPEC_FMUL UNSPEC_FMUL
UNSPEC_FMULS UNSPEC_FMULS
UNSPEC_FMULSU UNSPEC_FMULSU
...@@ -142,7 +141,7 @@ ...@@ -142,7 +141,7 @@
tsthi, tstpsi, tstsi, compare, compare64, call, tsthi, tstpsi, tstsi, compare, compare64, call,
mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32, mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
ufract, sfract, ufract, sfract,
xload, movmem, load_lpm, xload, movmem,
ashlqi, ashrqi, lshrqi, ashlqi, ashrqi, lshrqi,
ashlhi, ashrhi, lshrhi, ashlhi, ashrhi, lshrhi,
ashlsi, ashrsi, lshrsi, ashlsi, ashrsi, lshrsi,
...@@ -393,60 +392,57 @@ ...@@ -393,60 +392,57 @@
;;======================================================================== ;;========================================================================
;; Move stuff around ;; Move stuff around
;; Represent a load from __flash that needs libgcc support as UNSPEC. ;; Secondary input reload from non-generic 16-bit address spaces
;; This is legal because we read from non-changing memory. (define_insn "reload_in<mode>"
;; For rationale see the FIXME below. [(set (match_operand:MOVMODE 0 "register_operand" "=r")
(match_operand:MOVMODE 1 "memory_operand" "m"))
;; "load_psi_libgcc" (clobber (match_operand:QI 2 "d_register_operand" "=d"))]
;; "load_si_libgcc" "MEM_P (operands[1])
;; "load_sf_libgcc" && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[1]))"
(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)"
{ {
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")]) (set_attr "cc" "clobber")])
;; Similar to above for the complementary situation when there is no [E]LPMx. ;; "loadqi_libgcc"
;; Clobber Z in that case. ;; "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" ;; "load_qi_libgcc"
[(set (match_operand:MOVMODE 0 "register_operand" "=r") ;; "load_hi_libgcc"
(unspec:MOVMODE [(reg:HI REG_Z) ;; "load_psi_libgcc"
(match_operand:QI 1 "reg_or_0_operand" "rL")] ;; "load_si_libgcc"
UNSPEC_LPM)) ;; "load_sf_libgcc"
(clobber (reg:HI REG_Z))] (define_insn "load_<mode>_libgcc"
"!((CONST_INT_P (operands[1]) && AVR_HAVE_LPMX) [(set (reg:MOVMODE 22)
|| (REG_P (operands[1]) && AVR_HAVE_ELPMX))" (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")]) (set_attr "cc" "clobber")])
...@@ -464,6 +460,10 @@ ...@@ -464,6 +460,10 @@
"&& 1" "&& 1"
[(clobber (const_int 0))] [(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 insn, addr = XEXP (operands[1], 0);
rtx hi8 = gen_reg_rtx (QImode); rtx hi8 = gen_reg_rtx (QImode);
rtx reg_z = gen_rtx_REG (HImode, REG_Z); rtx reg_z = gen_rtx_REG (HImode, REG_Z);
...@@ -583,72 +583,29 @@ ...@@ -583,72 +583,29 @@
operands[1] = src = copy_to_mode_reg (<MODE>mode, src); operands[1] = src = copy_to_mode_reg (<MODE>mode, src);
} }
if (avr_mem_memx_p (src)) if (avr_mem_memx_p (src))
{ {
rtx addr = XEXP (src, 0); 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;
}
/* 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)) if (!avr_xload_libgcc_p (<MODE>mode))
{ /* ; No <mode> here because gen_xload8<mode>_A only iterates over ALL1.
emit_move_insn (gen_rtx_REG (Pmode, REG_Z), ; insn-emit does not depend on the mode, it's all about operands. */
force_reg (Pmode, XEXP (src, 0))); 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; DONE;
} }
/* ; FIXME: Hack around PR rtl-optimization/52543. if (avr_load_libgcc_p (src))
; 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))
{ {
rtx xsegment = GEN_INT (avr_addrspace[MEM_ADDR_SPACE (src)].segment); /* For the small devices, do loads per libgcc call. */
if (!AVR_HAVE_ELPM) emit_insn (gen_load<mode>_libgcc (dest, src));
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));
DONE; DONE;
} }
/* ; The only address-space for which we use plain MEM and reload
; machinery are 1-byte loads from __flash. */
}) })
;;======================================================================== ;;========================================================================
...@@ -798,6 +755,40 @@ ...@@ -798,6 +755,40 @@
operands[5] = gen_rtx_REG (HImode, REGNO (operands[3])); 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) ;; xpointer move (24 bit)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment