⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 romp.h

📁 gcc-2.95.3 Linux下最常用的C编译器
💻 H
📖 第 1 页 / 共 5 页
字号:
   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;				\}/* Select section for constant in constant pool.   On ROMP, all constants are in the data area.  */#define SELECT_RTX_SECTION(MODE, X)	data_section ()/* This macro generates the assembly code for function entry.   FILE is a stdio stream to output the code to.   SIZE is an int: how many units of temporary storage to allocate.   Refer to the array `regs_ever_live' to determine which registers   to save; `regs_ever_live[I]' is nonzero if register number I   is ever used in the function.  This macro is responsible for   knowing which registers should not be saved even if used.  */#define FUNCTION_PROLOGUE(FILE, SIZE) output_prolog (FILE, SIZE)/* 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	*//* This macro generates the assembly code for function exit,   on machines that need it.  If FUNCTION_EPILOGUE is not defined   then individual return instructions are generated for each   return statement.  Args are same as for FUNCTION_PROLOGUE.   The function epilogue should not depend on the current stack pointer!   It should use the frame pointer only.  This is mandatory because   of alloca; we also take advantage of it to omit stack adjustments   before returning.  */#define FUNCTION_EPILOGUE(FILE, SIZE) output_epilog (FILE, SIZE)/* 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)	\{					\  fprintf (FILE, "\t.short 0,0\n");	\  fprintf (FILE, "\tcau r0,0(r0)\n");	\  fprintf (FILE, "\toil r0,r0,0\n");	\  fprintf (FILE, "\tmts r10,r15\n");	\  fprintf (FILE, "\tst r0,-36(r1)\n");	\  fprintf (FILE, "\tcau r15,0(r0)\n");	\  fprintf (FILE, "\toil r15,r15,0\n");	\  fprintf (FILE, "\tcas r0,r15,r0\n");	\  fprintf (FILE, "\tls r15,0(r15)\n");	\  fprintf (FILE, "\tbrx r15\n");	\  fprintf (FILE, "\tmfs r10,r15\n");	\}/* Length in units of the trampoline for entering a nested function.  */#define TRAMPOLINE_SIZE    36/* Emit RTL insns to initialize the variable parts of a trampoline.   FNADDR is an RTX for the address of the function's pure code.   CXT is an RTX for the static chain value for the function.   On the RT, the static chain and function addresses are written in   two 16-bit sections.   We also need to write the address of the first instruction in   the trampoline into the first word of the trampoline to simulate a   data area.  */#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, CXT)		\{								\  rtx _addr, _temp;						\  rtx _val;							\								\  _temp = expand_binop (SImode, add_optab, ADDR,		\			GEN_INT (4),				\			0, 1, OPTAB_LIB_WIDEN);			\  emit_move_insn (gen_rtx (MEM, SImode,				\			   memory_address (SImode, ADDR)), _temp); \								\  _val = force_reg (SImode, CXT);				\  _addr = memory_address (HImode, plus_constant (ADDR, 10));	\  emit_move_insn (gen_rtx (MEM, HImode, _addr),			\		  gen_lowpart (HImode, _val));			\  _temp = expand_shift (RSHIFT_EXPR, SImode, _val,		\			build_int_2 (16, 0), 0, 1);		\  _addr = memory_address (HImode, plus_constant (ADDR, 6));	\  emit_move_insn (gen_rtx (MEM, HImode, _addr),			\		  gen_lowpart (HImode, _temp));			\								\  _val = force_reg (SImode, FNADDR);				\  _addr = memory_address (HImode, plus_constant (ADDR, 24));	\  emit_move_insn (gen_rtx (MEM, HImode, _addr),			\		  gen_lowpart (HImode, _val));			\  _temp = expand_shift (RSHIFT_EXPR, SImode, _val,		\			build_int_2 (16, 0), 0, 1);		\  _addr = memory_address (HImode, plus_constant (ADDR, 20));	\  emit_move_insn (gen_rtx (MEM, HImode, _addr),			\		  gen_lowpart (HImode, _temp));			\								\}/* Definitions for register eliminations.   We have two registers that can be eliminated on the ROMP.  First, the   frame pointer register can often be eliminated in favor of the stack   pointer register.  Secondly, the argument pointer register can always be   eliminated; it is replaced with either the stack or frame pointer.   In addition, we use the elimination mechanism to see if r14 is needed.   Initially we assume that it isn't.  If it is, we spill it.  This is done   by making it an eliminable register.  It doesn't matter what we replace   it with, since it will never occur in the rtl at this point.  *//* This is an array of structures.  Each structure initializes one pair   of eliminable registers.  The "from" register number is given first,   followed by "to".  Eliminations of the same "from" register are listed   in order of preference.  */#define ELIMINABLE_REGS				\{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},	\ { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},	\ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},	\ { 14, 0}}/* Given FROM and TO register numbers, say whether this elimination is allowed.   Frame pointer elimination is automatically handled.   For the ROMP, if frame pointer elimination is being done, we would like to   convert ap into fp, not sp.   We need r14 if various conditions (tested in romp_using_r14) are true.   All other eliminations are valid.  */#define CAN_ELIMINATE(FROM, TO)					\ ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM	\  ? ! frame_pointer_needed					\  : (FROM) == 14 ? ! romp_using_r14 ()				\  : 1)/* Define the offset between two registers, one to be eliminated, and the other   its replacement, at the start of a routine.  */#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			\{ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)	\    {									\      if (romp_pushes_stack ())						\	(OFFSET) = ((get_frame_size () - 64)				\		    + current_function_outgoing_args_size);		\      else								\	(OFFSET) = - (romp_sa_size () + 64);				\    }									\  else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \    (OFFSET) = romp_sa_size () - 16 + 64;				\  else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \    {									\      if (romp_pushes_stack ())						\	(OFFSET) = (get_frame_size () + (romp_sa_size () - 16)		\		    + current_function_outgoing_args_size);		\      else								\	(OFFSET) = -16;							\    }									\  else if ((FROM) == 14)						\    (OFFSET) = 0;							\  else									\    abort ();								\}/* Addressing modes, and classification of registers for them.  *//* #define HAVE_POST_INCREMENT 0 *//* #define HAVE_POST_DECREMENT 0 *//* #define HAVE_PRE_DECREMENT 0 *//* #define HAVE_PRE_INCREMENT 0 *//* Macros to check register numbers against specific register classes.  *//* 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_INDEX_P(REGNO) 0#define REGNO_OK_FOR_BASE_P(REGNO)				\((REGNO) < FIRST_PSEUDO_REGISTER				\ ? (REGNO) < 16 && (REGNO) != 0 && (REGNO) != 16		\ : (reg_renumber[REGNO] < 16 && reg_renumber[REGNO] >= 0	\    && reg_renumber[REGNO] != 16))/* Maximum number of registers that can appear in a valid memory address.  */#define MAX_REGS_PER_ADDRESS 1/* Recognize any constant value that is a valid address.  */#define CONSTANT_ADDRESS_P(X)   \  (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF		\   || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST		\   || GET_CODE (X) == HIGH)/* Nonzero if the constant value X is a legitimate general operand.   It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.   On the ROMP, there is a bit of a hack here.  Basically, we wish to   only issue instructions that are not `as' macros.  However, in the   case of `get', `load', and `store', if the operand is a relocatable   symbol (possibly +/- an integer), there is no way to express the   resulting split-relocation except with the macro.  Therefore, allow   either a constant valid in a normal (sign-extended) D-format insn or   a relocatable expression.   Also, for DFmode and DImode, we must ensure that both words are   addressable.   We define two macros: The first is given an offset (0 or 4) and indicates   that the operand is a CONST_INT that is valid for that offset.  The second   indicates a valid non-CONST_INT constant.  */#define LEGITIMATE_ADDRESS_INTEGER_P(X,OFFSET)				\  (GET_CODE (X) == CONST_INT						\   && (unsigned) (INTVAL (X) + (OFFSET) + 0x8000) < 0x10000)#define LEGITIMATE_ADDRESS_CONSTANT_P(X)				\ (GET_CODE (X) == SYMBOL_REF						\  || GET_CODE (X) == LABEL_REF						\  || (GET_CODE (X) == CONST						\      && (GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF		\          || GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF)		\      && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))/* Include all constant integers and constant double, but exclude    SYMBOL_REFs that are to be obtained from the data area (see below).  */#define LEGITIMATE_CONSTANT_P(X)		\  ((LEGITIMATE_ADDRESS_CONSTANT_P (X)		\    || GET_CODE (X) == CONST_INT		\    || GET_CODE (X) == CONST_DOUBLE)		\   && ! (GET_CODE (X) == SYMBOL_REF && SYMBOL_REF_FLAG (X)))/* For no good reason, we do the same as the other RT compilers and load   the addresses of data areas for a function from our data area.  That means   that we need to mark such SYMBOL_REFs.  We do so here.  */#define ENCODE_SECTION_INFO(DECL)			\  if (TREE_CODE (TREE_TYPE (DECL)) == FUNCTION_TYPE)	\    SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -