📄 c4x.h
字号:
#define FLOATUNSHIQF2_LIBCALL "__ufloathiqf2"#define FIX_TRUNCQFHI2_LIBCALL "__fix_truncqfhi2"#define FIXUNS_TRUNCQFHI2_LIBCALL "__ufix_truncqfhi2"#define FLOATHIHF2_LIBCALL "__floathihf2"#define FLOATUNSHIHF2_LIBCALL "__ufloathihf2"#define FIX_TRUNCHFHI2_LIBCALL "__fix_trunchfhi2"#define FIXUNS_TRUNCHFHI2_LIBCALL "__ufix_trunchfhi2"#define FFS_LIBCALL "__ffs"#define TARGET_MEM_FUNCTIONS/* Add any extra modes needed to represent the condition code. On the C4x, we have a "no-overflow" mode which is used when an ADD, SUB, NEG, or MPY insn is used to set the condition code. This is to prevent the combiner from optimising away a following CMP of the result with zero when a signed conditional branch or load insn follows. The problem is a subtle one and deals with the manner in which the negative condition (N) flag is used on the C4x. This flag does not reflect the status of the actual result but of the ideal result had no overflow occured (when considering signed operands). For example, 0x7fffffff + 1 => 0x80000000 Z=0 V=1 N=0 C=0. Here the flags reflect the untruncated result, not the actual result. While the actual result is less than zero, the N flag is not set since the ideal result of the addition without truncation would have been positive. Note that the while the N flag is handled differently to most other architectures, the use of it is self consistent and is not the cause of the problem. Logical operations set the N flag to the MSB of the result so if the result is negative, N is 1. However, integer and floating point operations set the N flag to be the MSB of the result exclusive ored with the overflow (V) flag. Thus if an overflow occurs and the result does not have the MSB set (i.e., the result looks like a positive number), the N flag is set. Conversely, if an overflow occurs and the MSB of the result is set, N is set to 0. Thus the N flag represents the sign of the result if it could have been stored without overflow but does not represent the apparent sign of the result. Note that most architectures set the N flag to be the MSB of the result. The C4x approach to setting the N flag simplifies signed conditional branches and loads which only have to test the state of the N flag, whereas most architectures have to look at both the N and V flags. The disadvantage is that there is no flag giving the status of the sign bit of the operation. However, there are no conditional load or branch instructions that make use of this feature (e.g., BMI---branch minus) instruction. Note that BN and BLT are identical in the C4x. To handle the problem where the N flag is set differently whenever there is an overflow we use a different CC mode, CC_NOOVmode which says that the CC reflects the comparison of the result against zero if no overflow occured. For example, [(set (reg:CC_NOOV 21) (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "") (match_operand:QI 2 "src_operand" "")) (const_int 0))) (set (match_operand:QI 0 "ext_reg_operand" "") (minus:QI (match_dup 1) (match_dup 2)))] Note that there is no problem for insns that don't return a result like CMP, since the CC reflects the effect of operation. An example of a potential problem is when GCC converts (LTU (MINUS (0x80000000) (0x7fffffff) (0x80000000))) to (LEU (MINUS (0x80000000) (0x7fffffff) (0x7fffffff))) to (GE (MINUS (0x80000000) (0x7fffffff) (0x00000000))) Now (MINUS (0x80000000) (0x7fffffff)) returns 0x00000001 but the C4x sets the N flag since the result without overflow would have been 0xffffffff when treating the operands as signed integers. Thus (GE (MINUS (0x80000000) (0x7fffffff) (0x00000000))) sets the N flag but (GE (0x00000001)) does not set the N flag. The upshot is that we can not use signed branch and conditional load instructions after an add, subtract, neg, abs or multiply. We must emit a compare insn to check the result against 0. */#define EXTRA_CC_MODES CC_NOOVmode/* Define the names for the modes specified above. */#define EXTRA_CC_NAMES "CC_NOOV"/* CC_NOOVmode should be used when the first operand is a PLUS, MINUS, NEG or MULT. CCmode should be used when no special processing is needed. */#define SELECT_CC_MODE(OP,X,Y) \ ((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS \ || GET_CODE (X) == NEG || GET_CODE (X) == MULT \ || GET_MODE (X) == ABS \ || GET_CODE (Y) == PLUS || GET_CODE (Y) == MINUS \ || GET_CODE (Y) == NEG || GET_CODE (Y) == MULT \ || GET_MODE (Y) == ABS) \ ? CC_NOOVmode : CCmode)extern struct rtx_def *c4x_gen_compare_reg ();/* Addressing Modes */#define HAVE_POST_INCREMENT 1#define HAVE_PRE_INCREMENT 1#define HAVE_POST_DECREMENT 1#define HAVE_PRE_DECREMENT 1#define HAVE_PRE_MODIFY_REG 1#define HAVE_POST_MODIFY_REG 1#define HAVE_PRE_MODIFY_DISP 1#define HAVE_POST_MODIFY_DISP 1/* The number of insns that can be packed into a single opcode. */#define MULTIPACK_INSNS 2/* Recognize any constant value that is a valid address. We could allow arbitrary constant addresses in the large memory model but for the small memory model we can only accept addresses within the data page. I suppose we could also allow CONST PLUS SYMBOL_REF. */#define CONSTANT_ADDRESS_P(X) (GET_CODE (X) == SYMBOL_REF)/* Maximum number of registers that can appear in a valid memory address. */#define MAX_REGS_PER_ADDRESS 2/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check its validity for a certain class. We have two alternate definitions for each of them. The usual definition accepts all pseudo regs; the other rejects them unless they have been allocated suitable hard regs. The symbol REG_OK_STRICT causes the latter definition to be used. Most source files want to accept pseudo regs in the hope that they will get allocated to the class that the insn wants them to be in. Source files for reload pass need to be strict. After reload, it makes no difference, since pseudo regs have been eliminated by then. */extern int c4x_check_legit_addr ();#ifndef REG_OK_STRICT/* Nonzero if X is a hard or pseudo reg that can be used as an base. */#define REG_OK_FOR_BASE_P(X) IS_ADDR_OR_PSEUDO_REG(REGNO(X))/* Nonzero if X is a hard or pseudo reg that can be used as an index. */#define REG_OK_FOR_INDEX_P(X) IS_INDEX_OR_PSEUDO_REG(REGNO(X))#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \{ \ if (c4x_check_legit_addr (MODE, X, 0)) \ goto ADDR; \}#else/* Nonzero if X is a hard reg that can be used as an index. */#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))/* Nonzero if X is a hard reg that can be used as a base reg. */#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \{ \ if (c4x_check_legit_addr (MODE, X, 1)) \ goto ADDR; \}#endifextern struct rtx_def *c4x_legitimize_address ();#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \{ \ rtx new; \ new = c4x_legitimize_address (X, MODE); \ if (new != NULL_RTX) \ { \ (X) = new; \ goto WIN; \ } \}extern struct rtx_def *c4x_legitimize_reload_address ();#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \{ \ rtx new; \ new = c4x_legitimize_reload_address (X, MODE, insn); \ if (new != NULL_RTX) \ { \ (X) = new; \ /* We do not have to call push_reload because we do not require \ any more reloads. */ \ goto WIN; \ } \}/* No mode-dependent addresses on the C4x are autoincrements. */#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ if (GET_CODE (ADDR) == PRE_DEC \ || GET_CODE (ADDR) == POST_DEC \ || GET_CODE (ADDR) == PRE_INC \ || GET_CODE (ADDR) == POST_INC \ || GET_CODE (ADDR) == POST_MODIFY \ || GET_CODE (ADDR) == PRE_MODIFY) \ goto LABEL/* Nonzero if the constant value X is a legitimate general operand. It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. The C4x can only load 16-bit immediate values, so we only allow a restricted subset of CONST_INT and CONST_DOUBLE. Disallow LABEL_REF and SYMBOL_REF (except on the C40 with the big memory model) so that the symbols will be forced into the constant pool. On second thoughts, let's do this with the move expanders since the alias analysis has trouble if we force constant addresses into memory.*/#define LEGITIMATE_CONSTANT_P(X) \ ((GET_CODE (X) == CONST_DOUBLE && c4x_H_constant (X)) \ || (GET_CODE (X) == CONST_INT && c4x_I_constant (X)) \ || (GET_CODE (X) == SYMBOL_REF) \ || (GET_CODE (X) == LABEL_REF) \ || (GET_CODE (X) == CONST) \ || (GET_CODE (X) == HIGH && ! TARGET_C3X) \ || (GET_CODE (X) == LO_SUM && ! TARGET_C3X))#define LEGITIMATE_DISPLACEMENT_P(X) IS_DISP8_CONST (INTVAL (X))/* Define this macro if references to a symbol must be treated differently depending on something about the variable or function named by the symbol (such as what section it is in). The macro definition, if any, is executed immediately after the rtl for DECL or other node is created. The value of the rtl will be a `mem' whose address is a `symbol_ref'. The usual thing for this macro to do is to a flag in the `symbol_ref' (such as `SYMBOL_REF_FLAG') or to store a modified name string in the `symbol_ref' (if one bit is not enough information). On the C4x we use this to indicate if a symbol is in text or data space. */extern void c4x_encode_section_info ();#define ENCODE_SECTION_INFO(DECL) c4x_encode_section_info (DECL);/* Descripting Relative Cost of Operations *//* Provide the costs of a rtl expression. This is in the body of a switch on CODE. Note that we return, rather than break so that rtx_cost doesn't include CONST_COSTS otherwise expand_mult will think that it is cheaper to synthesise a multiply rather than to use a multiply instruction. I think this is because the algorithm synth_mult doesn't take into account the loading of the operands, whereas the calculation of mult_cost does. */#define RTX_COSTS(RTX, CODE, OUTER_CODE) \ case PLUS: \ case MINUS: \ case AND: \ case IOR: \ case XOR: \ case ASHIFT: \ case ASHIFTRT: \ case LSHIFTRT: \ return COSTS_N_INSNS (1); \ case MULT: \ return COSTS_N_INSNS (GET_MODE_CLASS (GET_MODE (RTX)) == MODE_FLOAT \ || TARGET_MPYI ? 1 : 14); \ case DIV: \ case UDIV: \ case MOD: \ case UMOD: \ return COSTS_N_INSNS (GET_MODE_CLASS (GET_MODE (RTX)) == MODE_FLOAT \ ? 15 : 50);/* Compute the cost of computing a constant rtl expression RTX whose rtx-code is CODE. The body of this macro is a portion of a switch statement. If the code is computed here, return it with a return statement. Otherwise, break from the switch. An insn is assumed to cost 4 units. COSTS_N_INSNS (N) is defined as (N) * 4 - 2. Some small integers are effectively free for the C40. We should also consider if we are using the small memory model. With the big memory model we require an extra insn for a constant loaded from memory. This is used by expand_binop to decide whether to force a constant into a register. If the cost is greater than 2 and the constant is used within a short loop, it gets forced into a register. Ideally, there should be some weighting as to how mnay times it is used within the loop. */#define SHIFT_CODE_P(C) ((C) == ASHIFT || (C) == ASHIFTRT || (C) == LSHIFTRT)#define LOGICAL_CODE_P(C) ((C) == NOT || (C) == AND \ || (C) == IOR || (C) == XOR)#define NON_COMMUTATIVE_CODE_P ((C) == MINUS || (C) == COMPARE)#define CONST_COSTS(RTX,CODE,OUTER_CODE) \ case CONST_INT: \ if (c4x_J_constant (RTX)) \ return 0; \ if (! TARGET_C3X \ && OUTER_CODE == AND \ && GET_CODE (RTX) == CONST_INT \ && (INTVAL (RTX) == 255 || INTVAL (RTX) == 65535)) \ return 0; \ if (! TARGET_C3X \ && (OUTER_CODE == ASHIFTRT || OUTER_CODE == LSHIFTRT) \ && GET_CODE (RTX) == CONST_INT \ && (INTVAL (RTX) == 16 || INTVAL (RTX) == 24)) \ return 0; \ if (TARGET_C3X && SHIFT_CODE_P (OUTER_CODE)) \ return 3; \ if (LOGICAL_CODE_P (OUTER_CODE) \ ? c4x_L_constant (RTX) : c4x_I_constant (RTX)) \ return 2; \ case CONST: \ case LABEL_REF: \ case SYMBOL_REF: \ return 4; \ case CONST_DOUBLE: \ if (c4x_H_constant (RTX)) \ return 2; \ if (GET_MODE (RTX) == QFmode) \ return 4; \ else \ return 8;/* Compute the cost of an address. This is meant to approximate the size and/or execution delay of an insn using that address. If the cost is approximated by the RTL complexity, including CONST_COSTS above, as is usually the case for CISC machines, this macro should not be defined. For aggressively RISCy machines, only one insn format is allowed, so this macro should be a constant. The value of this macro only matters for valid addresses. We handle the most common address without a call to c4x_address_cost. */extern int c4x_address_cost ()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -