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

📄 expmed.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
			    ? MAX (0, bitsize - (i + 1) * BITS_PER_WORD)			    : i * BITS_PER_WORD);	  rtx target_part = operand_subword (target, wordnum, 1, VOIDmode);	  rtx result_part	    = extract_bit_field (op0, MIN (BITS_PER_WORD,					   bitsize - i * BITS_PER_WORD),				 bitnum + bit_offset,				 1, target_part, mode, word_mode,				 align, total_size);	  if (target_part == 0)	    abort ();	  if (result_part != target_part)	    emit_move_insn (target_part, result_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)    {      if (offset != 0	  || GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)	op0 = gen_rtx (SUBREG, TYPE_MODE (type_for_size (BITS_PER_WORD, 0)),		       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	  && (GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_extzv][0])	      >= bitsize))	{	  int xbitpos = bitpos, xoffset = offset;	  rtx bitsize_rtx, bitpos_rtx;	  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;	  enum machine_mode maxmode	    = insn_operand_mode[(int) CODE_FOR_extzv][0];	  if (GET_CODE (xop0) == MEM)	    {	      int save_volatile_ok = volatile_ok;	      volatile_ok = 1;	      /* Is the memory operand acceptable?  */	      if (flag_force_mem		  || ! ((*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;		  /* Get the mode to use for inserting into this field.  If		     OP0 is BLKmode, get the smallest mode consistent with the		     alignment. If OP0 is a non-BLKmode object that is no		     wider than MAXMODE, use its mode. Otherwise, use the		     smallest mode containing the field.  */		  if (GET_MODE (xop0) == BLKmode		      || (GET_MODE_SIZE (GET_MODE (op0))			  > GET_MODE_SIZE (maxmode)))		    bestmode = get_best_mode (bitsize, bitnum,					      align * BITS_PER_UNIT, maxmode,					      MEM_VOLATILE_P (xop0));		  else		    bestmode = GET_MODE (xop0);		  if (bestmode == VOIDmode)		    goto extzv_loses;		  /* Compute offset as multiple of this unit,		     counting in bytes.  */		  unit = GET_MODE_BITSIZE (bestmode);		  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);		  /* XBITPOS counts within UNIT, which is what is expected.  */		}	      else		/* Get ref to first byte containing part of the field.  */		xop0 = change_address (xop0, byte_mode,				       plus_constant (XEXP (xop0, 0), xoffset));	      volatile_ok = save_volatile_ok;	    }	  /* If op0 is a register, we need it in MAXMODE (which is usually	     SImode). to make it acceptable to the format of extzv.  */	  if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode)	    abort ();	  if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)	    xop0 = gen_rtx (SUBREG, maxmode, xop0, 0);	  /* On big-endian machines, we count bits from the most significant.	     If the bit field insn does not, we must invert.  */#if BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN	  xbitpos = unit - bitsize - xbitpos;#endif	  /* Now convert from counting within UNIT to counting in MAXMODE.  */#if BITS_BIG_ENDIAN	  if (GET_CODE (xop0) != MEM)	    xbitpos += GET_MODE_BITSIZE (maxmode) - unit;#endif	  unit = GET_MODE_BITSIZE (maxmode);	  if (xtarget == 0	      || (flag_force_mem && GET_CODE (xtarget) == MEM))	    xtarget = xspec_target = gen_reg_rtx (tmode);	  if (GET_MODE (xtarget) != maxmode)	    {	      if (GET_CODE (xtarget) == REG)		{		  int wider = (GET_MODE_SIZE (maxmode)			       > GET_MODE_SIZE (GET_MODE (xtarget)));		  xtarget = gen_lowpart (maxmode, xtarget);		  if (wider)		    xspec_target_subreg = xtarget;		}	      else		xtarget = gen_reg_rtx (maxmode);	    }	  /* 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, maxmode)))	    xtarget = gen_reg_rtx (maxmode);	  bitsize_rtx = GEN_INT (bitsize);	  bitpos_rtx = GEN_INT (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        extzv_loses:#endif	target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,					  target, 1, align);    }  else    {#ifdef HAVE_extv      if (HAVE_extv	  && (GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_extv][0])	      >= bitsize))	{	  int xbitpos = bitpos, xoffset = offset;	  rtx bitsize_rtx, bitpos_rtx;	  rtx last = get_last_insn();	  rtx xop0 = op0, xtarget = target;	  rtx xspec_target = spec_target;	  rtx xspec_target_subreg = spec_target_subreg;	  rtx pat;	  enum machine_mode maxmode	    = insn_operand_mode[(int) CODE_FOR_extv][0];	  if (GET_CODE (xop0) == MEM)	    {	      /* Is the memory operand acceptable?  */	      if (! ((*insn_operand_predicate[(int) CODE_FOR_extv][1])		     (xop0, GET_MODE (xop0))))		{		  /* No, load into a reg and extract from there.  */		  enum machine_mode bestmode;		  /* Get the mode to use for inserting into this field.  If		     OP0 is BLKmode, get the smallest mode consistent with the		     alignment. If OP0 is a non-BLKmode object that is no		     wider than MAXMODE, use its mode. Otherwise, use the		     smallest mode containing the field.  */		  if (GET_MODE (xop0) == BLKmode		      || (GET_MODE_SIZE (GET_MODE (op0))			  > GET_MODE_SIZE (maxmode)))		    bestmode = get_best_mode (bitsize, bitnum,					      align * BITS_PER_UNIT, maxmode,					      MEM_VOLATILE_P (xop0));		  else		    bestmode = GET_MODE (xop0);		  if (bestmode == VOIDmode)		    goto extv_loses;		  /* Compute offset as multiple of this unit,		     counting in bytes.  */		  unit = GET_MODE_BITSIZE (bestmode);		  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);		  /* XBITPOS counts within UNIT, which is what is expected.  */		}	      else		/* Get ref to first byte containing part of the field.  */		xop0 = change_address (xop0, byte_mode,				       plus_constant (XEXP (xop0, 0), xoffset));	    }	  /* If op0 is a register, we need it in MAXMODE (which is usually	     SImode) to make it acceptable to the format of extv.  */	  if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode)	    abort ();	  if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)	    xop0 = gen_rtx (SUBREG, maxmode, xop0, 0);	  /* On big-endian machines, we count bits from the most significant.	     If the bit field insn does not, we must invert.  */#if BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN	  xbitpos = unit - bitsize - xbitpos;#endif	  /* XBITPOS counts within a size of UNIT.	     Adjust to count within a size of MAXMODE.  */#if BITS_BIG_ENDIAN	  if (GET_CODE (xop0) != MEM)	    xbitpos += (GET_MODE_BITSIZE (maxmode) - unit);#endif	  unit = GET_MODE_BITSIZE (maxmode);	  if (xtarget == 0	      || (flag_force_mem && GET_CODE (xtarget) == MEM))	    xtarget = xspec_target = gen_reg_rtx (tmode);	  if (GET_MODE (xtarget) != maxmode)	    {	      if (GET_CODE (xtarget) == REG)		{		  int wider = (GET_MODE_SIZE (maxmode)			       > GET_MODE_SIZE (GET_MODE (xtarget)));		  xtarget = gen_lowpart (maxmode, xtarget);		  if (wider)		    xspec_target_subreg = xtarget;		}	      else		xtarget = gen_reg_rtx (maxmode);	    }	  /* If this machine's extv insists on a register target,	     make sure we have one.  */	  if (! ((*insn_operand_predicate[(int) CODE_FOR_extv][0])		 (xtarget, maxmode)))	    xtarget = gen_reg_rtx (maxmode);	  bitsize_rtx = GEN_INT (bitsize);	  bitpos_rtx = GEN_INT (xbitpos);	  pat = gen_extv (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, 0, align);	    }	}       else	extv_loses:#endif	target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,					  target, 0, align);    }  if (target == spec_target)    return target;  if (target == spec_target_subreg)    return spec_target;  if (GET_MODE (target) != tmode && GET_MODE (target) != mode)    {      /* If the target mode is floating-point, first convert to the	 integer mode of that size and then access it as a floating-point	 value via a SUBREG.  */      if (GET_MODE_CLASS (tmode) == MODE_FLOAT)	{	  target = convert_to_mode (mode_for_size (GET_MODE_BITSIZE (tmode),						   MODE_INT, 0),				    target, unsignedp);	  if (GET_CODE (target) != REG)	    target = copy_to_reg (target);	  return gen_rtx (SUBREG, tmode, target, 0);	}      else	return convert_to_mode (tmode, target, unsignedp);    }  return target;}/* Extract a bit field using shifts and boolean operations   Returns an rtx to represent the value.   OP0 addresses a register (word) or memory (byte).   BITPOS says which bit within the word or byte the bit field starts in.   OFFSET says how many bytes farther the bit field starts;    it is 0 if OP0 is a register.   BITSIZE says how many bits long the bit field is.    (If OP0 is a register, it may be narrower than a full word,     but BITPOS still counts within a full word,     which is significant on bigendian machines.)   UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value).   If TARGET is nonzero, attempts to store the value there   and return TARGET, but this is not guaranteed.   If TARGET is not used, create a pseudo-reg of mode TMODE for the value.   ALIGN is the alignment that STR_RTX is known to have, measured in bytes.  */static rtxextract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,			 target, unsignedp, align)     enum machine_mode tmode;     register rtx op0, target;     register int offset, bitsize, bitpos;     int unsignedp;     int align;{  int total_bits = BITS_PER_WORD;  enum machine_mode mode;  if (GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)    {      /* Special treatment for a bit field split across two registers.  */      if (bitsize + bitpos > BITS_PER_WORD)	return extract_split_bit_field (op0, bitsize, bitpos,					unsignedp, align);    }  else    {      /* Get the proper mode to use for this field.  We want a mode that	 includes the entire field.  If such a mode would be larger than	 a word, we won't be doing the extraction the normal way.  */      mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,			    align * BITS_PER_UNIT, word_mode,			    GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0));      if (mode == VOIDmode)	/* The only way this should occur is if the field spans word	   boundaries.  */	return extract_split_bit_field (op0, bitsize,					bitpos + offset * BITS_PER_UNIT,					unsignedp, align);      total_bits = GET_MODE_BITSIZE (mode);      /* Get ref to an aligned byte, halfword, or word containing the field.	 Adjust BITPOS to be position within a word,	 and OFFSET to be the offset of that word.	 Then alter OP0 to refer to that word.  */      bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;      offset -= (offset % (total_bits / BITS_PER_UNIT));      op0 = change_address (op0, mode,			    plus_constant (XEXP (op0, 0), offset));    }  mode = GET_MODE (op0);#if BYTES_BIG_ENDIAN  /* BITPOS is the distance between our msb and that of OP0.     Convert it to the distance from the lsb.  */  bitpos = total_bits - bitsize - bitpos;#endif  /* Now BITPOS is always the distance between the field's lsb and that of OP0.     We have reduced the big-endian case to the little-endian case.  */  if (unsignedp)    {      if (bitpos)

⌨️ 快捷键说明

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