/* Definitions of Tensilica's Xtensa target machine for GNU compiler.
- Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* Get Xtensa configuration settings */
#include "xtensa-config.h"
/* Standard GCC variables that we reference. */
-extern int current_function_calls_alloca;
extern int optimize;
/* External variables defined in xtensa.c. */
/* Macros used in the machine description to select various Xtensa
configuration options. */
+#ifndef XCHAL_HAVE_MUL32_HIGH
+#define XCHAL_HAVE_MUL32_HIGH 0
+#endif
+#ifndef XCHAL_HAVE_RELEASE_SYNC
+#define XCHAL_HAVE_RELEASE_SYNC 0
+#endif
+#ifndef XCHAL_HAVE_S32C1I
+#define XCHAL_HAVE_S32C1I 0
+#endif
#define TARGET_BIG_ENDIAN XCHAL_HAVE_BE
#define TARGET_DENSITY XCHAL_HAVE_DENSITY
#define TARGET_MAC16 XCHAL_HAVE_MAC16
#define TARGET_HARD_FLOAT_RSQRT XCHAL_HAVE_FP_RSQRT
#define TARGET_ABS XCHAL_HAVE_ABS
#define TARGET_ADDX XCHAL_HAVE_ADDX
+#define TARGET_RELEASE_SYNC XCHAL_HAVE_RELEASE_SYNC
+#define TARGET_S32C1I XCHAL_HAVE_S32C1I
+#define TARGET_ABSOLUTE_LITERALS XSHAL_USE_ABSOLUTE_LITERALS
-#define TARGET_DEFAULT ( \
- (XCHAL_HAVE_L32R ? 0 : MASK_CONST16))
+#define TARGET_DEFAULT \
+ ((XCHAL_HAVE_L32R ? 0 : MASK_CONST16) | \
+ MASK_SERIALIZE_VOLATILE)
#define OVERRIDE_OPTIONS override_options ()
{ 0xffffffff, 0x0000000f } /* all registers */ \
}
+#define IRA_COVER_CLASSES \
+{ \
+ BR_REGS, FP_REGS, ACC_REG, AR_REGS, LIM_REG_CLASSES \
+}
+
/* A C expression whose value is a register class containing hard
register REGNO. In general there is more that one such class;
choose a class which is "minimal", meaning that no smaller class
/* Offset within stack frame to start allocating local variables at. */
#define STARTING_FRAME_OFFSET \
- current_function_outgoing_args_size
+ crtl->outgoing_args_size
/* The ARG_POINTER and FRAME_POINTER are not real Xtensa registers, so
they are eliminated to either the stack pointer or hard frame pointer. */
/* If defined, the maximum amount of space required for outgoing
arguments will be computed and placed into the variable
- 'current_function_outgoing_args_size'. No space will be pushed
+ 'crtl->outgoing_args_size'. No space will be pushed
onto the stack for each call; instead, the function prologue
should increase the stack frame size by this amount. */
#define ACCUMULATE_OUTGOING_ARGS 1
#define LIBCALL_OUTGOING_VALUE(MODE) \
XTENSA_LIBCALL_VALUE ((MODE), 1)
-/* Define how to find the value returned by a function.
- VALTYPE is the data type of the value (as a tree).
- If the precise function being called is known, FUNC is its FUNCTION_DECL;
- otherwise, FUNC is 0. */
-#define XTENSA_FUNCTION_VALUE(VALTYPE, FUNC, OUTGOINGP) \
- gen_rtx_REG ((INTEGRAL_TYPE_P (VALTYPE) \
- && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
- ? SImode: TYPE_MODE (VALTYPE), \
- OUTGOINGP ? GP_OUTGOING_RETURN : GP_RETURN)
-
-#define FUNCTION_VALUE(VALTYPE, FUNC) \
- XTENSA_FUNCTION_VALUE (VALTYPE, FUNC, 0)
-
-#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \
- XTENSA_FUNCTION_VALUE (VALTYPE, FUNC, 1)
-
/* A C expression that is nonzero if REGNO is the number of a hard
register in which the values of called function may come back. A
register whose use for returning values is limited to serving as
/* Stack pointer value doesn't matter at exit. */
#define EXIT_IGNORE_STACK 1
-/* A C statement to output, on the stream FILE, assembler code for a
- block of data that contains the constant parts of a trampoline.
- This code should not include a label--the label is taken care of
- automatically.
-
- For Xtensa, the trampoline must perform an entry instruction with a
- minimal stack frame in order to get some free registers. Once the
- actual call target is known, the proper stack frame size is extracted
- from the entry instruction at the target and the current frame is
- adjusted to match. The trampoline then transfers control to the
- instruction following the entry at the target. Note: this assumes
- that the target begins with an entry instruction. */
-
-/* minimum frame = reg save area (4 words) plus static chain (1 word)
- and the total number of words must be a multiple of 128 bits */
-#define MIN_FRAME_SIZE (8 * UNITS_PER_WORD)
-
-#define TRAMPOLINE_TEMPLATE(STREAM) \
- do { \
- fprintf (STREAM, "\t.begin no-transform\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); \
- fprintf (STREAM, "\tslli\ta9, a9, 3\n"); \
- fprintf (STREAM, "\taddi\ta9, a9, %d\n", -MIN_FRAME_SIZE); \
- 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"); \
- fprintf (STREAM, "\t.byte\t0\n"); \
- fprintf (STREAM, "\t.end no-transform\n"); \
- } while (0)
+#define TRAMPOLINE_TEMPLATE(STREAM) xtensa_trampoline_template (STREAM)
/* Size in bytes of the trampoline, as an integer. Make sure this is
a multiple of TRAMPOLINE_ALIGNMENT to avoid -Wpadded warnings. */
-#define TRAMPOLINE_SIZE 60
+#define TRAMPOLINE_SIZE (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS ? 60 : 52)
/* Alignment required for trampolines, in bits. */
-#define TRAMPOLINE_ALIGNMENT (32)
+#define TRAMPOLINE_ALIGNMENT 32
/* A C statement to initialize the variable parts of a trampoline. */
#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)
+ xtensa_initialize_trampoline (ADDR, FUNC, CHAIN)
-/* Implement `va_start' for varargs and stdarg. */
-#define EXPAND_BUILTIN_VA_START(valist, nextarg) \
- xtensa_va_start (valist, nextarg)
/* If defined, a C expression that produces the machine-specific code
to setup the stack so that arbitrary frames can be accessed.
/* Addressing modes, and classification of registers for them. */
/* C expressions which are nonzero if register number NUM is suitable
- for use as a base or index register in operand addresses. It may
- be either a suitable hard register or a pseudo register that has
- been allocated such a hard register. The difference between an
- index register and a base register is that the index register may
- be scaled. */
+ for use as a base or index register in operand addresses. */
+#define REGNO_OK_FOR_INDEX_P(NUM) 0
#define REGNO_OK_FOR_BASE_P(NUM) \
(GP_REG_P (NUM) || GP_REG_P ((unsigned) reg_renumber[NUM]))
-#define REGNO_OK_FOR_INDEX_P(NUM) 0
-
/* C expressions that are nonzero if X (assumed to be a `reg' RTX) is
- valid for use as a base or index register. For hard registers, it
- should always accept those which the hardware permits and reject
- the others. Whether the macro accepts or rejects pseudo registers
- must be controlled by `REG_OK_STRICT'. This usually requires two
- variant definitions, of which `REG_OK_STRICT' controls the one
- actually used. The difference between an index register and a base
- register is that the index register may be scaled. */
+ valid for use as a base or index register. */
#ifdef REG_OK_STRICT
+#define REG_OK_STRICT_FLAG 1
+#else
+#define REG_OK_STRICT_FLAG 0
+#endif
-#define REG_OK_FOR_INDEX_P(X) 0
-#define REG_OK_FOR_BASE_P(X) \
- REGNO_OK_FOR_BASE_P (REGNO (X))
-
-#else /* !REG_OK_STRICT */
+#define BASE_REG_P(X, STRICT) \
+ ((!(STRICT) && REGNO (X) >= FIRST_PSEUDO_REGISTER) \
+ || REGNO_OK_FOR_BASE_P (REGNO (X)))
#define REG_OK_FOR_INDEX_P(X) 0
-#define REG_OK_FOR_BASE_P(X) \
- ((REGNO (X) >= FIRST_PSEUDO_REGISTER) || (GP_REG_P (REGNO (X))))
-
-#endif /* !REG_OK_STRICT */
+#define REG_OK_FOR_BASE_P(X) BASE_REG_P (X, REG_OK_STRICT_FLAG)
/* Maximum number of registers that can appear in a valid memory address. */
#define MAX_REGS_PER_ADDRESS 1
/* Identify valid Xtensa addresses. */
#define GO_IF_LEGITIMATE_ADDRESS(MODE, ADDR, LABEL) \
do { \
- rtx xinsn = (ADDR); \
- \
- /* allow constant pool addresses */ \
- if ((MODE) != BLKmode && GET_MODE_SIZE (MODE) >= UNITS_PER_WORD \
- && !TARGET_CONST16 && constantpool_address_p (xinsn)) \
+ if (xtensa_legitimate_address_p (MODE, ADDR, REG_OK_STRICT_FLAG)) \
goto LABEL; \
- \
- while (GET_CODE (xinsn) == SUBREG) \
- xinsn = SUBREG_REG (xinsn); \
- \
- /* allow base registers */ \
- if (GET_CODE (xinsn) == REG && REG_OK_FOR_BASE_P (xinsn)) \
- goto LABEL; \
- \
- /* check for "register + offset" addressing */ \
- if (GET_CODE (xinsn) == PLUS) \
- { \
- rtx xplus0 = XEXP (xinsn, 0); \
- rtx xplus1 = XEXP (xinsn, 1); \
- enum rtx_code code0; \
- enum rtx_code code1; \
- \
- while (GET_CODE (xplus0) == SUBREG) \
- xplus0 = SUBREG_REG (xplus0); \
- code0 = GET_CODE (xplus0); \
- \
- while (GET_CODE (xplus1) == SUBREG) \
- xplus1 = SUBREG_REG (xplus1); \
- code1 = GET_CODE (xplus1); \
- \
- /* swap operands if necessary so the register is first */ \
- if (code0 != REG && code1 == REG) \
- { \
- xplus0 = XEXP (xinsn, 1); \
- xplus1 = XEXP (xinsn, 0); \
- code0 = GET_CODE (xplus0); \
- code1 = GET_CODE (xplus1); \
- } \
- \
- if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) \
- && code1 == CONST_INT \
- && xtensa_mem_offset (INTVAL (xplus1), (MODE))) \
- { \
- goto LABEL; \
- } \
- } \
} while (0)
/* A C expression that is 1 if the RTX X is a constant which is a
&& GET_CODE (X) != LABEL_REF \
&& GET_CODE (X) != CONST)
-/* Tell GCC how to use ADDMI to generate addresses. */
#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
do { \
- rtx xinsn = (X); \
- if (GET_CODE (xinsn) == PLUS) \
- { \
- rtx plus0 = XEXP (xinsn, 0); \
- rtx plus1 = XEXP (xinsn, 1); \
- \
- if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG) \
- { \
- plus0 = XEXP (xinsn, 1); \
- plus1 = XEXP (xinsn, 0); \
- } \
- \
- if (GET_CODE (plus0) == REG \
- && GET_CODE (plus1) == CONST_INT \
- && !xtensa_mem_offset (INTVAL (plus1), MODE) \
- && !xtensa_simm8 (INTVAL (plus1)) \
- && xtensa_mem_offset (INTVAL (plus1) & 0xff, MODE) \
- && xtensa_simm8x256 (INTVAL (plus1) & ~0xff)) \
- { \
- rtx temp = gen_reg_rtx (Pmode); \
- emit_insn (gen_rtx_SET (Pmode, temp, \
- gen_rtx_PLUS (Pmode, plus0, \
- GEN_INT (INTVAL (plus1) & ~0xff)))); \
- (X) = gen_rtx_PLUS (Pmode, temp, \
- GEN_INT (INTVAL (plus1) & 0xff)); \
- goto WIN; \
- } \
+ rtx new_x = xtensa_legitimize_address (X, OLDX, MODE); \
+ if (new_x) \
+ { \
+ X = new_x; \
+ goto WIN; \
} \
} while (0)
constants. Used for PIC-specific UNSPECs. */
#define OUTPUT_ADDR_CONST_EXTRA(STREAM, X, FAIL) \
do { \
- if (flag_pic && GET_CODE (X) == UNSPEC && XVECLEN ((X), 0) == 1) \
- { \
- switch (XINT ((X), 1)) \
- { \
- case UNSPEC_PLT: \
- output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \
- fputs ("@PLT", (STREAM)); \
- break; \
- default: \
- goto FAIL; \
- } \
- break; \
- } \
- else \
+ if (xtensa_output_addr_const_extra (STREAM, X) == FALSE) \
goto FAIL; \
} while (0)
/* How to start an assembler comment. */
#define ASM_COMMENT_START "#"
-/* Exception handling TODO!! */
-#define DWARF_UNWIND_INFO 0
+/* Exception handling. Xtensa uses much of the standard DWARF2 unwinding
+ machinery, but the variable size register window save areas are too
+ complicated to efficiently describe with CFI entries. The CFA must
+ still be specified in DWARF so that DW_AT_frame_base is set correctly
+ for debugging. */
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, 0)
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (0)
+#define DWARF_FRAME_REGISTERS 16
+#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) + 2 : INVALID_REGNUM)
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \
+ (flag_pic \
+ ? (((GLOBAL) ? DW_EH_PE_indirect : 0) \
+ | DW_EH_PE_pcrel | DW_EH_PE_sdata4) \
+ : DW_EH_PE_absptr)
+
+/* Emit a PC-relative relocation. */
+#define ASM_OUTPUT_DWARF_PCREL(FILE, SIZE, LABEL) \
+ do { \
+ fputs (integer_asm_op (SIZE, FALSE), FILE); \
+ assemble_name (FILE, LABEL); \
+ fputs ("@pcrel", FILE); \
+ } while (0)
/* Xtensa constant pool breaks the devices in crtstuff.c to control
section in where code resides. We have to write it as asm code. Use