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

📄 combine.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	     the same INSN_CUID for value tracking.  Our fake I1 will	     never appear in the insn stream so giving it the same INSN_UID	     as I2 will not cause a problem.  */	  subst_prev_insn = i1	    = gen_rtx (INSN, VOIDmode, INSN_UID (i2), NULL_RTX, i2,		       XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX, NULL_RTX);	  SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));	  SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),		 SET_DEST (PATTERN (i1)));	}    }#endif  /* Verify that I2 and I1 are valid for combining.  */  if (! can_combine_p (i2, i3, i1, NULL_RTX, &i2dest, &i2src)      || (i1 && ! can_combine_p (i1, i3, NULL_RTX, i2, &i1dest, &i1src)))    {      undo_all ();      return 0;    }  /* Record whether I2DEST is used in I2SRC and similarly for the other     cases.  Knowing this will help in register status updating below.  */  i2dest_in_i2src = reg_overlap_mentioned_p (i2dest, i2src);  i1dest_in_i1src = i1 && reg_overlap_mentioned_p (i1dest, i1src);  i2dest_in_i1src = i1 && reg_overlap_mentioned_p (i2dest, i1src);  /* See if I1 directly feeds into I3.  It does if I1DEST is not used     in I2SRC.  */  i1_feeds_i3 = i1 && ! reg_overlap_mentioned_p (i1dest, i2src);  /* Ensure that I3's pattern can be the destination of combines.  */  if (! combinable_i3pat (i3, &PATTERN (i3), i2dest, i1dest,			  i1 && i2dest_in_i1src && i1_feeds_i3,			  &i3dest_killed))    {      undo_all ();      return 0;    }  /* See if any of the insns is a MULT operation.  Unless one is, we will     reject a combination that is, since it must be slower.  Be conservative     here.  */  if (GET_CODE (i2src) == MULT      || (i1 != 0 && GET_CODE (i1src) == MULT)      || (GET_CODE (PATTERN (i3)) == SET	  && GET_CODE (SET_SRC (PATTERN (i3))) == MULT))    have_mult = 1;  /* If I3 has an inc, then give up if I1 or I2 uses the reg that is inc'd.     We used to do this EXCEPT in one case: I3 has a post-inc in an     output operand.  However, that exception can give rise to insns like     	mov r3,(r3)+     which is a famous insn on the PDP-11 where the value of r3 used as the     source was model-dependent.  Avoid this sort of thing.  */#if 0  if (!(GET_CODE (PATTERN (i3)) == SET	&& GET_CODE (SET_SRC (PATTERN (i3))) == REG	&& GET_CODE (SET_DEST (PATTERN (i3))) == MEM	&& (GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_INC	    || GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC)))    /* It's not the exception.  */#endif#ifdef AUTO_INC_DEC    for (link = REG_NOTES (i3); link; link = XEXP (link, 1))      if (REG_NOTE_KIND (link) == REG_INC	  && (reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i2))	      || (i1 != 0		  && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i1)))))	{	  undo_all ();	  return 0;	}#endif  /* See if the SETs in I1 or I2 need to be kept around in the merged     instruction: whenever the value set there is still needed past I3.     For the SETs in I2, this is easy: we see if I2DEST dies or is set in I3.     For the SET in I1, we have two cases:  If I1 and I2 independently     feed into I3, the set in I1 needs to be kept around if I1DEST dies     or is set in I3.  Otherwise (if I1 feeds I2 which feeds I3), the set     in I1 needs to be kept around unless I1DEST dies or is set in either     I2 or I3.  We can distinguish these cases by seeing if I2SRC mentions     I1DEST.  If so, we know I1 feeds into I2.  */  added_sets_2 = ! dead_or_set_p (i3, i2dest);  added_sets_1    = i1 && ! (i1_feeds_i3 ? dead_or_set_p (i3, i1dest)	       : (dead_or_set_p (i3, i1dest) || dead_or_set_p (i2, i1dest)));  /* If the set in I2 needs to be kept around, we must make a copy of     PATTERN (I2), so that when we substitute I1SRC for I1DEST in     PATTERN (I2), we are only substituting for the original I1DEST, not into     an already-substituted copy.  This also prevents making self-referential     rtx.  If I2 is a PARALLEL, we just need the piece that assigns I2SRC to     I2DEST.  */  i2pat = (GET_CODE (PATTERN (i2)) == PARALLEL	   ? gen_rtx (SET, VOIDmode, i2dest, i2src)	   : PATTERN (i2));  if (added_sets_2)    i2pat = copy_rtx (i2pat);  combine_merges++;  /* Substitute in the latest insn for the regs set by the earlier ones.  */  maxreg = max_reg_num ();  subst_insn = i3;  /* It is possible that the source of I2 or I1 may be performing an     unneeded operation, such as a ZERO_EXTEND of something that is known     to have the high part zero.  Handle that case by letting subst look at     the innermost one of them.     Another way to do this would be to have a function that tries to     simplify a single insn instead of merging two or more insns.  We don't     do this because of the potential of infinite loops and because     of the potential extra memory required.  However, doing it the way     we are is a bit of a kludge and doesn't catch all cases.     But only do this if -fexpensive-optimizations since it slows things down     and doesn't usually win.  */  if (flag_expensive_optimizations)    {      /* Pass pc_rtx so no substitutions are done, just simplifications.	 The cases that we are interested in here do not involve the few	 cases were is_replaced is checked.  */      if (i1)	{	  subst_low_cuid = INSN_CUID (i1);	  i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);	}      else	{	  subst_low_cuid = INSN_CUID (i2);	  i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);	}      undobuf.previous_undos = undobuf.undos;    }#ifndef HAVE_cc0  /* Many machines that don't use CC0 have insns that can both perform an     arithmetic operation and set the condition code.  These operations will     be represented as a PARALLEL with the first element of the vector     being a COMPARE of an arithmetic operation with the constant zero.     The second element of the vector will set some pseudo to the result     of the same arithmetic operation.  If we simplify the COMPARE, we won't     match such a pattern and so will generate an extra insn.   Here we test     for this case, where both the comparison and the operation result are     needed, and make the PARALLEL by just replacing I2DEST in I3SRC with     I2SRC.  Later we will make the PARALLEL that contains I2.  */  if (i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET      && GET_CODE (SET_SRC (PATTERN (i3))) == COMPARE      && XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx      && rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))    {      rtx *cc_use;      enum machine_mode compare_mode;      newpat = PATTERN (i3);      SUBST (XEXP (SET_SRC (newpat), 0), i2src);      i2_is_used = 1;#ifdef EXTRA_CC_MODES      /* See if a COMPARE with the operand we substituted in should be done	 with the mode that is currently being used.  If not, do the same	 processing we do in `subst' for a SET; namely, if the destination	 is used only once, try to replace it with a register of the proper	 mode and also replace the COMPARE.  */      if (undobuf.other_insn == 0	  && (cc_use = find_single_use (SET_DEST (newpat), i3,					&undobuf.other_insn))	  && ((compare_mode = SELECT_CC_MODE (GET_CODE (*cc_use),					      i2src, const0_rtx))	      != GET_MODE (SET_DEST (newpat))))	{	  int regno = REGNO (SET_DEST (newpat));	  rtx new_dest = gen_rtx (REG, compare_mode, regno);	  if (regno < FIRST_PSEUDO_REGISTER	      || (REG_N_SETS (regno) == 1 && ! added_sets_2		  && ! REG_USERVAR_P (SET_DEST (newpat))))	    {	      if (regno >= FIRST_PSEUDO_REGISTER)		SUBST (regno_reg_rtx[regno], new_dest);	      SUBST (SET_DEST (newpat), new_dest);	      SUBST (XEXP (*cc_use, 0), new_dest);	      SUBST (SET_SRC (newpat),		     gen_rtx_combine (COMPARE, compare_mode,				      i2src, const0_rtx));	    }	  else	    undobuf.other_insn = 0;	}#endif	      }  else#endif    {      n_occurrences = 0;		/* `subst' counts here */      /* If I1 feeds into I2 (not into I3) and I1DEST is in I1SRC, we	 need to make a unique copy of I2SRC each time we substitute it	 to avoid self-referential rtl.  */      subst_low_cuid = INSN_CUID (i2);      newpat = subst (PATTERN (i3), i2dest, i2src, 0,		      ! i1_feeds_i3 && i1dest_in_i1src);      undobuf.previous_undos = undobuf.undos;      /* Record whether i2's body now appears within i3's body.  */      i2_is_used = n_occurrences;    }  /* If we already got a failure, don't try to do more.  Otherwise,     try to substitute in I1 if we have it.  */  if (i1 && GET_CODE (newpat) != CLOBBER)    {      /* Before we can do this substitution, we must redo the test done	 above (see detailed comments there) that ensures  that I1DEST	 isn't mentioned in any SETs in NEWPAT that are field assignments.  */      if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,			      0, NULL_PTR))	{	  undo_all ();	  return 0;	}      n_occurrences = 0;      subst_low_cuid = INSN_CUID (i1);      newpat = subst (newpat, i1dest, i1src, 0, 0);      undobuf.previous_undos = undobuf.undos;    }  /* Fail if an autoincrement side-effect has been duplicated.  Be careful     to count all the ways that I2SRC and I1SRC can be used.  */  if ((FIND_REG_INC_NOTE (i2, NULL_RTX) != 0       && i2_is_used + added_sets_2 > 1)      || (i1 != 0 && FIND_REG_INC_NOTE (i1, NULL_RTX) != 0	  && (n_occurrences + added_sets_1 + (added_sets_2 && ! i1_feeds_i3)	      > 1))      /* Fail if we tried to make a new register (we used to abort, but there's	 really no reason to).  */      || max_reg_num () != maxreg      /* Fail if we couldn't do something and have a CLOBBER.  */      || GET_CODE (newpat) == CLOBBER      /* Fail if this new pattern is a MULT and we didn't have one before	 at the outer level.  */      || (GET_CODE (newpat) == SET && GET_CODE (SET_SRC (newpat)) == MULT	  && ! have_mult))    {      undo_all ();      return 0;    }  /* If the actions of the earlier insns must be kept     in addition to substituting them into the latest one,     we must make a new PARALLEL for the latest insn     to hold additional the SETs.  */  if (added_sets_1 || added_sets_2)    {      combine_extras++;      if (GET_CODE (newpat) == PARALLEL)	{	  rtvec old = XVEC (newpat, 0);	  total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2;	  newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets));	  bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem,		 sizeof (old->elem[0]) * old->num_elem);	}      else	{	  rtx old = newpat;	  total_sets = 1 + added_sets_1 + added_sets_2;	  newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets));	  XVECEXP (newpat, 0, 0) = old;	}     if (added_sets_1)       XVECEXP (newpat, 0, --total_sets)	 = (GET_CODE (PATTERN (i1)) == PARALLEL	    ? gen_rtx (SET, VOIDmode, i1dest, i1src) : PATTERN (i1));     if (added_sets_2)	{	  /* If there is no I1, use I2's body as is.  We used to also not do	     the subst call below if I2 was substituted into I3,	     but that could lose a simplification.  */	  if (i1 == 0)	    XVECEXP (newpat, 0, --total_sets) = i2pat;	  else	    /* See comment where i2pat is assigned.  */	    XVECEXP (newpat, 0, --total_sets)	      = subst (i2pat, i1dest, i1src, 0, 0);	}    }  /* We come here when we are replacing a destination in I2 with the     destination of I3.  */ validate_replacement:  /* Note which hard regs this insn has as inputs.  */  mark_used_regs_combine (newpat);  /* Is the result of combination a valid instruction?  */  insn_code_number    = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);  /* If the result isn't valid, see if it is a PARALLEL of two SETs where     the second SET's destination is a register that is unused.  In that case,     we just need the first SET.   This can occur when simplifying a divmod     insn.  We *must* test for this case here because the code below that     splits two independent SETs doesn't handle this case correctly when it     updates the register status.  Also check the case where the first     SET's destination is unused.  That would not cause incorrect code, but     does cause an unneeded insn to remain.  */  if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL      && XVECLEN (newpat, 0) == 2      && GET_CODE (XVECEXP (newpat, 0, 0)) == SET      && GET_CODE (XVECEXP (newpat, 0, 1)) == SET      && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == REG      && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 1)))      && ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 1)))      && asm_noperands (newpat) < 0)    {      newpat = XVECEXP (newpat, 0, 0);      insn_code_number	= recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);    }  else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL	   && XVECLEN (newpat, 0) == 2	   && GET_CODE (XVECEXP (newpat, 0, 0)) == SET	   && GET_CODE (XVECEXP (newpat, 0, 1)) == SET	   && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) == REG	   && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 0)))	   && ! s

⌨️ 快捷键说明

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