This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Xtensa] new option for loading constants
- From: Bob Wilson <bwilson at tensilica dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 14 May 2003 12:03:24 -0700
- Subject: [Xtensa] new option for loading constants
- Organization: Tensilica, Inc.
This patch adds support for an alternative method of loading 32-bit constants
on Xtensa processors. The standard Xtensa ISA defines a PC-relative L32R
load instruction to load values from constant pools. The new method uses a
CONST16 instruction that shifts the contents of a register left by 16 bits
and then sets the low bits to a 16-bit immediate value, so that 2 CONST16
instructions can load a 32-bit value. The CONST16 instruction is currently
not a standard option from Tensilica but can be implemented as a user-defined
instruction.
As part of this change, I finally got around to generating the function
prologues and epilogues as RTL. I was also able to move the
TARGET_MACHINE_DEPENDENT_REORG gunk into the code to expand the prologue.
The new CONST16-related code is disabled by default. I ran the testsuite with
the xtensa-elf target with CONST16 disabled; there were no new regressions.
Committed on the mainline.
2003-05-13 Bob Wilson <bob.wilson@acm.org>
* 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.
Index: gcc/config/xtensa/lib2funcs.S
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/lib2funcs.S,v
retrieving revision 1.4
diff -c -3 -r1.4 lib2funcs.S
*** gcc/config/xtensa/lib2funcs.S 10 Apr 2003 16:57:58 -0000 1.4
--- gcc/config/xtensa/lib2funcs.S 14 May 2003 18:14:16 -0000
***************
*** 151,157 ****
make sure that the modified instructions are loaded into the instruction
fetch buffer. */
! #define TRAMPOLINE_SIZE 49
.text
.align 4
--- 151,157 ----
make sure that the modified instructions are loaded into the instruction
fetch buffer. */
! #define TRAMPOLINE_SIZE 59
.text
.align 4
Index: gcc/config/xtensa/xtensa-config.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa-config.h,v
retrieving revision 1.2
diff -c -3 -r1.2 xtensa-config.h
*** gcc/config/xtensa/xtensa-config.h 12 Mar 2002 20:02:36 -0000 1.2
--- gcc/config/xtensa/xtensa-config.h 14 May 2003 18:14:16 -0000
***************
*** 1,5 ****
/* Xtensa configuration settings.
! Copyright (C) 2001,2002 Free Software Foundation, Inc.
Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
** NOTE: This file was automatically generated by the Xtensa Processor
--- 1,5 ----
/* Xtensa configuration settings.
! 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,32 ****
--- 27,34 ----
#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
Index: gcc/config/xtensa/xtensa-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa-protos.h,v
retrieving revision 1.9
diff -c -3 -r1.9 xtensa-protos.h
*** gcc/config/xtensa/xtensa-protos.h 14 May 2003 07:29:54 -0000 1.9
--- gcc/config/xtensa/xtensa-protos.h 14 May 2003 18:14:16 -0000
***************
*** 57,67 ****
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));
--- 57,65 ----
***************
*** 110,117 ****
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 order_regs_for_local_alloc PARAMS ((void));
#endif /* !__XTENSA_PROTOS_H__ */
--- 108,114 ----
extern void override_options PARAMS ((void));
extern long compute_frame_size PARAMS ((int));
extern int xtensa_frame_pointer_required PARAMS ((void));
! extern void xtensa_expand_prologue PARAMS ((void));
extern void order_regs_for_local_alloc PARAMS ((void));
#endif /* !__XTENSA_PROTOS_H__ */
Index: gcc/config/xtensa/xtensa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.c,v
retrieving revision 1.32
diff -c -3 -r1.32 xtensa.c
*** gcc/config/xtensa/xtensa.c 14 May 2003 07:29:54 -0000 1.32
--- gcc/config/xtensa/xtensa.c 14 May 2003 18:14:16 -0000
***************
*** 198,226 ****
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 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
--- 198,215 ----
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 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 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 exit,
on machines that need it. If FUNCTION_EPILOGUE is not defined
***************
*** 244,252 ****
#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;
--- 233,238 ----
***************
*** 412,419 ****
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT)
! return (xtensa_simm8 (INTVAL (op)) ||
! xtensa_simm8x256 (INTVAL (op)));
return register_operand (op, mode);
}
--- 398,404 ----
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT)
! return (xtensa_simm8 (INTVAL (op)) || xtensa_simm8x256 (INTVAL (op)));
return register_operand (op, mode);
}
***************
*** 610,628 ****
rtx op;
enum machine_mode mode;
{
! if (register_operand (op, mode))
return TRUE;
/* 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) == MEM)
! return memory_address_p (mode, XEXP (op, 0));
return FALSE;
}
--- 595,617 ----
rtx op;
enum machine_mode 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 && xtensa_simm12b (INTVAL (op)))
! return TRUE;
! if (mode == SImode)
! return TARGET_CONST16 && CONSTANT_P (op);
return FALSE;
}
***************
*** 702,722 ****
}
- 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
--- 691,696 ----
***************
*** 778,809 ****
}
- 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;
--- 752,757 ----
***************
*** 899,906 ****
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));
case QImode:
return xtensa_uimm8 (v);
--- 847,854 ----
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));
case QImode:
return xtensa_uimm8 (v);
***************
*** 1260,1266 ****
/* 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. */
--- 1208,1213 ----
***************
*** 1275,1282 ****
&& (GET_CODE (operands[1]) != CONST_INT
|| !xtensa_simm12b (INTVAL (operands[1]))))
{
! xtensa_load_constant (operands[0], operands[1]);
! return 1;
}
if (!(reload_in_progress | reload_completed))
--- 1222,1248 ----
&& (GET_CODE (operands[1]) != CONST_INT
|| !xtensa_simm12b (INTVAL (operands[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,1304 ****
--- 1265,1271 ----
return 0;
}
+
static rtx
fixup_subreg_mem (x)
rtx x;
***************
*** 1848,1853 ****
--- 1815,1821 ----
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,1869 ****
int temp;
if (ACC_REG_P (regno))
! 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))
--- 1830,1837 ----
int temp;
if (ACC_REG_P (regno))
! 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,1887 ****
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))
flag_pic = 1;
}
--- 1847,1865 ----
init_machine_status = xtensa_init_machine_status;
! /* 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,1923 ****
--- 1896,1903 ----
'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,2029 ****
void
! print_operand (file, op, letter)
FILE *file; /* file to write to */
! rtx op; /* operand to print */
int letter; /* %<letter> or 0 */
{
! enum rtx_code code;
!
! if (! op)
error ("PRINT_OPERAND null pointer");
! code = GET_CODE (op);
! switch (code)
{
! case REG:
! case SUBREG:
! {
! int regnum = xt_true_regnum (op);
! if (letter == 'D')
! regnum++;
! fprintf (file, "%s", reg_names[regnum]);
! 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 '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);
! fprintf (file, "%d", num_bits);
! break;
! }
! case 'L':
! fprintf (file, "%ld", (32 - INTVAL (op)) & 0x1f);
! break;
! case 'R':
! fprintf (file, "%ld", INTVAL (op) & 0x1f);
! break;
! case 'x':
! printx (file, INTVAL (op));
! break;
! case 'd':
! default:
! fprintf (file, "%ld", INTVAL (op));
! break;
}
break;
default:
! output_addr_const (file, op);
}
}
--- 1916,2061 ----
void
! print_operand (file, x, letter)
FILE *file; /* file to write to */
! rtx x; /* operand to print */
int letter; /* %<letter> or 0 */
{
! if (!x)
error ("PRINT_OPERAND null pointer");
! switch (letter)
{
! 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 'v':
! if (GET_CODE (x) == MEM)
! {
! /* 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;
! 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 '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);
! fprintf (file, "%d", num_bits);
! }
! else
! output_operand_lossage ("invalid %%K value");
! 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 '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:
! 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,2319 ****
}
! /* 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;
! {
! unsigned long tsize = compute_frame_size (get_frame_size ());
!
! 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");
!
! /* 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");
}
}
! /* Do any necessary cleanup after a function to restore
! stack, frame, and regs. */
void
xtensa_function_epilogue (file, size)
! FILE *file;
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;
}
--- 2223,2307 ----
}
! void
! xtensa_expand_prologue ()
! {
! 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)
{
! rtx first, insn, set_frame_ptr_insn = 0;
! push_topmost_sequence ();
! first = get_insns ();
! pop_topmost_sequence ();
! /* Search all instructions, looking for the insn that sets up the
! frame pointer. This search will fail if the function does not
! have an incoming argument in $a7, but in that case, we can just
! set up the frame pointer at the very beginning of the
! function. */
!
! for (insn = first; insn; insn = NEXT_INSN (insn))
! {
! 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);
}
}
! /* Clear variables at function end. */
void
xtensa_function_epilogue (file, size)
! FILE *file ATTRIBUTE_UNUSED;
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{
xtensa_current_frame_size = 0;
}
***************
*** 2326,2332 ****
rtx result, retaddr;
if (count == -1)
! retaddr = gen_rtx_REG (Pmode, 0);
else
{
rtx addr = plus_constant (frame, -4 * UNITS_PER_WORD);
--- 2314,2320 ----
rtx result, retaddr;
if (count == -1)
! retaddr = gen_rtx_REG (Pmode, A0_REG);
else
{
rtx addr = plus_constant (frame, -4 * UNITS_PER_WORD);
***************
*** 2882,2887 ****
--- 2870,2877 ----
}
if (xtensa_simm12b (INTVAL (x)))
*total = 5;
+ else if (TARGET_CONST16)
+ *total = COSTS_N_INSNS (2);
else
*total = 6;
return true;
***************
*** 2889,2899 ****
case CONST:
case LABEL_REF:
case SYMBOL_REF:
! *total = 5;
return true;
case CONST_DOUBLE:
! *total = 7;
return true;
case MEM:
--- 2879,2895 ----
case CONST:
case LABEL_REF:
case SYMBOL_REF:
! if (TARGET_CONST16)
! *total = COSTS_N_INSNS (2);
! else
! *total = 5;
return true;
case CONST_DOUBLE:
! if (TARGET_CONST16)
! *total = COSTS_N_INSNS (4);
! else
! *total = 7;
return true;
case MEM:
Index: gcc/config/xtensa/xtensa.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.h,v
retrieving revision 1.31
diff -c -3 -r1.31 xtensa.h
*** gcc/config/xtensa/xtensa.h 14 May 2003 07:29:54 -0000 1.31
--- gcc/config/xtensa/xtensa.h 14 May 2003 18:14:16 -0000
***************
*** 61,66 ****
--- 61,67 ----
#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,92 ****
--- 82,95 ----
#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,119 ****
--- 117,126 ----
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,634 ****
--- 636,642 ----
'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,705 ****
&& 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) == 'U') ? !constantpool_mem_p (OP) \
: FALSE)
--- 707,713 ----
&& REGNO (OP) >= FIRST_PSEUDO_REGISTER) \
: ((CODE) == 'R') ? smalloffset_mem_p (OP) \
: ((CODE) == 'S') ? smalloffset_double_mem_p (OP) \
! : ((CODE) == 'T') ? !TARGET_CONST16 && constantpool_mem_p (OP) \
: ((CODE) == 'U') ? !constantpool_mem_p (OP) \
: FALSE)
***************
*** 968,991 ****
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. */ \
\
! fprintf (STREAM, "\tj\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, ".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)); \
\
/* set the proper stack pointer value */ \
! fprintf (STREAM, "\tl32r\ta8, .Lfnaddr\n"); \
fprintf (STREAM, "\tl32i\ta9, a8, 0\n"); \
fprintf (STREAM, "\textui\ta9, a9, %d, 12\n", \
TARGET_BIG_ENDIAN ? 8 : 12); \
--- 976,1002 ----
fprintf (STREAM, "\t.begin no-generics\n"); \
fprintf (STREAM, "\tentry\tsp, %d\n", MIN_FRAME_SIZE); \
\
! /* save the return address */ \
! fprintf (STREAM, "\tmov\ta10, a0\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, ".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, "\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, "\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,999 ****
--- 1005,1013 ----
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,1007 ****
} while (0)
/* Size in bytes of the trampoline, as an integer. */
! #define TRAMPOLINE_SIZE 49
/* Alignment required for trampolines, in bits. */
#define TRAMPOLINE_ALIGNMENT (32)
--- 1015,1021 ----
} while (0)
/* Size in bytes of the trampoline, as an integer. */
! #define TRAMPOLINE_SIZE 59
/* Alignment required for trampolines, in bits. */
#define TRAMPOLINE_ALIGNMENT (32)
***************
*** 1010,1017 ****
#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_library_call (gen_rtx (SYMBOL_REF, Pmode, "__xtensa_sync_caches"), \
0, VOIDmode, 1, addr, Pmode); \
} while (0)
--- 1024,1031 ----
#define INITIALIZE_TRAMPOLINE(ADDR, FUNC, CHAIN) \
do { \
rtx addr = ADDR; \
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,1134 ****
\
/* allow constant pool addresses */ \
if ((MODE) != BLKmode && GET_MODE_SIZE (MODE) >= UNITS_PER_WORD \
! && constantpool_address_p (xinsn)) \
goto LABEL; \
\
while (GET_CODE (xinsn) == SUBREG) \
--- 1142,1148 ----
\
/* allow constant pool addresses */ \
if ((MODE) != BLKmode && GET_MODE_SIZE (MODE) >= UNITS_PER_WORD \
! && !TARGET_CONST16 && constantpool_address_p (xinsn)) \
goto LABEL; \
\
while (GET_CODE (xinsn) == SUBREG) \
***************
*** 1330,1336 ****
{"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 }}, \
--- 1344,1349 ----
Index: gcc/config/xtensa/xtensa.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.md,v
retrieving revision 1.10
diff -c -3 -r1.10 xtensa.md
*** gcc/config/xtensa/xtensa.md 17 Apr 2003 11:24:04 -0000 1.10
--- gcc/config/xtensa/xtensa.md 14 May 2003 18:14:16 -0000
***************
*** 29,41 ****
--- 29,44 ----
(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,939 ****
""
"
{
! if (CONSTANT_P (operands[1]))
{
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]);
}
if (!(reload_in_progress | reload_completed))
--- 922,940 ----
""
"
{
! if (CONSTANT_P (operands[1])
! && register_operand (operands[0], DImode))
{
rtx src0, src1, dst0, dst1;
! 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,1007 ****
}")
(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"))]
"register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode)"
"*
{
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 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. */
!
! rtx 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\";
! }
! }
! }
}
abort ();
return \"\";
}"
! [(set_attr "type" "move,load,store,move,load,load,store")
(set_attr "mode" "DI")
! (set_attr "length" "4,4,4,6,6,6,6")])
;; 32-bit Integer moves
--- 949,1004 ----
}")
(define_insn "movdi_internal"
! [(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 5: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
case 1:
case 4:
! /* 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. */
!
! 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 \"%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,store")
(set_attr "mode" "DI")
! (set_attr "length" "4,4,4,6,6,6")])
;; 32-bit Integer moves
***************
*** 1017,1024 ****
}")
(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"))]
"xtensa_valid_move (SImode, operands)"
"@
movi.n\\t%0, %x1
--- 1014,1021 ----
}")
(define_insn "movsi_internal"
! [(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,1043 ****
mov\\t%0, %1
movsp\\t%0, %1
movi\\t%0, %x1
%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 "mode" "SI")
! (set_attr "length" "2,2,2,2,2,2,3,3,3,3,3,3,3,3")])
;; 16-bit Integer moves
--- 1027,1041 ----
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,move,load,load,store,rsr,wsr")
(set_attr "mode" "SI")
! (set_attr "length" "2,2,2,2,2,2,3,3,3,6,3,3,3,3,3")])
;; 16-bit Integer moves
***************
*** 1105,1119 ****
""
"
{
! if (GET_CODE (operands[1]) == CONST_DOUBLE)
operands[1] = force_const_mem (SFmode, operands[1]);
if (!(reload_in_progress | reload_completed))
{
! if (((!register_operand (operands[0], SFmode)
&& !register_operand (operands[1], SFmode))
|| (FP_REG_P (xt_true_regnum (operands[0]))
! && constantpool_mem_p (operands[1]))))
operands[1] = force_reg (SFmode, operands[1]);
if (xtensa_copy_incoming_a7 (operands, SFmode))
--- 1103,1118 ----
""
"
{
! if (!TARGET_CONST16 && CONSTANT_P (operands[1]))
operands[1] = force_const_mem (SFmode, operands[1]);
if (!(reload_in_progress | reload_completed))
{
! if ((!register_operand (operands[0], SFmode)
&& !register_operand (operands[1], SFmode))
|| (FP_REG_P (xt_true_regnum (operands[0]))
! && (constantpool_mem_p (operands[1])
! || CONSTANT_P (operands[1]))))
operands[1] = force_reg (SFmode, operands[1]);
if (xtensa_copy_incoming_a7 (operands, SFmode))
***************
*** 1122,1135 ****
}")
(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"))]
"((register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))
! && (!FP_REG_P (xt_true_regnum (operands[0]))
! || !constantpool_mem_p (operands[1])))"
"@
mov.s\\t%0, %1
%v1lsi\\t%0, %1
--- 1121,1132 ----
}")
(define_insn "movsf_internal"
! [(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]) || CONSTANT_P (operands[1]))))"
"@
mov.s\\t%0, %1
%v1lsi\\t%0, %1
***************
*** 1140,1151 ****
mov\\t%0, %1
wfr\\t%0, %1
rfr\\t%0, %1
%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 "mode" "SF")
! (set_attr "length" "3,3,3,2,2,2,3,3,3,3,3,3")])
(define_insn "*lsiu"
[(set (match_operand:SF 0 "register_operand" "=f")
--- 1137,1149 ----
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,move,load,load,store")
(set_attr "mode" "SF")
! (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,1196 ****
""
"
{
! if (GET_CODE (operands[1]) == CONST_DOUBLE)
! operands[1] = force_const_mem (DFmode, operands[1]);
if (!(reload_in_progress | reload_completed))
{
--- 1187,1205 ----
""
"
{
! 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,1263 ****
}")
(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"))]
"register_operand (operands[0], DFmode)
|| register_operand (operands[1], DFmode)"
"*
{
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 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. */
!
! rtx 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\";
! }
! }
! }
}
abort ();
return \"\";
}"
! [(set_attr "type" "move,load,store,move,load,load,store")
(set_attr "mode" "DF")
! (set_attr "length" "4,4,4,6,6,6,6")])
;; Block moves
--- 1213,1268 ----
}")
(define_insn "movdf_internal"
! [(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 5: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
case 1:
case 4:
! /* 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. */
!
! 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 \"%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,store")
(set_attr "mode" "DF")
! (set_attr "length" "4,4,4,6,6,6")])
;; Block moves
***************
*** 2340,2345 ****
--- 2345,2368 ----
(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,2366 ****
--- 2384,2407 ----
;; ....................
;;
+ (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,2406 ****
;; to set up the frame pointer.
(define_insn "set_frame_ptr"
! [(set (reg:SI A7_REG) (unspec_volatile [(const_int 0)] UNSPECV_SET_FP))]
""
"*
{
--- 2441,2447 ----
;; to set up the frame pointer.
(define_insn "set_frame_ptr"
! [(set (reg:SI A7_REG) (unspec_volatile:SI [(const_int 0)] UNSPECV_SET_FP))]
""
"*
{
***************
*** 2414,2420 ****
;; 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))]
"reload_completed && !frame_pointer_needed"
[(unspec [(const_int 0)] UNSPEC_NOP)]
"")
--- 2455,2461 ----
;; Post-reload splitter to remove fp assignment when it's not needed.
(define_split
! [(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)]
"")
Index: gcc/doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.275
diff -c -3 -r1.275 invoke.texi
*** gcc/doc/invoke.texi 14 May 2003 02:22:12 -0000 1.275
--- gcc/doc/invoke.texi 14 May 2003 18:14:17 -0000
***************
*** 632,637 ****
--- 632,638 ----
@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
***************
*** 10648,10653 ****
--- 10649,10664 ----
@opindex mdensity
@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