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:
parent
ae49d6e592
commit
f42f5a1b1e
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 }}, \
|
||||
|
|
|
@ -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)]
|
||||
"")
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue