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

📄 reorg.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    {      rtx temp = PREV_INSN (PREV_INSN (insn));      end_of_function_label = gen_label_rtx ();      LABEL_NUSES (end_of_function_label) = 0;      /* Put the label before an USE insns that may proceed the RETURN insn.  */      while (GET_CODE (temp) == USE)	temp = PREV_INSN (temp);      emit_label_after (end_of_function_label, temp);    }  else if (GET_CODE (insn) == CODE_LABEL)    end_of_function_label = insn;  else    {      /* Otherwise, make a new label and emit a RETURN and BARRIER,	 if needed.  */      end_of_function_label = gen_label_rtx ();      LABEL_NUSES (end_of_function_label) = 0;      emit_label (end_of_function_label);#ifdef HAVE_return      if (HAVE_return)	{	  /* The return we make may have delay slots too.  */	  rtx insn = gen_return ();	  insn = emit_jump_insn (insn);	  emit_barrier ();          if (num_delay_slots (insn) > 0)	    obstack_ptr_grow (&unfilled_slots_obstack, insn);	}#endif    }  /* Show one additional use for this label so it won't go away until     we are done.  */  ++LABEL_NUSES (end_of_function_label);  return end_of_function_label;}/* Put INSN and LIST together in a SEQUENCE rtx of LENGTH, and replace   the pattern of INSN with the SEQUENCE.   Chain the insns so that NEXT_INSN of each insn in the sequence points to   the next and NEXT_INSN of the last insn in the sequence points to   the first insn after the sequence.  Similarly for PREV_INSN.  This makes   it easier to scan all insns.   Returns the SEQUENCE that replaces INSN.  */static rtxemit_delay_sequence (insn, list, length, avail)     rtx insn;     rtx list;     int length;     int avail;{  register int i = 1;  register rtx li;  int had_barrier = 0;  /* Allocate the the rtvec to hold the insns and the SEQUENCE.  */  rtvec seqv = rtvec_alloc (length + 1);  rtx seq = gen_rtx (SEQUENCE, VOIDmode, seqv);  rtx seq_insn = make_insn_raw (seq);  rtx first = get_insns ();  rtx last = get_last_insn ();  /* Make a copy of the insn having delay slots.  */  rtx delay_insn = copy_rtx (insn);  /* If INSN is followed by a BARRIER, delete the BARRIER since it will only     confuse further processing.  Update LAST in case it was the last insn.       We will put the BARRIER back in later.  */  if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == BARRIER)    {      delete_insn (NEXT_INSN (insn));      last = get_last_insn ();      had_barrier = 1;    }  /* Splice our SEQUENCE into the insn stream where INSN used to be.  */  NEXT_INSN (seq_insn) = NEXT_INSN (insn);  PREV_INSN (seq_insn) = PREV_INSN (insn);  if (insn != last)    PREV_INSN (NEXT_INSN (seq_insn)) = seq_insn;  if (insn != first)    NEXT_INSN (PREV_INSN (seq_insn)) = seq_insn;  /* Note the calls to set_new_first_and_last_insn must occur after     SEQ_INSN has been completely spliced into the insn stream.     Otherwise CUR_INSN_UID will get set to an incorrect value because     set_new_first_and_last_insn will not find SEQ_INSN in the chain.  */  if (insn == last)    set_new_first_and_last_insn (first, seq_insn);  if (insn == first)    set_new_first_and_last_insn (seq_insn, last);  /* Build our SEQUENCE and rebuild the insn chain.  */  XVECEXP (seq, 0, 0) = delay_insn;  INSN_DELETED_P (delay_insn) = 0;  PREV_INSN (delay_insn) = PREV_INSN (seq_insn);  for (li = list; li; li = XEXP (li, 1), i++)    {      rtx tem = XEXP (li, 0);      rtx note;      /* Show that this copy of the insn isn't deleted.  */      INSN_DELETED_P (tem) = 0;      XVECEXP (seq, 0, i) = tem;      PREV_INSN (tem) = XVECEXP (seq, 0, i - 1);      NEXT_INSN (XVECEXP (seq, 0, i - 1)) = tem;      /* Remove any REG_DEAD notes because we can't rely on them now	 that the insn has been moved.  */      for (note = REG_NOTES (tem); note; note = XEXP (note, 1))	if (REG_NOTE_KIND (note) == REG_DEAD)	  XEXP (note, 0) = const0_rtx;    }  NEXT_INSN (XVECEXP (seq, 0, length)) = NEXT_INSN (seq_insn);  /* If the previous insn is a SEQUENCE, update the NEXT_INSN pointer on the     last insn in that SEQUENCE to point to us.  Similarly for the first     insn in the following insn if it is a SEQUENCE.  */  if (PREV_INSN (seq_insn) && GET_CODE (PREV_INSN (seq_insn)) == INSN      && GET_CODE (PATTERN (PREV_INSN (seq_insn))) == SEQUENCE)    NEXT_INSN (XVECEXP (PATTERN (PREV_INSN (seq_insn)), 0,			XVECLEN (PATTERN (PREV_INSN (seq_insn)), 0) - 1))      = seq_insn;  if (NEXT_INSN (seq_insn) && GET_CODE (NEXT_INSN (seq_insn)) == INSN      && GET_CODE (PATTERN (NEXT_INSN (seq_insn))) == SEQUENCE)    PREV_INSN (XVECEXP (PATTERN (NEXT_INSN (seq_insn)), 0, 0)) = seq_insn;      /* If there used to be a BARRIER, put it back.  */  if (had_barrier)    emit_barrier_after (seq_insn);  if (i != length + 1)    abort ();  return seq_insn;}/* Add INSN to DELAY_LIST and return the head of the new list.  The list must   be in the order in which the insns are to be executed.  */static rtxadd_to_delay_list (insn, delay_list)     rtx insn;     rtx delay_list;{  /* If we have an empty list, just make a new list element.  If     INSN has it's block number recorded, clear it since we may     be moving the insn to a new block.  */  if (delay_list == 0)    {      struct target_info *tinfo;            for (tinfo = target_hash_table[INSN_UID (insn) % TARGET_HASH_PRIME];	   tinfo; tinfo = tinfo->next)	if (tinfo->uid == INSN_UID (insn))	  break;      if (tinfo)	tinfo->block = -1;      return gen_rtx (INSN_LIST, VOIDmode, insn, NULL_RTX);    }  /* Otherwise this must be an INSN_LIST.  Add INSN to the end of the     list.  */  XEXP (delay_list, 1) = add_to_delay_list (insn, XEXP (delay_list, 1));  return delay_list;}   /* Delete INSN from the the delay slot of the insn that it is in.  This may   produce an insn without anything in its delay slots.  */static voiddelete_from_delay_slot (insn)     rtx insn;{  rtx trial, seq_insn, seq, prev;  rtx delay_list = 0;  int i;  /* We first must find the insn containing the SEQUENCE with INSN in its     delay slot.  Do this by finding an insn, TRIAL, where     PREV_INSN (NEXT_INSN (TRIAL)) != TRIAL.  */  for (trial = insn;       PREV_INSN (NEXT_INSN (trial)) == trial;       trial = NEXT_INSN (trial))    ;  seq_insn = PREV_INSN (NEXT_INSN (trial));  seq = PATTERN (seq_insn);  /* Create a delay list consisting of all the insns other than the one     we are deleting (unless we were the only one).  */  if (XVECLEN (seq, 0) > 2)    for (i = 1; i < XVECLEN (seq, 0); i++)      if (XVECEXP (seq, 0, i) != insn)	delay_list = add_to_delay_list (XVECEXP (seq, 0, i), delay_list);  /* Delete the old SEQUENCE, re-emit the insn that used to have the delay     list, and rebuild the delay list if non-empty.  */  prev = PREV_INSN (seq_insn);  trial = XVECEXP (seq, 0, 0);  delete_insn (seq_insn);  add_insn_after (trial, prev);  if (GET_CODE (trial) == JUMP_INSN      && (simplejump_p (trial) || GET_CODE (PATTERN (trial)) == RETURN))    emit_barrier_after (trial);  /* If there are any delay insns, remit them.  Otherwise clear the     annul flag.  */  if (delay_list)    trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2, 0);  else    INSN_ANNULLED_BRANCH_P (trial) = 0;  INSN_FROM_TARGET_P (insn) = 0;  /* Show we need to fill this insn again.  */  obstack_ptr_grow (&unfilled_slots_obstack, trial);}/* Delete INSN, a JUMP_INSN.  If it is a conditional jump, we must track down   the insn that sets CC0 for it and delete it too.  */static voiddelete_scheduled_jump (insn)     rtx insn;{  /* Delete the insn that sets cc0 for us.  On machines without cc0, we could     delete the insn that sets the condition code, but it is hard to find it.     Since this case is rare anyway, don't bother trying; there would likely     be other insns that became dead anyway, which we wouldn't know to     delete.  */#ifdef HAVE_cc0  if (reg_mentioned_p (cc0_rtx, insn))    {      rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);      /* If a reg-note was found, it points to an insn to set CC0.  This	 insn is in the delay list of some other insn.  So delete it from	 the delay list it was in.  */      if (note)	{	  if (! FIND_REG_INC_NOTE (XEXP (note, 0), NULL_RTX)	      && sets_cc0_p (PATTERN (XEXP (note, 0))) == 1)	    delete_from_delay_slot (XEXP (note, 0));	}      else	{	  /* The insn setting CC0 is our previous insn, but it may be in	     a delay slot.  It will be the last insn in the delay slot, if	     it is.  */	  rtx trial = previous_insn (insn);	  if (GET_CODE (trial) == NOTE)	    trial = prev_nonnote_insn (trial);	  if (sets_cc0_p (PATTERN (trial)) != 1	      || FIND_REG_INC_NOTE (trial, 0))	    return;	  if (PREV_INSN (NEXT_INSN (trial)) == trial)	    delete_insn (trial);	  else	    delete_from_delay_slot (trial);	}    }#endif  delete_insn (insn);}/* Counters for delay-slot filling.  */#define NUM_REORG_FUNCTIONS 2#define MAX_DELAY_HISTOGRAM 3#define MAX_REORG_PASSES 2static int num_insns_needing_delays[NUM_REORG_FUNCTIONS][MAX_REORG_PASSES];static int num_filled_delays[NUM_REORG_FUNCTIONS][MAX_DELAY_HISTOGRAM+1][MAX_REORG_PASSES];static int reorg_pass_number;static voidnote_delay_statistics (slots_filled, index)     int slots_filled, index;{  num_insns_needing_delays[index][reorg_pass_number]++;  if (slots_filled > MAX_DELAY_HISTOGRAM)    slots_filled = MAX_DELAY_HISTOGRAM;  num_filled_delays[index][slots_filled][reorg_pass_number]++;}#if defined(ANNUL_IFFALSE_SLOTS) || defined(ANNUL_IFTRUE_SLOTS)/* Optimize the following cases:   1.  When a conditional branch skips over only one instruction,       use an annulling branch and put that insn in the delay slot.       Use either a branch that annuls when the condition if true or       invert the test with a branch that annuls when the condition is       false.  This saves insns, since otherwise we must copy an insn       from the L1 target.        (orig)		 (skip)		(otherwise)	Bcc.n L1	Bcc',a L1	Bcc,a L1'	insn		insn		insn2      L1:	      L1:	      L1:	insn2		insn2		insn2	insn3		insn3	      L1':					insn3   2.  When a conditional branch skips over only one instruction,       and after that, it unconditionally branches somewhere else,       perform the similar optimization. This saves executing the       second branch in the case where the inverted condition is true.	Bcc.n L1	Bcc',a L2	insn		insn      L1:	      L1:	Bra L2		Bra L2   INSN is a JUMP_INSN.   This should be expanded to skip over N insns, where N is the number   of delay slots required.  */static rtxoptimize_skip (insn)     register rtx insn;{  register rtx trial = next_nonnote_insn (insn);  rtx next_trial = next_active_insn (trial);  rtx delay_list = 0;  rtx target_label;  int flags;  flags = get_jump_flags (insn, JUMP_LABEL (insn));  if (trial == 0      || GET_CODE (trial) != INSN      || GET_CODE (PATTERN (trial)) == SEQUENCE      || recog_memoized (trial) < 0      || (! eligible_for_annul_false (insn, 0, trial, flags)	  && ! eligible_for_annul_true (insn, 0, trial, flags)))    return 0;  /* There are two cases where we are just executing one insn (we assume     here that a branch requires only one insn; this should be generalized     at some point):  Where the branch goes around a single insn or where     we have one insn followed by a branch to the same label we branch to.     In both of these cases, inverting the jump and annulling the delay     slot give the same effect in fewer insns.  */  if ((next_trial == next_active_insn (JUMP_LABEL (insn)))      || (next_trial != 0	  && GET_CODE (next_trial) == JUMP_INSN	  && JUMP_LABEL (insn) == JUMP_LABEL (next_trial)	  && (simplejump_p (next_trial)	      || GET_CODE (PATTERN (next_trial)) == RETURN)))    {      if (eligible_for_annul_false (insn, 0, trial, flags))	{	  if (invert_jump (insn, JUMP_LABEL (insn)))	    INSN_FROM_TARGET_P (trial) = 1;	  else if (! eligible_for_annul_true (insn, 0, trial, flags))	    return 0;	}      delay_list = add_to_delay_list (trial, NULL_RTX);      next_trial = next_active_insn (trial);      update_block (trial, trial);      delete_insn (trial);      /* Also, if we are targeting an unconditional	 branch, thread our jump to the target of that branch.  Don't	 change this into a RETURN here, because it may not accept what	 we have in the delay slot.  We'll fix this up later.  */      if (next_trial && GET_CODE (next_trial) == JUMP_INSN	  && (simplejump_p (next_trial)	      || GET_CODE (PATTERN (next_trial)) == RETURN))	{	  target_label = JUMP_LABEL (next_trial);	  if (target_label == 0)	    target_label = find_end_label ();	  /* Recompute the flags based on TARGET_LABEL since threading

⌨️ 快捷键说明

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