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

📄 expr.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
  /* Don't crash if the lhs of the assignment was erroneous.  */  if (TREE_CODE (to) == ERROR_MARK)    return expand_expr (from, 0, VOIDmode, 0);  /* Assignment of a structure component needs special treatment     if the structure component's rtx is not simply a MEM.     Assignment of an array element at a constant index     has the same problem.  */  if (TREE_CODE (to) == COMPONENT_REF      || (TREE_CODE (to) == ARRAY_REF	  && TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST	  && TREE_CODE (TYPE_SIZE (TREE_TYPE (to))) == INTEGER_CST))    {      register enum machine_mode mode1;      int bitsize;      int volstruct = 0;      tree tem = to;      int bitpos = 0;      int unsignedp;      if (TREE_CODE (to) == COMPONENT_REF)	{	  tree field = TREE_OPERAND (to, 1);	  bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field);	  mode1 = DECL_MODE (TREE_OPERAND (to, 1));	  unsignedp = TREE_UNSIGNED (field);	}      else	{	  mode1 = TYPE_MODE (TREE_TYPE (to));	  bitsize = GET_MODE_BITSIZE (mode1);	  unsignedp = TREE_UNSIGNED (TREE_TYPE (to));	}      /* Compute cumulative bit-offset for nested component-refs	 and array-refs, and find the ultimate containing object.  */      while (1)	{	  if (TREE_CODE (tem) == COMPONENT_REF)	    {	      bitpos += DECL_OFFSET (TREE_OPERAND (tem, 1));	      if (TREE_THIS_VOLATILE (tem))		volstruct = 1;	    }	  else if (TREE_CODE (tem) == ARRAY_REF		   && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST		   && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST)	    {	      bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1))			 * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)))			 * TYPE_SIZE_UNIT (TREE_TYPE (tem)));	      if (TREE_THIS_VOLATILE (tem))		volstruct = 1;	    }	  else	    break;	  tem = TREE_OPERAND (tem, 0);	}      /* TEM is now the containing data object.  */      /* If we are going to use store_bit_field and extract_bit_field,	 make sure to_rtx will be safe for multiple use.  */      if (mode1 == BImode && want_value)	tem = stabilize_reference (tem);      to_rtx = expand_expr (tem, 0, VOIDmode, 0);      if (volstruct)	{	  if (GET_CODE (to_rtx) == MEM)	    MEM_VOLATILE_P (to_rtx) = 1;#if 0  /* This was turned off because, when a field is volatile	  in an object which is not volatile, the object may be in a register,	  and then we would abort over here.  */	  else	    abort ();#endif	}      return store_field (to_rtx, bitsize, bitpos, mode1, from,			  (want_value			   /* Spurious cast makes HPUX compiler happy.  */			   ? (enum machine_mode) TYPE_MODE (TREE_TYPE (to))			   : VOIDmode),			  unsignedp,			  /* Required alignment of containing datum.  */			  TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT,			  int_size_in_bytes (TREE_TYPE (tem)));    }  /* Ordinary treatment.  Expand TO to get a REG or MEM rtx.     Don't re-expand if it was expanded already (in COMPONENT_REF case).  */  if (to_rtx == 0)    to_rtx = expand_expr (to, 0, VOIDmode, 0);  /* Compute FROM and store the value in the rtx we got.  */  return store_expr (from, to_rtx, want_value);}/* Generate code for computing expression EXP,   and storing the value into TARGET.   Returns TARGET or an equivalent value.   TARGET may contain a QUEUED rtx.   If SUGGEST_REG is nonzero, copy the value through a register   and return that register, if that is possible.   If the value stored is a constant, we return the constant.  */rtxstore_expr (exp, target, suggest_reg)     register tree exp;     register rtx target;     int suggest_reg;{  register rtx temp;  int dont_return_target = 0;  /* Copying a non-constant CONSTRUCTOR needs special treatment.  */  if (TREE_CODE (exp) == CONSTRUCTOR && ! TREE_STATIC (exp))    {      store_constructor (exp, target);      return target;    }  if (suggest_reg && GET_CODE (target) == MEM && GET_MODE (target) != BLKmode)    /* If target is in memory and caller wants value in a register instead,       arrange that.  Pass TARGET as target for expand_expr so that,       if EXP is another assignment, SUGGEST_REG will be nonzero for it.       We know expand_expr will not use the target in that case.  */    {      temp = expand_expr (exp, cse_not_expected ? 0 : target,			  GET_MODE (target), 0);      if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)	temp = copy_to_reg (temp);      dont_return_target = 1;    }  else if (queued_subexp_p (target))    /* If target contains a postincrement, it is not safe       to use as the returned value.  It would access the wrong       place by the time the queued increment gets output.       So copy the value through a temporary and use that temp       as the result.  */    {      temp = expand_expr (exp, 0, GET_MODE (target), 0);      if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)	temp = copy_to_reg (temp);      dont_return_target = 1;    }  else    {      temp = expand_expr (exp, target, GET_MODE (target), 0);      /* DO return TARGET if it's a specified hardware register.	 expand_return relies on this.  */      if (!(target && GET_CODE (target) == REG	    && REGNO (target) < FIRST_PSEUDO_REGISTER)	  && (CONSTANT_P (temp) || GET_CODE (temp) == CONST_DOUBLE))	dont_return_target = 1;    }  /* If value was not generated in the target, store it there.     Convert the value to TARGET's type first if nec.  */  if (temp != target && TREE_CODE (exp) != ERROR_MARK)    {      target = protect_from_queue (target, 1);      if (GET_MODE (temp) != GET_MODE (target)	  && GET_MODE (temp) != VOIDmode)	{	  int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));	  if (dont_return_target)	    {	      /* In this case, we will return TEMP,		 so make sure it has the proper mode.		 But don't forget to store the value into TARGET.  */	      temp = convert_to_mode (GET_MODE (target), temp, unsignedp);	      emit_move_insn (target, temp);	    }	  else	    convert_move (target, temp, unsignedp);	}      else if (GET_MODE (temp) == BLKmode && TREE_CODE (exp) == STRING_CST)	{	  /* Handle copying a string constant into an array.	     The string constant may be shorter than the array.	     So copy just the string's actual length, and clear the rest.  */	  rtx size;	  emit_block_move (target, temp,			   gen_rtx (CONST_INT, VOIDmode,				    TREE_STRING_LENGTH (exp)),			   TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);	  temp = plus_constant (XEXP (target, 0), TREE_STRING_LENGTH (exp));	  size = plus_constant (expr_size (exp), - TREE_STRING_LENGTH (exp));#ifdef TARGET_MEM_FUNCTIONS	  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memset"),			     0, VOIDmode, 3,			     temp, Pmode, const0_rtx, Pmode, size, Pmode);#else	  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bzero"),			     0, VOIDmode, 2,			     temp, Pmode, size, Pmode);#endif	}      else if (GET_MODE (temp) == BLKmode)	emit_block_move (target, temp, expr_size (exp),			 TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);      else	emit_move_insn (target, temp);    }  if (dont_return_target)    return temp;  return target;}/* Store the value of constructor EXP into the rtx TARGET.   TARGET is either a REG or a MEM.  */static voidstore_constructor (exp, target)     tree exp;     rtx target;{  /* Don't try copying piece by piece into a hard register     since that is vulnerable to being clobbered by EXP.     Instead, construct in a pseudo register and then copy it all.  */  if (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)    {      rtx temp = gen_reg_rtx (GET_MODE (target));      store_constructor (exp, temp);      emit_move_insn (target, temp);      return;    }  if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE      || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)    {      register tree elt;      if (TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)	/* Inform later passes that the whole union value is dead.  */	emit_insn (gen_rtx (CLOBBER, VOIDmode, target));      /* If a record constructor has fewer fields than the structure,	 clear the whole structure first.  */      else if (list_length (CONSTRUCTOR_ELTS (exp))	       != list_length (TYPE_FIELDS (TREE_TYPE (exp))))	clear_storage (target, int_size_in_bytes (TREE_TYPE (exp)));      else	/* Inform later passes that the old value is dead.  */	emit_insn (gen_rtx (CLOBBER, VOIDmode, target));      /* Store each element of the constructor into	 the corresponding field of TARGET.  */      for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))	{	  register tree field = TREE_PURPOSE (elt);	  register enum machine_mode mode;	  int bitsize;	  int bitpos;	  int unsignedp;	  bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field);	  mode = DECL_MODE (field);	  unsignedp = TREE_UNSIGNED (field);	  bitpos = DECL_OFFSET (field);	  store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt),		       /* The alignment of TARGET is			  at least what its type requires.  */		       VOIDmode, 0,		       TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT,		       int_size_in_bytes (TREE_TYPE (exp)));	}    }  else if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)    {      register tree elt;      register int i;      tree domain = TYPE_DOMAIN (TREE_TYPE (exp));      int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));      int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));      tree elttype = TREE_TYPE (TREE_TYPE (exp));      /* If the constructor has fewer fields than the structure,	 clear the whole structure first.  */      if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1)	clear_storage (target, maxelt - minelt + 1);      else	/* Inform later passes that the old value is dead.  */	emit_insn (gen_rtx (CLOBBER, VOIDmode, target));      /* Store each element of the constructor into	 the corresponding element of TARGET, determined	 by counting the elements.  */      for (elt = CONSTRUCTOR_ELTS (exp), i = 0;	   elt;	   elt = TREE_CHAIN (elt), i++)	{	  register enum machine_mode mode;	  int bitsize;	  int bitpos;	  int unsignedp;	  mode = TYPE_MODE (elttype);	  bitsize = GET_MODE_BITSIZE (mode);	  unsignedp = TREE_UNSIGNED (elttype);	  bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype))		    * TYPE_SIZE_UNIT (elttype));	  store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt),		       /* The alignment of TARGET is			  at least what its type requires.  */		       VOIDmode, 0,		       TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT,		       int_size_in_bytes (TREE_TYPE (exp)));	}    }}/* Store the value of EXP (an expression tree)   into a subfield of TARGET which has mode MODE and occupies   BITSIZE bits, starting BITPOS bits from the start of TARGET.   If VALUE_MODE is VOIDmode, return nothing in particular.   UNSIGNEDP is not used in this case.   Otherwise, return an rtx for the value stored.  This rtx   has mode VALUE_MODE if that is convenient to do.   In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.   ALIGN is the alignment that TARGET is known to have, measured in bytes.   TOTAL_SIZE is its size in bytes, or -1 if variable.  */static rtxstore_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, align,	     total_size)     rtx target;     int bitsize, bitpos;     enum machine_mode mode;     tree exp;     enum machine_mode value_mode;     int unsignedp;     int align;     int total_size;{  /* If the structure is in a register or if the component     is a bit field, we cannot use addressing to access it.     Use bit-field techniques or SUBREG to store in it.  */  if (mode == BImode || GET_CODE (target) == REG      || GET_CODE (target) == SUBREG)    {      store_bit_field (target, bitsize, bitpos,		       mode,		       expand_expr (exp, 0, VOIDmode, 0),		       align, total_size);      if (value_mode != VOIDmode)	return extract_bit_field (target, bitsize, bitpos, unsignedp,				  0, value_mode, 0, align, total_size);      return const0_rtx;    }  else    {      rtx addr = XEXP (target, 0);      rtx to_rtx;      /* If a value is wanted, it must be the lhs;	 so make the address stable for multiple use.  */      if (value_mode != VOIDmode && GET_CODE (addr) != REG	  && ! CONSTANT_ADDRESS_P (addr))	addr = copy_to_reg (addr);      /* Now build a reference to just the desired component.  */      to_rtx = change_address (target, mode,			       plus_constant (addr,					      (bitpos / BITS_PER_UNIT)));      MEM_IN_STRUCT_P (to_rtx) = 1;      return store_expr (exp, to_rtx, value_mode != VOIDmode);    }}/* Given an rtx VALUE that may contain additions and multiplications,   return an equivalent value that just refers to a register or memory.   This is done by generating instructions to perform the arithmetic   and returning a pseudo-register containing the value.  */rtxforce_operand (value, target)     rtx value, target;{  register optab binoptab = 0;  register rtx op2;  /* Use subtarget as the target for operand 0 of a binary operation.  */  register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);  if (GET_CODE (value) == PLUS)    binoptab = add_optab;  else if (GET_CODE (value) == MINUS)    binoptab = sub_optab;  else if (GET_CODE (value) == MULT)    {      op2 = XEXP (value, 1);      if (!CONSTANT_P (op2)	  && !(GET_CODE (op2) == REG && op2 != subtarget))	subtarget = 0;      return expand_mult (GET_MODE (value),			  force_operand (XEXP (value, 0), subtarget),			  force_operand (op2, 0),			  target, 0);    }  if (binoptab)    {      op2 = XEXP (value, 1);      if (!CONSTANT_P (op2)	  && !(GET_CODE (op2) == REG && op2 != subtarget))	subtarget = 0;      if (binoptab == sub_optab	  && GET_CODE (op2) == CONST_INT && INTVAL (op2) < 0)	{	  binoptab = add_optab;	  op2 = gen_rtx (CONST_INT, VOIDmode, - INTVAL (op2));	}      return expand_binop (GET_MODE (value), binoptab,			   force_operand (XEXP (value, 0), subtarget),			   force_operand (op2, 0),			   target, 0, OPTAB_LIB_WIDEN);      /* We give UNSIGNEP = 0 to expand_binop	 because the only operations we are expanding here are signed ones.  */    }  return value;}/* expand_expr: generate code for computing expression EXP.   An rtx for the computed value is returned.  The value is never null.   In the case of a void EXP, const0_rtx is returned.   The value may b

⌨️ 快捷键说明

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