📄 c4x.h
字号:
with "asm" statements. */#define C4X_ARG0 -2#define C4X_LOC0 1/* Basic Stack Layout. */ /* The stack grows upward, stack frame grows upward, and args grow downward. */#define STARTING_FRAME_OFFSET C4X_LOC0#define FIRST_PARM_OFFSET(FNDECL) (C4X_ARG0 + 1)#define ARGS_GROW_DOWNWARD#define STACK_POINTER_OFFSET 1/* Define this if pushing a word on the stack makes the stack pointer a smaller address. *//* #define STACK_GROWS_DOWNWARD. *//* Like the dsp16xx, i370, i960, and we32k ports. *//* Define this to nonzero if the nominal address of the stack frame is at the high-address end of the local variables; that is, each additional local variable allocated goes at a more negative offset in the frame. */#define FRAME_GROWS_DOWNWARD 0/* Registers That Address the Stack Frame. */#define STACK_POINTER_REGNUM SP_REGNO /* SP. */#define FRAME_POINTER_REGNUM AR3_REGNO /* AR3. */#define ARG_POINTER_REGNUM AR3_REGNO /* AR3. */#define STATIC_CHAIN_REGNUM AR0_REGNO /* AR0. *//* Eliminating Frame Pointer and Arg Pointer. */#define FRAME_POINTER_REQUIRED 0#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) \{ \ int regno; \ int offset = 0; \ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \ if (regs_ever_live[regno] && ! call_used_regs[regno]) \ offset += TARGET_PRESERVE_FLOAT \ && IS_FLOAT_CALL_SAVED_REGNO (regno) ? 2 : 1; \ (DEPTH) = -(offset + get_frame_size ()); \}/* This is a hack... We need to specify a register. */#define ELIMINABLE_REGS \ {{ FRAME_POINTER_REGNUM, FRAME_POINTER_REGNUM }}#define CAN_ELIMINATE(FROM, TO) \ (! (((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \ || ((FROM) == FRAME_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM)))#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \{ \ int regno; \ int offset = 0; \ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \ if (regs_ever_live[regno] && ! call_used_regs[regno]) \ offset += TARGET_PRESERVE_FLOAT \ && IS_FLOAT_CALL_SAVED_REGNO (regno) ? 2 : 1; \ (OFFSET) = -(offset + get_frame_size ()); \}/* Passing Function Arguments on the Stack. */#define PUSH_ARGS 1#define PUSH_ROUNDING(BYTES) (BYTES)#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0/* The following structure is used by calls.c, function.c, c4x.c. */typedef struct c4x_args{ int floats; int ints; int maxfloats; int maxints; int init; int var; int prototype; int args;}CUMULATIVE_ARGS;#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ (c4x_init_cumulative_args (&CUM, FNTYPE, LIBNAME))#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ (c4x_function_arg_advance (&CUM, MODE, TYPE, NAMED))#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ (c4x_function_arg(&CUM, MODE, TYPE, NAMED))/* Define the profitability of saving registers around calls. We disable caller save to avoid a bug in flow.c (this also affects other targets such as m68k). Since we must use stf/sti, the profitability is marginal anyway. */#define CALLER_SAVE_PROFITABLE(REFS,CALLS) 0/* 1 if N is a possible register number for function argument passing. */#define FUNCTION_ARG_REGNO_P(REGNO) \ ( ( ((REGNO) == AR2_REGNO) /* AR2. */ \ || ((REGNO) == R2_REGNO) /* R2. */ \ || ((REGNO) == R3_REGNO) /* R3. */ \ || ((REGNO) == RC_REGNO) /* RC. */ \ || ((REGNO) == RS_REGNO) /* RS. */ \ || ((REGNO) == RE_REGNO)) /* RE. */ \ ? 1 \ : 0)/* How Scalar Function Values Are Returned. */#define FUNCTION_VALUE(VALTYPE, FUNC) \ gen_rtx_REG (TYPE_MODE(VALTYPE), R0_REGNO) /* Return in R0. */#define LIBCALL_VALUE(MODE) \ gen_rtx_REG (MODE, R0_REGNO) /* Return in R0. */#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == R0_REGNO)/* How Large Values Are Returned. */#define DEFAULT_PCC_STRUCT_RETURN 0/* Generating Code for Profiling. *//* Note that the generated assembly uses the ^ operator to load the 16 MSBs of the address. This is not supported by the TI assembler. The FUNCTION profiler needs a function mcount which gets passed a pointer to the LABELNO. */#define FUNCTION_PROFILER(FILE, LABELNO) \ if (! TARGET_C3X) \ { \ fprintf (FILE, "\tpush\tar2\n"); \ fprintf (FILE, "\tldhi\t^LP%d,ar2\n", (LABELNO)); \ fprintf (FILE, "\tor\t#LP%d,ar2\n", (LABELNO)); \ fprintf (FILE, "\tcall\tmcount\n"); \ fprintf (FILE, "\tpop\tar2\n"); \ } \ else \ { \ fprintf (FILE, "\tpush\tar2\n"); \ fprintf (FILE, "\tldiu\t^LP%d,ar2\n", (LABELNO)); \ fprintf (FILE, "\tlsh\t16,ar2\n"); \ fprintf (FILE, "\tor\t#LP%d,ar2\n", (LABELNO)); \ fprintf (FILE, "\tcall\tmcount\n"); \ fprintf (FILE, "\tpop\tar2\n"); \ }/* 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)/* 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 PACK_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. */#ifndef REG_OK_STRICT/* Nonzero if X is a hard or pseudo reg that can be used as a base. */#define REG_OK_FOR_BASE_P(X) IS_ADDR_OR_PSEUDO_REG(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(X)#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \{ \ if (c4x_legitimate_address_p (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_legitimate_address_p (MODE, X, 1)) \ goto ADDR; \}#endif#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \{ \ rtx new; \ \ new = c4x_legitimize_address (X, MODE); \ if (new != NULL_RTX) \ { \ (X) = new; \ goto WIN; \ } \}#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \{ \ if (MODE != HImode \ && MODE != HFmode \ && GET_MODE (X) != HImode \ && GET_MODE (X) != HFmode \ && (GET_CODE (X) == CONST \ || GET_CODE (X) == SYMBOL_REF \ || GET_CODE (X) == LABEL_REF)) \ { \ if (! TARGET_SMALL) \ { \ int i; \ (X) = gen_rtx_LO_SUM (GET_MODE (X), \ gen_rtx_HIGH (GET_MODE (X), X), X); \ i = push_reload (XEXP (X, 0), NULL_RTX, \ &XEXP (X, 0), NULL, \ DP_REG, GET_MODE (X), VOIDmode, 0, 0, \ OPNUM, TYPE); \ /* The only valid reg is DP. This is a fixed reg and will \ normally not be used so force it. */ \ rld[i].reg_rtx = gen_rtx_REG (Pmode, DP_REGNO); \ rld[i].nocombine = 1; \ } \ else \ { \ /* make_memloc in reload will substitute invalid memory \ references. We need to fix them up. */ \ (X) = gen_rtx_LO_SUM (Pmode, gen_rtx_REG (Pmode, DP_REGNO), (X)); \ } \ goto WIN; \ } \ else if (MODE != HImode \ && MODE != HFmode \ && GET_MODE (X) != HImode \ && GET_MODE (X) != HFmode \ && GET_CODE (X) == LO_SUM \ && GET_CODE (XEXP (X,0)) == HIGH \ && (GET_CODE (XEXP (XEXP (X,0),0)) == CONST \ || GET_CODE (XEXP (XEXP (X,0),0)) == SYMBOL_REF \ || GET_CODE (XEXP (XEXP (X,0),0)) == LABEL_REF)) \ { \ if (! TARGET_SMALL) \ { \ int i = push_reload (XEXP (X, 0), NULL_RTX, \ &XEXP (X, 0), NULL, \ DP_REG, GET_MODE (X), VOIDmode, 0, 0, \ OPNUM, TYPE); \ /* The only valid reg is DP. This is a fixed reg and will \ normally not be used so force it. */ \ rld[i].reg_rtx = gen_rtx_REG (Pmode, DP_REGNO); \ rld[i].nocombine = 1; \ } \ 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) \ || (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))/* Describing Relative Cost of Operations. */#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \if (REG_P (OP1) && ! REG_P (OP0)) \{ \ rtx tmp = OP0; OP0 = OP1 ; OP1 = tmp; \ CODE = swap_condition (CODE); \}#define EXT_CLASS_P(CLASS) (reg_class_subset_p (CLASS, EXT_REGS))#define ADDR_CLASS_P(CLASS) (reg_class_subset_p (CLASS, ADDR_REGS))#define INDEX_CLASS_P(CLASS) (reg_class_subset_p (CLASS, INDEX_REGS))#define EXPENSIVE_CLASS_P(CLASS) (ADDR_CLASS_P(CLASS) \ || INDEX_CLASS_P(CLASS) || (CLASS) == SP_REG)/* Compute extra cost of moving data between one register class and another. */#define REGISTER_MOVE_COST(MODE, FROM, TO) 2/* Memory move cost is same as fast register move. Maybe this should be bumped up?. */#define MEMORY_MOVE_COST(M,C,I) 4/* Branches are kind of expensive (even with delayed branching) so make their cost higher. */#define BRANCH_COST 8#define WORD_REGISTER_OPERATIONS/* Dividing the Output into Sections. */#define TEXT_SECTION_ASM_OP "\t.text"#define DATA_SECTION_ASM_OP "\t.data"#define READONLY_DATA_SECTION_ASM_OP "\t.sect\t\".const\""/* Do not use .init section so __main will be called on startup. This will call __do_global_ctors and prepare for __do_global_dtors on exit. */#if 0#define INIT_SECTION_ASM_OP "\t.sect\t\".init\""#endif#define FINI_SECTION_ASM_OP "\t.sect\t\".fini\""#undef EXTRA_SECTIONS#define EXTRA_SECTIONS in_init, in_fini#undef EXTRA_SECTION_FUNCTIONS#define EXTRA_SECTION_FUNCTIONS \ INIT_SECTION_FUNCTION \ FINI_SECTION_FUNCTION#define INIT_SECTION_FUNCTION \extern void init_section (void); \void \init_section (void) \{ \ if (in_section != in_init) \ { \ fprintf (asm_out_file, ";\t.init\n"); \ in_section = in_init; \ } \}#define FINI_SECTION_FUNCTION \void \fini_section () \{ \ if (in_section != in_fini) \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -