lib2funcs.S (TRAMPOLINE_SIZE): Change from 49 to 59.

* config/xtensa/lib2funcs.S (TRAMPOLINE_SIZE): Change from 49 to 59.
        * config/xtensa/xtensa-config.h (XCHAL_HAVE_CONST16,
        XCHAL_HAVE_L32R): New.
        * config/xtensa/xtensa-protos.h (non_const_move_operand,
        xtensa_load_constant, xtensa_function_prologue,
        xtensa_function_epilogue): Delete prototypes.
        (xtensa_expand_prologue): New.
        * config/xtensa/xtensa.c (frame_size_const,
        TARGET_ASM_FUNCTION_PROLOGUE, TARGET_MACHINE_DEPENDENT_REORG,
        non_const_move_operand, xtensa_load_constant, xtensa_reorg,
        xtensa_function_prologue): Delete.
        (add_operand, xtensa_mem_offset): Formatting.
        (move_operand): If the const16 option is available, allow any SFmode
        and SImode constants.
        (xtensa_emit_move_sequence): Inline the former contents of
        xtensa_load_constant with modifications to handle the const16 option.
        (override_options): Add xtensa_char_to_class['W'] and set it to
        the general register class only if the const16 option is enabled.
        Fix formatting.  Disallow PIC when using the const16 option.
        (print_operand): Reorganize to switch on "letter" instead of the
        RTL code.  Add output_operand_lossage calls for invalid cases.
        Add support for 't' and 'b' letters.
        (xtensa_expand_prologue): New function to replace
        xtensa_function_prologue and xtensa_reorg.
        (xtensa_function_epilogue): Declare this as static.  Delete code
        to print the retw.n or retw instruction.
        (xtensa_return_addr): Use A0_REG instead of 0.
        (xtensa_rtx_costs): Add costs for using the const16 option.
        * config/xtensa/xtensa.h (MASK_CONST16, TARGET_CONST16): New.
        (TARGET_DEFAULT): Add CONST16 if L32R instructions not available.
        (TARGET_SWITCHES): Add "const16" and "no-const16".
        (REG_CLASS_FROM_LETTER): Add comment about new 'W' letter.
        (EXTRA_CONSTRAINT): Change 'T' constraint to only apply when not
        using the const16 option.
        (TRAMPOLINE_TEMPLATE): Rewrite to avoid hardwired use of l32r insn.
        (TRAMPOLINE_SIZE): Change from 49 to 59.
        (INITIALIZE_TRAMPOLINE): Adjust offsets to match new trampoline.
        (GO_IF_LEGITIMATE_ADDRESS): Do not allow constant pool addresses
        when using the const16 option.
        (PREDICATE_CODES): Delete non_const_move_operand.
        * config/xtensa/xtensa.md (define_constants): Add A1_REG, A8_REG, and
        UNSPECV_ENTRY.
        (movdi, movdf): If the source is a constant, always expand to a
        sequence of movsi insns.
        (movdi_internal, movdf_internal): Remove alternative using l32r insns.
        (movsi_internal, movsf_internal): Add alternative using const16 insns.
        (movsf): Add const16 support.
        (entry, prologue, epilogue): New.
        (set_frame_ptr): Add missing mode for unspec_volatile operation.
        Likewise for subsequent split pattern.
        * doc/invoke.texi (Option Summary, Xtensa Options): Document new
        "-mconst16" and "-mno-const16" options.

From-SVN: r66809
This commit is contained in:
Bob Wilson 2003-05-14 18:37:26 +00:00
parent ae49d6e592
commit f42f5a1b1e
7 changed files with 437 additions and 377 deletions

View File

@ -151,7 +151,7 @@ __xtensa_nonlocal_goto:
make sure that the modified instructions are loaded into the instruction
fetch buffer. */
#define TRAMPOLINE_SIZE 49
#define TRAMPOLINE_SIZE 59
.text
.align 4

View File

@ -1,5 +1,5 @@
/* Xtensa configuration settings.
Copyright (C) 2001,2002 Free Software Foundation, Inc.
Copyright (C) 2001,2002,2003 Free Software Foundation, Inc.
Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
** NOTE: This file was automatically generated by the Xtensa Processor
@ -27,6 +27,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define XCHAL_HAVE_BE 1
#define XCHAL_HAVE_DENSITY 1
#define XCHAL_HAVE_CONST16 0
#define XCHAL_HAVE_L32R 1
#define XCHAL_HAVE_MAC16 0
#define XCHAL_HAVE_MUL16 0
#define XCHAL_HAVE_MUL32 0

View File

@ -57,11 +57,9 @@ extern int smalloffset_mem_p PARAMS ((rtx));
extern int smalloffset_double_mem_p PARAMS ((rtx));
extern int constantpool_address_p PARAMS ((rtx));
extern int constantpool_mem_p PARAMS ((rtx));
extern int non_const_move_operand PARAMS ((rtx, enum machine_mode));
extern int const_float_1_operand PARAMS ((rtx, enum machine_mode));
extern int fpmem_offset_operand PARAMS ((rtx, enum machine_mode));
extern void xtensa_extend_reg PARAMS ((rtx, rtx));
extern void xtensa_load_constant PARAMS ((rtx, rtx));
extern int branch_operator PARAMS ((rtx, enum machine_mode));
extern int ubranch_operator PARAMS ((rtx, enum machine_mode));
extern int boolean_operator PARAMS ((rtx, enum machine_mode));
@ -110,8 +108,7 @@ extern int xtensa_dbx_register_number PARAMS ((int));
extern void override_options PARAMS ((void));
extern long compute_frame_size PARAMS ((int));
extern int xtensa_frame_pointer_required PARAMS ((void));
extern void xtensa_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
extern void xtensa_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
extern void xtensa_expand_prologue PARAMS ((void));
extern void order_regs_for_local_alloc PARAMS ((void));
#endif /* !__XTENSA_PROTOS_H__ */

View File

@ -198,29 +198,18 @@ static rtx gen_conditional_move PARAMS ((rtx));
static rtx fixup_subreg_mem PARAMS ((rtx x));
static enum machine_mode xtensa_find_mode_for_size PARAMS ((unsigned));
static struct machine_function * xtensa_init_machine_status PARAMS ((void));
static void xtensa_reorg PARAMS ((void));
static void printx PARAMS ((FILE *, signed int));
static void xtensa_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static unsigned int xtensa_multibss_section_type_flags
PARAMS ((tree, const char *, int));
static void xtensa_select_rtx_section
PARAMS ((enum machine_mode, rtx, unsigned HOST_WIDE_INT));
static bool xtensa_rtx_costs PARAMS ((rtx, int, int, int *));
static rtx frame_size_const;
static int current_function_arg_words;
static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
REG_ALLOC_ORDER;
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate.
Refer to the array 'regs_ever_live' to determine which registers
to save; 'regs_ever_live[I]' is nonzero if register number I
is ever used in the function. This macro is responsible for
knowing which registers should not be saved even if used. */
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE xtensa_function_prologue
/* This macro generates the assembly code for function exit,
on machines that need it. If FUNCTION_EPILOGUE is not defined
@ -244,9 +233,6 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST hook_int_rtx_0
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG xtensa_reorg
struct gcc_target targetm = TARGET_INITIALIZER;
@ -412,8 +398,7 @@ add_operand (op, mode)
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT)
return (xtensa_simm8 (INTVAL (op)) ||
xtensa_simm8x256 (INTVAL (op)));
return (xtensa_simm8 (INTVAL (op)) || xtensa_simm8x256 (INTVAL (op)));
return register_operand (op, mode);
}
@ -610,19 +595,23 @@ move_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (register_operand (op, mode))
if (register_operand (op, mode)
|| memory_operand (op, mode))
return TRUE;
if (mode == SFmode)
return TARGET_CONST16 && CONSTANT_P (op);
/* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and
result in 0/1. */
if (GET_CODE (op) == CONSTANT_P_RTX)
return TRUE;
if (GET_CODE (op) == CONST_INT)
return xtensa_simm12b (INTVAL (op));
if (GET_CODE (op) == CONST_INT && xtensa_simm12b (INTVAL (op)))
return TRUE;
if (GET_CODE (op) == MEM)
return memory_address_p (mode, XEXP (op, 0));
if (mode == SImode)
return TARGET_CONST16 && CONSTANT_P (op);
return FALSE;
}
@ -702,21 +691,6 @@ constantpool_mem_p (op)
}
int
non_const_move_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (register_operand (op, mode))
return 1;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) == MEM)
return memory_address_p (mode, XEXP (op, 0));
return FALSE;
}
/* Accept the floating point constant 1 in the appropriate mode. */
int
@ -778,32 +752,6 @@ xtensa_extend_reg (dst, src)
}
void
xtensa_load_constant (dst, src)
rtx dst;
rtx src;
{
enum machine_mode mode = GET_MODE (dst);
src = force_const_mem (SImode, src);
/* PC-relative loads are always SImode so we have to add a SUBREG if that
is not the desired mode */
if (mode != SImode)
{
if (register_operand (dst, mode))
dst = simplify_gen_subreg (SImode, dst, mode, 0);
else
{
src = force_reg (SImode, src);
src = gen_lowpart_SUBREG (mode, src);
}
}
emit_move_insn (dst, src);
}
int
branch_operator (x, mode)
rtx x;
@ -899,8 +847,8 @@ xtensa_mem_offset (v, mode)
moved in < "move_ratio" pieces. The worst case is when the block is
aligned but has a size of (3 mod 4) (does this happen?) so that the
last piece requires a byte load/store. */
return (xtensa_uimm8 (v) &&
xtensa_uimm8 (v + MOVE_MAX * LARGEST_MOVE_RATIO));
return (xtensa_uimm8 (v)
&& xtensa_uimm8 (v + MOVE_MAX * LARGEST_MOVE_RATIO));
case QImode:
return xtensa_uimm8 (v);
@ -1260,7 +1208,6 @@ xtensa_expand_scc (operands)
/* Emit insns to move operands[1] into operands[0].
Return 1 if we have written out everything that needs to be done to
do the move. Otherwise, return 0 and the caller will emit the move
normally. */
@ -1275,8 +1222,27 @@ xtensa_emit_move_sequence (operands, mode)
&& (GET_CODE (operands[1]) != CONST_INT
|| !xtensa_simm12b (INTVAL (operands[1]))))
{
xtensa_load_constant (operands[0], operands[1]);
return 1;
if (!TARGET_CONST16)
operands[1] = force_const_mem (SImode, operands[1]);
/* PC-relative loads are always SImode, and CONST16 is only
supported in the movsi pattern, so add a SUBREG for any other
(smaller) mode. */
if (mode != SImode)
{
if (register_operand (operands[0], mode))
{
operands[0] = simplify_gen_subreg (SImode, operands[0], mode, 0);
emit_move_insn (operands[0], operands[1]);
return 1;
}
else
{
operands[1] = force_reg (SImode, operands[1]);
operands[1] = gen_lowpart_SUBREG (mode, operands[1]);
}
}
}
if (!(reload_in_progress | reload_completed))
@ -1299,6 +1265,7 @@ xtensa_emit_move_sequence (operands, mode)
return 0;
}
static rtx
fixup_subreg_mem (x)
rtx x;
@ -1848,6 +1815,7 @@ override_options ()
xtensa_char_to_class['C'] = ((TARGET_MUL16) ? GR_REGS: NO_REGS);
xtensa_char_to_class['D'] = ((TARGET_DENSITY) ? GR_REGS: NO_REGS);
xtensa_char_to_class['d'] = ((TARGET_DENSITY) ? AR_REGS: NO_REGS);
xtensa_char_to_class['W'] = ((TARGET_CONST16) ? GR_REGS: NO_REGS);
/* Set up array giving whether a given register can hold a given mode. */
for (mode = VOIDmode;
@ -1862,8 +1830,8 @@ override_options ()
int temp;
if (ACC_REG_P (regno))
temp = (TARGET_MAC16 &&
(class == MODE_INT) && (size <= UNITS_PER_WORD));
temp = (TARGET_MAC16
&& (class == MODE_INT) && (size <= UNITS_PER_WORD));
else if (GP_REG_P (regno))
temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD));
else if (FP_REG_P (regno))
@ -1879,9 +1847,19 @@ override_options ()
init_machine_status = xtensa_init_machine_status;
/* Check PIC settings. There's no need for -fPIC on Xtensa and
some targets need to always use PIC. */
if (flag_pic > 1 || (XTENSA_ALWAYS_PIC))
/* Check PIC settings. PIC is only supported when using L32R
instructions, and some targets need to always use PIC. */
if (flag_pic && TARGET_CONST16)
error ("-f%s is not supported with CONST16 instructions",
(flag_pic > 1 ? "PIC" : "pic"));
else if (XTENSA_ALWAYS_PIC)
{
if (TARGET_CONST16)
error ("PIC is required but not supported with CONST16 instructions");
flag_pic = 1;
}
/* There's no need for -fPIC (as opposed to -fpic) on Xtensa. */
if (flag_pic > 1)
flag_pic = 1;
}
@ -1918,6 +1896,8 @@ override_options ()
'D' REG, print second register of double-word register operand
'N' MEM, print address of next word following a memory operand
'v' MEM, if memory reference is volatile, output a MEMW before it
't' any constant, add "@h" suffix for top 16 bits
'b' any constant, add "@l" suffix for bottom 16 bits
*/
static void
@ -1936,94 +1916,146 @@ printx (file, val)
void
print_operand (file, op, letter)
print_operand (file, x, letter)
FILE *file; /* file to write to */
rtx op; /* operand to print */
rtx x; /* operand to print */
int letter; /* %<letter> or 0 */
{
enum rtx_code code;
if (! op)
if (!x)
error ("PRINT_OPERAND null pointer");
code = GET_CODE (op);
switch (code)
switch (letter)
{
case REG:
case SUBREG:
{
int regnum = xt_true_regnum (op);
if (letter == 'D')
regnum++;
fprintf (file, "%s", reg_names[regnum]);
break;
}
case 'D':
if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
fprintf (file, "%s", reg_names[xt_true_regnum (x) + 1]);
else
output_operand_lossage ("invalid %%D value");
break;
case MEM:
/* For a volatile memory reference, emit a MEMW before the
load or store. */
if (letter == 'v')
{
if (MEM_VOLATILE_P (op) && TARGET_SERIALIZE_VOLATILE)
fprintf (file, "memw\n\t");
break;
}
else if (letter == 'N')
{
enum machine_mode mode;
switch (GET_MODE (op))
{
case DFmode: mode = SFmode; break;
case DImode: mode = SImode; break;
default: abort ();
}
op = adjust_address (op, mode, 4);
}
output_address (XEXP (op, 0));
break;
case CONST_INT:
switch (letter)
case 'v':
if (GET_CODE (x) == MEM)
{
case 'K':
{
int num_bits = 0;
unsigned val = INTVAL (op);
while (val & 1)
{
num_bits += 1;
val = val >> 1;
}
if ((val != 0) || (num_bits == 0) || (num_bits > 16))
fatal_insn ("invalid mask", op);
/* For a volatile memory reference, emit a MEMW before the
load or store. */
if (MEM_VOLATILE_P (x) && TARGET_SERIALIZE_VOLATILE)
fprintf (file, "memw\n\t");
}
else
output_operand_lossage ("invalid %%v value");
break;
fprintf (file, "%d", num_bits);
break;
}
case 'N':
if (GET_CODE (x) == MEM
&& (GET_MODE (x) == DFmode || GET_MODE (x) == DImode))
{
x = adjust_address (x, GET_MODE (x) == DFmode ? SFmode : SImode, 4);
output_address (XEXP (x, 0));
}
else
output_operand_lossage ("invalid %%N value");
break;
case 'L':
fprintf (file, "%ld", (32 - INTVAL (op)) & 0x1f);
break;
case 'K':
if (GET_CODE (x) == CONST_INT)
{
int num_bits = 0;
unsigned val = INTVAL (x);
while (val & 1)
{
num_bits += 1;
val = val >> 1;
}
if ((val != 0) || (num_bits == 0) || (num_bits > 16))
fatal_insn ("invalid mask", x);
case 'R':
fprintf (file, "%ld", INTVAL (op) & 0x1f);
break;
fprintf (file, "%d", num_bits);
}
else
output_operand_lossage ("invalid %%K value");
break;
case 'x':
printx (file, INTVAL (op));
break;
case 'L':
if (GET_CODE (x) == CONST_INT)
fprintf (file, "%ld", (32 - INTVAL (x)) & 0x1f);
else
output_operand_lossage ("invalid %%L value");
break;
case 'd':
default:
fprintf (file, "%ld", INTVAL (op));
break;
case 'R':
if (GET_CODE (x) == CONST_INT)
fprintf (file, "%ld", INTVAL (x) & 0x1f);
else
output_operand_lossage ("invalid %%R value");
break;
case 'x':
if (GET_CODE (x) == CONST_INT)
printx (file, INTVAL (x));
else
output_operand_lossage ("invalid %%x value");
break;
case 'd':
if (GET_CODE (x) == CONST_INT)
fprintf (file, "%ld", INTVAL (x));
else
output_operand_lossage ("invalid %%d value");
break;
case 't':
case 'b':
if (GET_CODE (x) == CONST_INT)
{
printx (file, INTVAL (x));
fputs (letter == 't' ? "@h" : "@l", file);
}
else if (GET_CODE (x) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
if (GET_MODE (x) == SFmode)
{
long l;
REAL_VALUE_TO_TARGET_SINGLE (r, l);
fprintf (file, "0x%08lx@%c", l, letter == 't' ? 'h' : 'l');
}
else
output_operand_lossage ("invalid %%t/%%b value");
}
else if (GET_CODE (x) == CONST)
{
/* X must be a symbolic constant on ELF. Write an expression
suitable for 'const16' that sets the high or low 16 bits. */
if (GET_CODE (XEXP (x, 0)) != PLUS
|| (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF
&& GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
|| GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)
output_operand_lossage ("invalid %%t/%%b value");
print_operand (file, XEXP (XEXP (x, 0), 0), 0);
fputs (letter == 't' ? "@h" : "@l", file);
/* There must be a non-alphanumeric character between 'h' or 'l'
and the number. The '-' is added by print_operand() already. */
if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
fputs ("+", file);
print_operand (file, XEXP (XEXP (x, 0), 1), 0);
}
else
{
output_addr_const (file, x);
fputs (letter == 't' ? "@h" : "@l", file);
}
break;
default:
output_addr_const (file, op);
if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
fprintf (file, "%s", reg_names[xt_true_regnum (x)]);
else if (GET_CODE (x) == MEM)
output_address (XEXP (x, 0));
else if (GET_CODE (x) == CONST_INT)
fprintf (file, "%ld", INTVAL (x));
else
output_addr_const (file, x);
}
}
@ -2191,129 +2223,85 @@ xtensa_frame_pointer_required ()
}
/* If the stack frame size is too big to fit in the immediate field of
the ENTRY instruction, we need to store the frame size in the
constant pool. However, the code in xtensa_function_prologue runs too
late to be able to add anything to the constant pool. Since the
final frame size isn't known until reload is complete, this seems
like the best place to do it.
There may also be some fixup required if there is an incoming argument
in a7 and the function requires a frame pointer. */
static void
xtensa_reorg ()
{
rtx first, insn, set_frame_ptr_insn = 0;
unsigned long tsize = compute_frame_size (get_frame_size ());
first = get_insns ();
if (tsize < (1 << (12+3)))
frame_size_const = 0;
else
{
frame_size_const = force_const_mem (SImode, GEN_INT (tsize - 16));;
/* make sure the constant is used so it doesn't get eliminated
from the constant pool */
emit_insn_before (gen_rtx_USE (SImode, frame_size_const), first);
}
if (!frame_pointer_needed)
return;
/* 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
hard_frame_pointer references with stack_pointer */
for (insn = first; insn != set_frame_ptr_insn; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
PATTERN (insn) = replace_rtx (copy_rtx (PATTERN (insn)),
hard_frame_pointer_rtx,
stack_pointer_rtx);
}
}
else
{
/* emit the frame pointer move immediately after the NOTE that starts
the function */
emit_insn_after (gen_movsi (hard_frame_pointer_rtx,
stack_pointer_rtx), first);
}
}
/* Set up the stack and frame (if desired) for the function. */
void
xtensa_function_prologue (file, size)
FILE *file;
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
xtensa_expand_prologue ()
{
unsigned long tsize = compute_frame_size (get_frame_size ());
HOST_WIDE_INT total_size;
rtx size_rtx;
total_size = compute_frame_size (get_frame_size ());
size_rtx = GEN_INT (total_size);
if (total_size < (1 << (12+3)))
emit_insn (gen_entry (size_rtx, size_rtx));
else
{
/* Use a8 as a temporary since a0-a7 may be live. */
rtx tmp_reg = gen_rtx_REG (Pmode, A8_REG);
emit_insn (gen_entry (size_rtx, GEN_INT (MIN_FRAME_SIZE)));
emit_move_insn (tmp_reg, GEN_INT (total_size - MIN_FRAME_SIZE));
emit_insn (gen_subsi3 (tmp_reg, stack_pointer_rtx, tmp_reg));
emit_move_insn (stack_pointer_rtx, tmp_reg);
}
if (frame_pointer_needed)
fprintf (file, "\t.frame\ta7, %ld\n", tsize);
else
fprintf (file, "\t.frame\tsp, %ld\n", tsize);
if (tsize < (1 << (12+3)))
{
fprintf (file, "\tentry\tsp, %ld\n", tsize);
}
else
{
fprintf (file, "\tentry\tsp, 16\n");
rtx first, insn, set_frame_ptr_insn = 0;
/* use a8 as a temporary since a0-a7 may be live */
fprintf (file, "\tl32r\ta8, ");
print_operand (file, frame_size_const, 0);
fprintf (file, "\n\tsub\ta8, sp, a8\n");
fprintf (file, "\tmovsp\tsp, a8\n");
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))
{
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
hard_frame_pointer references with stack_pointer. */
for (insn = first;
insn != set_frame_ptr_insn;
insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
PATTERN (insn) = replace_rtx (copy_rtx (PATTERN (insn)),
hard_frame_pointer_rtx,
stack_pointer_rtx);
}
}
else
emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
}
}
/* Do any necessary cleanup after a function to restore
stack, frame, and regs. */
/* Clear variables at function end. */
void
xtensa_function_epilogue (file, size)
FILE *file;
FILE *file ATTRIBUTE_UNUSED;
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{
rtx insn = get_last_insn ();
/* If the last insn was a BARRIER, we don't have to write anything. */
if (GET_CODE (insn) == NOTE)
insn = prev_nonnote_insn (insn);
if (insn == 0 || GET_CODE (insn) != BARRIER)
fprintf (file, TARGET_DENSITY ? "\tretw.n\n" : "\tretw\n");
xtensa_current_frame_size = 0;
}
@ -2326,7 +2314,7 @@ xtensa_return_addr (count, frame)
rtx result, retaddr;
if (count == -1)
retaddr = gen_rtx_REG (Pmode, 0);
retaddr = gen_rtx_REG (Pmode, A0_REG);
else
{
rtx addr = plus_constant (frame, -4 * UNITS_PER_WORD);
@ -2882,6 +2870,8 @@ xtensa_rtx_costs (x, code, outer_code, total)
}
if (xtensa_simm12b (INTVAL (x)))
*total = 5;
else if (TARGET_CONST16)
*total = COSTS_N_INSNS (2);
else
*total = 6;
return true;
@ -2889,11 +2879,17 @@ xtensa_rtx_costs (x, code, outer_code, total)
case CONST:
case LABEL_REF:
case SYMBOL_REF:
*total = 5;
if (TARGET_CONST16)
*total = COSTS_N_INSNS (2);
else
*total = 5;
return true;
case CONST_DOUBLE:
*total = 7;
if (TARGET_CONST16)
*total = COSTS_N_INSNS (4);
else
*total = 7;
return true;
case MEM:

View File

@ -61,6 +61,7 @@ extern unsigned xtensa_current_frame_size;
#define MASK_HARD_FLOAT_RSQRT 0x00004000 /* floating-point recip sqrt */
#define MASK_NO_FUSED_MADD 0x00008000 /* avoid f-p mul/add */
#define MASK_SERIALIZE_VOLATILE 0x00010000 /* serialize volatile refs */
#define MASK_CONST16 0x00020000 /* use CONST16 instruction */
/* Macros used in the machine description to test the flags. */
@ -81,12 +82,14 @@ extern unsigned xtensa_current_frame_size;
#define TARGET_HARD_FLOAT_RSQRT (target_flags & MASK_HARD_FLOAT_RSQRT)
#define TARGET_NO_FUSED_MADD (target_flags & MASK_NO_FUSED_MADD)
#define TARGET_SERIALIZE_VOLATILE (target_flags & MASK_SERIALIZE_VOLATILE)
#define TARGET_CONST16 (target_flags & MASK_CONST16)
/* Default target_flags if no switches are specified */
#define TARGET_DEFAULT ( \
(XCHAL_HAVE_BE ? MASK_BIG_ENDIAN : 0) | \
(XCHAL_HAVE_DENSITY ? MASK_DENSITY : 0) | \
(XCHAL_HAVE_L32R ? 0 : MASK_CONST16) | \
(XCHAL_HAVE_MAC16 ? MASK_MAC16 : 0) | \
(XCHAL_HAVE_MUL16 ? MASK_MUL16 : 0) | \
(XCHAL_HAVE_MUL32 ? MASK_MUL32 : 0) | \
@ -114,6 +117,10 @@ extern unsigned xtensa_current_frame_size;
N_("Use the Xtensa code density option")}, \
{"no-density", -MASK_DENSITY, \
N_("Do not use the Xtensa code density option")}, \
{"const16", MASK_CONST16, \
N_("Use CONST16 instruction to load constants")}, \
{"no-const16", -MASK_CONST16, \
N_("Use PC-relative L32R instruction to load constants")}, \
{"mac16", MASK_MAC16, \
N_("Use the Xtensa MAC16 option")}, \
{"no-mac16", -MASK_MAC16, \
@ -629,6 +636,7 @@ extern const enum reg_class xtensa_regno_to_class[FIRST_PSEUDO_REGISTER];
'A' MAC16 accumulator (only if MAC16 option enabled)
'B' general-purpose registers (only if sext instruction enabled)
'C' general-purpose registers (only if mul16 option enabled)
'W' general-purpose registers (only if const16 option enabled)
'b' coprocessor boolean registers
'f' floating-point registers
*/
@ -699,7 +707,7 @@ extern enum reg_class xtensa_char_to_class[256];
&& REGNO (OP) >= FIRST_PSEUDO_REGISTER) \
: ((CODE) == 'R') ? smalloffset_mem_p (OP) \
: ((CODE) == 'S') ? smalloffset_double_mem_p (OP) \
: ((CODE) == 'T') ? constantpool_mem_p (OP) \
: ((CODE) == 'T') ? !TARGET_CONST16 && constantpool_mem_p (OP) \
: ((CODE) == 'U') ? !constantpool_mem_p (OP) \
: FALSE)
@ -968,24 +976,27 @@ typedef struct xtensa_args {
fprintf (STREAM, "\t.begin no-generics\n"); \
fprintf (STREAM, "\tentry\tsp, %d\n", MIN_FRAME_SIZE); \
\
/* GCC isn't prepared to deal with data at the beginning of the \
trampoline, and the Xtensa l32r instruction requires that the \
constant pool be located before the code. We put the constant \
pool in the middle of the trampoline and jump around it. */ \
/* save the return address */ \
fprintf (STREAM, "\tmov\ta10, a0\n"); \
\
fprintf (STREAM, "\tj\t.Lskipconsts\n"); \
/* Use a CALL0 instruction to skip past the constants and in the \
process get the PC into A0. This allows PC-relative access to \
the constants without relying on L32R, which may not always be \
available. */ \
\
fprintf (STREAM, "\tcall0\t.Lskipconsts\n"); \
fprintf (STREAM, "\t.align\t4\n"); \
fprintf (STREAM, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE)); \
fprintf (STREAM, ".Lchainval:%s0\n", integer_asm_op (4, TRUE)); \
fprintf (STREAM, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE)); \
fprintf (STREAM, ".Lskipconsts:\n"); \
\
/* store the static chain */ \
fprintf (STREAM, "\tl32r\ta8, .Lchainval\n"); \
fprintf (STREAM, "\ts32i\ta8, sp, %d\n", \
MIN_FRAME_SIZE - (5 * UNITS_PER_WORD)); \
fprintf (STREAM, "\taddi\ta0, a0, 3\n"); \
fprintf (STREAM, "\tl32i\ta8, a0, 0\n"); \
fprintf (STREAM, "\ts32i\ta8, sp, %d\n", MIN_FRAME_SIZE - 20); \
\
/* set the proper stack pointer value */ \
fprintf (STREAM, "\tl32r\ta8, .Lfnaddr\n"); \
fprintf (STREAM, "\tl32i\ta8, a0, 4\n"); \
fprintf (STREAM, "\tl32i\ta9, a8, 0\n"); \
fprintf (STREAM, "\textui\ta9, a9, %d, 12\n", \
TARGET_BIG_ENDIAN ? 8 : 12); \
@ -994,6 +1005,9 @@ typedef struct xtensa_args {
fprintf (STREAM, "\tsub\ta9, sp, a9\n"); \
fprintf (STREAM, "\tmovsp\tsp, a9\n"); \
\
/* restore the return address */ \
fprintf (STREAM, "\tmov\ta0, a10\n"); \
\
/* jump to the instruction following the entry */ \
fprintf (STREAM, "\taddi\ta8, a8, 3\n"); \
fprintf (STREAM, "\tjx\ta8\n"); \
@ -1001,7 +1015,7 @@ typedef struct xtensa_args {
} while (0)
/* Size in bytes of the trampoline, as an integer. */
#define TRAMPOLINE_SIZE 49
#define TRAMPOLINE_SIZE 59
/* Alignment required for trampolines, in bits. */
#define TRAMPOLINE_ALIGNMENT (32)
@ -1010,8 +1024,8 @@ typedef struct xtensa_args {
#define INITIALIZE_TRAMPOLINE(ADDR, FUNC, CHAIN) \
do { \
rtx addr = ADDR; \
emit_move_insn (gen_rtx_MEM (SImode, plus_constant (addr, 8)), FUNC); \
emit_move_insn (gen_rtx_MEM (SImode, plus_constant (addr, 12)), CHAIN); \
emit_move_insn (gen_rtx_MEM (SImode, plus_constant (addr, 16)), FUNC); \
emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__xtensa_sync_caches"), \
0, VOIDmode, 1, addr, Pmode); \
} while (0)
@ -1128,7 +1142,7 @@ typedef struct xtensa_args {
\
/* allow constant pool addresses */ \
if ((MODE) != BLKmode && GET_MODE_SIZE (MODE) >= UNITS_PER_WORD \
&& constantpool_address_p (xinsn)) \
&& !TARGET_CONST16 && constantpool_address_p (xinsn)) \
goto LABEL; \
\
while (GET_CODE (xinsn) == SUBREG) \
@ -1330,7 +1344,6 @@ typedef struct xtensa_args {
{"call_insn_operand", { CONST_INT, CONST, SYMBOL_REF, REG }}, \
{"move_operand", { REG, SUBREG, MEM, CONST_INT, CONST_DOUBLE, \
CONST, SYMBOL_REF, LABEL_REF }}, \
{"non_const_move_operand", { REG, SUBREG, MEM }}, \
{"const_float_1_operand", { CONST_DOUBLE }}, \
{"branch_operator", { EQ, NE, LT, GE }}, \
{"ubranch_operator", { LTU, GEU }}, \

View File

@ -29,13 +29,16 @@
(define_constants [
(A0_REG 0)
(A1_REG 1)
(A7_REG 7)
(A8_REG 8)
(UNSPEC_NSAU 1)
(UNSPEC_NOP 2)
(UNSPEC_PLT 3)
(UNSPEC_RET_ADDR 4)
(UNSPECV_SET_FP 1)
(UNSPECV_ENTRY 2)
])
;;
@ -919,21 +922,19 @@
""
"
{
if (CONSTANT_P (operands[1]))
if (CONSTANT_P (operands[1])
&& register_operand (operands[0], DImode))
{
rtx src0, src1, dst0, dst1;
if ((dst0 = operand_subword (operands[0], 0, 1, DImode))
&& (src0 = operand_subword (operands[1], 0, 1, DImode))
&& (dst1 = operand_subword (operands[0], 1, 1, DImode))
&& (src1 = operand_subword (operands[1], 1, 1, DImode)))
{
emit_insn (gen_movsi (dst0, src0));
emit_insn (gen_movsi (dst1, src1));
DONE;
}
else
/* any other constant will be loaded from memory */
operands[1] = force_const_mem (DImode, operands[1]);
dst0 = operand_subword (operands[0], 0, 1, DImode);
src0 = operand_subword (operands[1], 0, 1, DImode);
dst1 = operand_subword (operands[0], 1, 1, DImode);
src1 = operand_subword (operands[1], 1, 1, DImode);
if (!dst0 || !src0 || !dst1 || !src1)
abort ();
emit_insn (gen_movsi (dst0, src0));
emit_insn (gen_movsi (dst1, src1));
DONE;
}
if (!(reload_in_progress | reload_completed))
@ -948,60 +949,56 @@
}")
(define_insn "movdi_internal"
[(set (match_operand:DI 0 "nonimmed_operand" "=D,D,S,a,a,a,U")
(match_operand:DI 1 "non_const_move_operand" "d,S,d,r,T,U,r"))]
[(set (match_operand:DI 0 "nonimmed_operand" "=D,D,S,a,a,U")
(match_operand:DI 1 "nonimmed_operand" "d,S,d,r,U,r"))]
"register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode)"
"*
{
rtx dstreg;
switch (which_alternative)
{
case 0: return \"mov.n\\t%0, %1\;mov.n\\t%D0, %D1\";
case 2: return \"%v0s32i.n\\t%1, %0\;s32i.n\\t%D1, %N0\";
case 3: return \"mov\\t%0, %1\;mov\\t%D0, %D1\";
case 6: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
case 5: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
case 1:
case 4:
case 5:
{
/* Check if the first half of the destination register is used
in the source address. If so, reverse the order of the loads
so that the source address doesn't get clobbered until it is
no longer needed. */
/* Check if the first half of the destination register is used
in the source address. If so, reverse the order of the loads
so that the source address doesn't get clobbered until it is
no longer needed. */
rtx dstreg = operands[0];
if (GET_CODE (dstreg) == SUBREG)
dstreg = SUBREG_REG (dstreg);
if (GET_CODE (dstreg) != REG)
abort();
dstreg = operands[0];
if (GET_CODE (dstreg) == SUBREG)
dstreg = SUBREG_REG (dstreg);
if (GET_CODE (dstreg) != REG)
abort();
if (reg_mentioned_p (dstreg, operands[1]))
{
switch (which_alternative)
{
case 1: return \"%v1l32i.n\\t%D0, %N1\;l32i.n\\t%0, %1\";
case 4: return \"%v1l32r\\t%D0, %N1\;l32r\\t%0, %1\";
case 5: return \"%v1l32i\\t%D0, %N1\;l32i\\t%0, %1\";
}
}
else
{
switch (which_alternative)
{
case 1: return \"%v1l32i.n\\t%0, %1\;l32i.n\\t%D0, %N1\";
case 4: return \"%v1l32r\\t%0, %1\;l32r\\t%D0, %N1\";
case 5: return \"%v1l32i\\t%0, %1\;l32i\\t%D0, %N1\";
}
}
}
if (reg_mentioned_p (dstreg, operands[1]))
{
switch (which_alternative)
{
case 1: return \"%v1l32i.n\\t%D0, %N1\;l32i.n\\t%0, %1\";
case 4: return \"%v1l32i\\t%D0, %N1\;l32i\\t%0, %1\";
}
}
else
{
switch (which_alternative)
{
case 1: return \"%v1l32i.n\\t%0, %1\;l32i.n\\t%D0, %N1\";
case 4: return \"%v1l32i\\t%0, %1\;l32i\\t%D0, %N1\";
}
}
}
abort ();
return \"\";
}"
[(set_attr "type" "move,load,store,move,load,load,store")
[(set_attr "type" "move,load,store,move,load,store")
(set_attr "mode" "DI")
(set_attr "length" "4,4,4,6,6,6,6")])
(set_attr "length" "4,4,4,6,6,6")])
;; 32-bit Integer moves
@ -1017,8 +1014,8 @@
}")
(define_insn "movsi_internal"
[(set (match_operand:SI 0 "nonimmed_operand" "=D,D,D,D,R,R,a,q,a,a,a,U,*a,*A")
(match_operand:SI 1 "move_operand" "M,D,d,R,D,d,r,r,I,T,U,r,*A,*r"))]
[(set (match_operand:SI 0 "nonimmed_operand" "=D,D,D,D,R,R,a,q,a,W,a,a,U,*a,*A")
(match_operand:SI 1 "move_operand" "M,D,d,R,D,d,r,r,I,i,T,U,r,*A,*r"))]
"xtensa_valid_move (SImode, operands)"
"@
movi.n\\t%0, %x1
@ -1030,14 +1027,15 @@
mov\\t%0, %1
movsp\\t%0, %1
movi\\t%0, %x1
const16\\t%0, %t1\;const16\\t%0, %b1
%v1l32r\\t%0, %1
%v1l32i\\t%0, %1
%v0s32i\\t%1, %0
rsr\\t%0, 16 # ACCLO
wsr\\t%1, 16 # ACCLO"
[(set_attr "type" "move,move,move,load,store,store,move,move,move,load,load,store,rsr,wsr")
[(set_attr "type" "move,move,move,load,store,store,move,move,move,move,load,load,store,rsr,wsr")
(set_attr "mode" "SI")
(set_attr "length" "2,2,2,2,2,2,3,3,3,3,3,3,3,3")])
(set_attr "length" "2,2,2,2,2,2,3,3,3,6,3,3,3,3,3")])
;; 16-bit Integer moves
@ -1105,15 +1103,16 @@
""
"
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
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)
if ((!register_operand (operands[0], SFmode)
&& !register_operand (operands[1], SFmode))
|| (FP_REG_P (xt_true_regnum (operands[0]))
&& constantpool_mem_p (operands[1]))))
&& (constantpool_mem_p (operands[1])
|| CONSTANT_P (operands[1]))))
operands[1] = force_reg (SFmode, operands[1]);
if (xtensa_copy_incoming_a7 (operands, SFmode))
@ -1122,14 +1121,12 @@
}")
(define_insn "movsf_internal"
[(set (match_operand:SF 0 "nonimmed_operand"
"=f,f,U,D,D,R,a,f,a,a,a,U")
(match_operand:SF 1 "non_const_move_operand"
"f,U,f,d,R,d,r,r,f,T,U,r"))]
[(set (match_operand:SF 0 "nonimmed_operand" "=f,f,U,D,D,R,a,f,a,W,a,a,U")
(match_operand:SF 1 "move_operand" "f,U,f,d,R,d,r,r,f,F,T,U,r"))]
"((register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))
&& (!FP_REG_P (xt_true_regnum (operands[0]))
|| !constantpool_mem_p (operands[1])))"
&& !(FP_REG_P (xt_true_regnum (operands[0]))
&& (constantpool_mem_p (operands[1]) || CONSTANT_P (operands[1]))))"
"@
mov.s\\t%0, %1
%v1lsi\\t%0, %1
@ -1140,12 +1137,13 @@
mov\\t%0, %1
wfr\\t%0, %1
rfr\\t%0, %1
const16\\t%0, %t1\;const16\\t%0, %b1
%v1l32r\\t%0, %1
%v1l32i\\t%0, %1
%v0s32i\\t%1, %0"
[(set_attr "type" "farith,fload,fstore,move,load,store,move,farith,farith,load,load,store")
[(set_attr "type" "farith,fload,fstore,move,load,store,move,farith,farith,move,load,load,store")
(set_attr "mode" "SF")
(set_attr "length" "3,3,3,2,2,2,3,3,3,3,3,3")])
(set_attr "length" "3,3,3,2,2,2,3,3,3,6,3,3,3")])
(define_insn "*lsiu"
[(set (match_operand:SF 0 "register_operand" "=f")
@ -1189,8 +1187,19 @@
""
"
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
operands[1] = force_const_mem (DFmode, operands[1]);
if (CONSTANT_P (operands[1]))
{
rtx src0, src1, dst0, dst1;
dst0 = operand_subword (operands[0], 0, 1, DFmode);
src0 = operand_subword (operands[1], 0, 1, DFmode);
dst1 = operand_subword (operands[0], 1, 1, DFmode);
src1 = operand_subword (operands[1], 1, 1, DFmode);
if (!dst0 || !src0 || !dst1 || !src1)
abort ();
emit_insn (gen_movsi (dst0, src0));
emit_insn (gen_movsi (dst1, src1));
DONE;
}
if (!(reload_in_progress | reload_completed))
{
@ -1204,60 +1213,56 @@
}")
(define_insn "movdf_internal"
[(set (match_operand:DF 0 "nonimmed_operand" "=D,D,S,a,a,a,U")
(match_operand:DF 1 "non_const_move_operand" "d,S,d,r,T,U,r"))]
[(set (match_operand:DF 0 "nonimmed_operand" "=D,D,S,a,a,U")
(match_operand:DF 1 "nonimmed_operand" "d,S,d,r,U,r"))]
"register_operand (operands[0], DFmode)
|| register_operand (operands[1], DFmode)"
"*
{
rtx dstreg;
switch (which_alternative)
{
case 0: return \"mov.n\\t%0, %1\;mov.n\\t%D0, %D1\";
case 2: return \"%v0s32i.n\\t%1, %0\;s32i.n\\t%D1, %N0\";
case 3: return \"mov\\t%0, %1\;mov\\t%D0, %D1\";
case 6: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
case 5: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
case 1:
case 4:
case 5:
{
/* Check if the first half of the destination register is used
in the source address. If so, reverse the order of the loads
so that the source address doesn't get clobbered until it is
no longer needed. */
/* Check if the first half of the destination register is used
in the source address. If so, reverse the order of the loads
so that the source address doesn't get clobbered until it is
no longer needed. */
rtx dstreg = operands[0];
if (GET_CODE (dstreg) == SUBREG)
dstreg = SUBREG_REG (dstreg);
if (GET_CODE (dstreg) != REG)
abort ();
dstreg = operands[0];
if (GET_CODE (dstreg) == SUBREG)
dstreg = SUBREG_REG (dstreg);
if (GET_CODE (dstreg) != REG)
abort ();
if (reg_mentioned_p (dstreg, operands[1]))
{
switch (which_alternative)
{
case 1: return \"%v1l32i.n\\t%D0, %N1\;l32i.n\\t%0, %1\";
case 4: return \"%v1l32r\\t%D0, %N1\;l32r\\t%0, %1\";
case 5: return \"%v1l32i\\t%D0, %N1\;l32i\\t%0, %1\";
}
}
else
{
switch (which_alternative)
{
case 1: return \"%v1l32i.n\\t%0, %1\;l32i.n\\t%D0, %N1\";
case 4: return \"%v1l32r\\t%0, %1\;l32r\\t%D0, %N1\";
case 5: return \"%v1l32i\\t%0, %1\;l32i\\t%D0, %N1\";
}
}
}
if (reg_mentioned_p (dstreg, operands[1]))
{
switch (which_alternative)
{
case 1: return \"%v1l32i.n\\t%D0, %N1\;l32i.n\\t%0, %1\";
case 4: return \"%v1l32i\\t%D0, %N1\;l32i\\t%0, %1\";
}
}
else
{
switch (which_alternative)
{
case 1: return \"%v1l32i.n\\t%0, %1\;l32i.n\\t%D0, %N1\";
case 4: return \"%v1l32i\\t%0, %1\;l32i\\t%D0, %N1\";
}
}
}
abort ();
return \"\";
}"
[(set_attr "type" "move,load,store,move,load,load,store")
[(set_attr "type" "move,load,store,move,load,store")
(set_attr "mode" "DF")
(set_attr "length" "4,4,4,6,6,6,6")])
(set_attr "length" "4,4,4,6,6,6")])
;; Block moves
@ -2340,6 +2345,24 @@
(set_attr "mode" "none")
(set_attr "length" "3")])
(define_insn "entry"
[(set (reg:SI A1_REG)
(unspec_volatile:SI [(match_operand:SI 0 "const_int_operand" "i")
(match_operand:SI 1 "const_int_operand" "i")]
UNSPECV_ENTRY))]
""
"*
{
if (frame_pointer_needed)
output_asm_insn (\".frame\\ta7, %0\", operands);
else
output_asm_insn (\".frame\\tsp, %0\", operands);
return \"entry\\tsp, %1\";
}"
[(set_attr "type" "move")
(set_attr "mode" "SI")
(set_attr "length" "3")])
(define_insn "return"
[(return)
(use (reg:SI A0_REG))]
@ -2361,6 +2384,24 @@
;; ....................
;;
(define_expand "prologue"
[(const_int 0)]
""
"
{
xtensa_expand_prologue ();
DONE;
}")
(define_expand "epilogue"
[(return)]
""
"
{
emit_jump_insn (gen_return ());
DONE;
}")
(define_insn "nop"
[(const_int 0)]
""
@ -2400,7 +2441,7 @@
;; to set up the frame pointer.
(define_insn "set_frame_ptr"
[(set (reg:SI A7_REG) (unspec_volatile [(const_int 0)] UNSPECV_SET_FP))]
[(set (reg:SI A7_REG) (unspec_volatile:SI [(const_int 0)] UNSPECV_SET_FP))]
""
"*
{
@ -2414,7 +2455,7 @@
;; Post-reload splitter to remove fp assignment when it's not needed.
(define_split
[(set (reg:SI A7_REG) (unspec_volatile [(const_int 0)] UNSPECV_SET_FP))]
[(set (reg:SI A7_REG) (unspec_volatile:SI [(const_int 0)] UNSPECV_SET_FP))]
"reload_completed && !frame_pointer_needed"
[(unspec [(const_int 0)] UNSPEC_NOP)]
"")

View File

@ -632,6 +632,7 @@ in the following sections.
@emph{Xtensa Options}
@gccoptlist{-mbig-endian -mlittle-endian @gol
-mdensity -mno-density @gol
-mconst16 -mno-const16 @gol
-mmac16 -mno-mac16 @gol
-mmul16 -mno-mul16 @gol
-mmul32 -mno-mul32 @gol
@ -10649,6 +10650,16 @@ processor.
@opindex mno-density
Enable or disable use of the optional Xtensa code density instructions.
@item -mconst16
@itemx -mno-const16
@opindex mconst16
@opindex mno-const16
Enable or disable use of CONST16 instructions for loading constant values.
The CONST16 instruction is currently not a standard option from Tensilica.
When enabled, CONST16 instructions are always used in place of the standard
L32R instructions. The use of CONST16 is enabled by default only if the
L32R instruction is not available.
@item -mmac16
@itemx -mno-mac16
@opindex mmac16