Backport PRs 52148, 52461, 52484, 52488, 52496, 52499, 52505, 52506, 52507, 52508 and more
libgcc/ Backport from 2012-03-07 mainline r185033. PR target/52507 * config/avr/lib1funcs.S (__movmemx_hi): Fix loop label in RAM-part. Backport from 2012-03-07 mainline r185031. PR target/52505 * config/avr/lib1funcs.S (__xload_1): Don't read unintentionally from RAM. Backport from 2012-03-07 mainline r185030. PR target/52461 PR target/52508 * config/avr/lib1funcs.S (__do_copy_data): Clear RAMPZ after usage if RAMPZ affects reading from RAM. (__tablejump_elpm__): Ditto. (.xload): Ditto. (__movmemx_hi): Ditto. (__do_global_ctors): Right condition for RAMPZ usage is "have ELPM". (__do_global_dtors): Ditto. (__xload_1, __xload_2, __xload_3, __xload_4): Ditto. (__movmemx_hi): Ditto. gcc/ Backport from 2012-03-22 mainline r185692. PR target/52496 * config/avr/avr.md (unspec): Remove UNSPEC_MEMORY_BARRIER. (unspecv): Add UNSPECV_MEMORY_BARRIER. (cli_sei): Use unspec_volatile instead of unspec for memory barrier. (delay_cycles_1, delay_cycles_2): Ditto. (delay_cycles_3, delay_cycles_4): Ditto. (nopv, *nopv): Ditto. (sleep, *sleep): Ditto. (wdr, *wdr): Ditto. Backport from 2012-03-21 mainline r185605. PR rtl-optimization/52543 PR target/52461 * config/avr/avr-protos.h (avr_load_lpm): New prototype. * config/avr/avr.c (avr_mode_dependent_address_p): New function. (TARGET_MODE_DEPENDENT_ADDRESS_P): New define. (avr_load_libgcc_p): Restrict to __flash loads. (avr_out_lpm): Only handle 1-byte loads from __flash. (avr_load_lpm): New function. (avr_find_unused_d_reg): Remove. (avr_out_lpm_no_lpmx): Remove. (adjust_insn_length): Handle ADJUST_LEN_LOAD_LPM. * config/avr/avr.md (unspec): Add UNSPEC_LPM. (load_<mode>_libgcc): Use UNSPEC_LPM instead of MEM. (load_<mode>, load_<mode>_clobber): New insns. (mov<mode>): For multi-byte move from non-generic 16-bit address spaces: Expand to load_<mode> resp. load_<mode>_clobber. (load<mode>_libgcc): Remove expander. (split-lpmx): Remove split. Backport from 2012-03-13 mainline r185329. PR target/52488 * config/avr/avr.c (avr_prologue_setup_frame): Cut down stack offset (size) to a value the insns can deal with. (expand_epilogue): Ditto. Backport from 2012-03-12 mainline r185256. PR target/52499 * config/avr/avr.c (avr_mode_code_base_reg_class): Change return type from reg_class_t to enum reg_class. * config/avr/avr-protos.h (avr_mode_code_base_reg_class): Ditto. Backport from 2012-03-12 mainline r185253. PR target/52148 * config/avr/avr.c (avr_out_movmem): Fix typo in output template for the case ADDR_SPACE_FLASH and AVR_HAVE_LPMX introduced in r184615 from 2012-02-28. Backport from 2012-03-08 mainline r185105. * config/avr/avr.md (*addhi3, addhi3_clobber): Add "w" alternative for constants in [-63,63]. Backport from 2012-03-08 mainline r185100. PR target/52496 * config/avr/avr.c (avr_mem_clobber): New static function. (avr_expand_delay_cycles): Add memory clobber operand to delay_cycles_1, delay_cycles_2, delay_cycles_3, delay_cycles_4. * config/avr/avr.md (unspec): Add UNSPEC_MEMORY_BARRIER. (enable_interrupt, disable_interrupt): New expander. (nopv, sleep, wdr): New expanders. (delay_cycles_1): Add memory clobber. (delay_cycles_2): Add memory clobber. (delay_cycles_3): Add memory clobber. (delay_cycles_4): Add memory clobber. (cli_sei): New insn from former "enable_interrupt", "disable_interrupt" with memory clobber. (*wdt): New insn from former "wdt" with memory clobber. (*nopv): Similar, but for "nopv". (*sleep): Similar, but for "sleep". Backport from 2012-03-07 mainline r185043. PR target/52484 * config/avr/avr.md (xload<mode>_A): Add R22... to register footprint. Backport from 2012-03-07 mainline r185032. PR target/52506 * gcc/config/avr/avr.c (expand_epilogue): Fix order of restoration to: RAMPZ, RAMPY, RAMPX, RAMPD. (expand_prologue): Only clear RAMPZ if it has effect on RAM-read. Backport from 2012-03-07 mainline r185031. PR target/52505 * config/avr/avr.c (avr_out_xload): Don't read unintentionally from RAM. * config/avr/avr.md (xload_8): Adjust insn length. Backport from 2012-03-07 mainline r185030. PR target/52461 * gcc/config/avr/avr.c (avr_out_lpm): Clear RAMPZ after usage if RAMPZ affects reading from RAM. Backport from 2012-03-05 mainline r184919. * config/avr/avr.md (*umaddqihi4.2): New insn-and-split. From-SVN: r185697
This commit is contained in:
parent
c0aa57e4fb
commit
a8277c363f
110
gcc/ChangeLog
110
gcc/ChangeLog
|
@ -1,3 +1,113 @@
|
|||
2012-03-22 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
Backport from 2012-03-22 mainline r185692.
|
||||
|
||||
PR target/52496
|
||||
* config/avr/avr.md (unspec): Remove UNSPEC_MEMORY_BARRIER.
|
||||
(unspecv): Add UNSPECV_MEMORY_BARRIER.
|
||||
(cli_sei): Use unspec_volatile instead of unspec for memory barrier.
|
||||
(delay_cycles_1, delay_cycles_2): Ditto.
|
||||
(delay_cycles_3, delay_cycles_4): Ditto.
|
||||
(nopv, *nopv): Ditto.
|
||||
(sleep, *sleep): Ditto.
|
||||
(wdr, *wdr): Ditto.
|
||||
|
||||
Backport from 2012-03-21 mainline r185605.
|
||||
|
||||
PR rtl-optimization/52543
|
||||
PR target/52461
|
||||
* config/avr/avr-protos.h (avr_load_lpm): New prototype.
|
||||
* config/avr/avr.c (avr_mode_dependent_address_p): New function.
|
||||
(TARGET_MODE_DEPENDENT_ADDRESS_P): New define.
|
||||
(avr_load_libgcc_p): Restrict to __flash loads.
|
||||
(avr_out_lpm): Only handle 1-byte loads from __flash.
|
||||
(avr_load_lpm): New function.
|
||||
(avr_find_unused_d_reg): Remove.
|
||||
(avr_out_lpm_no_lpmx): Remove.
|
||||
(adjust_insn_length): Handle ADJUST_LEN_LOAD_LPM.
|
||||
* config/avr/avr.md (unspec): Add UNSPEC_LPM.
|
||||
(load_<mode>_libgcc): Use UNSPEC_LPM instead of MEM.
|
||||
(load_<mode>, load_<mode>_clobber): New insns.
|
||||
(mov<mode>): For multi-byte move from non-generic
|
||||
16-bit address spaces: Expand to load_<mode> resp.
|
||||
load_<mode>_clobber.
|
||||
(load<mode>_libgcc): Remove expander.
|
||||
(split-lpmx): Remove split.
|
||||
|
||||
Backport from 2012-03-13 mainline r185329.
|
||||
|
||||
PR target/52488
|
||||
* config/avr/avr.c (avr_prologue_setup_frame): Cut down stack
|
||||
offset (size) to a value the insns can deal with.
|
||||
(expand_epilogue): Ditto.
|
||||
|
||||
Backport from 2012-03-12 mainline r185256.
|
||||
|
||||
PR target/52499
|
||||
* config/avr/avr.c (avr_mode_code_base_reg_class): Change return
|
||||
type from reg_class_t to enum reg_class.
|
||||
* config/avr/avr-protos.h (avr_mode_code_base_reg_class): Ditto.
|
||||
|
||||
Backport from 2012-03-12 mainline r185253.
|
||||
|
||||
PR target/52148
|
||||
* config/avr/avr.c (avr_out_movmem): Fix typo in output template
|
||||
for the case ADDR_SPACE_FLASH and AVR_HAVE_LPMX introduced in
|
||||
r184615 from 2012-02-28.
|
||||
|
||||
Backport from 2012-03-08 mainline r185105.
|
||||
|
||||
* config/avr/avr.md (*addhi3, addhi3_clobber): Add "w" alternative
|
||||
for constants in [-63,63].
|
||||
|
||||
Backport from 2012-03-08 mainline r185100.
|
||||
|
||||
PR target/52496
|
||||
* config/avr/avr.c (avr_mem_clobber): New static function.
|
||||
(avr_expand_delay_cycles): Add memory clobber operand to
|
||||
delay_cycles_1, delay_cycles_2, delay_cycles_3, delay_cycles_4.
|
||||
* config/avr/avr.md (unspec): Add UNSPEC_MEMORY_BARRIER.
|
||||
(enable_interrupt, disable_interrupt): New expander.
|
||||
(nopv, sleep, wdr): New expanders.
|
||||
(delay_cycles_1): Add memory clobber.
|
||||
(delay_cycles_2): Add memory clobber.
|
||||
(delay_cycles_3): Add memory clobber.
|
||||
(delay_cycles_4): Add memory clobber.
|
||||
(cli_sei): New insn from former "enable_interrupt",
|
||||
"disable_interrupt" with memory clobber.
|
||||
(*wdt): New insn from former "wdt" with memory clobber.
|
||||
(*nopv): Similar, but for "nopv".
|
||||
(*sleep): Similar, but for "sleep".
|
||||
|
||||
Backport from 2012-03-07 mainline r185043.
|
||||
|
||||
PR target/52484
|
||||
* config/avr/avr.md (xload<mode>_A): Add R22... to register footprint.
|
||||
|
||||
Backport from 2012-03-07 mainline r185032.
|
||||
|
||||
PR target/52506
|
||||
* gcc/config/avr/avr.c (expand_epilogue): Fix order of restoration
|
||||
to: RAMPZ, RAMPY, RAMPX, RAMPD.
|
||||
(expand_prologue): Only clear RAMPZ if it has effect on RAM-read.
|
||||
|
||||
Backport from 2012-03-07 mainline r185031.
|
||||
|
||||
PR target/52505
|
||||
* config/avr/avr.c (avr_out_xload): Don't read unintentionally
|
||||
from RAM.
|
||||
* config/avr/avr.md (xload_8): Adjust insn length.
|
||||
|
||||
Backport from 2012-03-07 mainline r185030.
|
||||
|
||||
PR target/52461
|
||||
* gcc/config/avr/avr.c (avr_out_lpm): Clear RAMPZ after usage
|
||||
if RAMPZ affects reading from RAM.
|
||||
|
||||
Backport from 2012-03-05 mainline r184919.
|
||||
|
||||
* config/avr/avr.md (*umaddqihi4.2): New insn-and-split.
|
||||
|
||||
2012-03-22 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
Backport from mainline r185259.
|
||||
|
|
|
@ -75,6 +75,8 @@ extern const char *avr_out_ashlpsi3 (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_load_lpm (rtx, rtx*, int*);
|
||||
|
||||
extern bool avr_rotate_bytes (rtx operands[]);
|
||||
|
||||
extern void expand_prologue (void);
|
||||
|
@ -115,7 +117,7 @@ extern int avr_simplify_comparison_p (enum machine_mode mode,
|
|||
extern RTX_CODE avr_normalize_condition (RTX_CODE condition);
|
||||
extern void out_shift_with_cnt (const char *templ, rtx insn,
|
||||
rtx operands[], int *len, int t_len);
|
||||
extern reg_class_t avr_mode_code_base_reg_class (enum machine_mode, addr_space_t, RTX_CODE, RTX_CODE);
|
||||
extern enum reg_class avr_mode_code_base_reg_class (enum machine_mode, addr_space_t, RTX_CODE, RTX_CODE);
|
||||
extern bool avr_regno_mode_code_ok_for_base_p (int, enum machine_mode, addr_space_t, RTX_CODE, RTX_CODE);
|
||||
extern rtx avr_incoming_return_addr_rtx (void);
|
||||
extern rtx avr_legitimize_reload_address (rtx*, enum machine_mode, int, int, int, int, rtx (*)(rtx,int));
|
||||
|
|
|
@ -827,7 +827,11 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
|
|||
bool isr_p = cfun->machine->is_interrupt || cfun->machine->is_signal;
|
||||
int live_seq = sequent_regs_live ();
|
||||
|
||||
HOST_WIDE_INT size_max
|
||||
= (HOST_WIDE_INT) GET_MODE_MASK (AVR_HAVE_8BIT_SP ? QImode : Pmode);
|
||||
|
||||
bool minimize = (TARGET_CALL_PROLOGUES
|
||||
&& size < size_max
|
||||
&& live_seq
|
||||
&& !isr_p
|
||||
&& !cfun->machine->is_OS_task
|
||||
|
@ -933,6 +937,7 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
|
|||
leaf function and thus X has already been saved. */
|
||||
|
||||
int irq_state = -1;
|
||||
HOST_WIDE_INT size_cfa = size;
|
||||
rtx fp_plus_insns, fp, my_fp;
|
||||
|
||||
gcc_assert (frame_pointer_needed
|
||||
|
@ -951,6 +956,27 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
|
|||
my_fp = all_regs_rtx[FRAME_POINTER_REGNUM];
|
||||
}
|
||||
|
||||
/* Cut down size and avoid size = 0 so that we don't run
|
||||
into ICE like PR52488 in the remainder. */
|
||||
|
||||
if (size > size_max)
|
||||
{
|
||||
/* Don't error so that insane code from newlib still compiles
|
||||
and does not break building newlib. As PR51345 is implemented
|
||||
now, there are multilib variants with -mtiny-stack.
|
||||
|
||||
If user wants sanity checks he can use -Wstack-usage=
|
||||
or similar options.
|
||||
|
||||
For CFA we emit the original, non-saturated size so that
|
||||
the generic machinery is aware of the real stack usage and
|
||||
will print the above diagnostic as expected. */
|
||||
|
||||
size = size_max;
|
||||
}
|
||||
|
||||
size = trunc_int_for_mode (size, GET_MODE (my_fp));
|
||||
|
||||
/************ Method 1: Adjust frame pointer ************/
|
||||
|
||||
start_sequence ();
|
||||
|
@ -975,7 +1001,7 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
|
|||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
add_reg_note (insn, REG_CFA_ADJUST_CFA,
|
||||
gen_rtx_SET (VOIDmode, fp,
|
||||
plus_constant (fp, -size)));
|
||||
plus_constant (fp, -size_cfa)));
|
||||
}
|
||||
|
||||
/* Copy to stack pointer. Note that since we've already
|
||||
|
@ -1003,7 +1029,7 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
|
|||
add_reg_note (insn, REG_CFA_ADJUST_CFA,
|
||||
gen_rtx_SET (VOIDmode, stack_pointer_rtx,
|
||||
plus_constant (stack_pointer_rtx,
|
||||
-size)));
|
||||
-size_cfa)));
|
||||
}
|
||||
|
||||
fp_plus_insns = get_insns ();
|
||||
|
@ -1026,7 +1052,7 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
|
|||
add_reg_note (insn, REG_CFA_ADJUST_CFA,
|
||||
gen_rtx_SET (VOIDmode, stack_pointer_rtx,
|
||||
plus_constant (stack_pointer_rtx,
|
||||
-size)));
|
||||
-size_cfa)));
|
||||
if (frame_pointer_needed)
|
||||
{
|
||||
insn = emit_move_insn (fp, stack_pointer_rtx);
|
||||
|
@ -1048,7 +1074,7 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
|
|||
emit_insn (fp_plus_insns);
|
||||
}
|
||||
|
||||
cfun->machine->stack_usage += size;
|
||||
cfun->machine->stack_usage += size_cfa;
|
||||
} /* !minimize && size != 0 */
|
||||
} /* !minimize */
|
||||
}
|
||||
|
@ -1123,11 +1149,11 @@ expand_prologue (void)
|
|||
emit_push_sfr (rampy_rtx, false /* frame-related */, true /* clr */);
|
||||
}
|
||||
|
||||
if (AVR_HAVE_RAMPZ
|
||||
if (AVR_HAVE_RAMPZ
|
||||
&& TEST_HARD_REG_BIT (set, REG_Z)
|
||||
&& TEST_HARD_REG_BIT (set, REG_Z + 1))
|
||||
{
|
||||
emit_push_sfr (rampz_rtx, false /* frame-related */, true /* clr */);
|
||||
emit_push_sfr (rampz_rtx, false /* frame-related */, AVR_HAVE_RAMPD);
|
||||
}
|
||||
} /* is_interrupt is_signal */
|
||||
|
||||
|
@ -1261,6 +1287,7 @@ expand_epilogue (bool sibcall_p)
|
|||
int irq_state = -1;
|
||||
rtx fp, my_fp;
|
||||
rtx fp_plus_insns;
|
||||
HOST_WIDE_INT size_max;
|
||||
|
||||
gcc_assert (frame_pointer_needed
|
||||
|| !isr_p
|
||||
|
@ -1277,6 +1304,13 @@ expand_epilogue (bool sibcall_p)
|
|||
|
||||
my_fp = all_regs_rtx[FRAME_POINTER_REGNUM];
|
||||
}
|
||||
|
||||
/* For rationale see comment in prologue generation. */
|
||||
|
||||
size_max = (HOST_WIDE_INT) GET_MODE_MASK (GET_MODE (my_fp));
|
||||
if (size > size_max)
|
||||
size = size_max;
|
||||
size = trunc_int_for_mode (size, GET_MODE (my_fp));
|
||||
|
||||
/********** Method 1: Adjust fp register **********/
|
||||
|
||||
|
@ -1347,12 +1381,12 @@ expand_epilogue (bool sibcall_p)
|
|||
/* Restore RAMPZ/Y/X/D using tmp_reg as scratch.
|
||||
The conditions to restore them must be tha same as in prologue. */
|
||||
|
||||
if (AVR_HAVE_RAMPX
|
||||
&& TEST_HARD_REG_BIT (set, REG_X)
|
||||
&& TEST_HARD_REG_BIT (set, REG_X + 1))
|
||||
if (AVR_HAVE_RAMPZ
|
||||
&& TEST_HARD_REG_BIT (set, REG_Z)
|
||||
&& TEST_HARD_REG_BIT (set, REG_Z + 1))
|
||||
{
|
||||
emit_pop_byte (TMP_REGNO);
|
||||
emit_move_insn (rampx_rtx, tmp_reg_rtx);
|
||||
emit_move_insn (rampz_rtx, tmp_reg_rtx);
|
||||
}
|
||||
|
||||
if (AVR_HAVE_RAMPY
|
||||
|
@ -1364,12 +1398,12 @@ expand_epilogue (bool sibcall_p)
|
|||
emit_move_insn (rampy_rtx, tmp_reg_rtx);
|
||||
}
|
||||
|
||||
if (AVR_HAVE_RAMPZ
|
||||
&& TEST_HARD_REG_BIT (set, REG_Z)
|
||||
&& TEST_HARD_REG_BIT (set, REG_Z + 1))
|
||||
if (AVR_HAVE_RAMPX
|
||||
&& TEST_HARD_REG_BIT (set, REG_X)
|
||||
&& TEST_HARD_REG_BIT (set, REG_X + 1))
|
||||
{
|
||||
emit_pop_byte (TMP_REGNO);
|
||||
emit_move_insn (rampz_rtx, tmp_reg_rtx);
|
||||
emit_move_insn (rampx_rtx, tmp_reg_rtx);
|
||||
}
|
||||
|
||||
if (AVR_HAVE_RAMPD)
|
||||
|
@ -1423,6 +1457,22 @@ avr_cannot_modify_jumps_p (void)
|
|||
}
|
||||
|
||||
|
||||
/* Implement `TARGET_MODE_DEPENDENT_ADDRESS_P'. */
|
||||
|
||||
/* FIXME: PSImode addresses are not mode-dependent in themselves.
|
||||
This hook just serves to hack around PR rtl-optimization/52543 by
|
||||
claiming that PSImode addresses (which are used for the 24-bit
|
||||
address space __memx) were mode-dependent so that lower-subreg.s
|
||||
will skip these addresses. See also the similar FIXME comment along
|
||||
with mov<mode> expanders in avr.md. */
|
||||
|
||||
static bool
|
||||
avr_mode_dependent_address_p (const_rtx addr)
|
||||
{
|
||||
return GET_MODE (addr) != Pmode;
|
||||
}
|
||||
|
||||
|
||||
/* Helper function for `avr_legitimate_address_p'. */
|
||||
|
||||
static inline bool
|
||||
|
@ -2435,7 +2485,8 @@ avr_load_libgcc_p (rtx op)
|
|||
|
||||
return (n_bytes > 2
|
||||
&& !AVR_HAVE_LPMX
|
||||
&& avr_mem_flash_p (op));
|
||||
&& MEM_P (op)
|
||||
&& MEM_ADDR_SPACE (op) == ADDR_SPACE_FLASH);
|
||||
}
|
||||
|
||||
/* Return true if a value of mode MODE is read by __xload_* function. */
|
||||
|
@ -2450,155 +2501,6 @@ avr_xload_libgcc_p (enum machine_mode mode)
|
|||
}
|
||||
|
||||
|
||||
/* Find an unused d-register to be used as scratch in INSN.
|
||||
EXCLUDE is either NULL_RTX or some register. In the case where EXCLUDE
|
||||
is a register, skip all possible return values that overlap EXCLUDE.
|
||||
The policy for the returned register is similar to that of
|
||||
`reg_unused_after', i.e. the returned register may overlap the SET_DEST
|
||||
of INSN.
|
||||
|
||||
Return a QImode d-register or NULL_RTX if nothing found. */
|
||||
|
||||
static rtx
|
||||
avr_find_unused_d_reg (rtx insn, rtx exclude)
|
||||
{
|
||||
int regno;
|
||||
bool isr_p = (interrupt_function_p (current_function_decl)
|
||||
|| signal_function_p (current_function_decl));
|
||||
|
||||
for (regno = 16; regno < 32; regno++)
|
||||
{
|
||||
rtx reg = all_regs_rtx[regno];
|
||||
|
||||
if ((exclude
|
||||
&& reg_overlap_mentioned_p (exclude, reg))
|
||||
|| fixed_regs[regno])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try non-live register */
|
||||
|
||||
if (!df_regs_ever_live_p (regno)
|
||||
&& (TREE_THIS_VOLATILE (current_function_decl)
|
||||
|| cfun->machine->is_OS_task
|
||||
|| cfun->machine->is_OS_main
|
||||
|| (!isr_p && call_used_regs[regno])))
|
||||
{
|
||||
return reg;
|
||||
}
|
||||
|
||||
/* Any live register can be used if it is unused after.
|
||||
Prologue/epilogue will care for it as needed. */
|
||||
|
||||
if (df_regs_ever_live_p (regno)
|
||||
&& reg_unused_after (insn, reg))
|
||||
{
|
||||
return reg;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
|
||||
/* Helper function for the next function in the case where only restricted
|
||||
version of LPM instruction is available. */
|
||||
|
||||
static const char*
|
||||
avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen)
|
||||
{
|
||||
rtx dest = xop[0];
|
||||
rtx addr = xop[1];
|
||||
int n_bytes = GET_MODE_SIZE (GET_MODE (dest));
|
||||
int regno_dest;
|
||||
|
||||
regno_dest = REGNO (dest);
|
||||
|
||||
/* The implicit target register of LPM. */
|
||||
xop[3] = lpm_reg_rtx;
|
||||
|
||||
switch (GET_CODE (addr))
|
||||
{
|
||||
default:
|
||||
gcc_unreachable();
|
||||
|
||||
case REG:
|
||||
|
||||
gcc_assert (REG_Z == REGNO (addr));
|
||||
|
||||
switch (n_bytes)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable();
|
||||
|
||||
case 1:
|
||||
avr_asm_len ("%4lpm", xop, plen, 1);
|
||||
|
||||
if (regno_dest != LPM_REGNO)
|
||||
avr_asm_len ("mov %0,%3", xop, plen, 1);
|
||||
|
||||
return "";
|
||||
|
||||
case 2:
|
||||
if (REGNO (dest) == REG_Z)
|
||||
return avr_asm_len ("%4lpm" CR_TAB
|
||||
"push %3" CR_TAB
|
||||
"adiw %2,1" CR_TAB
|
||||
"%4lpm" CR_TAB
|
||||
"mov %B0,%3" CR_TAB
|
||||
"pop %A0", xop, plen, 6);
|
||||
|
||||
avr_asm_len ("%4lpm" CR_TAB
|
||||
"mov %A0,%3" CR_TAB
|
||||
"adiw %2,1" CR_TAB
|
||||
"%4lpm" CR_TAB
|
||||
"mov %B0,%3", xop, plen, 5);
|
||||
|
||||
if (!reg_unused_after (insn, addr))
|
||||
avr_asm_len ("sbiw %2,1", xop, plen, 1);
|
||||
|
||||
break; /* 2 */
|
||||
}
|
||||
|
||||
break; /* REG */
|
||||
|
||||
case POST_INC:
|
||||
|
||||
gcc_assert (REG_Z == REGNO (XEXP (addr, 0))
|
||||
&& n_bytes <= 4);
|
||||
|
||||
if (regno_dest == LPM_REGNO)
|
||||
avr_asm_len ("%4lpm" CR_TAB
|
||||
"adiw %2,1", xop, plen, 2);
|
||||
else
|
||||
avr_asm_len ("%4lpm" CR_TAB
|
||||
"mov %A0,%3" CR_TAB
|
||||
"adiw %2,1", xop, plen, 3);
|
||||
|
||||
if (n_bytes >= 2)
|
||||
avr_asm_len ("%4lpm" CR_TAB
|
||||
"mov %B0,%3" CR_TAB
|
||||
"adiw %2,1", xop, plen, 3);
|
||||
|
||||
if (n_bytes >= 3)
|
||||
avr_asm_len ("%4lpm" CR_TAB
|
||||
"mov %C0,%3" CR_TAB
|
||||
"adiw %2,1", xop, plen, 3);
|
||||
|
||||
if (n_bytes >= 4)
|
||||
avr_asm_len ("%4lpm" CR_TAB
|
||||
"mov %D0,%3" CR_TAB
|
||||
"adiw %2,1", xop, plen, 3);
|
||||
|
||||
break; /* POST_INC */
|
||||
|
||||
} /* switch CODE (addr) */
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/* If PLEN == NULL: Ouput instructions to load a value from a memory location
|
||||
OP[1] in AS1 to register OP[0].
|
||||
If PLEN != 0 set *PLEN to the length in words of the instruction sequence.
|
||||
|
@ -2607,13 +2509,11 @@ avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen)
|
|||
static const char*
|
||||
avr_out_lpm (rtx insn, rtx *op, int *plen)
|
||||
{
|
||||
rtx xop[6];
|
||||
rtx xop[3];
|
||||
rtx dest = op[0];
|
||||
rtx src = SET_SRC (single_set (insn));
|
||||
rtx addr;
|
||||
int n_bytes = GET_MODE_SIZE (GET_MODE (dest));
|
||||
int regno_dest;
|
||||
int segment;
|
||||
RTX_CODE code;
|
||||
addr_space_t as = MEM_ADDR_SPACE (src);
|
||||
|
||||
|
@ -2634,55 +2534,18 @@ avr_out_lpm (rtx insn, rtx *op, int *plen)
|
|||
gcc_assert (REG_P (dest));
|
||||
gcc_assert (REG == code || POST_INC == code);
|
||||
|
||||
/* Only 1-byte moves from __flash are representes as open coded
|
||||
mov insns. All other loads from flash are not handled here but
|
||||
by some UNSPEC instead, see respective FIXME in machine description. */
|
||||
|
||||
gcc_assert (as == ADDR_SPACE_FLASH);
|
||||
gcc_assert (n_bytes == 1);
|
||||
|
||||
xop[0] = dest;
|
||||
xop[1] = addr;
|
||||
xop[2] = lpm_addr_reg_rtx;
|
||||
xop[4] = xstring_empty;
|
||||
xop[5] = tmp_reg_rtx;
|
||||
xop[1] = lpm_addr_reg_rtx;
|
||||
xop[2] = lpm_reg_rtx;
|
||||
|
||||
regno_dest = REGNO (dest);
|
||||
|
||||
segment = avr_addrspace[as].segment;
|
||||
|
||||
/* Set RAMPZ as needed. */
|
||||
|
||||
if (segment)
|
||||
{
|
||||
xop[4] = GEN_INT (segment);
|
||||
|
||||
if (xop[3] = avr_find_unused_d_reg (insn, lpm_addr_reg_rtx),
|
||||
xop[3])
|
||||
{
|
||||
avr_asm_len ("ldi %3,%4" CR_TAB
|
||||
"out __RAMPZ__,%3", xop, plen, 2);
|
||||
}
|
||||
else if (segment == 1)
|
||||
{
|
||||
avr_asm_len ("clr %5" CR_TAB
|
||||
"inc %5" CR_TAB
|
||||
"out __RAMPZ__,%5", xop, plen, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
avr_asm_len ("mov %5,%2" CR_TAB
|
||||
"ldi %2,%4" CR_TAB
|
||||
"out __RAMPZ__,%2" CR_TAB
|
||||
"mov %2,%5", xop, plen, 4);
|
||||
}
|
||||
|
||||
xop[4] = xstring_e;
|
||||
|
||||
if (!AVR_HAVE_ELPMX)
|
||||
return avr_out_lpm_no_lpmx (insn, xop, plen);
|
||||
}
|
||||
else if (!AVR_HAVE_LPMX)
|
||||
{
|
||||
return avr_out_lpm_no_lpmx (insn, xop, plen);
|
||||
}
|
||||
|
||||
/* We have [E]LPMX: Output reading from Flash the comfortable way. */
|
||||
|
||||
switch (GET_CODE (addr))
|
||||
switch (code)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable();
|
||||
|
@ -2690,79 +2553,107 @@ avr_out_lpm (rtx insn, rtx *op, int *plen)
|
|||
case REG:
|
||||
|
||||
gcc_assert (REG_Z == REGNO (addr));
|
||||
|
||||
switch (n_bytes)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable();
|
||||
|
||||
case 1:
|
||||
return avr_asm_len ("%4lpm %0,%a2", xop, plen, 1);
|
||||
|
||||
case 2:
|
||||
if (REGNO (dest) == REG_Z)
|
||||
return avr_asm_len ("%4lpm %5,%a2+" CR_TAB
|
||||
"%4lpm %B0,%a2" CR_TAB
|
||||
"mov %A0,%5", xop, plen, 3);
|
||||
else
|
||||
{
|
||||
avr_asm_len ("%4lpm %A0,%a2+" CR_TAB
|
||||
"%4lpm %B0,%a2", xop, plen, 2);
|
||||
|
||||
if (!reg_unused_after (insn, addr))
|
||||
avr_asm_len ("sbiw %2,1", xop, plen, 1);
|
||||
}
|
||||
|
||||
break; /* 2 */
|
||||
|
||||
case 3:
|
||||
|
||||
avr_asm_len ("%4lpm %A0,%a2+" CR_TAB
|
||||
"%4lpm %B0,%a2+" CR_TAB
|
||||
"%4lpm %C0,%a2", xop, plen, 3);
|
||||
|
||||
if (!reg_unused_after (insn, addr))
|
||||
avr_asm_len ("sbiw %2,2", xop, plen, 1);
|
||||
|
||||
break; /* 3 */
|
||||
|
||||
case 4:
|
||||
|
||||
avr_asm_len ("%4lpm %A0,%a2+" CR_TAB
|
||||
"%4lpm %B0,%a2+", xop, plen, 2);
|
||||
|
||||
if (REGNO (dest) == REG_Z - 2)
|
||||
return avr_asm_len ("%4lpm %5,%a2+" CR_TAB
|
||||
"%4lpm %C0,%a2" CR_TAB
|
||||
"mov %D0,%5", xop, plen, 3);
|
||||
else
|
||||
{
|
||||
avr_asm_len ("%4lpm %C0,%a2+" CR_TAB
|
||||
"%4lpm %D0,%a2", xop, plen, 2);
|
||||
|
||||
if (!reg_unused_after (insn, addr))
|
||||
avr_asm_len ("sbiw %2,3", xop, plen, 1);
|
||||
}
|
||||
|
||||
break; /* 4 */
|
||||
} /* n_bytes */
|
||||
return AVR_HAVE_LPMX
|
||||
? avr_asm_len ("lpm %0,%a1", xop, plen, 1)
|
||||
: avr_asm_len ("lpm" CR_TAB
|
||||
"mov %0,%2", xop, plen, 2);
|
||||
|
||||
break; /* REG */
|
||||
|
||||
case POST_INC:
|
||||
|
||||
gcc_assert (REG_Z == REGNO (XEXP (addr, 0))
|
||||
&& n_bytes <= 4);
|
||||
|
||||
avr_asm_len ("%4lpm %A0,%a2+", xop, plen, 1);
|
||||
if (n_bytes >= 2) avr_asm_len ("%4lpm %B0,%a2+", xop, plen, 1);
|
||||
if (n_bytes >= 3) avr_asm_len ("%4lpm %C0,%a2+", xop, plen, 1);
|
||||
if (n_bytes >= 4) avr_asm_len ("%4lpm %D0,%a2+", xop, plen, 1);
|
||||
|
||||
break; /* POST_INC */
|
||||
|
||||
} /* switch CODE (addr) */
|
||||
|
||||
gcc_assert (REG_Z == REGNO (XEXP (addr, 0)));
|
||||
|
||||
return AVR_HAVE_LPMX
|
||||
? avr_asm_len ("lpm %0,%a1+", xop, plen, 1)
|
||||
: avr_asm_len ("lpm" CR_TAB
|
||||
"adiw %1, 1" CR_TAB
|
||||
"mov %0,%2", xop, plen, 3);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/* If PLEN == NULL: Ouput instructions to load $0 with a value from
|
||||
flash address $1:Z. If $1 = 0 we can use LPM to read, otherwise
|
||||
use ELPM.
|
||||
If PLEN != 0 set *PLEN to the length in words of the instruction sequence.
|
||||
Return "". */
|
||||
|
||||
const char*
|
||||
avr_load_lpm (rtx insn, rtx *op, int *plen)
|
||||
{
|
||||
rtx xop[4];
|
||||
int n, n_bytes = GET_MODE_SIZE (GET_MODE (op[0]));
|
||||
rtx xsegment = op[1];
|
||||
bool clobber_z = PARALLEL == GET_CODE (PATTERN (insn));
|
||||
bool r30_in_tmp = false;
|
||||
|
||||
if (plen)
|
||||
*plen = 0;
|
||||
|
||||
xop[1] = lpm_addr_reg_rtx;
|
||||
xop[2] = lpm_reg_rtx;
|
||||
xop[3] = xstring_empty;
|
||||
|
||||
/* Set RAMPZ as needed. */
|
||||
|
||||
if (REG_P (xsegment))
|
||||
{
|
||||
avr_asm_len ("out __RAMPZ__,%0", &xsegment, plen, 1);
|
||||
xop[3] = xstring_e;
|
||||
}
|
||||
|
||||
/* Load the individual bytes from LSB to MSB. */
|
||||
|
||||
for (n = 0; n < n_bytes; n++)
|
||||
{
|
||||
xop[0] = all_regs_rtx[REGNO (op[0]) + n];
|
||||
|
||||
if ((CONST_INT_P (xsegment) && AVR_HAVE_LPMX)
|
||||
|| (REG_P (xsegment) && AVR_HAVE_ELPMX))
|
||||
{
|
||||
if (n == n_bytes-1)
|
||||
avr_asm_len ("%3lpm %0,%a1", xop, plen, 1);
|
||||
else if (REGNO (xop[0]) == REG_Z)
|
||||
{
|
||||
avr_asm_len ("%3lpm %2,%a1+", xop, plen, 1);
|
||||
r30_in_tmp = true;
|
||||
}
|
||||
else
|
||||
avr_asm_len ("%3lpm %0,%a1+", xop, plen, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
gcc_assert (clobber_z);
|
||||
|
||||
avr_asm_len ("%3lpm" CR_TAB
|
||||
"mov %0,%2", xop, plen, 2);
|
||||
|
||||
if (n != n_bytes-1)
|
||||
avr_asm_len ("adiw %1,1", xop, plen, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (r30_in_tmp)
|
||||
avr_asm_len ("mov %1,%2", xop, plen, 1);
|
||||
|
||||
if (!clobber_z
|
||||
&& n_bytes > 1
|
||||
&& !reg_unused_after (insn, lpm_addr_reg_rtx)
|
||||
&& !reg_overlap_mentioned_p (op[0], lpm_addr_reg_rtx))
|
||||
{
|
||||
xop[2] = GEN_INT (n_bytes-1);
|
||||
avr_asm_len ("sbiw %1,%2", xop, plen, 1);
|
||||
}
|
||||
|
||||
if (REG_P (xsegment) && AVR_HAVE_RAMPD)
|
||||
{
|
||||
/* Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM */
|
||||
|
||||
avr_asm_len ("out __RAMPZ__,__zero_reg__", xop, plen, 1);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -2782,8 +2673,9 @@ avr_out_xload (rtx insn ATTRIBUTE_UNUSED, rtx *op, int *plen)
|
|||
if (plen)
|
||||
*plen = 0;
|
||||
|
||||
avr_asm_len ("ld %3,%a2" CR_TAB
|
||||
"sbrs %1,7", xop, plen, 2);
|
||||
avr_asm_len ("sbrc %1,7" CR_TAB
|
||||
"ld %3,%a2" CR_TAB
|
||||
"sbrs %1,7", xop, plen, 3);
|
||||
|
||||
avr_asm_len (AVR_HAVE_LPMX ? "lpm %3,%a2" : "lpm", xop, plen, 1);
|
||||
|
||||
|
@ -2794,13 +2686,11 @@ avr_out_xload (rtx insn ATTRIBUTE_UNUSED, rtx *op, int *plen)
|
|||
}
|
||||
|
||||
|
||||
const char *
|
||||
output_movqi (rtx insn, rtx operands[], int *l)
|
||||
const char*
|
||||
output_movqi (rtx insn, rtx operands[], int *real_l)
|
||||
{
|
||||
int dummy;
|
||||
rtx dest = operands[0];
|
||||
rtx src = operands[1];
|
||||
int *real_l = l;
|
||||
|
||||
if (avr_mem_flash_p (src)
|
||||
|| avr_mem_flash_p (dest))
|
||||
|
@ -2808,10 +2698,8 @@ output_movqi (rtx insn, rtx operands[], int *l)
|
|||
return avr_out_lpm (insn, operands, real_l);
|
||||
}
|
||||
|
||||
if (!l)
|
||||
l = &dummy;
|
||||
|
||||
*l = 1;
|
||||
if (real_l)
|
||||
*real_l = 1;
|
||||
|
||||
if (register_operand (dest, QImode))
|
||||
{
|
||||
|
@ -2829,10 +2717,10 @@ output_movqi (rtx insn, rtx operands[], int *l)
|
|||
output_reload_in_const (operands, NULL_RTX, real_l, false);
|
||||
return "";
|
||||
}
|
||||
else if (GET_CODE (src) == MEM)
|
||||
else if (MEM_P (src))
|
||||
return out_movqi_r_mr (insn, operands, real_l); /* mov r,m */
|
||||
}
|
||||
else if (GET_CODE (dest) == MEM)
|
||||
else if (MEM_P (dest))
|
||||
{
|
||||
rtx xop[2];
|
||||
|
||||
|
@ -6533,6 +6421,7 @@ adjust_insn_length (rtx insn, int len)
|
|||
case ADJUST_LEN_MOV32: output_movsisf (insn, op, &len); break;
|
||||
case ADJUST_LEN_MOVMEM: avr_out_movmem (insn, op, &len); break;
|
||||
case ADJUST_LEN_XLOAD: avr_out_xload (insn, op, &len); break;
|
||||
case ADJUST_LEN_LOAD_LPM: avr_load_lpm (insn, op, &len); break;
|
||||
|
||||
case ADJUST_LEN_TSTHI: avr_out_tsthi (insn, op, &len); break;
|
||||
case ADJUST_LEN_TSTPSI: avr_out_tstpsi (insn, op, &len); break;
|
||||
|
@ -8975,7 +8864,7 @@ avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
|
|||
|
||||
/* Implement `MODE_CODE_BASE_REG_CLASS'. */
|
||||
|
||||
reg_class_t
|
||||
enum reg_class
|
||||
avr_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
|
||||
addr_space_t as, RTX_CODE outer_code,
|
||||
RTX_CODE index_code ATTRIBUTE_UNUSED)
|
||||
|
@ -9568,7 +9457,8 @@ avr_addr_space_pointer_mode (addr_space_t as)
|
|||
static bool
|
||||
avr_reg_ok_for_pgm_addr (rtx reg, bool strict)
|
||||
{
|
||||
gcc_assert (REG_P (reg));
|
||||
if (!REG_P (reg))
|
||||
return false;
|
||||
|
||||
if (strict)
|
||||
{
|
||||
|
@ -9916,7 +9806,7 @@ avr_out_movmem (rtx insn ATTRIBUTE_UNUSED, rtx *op, int *plen)
|
|||
case ADDR_SPACE_FLASH:
|
||||
|
||||
if (AVR_HAVE_LPMX)
|
||||
avr_asm_len ("lpm %2,%Z+", xop, plen, 1);
|
||||
avr_asm_len ("lpm %2,Z+", xop, plen, 1);
|
||||
else
|
||||
avr_asm_len ("lpm" CR_TAB
|
||||
"adiw r30,1", xop, plen, 2);
|
||||
|
@ -9965,6 +9855,14 @@ avr_out_movmem (rtx insn ATTRIBUTE_UNUSED, rtx *op, int *plen)
|
|||
|
||||
/* Helper for __builtin_avr_delay_cycles */
|
||||
|
||||
static rtx
|
||||
avr_mem_clobber (void)
|
||||
{
|
||||
rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
|
||||
MEM_VOLATILE_P (mem) = 1;
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void
|
||||
avr_expand_delay_cycles (rtx operands0)
|
||||
{
|
||||
|
@ -9976,7 +9874,8 @@ avr_expand_delay_cycles (rtx operands0)
|
|||
{
|
||||
loop_count = ((cycles - 9) / 6) + 1;
|
||||
cycles_used = ((loop_count - 1) * 6) + 9;
|
||||
emit_insn (gen_delay_cycles_4 (gen_int_mode (loop_count, SImode)));
|
||||
emit_insn (gen_delay_cycles_4 (gen_int_mode (loop_count, SImode),
|
||||
avr_mem_clobber()));
|
||||
cycles -= cycles_used;
|
||||
}
|
||||
|
||||
|
@ -9986,7 +9885,8 @@ avr_expand_delay_cycles (rtx operands0)
|
|||
if (loop_count > 0xFFFFFF)
|
||||
loop_count = 0xFFFFFF;
|
||||
cycles_used = ((loop_count - 1) * 5) + 7;
|
||||
emit_insn (gen_delay_cycles_3 (gen_int_mode (loop_count, SImode)));
|
||||
emit_insn (gen_delay_cycles_3 (gen_int_mode (loop_count, SImode),
|
||||
avr_mem_clobber()));
|
||||
cycles -= cycles_used;
|
||||
}
|
||||
|
||||
|
@ -9996,7 +9896,8 @@ avr_expand_delay_cycles (rtx operands0)
|
|||
if (loop_count > 0xFFFF)
|
||||
loop_count = 0xFFFF;
|
||||
cycles_used = ((loop_count - 1) * 4) + 5;
|
||||
emit_insn (gen_delay_cycles_2 (gen_int_mode (loop_count, HImode)));
|
||||
emit_insn (gen_delay_cycles_2 (gen_int_mode (loop_count, HImode),
|
||||
avr_mem_clobber()));
|
||||
cycles -= cycles_used;
|
||||
}
|
||||
|
||||
|
@ -10006,7 +9907,8 @@ avr_expand_delay_cycles (rtx operands0)
|
|||
if (loop_count > 255)
|
||||
loop_count = 255;
|
||||
cycles_used = loop_count * 3;
|
||||
emit_insn (gen_delay_cycles_1 (gen_int_mode (loop_count, QImode)));
|
||||
emit_insn (gen_delay_cycles_1 (gen_int_mode (loop_count, QImode),
|
||||
avr_mem_clobber()));
|
||||
cycles -= cycles_used;
|
||||
}
|
||||
|
||||
|
@ -11007,6 +10909,9 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg,
|
|||
#undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS
|
||||
#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS avr_addr_space_legitimize_address
|
||||
|
||||
#undef TARGET_MODE_DEPENDENT_ADDRESS_P
|
||||
#define TARGET_MODE_DEPENDENT_ADDRESS_P avr_mode_dependent_address_p
|
||||
|
||||
#undef TARGET_PRINT_OPERAND
|
||||
#define TARGET_PRINT_OPERAND avr_print_operand
|
||||
#undef TARGET_PRINT_OPERAND_ADDRESS
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
[UNSPEC_STRLEN
|
||||
UNSPEC_MOVMEM
|
||||
UNSPEC_INDEX_JMP
|
||||
UNSPEC_LPM
|
||||
UNSPEC_FMUL
|
||||
UNSPEC_FMULS
|
||||
UNSPEC_FMULSU
|
||||
|
@ -77,6 +78,7 @@
|
|||
UNSPECV_WRITE_SP
|
||||
UNSPECV_GOTO_RECEIVER
|
||||
UNSPECV_ENABLE_IRQS
|
||||
UNSPECV_MEMORY_BARRIER
|
||||
UNSPECV_NOP
|
||||
UNSPECV_SLEEP
|
||||
UNSPECV_WDR
|
||||
|
@ -139,7 +141,7 @@
|
|||
"out_bitop, out_plus, out_plus_noclobber, plus64, addto_sp,
|
||||
tsthi, tstpsi, tstsi, compare, compare64, call,
|
||||
mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
|
||||
xload, movmem,
|
||||
xload, movmem, load_lpm,
|
||||
ashlqi, ashrqi, lshrqi,
|
||||
ashlhi, ashrhi, lshrhi,
|
||||
ashlsi, ashrsi, lshrsi,
|
||||
|
@ -363,33 +365,60 @@
|
|||
;;========================================================================
|
||||
;; Move stuff around
|
||||
|
||||
(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);
|
||||
})
|
||||
|
||||
;; 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)
|
||||
(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))"
|
||||
(unspec:MOVMODE [(reg:HI REG_Z)]
|
||||
UNSPEC_LPM))]
|
||||
""
|
||||
{
|
||||
operands[0] = GEN_INT (GET_MODE_SIZE (<MODE>mode));
|
||||
return "%~call __load_%0";
|
||||
rtx n_bytes = GEN_INT (GET_MODE_SIZE (<MODE>mode));
|
||||
output_asm_insn ("%~call __load_%0", &n_bytes);
|
||||
return "";
|
||||
}
|
||||
[(set_attr "length" "1,2")
|
||||
(set_attr "isa" "rjmp,jmp")
|
||||
[(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);
|
||||
}
|
||||
[(set_attr "adjust_len" "load_lpm")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
|
||||
;; Similar to above for the complementary situation when there is no [E]LPMx.
|
||||
;; Clobber Z in that case.
|
||||
|
||||
(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))"
|
||||
{
|
||||
return avr_load_lpm (insn, operands, NULL);
|
||||
}
|
||||
[(set_attr "adjust_len" "load_lpm")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
|
||||
|
@ -418,9 +447,15 @@
|
|||
DONE;
|
||||
})
|
||||
|
||||
;; "xloadqi_A"
|
||||
;; "xloadhi_A"
|
||||
;; "xloadpsi_A"
|
||||
;; "xloadsi_A"
|
||||
;; "xloadsf_A"
|
||||
(define_insn_and_split "xload<mode>_A"
|
||||
[(set (match_operand:MOVMODE 0 "register_operand" "=r")
|
||||
(match_operand:MOVMODE 1 "memory_operand" "m"))
|
||||
(clobber (reg:MOVMODE 22))
|
||||
(clobber (reg:QI 21))
|
||||
(clobber (reg:HI REG_Z))]
|
||||
"can_create_pseudo_p()
|
||||
|
@ -461,7 +496,7 @@
|
|||
{
|
||||
return avr_out_xload (insn, operands, NULL);
|
||||
}
|
||||
[(set_attr "length" "3,4")
|
||||
[(set_attr "length" "4,4")
|
||||
(set_attr "adjust_len" "*,xload")
|
||||
(set_attr "isa" "lpmx,lpm")
|
||||
(set_attr "cc" "none")])
|
||||
|
@ -532,12 +567,55 @@
|
|||
DONE;
|
||||
}
|
||||
|
||||
/* For old devices without LPMx, prefer __flash loads per libcall. */
|
||||
|
||||
if (avr_load_libgcc_p (src))
|
||||
{
|
||||
/* For the small devices, do loads per libgcc call. */
|
||||
emit_insn (gen_load<mode>_libgcc (dest, src));
|
||||
emit_move_insn (gen_rtx_REG (Pmode, REG_Z),
|
||||
force_reg (Pmode, XEXP (src, 0)));
|
||||
|
||||
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))
|
||||
{
|
||||
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));
|
||||
DONE;
|
||||
}
|
||||
|
||||
/* ; The only address-space for which we use plain MEM and reload
|
||||
; machinery are 1-byte loads from __flash. */
|
||||
})
|
||||
|
||||
;;========================================================================
|
||||
|
@ -677,40 +755,6 @@
|
|||
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)
|
||||
|
||||
|
@ -1081,15 +1125,16 @@
|
|||
(set_attr "adjust_len" "addto_sp")])
|
||||
|
||||
(define_insn "*addhi3"
|
||||
[(set (match_operand:HI 0 "register_operand" "=r,d,d")
|
||||
(plus:HI (match_operand:HI 1 "register_operand" "%0,0,0")
|
||||
(match_operand:HI 2 "nonmemory_operand" "r,s,n")))]
|
||||
[(set (match_operand:HI 0 "register_operand" "=r,d,!w,d")
|
||||
(plus:HI (match_operand:HI 1 "register_operand" "%0,0,0 ,0")
|
||||
(match_operand:HI 2 "nonmemory_operand" "r,s,IJ,n")))]
|
||||
""
|
||||
{
|
||||
static const char * const asm_code[] =
|
||||
{
|
||||
"add %A0,%A2\;adc %B0,%B2",
|
||||
"subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))",
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
|
@ -1098,9 +1143,9 @@
|
|||
|
||||
return avr_out_plus_noclobber (operands, NULL, NULL);
|
||||
}
|
||||
[(set_attr "length" "2,2,2")
|
||||
(set_attr "adjust_len" "*,*,out_plus_noclobber")
|
||||
(set_attr "cc" "set_n,set_czn,out_plus_noclobber")])
|
||||
[(set_attr "length" "2,2,2,2")
|
||||
(set_attr "adjust_len" "*,*,out_plus_noclobber,out_plus_noclobber")
|
||||
(set_attr "cc" "set_n,set_czn,out_plus_noclobber,out_plus_noclobber")])
|
||||
|
||||
;; Adding a constant to NO_LD_REGS might have lead to a reload of
|
||||
;; that constant to LD_REGS. We don't add a scratch to *addhi3
|
||||
|
@ -1138,10 +1183,10 @@
|
|||
(clobber (match_dup 2))])])
|
||||
|
||||
(define_insn "addhi3_clobber"
|
||||
[(set (match_operand:HI 0 "register_operand" "=d,l")
|
||||
(plus:HI (match_operand:HI 1 "register_operand" "%0,0")
|
||||
(match_operand:HI 2 "const_int_operand" "n,n")))
|
||||
(clobber (match_scratch:QI 3 "=X,&d"))]
|
||||
[(set (match_operand:HI 0 "register_operand" "=!w,d,r")
|
||||
(plus:HI (match_operand:HI 1 "register_operand" "%0,0,0")
|
||||
(match_operand:HI 2 "const_int_operand" "IJ,n,n")))
|
||||
(clobber (match_scratch:QI 3 "=X,X,&d"))]
|
||||
""
|
||||
{
|
||||
gcc_assert (REGNO (operands[0]) == REGNO (operands[1]));
|
||||
|
@ -1692,6 +1737,29 @@
|
|||
|
||||
;; Handle small constants
|
||||
|
||||
;; Special case of a += 2*b as frequently seen with accesses to int arrays.
|
||||
;; This is shorter, faster than MUL and has lower register pressure.
|
||||
|
||||
(define_insn_and_split "*umaddqihi4.2"
|
||||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||||
(plus:HI (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r"))
|
||||
(const_int 2))
|
||||
(match_operand:HI 2 "register_operand" "r")))]
|
||||
"!reload_completed
|
||||
&& !reg_overlap_mentioned_p (operands[0], operands[1])"
|
||||
{ gcc_unreachable(); }
|
||||
"&& 1"
|
||||
[(set (match_dup 0)
|
||||
(match_dup 2))
|
||||
; *addhi3_zero_extend
|
||||
(set (match_dup 0)
|
||||
(plus:HI (zero_extend:HI (match_dup 1))
|
||||
(match_dup 0)))
|
||||
; *addhi3_zero_extend
|
||||
(set (match_dup 0)
|
||||
(plus:HI (zero_extend:HI (match_dup 1))
|
||||
(match_dup 0)))])
|
||||
|
||||
;; "umaddqihi4.uconst"
|
||||
;; "maddqihi4.sconst"
|
||||
(define_insn_and_split "*<extend_u>maddqihi4.<extend_su>const"
|
||||
|
@ -5198,18 +5266,36 @@
|
|||
(set_attr "length" "1")])
|
||||
|
||||
;; Enable Interrupts
|
||||
(define_insn "enable_interrupt"
|
||||
[(unspec_volatile [(const_int 1)] UNSPECV_ENABLE_IRQS)]
|
||||
(define_expand "enable_interrupt"
|
||||
[(clobber (const_int 0))]
|
||||
""
|
||||
"sei"
|
||||
[(set_attr "length" "1")
|
||||
(set_attr "cc" "none")])
|
||||
{
|
||||
rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
|
||||
MEM_VOLATILE_P (mem) = 1;
|
||||
emit_insn (gen_cli_sei (const1_rtx, mem));
|
||||
DONE;
|
||||
})
|
||||
|
||||
;; Disable Interrupts
|
||||
(define_insn "disable_interrupt"
|
||||
[(unspec_volatile [(const_int 0)] UNSPECV_ENABLE_IRQS)]
|
||||
(define_expand "disable_interrupt"
|
||||
[(clobber (const_int 0))]
|
||||
""
|
||||
"cli"
|
||||
{
|
||||
rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
|
||||
MEM_VOLATILE_P (mem) = 1;
|
||||
emit_insn (gen_cli_sei (const0_rtx, mem));
|
||||
DONE;
|
||||
})
|
||||
|
||||
(define_insn "cli_sei"
|
||||
[(unspec_volatile [(match_operand:QI 0 "const_int_operand" "L,P")]
|
||||
UNSPECV_ENABLE_IRQS)
|
||||
(set (match_operand:BLK 1 "" "")
|
||||
(unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER))]
|
||||
""
|
||||
"@
|
||||
cli
|
||||
sei"
|
||||
[(set_attr "length" "1")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
|
@ -5316,10 +5402,12 @@
|
|||
[(unspec_volatile [(match_operand:QI 0 "const_int_operand" "n")
|
||||
(const_int 1)]
|
||||
UNSPECV_DELAY_CYCLES)
|
||||
(clobber (match_scratch:QI 1 "=&d"))]
|
||||
(set (match_operand:BLK 1 "" "")
|
||||
(unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER))
|
||||
(clobber (match_scratch:QI 2 "=&d"))]
|
||||
""
|
||||
"ldi %1,lo8(%0)
|
||||
1: dec %1
|
||||
"ldi %2,lo8(%0)
|
||||
1: dec %2
|
||||
brne 1b"
|
||||
[(set_attr "length" "3")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
@ -5328,11 +5416,13 @@
|
|||
[(unspec_volatile [(match_operand:HI 0 "const_int_operand" "n")
|
||||
(const_int 2)]
|
||||
UNSPECV_DELAY_CYCLES)
|
||||
(clobber (match_scratch:HI 1 "=&w"))]
|
||||
(set (match_operand:BLK 1 "" "")
|
||||
(unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER))
|
||||
(clobber (match_scratch:HI 2 "=&w"))]
|
||||
""
|
||||
"ldi %A1,lo8(%0)
|
||||
ldi %B1,hi8(%0)
|
||||
1: sbiw %A1,1
|
||||
"ldi %A2,lo8(%0)
|
||||
ldi %B2,hi8(%0)
|
||||
1: sbiw %A2,1
|
||||
brne 1b"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
@ -5341,16 +5431,18 @@
|
|||
[(unspec_volatile [(match_operand:SI 0 "const_int_operand" "n")
|
||||
(const_int 3)]
|
||||
UNSPECV_DELAY_CYCLES)
|
||||
(clobber (match_scratch:QI 1 "=&d"))
|
||||
(set (match_operand:BLK 1 "" "")
|
||||
(unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER))
|
||||
(clobber (match_scratch:QI 2 "=&d"))
|
||||
(clobber (match_scratch:QI 3 "=&d"))]
|
||||
(clobber (match_scratch:QI 3 "=&d"))
|
||||
(clobber (match_scratch:QI 4 "=&d"))]
|
||||
""
|
||||
"ldi %1,lo8(%0)
|
||||
ldi %2,hi8(%0)
|
||||
ldi %3,hlo8(%0)
|
||||
1: subi %1,1
|
||||
sbci %2,0
|
||||
"ldi %2,lo8(%0)
|
||||
ldi %3,hi8(%0)
|
||||
ldi %4,hlo8(%0)
|
||||
1: subi %2,1
|
||||
sbci %3,0
|
||||
sbci %4,0
|
||||
brne 1b"
|
||||
[(set_attr "length" "7")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
@ -5359,19 +5451,21 @@
|
|||
[(unspec_volatile [(match_operand:SI 0 "const_int_operand" "n")
|
||||
(const_int 4)]
|
||||
UNSPECV_DELAY_CYCLES)
|
||||
(clobber (match_scratch:QI 1 "=&d"))
|
||||
(set (match_operand:BLK 1 "" "")
|
||||
(unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER))
|
||||
(clobber (match_scratch:QI 2 "=&d"))
|
||||
(clobber (match_scratch:QI 3 "=&d"))
|
||||
(clobber (match_scratch:QI 4 "=&d"))]
|
||||
(clobber (match_scratch:QI 4 "=&d"))
|
||||
(clobber (match_scratch:QI 5 "=&d"))]
|
||||
""
|
||||
"ldi %1,lo8(%0)
|
||||
ldi %2,hi8(%0)
|
||||
ldi %3,hlo8(%0)
|
||||
ldi %4,hhi8(%0)
|
||||
1: subi %1,1
|
||||
sbci %2,0
|
||||
"ldi %2,lo8(%0)
|
||||
ldi %3,hi8(%0)
|
||||
ldi %4,hlo8(%0)
|
||||
ldi %5,hhi8(%0)
|
||||
1: subi %2,1
|
||||
sbci %3,0
|
||||
sbci %4,0
|
||||
sbci %5,0
|
||||
brne 1b"
|
||||
[(set_attr "length" "9")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
@ -5757,9 +5851,23 @@
|
|||
;; CPU instructions
|
||||
|
||||
;; NOP taking 1 or 2 Ticks
|
||||
(define_insn "nopv"
|
||||
(define_expand "nopv"
|
||||
[(parallel [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "")]
|
||||
UNSPECV_NOP)
|
||||
(set (match_dup 1)
|
||||
(unspec_volatile:BLK [(match_dup 1)]
|
||||
UNSPECV_MEMORY_BARRIER))])]
|
||||
""
|
||||
{
|
||||
operands[1] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
|
||||
MEM_VOLATILE_P (operands[1]) = 1;
|
||||
})
|
||||
|
||||
(define_insn "*nopv"
|
||||
[(unspec_volatile [(match_operand:SI 0 "const_int_operand" "P,K")]
|
||||
UNSPECV_NOP)]
|
||||
UNSPECV_NOP)
|
||||
(set (match_operand:BLK 1 "" "")
|
||||
(unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER))]
|
||||
""
|
||||
"@
|
||||
nop
|
||||
|
@ -5768,16 +5876,42 @@
|
|||
(set_attr "cc" "none")])
|
||||
|
||||
;; SLEEP
|
||||
(define_insn "sleep"
|
||||
[(unspec_volatile [(const_int 0)] UNSPECV_SLEEP)]
|
||||
(define_expand "sleep"
|
||||
[(parallel [(unspec_volatile [(const_int 0)] UNSPECV_SLEEP)
|
||||
(set (match_dup 0)
|
||||
(unspec_volatile:BLK [(match_dup 0)]
|
||||
UNSPECV_MEMORY_BARRIER))])]
|
||||
""
|
||||
{
|
||||
operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
|
||||
MEM_VOLATILE_P (operands[0]) = 1;
|
||||
})
|
||||
|
||||
(define_insn "*sleep"
|
||||
[(unspec_volatile [(const_int 0)] UNSPECV_SLEEP)
|
||||
(set (match_operand:BLK 0 "" "")
|
||||
(unspec_volatile:BLK [(match_dup 0)] UNSPECV_MEMORY_BARRIER))]
|
||||
""
|
||||
"sleep"
|
||||
[(set_attr "length" "1")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
;; WDR
|
||||
(define_insn "wdr"
|
||||
[(unspec_volatile [(const_int 0)] UNSPECV_WDR)]
|
||||
(define_expand "wdr"
|
||||
[(parallel [(unspec_volatile [(const_int 0)] UNSPECV_WDR)
|
||||
(set (match_dup 0)
|
||||
(unspec_volatile:BLK [(match_dup 0)]
|
||||
UNSPECV_MEMORY_BARRIER))])]
|
||||
""
|
||||
{
|
||||
operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
|
||||
MEM_VOLATILE_P (operands[0]) = 1;
|
||||
})
|
||||
|
||||
(define_insn "*wdr"
|
||||
[(unspec_volatile [(const_int 0)] UNSPECV_WDR)
|
||||
(set (match_operand:BLK 0 "" "")
|
||||
(unspec_volatile:BLK [(match_dup 0)] UNSPECV_MEMORY_BARRIER))]
|
||||
""
|
||||
"wdr"
|
||||
[(set_attr "length" "1")
|
||||
|
|
|
@ -1,3 +1,30 @@
|
|||
2012-03-22 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
Backport from 2012-03-07 mainline r185033.
|
||||
|
||||
PR target/52507
|
||||
* config/avr/lib1funcs.S (__movmemx_hi): Fix loop label in RAM-part.
|
||||
|
||||
Backport from 2012-03-07 mainline r185031.
|
||||
|
||||
PR target/52505
|
||||
* config/avr/lib1funcs.S (__xload_1): Don't read unintentionally
|
||||
from RAM.
|
||||
|
||||
Backport from 2012-03-07 mainline r185030.
|
||||
|
||||
PR target/52461
|
||||
PR target/52508
|
||||
* config/avr/lib1funcs.S (__do_copy_data): Clear RAMPZ after usage
|
||||
if RAMPZ affects reading from RAM.
|
||||
(__tablejump_elpm__): Ditto.
|
||||
(.xload): Ditto.
|
||||
(__movmemx_hi): Ditto.
|
||||
(__do_global_ctors): Right condition for RAMPZ usage is "have ELPM".
|
||||
(__do_global_dtors): Ditto.
|
||||
(__xload_1, __xload_2, __xload_3, __xload_4): Ditto.
|
||||
(__movmemx_hi): Ditto.
|
||||
|
||||
2012-03-22 Release Manager
|
||||
|
||||
* GCC 4.7.0 released.
|
||||
|
|
|
@ -1893,6 +1893,10 @@ DEFUN __do_copy_data
|
|||
cpc r27, r17
|
||||
brne .L__do_copy_data_loop
|
||||
#endif /* !defined(__AVR_HAVE_ELPMX__) && !defined(__AVR_HAVE_ELPM__) */
|
||||
#if defined (__AVR_HAVE_ELPM__) && defined (__AVR_HAVE_RAMPD__)
|
||||
;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM
|
||||
out __RAMPZ__, __zero_reg__
|
||||
#endif /* ELPM && RAMPD */
|
||||
ENDF __do_copy_data
|
||||
#endif /* L_copy_data */
|
||||
|
||||
|
@ -1920,7 +1924,7 @@ ENDF __do_clear_bss
|
|||
#ifdef L_ctors
|
||||
.section .init6,"ax",@progbits
|
||||
DEFUN __do_global_ctors
|
||||
#if defined(__AVR_HAVE_RAMPZ__)
|
||||
#if defined(__AVR_HAVE_ELPM__)
|
||||
ldi r17, hi8(__ctors_start)
|
||||
ldi r28, lo8(__ctors_end)
|
||||
ldi r29, hi8(__ctors_end)
|
||||
|
@ -1953,14 +1957,14 @@ DEFUN __do_global_ctors
|
|||
cpi r28, lo8(__ctors_start)
|
||||
cpc r29, r17
|
||||
brne .L__do_global_ctors_loop
|
||||
#endif /* defined(__AVR_HAVE_RAMPZ__) */
|
||||
#endif /* defined(__AVR_HAVE_ELPM__) */
|
||||
ENDF __do_global_ctors
|
||||
#endif /* L_ctors */
|
||||
|
||||
#ifdef L_dtors
|
||||
.section .fini6,"ax",@progbits
|
||||
DEFUN __do_global_dtors
|
||||
#if defined(__AVR_HAVE_RAMPZ__)
|
||||
#if defined(__AVR_HAVE_ELPM__)
|
||||
ldi r17, hi8(__dtors_end)
|
||||
ldi r28, lo8(__dtors_start)
|
||||
ldi r29, hi8(__dtors_start)
|
||||
|
@ -1993,7 +1997,7 @@ DEFUN __do_global_dtors
|
|||
cpi r28, lo8(__dtors_end)
|
||||
cpc r29, r17
|
||||
brne .L__do_global_dtors_loop
|
||||
#endif /* defined(__AVR_HAVE_RAMPZ__) */
|
||||
#endif /* defined(__AVR_HAVE_ELPM__) */
|
||||
ENDF __do_global_dtors
|
||||
#endif /* L_dtors */
|
||||
|
||||
|
@ -2001,18 +2005,21 @@ ENDF __do_global_dtors
|
|||
|
||||
#ifdef L_tablejump_elpm
|
||||
DEFUN __tablejump_elpm__
|
||||
#if defined (__AVR_HAVE_ELPM__)
|
||||
#if defined (__AVR_HAVE_LPMX__)
|
||||
#if defined (__AVR_HAVE_ELPMX__)
|
||||
elpm __tmp_reg__, Z+
|
||||
elpm r31, Z
|
||||
mov r30, __tmp_reg__
|
||||
#if defined (__AVR_HAVE_RAMPD__)
|
||||
;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM
|
||||
out __RAMPZ__, __zero_reg__
|
||||
#endif /* RAMPD */
|
||||
#if defined (__AVR_HAVE_EIJMP_EICALL__)
|
||||
eijmp
|
||||
#else
|
||||
ijmp
|
||||
#endif
|
||||
|
||||
#else
|
||||
#elif defined (__AVR_HAVE_ELPM__)
|
||||
elpm
|
||||
adiw r30, 1
|
||||
push r0
|
||||
|
@ -2024,7 +2031,6 @@ DEFUN __tablejump_elpm__
|
|||
#endif
|
||||
ret
|
||||
#endif
|
||||
#endif /* defined (__AVR_HAVE_ELPM__) */
|
||||
ENDF __tablejump_elpm__
|
||||
#endif /* defined (L_tablejump_elpm) */
|
||||
|
||||
|
@ -2114,11 +2120,18 @@ ENDF __load_4
|
|||
adiw r30, 1
|
||||
.endif
|
||||
#endif
|
||||
#if defined (__AVR_HAVE_ELPM__) && defined (__AVR_HAVE_RAMPD__)
|
||||
.if \dest == D0+\n-1
|
||||
;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM
|
||||
out __RAMPZ__, __zero_reg__
|
||||
.endif
|
||||
#endif
|
||||
.endm ; .xload
|
||||
|
||||
#if defined (L_xload_1)
|
||||
DEFUN __xload_1
|
||||
#if defined (__AVR_HAVE_LPMX__) && !defined (__AVR_HAVE_RAMPZ__)
|
||||
#if defined (__AVR_HAVE_LPMX__) && !defined (__AVR_HAVE_ELPM__)
|
||||
sbrc HHI8, 7
|
||||
ld D0, Z
|
||||
sbrs HHI8, 7
|
||||
lpm D0, Z
|
||||
|
@ -2126,14 +2139,14 @@ DEFUN __xload_1
|
|||
#else
|
||||
sbrc HHI8, 7
|
||||
rjmp 1f
|
||||
#if defined (__AVR_HAVE_RAMPZ__)
|
||||
#if defined (__AVR_HAVE_ELPM__)
|
||||
out __RAMPZ__, HHI8
|
||||
#endif /* __AVR_HAVE_RAMPZ__ */
|
||||
#endif /* __AVR_HAVE_ELPM__ */
|
||||
.xload D0, 1
|
||||
ret
|
||||
1: ld D0, Z
|
||||
ret
|
||||
#endif /* LPMx && ! RAMPZ */
|
||||
#endif /* LPMx && ! ELPM */
|
||||
ENDF __xload_1
|
||||
#endif /* L_xload_1 */
|
||||
|
||||
|
@ -2141,9 +2154,9 @@ ENDF __xload_1
|
|||
DEFUN __xload_2
|
||||
sbrc HHI8, 7
|
||||
rjmp 1f
|
||||
#if defined (__AVR_HAVE_RAMPZ__)
|
||||
#if defined (__AVR_HAVE_ELPM__)
|
||||
out __RAMPZ__, HHI8
|
||||
#endif /* __AVR_HAVE_RAMPZ__ */
|
||||
#endif /* __AVR_HAVE_ELPM__ */
|
||||
.xload D0, 2
|
||||
.xload D1, 2
|
||||
ret
|
||||
|
@ -2157,9 +2170,9 @@ ENDF __xload_2
|
|||
DEFUN __xload_3
|
||||
sbrc HHI8, 7
|
||||
rjmp 1f
|
||||
#if defined (__AVR_HAVE_RAMPZ__)
|
||||
#if defined (__AVR_HAVE_ELPM__)
|
||||
out __RAMPZ__, HHI8
|
||||
#endif /* __AVR_HAVE_RAMPZ__ */
|
||||
#endif /* __AVR_HAVE_ELPM__ */
|
||||
.xload D0, 3
|
||||
.xload D1, 3
|
||||
.xload D2, 3
|
||||
|
@ -2175,9 +2188,9 @@ ENDF __xload_3
|
|||
DEFUN __xload_4
|
||||
sbrc HHI8, 7
|
||||
rjmp 1f
|
||||
#if defined (__AVR_HAVE_RAMPZ__)
|
||||
#if defined (__AVR_HAVE_ELPM__)
|
||||
out __RAMPZ__, HHI8
|
||||
#endif /* __AVR_HAVE_RAMPZ__ */
|
||||
#endif /* __AVR_HAVE_ELPM__ */
|
||||
.xload D0, 4
|
||||
.xload D1, 4
|
||||
.xload D2, 4
|
||||
|
@ -2219,7 +2232,7 @@ DEFUN __movmemx_hi
|
|||
|
||||
;; Read from Flash
|
||||
|
||||
#if defined (__AVR_HAVE_RAMPZ__)
|
||||
#if defined (__AVR_HAVE_ELPM__)
|
||||
out __RAMPZ__, HHI8
|
||||
#endif
|
||||
|
||||
|
@ -2243,6 +2256,10 @@ DEFUN __movmemx_hi
|
|||
st X+, r0
|
||||
sbiw LOOP, 1
|
||||
brne 0b
|
||||
#if defined (__AVR_HAVE_ELPM__) && defined (__AVR_HAVE_RAMPD__)
|
||||
;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM
|
||||
out __RAMPZ__, __zero_reg__
|
||||
#endif /* ELPM && RAMPD */
|
||||
ret
|
||||
|
||||
;; Read from RAM
|
||||
|
@ -2252,7 +2269,7 @@ DEFUN __movmemx_hi
|
|||
;; and store that Byte to RAM Destination
|
||||
st X+, r0
|
||||
sbiw LOOP, 1
|
||||
brne 0b
|
||||
brne 1b
|
||||
ret
|
||||
ENDF __movmemx_hi
|
||||
|
||||
|
|
Loading…
Reference in New Issue