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

📄 expmed.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
  /* BITPOS is the distance between our msb     and that of the containing datum.     Convert it to the distance from the lsb.  */  bitpos = total_bits - bitsize - bitpos;#endif  /* Now BITPOS is always the distance between our lsb     and that of OP0.  */  /* Shift VALUE left by BITPOS bits.  If VALUE is not constant,     we must first convert its mode to MODE.  */  if (GET_CODE (value) == CONST_INT)    {      register int v = INTVAL (value);      if (bitsize < HOST_BITS_PER_INT)	v &= (1 << bitsize) - 1;      if (v == 0)	all_zero = 1;      else if (bitsize < HOST_BITS_PER_INT && v == (1 << bitsize) - 1)	all_one = 1;      value = gen_rtx (CONST_INT, VOIDmode, v << bitpos);    }  else    {      int must_and = (GET_MODE_BITSIZE (GET_MODE (value)) != bitsize);      if (GET_MODE (value) != mode)	{	  if ((GET_CODE (value) == REG || GET_CODE (value) == SUBREG)	      && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (value)))	    value = gen_lowpart (mode, value);	  else	    value = convert_to_mode (mode, value, 1);	}      if (must_and && bitsize < HOST_BITS_PER_INT)	value = expand_bit_and (mode, value,				gen_rtx (CONST_INT, VOIDmode,					 (1 << bitsize) - 1),				0);      if (bitpos > 0)	value = expand_shift (LSHIFT_EXPR, mode, value,			      build_int_2 (bitpos, 0), 0, 1);    }  /* Now clear the chosen bits in OP0,     except that if VALUE is -1 we need not bother.  */  subtarget = op0;  if (! all_one)    subtarget = expand_bit_and (mode, op0,				gen_rtx (CONST_INT, VOIDmode, 					 (~ (((unsigned) ~0					      >> (HOST_BITS_PER_INT - bitsize))					     << bitpos))					 & ((GET_MODE_BITSIZE (mode)					     == HOST_BITS_PER_INT)					    ? -1					    : ((1 << GET_MODE_BITSIZE (mode)) - 1))),				subtarget);  /* Now logical-or VALUE into OP0, unless it is zero.  */  if (! all_zero)    subtarget = expand_binop (mode, ior_optab, subtarget, value,			      op0, 1, OPTAB_LIB_WIDEN);  if (op0 != subtarget)    emit_move_insn (op0, subtarget);}/* Store a bit field that is split across two words.   OP0 is the REG, SUBREG or MEM rtx for the first of the two words.   BITSIZE is the field width; BITPOS the position of its first bit   (within the word).   VALUE is the value to store.  */static voidstore_split_bit_field (op0, bitsize, bitpos, value, align)     rtx op0;     int bitsize, bitpos;     rtx value;     int align;{  /* BITSIZE_1 is size of the part in the first word.  */  int bitsize_1 = BITS_PER_WORD - bitpos;  /* BITSIZE_2 is size of the rest (in the following word).  */  int bitsize_2 = bitsize - bitsize_1;  rtx part1, part2;  /* Alignment of VALUE, after conversion.  */  int valalign = GET_MODE_SIZE (SImode);  if (GET_MODE (value) != VOIDmode)    value = convert_to_mode (SImode, value, 1);  if (CONSTANT_P (value) && GET_CODE (value) != CONST_INT)    value = copy_to_reg (value);  /* Split the value into two parts:     PART1 gets that which goes in the first word; PART2 the other.  */#ifdef BYTES_BIG_ENDIAN  /* PART1 gets the more significant part.  */  if (GET_CODE (value) == CONST_INT)    {      part1 = gen_rtx (CONST_INT, VOIDmode,		       (unsigned) (INTVAL (value)) >> bitsize_2);      part2 = gen_rtx (CONST_INT, VOIDmode,		       (unsigned) (INTVAL (value)) & ((1 << bitsize_2) - 1));    }  else    {      part1 = extract_fixed_bit_field (SImode, value, 0, bitsize_1,				       BITS_PER_WORD - bitsize, 0, 1, valalign);      part2 = extract_fixed_bit_field (SImode, value, 0, bitsize_2,				       BITS_PER_WORD - bitsize_2, 0, 1, valalign);    }#else  /* PART1 gets the less significant part.  */  if (GET_CODE (value) == CONST_INT)    {      part1 = gen_rtx (CONST_INT, VOIDmode,		       (unsigned) (INTVAL (value)) & ((1 << bitsize_1) - 1));      part2 = gen_rtx (CONST_INT, VOIDmode,		       (unsigned) (INTVAL (value)) >> bitsize_1);    }  else    {      part1 = extract_fixed_bit_field (SImode, value, 0, bitsize_1, 0,				       0, 1, valalign);      part2 = extract_fixed_bit_field (SImode, value, 0, bitsize_2,				       bitsize_1, 0, 1, valalign);    }#endif  /* Store PART1 into the first word.  */  store_fixed_bit_field (op0, 0, bitsize_1, bitpos, part1, align);  /* Offset op0 to get to the following word.  */  if (GET_CODE (op0) == MEM)    op0 = change_address (op0, SImode,			  plus_constant (XEXP (op0, 0), UNITS_PER_WORD));  else if (GET_CODE (op0) == REG)    op0 = gen_rtx (SUBREG, SImode, op0, 1);  else if (GET_CODE (op0) == SUBREG)    op0 = gen_rtx (SUBREG, SImode, SUBREG_REG (op0), SUBREG_WORD (op0) + 1);  /* Store PART2 into the second word.  */  store_fixed_bit_field (op0, 0, bitsize_2, 0, part2, align);}/* Generate code to extract a byte-field from STR_RTX   containing BITSIZE bits, starting at BITNUM,   and put it in TARGET if possible (if TARGET is nonzero).   Regardless of TARGET, we return the rtx for where the value is placed.   It may be a QUEUED.   STR_RTX is the structure containing the byte (a REG or MEM).   UNSIGNEDP is nonzero if this is an unsigned bit field.   MODE is the natural mode of the field value once extracted.   TMODE is the mode the caller would like the value to have;   but the value may be returned with type MODE instead.   ALIGN is the alignment that STR_RTX is known to have, measured in bytes.   TOTAL_SIZE is the total size in bytes of the structure, if known.   Otherwise it is -1.   If a TARGET is specified and we can store in it at no extra cost,   we do so, and return TARGET.   Otherwise, we return a REG of mode TMODE or MODE, with TMODE preferred   if they are equally easy.  */rtxextract_bit_field (str_rtx, bitsize, bitnum, unsignedp,		   target, mode, tmode, align, total_size)     rtx str_rtx;     register int bitsize;     int bitnum;     int unsignedp;     rtx target;     enum machine_mode mode, tmode;     int align;     int total_size;{  int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD;  register int offset = bitnum / unit;  register int bitpos = bitnum % unit;  register rtx op0 = str_rtx;  rtx spec_target = target;  rtx bitsize_rtx, bitpos_rtx;  rtx spec_target_subreg = 0;  /* Discount the part of the structure before the desired byte.     We need to know how many bytes are safe to reference after it.  */  if (total_size >= 0)    total_size -= (bitpos / BIGGEST_ALIGNMENT		   * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));  if (tmode == VOIDmode)    tmode = mode;  while (GET_CODE (op0) == SUBREG)    {#ifdef BYTES_BIG_ENDIAN      /* Keep BITPOS counting within the size of op0.  */      bitpos += (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))		 - GET_MODE_BITSIZE (GET_MODE (op0)));#endif      offset += SUBREG_WORD (op0);      op0 = SUBREG_REG (op0);    }  #ifdef BYTES_BIG_ENDIAN  /* If OP0 is a register, BITPOS must count within a word.     But as we have it, it counts within whatever size OP0 now has.     On a bigendian machine, these are not the same, so convert.  */  if (GET_CODE (op0) != MEM && unit > GET_MODE_BITSIZE (GET_MODE (op0)))    {      bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));      /* Change the mode now so we don't adjust BITPOS again.  */      if (GET_CODE (op0) == SUBREG)	PUT_MODE (op0, SImode);      else	op0 = gen_rtx (SUBREG, SImode, op0, 0);    }#endif  /* Extracting a full-word or multi-word value     from a structure in a register.     This can be done with just SUBREG.     So too extracting a subword value in     the least significant part of the register.  */  if (GET_CODE (op0) == REG      && ((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode)	   && bitpos % BITS_PER_WORD == 0)	  || ((bitsize == GET_MODE_BITSIZE (mode)	       || bitsize == GET_MODE_BITSIZE (QImode)	       || bitsize == GET_MODE_BITSIZE (HImode))#ifdef BYTES_BIG_ENDIAN	      && bitpos + bitsize == BITS_PER_WORD#else	      && bitpos == 0#endif	      )))    {      enum machine_mode mode1 = mode;      if (bitsize == GET_MODE_BITSIZE (QImode))	mode1 = QImode;      if (bitsize == GET_MODE_BITSIZE (HImode))	mode1 = HImode;      if (mode1 != GET_MODE (op0))	{	  if (GET_CODE (op0) == SUBREG)	    PUT_MODE (op0, mode1);	  else	    op0 = gen_rtx (SUBREG, mode1, op0, offset);	}      if (mode1 != mode)	return convert_to_mode (tmode, op0, unsignedp);      return op0;    }  /* Handle fields bigger than a word.  */    if (bitsize > BITS_PER_WORD)    {      int low_size = BITS_PER_WORD;      int low_pos = bitpos + offset * unit;      rtx target_low_part, low_part;      int high_size = bitsize - low_size;      int high_pos;      rtx target_high_part, high_part;#ifdef BYTES_BIG_ENDIAN      high_pos = low_pos;      low_pos += high_size;#else      high_pos = low_pos + low_size;#endif      if (target == 0 || GET_CODE (target) != REG)	target = gen_reg_rtx (mode);      /* Extract the low part of the bitfield, and make sure	 to store it in the low part of TARGET.  */      target_low_part = gen_lowpart (SImode, target);      low_part = extract_bit_field (op0, low_size, low_pos, 1,				    target_low_part, SImode, SImode,				    align, total_size);      if (low_part != target_low_part)	emit_move_insn (target_low_part, low_part);      /* Likewise for the high part.  */      target_high_part = gen_highpart (SImode, target);      high_part = extract_bit_field (op0, high_size, high_pos, unsignedp,				     target_high_part, SImode, SImode,				     align, total_size);      if (high_part != target_high_part)	emit_move_insn (target_high_part, high_part);      return target;    }  /* From here on we know the desired field is smaller than a word     so we can assume it is an integer.  So we can safely extract it as one     size of integer, if necessary, and then truncate or extend     to the size that is wanted.  */  /* OFFSET is the number of words or bytes (UNIT says which)     from STR_RTX to the first word or byte containing part of the field.  */  if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)    {      /* If not in memory, merge in the offset now.  */      if (offset != 0	  || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (SImode))	{	  if (GET_CODE (op0) == SUBREG)	    SUBREG_WORD (op0) += offset;	  else	    op0 = gen_rtx (SUBREG, SImode, op0, offset);	}      offset = 0;    }  else    {      op0 = protect_from_queue (str_rtx, 1);    }  /* Now OFFSET is nonzero only for memory operands.  */  if (unsignedp)    {#ifdef HAVE_extzv      if (HAVE_extzv)	{	  int xbitpos = bitpos, xoffset = offset;	  rtx last = get_last_insn();	  rtx xop0 = op0;	  rtx xtarget = target;	  rtx xspec_target = spec_target;	  rtx xspec_target_subreg = spec_target_subreg;	  rtx pat;	  if (GET_CODE (xop0) == MEM)	    {	      extern int volatile_ok;	      int save_volatile_ok = volatile_ok;	      volatile_ok = 1;	      /* Is the memory operand acceptable?  */	      if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][1])		     (xop0, GET_MODE (xop0))))		{		  /* No, load into a reg and extract from there.  */		  enum machine_mode bestmode = VOIDmode, trymode;		  /* Don't use a mode bigger than the one of the value		     to be fetched.  That mode must be okay,		     since a bit field can be that big.  */		  int maxsize		    = GET_MODE_SIZE (insn_operand_mode[(int) CODE_FOR_extzv][0]);		  /* This used to use the mode desired for operand 1,		     but that is normally QImode on most machines,		     and QImode won't work for fields that cross byte		     boundaries.  */		  /* Also don't use a mode bigger than the structure.  */		  if (total_size >= 0 && maxsize > total_size)		    maxsize = total_size;		  /* Find biggest machine mode we can safely use		     to fetch from this structure.		     But don't use a bigger mode than the insn wants.  */		  for (trymode = QImode;		       trymode && GET_MODE_SIZE (trymode) <= maxsize;		       trymode = GET_MODE_WIDER_MODE (trymode))		    if (GET_MODE_SIZE (trymode) <= align			|| align == BIGGEST_ALIGNMENT / BITS_PER_UNIT)		      bestmode = trymode;		  if (! bestmode)		    abort ();		  unit = GET_MODE_BITSIZE (bestmode);		  /* Compute offset as multiple of this unit,		     counting in bytes.  */		  xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);		  xbitpos = bitnum % unit;		  xop0 = change_address (xop0, bestmode,					 plus_constant (XEXP (xop0, 0),							xoffset));		  /* Fetch it to a register in that size.  */		  xop0 = force_reg (bestmode, xop0);		  /* Now ref the register in the mode extzv wants.  */		  /* We used to use the mode from operand 1 in the md,		     but that is often QImode because that's needed for MEM.		     Here we need SImode instead.  */		  if (bestmode != SImode)		    xop0 = gen_rtx (SUBREG, SImode, xop0, 0);#ifdef BYTES_BIG_ENDIAN		  if (GET_MODE_BITSIZE (GET_MODE (xop0)) > unit)		    xbitpos += GET_MODE_BITSIZE (GET_MODE (xop0)) - unit;#endif		}	      else		/* Get ref to first byte containing part of the field.  */		xop0 = change_address (xop0, QImode,				       plus_constant (XEXP (xop0, 0), xoffset));	      volatile_ok = save_volatile_ok;	    }	  /* If op0 is a register, we need it in SImode	     to make it acceptable to the format of extzv.  */	  if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != SImode)	    abort ();	  if (GET_CODE (xop0) == REG && GET_MODE (xop0) != SImode)	    {#ifdef BYTES_BIG_ENDIAN	      xbitpos += (GET_MODE_BITSIZE (SImode)			  - GET_MODE_BITSIZE (GET_MODE (xop0)));#endif	      xop0 = gen_rtx (SUBREG, SImode, xop0, 0);	    }	  if (xtarget == 0	      || (flag_force_mem && GET_CODE (xtarget) == MEM))	    xtarget = xspec_target = gen_reg_rtx (tmode);	  if (GET_MODE (xtarget) != SImode)	    {	      if (GET_CODE (xtarget) == REG)		xspec_target_subreg = xtarget = gen_lowpart (SImode, xtarget);	      else		xtarget = gen_reg_rtx (SImode);	    }	  /* If this machine's extzv insists on a register target,	     make sure we have one.  */	  if (! (*insn_operand_predicate[(int) CODE_FOR_extzv][0]) (xtarget, SImode))	    xtarget = gen_reg_rtx (SImode);	  /* On big-endian machines, we count bits from the most significant.	     If the bit field insn does not, we must invert.  */#if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN)	  xbitpos = unit - 1 - xbitpos;#endif	  bitsize_rtx = gen_rtx (CONST_INT, VOIDmode, bitsize);	  bitpos_rtx = gen_rtx (CONST_INT, VOIDmode, xbitpos);	  pat = gen_extzv (protect_from_queue (xtarget, 1),			   xop0, bitsize_rtx, bitpos_rtx);	  if (pat)	    {	      emit_insn (pat);	      target = xtarget;	      spec_target = xspec_target;	      spec_target_subreg = xspec_target_subreg;	    }	  else	    {	      delete_insns_since (last);	      target = extract_fixed_bit_field (tmode, op0, offset, bitsize,						bitpos, target, 1, align);	    }	}      else

⌨️ 快捷键说明

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