rtx copy = 0;
rtx copy = 0, first_copy = 0;
duplicate_loop_exit_test (loop_start)     rtx loop_start;{  rtx insn, set, reg, p, link;  rtx copy = 0;  int num_insns = 0;  rtx exitcode = NEXT_INSN (JUMP_LABEL (next_nonnote_insn (loop_start)));  rtx lastexit;  int max_reg = max_reg_num ();  rtx *reg_map = 0;  /* Scan the exit code.  We do not perform this optimization if any insn:         is a CALL_INSN	 is a CODE_LABEL	 has a REG_RETVAL or REG_LIBCALL note (hard to adjust)	 is a NOTE_INSN_LOOP_BEG because this means we have a nested loop	 is a NOTE_INSN_BLOCK_{BEG,END} because duplicating these notes	      is not valid.     We also do not do this if we find an insn with ASM_OPERANDS.  While     this restriction should not be necessary, copying an insn with     ASM_OPERANDS can confuse asm_noperands in some cases.     Also, don't do this if the exit code is more than 20 insns.  */  for (insn = exitcode;       insn       && ! (GET_CODE (insn) == NOTE	     && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END);       insn = NEXT_INSN (insn))    {      switch (GET_CODE (insn))	{	case CODE_LABEL:	case CALL_INSN:	  return 0;	case NOTE:	  /* We could be in front of the wrong NOTE_INSN_LOOP_END if there is	     a jump immediately after the loop start that branches outside	     the loop but within an outer loop, near the exit test.	     If we copied this exit test and created a phony	     NOTE_INSN_LOOP_VTOP, this could make instructions immediately	     before the exit test look like these could be safely moved	     out of the loop even if they actually may be never executed.	     This can be avoided by checking here for NOTE_INSN_LOOP_CONT.  */	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG	      || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)	    return 0;	  if (optimize < 2	      && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG		  || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))	    /* If we were to duplicate this code, we would not move	       the BLOCK notes, and so debugging the moved code would	       be difficult.  Thus, we only move the code with -O2 or	       higher.  */	    return 0;	  break;	case JUMP_INSN:	case INSN:	  /* The code below would grossly mishandle REG_WAS_0 notes,	     so get rid of them here.  */	  while ((p = find_reg_note (insn, REG_WAS_0, NULL_RTX)) != 0)	    remove_note (insn, p);	  if (++num_insns > 20	      || find_reg_note (insn, REG_RETVAL, NULL_RTX)	      || find_reg_note (insn, REG_LIBCALL, NULL_RTX)	      || asm_noperands (PATTERN (insn)) > 0)	    return 0;	  break;	default:	  break;	}    }  /* Unless INSN is zero, we can do the optimization.  */  if (insn == 0)    return 0;  lastexit = insn;  /* See if any insn sets a register only used in the loop exit code and     not a user variable.  If so, replace it with a new register.  */  for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))    if (GET_CODE (insn) == INSN	&& (set = single_set (insn)) != 0	&& ((reg = SET_DEST (set), GET_CODE (reg) == REG)	    || (GET_CODE (reg) == SUBREG		&& (reg = SUBREG_REG (reg), GET_CODE (reg) == REG)))	&& REGNO (reg) >= FIRST_PSEUDO_REGISTER	&& REGNO_FIRST_UID (REGNO (reg)) == INSN_UID (insn))      {	for (p = NEXT_INSN (insn); p != lastexit; p = NEXT_INSN (p))	  if (REGNO_LAST_UID (REGNO (reg)) == INSN_UID (p))	    break;	if (p != lastexit)	  {	    /* We can do the replacement.  Allocate reg_map if this is the	       first replacement we found.  */	    if (reg_map == 0)	      {		reg_map = (rtx *) alloca (max_reg * sizeof (rtx));		bzero ((char *) reg_map, max_reg * sizeof (rtx));	      }	    REG_LOOP_TEST_P (reg) = 1;	    reg_map[REGNO (reg)] = gen_reg_rtx (GET_MODE (reg));	  }      }  /* Now copy each insn.  */  for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))    switch (GET_CODE (insn))      {      case BARRIER:	copy = emit_barrier_before (loop_start);	break;      case NOTE:	/* Only copy line-number notes.  */	if (NOTE_LINE_NUMBER (insn) >= 0)	  {	    copy = emit_note_before (NOTE_LINE_NUMBER (insn), loop_start);	    NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);	  }	break;      case INSN:	copy = emit_insn_before (copy_rtx (PATTERN (insn)), loop_start);	if (reg_map)	  replace_regs (PATTERN (copy), reg_map, max_reg, 1);	mark_jump_label (PATTERN (copy), copy, 0);	/* Copy all REG_NOTES except REG_LABEL since mark_jump_label will	   make them.  */	for (link = REG_NOTES (insn); link; link = XEXP (link, 1))	  if (REG_NOTE_KIND (link) != REG_LABEL)	    REG_NOTES (copy)	      = copy_rtx (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),					     XEXP (link, 0),					     REG_NOTES (copy)));	if (reg_map && REG_NOTES (copy))	  replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);	break;      case JUMP_INSN:	copy = emit_jump_insn_before (copy_rtx (PATTERN (insn)), loop_start);	if (reg_map)	  replace_regs (PATTERN (copy), reg_map, max_reg, 1);	mark_jump_label (PATTERN (copy), copy, 0);	if (REG_NOTES (insn))	  {	    REG_NOTES (copy) = copy_rtx (REG_NOTES (insn));	    if (reg_map)	      replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);	  }		/* If this is a simple jump, add it to the jump chain.  */	if (INSN_UID (copy) < max_jump_chain && JUMP_LABEL (copy)	    && simplejump_p (copy))	  {	    jump_chain[INSN_UID (copy)]	      = jump_chain[INSN_UID (JUMP_LABEL (copy))];	    jump_chain[INSN_UID (JUMP_LABEL (copy))] = copy;	  }	break;      default:	abort ();      }  /* Now clean up by emitting a jump to the end label and deleting the jump     at the start of the loop.  */  if (! copy || GET_CODE (copy) != BARRIER)    {      copy = emit_jump_insn_before (gen_jump (get_label_after (insn)),				    loop_start);      mark_jump_label (PATTERN (copy), copy, 0);      if (INSN_UID (copy) < max_jump_chain	  && INSN_UID (JUMP_LABEL (copy)) < max_jump_chain)	{	  jump_chain[INSN_UID (copy)]	    = jump_chain[INSN_UID (JUMP_LABEL (copy))];	  jump_chain[INSN_UID (JUMP_LABEL (copy))] = copy;	}      emit_barrier_before (loop_start);    }  /* Mark the exit code as the virtual top of the converted loop.  */  emit_note_before (NOTE_INSN_LOOP_VTOP, exitcode);  delete_insn (next_nonnote_insn (loop_start));  return 1;}