xtensa-protos.h (xtensa_copy_incoming_a7): Update.
* config/xtensa/xtensa-protos.h (xtensa_copy_incoming_a7): Update. (init_cumulative_args): Likewise. (a7_overlap_mentioned_p): Delete prototype. * config/xtensa/xtensa.c (struct machine_function): Replace incoming_a7_copied field with need_a7_copy and vararg_a7 flags. Add set_frame_ptr_insn field. (xtensa_emit_move_sequence): Update call to xtensa_copy_incoming_a7. (xtensa_copy_incoming_a7): Rewrite to check need_a7_copy flag and check if the operand is an argument in a7. If so, copy a7 to a new pseudo at the function entry and replace the operand with the pseudo. (init_cumulative_args): Remove unused arguments. Add new "incoming" argument and record this flag in CUMULATIVE_ARGS. (function_arg): Remove result_mode and special-case code to handle arguments in a7. Instead, set need_a7_copy flag when there is an incoming argument in a7. (xtensa_expand_prologue): Remove code to search for set_frame_ptr insn and use the value recorded in cfun->machine->set_frame_ptr_insn. (xtensa_builtin_saveregs): Check for negative gp_left value. Set need_a7_copy and vararg_a7 flags. Use move_block_from_reg instead of special-case code. (a7_overlap_mentioned_p): Delete. * config/xtensa/xtensa.h (CUMULATIVE_ARGS): Add "incoming" flag. (INIT_CUMULATIVE_ARGS, INIT_CUMULATIVE_INCOMING_ARGS): Remove useless arguments to init_cumulative_args and pass "incoming" flag instead. (BLOCK_REG_PADDING): Delete. * config/xtensa/xtensa.md (movdi, movsf, movdf): Remove unnecessary checks for reload_in_progress and reload_completed. Update calls to xtensa_copy_incoming_a7. (ashlsi3): Rename existing insn to ashlsi3_internal. Add expander to call xtensa_copy_incoming_a7. From-SVN: r77583
This commit is contained in:
parent
99bee03ac2
commit
997b8b4d4c
@ -1,3 +1,36 @@
|
||||
2004-02-09 Bob Wilson <bob.wilson@acm.org>
|
||||
|
||||
* config/xtensa/xtensa-protos.h (xtensa_copy_incoming_a7): Update.
|
||||
(init_cumulative_args): Likewise.
|
||||
(a7_overlap_mentioned_p): Delete prototype.
|
||||
* config/xtensa/xtensa.c (struct machine_function): Replace
|
||||
incoming_a7_copied field with need_a7_copy and vararg_a7 flags.
|
||||
Add set_frame_ptr_insn field.
|
||||
(xtensa_emit_move_sequence): Update call to xtensa_copy_incoming_a7.
|
||||
(xtensa_copy_incoming_a7): Rewrite to check need_a7_copy flag and check
|
||||
if the operand is an argument in a7. If so, copy a7 to a new pseudo
|
||||
at the function entry and replace the operand with the pseudo.
|
||||
(init_cumulative_args): Remove unused arguments. Add new "incoming"
|
||||
argument and record this flag in CUMULATIVE_ARGS.
|
||||
(function_arg): Remove result_mode and special-case code to handle
|
||||
arguments in a7. Instead, set need_a7_copy flag when there is an
|
||||
incoming argument in a7.
|
||||
(xtensa_expand_prologue): Remove code to search for set_frame_ptr insn
|
||||
and use the value recorded in cfun->machine->set_frame_ptr_insn.
|
||||
(xtensa_builtin_saveregs): Check for negative gp_left value. Set
|
||||
need_a7_copy and vararg_a7 flags. Use move_block_from_reg instead of
|
||||
special-case code.
|
||||
(a7_overlap_mentioned_p): Delete.
|
||||
* config/xtensa/xtensa.h (CUMULATIVE_ARGS): Add "incoming" flag.
|
||||
(INIT_CUMULATIVE_ARGS, INIT_CUMULATIVE_INCOMING_ARGS): Remove useless
|
||||
arguments to init_cumulative_args and pass "incoming" flag instead.
|
||||
(BLOCK_REG_PADDING): Delete.
|
||||
* config/xtensa/xtensa.md (movdi, movsf, movdf): Remove unnecessary
|
||||
checks for reload_in_progress and reload_completed. Update calls to
|
||||
xtensa_copy_incoming_a7.
|
||||
(ashlsi3): Rename existing insn to ashlsi3_internal. Add expander
|
||||
to call xtensa_copy_incoming_a7.
|
||||
|
||||
2004-02-09 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* config/i386/xm-djgpp.h (GCC_DRIVER_HOST_INITIALIZATION): No
|
||||
|
@ -68,14 +68,14 @@ extern int xtensa_expand_scc (rtx *);
|
||||
extern int xtensa_expand_block_move (rtx *);
|
||||
extern void xtensa_split_operand_pair (rtx *, enum machine_mode);
|
||||
extern int xtensa_emit_move_sequence (rtx *, enum machine_mode);
|
||||
extern bool xtensa_copy_incoming_a7 (rtx *, enum machine_mode);
|
||||
extern rtx xtensa_copy_incoming_a7 (rtx);
|
||||
extern void xtensa_emit_block_move (rtx *, rtx *, int);
|
||||
extern void xtensa_expand_nonlocal_goto (rtx *);
|
||||
extern void xtensa_emit_loop_end (rtx, rtx *);
|
||||
extern char *xtensa_emit_call (int, rtx *);
|
||||
|
||||
#ifdef TREE_CODE
|
||||
extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx);
|
||||
extern void init_cumulative_args (CUMULATIVE_ARGS *, int);
|
||||
extern void xtensa_va_start (tree, rtx);
|
||||
extern rtx xtensa_va_arg (tree, tree);
|
||||
#endif /* TREE_CODE */
|
||||
@ -88,7 +88,6 @@ extern enum reg_class xtensa_preferred_reload_class (rtx, enum reg_class, int);
|
||||
extern enum reg_class xtensa_secondary_reload_class (enum reg_class,
|
||||
enum machine_mode, rtx,
|
||||
int);
|
||||
extern int a7_overlap_mentioned_p (rtx);
|
||||
#endif /* RTX_CODE */
|
||||
|
||||
#ifdef TREE_CODE
|
||||
|
@ -91,7 +91,9 @@ const char *xtensa_st_opcodes[(int) MAX_MACHINE_MODE];
|
||||
struct machine_function GTY(())
|
||||
{
|
||||
int accesses_prev_frame;
|
||||
bool incoming_a7_copied;
|
||||
bool need_a7_copy;
|
||||
bool vararg_a7;
|
||||
rtx set_frame_ptr_insn;
|
||||
};
|
||||
|
||||
/* Vector, indexed by hard register number, which contains 1 for a
|
||||
@ -1271,14 +1273,11 @@ xtensa_emit_move_sequence (rtx *operands, enum machine_mode mode)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(reload_in_progress | reload_completed))
|
||||
{
|
||||
if (!xtensa_valid_move (mode, operands))
|
||||
operands[1] = force_reg (mode, operands[1]);
|
||||
if (!(reload_in_progress | reload_completed)
|
||||
&& !xtensa_valid_move (mode, operands))
|
||||
operands[1] = force_reg (mode, operands[1]);
|
||||
|
||||
if (xtensa_copy_incoming_a7 (operands, mode))
|
||||
return 1;
|
||||
}
|
||||
operands[1] = xtensa_copy_incoming_a7 (operands[1]);
|
||||
|
||||
/* During reload we don't want to emit (subreg:X (mem:Y)) since that
|
||||
instruction won't be recognized after reload, so we remove the
|
||||
@ -1309,89 +1308,114 @@ fixup_subreg_mem (rtx x)
|
||||
}
|
||||
|
||||
|
||||
/* Check if this move is copying an incoming argument in a7. If so,
|
||||
emit the move, followed by the special "set_frame_ptr"
|
||||
unspec_volatile insn, at the very beginning of the function. This
|
||||
is necessary because the register allocator will ignore conflicts
|
||||
with a7 and may assign some other pseudo to a7. If that pseudo was
|
||||
assigned prior to this move, it would clobber the incoming argument
|
||||
in a7. By copying the argument out of a7 as the very first thing,
|
||||
and then immediately following that with an unspec_volatile to keep
|
||||
the scheduler away, we should avoid any problems. */
|
||||
/* Check if an incoming argument in a7 is expected to be used soon and
|
||||
if OPND is a register or register pair that includes a7. If so,
|
||||
create a new pseudo and copy a7 into that pseudo at the very
|
||||
beginning of the function, followed by the special "set_frame_ptr"
|
||||
unspec_volatile insn. The return value is either the original
|
||||
operand, if it is not a7, or the new pseudo containing a copy of
|
||||
the incoming argument. This is necessary because the register
|
||||
allocator will ignore conflicts with a7 and may either assign some
|
||||
other pseudo to a7 or use a7 as the hard_frame_pointer, clobbering
|
||||
the incoming argument in a7. By copying the argument out of a7 as
|
||||
the very first thing, and then immediately following that with an
|
||||
unspec_volatile to keep the scheduler away, we should avoid any
|
||||
problems. Putting the set_frame_ptr insn at the beginning, with
|
||||
only the a7 copy before it, also makes it easier for the prologue
|
||||
expander to initialize the frame pointer after the a7 copy and to
|
||||
fix up the a7 copy to use the stack pointer instead of the frame
|
||||
pointer. */
|
||||
|
||||
bool
|
||||
xtensa_copy_incoming_a7 (rtx *operands, enum machine_mode mode)
|
||||
rtx
|
||||
xtensa_copy_incoming_a7 (rtx opnd)
|
||||
{
|
||||
if (a7_overlap_mentioned_p (operands[1])
|
||||
&& !cfun->machine->incoming_a7_copied)
|
||||
rtx entry_insns = 0;
|
||||
rtx reg, tmp;
|
||||
enum machine_mode mode;
|
||||
|
||||
if (!cfun->machine->need_a7_copy)
|
||||
return opnd;
|
||||
|
||||
/* This function should never be called again once a7 has been copied. */
|
||||
if (cfun->machine->set_frame_ptr_insn)
|
||||
abort ();
|
||||
|
||||
mode = GET_MODE (opnd);
|
||||
|
||||
/* The operand using a7 may come in a later instruction, so just return
|
||||
the original operand if it doesn't use a7. */
|
||||
reg = opnd;
|
||||
if (GET_CODE (reg) == SUBREG)
|
||||
{
|
||||
rtx mov, src;
|
||||
if (SUBREG_BYTE (reg) != 0)
|
||||
abort ();
|
||||
reg = SUBREG_REG (reg);
|
||||
}
|
||||
if (GET_CODE (reg) != REG
|
||||
|| REGNO (reg) > A7_REG
|
||||
|| REGNO (reg) + HARD_REGNO_NREGS (A7_REG, mode) <= A7_REG)
|
||||
return opnd;
|
||||
|
||||
/* Despite defining SPLIT_COMPLEX_ARGS, complex function
|
||||
arguments may still appear if they are wrapped in a struct.
|
||||
For CQImode and CHImode arguments, this results in a move
|
||||
with a source operand of the form: "(subreg:SI (reg:CHI a7)
|
||||
0)". The subreg is later removed by the reload pass,
|
||||
resulting in the RTL for a7 being regenerated using
|
||||
hard_frame_pointer_rtx, and making it impossible for us to
|
||||
distinguish the function argument. Detect this here when
|
||||
generating the RTL and remove the subreg immediately so that
|
||||
reload won't mess it up. */
|
||||
src = operands[1];
|
||||
if (GET_CODE (src) == SUBREG
|
||||
&& GET_CODE (SUBREG_REG (src)) == REG
|
||||
&& REGNO (SUBREG_REG (src)) == A7_REG
|
||||
&& SUBREG_BYTE (src) == 0
|
||||
&& (GET_MODE (SUBREG_REG (src)) == CHImode
|
||||
|| GET_MODE (SUBREG_REG (src)) == CQImode))
|
||||
operands[1] = gen_raw_REG (mode, A7_REG);
|
||||
/* 1-word args will always be in a7; 2-word args in a6/a7. */
|
||||
if (REGNO (reg) + HARD_REGNO_NREGS (A7_REG, mode) - 1 != A7_REG)
|
||||
abort ();
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case DFmode:
|
||||
mov = gen_movdf_internal (operands[0], operands[1]);
|
||||
break;
|
||||
case SFmode:
|
||||
mov = gen_movsf_internal (operands[0], operands[1]);
|
||||
break;
|
||||
case DImode:
|
||||
mov = gen_movdi_internal (operands[0], operands[1]);
|
||||
break;
|
||||
case SImode:
|
||||
mov = gen_movsi_internal (operands[0], operands[1]);
|
||||
break;
|
||||
case HImode:
|
||||
mov = gen_movhi_internal (operands[0], operands[1]);
|
||||
break;
|
||||
case QImode:
|
||||
mov = gen_movqi_internal (operands[0], operands[1]);
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
cfun->machine->need_a7_copy = false;
|
||||
|
||||
/* Insert the instructions before any other argument copies.
|
||||
(The set_frame_ptr insn comes _after_ the move, so push it
|
||||
out first.) */
|
||||
push_topmost_sequence ();
|
||||
emit_insn_after (gen_set_frame_ptr (), get_insns ());
|
||||
emit_insn_after (mov, get_insns ());
|
||||
pop_topmost_sequence ();
|
||||
/* Copy a7 to a new pseudo at the function entry. Use gen_raw_REG to
|
||||
create the REG for a7 so that hard_frame_pointer_rtx is not used. */
|
||||
|
||||
/* Ideally the incoming argument in a7 would only be copied
|
||||
once, since propagating a7 into the body of a function
|
||||
will almost certainly lead to errors. However, there is
|
||||
at least one harmless case (in GCSE) where the original
|
||||
copy from a7 is changed to copy into a new pseudo. Thus,
|
||||
we use a flag to only do this special treatment for the
|
||||
first copy of a7. */
|
||||
push_to_sequence (entry_insns);
|
||||
tmp = gen_reg_rtx (mode);
|
||||
|
||||
cfun->machine->incoming_a7_copied = true;
|
||||
|
||||
return 1;
|
||||
switch (mode)
|
||||
{
|
||||
case DFmode:
|
||||
case DImode:
|
||||
emit_insn (gen_movsi_internal (gen_rtx_SUBREG (SImode, tmp, 0),
|
||||
gen_rtx_REG (SImode, A7_REG - 1)));
|
||||
emit_insn (gen_movsi_internal (gen_rtx_SUBREG (SImode, tmp, 4),
|
||||
gen_raw_REG (SImode, A7_REG)));
|
||||
break;
|
||||
case SFmode:
|
||||
emit_insn (gen_movsf_internal (tmp, gen_raw_REG (mode, A7_REG)));
|
||||
break;
|
||||
case SImode:
|
||||
emit_insn (gen_movsi_internal (tmp, gen_raw_REG (mode, A7_REG)));
|
||||
break;
|
||||
case HImode:
|
||||
emit_insn (gen_movhi_internal (tmp, gen_raw_REG (mode, A7_REG)));
|
||||
break;
|
||||
case QImode:
|
||||
emit_insn (gen_movqi_internal (tmp, gen_raw_REG (mode, A7_REG)));
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
cfun->machine->set_frame_ptr_insn = emit_insn (gen_set_frame_ptr ());
|
||||
entry_insns = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
if (cfun->machine->vararg_a7)
|
||||
{
|
||||
/* This is called from within builtin_savereg, so we're already
|
||||
inside a start_sequence that will be placed at the start of
|
||||
the function. */
|
||||
emit_insn (entry_insns);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Put entry_insns after the NOTE that starts the function. If
|
||||
this is inside a start_sequence, make the outer-level insn
|
||||
chain current, so the code is placed at the start of the
|
||||
function. */
|
||||
push_topmost_sequence ();
|
||||
emit_insn_after (entry_insns, get_insns ());
|
||||
pop_topmost_sequence ();
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
@ -1727,11 +1751,10 @@ xtensa_dbx_register_number (int regno)
|
||||
/* Initialize CUMULATIVE_ARGS for a function. */
|
||||
|
||||
void
|
||||
init_cumulative_args (CUMULATIVE_ARGS *cum,
|
||||
tree fntype ATTRIBUTE_UNUSED,
|
||||
rtx libname ATTRIBUTE_UNUSED)
|
||||
init_cumulative_args (CUMULATIVE_ARGS *cum, int incoming)
|
||||
{
|
||||
cum->arg_words = 0;
|
||||
cum->incoming = incoming;
|
||||
}
|
||||
|
||||
|
||||
@ -1768,7 +1791,6 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
|
||||
int regbase, words, max;
|
||||
int *arg_words;
|
||||
int regno;
|
||||
enum machine_mode result_mode;
|
||||
|
||||
arg_words = &cum->arg_words;
|
||||
regbase = (incoming_p ? GP_ARG_FIRST : GP_OUTGOING_ARG_FIRST);
|
||||
@ -1785,37 +1807,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
|
||||
return (rtx)0;
|
||||
|
||||
regno = regbase + *arg_words;
|
||||
result_mode = (mode == BLKmode ? TYPE_MODE (type) : mode);
|
||||
|
||||
/* We need to make sure that references to a7 are represented with
|
||||
rtx that is not equal to hard_frame_pointer_rtx. For multi-word
|
||||
modes for which we don't define move patterns, we can't control
|
||||
the expansion unless we explicitly list the individual registers
|
||||
in a PARALLEL. Likewise, a single-word BLKmode argument passed
|
||||
in a7 must be wrapped in a PARALLEL to avoid code that takes the
|
||||
register number and builds a new REG. This is extremely fragile
|
||||
but seems to be the best solution for now. */
|
||||
if (cum->incoming && regno <= A7_REG && regno + words > A7_REG)
|
||||
cfun->machine->need_a7_copy = true;
|
||||
|
||||
if ((mode != DImode && mode != DFmode
|
||||
&& regno < A7_REG
|
||||
&& regno + words > A7_REG)
|
||||
|| (mode == BLKmode && regno == A7_REG))
|
||||
{
|
||||
rtx result;
|
||||
int n;
|
||||
|
||||
result = gen_rtx_PARALLEL (result_mode, rtvec_alloc (words));
|
||||
for (n = 0; n < words; n++)
|
||||
{
|
||||
XVECEXP (result, 0, n) =
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_raw_REG (SImode, regno + n),
|
||||
GEN_INT (n * UNITS_PER_WORD));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return gen_raw_REG (result_mode, regno);
|
||||
return gen_rtx_REG (mode, regno);
|
||||
}
|
||||
|
||||
|
||||
@ -2264,41 +2260,18 @@ xtensa_expand_prologue (void)
|
||||
|
||||
if (frame_pointer_needed)
|
||||
{
|
||||
rtx first, insn, set_frame_ptr_insn = 0;
|
||||
|
||||
push_topmost_sequence ();
|
||||
first = get_insns ();
|
||||
pop_topmost_sequence ();
|
||||
|
||||
/* Search all instructions, looking for the insn that sets up the
|
||||
frame pointer. This search will fail if the function does not
|
||||
have an incoming argument in $a7, but in that case, we can just
|
||||
set up the frame pointer at the very beginning of the
|
||||
function. */
|
||||
|
||||
for (insn = first; insn; insn = NEXT_INSN (insn))
|
||||
if (cfun->machine->set_frame_ptr_insn)
|
||||
{
|
||||
rtx pat;
|
||||
rtx first, insn;
|
||||
|
||||
if (!INSN_P (insn))
|
||||
continue;
|
||||
push_topmost_sequence ();
|
||||
first = get_insns ();
|
||||
pop_topmost_sequence ();
|
||||
|
||||
pat = PATTERN (insn);
|
||||
if (GET_CODE (pat) == SET
|
||||
&& GET_CODE (SET_SRC (pat)) == UNSPEC_VOLATILE
|
||||
&& (XINT (SET_SRC (pat), 1) == UNSPECV_SET_FP))
|
||||
{
|
||||
set_frame_ptr_insn = insn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (set_frame_ptr_insn)
|
||||
{
|
||||
/* For all instructions prior to set_frame_ptr_insn, replace
|
||||
hard_frame_pointer references with stack_pointer. */
|
||||
for (insn = first;
|
||||
insn != set_frame_ptr_insn;
|
||||
insn != cfun->machine->set_frame_ptr_insn;
|
||||
insn = NEXT_INSN (insn))
|
||||
{
|
||||
if (INSN_P (insn))
|
||||
@ -2400,9 +2373,8 @@ xtensa_builtin_saveregs (void)
|
||||
rtx gp_regs, dest;
|
||||
int arg_words = current_function_arg_words;
|
||||
int gp_left = MAX_ARGS_IN_REGISTERS - arg_words;
|
||||
int i;
|
||||
|
||||
if (gp_left == 0)
|
||||
if (gp_left <= 0)
|
||||
return const0_rtx;
|
||||
|
||||
/* Allocate the general-purpose register space. */
|
||||
@ -2414,16 +2386,9 @@ xtensa_builtin_saveregs (void)
|
||||
dest = change_address (gp_regs, SImode,
|
||||
plus_constant (XEXP (gp_regs, 0),
|
||||
arg_words * UNITS_PER_WORD));
|
||||
|
||||
/* Note: Don't use move_block_from_reg() here because the incoming
|
||||
argument in a7 cannot be represented by hard_frame_pointer_rtx.
|
||||
Instead, call gen_raw_REG() directly so that we get a distinct
|
||||
instance of (REG:SI 7). */
|
||||
for (i = 0; i < gp_left; i++)
|
||||
{
|
||||
emit_move_insn (operand_subword (dest, i, 1, BLKmode),
|
||||
gen_raw_REG (SImode, GP_ARG_FIRST + arg_words + i));
|
||||
}
|
||||
cfun->machine->need_a7_copy = true;
|
||||
cfun->machine->vararg_a7 = true;
|
||||
move_block_from_reg (GP_ARG_FIRST + arg_words, dest, gp_left);
|
||||
|
||||
return XEXP (gp_regs, 0);
|
||||
}
|
||||
@ -2749,55 +2714,6 @@ order_regs_for_local_alloc (void)
|
||||
}
|
||||
|
||||
|
||||
/* A customized version of reg_overlap_mentioned_p that only looks for
|
||||
references to a7 (as opposed to hard_frame_pointer_rtx). */
|
||||
|
||||
int
|
||||
a7_overlap_mentioned_p (rtx x)
|
||||
{
|
||||
int i, j;
|
||||
unsigned int x_regno;
|
||||
const char *fmt;
|
||||
|
||||
if (GET_CODE (x) == REG)
|
||||
{
|
||||
x_regno = REGNO (x);
|
||||
return (x != hard_frame_pointer_rtx
|
||||
&& x_regno < A7_REG + 1
|
||||
&& x_regno + HARD_REGNO_NREGS (A7_REG, GET_MODE (x)) > A7_REG);
|
||||
}
|
||||
|
||||
if (GET_CODE (x) == SUBREG
|
||||
&& GET_CODE (SUBREG_REG (x)) == REG
|
||||
&& REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
|
||||
{
|
||||
x_regno = subreg_regno (x);
|
||||
return (SUBREG_REG (x) != hard_frame_pointer_rtx
|
||||
&& x_regno < A7_REG + 1
|
||||
&& x_regno + HARD_REGNO_NREGS (A7_REG, GET_MODE (x)) > A7_REG);
|
||||
}
|
||||
|
||||
/* X does not match, so try its subexpressions. */
|
||||
fmt = GET_RTX_FORMAT (GET_CODE (x));
|
||||
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
|
||||
{
|
||||
if (fmt[i] == 'e')
|
||||
{
|
||||
if (a7_overlap_mentioned_p (XEXP (x, i)))
|
||||
return 1;
|
||||
}
|
||||
else if (fmt[i] == 'E')
|
||||
{
|
||||
for (j = XVECLEN (x, i) - 1; j >=0; j--)
|
||||
if (a7_overlap_mentioned_p (XVECEXP (x, i, j)))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Some Xtensa targets support multiple bss sections. If the section
|
||||
name ends with ".bss", add SECTION_BSS to the flags. */
|
||||
|
||||
|
@ -736,23 +736,21 @@ extern enum reg_class xtensa_char_to_class[256];
|
||||
#define FUNCTION_ARG_REGNO_P(N) \
|
||||
((N) >= GP_OUTGOING_ARG_FIRST && (N) <= GP_OUTGOING_ARG_LAST)
|
||||
|
||||
/* Define a data type for recording info about an argument list
|
||||
during the scan of that argument list. This data type should
|
||||
hold all necessary information about the function itself
|
||||
and about the args processed so far, enough to enable macros
|
||||
such as FUNCTION_ARG to determine where the next arg should go. */
|
||||
typedef struct xtensa_args {
|
||||
int arg_words; /* # total words the arguments take */
|
||||
/* Record the number of argument words seen so far, along with a flag to
|
||||
indicate whether these are incoming arguments. (FUNCTION_INCOMING_ARG
|
||||
is used for both incoming and outgoing args, so a separate flag is
|
||||
needed. */
|
||||
typedef struct xtensa_args
|
||||
{
|
||||
int arg_words;
|
||||
int incoming;
|
||||
} CUMULATIVE_ARGS;
|
||||
|
||||
/* Initialize a variable CUM of type CUMULATIVE_ARGS
|
||||
for a call to a function whose data type is FNTYPE.
|
||||
For a library call, FNTYPE is 0. */
|
||||
#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
|
||||
init_cumulative_args (&CUM, FNTYPE, LIBNAME)
|
||||
init_cumulative_args (&CUM, 0)
|
||||
|
||||
#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \
|
||||
init_cumulative_args (&CUM, FNTYPE, LIBNAME)
|
||||
init_cumulative_args (&CUM, 1)
|
||||
|
||||
/* Update the data in CUM to advance over an argument
|
||||
of mode MODE and data type TYPE.
|
||||
@ -798,12 +796,6 @@ typedef struct xtensa_args {
|
||||
/* Pass complex arguments independently. */
|
||||
#define SPLIT_COMPLEX_ARGS 1
|
||||
|
||||
/* Because Xtensa's function_arg() wraps BLKmode arguments passed in
|
||||
a7 inside a PARALLEL, BLOCK_REG_PADDING needs to be defined
|
||||
to get emit_group_store to do the right thing. */
|
||||
#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
|
||||
FUNCTION_ARG_PADDING (MODE, TYPE)
|
||||
|
||||
/* Profiling Xtensa code is typically done with the built-in profiling
|
||||
feature of Tensilica's instruction set simulator, which does not
|
||||
require any compiler support. Profiling code on a real (i.e.,
|
||||
@ -1142,11 +1134,6 @@ typedef struct xtensa_args {
|
||||
/* Prefer word-sized loads. */
|
||||
#define SLOW_BYTE_ACCESS 1
|
||||
|
||||
/* ??? Xtensa doesn't have any instructions that set integer values
|
||||
based on the results of comparisons, but the simplification code in
|
||||
the combiner also uses STORE_FLAG_VALUE. The default value (1) is
|
||||
fine for us, but (-1) might be better. */
|
||||
|
||||
/* Shift instructions ignore all but the low-order few bits. */
|
||||
#define SHIFT_COUNT_TRUNCATED 1
|
||||
|
||||
|
@ -803,15 +803,11 @@
|
||||
if (CONSTANT_P (operands[1]) && !TARGET_CONST16)
|
||||
operands[1] = force_const_mem (DImode, operands[1]);
|
||||
|
||||
if (!(reload_in_progress | reload_completed))
|
||||
{
|
||||
if (!register_operand (operands[0], DImode)
|
||||
&& !register_operand (operands[1], DImode))
|
||||
operands[1] = force_reg (DImode, operands[1]);
|
||||
if (!register_operand (operands[0], DImode)
|
||||
&& !register_operand (operands[1], DImode))
|
||||
operands[1] = force_reg (DImode, operands[1]);
|
||||
|
||||
if (xtensa_copy_incoming_a7 (operands, DImode))
|
||||
DONE;
|
||||
}
|
||||
operands[1] = xtensa_copy_incoming_a7 (operands[1]);
|
||||
})
|
||||
|
||||
(define_insn_and_split "movdi_internal"
|
||||
@ -934,18 +930,15 @@
|
||||
if (!TARGET_CONST16 && CONSTANT_P (operands[1]))
|
||||
operands[1] = force_const_mem (SFmode, operands[1]);
|
||||
|
||||
if (!(reload_in_progress | reload_completed))
|
||||
{
|
||||
if ((!register_operand (operands[0], SFmode)
|
||||
&& !register_operand (operands[1], SFmode))
|
||||
|| (FP_REG_P (xt_true_regnum (operands[0]))
|
||||
&& (constantpool_mem_p (operands[1])
|
||||
|| CONSTANT_P (operands[1]))))
|
||||
operands[1] = force_reg (SFmode, operands[1]);
|
||||
if ((!register_operand (operands[0], SFmode)
|
||||
&& !register_operand (operands[1], SFmode))
|
||||
|| (FP_REG_P (xt_true_regnum (operands[0]))
|
||||
&& !(reload_in_progress | reload_completed)
|
||||
&& (constantpool_mem_p (operands[1])
|
||||
|| CONSTANT_P (operands[1]))))
|
||||
operands[1] = force_reg (SFmode, operands[1]);
|
||||
|
||||
if (xtensa_copy_incoming_a7 (operands, SFmode))
|
||||
DONE;
|
||||
}
|
||||
operands[1] = xtensa_copy_incoming_a7 (operands[1]);
|
||||
})
|
||||
|
||||
(define_insn "movsf_internal"
|
||||
@ -1015,15 +1008,11 @@
|
||||
if (CONSTANT_P (operands[1]) && !TARGET_CONST16)
|
||||
operands[1] = force_const_mem (DFmode, operands[1]);
|
||||
|
||||
if (!(reload_in_progress | reload_completed))
|
||||
{
|
||||
if (!register_operand (operands[0], DFmode)
|
||||
&& !register_operand (operands[1], DFmode))
|
||||
operands[1] = force_reg (DFmode, operands[1]);
|
||||
if (!register_operand (operands[0], DFmode)
|
||||
&& !register_operand (operands[1], DFmode))
|
||||
operands[1] = force_reg (DFmode, operands[1]);
|
||||
|
||||
if (xtensa_copy_incoming_a7 (operands, DFmode))
|
||||
DONE;
|
||||
}
|
||||
operands[1] = xtensa_copy_incoming_a7 (operands[1]);
|
||||
})
|
||||
|
||||
(define_insn_and_split "movdf_internal"
|
||||
@ -1081,7 +1070,16 @@
|
||||
|
||||
;; Shift instructions.
|
||||
|
||||
(define_insn "ashlsi3"
|
||||
(define_expand "ashlsi3"
|
||||
[(set (match_operand:SI 0 "register_operand" "")
|
||||
(ashift:SI (match_operand:SI 1 "register_operand" "")
|
||||
(match_operand:SI 2 "arith_operand" "")))]
|
||||
""
|
||||
{
|
||||
operands[1] = xtensa_copy_incoming_a7 (operands[1]);
|
||||
})
|
||||
|
||||
(define_insn "ashlsi3_internal"
|
||||
[(set (match_operand:SI 0 "register_operand" "=a,a")
|
||||
(ashift:SI (match_operand:SI 1 "register_operand" "r,r")
|
||||
(match_operand:SI 2 "arith_operand" "J,r")))]
|
||||
|
Loading…
x
Reference in New Issue
Block a user