📄 xtensa.h
字号:
address. On some machines it may depend on the data type of the function. If 'ARGS_GROW_DOWNWARD', this is the offset to the location above the first argument's address. */#define FIRST_PARM_OFFSET(FNDECL) 0/* Align stack frames on 128 bits for Xtensa. This is necessary for 128-bit datatypes defined in TIE (e.g., for Vectra). */#define STACK_BOUNDARY 128/* Functions do not pop arguments off the stack. */#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) 0/* Use a fixed register window size of 8. */#define WINDOW_SIZE 8/* Symbolic macros for the registers used to return integer, floating point, and values of coprocessor and user-defined modes. */#define GP_RETURN (GP_REG_FIRST + 2 + WINDOW_SIZE)#define GP_OUTGOING_RETURN (GP_REG_FIRST + 2)/* Symbolic macros for the first/last argument registers. */#define GP_ARG_FIRST (GP_REG_FIRST + 2)#define GP_ARG_LAST (GP_REG_FIRST + 7)#define GP_OUTGOING_ARG_FIRST (GP_REG_FIRST + 2 + WINDOW_SIZE)#define GP_OUTGOING_ARG_LAST (GP_REG_FIRST + 7 + WINDOW_SIZE)#define MAX_ARGS_IN_REGISTERS 6/* Don't worry about compatibility with PCC. */#define DEFAULT_PCC_STRUCT_RETURN 0/* Define how to find the value returned by a library function assuming the value has mode MODE. Because we have defined TARGET_PROMOTE_FUNCTION_RETURN that returns true, we have to perform the same promotions as PROMOTE_MODE. */#define XTENSA_LIBCALL_VALUE(MODE, OUTGOINGP) \ gen_rtx_REG ((GET_MODE_CLASS (MODE) == MODE_INT \ && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \ ? SImode : (MODE), \ OUTGOINGP ? GP_OUTGOING_RETURN : GP_RETURN)#define LIBCALL_VALUE(MODE) \ XTENSA_LIBCALL_VALUE ((MODE), 0)#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 the second of a pair (for a value of type 'double', say) need not be recognized by this macro. If the machine has register windows, so that the caller and the called function use different registers for the return value, this macro should recognize only the caller's register numbers. */#define FUNCTION_VALUE_REGNO_P(N) \ ((N) == GP_RETURN)/* A C expression that is nonzero if REGNO is the number of a hard register in which function arguments are sometimes passed. This does *not* include implicit arguments such as the static chain and the structure-value address. On many machines, no registers can be used for this purpose since all function arguments are pushed on the stack. */#define FUNCTION_ARG_REGNO_P(N) \ ((N) >= GP_OUTGOING_ARG_FIRST && (N) <= GP_OUTGOING_ARG_LAST)/* Record the number of argument words seen so far, along with a flag to indicate whether these are incoming arguments. (FUNCTION_INCOMING_ARG is used for both incoming and outgoing args, so a separate flag is needed. */typedef struct xtensa_args{ int arg_words; int incoming;} CUMULATIVE_ARGS;#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ init_cumulative_args (&CUM, 0)#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \ init_cumulative_args (&CUM, 1)/* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ function_arg_advance (&CUM, MODE, TYPE)#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ function_arg (&CUM, MODE, TYPE, FALSE)#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \ function_arg (&CUM, MODE, TYPE, TRUE)/* Specify function argument alignment. */#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \ ((TYPE) != 0 \ ? (TYPE_ALIGN (TYPE) <= PARM_BOUNDARY \ ? PARM_BOUNDARY \ : TYPE_ALIGN (TYPE)) \ : (GET_MODE_ALIGNMENT (MODE) <= PARM_BOUNDARY \ ? PARM_BOUNDARY \ : GET_MODE_ALIGNMENT (MODE)))/* Profiling Xtensa code is typically done with the built-in profiling feature of Tensilica's instruction set simulator, which does not require any compiler support. Profiling code on a real (i.e., non-simulated) Xtensa processor is currently only supported by GNU/Linux with glibc. The glibc version of _mcount doesn't require counter variables. The _mcount function needs the current PC and the current return address to identify an arc in the call graph. Pass the current return address as the first argument; the current PC is available as a0 in _mcount's register window. Both of these values contain window size information in the two most significant bits; we assume that _mcount will mask off those bits. The call to _mcount uses a window size of 8 to make sure that it doesn't clobber any incoming argument values. */#define NO_PROFILE_COUNTERS 1#define FUNCTION_PROFILER(FILE, LABELNO) \ do { \ fprintf (FILE, "\t%s\ta10, a0\n", TARGET_DENSITY ? "mov.n" : "mov"); \ if (flag_pic) \ { \ fprintf (FILE, "\tmovi\ta8, _mcount@PLT\n"); \ fprintf (FILE, "\tcallx8\ta8\n"); \ } \ else \ fprintf (FILE, "\tcall8\t_mcount\n"); \ } while (0)/* 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-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); \ 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.end no-generics\n"); \ } 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)/* 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)/* 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. On Xtensa, a stack back-trace must always begin from the stack pointer, so that the register overflow save area can be located. However, the stack-walking code in GCC always begins from the hard_frame_pointer register, not the stack pointer. The frame pointer is usually equal to the stack pointer, but the __builtin_return_address and __builtin_frame_address functions will not work if count > 0 and they are called from a routine that uses alloca. These functions are not guaranteed to work at all if count > 0 so maybe that is OK. A nicer solution would be to allow the architecture-specific files to specify whether to start from the stack pointer or frame pointer. That would also allow us to skip the machine->accesses_prev_frame stuff that we currently need to ensure that there is a frame pointer when these builtin functions are used. */#define SETUP_FRAME_ADDRESSES xtensa_setup_frame_addresses/* A C expression whose value is RTL representing the address in a stack frame where the pointer to the caller's frame is stored. Assume that FRAMEADDR is an RTL expression for the address of the stack frame itself. For Xtensa, there is no easy way to get the frame pointer if it is not equivalent to the stack pointer. Moreover, the result of this macro is used for continuing to walk back up the stack, so it must return the stack pointer address. Thus, there is some inconsistency here in that __builtin_frame_address will return the frame pointer when count == 0 and the stack pointer when count > 0. */#define DYNAMIC_CHAIN_ADDRESS(frame) \ gen_rtx_PLUS (Pmode, frame, GEN_INT (-3 * UNITS_PER_WORD))/* Define this if the return address of a particular stack frame is accessed from the frame pointer of the previous stack frame. */#define RETURN_ADDR_IN_PREVIOUS_FRAME/* A C expression whose value is RTL representing the value of the return address for the frame COUNT steps up from the current frame, after the prologue. */#define RETURN_ADDR_RTX xtensa_return_addr/* 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. */#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. */#ifdef REG_OK_STRICT#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 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 *//* 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)) \ 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)) \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -