explow.c

来自「GCC编译器源代码」· C语言 代码 · 共 1,396 行 · 第 1/3 页

C
1,396
字号
	 then we generate that address in a register	 and index off of it.  We do this because it often makes	 shorter code, and because the addresses thus generated	 in registers often become common subexpressions.  */      if (GET_CODE (x) == PLUS)	{	  rtx constant_term = const0_rtx;	  rtx y = eliminate_constant_term (x, &constant_term);	  if (constant_term == const0_rtx	      || ! memory_address_p (mode, y))	    x = force_operand (x, NULL_RTX);	  else	    {	      y = gen_rtx (PLUS, GET_MODE (x), copy_to_reg (y), constant_term);	      if (! memory_address_p (mode, y))		x = force_operand (x, NULL_RTX);	      else		x = y;	    }	}      else if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS)	x = force_operand (x, NULL_RTX);      /* If we have a register that's an invalid address,	 it must be a hard reg of the wrong class.  Copy it to a pseudo.  */      else if (GET_CODE (x) == REG)	x = copy_to_reg (x);      /* Last resort: copy the value to a register, since	 the register is a valid address.  */      else	x = force_reg (Pmode, x);      goto done;    win2:      x = oldx;    win:      if (flag_force_addr && ! cse_not_expected && GET_CODE (x) != REG	  /* Don't copy an addr via a reg if it is one of our stack slots.  */	  && ! (GET_CODE (x) == PLUS		&& (XEXP (x, 0) == virtual_stack_vars_rtx		    || XEXP (x, 0) == virtual_incoming_args_rtx)))	{	  if (general_operand (x, Pmode))	    x = force_reg (Pmode, x);	  else	    x = force_operand (x, NULL_RTX);	}    } done:  /* If we didn't change the address, we are done.  Otherwise, mark     a reg as a pointer if we have REG or REG + CONST_INT.  */  if (oldx == x)    return x;  else if (GET_CODE (x) == REG)    mark_reg_pointer (x, 1);  else if (GET_CODE (x) == PLUS	   && GET_CODE (XEXP (x, 0)) == REG	   && GET_CODE (XEXP (x, 1)) == CONST_INT)    mark_reg_pointer (XEXP (x, 0), 1);  /* OLDX may have been the address on a temporary.  Update the address     to indicate that X is now used.  */  update_temp_slot_address (oldx, x);  return x;}/* Like `memory_address' but pretend `flag_force_addr' is 0.  */rtxmemory_address_noforce (mode, x)     enum machine_mode mode;     rtx x;{  int ambient_force_addr = flag_force_addr;  rtx val;  flag_force_addr = 0;  val = memory_address (mode, x);  flag_force_addr = ambient_force_addr;  return val;}/* Convert a mem ref into one with a valid memory address.   Pass through anything else unchanged.  */rtxvalidize_mem (ref)     rtx ref;{  if (GET_CODE (ref) != MEM)    return ref;  if (memory_address_p (GET_MODE (ref), XEXP (ref, 0)))    return ref;  /* Don't alter REF itself, since that is probably a stack slot.  */  return change_address (ref, GET_MODE (ref), XEXP (ref, 0));}/* Return a modified copy of X with its memory address copied   into a temporary register to protect it from side effects.   If X is not a MEM, it is returned unchanged (and not copied).   Perhaps even if it is a MEM, if there is no need to change it.  */rtxstabilize (x)     rtx x;{  register rtx addr;  if (GET_CODE (x) != MEM)    return x;  addr = XEXP (x, 0);  if (rtx_unstable_p (addr))    {      rtx temp = copy_all_regs (addr);      rtx mem;      if (GET_CODE (temp) != REG)	temp = copy_to_reg (temp);      mem = gen_rtx (MEM, GET_MODE (x), temp);      /* Mark returned memref with in_struct if it's in an array or	 structure.  Copy const and volatile from original memref.  */      MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (x) || GET_CODE (addr) == PLUS;      RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (x);      MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (x);      return mem;    }  return x;}/* Copy the value or contents of X to a new temp reg and return that reg.  */rtxcopy_to_reg (x)     rtx x;{  register rtx temp = gen_reg_rtx (GET_MODE (x));   /* If not an operand, must be an address with PLUS and MULT so     do the computation.  */   if (! general_operand (x, VOIDmode))    x = force_operand (x, temp);    if (x != temp)    emit_move_insn (temp, x);  return temp;}/* Like copy_to_reg but always give the new register mode Pmode   in case X is a constant.  */rtxcopy_addr_to_reg (x)     rtx x;{  return copy_to_mode_reg (Pmode, x);}/* Like copy_to_reg but always give the new register mode MODE   in case X is a constant.  */rtxcopy_to_mode_reg (mode, x)     enum machine_mode mode;     rtx x;{  register rtx temp = gen_reg_rtx (mode);    /* If not an operand, must be an address with PLUS and MULT so     do the computation.  */   if (! general_operand (x, VOIDmode))    x = force_operand (x, temp);  if (GET_MODE (x) != mode && GET_MODE (x) != VOIDmode)    abort ();  if (x != temp)    emit_move_insn (temp, x);  return temp;}/* Load X into a register if it is not already one.   Use mode MODE for the register.   X should be valid for mode MODE, but it may be a constant which   is valid for all integer modes; that's why caller must specify MODE.   The caller must not alter the value in the register we return,   since we mark it as a "constant" register.  */rtxforce_reg (mode, x)     enum machine_mode mode;     rtx x;{  register rtx temp, insn, set;  if (GET_CODE (x) == REG)    return x;  temp = gen_reg_rtx (mode);  insn = emit_move_insn (temp, x);  /* Let optimizers know that TEMP's value never changes     and that X can be substituted for it.  Don't get confused     if INSN set something else (such as a SUBREG of TEMP).  */  if (CONSTANT_P (x)      && (set = single_set (insn)) != 0      && SET_DEST (set) == temp)    {      rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);      if (note)	XEXP (note, 0) = x;      else	REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, x, REG_NOTES (insn));    }  return temp;}/* If X is a memory ref, copy its contents to a new temp reg and return   that reg.  Otherwise, return X.  */rtxforce_not_mem (x)     rtx x;{  register rtx temp;  if (GET_CODE (x) != MEM || GET_MODE (x) == BLKmode)    return x;  temp = gen_reg_rtx (GET_MODE (x));  emit_move_insn (temp, x);  return temp;}/* Copy X to TARGET (if it's nonzero and a reg)   or to a new temp reg and return that reg.   MODE is the mode to use for X in case it is a constant.  */rtxcopy_to_suggested_reg (x, target, mode)     rtx x, target;     enum machine_mode mode;{  register rtx temp;  if (target && GET_CODE (target) == REG)    temp = target;  else    temp = gen_reg_rtx (mode);  emit_move_insn (temp, x);  return temp;}/* Return the mode to use to store a scalar of TYPE and MODE.   PUNSIGNEDP points to the signedness of the type and may be adjusted   to show what signedness to use on extension operations.   FOR_CALL is non-zero if this call is promoting args for a call.  */enum machine_modepromote_mode (type, mode, punsignedp, for_call)     tree type;     enum machine_mode mode;     int *punsignedp;     int for_call;{  enum tree_code code = TREE_CODE (type);  int unsignedp = *punsignedp;#ifdef PROMOTE_FOR_CALL_ONLY  if (! for_call)    return mode;#endif  switch (code)    {#ifdef PROMOTE_MODE    case INTEGER_TYPE:   case ENUMERAL_TYPE:   case BOOLEAN_TYPE:    case CHAR_TYPE:      case REAL_TYPE:       case OFFSET_TYPE:      PROMOTE_MODE (mode, unsignedp, type);      break;#endif#ifdef POINTERS_EXTEND_UNSIGNED    case REFERENCE_TYPE:    case POINTER_TYPE:      mode = Pmode;      unsignedp = POINTERS_EXTEND_UNSIGNED;      break;#endif          default:      break;    }  *punsignedp = unsignedp;  return mode;}/* Adjust the stack pointer by ADJUST (an rtx for a number of bytes).   This pops when ADJUST is positive.  ADJUST need not be constant.  */voidadjust_stack (adjust)     rtx adjust;{  rtx temp;  adjust = protect_from_queue (adjust, 0);  if (adjust == const0_rtx)    return;  temp = expand_binop (Pmode,#ifdef STACK_GROWS_DOWNWARD		       add_optab,#else		       sub_optab,#endif		       stack_pointer_rtx, adjust, stack_pointer_rtx, 0,		       OPTAB_LIB_WIDEN);  if (temp != stack_pointer_rtx)    emit_move_insn (stack_pointer_rtx, temp);}/* Adjust the stack pointer by minus ADJUST (an rtx for a number of bytes).   This pushes when ADJUST is positive.  ADJUST need not be constant.  */voidanti_adjust_stack (adjust)     rtx adjust;{  rtx temp;  adjust = protect_from_queue (adjust, 0);  if (adjust == const0_rtx)    return;  temp = expand_binop (Pmode,#ifdef STACK_GROWS_DOWNWARD		       sub_optab,#else		       add_optab,#endif		       stack_pointer_rtx, adjust, stack_pointer_rtx, 0,		       OPTAB_LIB_WIDEN);  if (temp != stack_pointer_rtx)    emit_move_insn (stack_pointer_rtx, temp);}/* Round the size of a block to be pushed up to the boundary required   by this machine.  SIZE is the desired size, which need not be constant.  */rtxround_push (size)     rtx size;{#ifdef STACK_BOUNDARY  int align = STACK_BOUNDARY / BITS_PER_UNIT;  if (align == 1)    return size;  if (GET_CODE (size) == CONST_INT)    {      int new = (INTVAL (size) + align - 1) / align * align;      if (INTVAL (size) != new)	size = GEN_INT (new);    }  else    {      /* CEIL_DIV_EXPR needs to worry about the addition overflowing,	 but we know it can't.  So add ourselves and then do	 TRUNC_DIV_EXPR.  */      size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1),			   NULL_RTX, 1, OPTAB_LIB_WIDEN);      size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align),			    NULL_RTX, 1);      size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1);    }#endif /* STACK_BOUNDARY */  return size;}/* Save the stack pointer for the purpose in SAVE_LEVEL.  PSAVE is a pointer   to a previously-created save area.  If no save area has been allocated,   this function will allocate one.  If a save area is specified, it   must be of the proper mode.   The insns are emitted after insn AFTER, if nonzero, otherwise the insns   are emitted at the current position.  */voidemit_stack_save (save_level, psave, after)     enum save_level save_level;     rtx *psave;     rtx after;{  rtx sa = *psave;  /* The default is that we use a move insn and save in a Pmode object.  */  rtx (*fcn) () = gen_move_insn;  enum machine_mode mode = Pmode;  /* See if this machine has anything special to do for this kind of save.  */  switch (save_level)    {#ifdef HAVE_save_stack_block    case SAVE_BLOCK:      if (HAVE_save_stack_block)	{	  fcn = gen_save_stack_block;	  mode = insn_operand_mode[CODE_FOR_save_stack_block][0];	}      break;#endif#ifdef HAVE_save_stack_function    case SAVE_FUNCTION:      if (HAVE_save_stack_function)	{	  fcn = gen_save_stack_function;	  mode = insn_operand_mode[CODE_FOR_save_stack_function][0];	}      break;#endif#ifdef HAVE_save_stack_nonlocal    case SAVE_NONLOCAL:      if (HAVE_save_stack_nonlocal)	{	  fcn = gen_save_stack_nonlocal;	  mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0];	}      break;#endif    default:      break;    }  /* If there is no save area and we have to allocate one, do so.  Otherwise     verify the save area is the proper mode.  */  if (sa == 0)    {      if (mode != VOIDmode)	{	  if (save_level == SAVE_NONLOCAL)	    *psave = sa = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);	  else	    *psave = sa = gen_reg_rtx (mode);	}    }  else    {      if (mode == VOIDmode || GET_MODE (sa) != mode)	abort ();    }  if (after)    {      rtx seq;      start_sequence ();      /* We must validize inside the sequence, to ensure that any instructions

⌨️ 快捷键说明

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