📄 romp.h
字号:
No floating-point constants on ROMP. */#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0/* Optional extra constraints for this machine. For the ROMP, `Q' means that this is a memory operand but not a symbolic memory operand. Note that an unassigned pseudo register is such a memory operand. If register allocation has not been done, we reject pseudos, since we assume (hope) that they will get hard registers. `R' means that this is a constant pool reference to the current function. This is just r14 and so can be treated as a register. We bother with this just in move insns as that is the only place it is likely to occur. `S' means that this is the address of a constant pool location. This is equal to r14 plus a constant. We also only check for this in move insns. */#define EXTRA_CONSTRAINT(OP, C) \ ((C) == 'Q' ? \ ((GET_CODE (OP) == REG \ && REGNO (OP) >= FIRST_PSEUDO_REGISTER \ && reg_renumber != 0 \ && reg_renumber[REGNO (OP)] < 0) \ || (GET_CODE (OP) == MEM \ && ! symbolic_memory_operand (OP, VOIDmode))) \ : (C) == 'R' ? current_function_operand (OP, VOIDmode) \ : (C) == 'S' ? constant_pool_address_operand (OP, VOIDmode) \ : 0)/* Given an rtx X being reloaded into a reg required to be in class CLASS, return the class of reg to actually use. In general this is just CLASS; but on some machines in some cases it is preferable to use a more restrictive class. For the ROMP, if X is a memory reference that involves a symbol, we must use a BASE_REGS register instead of GENERAL_REGS to do the reload. The argument of MEM be either REG, PLUS, or SYMBOL_REF to be valid, so we assume that this is the case. Also, if X is an integer class, ensure that floating-point registers aren't used. */#define PREFERRED_RELOAD_CLASS(X,CLASS) \ ((CLASS) == FP_REGS && GET_MODE_CLASS (GET_MODE (X)) == MODE_INT \ ? GENERAL_REGS : \ (CLASS) != GENERAL_REGS ? (CLASS) : \ GET_CODE (X) != MEM ? GENERAL_REGS : \ GET_CODE (XEXP (X, 0)) == SYMBOL_REF ? BASE_REGS : \ GET_CODE (XEXP (X, 0)) == LABEL_REF ? BASE_REGS : \ GET_CODE (XEXP (X, 0)) == CONST ? BASE_REGS : \ GET_CODE (XEXP (X, 0)) == REG ? GENERAL_REGS : \ GET_CODE (XEXP (X, 0)) != PLUS ? GENERAL_REGS : \ GET_CODE (XEXP (XEXP (X, 0), 1)) == SYMBOL_REF ? BASE_REGS : \ GET_CODE (XEXP (XEXP (X, 0), 1)) == LABEL_REF ? BASE_REGS : \ GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST ? BASE_REGS : GENERAL_REGS)/* Return the register class of a scratch register needed to store into OUT from a register of class CLASS in MODE. On the ROMP, we cannot store into a symbolic memory address from an integer register; we need a BASE_REGS register as a scratch to do it. */#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, OUT) \ (GET_MODE_CLASS (MODE) == MODE_INT && symbolic_memory_operand (OUT, MODE) \ ? BASE_REGS : NO_REGS)/* Return the maximum number of consecutive registers needed to represent mode MODE in a register of class CLASS. On ROMP, this is the size of MODE in words, except in the FP regs, where a single reg is always enough. */#define CLASS_MAX_NREGS(CLASS, MODE) \ ((CLASS) == FP_REGS ? 1 \ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))/* Stack layout; function entry, exit and calling. *//* Define this if pushing a word on the stack makes the stack pointer a smaller address. */#define STACK_GROWS_DOWNWARD/* Define this 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/* Offset within stack frame to start allocating local variables at. If FRAME_GROWS_DOWNWARD, this is the offset to the END of the first local allocated. Otherwise, it is the offset to the BEGINNING of the first local allocated. On the ROMP, if we set the frame pointer to 15 words below the highest address of the highest local variable, the first 16 words will be addressable via D-short insns. */#define STARTING_FRAME_OFFSET 64/* If we generate an insn to push BYTES bytes, this says how many the stack pointer really advances by. On ROMP, don't define this because there are no push insns. *//* #define PUSH_ROUNDING(BYTES) *//* Offset of first parameter from the argument pointer register value. On the ROMP, we define the argument pointer to the start of the argument area. */#define FIRST_PARM_OFFSET(FNDECL) 0/* Define this if stack space is still allocated for a parameter passed in a register. The value is the number of bytes. */#define REG_PARM_STACK_SPACE(FNDECL) 16/* This is the difference between the logical top of stack and the actual sp. For the ROMP, sp points past the words allocated for the first four outgoing arguments (they are part of the callee's frame). */#define STACK_POINTER_OFFSET -16/* Define this if the maximum size of all the outgoing args is to be accumulated and pushed during the prologue. The amount can be found in the variable current_function_outgoing_args_size. */#define ACCUMULATE_OUTGOING_ARGS 1/* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. FUNDECL is the declaration node of the function (as a tree), FUNTYPE is the data type of the function (as a tree), or for a library call it is an identifier node for the subroutine name. SIZE is the number of bytes of arguments passed on the stack. */#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0/* Define how to find the value returned by a function. VALTYPE is the data type of the value (as a tree). If the precise function being called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0. On ROMP the value is found in r2, unless the machine specific option fp-arg-in-fpregs is selected, in which case FP return values are in fr1 */#define FUNCTION_VALUE(VALTYPE, FUNC) \ gen_rtx_REG (TYPE_MODE (VALTYPE), \ (TARGET_FP_REGS \ && GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT) \ ? 18 : 2)/* Define how to find the value returned by a library function assuming the value has mode MODE. */#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, 2)/* The definition of this macro implies that there are cases where a scalar value cannot be returned in registers. For the ROMP, if compatibility with HC is required, anything of type DImode is returned in memory. */#define RETURN_IN_MEMORY(type) \ (TYPE_MODE (type) == BLKmode \ || (TARGET_HC_STRUCT_RETURN && TYPE_MODE (type) == DImode))/* 1 if N is a possible register number for a function value as seen by the caller. On ROMP, r2 is the only register thus used unless fp values are to be returned in fp regs, in which case fr1 is also used. */#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || ((N) == 18 && TARGET_FP_REGS))/* 1 if N is a possible register number for function argument passing. On ROMP, these are r2-r5 (and fr1-fr4 if fp regs are used). */#define FUNCTION_ARG_REGNO_P(N) \ (((N) <= 5 && (N) >= 2) || (TARGET_FP_REGS && (N) > 17 && (N) < 21))/* Define a data type for recording info about an argument list during the scan of that argument list. This data type should hold all necessary information about the function itself and about the args processed so far, enough to enable macros such as FUNCTION_ARG to determine where the next arg should go. On the ROMP, this is a structure. The first word is the number of words of (integer only if -mfp-arg-in-fpregs is specified) arguments scanned so far (including the invisible argument, if any, which holds the structure-value-address). The second word hold the corresponding value for floating-point arguments, except that both single and double count as one register. */struct rt_cargs {int gregs, fregs; };#define CUMULATIVE_ARGS struct rt_cargs #define USE_FP_REG(MODE,CUM) \ (TARGET_FP_REGS && GET_MODE_CLASS (MODE) == MODE_FLOAT \ && (CUM).fregs < 3)/* Define intermediate macro to compute the size (in registers) of an argument for the ROMP. */#define ROMP_ARG_SIZE(MODE, TYPE, NAMED) \(! (NAMED) ? 0 \ : (MODE) != BLKmode \ ? (GET_MODE_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD \ : (int_size_in_bytes (TYPE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. On ROMP, the offset normally starts at 0, but starts at 4 bytes when the function gets a structure-value-address as an invisible first argument. */#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \ (CUM).gregs = 0, \ (CUM).fregs = 0/* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \{ if (NAMED) \ { \ if (USE_FP_REG(MODE, CUM)) \ (CUM).fregs++; \ else \ (CUM).gregs += ROMP_ARG_SIZE (MODE, TYPE, NAMED); \ } \}/* Determine where to put an argument to a function. Value is zero to push the argument on the stack, or a hard register in which to store the argument. MODE is the argument's machine mode. TYPE is the data type of the argument (as a tree). This is null for libcalls where that information may not be available. CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called. NAMED is nonzero if this argument is a named parameter (otherwise it is an extra parameter matching an ellipsis). On ROMP the first four words of args are normally in registers and the rest are pushed. */#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ (! (NAMED) ? 0 \ : ((TYPE) != 0 && TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST) ? 0 \ : USE_FP_REG(MODE,CUM) ? gen_rtx_REG ((MODE), (CUM).fregs + 17) \ : (CUM).gregs < 4 ? gen_rtx_REG ((MODE), 2 + (CUM).gregs) : 0)/* For an arg passed partly in registers and partly in memory, this is the number of registers used. For args passed entirely in registers or entirely in memory, zero. */#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ (! (NAMED) ? 0 \ : USE_FP_REG(MODE,CUM) ? 0 \ : (((CUM).gregs < 4 \ && 4 < ((CUM).gregs + ROMP_ARG_SIZE (MODE, TYPE, NAMED))) \ ? 4 - (CUM).gregs : 0))/* Perform any needed actions needed for a function that is receiving a variable number of arguments. CUM is as above. MODE and TYPE are the mode and type of the current parameter. PRETEND_SIZE is a variable that should be set to the amount of stack that must be pushed by the prolog to pretend that our caller pushed it. Normally, this macro will push all remaining incoming registers on the stack and set PRETEND_SIZE to the length of the registers pushed. */#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \{ if (TARGET_FP_REGS) \ error ("can't have varargs with -mfp-arg-in-fp-regs"); \ else if ((CUM).gregs < 4) \ { \ int first_reg_offset = (CUM).gregs; \ \ if (MUST_PASS_IN_STACK (MODE, TYPE)) \ first_reg_offset += ROMP_ARG_SIZE (TYPE_MODE (TYPE), TYPE, 1); \ \ if (first_reg_offset > 4) \ first_reg_offset = 4; \ \ if (! NO_RTL && first_reg_offset != 4) \ move_block_from_reg \ (2 + first_reg_offset, \ gen_rtx_MEM (BLKmode, \ plus_constant (virtual_incoming_args_rtx, \ first_reg_offset * 4)), \ 4 - first_reg_offset, (4 - first_reg_offset) * UNITS_PER_WORD); \ PRETEND_SIZE = (4 - first_reg_offset) * UNITS_PER_WORD; \ } \}/* This macro produces the initial definition of a function name. On the ROMP, we need to place an extra '.' in the function name. */#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \{ if (TREE_PUBLIC(DECL)) \ fprintf (FILE, "\t.globl _.%s\n", NAME); \ fprintf (FILE, "_.%s:\n", NAME); \}/* This macro is used to output the start of the data area. On the ROMP, the _name is a pointer to the data area. At that location is the address of _.name, which is really the name of the function. We need to set all this up here. The global declaration of the data area, if needed, is done in `assemble_function', where it thinks it is globalizing the function itself. */#define ASM_OUTPUT_POOL_PROLOGUE(FILE, NAME, DECL, SIZE) \{ extern int data_offset; \ data_section (); \ fprintf (FILE, "\t.align 2\n"); \ ASM_OUTPUT_LABEL (FILE, NAME); \ fprintf (FILE, "\t.long _.%s, 0, ", NAME); \ if (current_function_calls_alloca) \ fprintf (FILE, "0x%x\n", \ 0xf6900000 + current_function_outgoing_args_size); \ else \ fprintf (FILE, "0\n"); \ data_offset = ((SIZE) + 12 + 3) / 4; \}/* Output assembler code to FILE to increment profiler label # LABELNO for profiling a function entry. */#define FUNCTION_PROFILER(FILE, LABELNO) \ fprintf(FILE, "\tcas r0,r15,r0\n\tbali r15,mcount\n");/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, the stack pointer does not matter. The value is tested only in functions that have frame pointers. No definition is equivalent to always zero. *//* #define EXIT_IGNORE_STACK 1 *//* Output assembler code for a block containing the constant parts of a trampoline, leaving space for the variable parts. The trampoline should set the static chain pointer to value placed into the trampoline and should branch to the specified routine. On the ROMP, we have a problem. There are no free registers to use to construct the static chain and function addresses. Hence we use the following kludge: r15 (the return address) is first saved in mq. Then we use r15 to form the function address. We then branch to the function and restore r15 in the delay slot. This makes it appear that the function was called directly from the caller. (Note that the function address built is actually that of the data block. This is passed in r0 and the actual routine address is loaded into r15.) In addition, note that the address of the "called function", in this case the trampoline, is actually the address of the data area. So we need to make a fake data area that will contain the address of the trampoline. Note that this must be defined as two half-words, since the trampoline template (as opposed to the trampoline on the stack) is only half-word aligned. */#define TRAMPOLINE_TEMPLATE(FILE) \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -