📄 xtensa.h
字号:
fprintf (STREAM, "\tmovsp\tsp, a9\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 49/* 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, 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)/* Define the `__builtin_va_list' type for the ABI. */#define BUILD_VA_LIST_TYPE(VALIST) \ (VALIST) = xtensa_build_va_list ()/* If defined, is a C expression that produces the machine-specific code for a call to '__builtin_saveregs'. This code will be moved to the very beginning of the function, before any parameter access are made. The return value of this function should be an RTX that contains the value to use as the return of '__builtin_saveregs'. */#define EXPAND_BUILTIN_SAVEREGS \ xtensa_builtin_saveregs/* Implement `va_start' for varargs and stdarg. */#define EXPAND_BUILTIN_VA_START(valist, nextarg) \ xtensa_va_start (valist, nextarg)/* Implement `va_arg'. */#define EXPAND_BUILTIN_VA_ARG(valist, type) \ xtensa_va_arg (valist, type)/* 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_rtx_CONST_INT (VOIDmode, -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 \ && 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)) \ 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 valid address. This is defined to be the same as 'CONSTANT_P (X)', but rejecting CONST_DOUBLE. */#define CONSTANT_ADDRESS_P(X) \ ((GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ || GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH \ || (GET_CODE (X) == CONST)))/* Nonzero if the constant value X is a legitimate general operand. It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */#define LEGITIMATE_CONSTANT_P(X) 1/* A C expression that is nonzero if X is a legitimate immediate operand on the target machine when generating position independent code. */#define LEGITIMATE_PIC_OPERAND_P(X) \ ((GET_CODE (X) != SYMBOL_REF || SYMBOL_REF_FLAG (X)) \ && 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; \ } \ } \ } while (0)/* Treat constant-pool references as "mode dependent" since they can only be accessed with SImode loads. This works around a bug in the combiner where a constant pool reference is temporarily converted to an HImode load, which is then assumed to zero-extend based on our definition of LOAD_EXTEND_OP. This is wrong because the high bits of a 16-bit value in the constant pool are now sign-extended by default. */#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ do { \ if (constantpool_address_p (ADDR)) \ goto LABEL; \ } while (0)/* Specify the machine mode that this machine uses for the index in the tablejump instruction. */#define CASE_VECTOR_MODE (SImode)/* Define this if the tablejump instruction expects the table to contain offsets from the address of the table. Do not define this if the table should contain absolute addresses. *//* #define CASE_VECTOR_PC_RELATIVE *//* Define this as 1 if 'char' should by default be signed; else as 0. */#define DEFAULT_SIGNED_CHAR 0/* Max number of bytes we can move from memory to memory in one reasonably fast instruction. */#define MOVE_MAX 4#define MAX_MOVE_MAX 4/* Prefer word-sized loads. */#define SLOW_BYTE_ACCESS 1/* Xtensa doesn't have any instructions that set integer values based on the results of comparisons, but the simplification code in the combiner also uses this macro. The value should be either 1 or -1 to enable some optimizations in the combiner; I'm not sure which is better for us. Since we've been using 1 for a while, it should probably stay that way for compatibility. */#define STORE_FLAG_VALUE 1/* Shift instructions ignore all but the low-order few bits. */#define SHIFT_COUNT_TRUNCATED 1/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits is done just by pretending it is already truncated. */#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1/* Specify the machine mode that pointers have. After generation of rtl, the compiler makes no further distinction between pointers and any other objects of this machine mode. */#define Pmode SImode/* A function address in a call instruction is a word address (for indexing purposes) so give the MEM rtx a words's mode. */#define FUNCTION_MODE SImode/* A C expression that evaluates to true if it is ok to perform a sibling call to DECL. *//* TODO: fix this up to allow at least some sibcalls */#define FUNCTION_OK_FOR_SIBCALL(DECL) 0/* Xtensa constant costs. */#define CONST_COSTS(X, CODE, OUTER_CODE) \ case CONST_INT: \ switch (OUTER_CODE) \ { \ case SET: \ if (xtensa_simm12b (INTVAL (X))) return 4; \ break; \ case PLUS: \ if (xtensa_simm8 (INTVAL (X))) return 0; \ if (xtensa_simm8x256 (INTVAL (X))) return 0; \ break; \ case AND: \ if (xtensa_mask_immediate (INTVAL (X))) return 0; \ break; \ case COMPARE: \ if ((INTVAL (X) == 0) || xtensa_b4const (INTVAL (X))) return 0; \ break; \ case ASHIFT: \ case ASHIFTRT: \ case LSHIFTRT: \ case ROTATE: \ case ROTATERT: \ /* no way to tell if X is the 2nd operand so be conservative */ \ default: break; \ } \ if (xtensa_simm12b (INTVAL (X))) return 5; \ return 6; \ case CONST: \ case LABEL_REF: \ case SYMBOL_REF: \ return 5; \ case CONST_DOUBLE: \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -