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

📄 mn10300.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
  if (zero_dreg)    emit_move_insn (zero_dreg, const0_rtx);  if (zero_areg)    emit_move_insn (zero_areg, const0_rtx);}voidexpand_epilogue (){  unsigned int size;  /* SIZE includes the fixed stack space needed for function calls.  */  size = get_frame_size () + current_function_outgoing_args_size;  size += (current_function_outgoing_args_size ? 4 : 0);  /* Maybe cut back the stack, except for the register save area.     If the frame pointer exists, then use the frame pointer to     cut back the stack.     If the stack size + register save area is more than 255 bytes,     then the stack must be cut back here since the size + register     save size is too big for a ret/retf instruction.      Else leave it alone, it will be cut back as part of the     ret/retf instruction, or there wasn't any stack to begin with.     Under no circumstances should the register save area be     deallocated here, that would leave a window where an interrupt     could occur and trash the register save area.  */  if (frame_pointer_needed)    {      emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);      size = 0;    }  else if ((regs_ever_live[2] || regs_ever_live[3]	    || regs_ever_live[6] || regs_ever_live[7])	   && size + 16 > 255)    {      emit_insn (gen_addsi3 (stack_pointer_rtx,			     stack_pointer_rtx,			     GEN_INT (size)));      size = 0;    }  /* For simplicity, we just movm all the callee saved registers to     the stack with one instruction.     ?!? Only save registers which are actually used.  Reduces     stack requirements and is faster.  */  if (regs_ever_live[2] || regs_ever_live[3]      || regs_ever_live[6] || regs_ever_live[7]      || frame_pointer_needed)    emit_jump_insn (gen_return_internal_regs (GEN_INT (size + 16)));  else    {      if (size)	{	  emit_insn (gen_addsi3 (stack_pointer_rtx,				 stack_pointer_rtx,				 GEN_INT (size)));	  emit_jump_insn (gen_return_internal ());	}      else	{	  emit_jump_insn (gen_return ());	}    }}/* Update the condition code from the insn.  */voidnotice_update_cc (body, insn)     rtx body;     rtx insn;{  switch (get_attr_cc (insn))    {    case CC_NONE:      /* Insn does not affect CC at all.  */      break;    case CC_NONE_0HIT:      /* Insn does not change CC, but the 0'th operand has been changed.  */      if (cc_status.value1 != 0	  && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))	cc_status.value1 = 0;      break;    case CC_SET_ZN:      /* Insn sets the Z,N flags of CC to recog_operand[0].	 V,C are unusable.  */      CC_STATUS_INIT;      cc_status.flags |= CC_NO_CARRY | CC_OVERFLOW_UNUSABLE;      cc_status.value1 = recog_operand[0];      break;    case CC_SET_ZNV:      /* Insn sets the Z,N,V flags of CC to recog_operand[0].	 C is unusable.  */      CC_STATUS_INIT;      cc_status.flags |= CC_NO_CARRY;      cc_status.value1 = recog_operand[0];      break;    case CC_COMPARE:      /* The insn is a compare instruction.  */      CC_STATUS_INIT;      cc_status.value1 = SET_SRC (body);      break;    case CC_INVERT:      /* The insn is a compare instruction.  */      CC_STATUS_INIT;      cc_status.value1 = SET_SRC (body);      cc_status.flags |= CC_INVERTED;      break;    case CC_CLOBBER:      /* Insn doesn't leave CC in a usable state.  */      CC_STATUS_INIT;      break;    default:      abort ();    }}/* Return true if OP is a valid call operand.  */intcall_address_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);}/* What (if any) secondary registers are needed to move IN with mode   MODE into a register from in register class CLASS.    We might be able to simplify this.  */enum reg_classsecondary_reload_class (class, mode, in)     enum reg_class class;     enum machine_mode mode;     rtx in;{  int regno;  /* Memory loads less than a full word wide can't have an     address or stack pointer destination.  They must use     a data register as an intermediate register.  */  if (GET_CODE (in) == MEM      && (mode == QImode || mode == HImode)      && (class == ADDRESS_REGS || class == SP_REGS))    return DATA_REGS;  /* We can't directly load sp + const_int into a data register;     we must use an address register as an intermediate.  */  if (class != SP_REGS      && class != ADDRESS_REGS      && class != SP_OR_ADDRESS_REGS      && (in == stack_pointer_rtx	  || (GET_CODE (in) == PLUS	      && (XEXP (in, 0) == stack_pointer_rtx		  || XEXP (in, 1) == stack_pointer_rtx))))    return ADDRESS_REGS;  if (GET_CODE (in) == PLUS      && (XEXP (in, 0) == stack_pointer_rtx	  || XEXP (in, 1) == stack_pointer_rtx))    return DATA_REGS;   /* Otherwise assume no secondary reloads are needed.  */  return NO_REGS;}intinitial_offset (from, to)     int from, to;{  /* The difference between the argument pointer and the frame pointer     is the size of the callee register save area.  */  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)    {      if (regs_ever_live[2] || regs_ever_live[3]	  || regs_ever_live[6] || regs_ever_live[7]	  || frame_pointer_needed)	return 16;      else	return 0;    }  /* The difference between the argument pointer and the stack pointer is     the sum of the size of this function's frame, the callee register save     area, and the fixed stack space needed for function calls (if any).  */  if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)    {      if (regs_ever_live[2] || regs_ever_live[3]	  || regs_ever_live[6] || regs_ever_live[7]	  || frame_pointer_needed)	return (get_frame_size () + 16 		+ (current_function_outgoing_args_size		   ? current_function_outgoing_args_size + 4 : 0));       else	return (get_frame_size ()		+ (current_function_outgoing_args_size		   ? current_function_outgoing_args_size + 4 : 0));     }  /* The difference between the frame pointer and stack pointer is the sum     of the size of this function's frame and the fixed stack space needed     for function calls (if any).  */  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)    return (get_frame_size ()	    + (current_function_outgoing_args_size	       ? current_function_outgoing_args_size + 4 : 0));   abort ();}/* Flush the argument registers to the stack for a stdarg function;   return the new argument pointer.  */rtxmn10300_builtin_saveregs (arglist)     tree arglist;{  rtx offset;  tree fntype = TREE_TYPE (current_function_decl);  int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0                   && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))                       != void_type_node)))                ? UNITS_PER_WORD : 0);  if (argadj)    offset = plus_constant (current_function_arg_offset_rtx, argadj);  else    offset = current_function_arg_offset_rtx;  emit_move_insn (gen_rtx (MEM, SImode, current_function_internal_arg_pointer),		  gen_rtx (REG, SImode, 0));  emit_move_insn (gen_rtx (MEM, SImode,			   plus_constant			     (current_function_internal_arg_pointer, 4)),		  gen_rtx (REG, SImode, 1));  return copy_to_reg (expand_binop (Pmode, add_optab,				    current_function_internal_arg_pointer,				    offset, 0, 0, OPTAB_LIB_WIDEN));}/* Return an RTX to represent where a value with mode MODE will be returned   from a function.  If the result is 0, the argument is pushed.  */rtxfunction_arg (cum, mode, type, named)     CUMULATIVE_ARGS *cum;     enum machine_mode mode;     tree type;     int named;{  rtx result = 0;  int size, align;  /* We only support using 2 data registers as argument registers.  */  int nregs = 2;  /* Figure out the size of the object to be passed.  */  if (mode == BLKmode)    size = int_size_in_bytes (type);  else    size = GET_MODE_SIZE (mode);  /* Figure out the alignment of the object to be passed.  */  align = size;  cum->nbytes = (cum->nbytes + 3) & ~3;  /* Don't pass this arg via a register if all the argument registers     are used up.  */  if (cum->nbytes > nregs * UNITS_PER_WORD)    return 0;  /* Don't pass this arg via a register if it would be split between     registers and memory.  */  if (type == NULL_TREE      && cum->nbytes + size > nregs * UNITS_PER_WORD)    return 0;  switch (cum->nbytes / UNITS_PER_WORD)    {    case 0:      result = gen_rtx (REG, mode, 0);      break;    case 1:      result = gen_rtx (REG, mode, 1);      break;    default:      result = 0;    }  return result;}/* Return the number of registers to use for an argument passed partially   in registers and partially in memory.  */intfunction_arg_partial_nregs (cum, mode, type, named)     CUMULATIVE_ARGS *cum;     enum machine_mode mode;     tree type;     int named;{  int size, align;  /* We only support using 2 data registers as argument registers.  */  int nregs = 2;  /* Figure out the size of the object to be passed.  */  if (mode == BLKmode)    size = int_size_in_bytes (type);  else    size = GET_MODE_SIZE (mode);  /* Figure out the alignment of the object to be passed.  */  align = size;  cum->nbytes = (cum->nbytes + 3) & ~3;  /* Don't pass this arg via a register if all the argument registers     are used up.  */  if (cum->nbytes > nregs * UNITS_PER_WORD)    return 0;  if (cum->nbytes + size <= nregs * UNITS_PER_WORD)    return 0;  /* Don't pass this arg via a register if it would be split between     registers and memory.  */  if (type == NULL_TREE      && cum->nbytes + size > nregs * UNITS_PER_WORD)    return 0;  return (nregs * UNITS_PER_WORD - cum->nbytes) / UNITS_PER_WORD;}/* Output a tst insn.  */char *output_tst (operand, insn)     rtx operand, insn;{  rtx temp;  int past_call = 0;  /* If we have a data register which is known to be zero throughout     the function, then use it instead of doing a search.  */  if (zero_dreg && REGNO_REG_CLASS (REGNO (operand)) == DATA_REGS)    {      rtx xoperands[2];      xoperands[0] = operand;      xoperands[1] = zero_dreg;      output_asm_insn ("cmp %1,%0", xoperands);      return "";    }  /* Similarly for address registers.  */  if (zero_areg && REGNO_REG_CLASS (REGNO (operand)) == ADDRESS_REGS)    {      rtx xoperands[2];      xoperands[0] = operand;      xoperands[1] = zero_areg;      output_asm_insn ("cmp %1,%0", xoperands);      return "";    }  /* We can save a byte if we can find a register which has the value     zero in it.  */  temp = PREV_INSN (insn);  while (optimize && temp)    {      rtx set;      /* We allow the search to go through call insns.  We record	 the fact that we've past a CALL_INSN and reject matches which	 use call clobbered registers.  */      if (GET_CODE (temp) == CODE_LABEL	  || GET_CODE (temp) == JUMP_INSN	  || GET_CODE (temp) == BARRIER)	break;      if (GET_CODE (temp) == CALL_INSN)	past_call = 1;      if (GET_CODE (temp) == NOTE)	{	  temp = PREV_INSN (temp);	  continue;	}      /* It must be an insn, see if it is a simple set. */      set = single_set (temp);      if (!set)	{	  temp = PREV_INSN (temp);	  continue;	}      /* Are we setting a data register to zero (this does not win for	 address registers)? 	 If it's a call clobbered register, have we past a call?	 Make sure the register we find isn't the same as ourself;	 the mn10300 can't encode that.  */      if (REG_P (SET_DEST (set))	  && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set)))	  && !reg_set_between_p (SET_DEST (set), temp, insn)	  && (REGNO_REG_CLASS (REGNO (SET_DEST (set)))	      == REGNO_REG_CLASS (REGNO (operand)))	  && REGNO (SET_DEST (set)) != REGNO (operand)	  && (!past_call 	      || !call_used_regs[REGNO (SET_DEST (set))]))	{	  rtx xoperands[2];	  xoperands[0] = operand;	  xoperands[1] = SET_DEST (set);	  output_asm_insn ("cmp %1,%0", xoperands);	  return "";	}      temp = PREV_INSN (temp);    }  return "cmp 0,%0";}intimpossible_plus_operand (op, mode)     rtx op;     enum machine_mode mode;{  extern rtx *reg_equiv_mem;  rtx reg1, reg2;    if (GET_CODE (op) != PLUS)    return 0;  if (XEXP (op, 0) == stack_pointer_rtx      || XEXP (op, 1) == stack_pointer_rtx)    return 1;  return 0;}/* Return 1 if X contains a symbolic expression.  We know these   expressions will have one of a few well defined forms, so   we need only check those forms.  */intsymbolic_operand (op, mode)     register rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case SYMBOL_REF:    case LABEL_REF:      return 1;    case CONST:      op = XEXP (op, 0);      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF               || GET_CODE (XEXP (op, 0)) == LABEL_REF)              && GET_CODE (XEXP (op, 1)) == CONST_INT);    default:      return 0;    }}/* Try machine dependent ways of modifying an illegitimate address   to be legitimate.  If we find one, return the new valid address.   This macro is used in only one place: `memory_address' in explow.c.   OLDX is the address as it was before break_out_memory_refs was called.   In some cases it is useful to look at this to decide what needs to be done.   MODE and WIN are passed so that this macro can use   GO_IF_LEGITIMATE_ADDRESS.   Normally it is always safe for this macro to do nothing.  It exists to   recognize opportunities to optimize the output.   But on a few ports with segmented architectures and indexed addressing   (mn10300, hppa) it is used to rewrite certain problematical addresses.  */rtxlegitimize_address (x, oldx, mode)     rtx x;     rtx oldx;     enum machine_mode mode;{  /* Uh-oh.  We might have an address for x[n-100000].  This needs     special handling to avoid creating an indexed memory address     with x-100000 as the base.  */  if (GET_CODE (x) == PLUS      && symbolic_operand (XEXP (x, 1), VOIDmode))    {      /* Ugly.  We modify things here so that the address offset specified         by the index expression is computed first, then added to x to form         the entire address.  */      rtx regx1, regx2, regy1, regy2, y;      /* Strip off any CONST.  */      y = XEXP (x, 1);      if (GET_CODE (y) == CONST)        y = XEXP (y, 0);      if (GET_CODE (y) == PLUS || GET_CODE (y) == MINUS)	{	  regx1 = force_reg (Pmode, force_operand (XEXP (x, 0), 0));	  regy1 = force_reg (Pmode, force_operand (XEXP (y, 0), 0));	  regy2 = force_reg (Pmode, force_operand (XEXP (y, 1), 0));	  regx1 = force_reg (Pmode,			     gen_rtx (GET_CODE (y), Pmode, regx1, regy2));	  return force_reg (Pmode, gen_rtx (PLUS, Pmode, regx1, regy1));	}    }  return x;}

⌨️ 快捷键说明

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