📄 thumb.h
字号:
(CHAIN)); \ emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ (FNADDR)); \}/* Implicit Calls to Library Routines */#define TARGET_MEM_FUNCTIONS 1#define OVERRIDE_OPTIONS thumb_override_options ()/* Addressing Modes */#define HAVE_POST_INCREMENT 1#define CONSTANT_ADDRESS_P(X) \ (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X))#define MAX_REGS_PER_ADDRESS 2#ifdef REG_OK_STRICT#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE)#else /* REG_OK_STRICT */#define REG_OK_FOR_BASE_P(X) \ (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ || (X) == arg_pointer_rtx \ || REGNO (X) >= FIRST_PSEUDO_REGISTER)#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ (REGNO (X) < 8 \ || REGNO (X) >= FIRST_PSEUDO_REGISTER \ || (GET_MODE_SIZE (MODE) >= 4 \ && (REGNO (X) == STACK_POINTER_REGNUM \ || (X) == arg_pointer_rtx)))#define REG_OK_FOR_INDEX_P(X) \ (REGNO (X) < 8 \ || REGNO (X) >= FIRST_PSEUDO_REGISTER)#endif /* REG_OK_STRICT *//* In a REG+REG address, both must be INDEX registers. */#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X)#define LEGITIMATE_OFFSET(MODE,VAL) \(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ && ((VAL) & 1) == 0) \ : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ && ((VAL) & 3) == 0))/* The AP may be eliminated to either the SP or the FP, so we use the least common denominator, e.g. SImode, and offsets from 0 to 64. *//* ??? Verify whether the above is the right approach. *//* ??? Also, the FP may be eliminated to the SP, so perhaps that needs special handling also. *//* ??? Look at how the mips16 port solves this problem. It probably uses better ways to solve some of these problems. *//* Although it is not incorrect, we don't accept QImode and HImode addresses based on the frame pointer or arg pointer until the reload pass starts. This is so that eliminating such addresses into stack based ones won't produce impossible code. */#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \{ \ /* ??? Not clear if this is right. Experiment. */ \ if (GET_MODE_SIZE (MODE) < 4 \ && ! (reload_in_progress || reload_completed) \ && (reg_mentioned_p (frame_pointer_rtx, X) \ || reg_mentioned_p (arg_pointer_rtx, X) \ || reg_mentioned_p (virtual_incoming_args_rtx, X) \ || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ ; \ /* Accept any base register. SP only in SImode or larger. */ \ else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ goto WIN; \ /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ && CONSTANT_POOL_ADDRESS_P (X)) \ goto WIN; \ /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ && (GET_CODE (X) == LABEL_REF \ || (GET_CODE (X) == CONST \ && GET_CODE (XEXP (X, 0)) == PLUS \ && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ goto WIN; \ /* Post-inc indexing only supported for SImode and larger. */ \ else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ && GET_CODE (XEXP (X, 0)) == REG \ && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ goto WIN; \ else if (GET_CODE (X) == PLUS) \ { \ /* REG+REG address can be any two index registers. */ \ /* ??? REG+REG addresses have been completely disabled before \ reload completes, because we do not have enough available \ reload registers. We only have 3 guaranteed reload registers \ (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ to support REG+REG addresses. We have left them enabled after \ reload completes, in the hope that reload_cse_regs and related \ routines will be able to create them after the fact. It is \ probably possible to support REG+REG addresses with additional \ reload work, but I do not not have enough time to attempt such \ a change at this time. */ \ /* ??? Normally checking the mode here is wrong, since it isn't \ impossible to use REG+REG with DFmode. However, the movdf \ pattern requires offsettable addresses, and REG+REG is not \ offsettable, so it must be rejected somehow. Trying to use \ 'o' fails, because offsettable_address_p does a QImode check. \ QImode is not valid for stack addresses, and has a smaller \ range for non-stack bases, and this causes valid addresses \ to be rejected. So we just eliminate REG+REG here by checking \ the mode. */ \ /* We also disallow FRAME+REG addressing since we know that FRAME \ will be replaced with STACK, and SP relative addressing only \ permits SP+OFFSET. */ \ if (GET_MODE_SIZE (MODE) <= 4 \ /* ??? See comment above. */ \ && reload_completed \ && GET_CODE (XEXP (X, 0)) == REG \ && GET_CODE (XEXP (X, 1)) == REG \ && XEXP (X, 0) != frame_pointer_rtx \ && XEXP (X, 1) != frame_pointer_rtx \ && XEXP (X, 0) != virtual_stack_vars_rtx \ && XEXP (X, 1) != virtual_stack_vars_rtx \ && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ goto WIN; \ /* REG+const has 5-7 bit offset for non-SP registers. */ \ else if (GET_CODE (XEXP (X, 0)) == REG \ && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ || XEXP (X, 0) == arg_pointer_rtx) \ && GET_CODE (XEXP (X, 1)) == CONST_INT \ && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ goto WIN; \ /* REG+const has 10 bit offset for SP, but only SImode and \ larger is supported. */ \ /* ??? Should probably check for DI/DFmode overflow here \ just like GO_IF_LEGITIMATE_OFFSET does. */ \ else if (GET_CODE (XEXP (X, 0)) == REG \ && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ && GET_MODE_SIZE (MODE) >= 4 \ && GET_CODE (XEXP (X, 1)) == CONST_INT \ && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ && (INTVAL (XEXP (X, 1)) & 3) == 0) \ goto WIN; \ } \}/* ??? If an HImode FP+large_offset address is converted to an HImode SP+large_offset address, then reload won't know how to fix it. It sees only that SP isn't valid for HImode, and so reloads the SP into an index register, but the resulting address is still invalid because the offset is too big. We fix it here instead by reloading the entire address. *//* We could probably achieve better results by defining PROMOTE_MODE to help cope with the variances between the Thumb's signed and unsigned byte and halfword load instructions. */#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \{ \ if (GET_CODE (X) == PLUS \ && GET_MODE_SIZE (MODE) < 4 \ && GET_CODE (XEXP (X, 0)) == REG \ && XEXP (X, 0) == stack_pointer_rtx \ && GET_CODE (XEXP (X, 1)) == CONST_INT \ && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ { \ rtx orig_X = X; \ X = copy_rtx (X); \ push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ BASE_REG_CLASS, \ Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ goto WIN; \ } \} #define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL)#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)#define LEGITIMATE_CONSTANT_P(X) \ (GET_CODE (X) == CONST_INT \ || GET_CODE (X) == CONST_DOUBLE \ || CONSTANT_ADDRESS_P (X))/* Condition Code Status */#define NOTICE_UPDATE_CC(EXP,INSN) \{ \ if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ CC_STATUS_INIT; \}/* Describing Relative Costs of Operations */#define SLOW_BYTE_ACCESS 0#define SLOW_UNALIGNED_ACCESS 1#define NO_FUNCTION_CSE 1#define NO_RECURSIVE_FUNCTION_CSE 1#define REGISTER_MOVE_COST(FROM,TO) \ (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2)#define MEMORY_MOVE_COST(M,CLASS,IN) \ ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2))/* This will allow better space optimization when compiling with -O */#define BRANCH_COST (optimize > 1 ? 1 : 0)#define RTX_COSTS(X,CODE,OUTER) \ case MULT: \ if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ { \ int cycles = 0; \ unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ while (i) \ { \ i >>= 2; \ cycles++; \ } \ return COSTS_N_INSNS (2) + cycles; \ } \ return COSTS_N_INSNS (1) + 16; \ case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ return COSTS_N_INSNS (1); \ case SET: \ return (COSTS_N_INSNS (1) \ + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ + GET_CODE (SET_DEST (X)) == MEM))#define CONST_COSTS(X,CODE,OUTER) \ case CONST_INT: \ if ((OUTER) == SET) \ { \ if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ return 0; \ if (thumb_shiftable_const (INTVAL (X))) \ return COSTS_N_INSNS (2); \ return COSTS_N_INSNS (3); \ } \ else if (OUTER == PLUS \ && INTVAL (X) < 256 && INTVAL (X) > -256) \ return 0; \ else if (OUTER == COMPARE \ && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ return 0; \ else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ || OUTER == LSHIFTRT) \ return 0; \ return COSTS_N_INSNS (2); \ case CONST: \ case CONST_DOUBLE: \ case LABEL_REF: \ case SYMBOL_REF: \ return COSTS_N_INSNS(3);#define ADDRESS_COST(X) \ ((GET_CODE (X) == REG \ || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ ? 1 : 2)/* Position Independent Code */#define PRINT_OPERAND(STREAM,X,CODE) \ thumb_print_operand((STREAM), (X), (CODE))#define PRINT_OPERAND_ADDRESS(STREAM,X) \{ \ if (GET_CODE ((X)) == REG) \ fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ else if (GET_CODE ((X)) == POST_INC) \ fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ else if (GET_CODE ((X)) == PLUS) \ { \ if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ fprintf ((STREAM), "[%s, #%d]", \ reg_names[REGNO (XEXP ((X), 0))], \ (int) INTVAL (XEXP ((X), 1))); \ else \ fprintf ((STREAM), "[%s, %s]", \ reg_names[REGNO (XEXP ((X), 0))], \ reg_names[REGNO (XEXP ((X), 1))]); \ } \ else \ output_addr_const ((STREAM), (X)); \}#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_'))/* Emit a special directive when defining a function name. This is used by the assembler to assit with interworking. */#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ if (! is_called_in_ARM_mode (decl)) \ fprintf (file, "\t.thumb_func\n") ; \ else \ fprintf (file, "\t.code\t32\n") ; \ ASM_OUTPUT_LABEL (file, name)#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)])#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)])#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ final_prescan_insn((INSN))/* Controlling Debugging Information Format */#define DBX_REGISTER_NUMBER(REGNO) (REGNO)/* Specific options for DBX Output */#define DBX_DEBUGGING_INFO 1#define DEFAULT_GDB_EXTENSIONS 1/* Cross Compilation and Floating Point */#define REAL_ARITHMETIC/* Miscellaneous Parameters */#define PREDICATE_CODES \ {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}},#define CASE_VECTOR_MODE Pmode#define WORD_REGISTER_OPERATIONS#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR#define EASY_DIV_EXPR TRUNC_DIV_EXPR#define MOVE_MAX 4#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1#define STORE_FLAG_VALUE 1#define Pmode SImode#define FUNCTION_MODE SImode#define DOLLARS_IN_IDENTIFIERS 0#define NO_DOLLAR_IN_LABEL 1#define HAVE_ATEXIT/* The literal pool needs to reside in the text area due to the limited PC addressing range: */#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN))/* Options specific to Thumb *//* True if a return instruction can be used in this function. */int thumb_trivial_epilogue ();#define USE_RETURN (reload_completed && thumb_trivial_epilogue ())extern char * thumb_unexpanded_epilogue ();extern char * output_move_mem_multiple ();extern char * thumb_load_double_from_address ();extern char * output_return ();extern int far_jump_used_p();extern int is_called_in_ARM_mode ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -