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

📄 combine.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
}/* Called via note_stores.  If X is a pseudo that is narrower than   HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero.   If we are setting only a portion of X and we can't figure out what   portion, assume all bits will be used since we don't know what will   be happening.   Similarly, set how many bits of X are known to be copies of the sign bit   at all locations in the function.  This is the smallest number implied    by any set of X.  */static voidset_nonzero_bits_and_sign_copies (x, set)     rtx x;     rtx set;{  int num;  if (GET_CODE (x) == REG      && REGNO (x) >= FIRST_PSEUDO_REGISTER      /* If this register is undefined at the start of the file, we can't	 say what its contents were.  */      && ! REGNO_REG_SET_P (basic_block_live_at_start[0], REGNO (x))      && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)    {      if (set == 0 || GET_CODE (set) == CLOBBER)	{	  reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));	  reg_sign_bit_copies[REGNO (x)] = 1;	  return;	}      /* If this is a complex assignment, see if we can convert it into a	 simple assignment.  */      set = expand_field_assignment (set);      /* If this is a simple assignment, or we have a paradoxical SUBREG,	 set what we know about X.  */      if (SET_DEST (set) == x	  || (GET_CODE (SET_DEST (set)) == SUBREG	      && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))		  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (set)))))	      && SUBREG_REG (SET_DEST (set)) == x))	{	  rtx src = SET_SRC (set);#ifdef SHORT_IMMEDIATES_SIGN_EXTEND	  /* If X is narrower than a word and SRC is a non-negative	     constant that would appear negative in the mode of X,	     sign-extend it for use in reg_nonzero_bits because some	     machines (maybe most) will actually do the sign-extension	     and this is the conservative approach. 	     ??? For 2.5, try to tighten up the MD files in this regard	     instead of this kludge.  */	  if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD	      && GET_CODE (src) == CONST_INT	      && INTVAL (src) > 0	      && 0 != (INTVAL (src)		       & ((HOST_WIDE_INT) 1			  << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))	    src = GEN_INT (INTVAL (src)			   | ((HOST_WIDE_INT) (-1)			      << GET_MODE_BITSIZE (GET_MODE (x))));#endif	  reg_nonzero_bits[REGNO (x)]	    |= nonzero_bits (src, nonzero_bits_mode);	  num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));	  if (reg_sign_bit_copies[REGNO (x)] == 0	      || reg_sign_bit_copies[REGNO (x)] > num)	    reg_sign_bit_copies[REGNO (x)] = num;	}      else	{	  reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));	  reg_sign_bit_copies[REGNO (x)] = 1;	}    }}/* See if INSN can be combined into I3.  PRED and SUCC are optionally   insns that were previously combined into I3 or that will be combined   into the merger of INSN and I3.   Return 0 if the combination is not allowed for any reason.   If the combination is allowed, *PDEST will be set to the single    destination of INSN and *PSRC to the single source, and this function   will return 1.  */static intcan_combine_p (insn, i3, pred, succ, pdest, psrc)     rtx insn;     rtx i3;     rtx pred, succ;     rtx *pdest, *psrc;{  int i;  rtx set = 0, src, dest;  rtx p, link;  int all_adjacent = (succ ? (next_active_insn (insn) == succ			      && next_active_insn (succ) == i3)		      : next_active_insn (insn) == i3);  /* Can combine only if previous insn is a SET of a REG, a SUBREG or CC0.     or a PARALLEL consisting of such a SET and CLOBBERs.      If INSN has CLOBBER parallel parts, ignore them for our processing.     By definition, these happen during the execution of the insn.  When it     is merged with another insn, all bets are off.  If they are, in fact,     needed and aren't also supplied in I3, they may be added by     recog_for_combine.  Otherwise, it won't match.      We can also ignore a SET whose SET_DEST is mentioned in a REG_UNUSED     note.     Get the source and destination of INSN.  If more than one, can't      combine.  */       if (GET_CODE (PATTERN (insn)) == SET)    set = PATTERN (insn);  else if (GET_CODE (PATTERN (insn)) == PARALLEL	   && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)    {      for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)	{	  rtx elt = XVECEXP (PATTERN (insn), 0, i);	  switch (GET_CODE (elt))	    {	      /* We can ignore CLOBBERs.  */	    case CLOBBER:	      break;	    case SET:	      /* Ignore SETs whose result isn't used but not those that		 have side-effects.  */	      if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt))		  && ! side_effects_p (elt))		break;	      /* If we have already found a SET, this is a second one and		 so we cannot combine with this insn.  */	      if (set)		return 0;	      set = elt;	      break;	    default:	      /* Anything else means we can't combine.  */	      return 0;	    }	}      if (set == 0	  /* If SET_SRC is an ASM_OPERANDS we can't throw away these CLOBBERs,	     so don't do anything with it.  */	  || GET_CODE (SET_SRC (set)) == ASM_OPERANDS)	return 0;    }  else    return 0;  if (set == 0)    return 0;  set = expand_field_assignment (set);  src = SET_SRC (set), dest = SET_DEST (set);  /* Don't eliminate a store in the stack pointer.  */  if (dest == stack_pointer_rtx      /* If we couldn't eliminate a field assignment, we can't combine.  */      || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART      /* Don't combine with an insn that sets a register to itself if it has	 a REG_EQUAL note.  This may be part of a REG_NO_CONFLICT sequence.  */      || (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))      /* Can't merge a function call.  */      || GET_CODE (src) == CALL      /* Don't eliminate a function call argument.  */      || (GET_CODE (i3) == CALL_INSN	  && (find_reg_fusage (i3, USE, dest)	      || (GET_CODE (dest) == REG		  && REGNO (dest) < FIRST_PSEUDO_REGISTER		  && global_regs[REGNO (dest)])))      /* Don't substitute into an incremented register.  */      || FIND_REG_INC_NOTE (i3, dest)      || (succ && FIND_REG_INC_NOTE (succ, dest))      /* Don't combine the end of a libcall into anything.  */      || find_reg_note (insn, REG_RETVAL, NULL_RTX)      /* Make sure that DEST is not used after SUCC but before I3.  */      || (succ && ! all_adjacent	  && reg_used_between_p (dest, succ, i3))      /* Make sure that the value that is to be substituted for the register	 does not use any registers whose values alter in between.  However,	 If the insns are adjacent, a use can't cross a set even though we	 think it might (this can happen for a sequence of insns each setting	 the same destination; reg_last_set of that register might point to	 a NOTE).  If INSN has a REG_EQUIV note, the register is always	 equivalent to the memory so the substitution is valid even if there	 are intervening stores.  Also, don't move a volatile asm or	 UNSPEC_VOLATILE across any other insns.  */      || (! all_adjacent	  && (((GET_CODE (src) != MEM		|| ! find_reg_note (insn, REG_EQUIV, src))	       && use_crosses_set_p (src, INSN_CUID (insn)))	      || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))	      || GET_CODE (src) == UNSPEC_VOLATILE))      /* If there is a REG_NO_CONFLICT note for DEST in I3 or SUCC, we get	 better register allocation by not doing the combine.  */      || find_reg_note (i3, REG_NO_CONFLICT, dest)      || (succ && find_reg_note (succ, REG_NO_CONFLICT, dest))      /* Don't combine across a CALL_INSN, because that would possibly	 change whether the life span of some REGs crosses calls or not,	 and it is a pain to update that information.	 Exception: if source is a constant, moving it later can't hurt.	 Accept that special case, because it helps -fforce-addr a lot.  */      || (INSN_CUID (insn) < last_call_cuid && ! CONSTANT_P (src)))    return 0;  /* DEST must either be a REG or CC0.  */  if (GET_CODE (dest) == REG)    {      /* If register alignment is being enforced for multi-word items in all	 cases except for parameters, it is possible to have a register copy	 insn referencing a hard register that is not allowed to contain the	 mode being copied and which would not be valid as an operand of most	 insns.  Eliminate this problem by not combining with such an insn.	 Also, on some machines we don't want to extend the life of a hard	 register.	 This is the same test done in can_combine except that we don't test	 if SRC is a CALL operation to permit a hard register with	 SMALL_REGISTER_CLASSES, and that we have to take all_adjacent	 into account.  */      if (GET_CODE (src) == REG	  && ((REGNO (dest) < FIRST_PSEUDO_REGISTER	       && ! HARD_REGNO_MODE_OK (REGNO (dest), GET_MODE (dest)))	      /* Don't extend the life of a hard register unless it is		 user variable (if we have few registers) or it can't		 fit into the desired register (meaning something special		 is going on).		 Also avoid substituting a return register into I3, because		 reload can't handle a conflict with constraints of other		 inputs.  */	      || (REGNO (src) < FIRST_PSEUDO_REGISTER		  && (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))		      || (SMALL_REGISTER_CLASSES			  && ((! all_adjacent && ! REG_USERVAR_P (src))			      || (FUNCTION_VALUE_REGNO_P (REGNO (src))				  && ! REG_USERVAR_P (src))))))))	return 0;    }  else if (GET_CODE (dest) != CC0)    return 0;  /* Don't substitute for a register intended as a clobberable operand.     Similarly, don't substitute an expression containing a register that     will be clobbered in I3.  */  if (GET_CODE (PATTERN (i3)) == PARALLEL)    for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)      if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER	  && (reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0),				       src)	      || rtx_equal_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), dest)))	return 0;  /* If INSN contains anything volatile, or is an `asm' (whether volatile     or not), reject, unless nothing volatile comes between it and I3,     with the exception of SUCC.  */  if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src))    for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))      if (GET_RTX_CLASS (GET_CODE (p)) == 'i'	  && p != succ && volatile_refs_p (PATTERN (p)))	return 0;  /* If there are any volatile insns between INSN and I3, reject, because     they might affect machine state.  */  for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))    if (GET_RTX_CLASS (GET_CODE (p)) == 'i'	&& p != succ && volatile_insn_p (PATTERN (p)))      return 0;  /* If INSN or I2 contains an autoincrement or autodecrement,     make sure that register is not used between there and I3,     and not already used in I3 either.     Also insist that I3 not be a jump; if it were one     and the incremented register were spilled, we would lose.  */#ifdef AUTO_INC_DEC  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))    if (REG_NOTE_KIND (link) == REG_INC	&& (GET_CODE (i3) == JUMP_INSN	    || reg_used_between_p (XEXP (link, 0), insn, i3)	    || reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3))))      return 0;#endif#ifdef HAVE_cc0  /* Don't combine an insn that follows a CC0-setting insn.     An insn that uses CC0 must not be separated from the one that sets it.     We do, however, allow I2 to follow a CC0-setting insn if that insn     is passed as I1; in that case it will be deleted also.     We also allow combining in this case if all the insns are adjacent     because that would leave the two CC0 insns adjacent as well.     It would be more logical to test whether CC0 occurs inside I1 or I2,     but that would be much slower, and this ought to be equivalent.  */  p = prev_nonnote_insn (insn);  if (p && p != pred && GET_CODE (p) == INSN && sets_cc0_p (PATTERN (p))      && ! all_adjacent)    return 0;#endif  /* If we get here, we have passed all the tests and the combination is     to be allowed.  */  *pdest = dest;  *psrc = src;  return 1;}/* Check if PAT is an insn - or a part of it - used to set up an   argument for a function in a hard register.  */static intsets_function_arg_p (pat)     rtx pat;{  int i;  rtx inner_dest;  switch (GET_CODE (pat))    {    case INSN:      return sets_function_arg_p (PATTERN (pat));    case PARALLEL:      for (i = XVECLEN (pat, 0); --i >= 0;)	if (sets_function_arg_p (XVECEXP (pat, 0, i)))	  return 1;      break;    case SET:      inner_dest = SET_DEST (pat);      while (GET_CODE (inner_dest) == STRICT_LOW_PART	     || GET_CODE (inner_dest) == SUBREG	     || GET_CODE (inner_dest) == ZERO_EXTRACT)

⌨️ 快捷键说明

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