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

📄 expr.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
  rtx source_reg, target;  int i;  if (GET_CODE (y) != PARALLEL)    abort ();  /* Check for a NULL entry, used to indicate that the parameter goes     both on the stack and in registers.  */  if (XEXP (XVECEXP (y, 0, 0), 0))    i = 0;  else    i = 1;  for (; i < XVECLEN (y, 0); i++)    {      rtx element = XVECEXP (y, 0, i);      source_reg = XEXP (element, 0);      if (GET_CODE (x) == MEM)	target = change_address (x, GET_MODE (source_reg),				 plus_constant (XEXP (x, 0),						INTVAL (XEXP (element, 1))));      else if (XEXP (element, 1) == const0_rtx)	{	  target = x;	  if (GET_MODE (target) != GET_MODE (source_reg))	    target = gen_lowpart (GET_MODE (source_reg), target);	}      else	abort ();      emit_move_insn (target, source_reg);    }}/* Add a USE expression for REG to the (possibly empty) list pointed   to by CALL_FUSAGE.  REG must denote a hard register.  */voiduse_reg (call_fusage, reg)     rtx *call_fusage, reg;{  if (GET_CODE (reg) != REG      || REGNO (reg) >= FIRST_PSEUDO_REGISTER)    abort();  *call_fusage    = gen_rtx (EXPR_LIST, VOIDmode,	       gen_rtx (USE, VOIDmode, reg), *call_fusage);}/* Add USE expressions to *CALL_FUSAGE for each of NREGS consecutive regs,   starting at REGNO.  All of these registers must be hard registers.  */voiduse_regs (call_fusage, regno, nregs)     rtx *call_fusage;     int regno;     int nregs;{  int i;  if (regno + nregs > FIRST_PSEUDO_REGISTER)    abort ();  for (i = 0; i < nregs; i++)    use_reg (call_fusage, gen_rtx (REG, reg_raw_mode[regno + i], regno + i));}/* Add USE expressions to *CALL_FUSAGE for each REG contained in the   PARALLEL REGS.  This is for calls that pass values in multiple   non-contiguous locations.  The Irix 6 ABI has examples of this.  */voiduse_group_regs (call_fusage, regs)     rtx *call_fusage;     rtx regs;{  int i;  for (i = 0; i < XVECLEN (regs, 0); i++)    {      rtx reg = XEXP (XVECEXP (regs, 0, i), 0);      /* A NULL entry means the parameter goes both on the stack and in	 registers.  This can also be a MEM for targets that pass values	 partially on the stack and partially in registers.  */      if (reg != 0 && GET_CODE (reg) == REG)	use_reg (call_fusage, reg);    }}/* Generate several move instructions to clear LEN bytes of block TO.   (A MEM rtx with BLKmode).   The caller must pass TO through   protect_from_queue before calling. ALIGN (in bytes) is maximum alignment   we can assume.  */static voidclear_by_pieces (to, len, align)     rtx to;     int len, align;{  struct clear_by_pieces data;  rtx to_addr = XEXP (to, 0);  int max_size = MOVE_MAX + 1;  data.offset = 0;  data.to_addr = to_addr;  data.to = to;  data.autinc_to    = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC       || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);  data.explicit_inc_to = 0;  data.reverse    = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);  if (data.reverse) data.offset = len;  data.len = len;  data.to_struct = MEM_IN_STRUCT_P (to);  /* If copying requires more than two move insns,     copy addresses to registers (to make displacements shorter)     and use post-increment if available.  */  if (!data.autinc_to      && move_by_pieces_ninsns (len, align) > 2)    {#ifdef HAVE_PRE_DECREMENT      if (data.reverse && ! data.autinc_to)	{	  data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));	  data.autinc_to = 1;	  data.explicit_inc_to = -1;	}#endif#ifdef HAVE_POST_INCREMENT      if (! data.reverse && ! data.autinc_to)	{	  data.to_addr = copy_addr_to_reg (to_addr);	  data.autinc_to = 1;	  data.explicit_inc_to = 1;	}#endif      if (!data.autinc_to && CONSTANT_P (to_addr))	data.to_addr = copy_addr_to_reg (to_addr);    }  if (! SLOW_UNALIGNED_ACCESS      || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)    align = MOVE_MAX;  /* First move what we can in the largest integer mode, then go to     successively smaller modes.  */  while (max_size > 1)    {      enum machine_mode mode = VOIDmode, tmode;      enum insn_code icode;      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);	   tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))	if (GET_MODE_SIZE (tmode) < max_size)	  mode = tmode;      if (mode == VOIDmode)	break;      icode = mov_optab->handlers[(int) mode].insn_code;      if (icode != CODE_FOR_nothing	  && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,			   GET_MODE_SIZE (mode)))	clear_by_pieces_1 (GEN_FCN (icode), mode, &data);      max_size = GET_MODE_SIZE (mode);    }  /* The code above should have handled everything.  */  if (data.len != 0)    abort ();}/* Subroutine of clear_by_pieces.  Clear as many bytes as appropriate   with move instructions for mode MODE.  GENFUN is the gen_... function   to make a move insn for that mode.  DATA has all the other info.  */static voidclear_by_pieces_1 (genfun, mode, data)     rtx (*genfun) ();     enum machine_mode mode;     struct clear_by_pieces *data;{  register int size = GET_MODE_SIZE (mode);  register rtx to1;  while (data->len >= size)    {      if (data->reverse) data->offset -= size;      to1 = (data->autinc_to	     ? gen_rtx (MEM, mode, data->to_addr)	     : copy_rtx (change_address (data->to, mode,					 plus_constant (data->to_addr,							data->offset))));      MEM_IN_STRUCT_P (to1) = data->to_struct;#ifdef HAVE_PRE_DECREMENT      if (data->explicit_inc_to < 0)	emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));#endif      emit_insn ((*genfun) (to1, const0_rtx));#ifdef HAVE_POST_INCREMENT      if (data->explicit_inc_to > 0)	emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));#endif      if (! data->reverse) data->offset += size;      data->len -= size;    }}/* Write zeros through the storage of OBJECT.   If OBJECT has BLKmode, SIZE is its length in bytes and ALIGN is   the maximum alignment we can is has, measured in bytes.   If we call a function that returns the length of the block, return it.  */rtxclear_storage (object, size, align)     rtx object;     rtx size;     int align;{  rtx retval = 0;  if (GET_MODE (object) == BLKmode)    {      object = protect_from_queue (object, 1);      size = protect_from_queue (size, 0);      if (GET_CODE (size) == CONST_INT	  && (move_by_pieces_ninsns (INTVAL (size), align) < MOVE_RATIO))	clear_by_pieces (object, INTVAL (size), align);      else	{	  /* Try the most limited insn first, because there's no point	     including more than one in the machine description unless	     the more limited one has some advantage.  */	  rtx opalign = GEN_INT (align);	  enum machine_mode mode;	  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;	       mode = GET_MODE_WIDER_MODE (mode))	    {	      enum insn_code code = clrstr_optab[(int) mode];	      if (code != CODE_FOR_nothing		  /* We don't need MODE to be narrower than		     BITS_PER_HOST_WIDE_INT here because if SIZE is less than		     the mode mask, as it is returned by the macro, it will		     definitely be less than the actual mode mask.  */		  && ((GET_CODE (size) == CONST_INT		       && ((unsigned HOST_WIDE_INT) INTVAL (size)			   <= GET_MODE_MASK (mode)))		      || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)		  && (insn_operand_predicate[(int) code][0] == 0		      || (*insn_operand_predicate[(int) code][0]) (object,								   BLKmode))		  && (insn_operand_predicate[(int) code][2] == 0		      || (*insn_operand_predicate[(int) code][2]) (opalign,								   VOIDmode)))		{		  rtx op1;		  rtx last = get_last_insn ();		  rtx pat;		  op1 = convert_to_mode (mode, size, 1);		  if (insn_operand_predicate[(int) code][1] != 0		      && ! (*insn_operand_predicate[(int) code][1]) (op1,								     mode))		    op1 = copy_to_mode_reg (mode, op1);		  pat = GEN_FCN ((int) code) (object, op1, opalign);		  if (pat)		    {		      emit_insn (pat);		      return 0;		    }		  else		    delete_insns_since (last);		}	    }#ifdef TARGET_MEM_FUNCTIONS	  retval	    = emit_library_call_value (memset_libfunc, NULL_RTX, 0,				       ptr_mode, 3,				       XEXP (object, 0), Pmode,				       const0_rtx,				       TYPE_MODE (integer_type_node),				       convert_to_mode				       (TYPE_MODE (sizetype), size,					TREE_UNSIGNED (sizetype)),				       TYPE_MODE (sizetype));#else	  emit_library_call (bzero_libfunc, 0,			     VOIDmode, 2,			     XEXP (object, 0), Pmode,				     convert_to_mode			     (TYPE_MODE (integer_type_node), size,			      TREE_UNSIGNED (integer_type_node)),			     TYPE_MODE (integer_type_node));#endif	}    }  else    emit_move_insn (object, CONST0_RTX (GET_MODE (object)));  return retval;}/* Generate code to copy Y into X.   Both Y and X must have the same mode, except that   Y can be a constant with VOIDmode.   This mode cannot be BLKmode; use emit_block_move for that.   Return the last instruction emitted.  */rtxemit_move_insn (x, y)     rtx x, y;{  enum machine_mode mode = GET_MODE (x);  x = protect_from_queue (x, 1);  y = protect_from_queue (y, 0);  if (mode == BLKmode || (GET_MODE (y) != mode && GET_MODE (y) != VOIDmode))    abort ();  if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y))    y = force_const_mem (mode, y);  /* If X or Y are memory references, verify that their addresses are valid     for the machine.  */  if (GET_CODE (x) == MEM      && ((! memory_address_p (GET_MODE (x), XEXP (x, 0))	   && ! push_operand (x, GET_MODE (x)))	  || (flag_force_addr	      && CONSTANT_ADDRESS_P (XEXP (x, 0)))))    x = change_address (x, VOIDmode, XEXP (x, 0));  if (GET_CODE (y) == MEM      && (! memory_address_p (GET_MODE (y), XEXP (y, 0))	  || (flag_force_addr	      && CONSTANT_ADDRESS_P (XEXP (y, 0)))))    y = change_address (y, VOIDmode, XEXP (y, 0));  if (mode == BLKmode)    abort ();  return emit_move_insn_1 (x, y);}/* Low level part of emit_move_insn.   Called just like emit_move_insn, but assumes X and Y   are basically valid.  */rtxemit_move_insn_1 (x, y)     rtx x, y;{  enum machine_mode mode = GET_MODE (x);  enum machine_mode submode;  enum mode_class class = GET_MODE_CLASS (mode);  int i;  if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)    return      emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));  /* Expand complex moves by moving real part and imag part, if possible.  */  else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)	   && BLKmode != (submode = mode_for_size ((GET_MODE_UNIT_SIZE (mode)						    * BITS_PER_UNIT),						   (class == MODE_COMPLEX_INT						    ? MODE_INT : MODE_FLOAT),						   0))	   && (mov_optab->handlers[(int) submode].insn_code	       != CODE_FOR_nothing))    {      /* Don't split destination if it is a stack push.  */      int stack = push_operand (x, GET_MODE (x));      rtx insns;      /* If this is a stack, push the highpart first, so it	 will be in the argument order.	 In that case, change_address is used only to convert	 the mode, not to change the address.  */      if (stack)	{	  /* Note that the real part always precedes the imag part in memory	     regardless of machine's endianness.  */#ifdef STACK_GROWS_DOWNWARD	  emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)		     (gen_rtx (MEM, submode, (XEXP (x, 0))),		      gen_imagpart (submode, y)));	  emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)		     (gen_rtx (MEM, submode, (XEXP (x, 0))),		      gen_realpart (submode, y)));#else	  emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)		     (gen_rtx (MEM, submode, (XEXP (x, 0))),		      gen_realpart (submode, y)));	  emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)		     (gen_rtx (MEM, submode, (XEXP (x, 0))),		      gen_imagpart (submode, y)));#endif	}      else	{	  emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)		     (gen_realpart (submode, x), gen_realpart (submode, y)));	  emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)		     (gen_imagpart (submode, x), gen_imagpart (submode, y)));	}      return get_last_insn ();    }  /* This will handle any multi-word mode that lacks a move_insn pattern.     However, you will get better code if you define such patterns,     even if they must turn into multiple assembler instructions.  */  else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)    {      rtx last_insn = 0;      rtx insns;      #ifdef PUSH_ROUNDING      /* If X is a push on the stack, do the push now and replace	 X with a reference to the stack pointer.  */      if (push_operand (x, GET_MODE (x)))	{	  anti_adjust_stack (GEN_INT (GET_MODE_SIZE (GET_MODE (x))));	  x = change_address (x, VOIDmode, stack_pointer_rtx);	}#endif			           /* Show the output dies here.  */      if (x != y)        emit_insn (gen_rtx (CLOBBER, VOIDmode, x));      for (i = 0;	   i < (GET_MODE_SIZE (mode)  + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;	   i++)	{	  rtx xpart = operand_subword (x, i, 1, mode);	  rtx ypart = operand_subword (y, i, 1, mode);	  /* If we can't get a part of Y, put Y into memory if it is a	     constant.

⌨️ 快捷键说明

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