📄 c4x.h
字号:
/* List the order in which to allocate registers. Each register must be listed once, even those in FIXED_REGISTERS. First allocate registers that don't need preservation across calls, except index and address registers. Then allocate data registers that require preservation across calls (even though this invokes an extra overhead of having to save/restore these registers). Next allocate the address and index registers, since using these registers for arithmetic can cause pipeline stalls. Finally allocated the fixed registers which won't be allocated anyhow. */#define REG_ALLOC_ORDER \{R0_REGNO, R1_REGNO, R2_REGNO, R3_REGNO, \ R9_REGNO, R10_REGNO, R11_REGNO, \ RS_REGNO, RE_REGNO, RC_REGNO, BK_REGNO, \ R4_REGNO, R5_REGNO, R6_REGNO, R7_REGNO, R8_REGNO, \ AR0_REGNO, AR1_REGNO, AR2_REGNO, AR3_REGNO, \ AR4_REGNO, AR5_REGNO, AR6_REGNO, AR7_REGNO, \ IR0_REGNO, IR1_REGNO, \ SP_REGNO, DP_REGNO, ST_REGNO, IE_REGNO, IF_REGNO, IOF_REGNO}/* A C expression that is nonzero if hard register number REGNO2 can be considered for use as a rename register for REGNO1 */#define HARD_REGNO_RENAME_OK(REGNO1,REGNO2) \ c4x_hard_regno_rename_ok((REGNO1), (REGNO2))/* Determine which register classes are very likely used by spill registers. local-alloc.c won't allocate pseudos that have these classes as their preferred class unless they are "preferred or nothing". */#define CLASS_LIKELY_SPILLED_P(CLASS) ((CLASS) == INDEX_REGS)/* CCmode is wrongly defined in machmode.def. It should have a size of UNITS_PER_WORD. HFmode is 40-bits and thus fits within a single extended precision register. Similarly, HCmode fits within two extended precision registers. */#define HARD_REGNO_NREGS(REGNO, MODE) \(((MODE) == CCmode || (MODE) == CC_NOOVmode) ? 1 : \ ((MODE) == HFmode) ? 1 : \ ((MODE) == HCmode) ? 2 : \ ((GET_MODE_SIZE(MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))/* A C expression that is nonzero if the hard register REGNO is preserved across a call in mode MODE. This does not have to include the call used registers. */#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) \ ((IS_FLOAT_CALL_SAVED_REGNO (REGNO) && ! ((MODE) == QFmode)) \ || (IS_INT_CALL_SAVED_REGNO (REGNO) \ && ! ((MODE) == QImode || (MODE) == HImode || (MODE) == Pmode)))/* Specify the modes required to caller save a given hard regno. */#define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) (c4x_caller_save_map[REGNO])#define HARD_REGNO_MODE_OK(REGNO, MODE) c4x_hard_regno_mode_ok(REGNO, MODE)/* A C expression that is nonzero if it is desirable to choose register allocation so as to avoid move instructions between a value of mode MODE1 and a value of mode MODE2. Value is 1 if it is a good idea to tie two pseudo registers when one has mode MODE1 and one has mode MODE2. If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, for any hard reg, then this must be 0 for correct output. */#define MODES_TIEABLE_P(MODE1, MODE2) 0/* Define the classes of registers for register constraints in the machine description. Also define ranges of constants. One of the classes must always be named ALL_REGS and include all hard regs. If there is more than one class, another class must be named NO_REGS and contain no registers. The name GENERAL_REGS must be the name of a class (or an alias for another name such as ALL_REGS). This is the class of registers that is allowed by "g" or "r" in a register constraint. Also, registers outside this class are allocated only when instructions express preferences for them. The classes must be numbered in nondecreasing order; that is, a larger-numbered class must never be contained completely in a smaller-numbered class. For any two classes, it is very desirable that there be another class that represents their union. */ enum reg_class { NO_REGS, R0R1_REGS, /* 't'. */ R2R3_REGS, /* 'u'. */ EXT_LOW_REGS, /* 'q'. */ EXT_REGS, /* 'f'. */ ADDR_REGS, /* 'a'. */ INDEX_REGS, /* 'x'. */ BK_REG, /* 'k'. */ SP_REG, /* 'b'. */ RC_REG, /* 'v'. */ COUNTER_REGS, /* */ INT_REGS, /* 'c'. */ GENERAL_REGS, /* 'r'. */ DP_REG, /* 'z'. */ ST_REG, /* 'y'. */ ALL_REGS, LIM_REG_CLASSES };#define N_REG_CLASSES (int) LIM_REG_CLASSES#define REG_CLASS_NAMES \{ \ "NO_REGS", \ "R0R1_REGS", \ "R2R3_REGS", \ "EXT_LOW_REGS", \ "EXT_REGS", \ "ADDR_REGS", \ "INDEX_REGS", \ "BK_REG", \ "SP_REG", \ "RC_REG", \ "COUNTER_REGS", \ "INT_REGS", \ "GENERAL_REGS", \ "DP_REG", \ "ST_REG", \ "ALL_REGS" \}/* Define which registers fit in which classes. This is an initializer for a vector of HARD_REG_SET of length N_REG_CLASSES. RC is not included in GENERAL_REGS since the register allocator will often choose a general register in preference to RC for the decrement_and_branch_on_count pattern. */#define REG_CLASS_CONTENTS \{ \ {0x00000000}, /* No registers. */ \ {0x00000003}, /* 't' R0-R1 . */ \ {0x0000000c}, /* 'u' R2-R3 . */ \ {0x000000ff}, /* 'q' R0-R7 . */ \ {0xf00000ff}, /* 'f' R0-R11 */ \ {0x0000ff00}, /* 'a' AR0-AR7. */ \ {0x00060000}, /* 'x' IR0-IR1. */ \ {0x00080000}, /* 'k' BK. */ \ {0x00100000}, /* 'b' SP. */ \ {0x08000000}, /* 'v' RC. */ \ {0x0800ff00}, /* RC,AR0-AR7. */ \ {0x0e1eff00}, /* 'c' AR0-AR7, IR0-IR1, BK, SP, RS, RE, RC. */ \ {0xfe1effff}, /* 'r' R0-R11, AR0-AR7, IR0-IR1, BK, SP, RS, RE, RC. */\ {0x00010000}, /* 'z' DP. */ \ {0x00200000}, /* 'y' ST. */ \ {0xffffffff}, /* All registers. */ \}/* The same information, inverted: Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression or could index an array. */#define REGNO_REG_CLASS(REGNO) (c4x_regclass_map[REGNO])/* When SMALL_REGISTER_CLASSES is defined, the lifetime of registers explicitly used in the rtl is kept as short as possible. We only need to define SMALL_REGISTER_CLASSES if TARGET_PARALLEL_MPY is defined since the MPY|ADD insns require the classes R0R1_REGS and R2R3_REGS which are used by the function return registers (R0,R1) and the register arguments (R2,R3), respectively. I'm reluctant to define this macro since it stomps on many potential optimizations. Ideally it should have a register class argument so that not all the register classes gets penalized for the sake of a naughty few... For long double arithmetic we need two additional registers that we can use as spill registers. */#define SMALL_REGISTER_CLASSES (TARGET_SMALL_REG_CLASS && TARGET_PARALLEL_MPY)#define BASE_REG_CLASS ADDR_REGS#define INDEX_REG_CLASS INDEX_REGS/* Register constraints for the C4x a - address reg (ar0-ar7) b - stack reg (sp) c - other gp int-only reg d - data/int reg (equiv. to f) f - data/float reg h - data/long double reg (equiv. to f) k - block count (bk) q - r0-r7 t - r0-r1 u - r2-r3 v - repeat count (rc) x - index register (ir0-ir1) y - status register (st) z - dp reg (dp) Memory/constant constraints for the C4x G - short float 16-bit I - signed 16-bit constant (sign extended) J - signed 8-bit constant (sign extended) (C4x only) K - signed 5-bit constant (sign extended) (C4x only for stik) L - unsigned 16-bit constant M - unsigned 8-bit constant (C4x only) N - ones complement of unsigned 16-bit constant Q - indirect arx + 9-bit signed displacement (a *-arx(n) or *+arx(n) is used to account for the sign bit) R - indirect arx + 5-bit unsigned displacement (C4x only) S - indirect arx + 0, 1, or irn displacement T - direct symbol ref > - indirect with autoincrement < - indirect with autodecrement } - indirect with post-modify { - indirect with pre-modify */#define REG_CLASS_FROM_LETTER(CC) \ ( ((CC) == 'a') ? ADDR_REGS \ : ((CC) == 'b') ? SP_REG \ : ((CC) == 'c') ? INT_REGS \ : ((CC) == 'd') ? EXT_REGS \ : ((CC) == 'f') ? EXT_REGS \ : ((CC) == 'h') ? EXT_REGS \ : ((CC) == 'k') ? BK_REG \ : ((CC) == 'q') ? EXT_LOW_REGS \ : ((CC) == 't') ? R0R1_REGS \ : ((CC) == 'u') ? R2R3_REGS \ : ((CC) == 'v') ? RC_REG \ : ((CC) == 'x') ? INDEX_REGS \ : ((CC) == 'y') ? ST_REG \ : ((CC) == 'z') ? DP_REG \ : NO_REGS )/* These assume that REGNO is a hard or pseudo reg number. They give nonzero only if REGNO is a hard reg of the suitable class or a pseudo reg currently allocated to a suitable hard reg. Since they use reg_renumber, they are safe only once reg_renumber has been allocated, which happens in local-alloc.c. */#define REGNO_OK_FOR_BASE_P(REGNO) \ (IS_ADDR_REGNO(REGNO) || IS_ADDR_REGNO((unsigned)reg_renumber[REGNO]))#define REGNO_OK_FOR_INDEX_P(REGNO) \ (IS_INDEX_REGNO(REGNO) || IS_INDEX_REGNO((unsigned)reg_renumber[REGNO]))/* If we have to generate framepointer + constant prefer an ADDR_REGS register. This avoids using EXT_REGS in addqi3_noclobber_reload. */#define PREFERRED_RELOAD_CLASS(X, CLASS) \ (GET_CODE (X) == PLUS \ && GET_MODE (X) == Pmode \ && GET_CODE (XEXP ((X), 0)) == REG \ && GET_MODE (XEXP ((X), 0)) == Pmode \ && REGNO (XEXP ((X), 0)) == FRAME_POINTER_REGNUM \ && GET_CODE (XEXP ((X), 1)) == CONST_INT \ ? ADDR_REGS : (CLASS))#define LIMIT_RELOAD_CLASS(X, CLASS) (CLASS)#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) 0#define CLASS_MAX_NREGS(CLASS, MODE) \(((MODE) == CCmode || (MODE) == CC_NOOVmode) ? 1 : ((MODE) == HFmode) ? 1 : \((GET_MODE_SIZE(MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))#define IS_INT5_CONST(VAL) (((VAL) <= 15) && ((VAL) >= -16)) /* 'K'. */#define IS_UINT5_CONST(VAL) (((VAL) <= 31) && ((VAL) >= 0)) /* 'R'. */#define IS_INT8_CONST(VAL) (((VAL) <= 127) && ((VAL) >= -128)) /* 'J'. */#define IS_UINT8_CONST(VAL) (((VAL) <= 255) && ((VAL) >= 0)) /* 'M'. */#define IS_INT16_CONST(VAL) (((VAL) <= 32767) && ((VAL) >= -32768)) /* 'I'. */#define IS_UINT16_CONST(VAL) (((VAL) <= 65535) && ((VAL) >= 0)) /* 'L'. */#define IS_NOT_UINT16_CONST(VAL) IS_UINT16_CONST(~(VAL)) /* 'N'. */#define IS_HIGH_CONST(VAL) \(! TARGET_C3X && (((VAL) & 0xffff) == 0)) /* 'O'. */#define IS_DISP1_CONST(VAL) (((VAL) <= 1) && ((VAL) >= -1)) /* 'S'. */#define IS_DISP8_CONST(VAL) (((VAL) <= 255) && ((VAL) >= -255)) /* 'Q'. */#define IS_DISP1_OFF_CONST(VAL) (IS_DISP1_CONST (VAL) \ && IS_DISP1_CONST (VAL + 1))#define IS_DISP8_OFF_CONST(VAL) (IS_DISP8_CONST (VAL) \ && IS_DISP8_CONST (VAL + 1))#define CONST_OK_FOR_LETTER_P(VAL, C) \ ( ((C) == 'I') ? (IS_INT16_CONST (VAL)) \ : ((C) == 'J') ? (! TARGET_C3X && IS_INT8_CONST (VAL)) \ : ((C) == 'K') ? (! TARGET_C3X && IS_INT5_CONST (VAL)) \ : ((C) == 'L') ? (IS_UINT16_CONST (VAL)) \ : ((C) == 'M') ? (! TARGET_C3X && IS_UINT8_CONST (VAL)) \ : ((C) == 'N') ? (IS_NOT_UINT16_CONST (VAL)) \ : ((C) == 'O') ? (IS_HIGH_CONST (VAL)) \ : 0 ) #define CONST_DOUBLE_OK_FOR_LETTER_P(OP, C) \ ( ((C) == 'G') ? (fp_zero_operand (OP, QFmode)) \ : ((C) == 'H') ? (c4x_H_constant (OP)) \ : 0 )#define EXTRA_CONSTRAINT(OP, C) \ ( ((C) == 'Q') ? (c4x_Q_constraint (OP)) \ : ((C) == 'R') ? (c4x_R_constraint (OP)) \ : ((C) == 'S') ? (c4x_S_constraint (OP)) \ : ((C) == 'T') ? (c4x_T_constraint (OP)) \ : ((C) == 'U') ? (c4x_U_constraint (OP)) \ : 0 )#define SMALL_CONST(VAL, insn) \ ( ((insn == NULL_RTX) || (get_attr_data (insn) == DATA_INT16)) \ ? IS_INT16_CONST (VAL) \ : ( (get_attr_data (insn) == DATA_NOT_UINT16) \ ? IS_NOT_UINT16_CONST (VAL) \ : ( (get_attr_data (insn) == DATA_HIGH_16) \ ? IS_HIGH_CONST (VAL) \ : IS_UINT16_CONST (VAL) \ ) \ ) \ )/* I. Routine calling with arguments in registers ---------------------------------------------- The TI C3x compiler has a rather unusual register passing algorithm. Data is passed in the following registers (in order): AR2, R2, R3, RC, RS, RE However, the first and second floating point values are always in R2 and R3 (and all other floats are on the stack). Structs are always passed on the stack. If the last argument is an ellipsis, the previous argument is passed on the stack so that its address can be taken for the stdargs macros. Because of this, we have to pre-scan the list of arguments to figure out what goes where in the list. II. Routine calling with arguments on stack ------------------------------------------- Let the subroutine declared as "foo(arg0, arg1, arg2);" have local variables loc0, loc1, and loc2. After the function prologue has been executed, the stack frame will look like: [stack grows towards increasing addresses] I-------------I 5 I saved reg1 I <= SP points here I-------------I 4 I saved reg0 I I-------------I 3 I loc2 I I-------------I 2 I loc1 I I-------------I 1 I loc0 I I-------------I 0 I old FP I <= FP (AR3) points here I-------------I -1 I return PC I I-------------I -2 I arg0 I I-------------I -3 I arg1 I I-------------I -4 I arg2 I I-------------I All local variables (locn) are accessible by means of +FP(n+1) addressing, where n is the local variable number. All stack arguments (argn) are accessible by means of -FP(n-2). The stack pointer (SP) points to the last register saved in the prologue (regn). Note that a push instruction performs a preincrement of the stack pointer. (STACK_PUSH_CODE == PRE_INC) III. Registers used in function calling convention -------------------------------------------------- Preserved across calls: R4...R5 (only by PUSH, i.e. lower 32 bits) R6...R7 (only by PUSHF, i.e. upper 32 bits) AR3...AR7 (Because of this model, we only assign FP values in R6, R7 and only assign integer values in R4, R5.) These registers are saved at each function entry and restored at the exit. Also it is expected any of these not affected by any call to user-defined (not service) functions. Not preserved across calls: R0...R3 R4...R5 (upper 8 bits) R6...R7 (lower 8 bits) AR0...AR2, IR0, IR1, BK, ST, RS, RE, RC These registers are used arbitrary in a function without being preserved. It is also expected that any of these can be clobbered by any call. Not used by GCC (except for in user "asm" statements): IE (DIE), IF (IIE), IOF (IIF) These registers are never used by GCC for any data, but can be used
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -