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

📄 mmix.c

📁 gcc-you can use this code to learn something about gcc, and inquire further into linux,
💻 C
📖 第 1 页 / 共 5 页
字号:
    (-8     + (MMIX_CFUN_HAS_LANDING_PAD	? -16 : (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS ? -8 : 0)));}/* RETURN_ADDR_RTX.  */rtxmmix_return_addr_rtx (count, frame)     int count;     rtx frame ATTRIBUTE_UNUSED;{  return count == 0    ? (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS       /* FIXME: Set frame_alias_set on the following.  (Why?)	  See mmix_initial_elimination_offset for the reason we can't use	  get_hard_reg_initial_val for both.  Always using a stack slot	  and not a register would be suboptimal.  */       ? validize_mem (gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx, -16)))       : get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM))    : NULL_RTX;}/* SETUP_FRAME_ADDRESSES.  */voidmmix_setup_frame_addresses (){  /* Nothing needed at the moment.  */}/* The difference between the (imaginary) frame pointer and the stack   pointer.  Used to eliminate the frame pointer.  */intmmix_initial_elimination_offset (fromreg, toreg)     int fromreg;     int toreg;{  int regno;  int fp_sp_offset    = (get_frame_size () + current_function_outgoing_args_size + 7) & ~7;  /* There is no actual offset between these two virtual values, but for     the frame-pointer, we have the old one in the stack position below     it, so the offset for the frame-pointer to the stack-pointer is one     octabyte larger.  */  if (fromreg == MMIX_ARG_POINTER_REGNUM      && toreg == MMIX_FRAME_POINTER_REGNUM)    return 0;  /* The difference is the size of local variables plus the size of     outgoing function arguments that would normally be passed as     registers but must be passed on stack because we're out of     function-argument registers.  Only global saved registers are     counted; the others go on the register stack.     The frame-pointer is counted too if it is what is eliminated, as we     need to balance the offset for it from STARTING_FRAME_OFFSET.     Also add in the slot for the register stack pointer we save if we     have a landing pad.     Unfortunately, we can't access $0..$14, from unwinder code easily, so     store the return address in a frame slot too.  FIXME: Only for     non-leaf functions.  FIXME: Always with a landing pad, because it's     hard to know whether we need the other at the time we know we need     the offset for one (and have to state it).  It's a kludge until we     can express the register stack in the EH frame info.     We have to do alignment here; get_frame_size will not return a     multiple of STACK_BOUNDARY.  FIXME: Add note in manual.  */  for (regno = MMIX_FIRST_GLOBAL_REGNUM;       regno <= 255;       regno++)    if ((regs_ever_live[regno] && ! call_used_regs[regno])	|| IS_MMIX_EH_RETURN_DATA_REG (regno))      fp_sp_offset += 8;  return fp_sp_offset    + (MMIX_CFUN_HAS_LANDING_PAD       ? 16 : (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS ? 8 : 0))    + (fromreg == MMIX_ARG_POINTER_REGNUM ? 0 : 8);}/* Return an rtx for a function argument to go in a register, and 0 for   one that must go on stack.  */rtxmmix_function_arg (argsp, mode, type, named, incoming)     const CUMULATIVE_ARGS * argsp;     enum machine_mode mode;     tree type;     int named ATTRIBUTE_UNUSED;     int incoming;{  /* Last-argument marker.  */  if (type == void_type_node)    return (argsp->regs < MMIX_MAX_ARGS_IN_REGS)      ? gen_rtx_REG (mode,		     (incoming		      ? MMIX_FIRST_INCOMING_ARG_REGNUM		      : MMIX_FIRST_ARG_REGNUM) + argsp->regs)      : NULL_RTX;  return (argsp->regs < MMIX_MAX_ARGS_IN_REGS	  && !MUST_PASS_IN_STACK (mode, type)	  && (GET_MODE_BITSIZE (mode) <= 64	      || argsp->lib	      || TARGET_LIBFUNC))    ? gen_rtx_REG (mode,		   (incoming		    ? MMIX_FIRST_INCOMING_ARG_REGNUM		    : MMIX_FIRST_ARG_REGNUM)		   + argsp->regs)    : NULL_RTX;}/* Returns nonzero for everything that goes by reference, 0 for   everything that goes by value.  */intmmix_function_arg_pass_by_reference (argsp, mode, type, named)     const CUMULATIVE_ARGS * argsp;     enum machine_mode mode;     tree type;     int named ATTRIBUTE_UNUSED;{  /* FIXME: Check: I'm not sure the MUST_PASS_IN_STACK check is     necessary.  */  return    MUST_PASS_IN_STACK (mode, type)    || (MMIX_FUNCTION_ARG_SIZE (mode, type) > 8	&& !TARGET_LIBFUNC	&& !argsp->lib);}/* Return nonzero if regno is a register number where a parameter is   passed, and 0 otherwise.  */intmmix_function_arg_regno_p (regno, incoming)     int regno;     int incoming;{  int first_arg_regnum    = incoming ? MMIX_FIRST_INCOMING_ARG_REGNUM : MMIX_FIRST_ARG_REGNUM;  return regno >= first_arg_regnum    && regno < first_arg_regnum + MMIX_MAX_ARGS_IN_REGS;}/* FUNCTION_OUTGOING_VALUE.  */rtxmmix_function_outgoing_value (valtype, func)     tree valtype;     tree func ATTRIBUTE_UNUSED;{  enum machine_mode mode = TYPE_MODE (valtype);  enum machine_mode cmode;  int first_val_regnum = MMIX_OUTGOING_RETURN_VALUE_REGNUM;  rtx vec[MMIX_MAX_REGS_FOR_VALUE];  int i;  int nregs;  /* Return values that fit in a register need no special handling.     There's no register hole when parameters are passed in global     registers.  */  if (TARGET_ABI_GNU      || GET_MODE_BITSIZE (mode) <= BITS_PER_WORD)    return      gen_rtx_REG (mode, MMIX_OUTGOING_RETURN_VALUE_REGNUM);  /* A complex type, made up of components.  */  cmode = TYPE_MODE (TREE_TYPE (valtype));  nregs = ((GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD);  /* We need to take care of the effect of the register hole on return     values of large sizes; the last register will appear as the first     register, with the rest shifted.  (For complex modes, this is just     swapped registers.)  */  if (nregs > MMIX_MAX_REGS_FOR_VALUE)    internal_error ("too large function value type, needs %d registers,\ have only %d registers for this", nregs, MMIX_MAX_REGS_FOR_VALUE);  /* FIXME: Maybe we should handle structure values like this too     (adjusted for BLKmode), perhaps for both ABI:s.  */  for (i = 0; i < nregs - 1; i++)    vec[i]      = gen_rtx_EXPR_LIST (VOIDmode,			   gen_rtx_REG (cmode, first_val_regnum + i),			   GEN_INT ((i + 1) * BITS_PER_UNIT));  vec[nregs - 1]    = gen_rtx_EXPR_LIST (VOIDmode,			 gen_rtx_REG (cmode, first_val_regnum + nregs - 1),			 GEN_INT (0));  return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nregs, vec));}/* FUNCTION_VALUE_REGNO_P.  */intmmix_function_value_regno_p (regno)     int regno;{  return regno == MMIX_RETURN_VALUE_REGNUM;}/* EH_RETURN_DATA_REGNO. */intmmix_eh_return_data_regno (n)     int n ATTRIBUTE_UNUSED;{  if (n >= 0 && n < 4)    return MMIX_EH_RETURN_DATA_REGNO_START + n;  return INVALID_REGNUM;}/* EH_RETURN_STACKADJ_RTX. */rtxmmix_eh_return_stackadj_rtx (){  return gen_rtx_REG (Pmode, MMIX_EH_RETURN_STACKADJ_REGNUM);}/* EH_RETURN_HANDLER_RTX.  */rtxmmix_eh_return_handler_rtx (){  return    gen_rtx_REG (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);}/* ASM_PREFERRED_EH_DATA_FORMAT. */intmmix_asm_preferred_eh_data_format (code, global)     int code ATTRIBUTE_UNUSED;     int global ATTRIBUTE_UNUSED;{  /* This is the default (was at 2001-07-20).  Revisit when needed.  */  return DW_EH_PE_absptr;}/* Make a note that we've seen the beginning of the prologue.  This   matters to whether we'll translate register numbers as calculated by   mmix_machine_dependent_reorg.  */static voidmmix_target_asm_function_prologue (stream, framesize)     FILE *stream ATTRIBUTE_UNUSED;     HOST_WIDE_INT framesize ATTRIBUTE_UNUSED;{  cfun->machine->in_prologue = 1;}/* Make a note that we've seen the end of the prologue.  */static voidmmix_target_asm_function_end_prologue (stream)     FILE *stream ATTRIBUTE_UNUSED;{  cfun->machine->in_prologue = 0;}/* MACHINE_DEPENDENT_REORG.   No actual rearrangements done here; just virtually by calculating the   highest saved stack register number used to modify the register numbers   at output time.  */voidmmix_machine_dependent_reorg (first)     rtx first ATTRIBUTE_UNUSED;{  int regno;  /* We put the number of the highest saved register-file register in a     location convenient for the call-patterns to output.  Note that we     don't tell dwarf2 about these registers, since it can't restore them     anyway.  */  for (regno = MMIX_LAST_STACK_REGISTER_REGNUM;       regno >= 0;       regno--)    if ((regs_ever_live[regno] && !call_used_regs[regno])	|| (regno == MMIX_FRAME_POINTER_REGNUM && frame_pointer_needed))      break;  /* Regardless of whether they're saved (they might be just read), we     mustn't include registers that carry parameters.  We could scan the     insns to see whether they're actually used (and indeed do other less     trivial register usage analysis and transformations), but it seems     wasteful to optimize for unused parameter registers.  As of     2002-04-30, regs_ever_live[n] seems to be set for only-reads too, but     that might change.  */  if (!TARGET_ABI_GNU && regno < current_function_args_info.regs - 1)    {      regno = current_function_args_info.regs - 1;      /* We don't want to let this cause us to go over the limit and make	 incoming parameter registers be misnumbered and treating the last	 parameter register and incoming return value register call-saved.	 Stop things at the unmodified scheme.  */      if (regno > MMIX_RETURN_VALUE_REGNUM - 1)	regno = MMIX_RETURN_VALUE_REGNUM - 1;    }  cfun->machine->highest_saved_stack_register = regno;}/* TARGET_ASM_FUNCTION_EPILOGUE.  */static voidmmix_target_asm_function_epilogue (stream, locals_size)     FILE *stream;     HOST_WIDE_INT locals_size ATTRIBUTE_UNUSED;{  /* Emit an \n for readability of the generated assembly.  */  fputc ('\n', stream);}/* TARGET_ASM_OUTPUT_MI_THUNK.  */static voidmmix_asm_output_mi_thunk (stream, fndecl, delta, vcall_offset, func)     FILE * stream;     tree fndecl ATTRIBUTE_UNUSED;     HOST_WIDE_INT delta;     HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED;     tree func;{  /* If you define STRUCT_VALUE to 0, rather than use STRUCT_VALUE_REGNUM,     (i.e. pass location of structure to return as invisible first     argument) you need to tweak this code too.  */  const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM];  if (delta >= 0 && delta < 65536)    fprintf (stream, "\tINCL %s,%d\n", regname, (int)delta);  else if (delta < 0 && delta >= -255)    fprintf (stream, "\tSUBU %s,%s,%d\n", regname, regname, (int)-delta);  else    {      mmix_output_register_setting (stream, 255, delta, 1);      fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);    }  fprintf (stream, "\tJMP ");  assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));  fprintf (stream, "\n");}/* FUNCTION_PROFILER.  */voidmmix_function_profiler (stream, labelno)     FILE *stream ATTRIBUTE_UNUSED;     int labelno ATTRIBUTE_UNUSED;{  sorry ("function_profiler support for MMIX");}/* SETUP_INCOMING_VARARGS.  */voidmmix_setup_incoming_varargs (args_so_farp, mode, vartype, pretend_sizep,			     second_time)     CUMULATIVE_ARGS * args_so_farp;     enum machine_mode mode;     tree vartype;     int * pretend_sizep;     int second_time ATTRIBUTE_UNUSED;{  /* The last named variable has been handled, but     args_so_farp has not been advanced for it.  */  if (args_so_farp->regs + 1 < MMIX_MAX_ARGS_IN_REGS)    *pretend_sizep = (MMIX_MAX_ARGS_IN_REGS - (args_so_farp->regs + 1)) * 8;  /* We assume that one argument takes up one register here.  That should     be true until we start messing with multi-reg parameters.   */  if ((7 + (MMIX_FUNCTION_ARG_SIZE (mode, vartype))) / 8 != 1)    internal_error ("MMIX Internal: Last named vararg would not fit in a register");}/* EXPAND_BUILTIN_VA_ARG.  *//* This is modified from the "standard" implementation of va_arg: read the   value from the current (padded) address and increment by the (padded)   size.  The difference for MMIX is that if the type is   pass-by-reference, then perform an indirection.  */rtxmmix_expand_builtin_va_arg (valist, type)     tree valist;     tree type;{  tree ptr_size = size_int (BITS_PER_WORD / BITS_PER_UNIT);  tree addr_tree, type_size = NULL;  tree align, alignm1;  tree rounded_size;  rtx addr;  /* Compute the rounded size of the type.  */  /* Get AP.  */  addr_tree = valist;  align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);  alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);  if (type == error_mark_node      || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL      || TREE_OVERFLOW (type_size))    /* Presumably an error; the size isn't computable.  A message has       supposedly been emitted elsewhere.  */    rounded_size = size_zero_node;  else    rounded_size = fold (build (MULT_EXPR, sizetype,				fold (build (TRUNC_DIV_EXPR, sizetype,					     fold (build (PLUS_EXPR, sizetype,							  type_size, alignm1)),					     align)),				align)); if (AGGREGATE_TYPE_P (type)     && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) < 8     && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) != 0)   {     /* Adjust for big-endian the location of aggregates passed in a	register, but where the aggregate is accessed in a shorter mode	than the natural register mode (i.e. it is accessed as SFmode(?),	SImode, HImode or QImode rather than DImode or DFmode(?)).  FIXME:	Or should we adjust the mode in which the aggregate is read, to be	a register size mode?  (Hum, nah, a small offset is generally	cheaper than a wider memory access on MMIX.)  */     addr_tree       = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,		size_int ((BITS_PER_WORD / BITS_PER_UNIT)			  - GET_MODE_UNIT_SIZE (TYPE_MODE (type))));   } else if (!integer_zerop (rounded_size))   {     if (!really_constant_p (type_size))       /* Varying-size types come in by reference.  */       addr_tree	 = build1 (INDIRECT_REF, build_pointer_type (type), addr_tree);     else       {	 /* If the size is less than a register, then we need to pad the	    address by adding the difference.  */	 tree addend	   = fold (build (COND_EXPR, sizetype,

⌨️ 快捷键说明

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