Commit 997b8b4d by Bob Wilson Committed by Bob Wilson

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
parent 99bee03a
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> 2004-02-09 DJ Delorie <dj@redhat.com>
* config/i386/xm-djgpp.h (GCC_DRIVER_HOST_INITIALIZATION): No * config/i386/xm-djgpp.h (GCC_DRIVER_HOST_INITIALIZATION): No
......
...@@ -68,14 +68,14 @@ extern int xtensa_expand_scc (rtx *); ...@@ -68,14 +68,14 @@ extern int xtensa_expand_scc (rtx *);
extern int xtensa_expand_block_move (rtx *); extern int xtensa_expand_block_move (rtx *);
extern void xtensa_split_operand_pair (rtx *, enum machine_mode); extern void xtensa_split_operand_pair (rtx *, enum machine_mode);
extern int xtensa_emit_move_sequence (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_emit_block_move (rtx *, rtx *, int);
extern void xtensa_expand_nonlocal_goto (rtx *); extern void xtensa_expand_nonlocal_goto (rtx *);
extern void xtensa_emit_loop_end (rtx, rtx *); extern void xtensa_emit_loop_end (rtx, rtx *);
extern char *xtensa_emit_call (int, rtx *); extern char *xtensa_emit_call (int, rtx *);
#ifdef TREE_CODE #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 void xtensa_va_start (tree, rtx);
extern rtx xtensa_va_arg (tree, tree); extern rtx xtensa_va_arg (tree, tree);
#endif /* TREE_CODE */ #endif /* TREE_CODE */
...@@ -88,7 +88,6 @@ extern enum reg_class xtensa_preferred_reload_class (rtx, enum reg_class, int); ...@@ -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, extern enum reg_class xtensa_secondary_reload_class (enum reg_class,
enum machine_mode, rtx, enum machine_mode, rtx,
int); int);
extern int a7_overlap_mentioned_p (rtx);
#endif /* RTX_CODE */ #endif /* RTX_CODE */
#ifdef TREE_CODE #ifdef TREE_CODE
......
...@@ -91,7 +91,9 @@ const char *xtensa_st_opcodes[(int) MAX_MACHINE_MODE]; ...@@ -91,7 +91,9 @@ const char *xtensa_st_opcodes[(int) MAX_MACHINE_MODE];
struct machine_function GTY(()) struct machine_function GTY(())
{ {
int accesses_prev_frame; 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 /* 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) ...@@ -1271,14 +1273,11 @@ xtensa_emit_move_sequence (rtx *operands, enum machine_mode mode)
} }
} }
if (!(reload_in_progress | reload_completed)) if (!(reload_in_progress | reload_completed)
{ && !xtensa_valid_move (mode, operands))
if (!xtensa_valid_move (mode, operands))
operands[1] = force_reg (mode, operands[1]); operands[1] = force_reg (mode, operands[1]);
if (xtensa_copy_incoming_a7 (operands, mode)) operands[1] = xtensa_copy_incoming_a7 (operands[1]);
return 1;
}
/* During reload we don't want to emit (subreg:X (mem:Y)) since that /* 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 instruction won't be recognized after reload, so we remove the
...@@ -1309,89 +1308,114 @@ fixup_subreg_mem (rtx x) ...@@ -1309,89 +1308,114 @@ fixup_subreg_mem (rtx x)
} }
/* Check if this move is copying an incoming argument in a7. If so, /* Check if an incoming argument in a7 is expected to be used soon and
emit the move, followed by the special "set_frame_ptr" if OPND is a register or register pair that includes a7. If so,
unspec_volatile insn, at the very beginning of the function. This create a new pseudo and copy a7 into that pseudo at the very
is necessary because the register allocator will ignore conflicts beginning of the function, followed by the special "set_frame_ptr"
with a7 and may assign some other pseudo to a7. If that pseudo was unspec_volatile insn. The return value is either the original
assigned prior to this move, it would clobber the incoming argument operand, if it is not a7, or the new pseudo containing a copy of
in a7. By copying the argument out of a7 as the very first thing, the incoming argument. This is necessary because the register
and then immediately following that with an unspec_volatile to keep allocator will ignore conflicts with a7 and may either assign some
the scheduler away, we should avoid any problems. */ 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
bool the very first thing, and then immediately following that with an
xtensa_copy_incoming_a7 (rtx *operands, enum machine_mode mode) unspec_volatile to keep the scheduler away, we should avoid any
{ problems. Putting the set_frame_ptr insn at the beginning, with
if (a7_overlap_mentioned_p (operands[1]) only the a7 copy before it, also makes it easier for the prologue
&& !cfun->machine->incoming_a7_copied) 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
rtx mov, src; pointer. */
/* Despite defining SPLIT_COMPLEX_ARGS, complex function rtx
arguments may still appear if they are wrapped in a struct. xtensa_copy_incoming_a7 (rtx opnd)
For CQImode and CHImode arguments, this results in a move {
with a source operand of the form: "(subreg:SI (reg:CHI a7) rtx entry_insns = 0;
0)". The subreg is later removed by the reload pass, rtx reg, tmp;
resulting in the RTL for a7 being regenerated using enum machine_mode mode;
hard_frame_pointer_rtx, and making it impossible for us to
distinguish the function argument. Detect this here when if (!cfun->machine->need_a7_copy)
generating the RTL and remove the subreg immediately so that return opnd;
reload won't mess it up. */
src = operands[1]; /* This function should never be called again once a7 has been copied. */
if (GET_CODE (src) == SUBREG if (cfun->machine->set_frame_ptr_insn)
&& GET_CODE (SUBREG_REG (src)) == REG abort ();
&& REGNO (SUBREG_REG (src)) == A7_REG
&& SUBREG_BYTE (src) == 0 mode = GET_MODE (opnd);
&& (GET_MODE (SUBREG_REG (src)) == CHImode
|| GET_MODE (SUBREG_REG (src)) == CQImode)) /* The operand using a7 may come in a later instruction, so just return
operands[1] = gen_raw_REG (mode, A7_REG); the original operand if it doesn't use a7. */
reg = opnd;
if (GET_CODE (reg) == SUBREG)
{
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;
/* 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 ();
cfun->machine->need_a7_copy = false;
/* 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. */
push_to_sequence (entry_insns);
tmp = gen_reg_rtx (mode);
switch (mode) switch (mode)
{ {
case DFmode: case DFmode:
mov = gen_movdf_internal (operands[0], operands[1]); 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; break;
case SFmode: case SFmode:
mov = gen_movsf_internal (operands[0], operands[1]); emit_insn (gen_movsf_internal (tmp, gen_raw_REG (mode, A7_REG)));
break;
case DImode:
mov = gen_movdi_internal (operands[0], operands[1]);
break; break;
case SImode: case SImode:
mov = gen_movsi_internal (operands[0], operands[1]); emit_insn (gen_movsi_internal (tmp, gen_raw_REG (mode, A7_REG)));
break; break;
case HImode: case HImode:
mov = gen_movhi_internal (operands[0], operands[1]); emit_insn (gen_movhi_internal (tmp, gen_raw_REG (mode, A7_REG)));
break; break;
case QImode: case QImode:
mov = gen_movqi_internal (operands[0], operands[1]); emit_insn (gen_movqi_internal (tmp, gen_raw_REG (mode, A7_REG)));
break; break;
default: default:
abort (); abort ();
} }
/* Insert the instructions before any other argument copies. cfun->machine->set_frame_ptr_insn = emit_insn (gen_set_frame_ptr ());
(The set_frame_ptr insn comes _after_ the move, so push it entry_insns = get_insns ();
out first.) */ 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 (); push_topmost_sequence ();
emit_insn_after (gen_set_frame_ptr (), get_insns ()); emit_insn_after (entry_insns, get_insns ());
emit_insn_after (mov, get_insns ());
pop_topmost_sequence (); pop_topmost_sequence ();
/* 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. */
cfun->machine->incoming_a7_copied = true;
return 1;
} }
return 0; return tmp;
} }
...@@ -1727,11 +1751,10 @@ xtensa_dbx_register_number (int regno) ...@@ -1727,11 +1751,10 @@ xtensa_dbx_register_number (int regno)
/* Initialize CUMULATIVE_ARGS for a function. */ /* Initialize CUMULATIVE_ARGS for a function. */
void void
init_cumulative_args (CUMULATIVE_ARGS *cum, init_cumulative_args (CUMULATIVE_ARGS *cum, int incoming)
tree fntype ATTRIBUTE_UNUSED,
rtx libname ATTRIBUTE_UNUSED)
{ {
cum->arg_words = 0; cum->arg_words = 0;
cum->incoming = incoming;
} }
...@@ -1768,7 +1791,6 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, ...@@ -1768,7 +1791,6 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
int regbase, words, max; int regbase, words, max;
int *arg_words; int *arg_words;
int regno; int regno;
enum machine_mode result_mode;
arg_words = &cum->arg_words; arg_words = &cum->arg_words;
regbase = (incoming_p ? GP_ARG_FIRST : GP_OUTGOING_ARG_FIRST); 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, ...@@ -1785,37 +1807,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
return (rtx)0; return (rtx)0;
regno = regbase + *arg_words; 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 ((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)); if (cum->incoming && regno <= A7_REG && regno + words > A7_REG)
for (n = 0; n < words; n++) cfun->machine->need_a7_copy = true;
{
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) ...@@ -2264,41 +2260,18 @@ xtensa_expand_prologue (void)
if (frame_pointer_needed) if (frame_pointer_needed)
{ {
rtx first, insn, set_frame_ptr_insn = 0; if (cfun->machine->set_frame_ptr_insn)
{
rtx first, insn;
push_topmost_sequence (); push_topmost_sequence ();
first = get_insns (); first = get_insns ();
pop_topmost_sequence (); 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))
{
rtx pat;
if (!INSN_P (insn))
continue;
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 /* For all instructions prior to set_frame_ptr_insn, replace
hard_frame_pointer references with stack_pointer. */ hard_frame_pointer references with stack_pointer. */
for (insn = first; for (insn = first;
insn != set_frame_ptr_insn; insn != cfun->machine->set_frame_ptr_insn;
insn = NEXT_INSN (insn)) insn = NEXT_INSN (insn))
{ {
if (INSN_P (insn)) if (INSN_P (insn))
...@@ -2400,9 +2373,8 @@ xtensa_builtin_saveregs (void) ...@@ -2400,9 +2373,8 @@ xtensa_builtin_saveregs (void)
rtx gp_regs, dest; rtx gp_regs, dest;
int arg_words = current_function_arg_words; int arg_words = current_function_arg_words;
int gp_left = MAX_ARGS_IN_REGISTERS - arg_words; int gp_left = MAX_ARGS_IN_REGISTERS - arg_words;
int i;
if (gp_left == 0) if (gp_left <= 0)
return const0_rtx; return const0_rtx;
/* Allocate the general-purpose register space. */ /* Allocate the general-purpose register space. */
...@@ -2414,16 +2386,9 @@ xtensa_builtin_saveregs (void) ...@@ -2414,16 +2386,9 @@ xtensa_builtin_saveregs (void)
dest = change_address (gp_regs, SImode, dest = change_address (gp_regs, SImode,
plus_constant (XEXP (gp_regs, 0), plus_constant (XEXP (gp_regs, 0),
arg_words * UNITS_PER_WORD)); arg_words * UNITS_PER_WORD));
cfun->machine->need_a7_copy = true;
/* Note: Don't use move_block_from_reg() here because the incoming cfun->machine->vararg_a7 = true;
argument in a7 cannot be represented by hard_frame_pointer_rtx. move_block_from_reg (GP_ARG_FIRST + arg_words, dest, gp_left);
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));
}
return XEXP (gp_regs, 0); return XEXP (gp_regs, 0);
} }
...@@ -2749,55 +2714,6 @@ order_regs_for_local_alloc (void) ...@@ -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 /* Some Xtensa targets support multiple bss sections. If the section
name ends with ".bss", add SECTION_BSS to the flags. */ name ends with ".bss", add SECTION_BSS to the flags. */
......
...@@ -736,23 +736,21 @@ extern enum reg_class xtensa_char_to_class[256]; ...@@ -736,23 +736,21 @@ extern enum reg_class xtensa_char_to_class[256];
#define FUNCTION_ARG_REGNO_P(N) \ #define FUNCTION_ARG_REGNO_P(N) \
((N) >= GP_OUTGOING_ARG_FIRST && (N) <= GP_OUTGOING_ARG_LAST) ((N) >= GP_OUTGOING_ARG_FIRST && (N) <= GP_OUTGOING_ARG_LAST)
/* Define a data type for recording info about an argument list /* Record the number of argument words seen so far, along with a flag to
during the scan of that argument list. This data type should indicate whether these are incoming arguments. (FUNCTION_INCOMING_ARG
hold all necessary information about the function itself is used for both incoming and outgoing args, so a separate flag is
and about the args processed so far, enough to enable macros needed. */
such as FUNCTION_ARG to determine where the next arg should go. */ typedef struct xtensa_args
typedef struct xtensa_args { {
int arg_words; /* # total words the arguments take */ int arg_words;
int incoming;
} CUMULATIVE_ARGS; } 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) \ #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) \ #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 /* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE. of mode MODE and data type TYPE.
...@@ -798,12 +796,6 @@ typedef struct xtensa_args { ...@@ -798,12 +796,6 @@ typedef struct xtensa_args {
/* Pass complex arguments independently. */ /* Pass complex arguments independently. */
#define SPLIT_COMPLEX_ARGS 1 #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 /* Profiling Xtensa code is typically done with the built-in profiling
feature of Tensilica's instruction set simulator, which does not feature of Tensilica's instruction set simulator, which does not
require any compiler support. Profiling code on a real (i.e., require any compiler support. Profiling code on a real (i.e.,
...@@ -1142,11 +1134,6 @@ typedef struct xtensa_args { ...@@ -1142,11 +1134,6 @@ typedef struct xtensa_args {
/* Prefer word-sized loads. */ /* Prefer word-sized loads. */
#define SLOW_BYTE_ACCESS 1 #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. */ /* Shift instructions ignore all but the low-order few bits. */
#define SHIFT_COUNT_TRUNCATED 1 #define SHIFT_COUNT_TRUNCATED 1
......
...@@ -803,15 +803,11 @@ ...@@ -803,15 +803,11 @@
if (CONSTANT_P (operands[1]) && !TARGET_CONST16) if (CONSTANT_P (operands[1]) && !TARGET_CONST16)
operands[1] = force_const_mem (DImode, operands[1]); operands[1] = force_const_mem (DImode, operands[1]);
if (!(reload_in_progress | reload_completed))
{
if (!register_operand (operands[0], DImode) if (!register_operand (operands[0], DImode)
&& !register_operand (operands[1], DImode)) && !register_operand (operands[1], DImode))
operands[1] = force_reg (DImode, operands[1]); operands[1] = force_reg (DImode, operands[1]);
if (xtensa_copy_incoming_a7 (operands, DImode)) operands[1] = xtensa_copy_incoming_a7 (operands[1]);
DONE;
}
}) })
(define_insn_and_split "movdi_internal" (define_insn_and_split "movdi_internal"
...@@ -934,18 +930,15 @@ ...@@ -934,18 +930,15 @@
if (!TARGET_CONST16 && CONSTANT_P (operands[1])) if (!TARGET_CONST16 && CONSTANT_P (operands[1]))
operands[1] = force_const_mem (SFmode, operands[1]); operands[1] = force_const_mem (SFmode, operands[1]);
if (!(reload_in_progress | reload_completed))
{
if ((!register_operand (operands[0], SFmode) if ((!register_operand (operands[0], SFmode)
&& !register_operand (operands[1], SFmode)) && !register_operand (operands[1], SFmode))
|| (FP_REG_P (xt_true_regnum (operands[0])) || (FP_REG_P (xt_true_regnum (operands[0]))
&& !(reload_in_progress | reload_completed)
&& (constantpool_mem_p (operands[1]) && (constantpool_mem_p (operands[1])
|| CONSTANT_P (operands[1])))) || CONSTANT_P (operands[1]))))
operands[1] = force_reg (SFmode, operands[1]); operands[1] = force_reg (SFmode, operands[1]);
if (xtensa_copy_incoming_a7 (operands, SFmode)) operands[1] = xtensa_copy_incoming_a7 (operands[1]);
DONE;
}
}) })
(define_insn "movsf_internal" (define_insn "movsf_internal"
...@@ -1015,15 +1008,11 @@ ...@@ -1015,15 +1008,11 @@
if (CONSTANT_P (operands[1]) && !TARGET_CONST16) if (CONSTANT_P (operands[1]) && !TARGET_CONST16)
operands[1] = force_const_mem (DFmode, operands[1]); operands[1] = force_const_mem (DFmode, operands[1]);
if (!(reload_in_progress | reload_completed))
{
if (!register_operand (operands[0], DFmode) if (!register_operand (operands[0], DFmode)
&& !register_operand (operands[1], DFmode)) && !register_operand (operands[1], DFmode))
operands[1] = force_reg (DFmode, operands[1]); operands[1] = force_reg (DFmode, operands[1]);
if (xtensa_copy_incoming_a7 (operands, DFmode)) operands[1] = xtensa_copy_incoming_a7 (operands[1]);
DONE;
}
}) })
(define_insn_and_split "movdf_internal" (define_insn_and_split "movdf_internal"
...@@ -1081,7 +1070,16 @@ ...@@ -1081,7 +1070,16 @@
;; Shift instructions. ;; 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") [(set (match_operand:SI 0 "register_operand" "=a,a")
(ashift:SI (match_operand:SI 1 "register_operand" "r,r") (ashift:SI (match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "arith_operand" "J,r")))] (match_operand:SI 2 "arith_operand" "J,r")))]
......
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