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

📄 emit-rtl.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
  else if (GET_CODE (x) == REG)    {      int word = 0;      if (! WORDS_BIG_ENDIAN	  && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)	word = ((GET_MODE_SIZE (GET_MODE (x))		 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))		/ UNITS_PER_WORD);      /*       * ??? This fails miserably for complex values being passed in registers       * where the sizeof the real and imaginary part are not equal to the       * sizeof SImode.  FIXME       */      if (REGNO (x) < FIRST_PSEUDO_REGISTER	  /* integrate.c can't handle parts of a return value register. */	  && (! REG_FUNCTION_VALUE_P (x)	      || ! rtx_equal_function_value_matters)	  /* We want to keep the stack, frame, and arg pointers special.  */	  && x != frame_pointer_rtx#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM	  && x != arg_pointer_rtx#endif	  && x != stack_pointer_rtx)	return gen_rtx (REG, mode, REGNO (x) + word);      else	return gen_rtx (SUBREG, mode, x, word);    }  else    abort ();}/* Return 1 iff X, assumed to be a SUBREG,   refers to the least significant part of its containing reg.   If X is not a SUBREG, always return 1 (it is its own low part!).  */intsubreg_lowpart_p (x)     rtx x;{  if (GET_CODE (x) != SUBREG)    return 1;  if (WORDS_BIG_ENDIAN      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD)    return (SUBREG_WORD (x)	    == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))		 - MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD))		/ UNITS_PER_WORD));  return SUBREG_WORD (x) == 0;}/* Return subword I of operand OP.   The word number, I, is interpreted as the word number starting at the   low-order address.  Word 0 is the low-order word if not WORDS_BIG_ENDIAN,   otherwise it is the high-order word.   If we cannot extract the required word, we return zero.  Otherwise, an   rtx corresponding to the requested word will be returned.   VALIDATE_ADDRESS is nonzero if the address should be validated.  Before   reload has completed, a valid address will always be returned.  After   reload, if a valid address cannot be returned, we return zero.   If VALIDATE_ADDRESS is zero, we simply form the required address; validating   it is the responsibility of the caller.   MODE is the mode of OP in case it is a CONST_INT.  */rtxoperand_subword (op, i, validate_address, mode)     rtx op;     int i;     int validate_address;     enum machine_mode mode;{  HOST_WIDE_INT val;  int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;  if (mode == VOIDmode)    mode = GET_MODE (op);  if (mode == VOIDmode)    abort ();  /* If OP is narrower than a word or if we want a word outside OP, fail.  */  if (mode != BLKmode      && (GET_MODE_SIZE (mode) < UNITS_PER_WORD	  || (i + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode)))    return 0;  /* If OP is already an integer word, return it.  */  if (GET_MODE_CLASS (mode) == MODE_INT      && GET_MODE_SIZE (mode) == UNITS_PER_WORD)    return op;  /* If OP is a REG or SUBREG, we can handle it very simply.  */  if (GET_CODE (op) == REG)    {      /* If the register is not valid for MODE, return 0.  If we don't	 do this, there is no way to fix up the resulting REG later.  */      if (REGNO (op) < FIRST_PSEUDO_REGISTER	  && ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode))	return 0;      else if (REGNO (op) >= FIRST_PSEUDO_REGISTER	       || (REG_FUNCTION_VALUE_P (op)		   && rtx_equal_function_value_matters)	       /* We want to keep the stack, frame, and arg pointers		  special.  */	       || op == frame_pointer_rtx#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM	       || op == arg_pointer_rtx#endif	       || op == stack_pointer_rtx)	return gen_rtx (SUBREG, word_mode, op, i);      else	return gen_rtx (REG, word_mode, REGNO (op) + i);    }  else if (GET_CODE (op) == SUBREG)    return gen_rtx (SUBREG, word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));  else if (GET_CODE (op) == CONCAT)    {      int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;      if (i < partwords)	return operand_subword (XEXP (op, 0), i, validate_address, mode);      return operand_subword (XEXP (op, 1), i - partwords,			      validate_address, mode);    }  /* Form a new MEM at the requested address.  */  if (GET_CODE (op) == MEM)    {      rtx addr = plus_constant (XEXP (op, 0), i * UNITS_PER_WORD);      rtx new;      if (validate_address)	{	  if (reload_completed)	    {	      if (! strict_memory_address_p (word_mode, addr))		return 0;	    }	  else	    addr = memory_address (word_mode, addr);	}      new = gen_rtx (MEM, word_mode, addr);      MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op);      MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op);      RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (op);      return new;    }  /* The only remaining cases are when OP is a constant.  If the host and     target floating formats are the same, handling two-word floating     constants are easy.  Note that REAL_VALUE_TO_TARGET_{SINGLE,DOUBLE}     are defined as returning one or two 32 bit values, respectively,     and not values of BITS_PER_WORD bits.  */#ifdef REAL_ARITHMETIC/*  The output is some bits, the width of the target machine's word.    A wider-word host can surely hold them in a CONST_INT. A narrower-word    host can't.  */  if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD      && GET_MODE_CLASS (mode) == MODE_FLOAT      && GET_MODE_BITSIZE (mode) == 64      && GET_CODE (op) == CONST_DOUBLE)    {      long k[2];      REAL_VALUE_TYPE rv;      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);      /* We handle 32-bit and >= 64-bit words here.  Note that the order in	 which the words are written depends on the word endianness.	 ??? This is a potential portability problem and should	 be fixed at some point.  */      if (BITS_PER_WORD == 32)	return GEN_INT ((HOST_WIDE_INT) k[i]);#if HOST_BITS_PER_WIDE_INT > 32      else if (BITS_PER_WORD >= 64 && i == 0)	return GEN_INT ((((HOST_WIDE_INT) k[! WORDS_BIG_ENDIAN]) << 32)			| (HOST_WIDE_INT) k[WORDS_BIG_ENDIAN]);#endif      else if (BITS_PER_WORD == 16)	{	  long value;	  value = k[i >> 1];	  if ((i & 0x1) == 0)	    value >>= 16;	  value &= 0xffff;	  return GEN_INT ((HOST_WIDE_INT) value);	}      else	abort ();    }#else /* no REAL_ARITHMETIC */  if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT	&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)       || flag_pretend_float)      && GET_MODE_CLASS (mode) == MODE_FLOAT      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD      && GET_CODE (op) == CONST_DOUBLE)    {      /* The constant is stored in the host's word-ordering,	 but we want to access it in the target's word-ordering.  Some	 compilers don't like a conditional inside macro args, so we have two	 copies of the return.  */#ifdef HOST_WORDS_BIG_ENDIAN      return GEN_INT (i == WORDS_BIG_ENDIAN		      ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));#else      return GEN_INT (i != WORDS_BIG_ENDIAN		      ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));#endif    }#endif /* no REAL_ARITHMETIC */  /* Single word float is a little harder, since single- and double-word     values often do not have the same high-order bits.  We have already     verified that we want the only defined word of the single-word value.  */#ifdef REAL_ARITHMETIC  if (GET_MODE_CLASS (mode) == MODE_FLOAT      && GET_MODE_BITSIZE (mode) == 32      && GET_CODE (op) == CONST_DOUBLE)    {      long l;      REAL_VALUE_TYPE rv;      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);      REAL_VALUE_TO_TARGET_SINGLE (rv, l);      return GEN_INT ((HOST_WIDE_INT) l);    }#else  if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT	&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)       || flag_pretend_float)      && GET_MODE_CLASS (mode) == MODE_FLOAT      && GET_MODE_SIZE (mode) == UNITS_PER_WORD      && GET_CODE (op) == CONST_DOUBLE)    {      double d;      union {float f; HOST_WIDE_INT i; } u;      REAL_VALUE_FROM_CONST_DOUBLE (d, op);      u.f = d;      return GEN_INT (u.i);    }#endif /* no REAL_ARITHMETIC */        /* The only remaining cases that we can handle are integers.     Convert to proper endianness now since these cases need it.     At this point, i == 0 means the low-order word.       We do not want to handle the case when BITS_PER_WORD <= HOST_BITS_PER_INT     in general.  However, if OP is (const_int 0), we can just return     it for any word.  */  if (op == const0_rtx)    return op;  if (GET_MODE_CLASS (mode) != MODE_INT      || (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE)      || BITS_PER_WORD > HOST_BITS_PER_WIDE_INT)    return 0;  if (WORDS_BIG_ENDIAN)    i = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - i;  /* Find out which word on the host machine this value is in and get     it from the constant.  */  val = (i / size_ratio == 0	 ? (GET_CODE (op) == CONST_INT ? INTVAL (op) : CONST_DOUBLE_LOW (op))	 : (GET_CODE (op) == CONST_INT	    ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op)));  /* If BITS_PER_WORD is smaller than an int, get the appropriate bits.  */  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)    val = ((val >> ((i % size_ratio) * BITS_PER_WORD))	   & (((HOST_WIDE_INT) 1	       << (BITS_PER_WORD % HOST_BITS_PER_WIDE_INT)) - 1));  return GEN_INT (val);}/* Similar to `operand_subword', but never return 0.  If we can't extract   the required subword, put OP into a register and try again.  If that fails,   abort.  We always validate the address in this case.  It is not valid   to call this function after reload; it is mostly meant for RTL   generation.    MODE is the mode of OP, in case it is CONST_INT.  */rtxoperand_subword_force (op, i, mode)     rtx op;     int i;     enum machine_mode mode;{  rtx result = operand_subword (op, i, 1, mode);  if (result)    return result;  if (mode != BLKmode && mode != VOIDmode)    op = force_reg (mode, op);  result = operand_subword (op, i, 1, mode);  if (result == 0)    abort ();  return result;}/* Given a compare instruction, swap the operands.   A test instruction is changed into a compare of 0 against the operand.  */voidreverse_comparison (insn)     rtx insn;{  rtx body = PATTERN (insn);  rtx comp;  if (GET_CODE (body) == SET)    comp = SET_SRC (body);  else    comp = SET_SRC (XVECEXP (body, 0, 0));  if (GET_CODE (comp) == COMPARE)    {      rtx op0 = XEXP (comp, 0);      rtx op1 = XEXP (comp, 1);      XEXP (comp, 0) = op1;      XEXP (comp, 1) = op0;    }  else    {      rtx new = gen_rtx (COMPARE, VOIDmode,			 CONST0_RTX (GET_MODE (comp)), comp);      if (GET_CODE (body) == SET)	SET_SRC (body) = new;      else	SET_SRC (XVECEXP (body, 0, 0)) = new;    }}/* Return a memory reference like MEMREF, but with its mode changed   to MODE and its address changed to ADDR.   (VOIDmode means don't change the mode.   NULL for ADDR means don't change the address.)  */rtxchange_address (memref, mode, addr)     rtx memref;     enum machine_mode mode;     rtx addr;{  rtx new;  if (GET_CODE (memref) != MEM)    abort ();  if (mode == VOIDmode)    mode = GET_MODE (memref);  if (addr == 0)    addr = XEXP (memref, 0);  /* If reload is in progress or has completed, ADDR must be valid.     Otherwise, we can call memory_address to make it valid.  */  if (reload_completed || reload_in_progress)    {      if (! memory_address_p (mode, addr))	abort ();    }  else    addr = memory_address (mode, addr);	  new = gen_rtx (MEM, mode, addr);  MEM_VOLATILE_P (new) = MEM_VOLATILE_P (memref);  RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (memref);  MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (memref);  return new;}/* Return a newly created CODE_LABEL rtx with a unique label number.  */rtxgen_label_rtx (){  register rtx label;  label = (output_bytecode	   ? gen_rtx (CODE_LABEL, VOIDmode, NULL, bc_get_bytecode_label ())	   : gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0, label_num++, NULL_PTR));  LABEL_NUSES (label) = 0;  return label;}/* For procedure integration.  *//* Return a newly created INLINE_HEADER rtx.  Should allocate this   from a permanent obstack when the opportunity arises.  */rtxgen_inline_header_rtx (first_insn, first_parm_insn, first_labelno,		       last_labelno, max_parm_regnum, max_regnum, args_size,		       pops_args, stack_slots, forced_labels, function_flags,		       outgoing_args_size, original_arg_vector,		       original_decl_initial)     rtx first_insn, first_parm_insn;     int first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size;     int pops_args;     rtx stack_slots;     rtx forced_labels;     int function_flags;     int outgoing_args_size;     rtvec original_arg_vector;     rtx original_decl_initial;{  rtx header = gen_rtx (INLINE_HEADER, VOIDmode,			cur_insn_uid++, NULL_RTX,			first_insn, first_parm_insn,			first_labelno, last_labelno,			max_parm_regnum, max_regnum, args_size, pops_args,			stack_slots, forced_labels, function_flags,			outgoing_args_size,			original_arg_vector, original_decl_initial);  return header;}/* Install new pointers to the first and last insns in the chain.   Used for an inline-procedure after copying the insn chain.  */voidset_new_first_and_last_insn (first, last)     rtx first, last;{  first_insn = first;  last_insn = last;}/* Set the range of label numbers found in the current function.   This is used when belatedly compiling an inline function.  */voidset_new_first_and_last_label_num (first, last)     int first, last;{  base_label_num = label_num;  first_label_num = first;  last_label_num = last;}/* Save all variables describing the current status into the structure *P.   This is used before starting a nested function.  */voidsave_emit_status (p)

⌨️ 快捷键说明

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