This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

frv scheduling patch


This is a scheduling patch for the frv port.  It shows a small (~2.5%)
improvement in benchmark scores for the FR500.  But the main motivation
is to allow FR550 support to be added.

Some background:

Each member of the FR-V family has its own restrictions on what can go
into a VLIW packet.  This includes a maximum number of instructions per
packet (2 for the FR400, 4 for the FR500, 8 for the FR550, which gcc
doesn't support yet).

All instructions within the packet execute in parallel.  However,
they must still be listed in a certain order.  For example:

  - If a packet includes both integer and floating-point
    instructions, the two kinds of instruction must be interleaved.

  - Branch instructions must come last.

So gcc has to do two things: partition instructions into packets
and sort the packets into the correct assembly-language order.
At the moment it uses the DFA to do both.  For example, the FR550 has:

   - 4 "instruction slots" per packet, each of which can issue to one of...
   - 6 execution units (2 integer, 2 float/media, 2 branch)

The DFA description has a cpu_unit for each valid slot/unit combination
and uses exclusion_sets to describe inter-slot restrictions.  These
exclusion_sets also make sure that slot 0 is filled before slot 1, etc.

While this works well for the FR400 and FR500, it doesn't really scale
to the FR550, which has 8 slots and 10 execution units.  It also
prevents out-of-order dependencies within a packet.  To take a trivial
example, direct jumps (which are classified as integer instructions)
must be listed first in a packet.  So we'll never create packets like:

     jmpl.p @(gr5,gr0)
     addi sp,#16,sp

But the same sort of restriction can trigger in more critical
situations, such as with WAR dependencies involving floating-point
registers.

The idea with this patch is to remove the order restrictions from
the scheduler and deal with them separately in the packing pass.
It's quite easy to do this with the new CPU_UNITS_QUERY interface.

There are a couple of other changes:

  - The packing pass now takes account of hints left behind by
    the scheduler (see frv_pack_insn_p).  This seems to account
    for about half the performance improvement.

  - Insns now have TImode unless they come last in a packet.
    Previously we followed the scheduler's convention and only
    marked the first instruction in a packet.  This led to some
    unnecessarily complicated lookahed during final.

The patch relies on:

    http://gcc.gnu.org/ml/gcc-patches/2003-10/msg00134.html

Tested on frv-elf.  OK to install?

Richard


	* config/frv/frv.h (ISSUE_RATE): Remove.
	(CLEAR_VLIW_START, SET_VLIW_START, PACKING_FLAG_USED_P): Remove.
	(CPU_UNITS_QUERY): Define.
	* config/frv/frv.c (REGSTATE_LIVE): Remove.
	(REGSTATE_UNUSED, REGSTATE_MASK, REGSTATE_CONDJUMP): Remove.
	(regstate_t): New typedef.
	(SET_PACKING_FLAG, CLEAR_PACKING_FLAG, PACKING_FLAG_P): New macros.
	(frv_insn_packing_flag): Update comments to mention new -1 value.
	(frv_function_prologue): Don't set frv_insn_packing_flag.
	(frv_asm_output_mi_thunk): Use frv_issue_rate to detect whether
	packing is enabled.
	(frv_asm_output_opcode): Return the original opcode if an insn
	isn't packed.
	(frv_final_prescan_insn): Simplify after PACKING_FLAG_P changes.
	(frv_registers_update): Remove.
	(frv_registers_used_p, frv_registers_set_p): Remove.
	(FOR_EACH_REGNO): New macro.
	(frv_packet): New variable.
	(frv_packet_insn): New structure.
	(frv_compare_insns, frv_reorder_packet, frv_cond_flags,
	frv_registers_conflict_p_1, frv_registers_conflict_p,
	frv_registers_update_1, frv_registers_update,
	frv_start_packet, frv_start_packet_block, frv_finish_packet,
	frv_pack_insn_p): New functions.
	(frv_pack_insns): Rewrite to use them.
	* config/frv/frv.md (define_automaton nodiv): Split into...
	(define_automaton integer, float_media, branch): ...three automota.
	(define_cpu_unit sl*, fr400*): Remove.
	(define_reservation i0,i1,f0,f1,m0,m1,b0,b1): Remove in favor of...
	(define_query_cpu_unit i0,i1,f0,f1,b0,b1): ...these new units.
	(define_reservation c): Redefine in terms of the new units.
	(define_cpu_unit idiv1,idiv2,div1,div2,root): Move out of fr500 area.
	(define_insn_reservation fr500_control, unknown, fr400_c,
	fr400_unknown): Remove in favor of...
	(define_insn_reservation control): ...this generic reservation.
	(define_insn_reservation *): Allocate units from high to low.
	(define_insn_reservation fr400_*): Use the new generic units.
	(define_insn_reservation fr400_i2_gload, fr400_i2_fload): Combine.
	(define_insn_reservation fr400_i3_gstore, fr400_i3_fstore): Likewise.
	(define_insn_reservation fr400_i4_movfg, fr400_i4_movgf): Likewise.

*** config/frv.fr500/frv.h	Thu Oct  2 01:44:21 2003
--- config/frv/frv.h	Tue Oct  7 17:06:38 2003
*************** frv_ifcvt_modify_multiple_tests (CE_INFO
*** 3226,3243 ****
  /* Initialize the extra fields provided by IFCVT_EXTRA_FIELDS.  */
  #define IFCVT_INIT_EXTRA_FIELDS(CE_INFO) frv_ifcvt_init_extra_fields (CE_INFO)
  
- /* Indicate how many instructions can be issued at the same time.  */
- #define ISSUE_RATE							\
- (! TARGET_PACK ? 1							\
-  : (frv_cpu_type == FRV_CPU_GENERIC					\
-     || frv_cpu_type == FRV_CPU_FR500					\
-     || frv_cpu_type == FRV_CPU_TOMCAT) ? 4				\
-  : frv_cpu_type == FRV_CPU_FR400 ? 2 : 1)
- 
- /* Set and clear whether this insn begins a VLIW insn.  */
- #define CLEAR_VLIW_START(INSN) PUT_MODE (INSN, VOIDmode)
- #define SET_VLIW_START(INSN) PUT_MODE (INSN, TImode)
- 
  /* The definition of the following macro results in that the 2nd jump
     optimization (after the 2nd insn scheduling) is minimal.  It is
     necessary to define when start cycle marks of insns (TImode is used
--- 3226,3231 ----
*************** frv_ifcvt_modify_multiple_tests (CE_INFO
*** 3251,3261 ****
  
  #define MINIMAL_SECOND_JUMP_OPTIMIZATION
  
- /* Return true if parallel operations are expected to be emitted via the
-    packing flag.  */
- #define PACKING_FLAG_USED_P() \
- (optimize && flag_schedule_insns_after_reload && ISSUE_RATE > 1)
- 
  /* If the following macro is defined and nonzero and deterministic
     finite state automata are used for pipeline hazard recognition, the
     code making resource-constrained software pipelining is on.  */
--- 3239,3244 ----
*************** enum frv_builtins
*** 3367,3371 ****
--- 3350,3356 ----
  
  extern GTY(()) rtx frv_compare_op0;			/* operand save for */
  extern GTY(()) rtx frv_compare_op1;			/* comparison generation */
+ 
+ #define CPU_UNITS_QUERY 1
  
  #endif /* __FRV_H__ */
*** config/frv.fr500/frv.c	Tue Oct  7 03:23:39 2003
--- config/frv/frv.c	Wed Oct  8 10:28:19 2003
*************** typedef struct frv_tmp_reg_struct
*** 60,82 ****
    }
  frv_tmp_reg_t;
  
! /* Register state information for VLIW re-packing phase.  These values must fit
!    within an unsigned char.  */
! #define REGSTATE_DEAD		0x00	/* register is currently dead */
  #define REGSTATE_CC_MASK	0x07	/* Mask to isolate CCn for cond exec */
! #define REGSTATE_LIVE		0x08	/* register is live */
! #define REGSTATE_MODIFIED	0x10	/* reg modified in current VLIW insn */
! #define REGSTATE_IF_TRUE	0x20	/* reg modified in cond exec true */
! #define REGSTATE_IF_FALSE	0x40	/* reg modified in cond exec false */
! #define REGSTATE_UNUSED		0x80	/* bit for hire */
! #define REGSTATE_MASK		0xff	/* mask for the bits to set */
  
- 					/* conditional expression used */
  #define REGSTATE_IF_EITHER	(REGSTATE_IF_TRUE | REGSTATE_IF_FALSE)
  
! /* the following is not sure in the reg_state bytes, so can have a larger value
!    than 0xff.  */
! #define REGSTATE_CONDJUMP	0x100	/* conditional jump done in VLIW insn */
  
  /* Used in frv_frame_accessor_t to indicate the direction of a register-to-
     memory move.  */
--- 60,75 ----
    }
  frv_tmp_reg_t;
  
! /* Register state information for VLIW re-packing phase.  */
  #define REGSTATE_CC_MASK	0x07	/* Mask to isolate CCn for cond exec */
! #define REGSTATE_MODIFIED	0x08	/* reg modified in current VLIW insn */
! #define REGSTATE_IF_TRUE	0x10	/* reg modified in cond exec true */
! #define REGSTATE_IF_FALSE	0x20	/* reg modified in cond exec false */
  
  #define REGSTATE_IF_EITHER	(REGSTATE_IF_TRUE | REGSTATE_IF_FALSE)
  
! typedef unsigned char regstate_t;
! 
  
  /* Used in frv_frame_accessor_t to indicate the direction of a register-to-
     memory move.  */
*************** static rtx frv_ifcvt_rewrite_mem		PARAMS
*** 265,278 ****
  							 enum machine_mode,
  							 rtx));
  static rtx frv_ifcvt_load_value			PARAMS ((rtx, rtx));
- static void frv_registers_update		PARAMS  ((rtx, unsigned char [],
- 							 int [], int *, int));
- static int frv_registers_used_p			PARAMS ((rtx, unsigned char [],
- 							 int));
- static int frv_registers_set_p			PARAMS ((rtx, unsigned char [],
- 							 int));
  static int frv_issue_rate			PARAMS ((void));
  static int frv_use_dfa_pipeline_interface	PARAMS ((void));
  static void frv_pack_insns			PARAMS ((void));
  static void frv_function_prologue		PARAMS ((FILE *, HOST_WIDE_INT));
  static void frv_function_epilogue		PARAMS ((FILE *, HOST_WIDE_INT));
--- 258,275 ----
  							 enum machine_mode,
  							 rtx));
  static rtx frv_ifcvt_load_value			PARAMS ((rtx, rtx));
  static int frv_issue_rate			PARAMS ((void));
  static int frv_use_dfa_pipeline_interface	PARAMS ((void));
+ static int frv_compare_insns (const void *, const void *);
+ static void frv_reorder_packet (void);
+ static int frv_cond_flags (rtx);
+ static int frv_registers_conflict_p_1 (rtx *, void *);
+ static bool frv_registers_conflict_p (rtx);
+ static void frv_registers_update_1 (rtx, rtx, void *);
+ static void frv_registers_update (rtx);
+ static void frv_start_packet (void);
+ static void frv_start_packet_block (void);
+ static rtx frv_finish_packet (void);
  static void frv_pack_insns			PARAMS ((void));
  static void frv_function_prologue		PARAMS ((FILE *, HOST_WIDE_INT));
  static void frv_function_epilogue		PARAMS ((FILE *, HOST_WIDE_INT));
*************** static void frv_asm_out_destructor		PARA
*** 320,325 ****
--- 317,326 ----
  #define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE frv_use_dfa_pipeline_interface
  
  struct gcc_target targetm = TARGET_INITIALIZER;
+ 
+ #define SET_PACKING_FLAG(INSN) PUT_MODE (INSN, TImode)
+ #define CLEAR_PACKING_FLAG(INSN) PUT_MODE (INSN, VOIDmode)
+ #define PACKING_FLAG_P(INSN) (GET_MODE (INSN) == TImode)
  
  /* Given a CONST, return true if the symbol_ref points to small data.  */
  
*************** frv_debug_stack (info)
*** 1264,1272 ****
  
  
  
! /* The following variable value is TRUE if the next output insn should
!    finish cpu cycle.  In order words the insn will have packing bit
!    (which means absence of asm code suffix `.p' on assembler. */
  
  static int frv_insn_packing_flag;
  
--- 1265,1273 ----
  
  
  
! /* Used during final to control the packing of insns.  The value is
!    1 if the current instruction should be packed with the next one,
!    0 if it shouldn't or -1 if packing is disabled altogether.  */
  
  static int frv_insn_packing_flag;
  
*************** frv_function_prologue (file, size)
*** 1332,1338 ****
      }
  
    frv_pack_insns ();
-   frv_insn_packing_flag = TRUE;
  }
  
  
--- 1333,1338 ----
*************** frv_asm_output_mi_thunk (file, thunk_fnd
*** 1831,1837 ****
    const char *name_func = XSTR (XEXP (DECL_RTL (function), 0), 0);
    const char *name_arg0 = reg_names[FIRST_ARG_REGNUM];
    const char *name_jmp = reg_names[JUMP_REGNO];
!   const char *parallel = ((PACKING_FLAG_USED_P ()) ? ".p" : "");
  
    /* Do the add using an addi if possible */
    if (IN_RANGE_P (delta, -2048, 2047))
--- 1831,1837 ----
    const char *name_func = XSTR (XEXP (DECL_RTL (function), 0), 0);
    const char *name_arg0 = reg_names[FIRST_ARG_REGNUM];
    const char *name_jmp = reg_names[JUMP_REGNO];
!   const char *parallel = (frv_issue_rate () > 1 ? ".p" : "");
  
    /* Do the add using an addi if possible */
    if (IN_RANGE_P (delta, -2048, 2047))
*************** frv_asm_output_opcode (f, ptr)
*** 2297,2303 ****
  {
    int c;
  
!   if (! PACKING_FLAG_USED_P())
      return ptr;
  
    for (; *ptr && *ptr != ' ' && *ptr != '\t';)
--- 2297,2303 ----
  {
    int c;
  
!   if (frv_insn_packing_flag <= 0)
      return ptr;
  
    for (; *ptr && *ptr != ' ' && *ptr != '\t';)
*************** frv_asm_output_opcode (f, ptr)
*** 2317,2331 ****
  	fputc (c, f);
      }
  
!   if (!frv_insn_packing_flag)
!     fprintf (f, ".p");
! 
    return ptr;
  }
  
! /* The following function sets up the packing bit for the current
!    output insn.  Remember that the function is not called for asm
!    insns. */
  
  void
  frv_final_prescan_insn (insn, opvec, noperands)
--- 2317,2328 ----
  	fputc (c, f);
      }
  
!   fprintf (f, ".p");
    return ptr;
  }
  
! /* Set up the packing bit for the current output insn.  Note that this
!    function is not called for asm insns.  */
  
  void
  frv_final_prescan_insn (insn, opvec, noperands)
*************** frv_final_prescan_insn (insn, opvec, nop
*** 2333,2372 ****
       rtx *opvec;
       int noperands ATTRIBUTE_UNUSED;
  {
!   if (! PACKING_FLAG_USED_P())
!     return;
! 
!   if (!INSN_P (insn))
!     return;
! 
!   frv_insn_operands = opvec;
! 
!   /* Look for the next printable instruction.  frv_pack_insns () has set
!      things up so that any printable instruction will have TImode if it
!      starts a new packet and VOIDmode if it should be packed with the
!      previous instruction.
! 
!      Printable instructions will be asm_operands or match one of the .md
!      patterns.  Since asm instructions cannot be packed -- and will
!      therefore have TImode -- this loop terminates on any recognizable
!      instruction, and on any unrecognizable instruction with TImode.  */
!   for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
      {
!       if (NOTE_P (insn))
! 	continue;
!       else if (!INSN_P (insn))
! 	break;
!       else if (GET_MODE (insn) == TImode || INSN_CODE (insn) != -1)
! 	break;
      }
- 
-   /* Set frv_insn_packing_flag to FALSE if the next instruction should
-      be packed with this one.  Set it to TRUE otherwise.  If the next
-      instruction is an asm insntruction, this statement will set the
-      flag to TRUE, and that value will still hold when the asm operands
-      themselves are printed.  */
-   frv_insn_packing_flag = ! (insn && INSN_P (insn)
- 			     && GET_MODE (insn) != TImode);
  }
  
  
--- 2330,2340 ----
       rtx *opvec;
       int noperands ATTRIBUTE_UNUSED;
  {
!   if (frv_insn_packing_flag >= 0 && INSN_P (insn))
      {
!       frv_insn_operands = opvec;
!       frv_insn_packing_flag = PACKING_FLAG_P (insn);
      }
  }
  
  
*************** frv_use_dfa_pipeline_interface (void)
*** 8231,8825 ****
    return true;
  }
  
! /* Update the register state information, to know about which registers are set
!    or clobbered.  */
  
! static void
! frv_registers_update (x, reg_state, modified, p_num_mod, flag)
!      rtx x;
!      unsigned char reg_state[];
!      int modified[];
!      int *p_num_mod;
!      int flag;
  {
!   int regno, reg_max;
!   rtx reg;
!   rtx cond;
!   const char *format;
!   int length;
!   int j;
  
-   switch (GET_CODE (x))
-     {
-     default:
-       break;
  
!       /* Clobber just modifies a register, it doesn't make it live.  */
!     case CLOBBER:
!       frv_registers_update (XEXP (x, 0), reg_state, modified, p_num_mod,
! 			    flag | REGSTATE_MODIFIED);
!       return;
  
!       /* Pre modify updates the first argument, just references the second.  */
!     case PRE_MODIFY:
!     case SET:
!       frv_registers_update (XEXP (x, 0), reg_state, modified, p_num_mod,
! 			    flag | REGSTATE_MODIFIED | REGSTATE_LIVE);
!       frv_registers_update (XEXP (x, 1), reg_state, modified, p_num_mod, flag);
!       return;
  
!       /* For COND_EXEC, pass the appropriate flag to evaluate the conditional
!          statement, but just to be sure, make sure it is the type of cond_exec
!          we expect.  */
!     case COND_EXEC:
!       cond = XEXP (x, 0);
!       if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
! 	  && GET_CODE (XEXP (cond, 0)) == REG
! 	  && CR_P (REGNO (XEXP (cond, 0)))
! 	  && GET_CODE (XEXP (cond, 1)) == CONST_INT
! 	  && INTVAL (XEXP (cond, 1)) == 0
! 	  && (flag & (REGSTATE_MODIFIED | REGSTATE_IF_EITHER)) == 0)
! 	{
! 	  frv_registers_update (cond, reg_state, modified, p_num_mod, flag);
! 	  flag |= ((REGNO (XEXP (cond, 0)) - CR_FIRST)
! 		   | ((GET_CODE (cond) == NE)
! 		      ? REGSTATE_IF_TRUE
! 		      : REGSTATE_IF_FALSE));
  
! 	  frv_registers_update (XEXP (x, 1), reg_state, modified, p_num_mod,
! 				flag);
! 	  return;
! 	}
!       else
! 	fatal_insn ("frv_registers_update", x);
  
!       /* MEM resets the modification bits.  */
!     case MEM:
!       flag &= ~REGSTATE_MODIFIED;
!       break;
  
!       /* See if we need to set the modified flag.  */
!     case SUBREG:
!       reg = SUBREG_REG (x);
!       if (GET_CODE (reg) == REG)
! 	{
! 	  regno = subreg_regno (x);
! 	  reg_max = REGNO (reg) + HARD_REGNO_NREGS (regno, GET_MODE (reg));
! 	  goto reg_common;
! 	}
!       break;
  
!     case REG:
!       regno = REGNO (x);
!       reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
!       /* fall through */
  
!     reg_common:
!       if (flag & REGSTATE_MODIFIED)
! 	{
! 	  flag &= REGSTATE_MASK;
! 	  while (regno < reg_max)
! 	    {
! 	      int rs = reg_state[regno];
  
! 	      if (flag != rs)
! 		{
! 		  if ((rs & REGSTATE_MODIFIED) == 0)
! 		    {
! 		      modified[ *p_num_mod ] = regno;
! 		      (*p_num_mod)++;
! 		    }
  
! 		  /* If the previous register state had the register as
!                      modified, possibly in some conditional execution context,
!                      and the current insn modifies in some other context, or
!                      outside of conditional execution, just mark the variable
!                      as modified.  */
! 		  else
! 		    flag &= ~(REGSTATE_IF_EITHER | REGSTATE_CC_MASK);
  
! 		  reg_state[regno] = (rs | flag);
! 		}
! 	      regno++;
! 	    }
! 	}
!       return;
!     }
  
  
!   length = GET_RTX_LENGTH (GET_CODE (x));
!   format = GET_RTX_FORMAT (GET_CODE (x));
  
!   for (j = 0; j < length; ++j)
      {
!       switch (format[j])
  	{
! 	case 'e':
! 	  frv_registers_update (XEXP (x, j), reg_state, modified, p_num_mod,
! 				flag);
! 	  break;
  
! 	case 'V':
! 	case 'E':
! 	  if (XVEC (x, j) != 0)
! 	    {
! 	      int k;
! 	      for (k = 0; k < XVECLEN (x, j); ++k)
! 		frv_registers_update (XVECEXP (x, j, k), reg_state, modified,
! 				      p_num_mod, flag);
! 	    }
! 	  break;
  
! 	default:
! 	  /* Nothing to do.  */
! 	  break;
  	}
      }
  
!   return;
  }
  
! 
! /* Return if any registers in a hard register set were used an insn.  */
  
  static int
! frv_registers_used_p (x, reg_state, flag)
!      rtx x;
!      unsigned char reg_state[];
!      int flag;
  {
!   int regno, reg_max;
!   rtx reg;
!   rtx cond;
!   rtx dest;
!   const char *format;
!   int result;
!   int length;
!   int j;
  
-   switch (GET_CODE (x))
-     {
-     default:
-       break;
  
!       /* Skip clobber, that doesn't use the previous value */
!     case CLOBBER:
!       return FALSE;
  
!       /* For SET, if a conditional jump has occurred in the same insn, only
! 	 allow a set of a CR register if that register is not currently live.
! 	 This is because on the FR-V, B0/B1 instructions are always last.
! 	 Otherwise, don't look at the result, except within a MEM, but do look
! 	 at the source.  */
!     case SET:
!       dest = SET_DEST (x);
!       if (flag & REGSTATE_CONDJUMP
! 	  && GET_CODE (dest) == REG && CR_P (REGNO (dest))
! 	  && (reg_state[ REGNO (dest) ] & REGSTATE_LIVE) != 0)
! 	return TRUE;
  
!       if (GET_CODE (dest) == MEM)
  	{
! 	  result = frv_registers_used_p (XEXP (dest, 0), reg_state, flag);
! 	  if (result)
! 	    return result;
! 	}
  
!       return frv_registers_used_p (SET_SRC (x), reg_state, flag);
  
!       /* For COND_EXEC, pass the appropriate flag to evaluate the conditional
!          statement, but just to be sure, make sure it is the type of cond_exec
!          we expect.  */
!     case COND_EXEC:
!       cond = XEXP (x, 0);
!       if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
! 	  && GET_CODE (XEXP (cond, 0)) == REG
! 	  && CR_P (REGNO (XEXP (cond, 0)))
! 	  && GET_CODE (XEXP (cond, 1)) == CONST_INT
! 	  && INTVAL (XEXP (cond, 1)) == 0
! 	  && (flag & (REGSTATE_MODIFIED | REGSTATE_IF_EITHER)) == 0)
! 	{
! 	  result = frv_registers_used_p (cond, reg_state, flag);
! 	  if (result)
! 	    return result;
  
! 	  flag |= ((REGNO (XEXP (cond, 0)) - CR_FIRST)
! 		   | ((GET_CODE (cond) == NE)
! 		      ? REGSTATE_IF_TRUE
! 		      : REGSTATE_IF_FALSE));
  
! 	  return frv_registers_used_p (XEXP (x, 1), reg_state, flag);
  	}
-       else
- 	fatal_insn ("frv_registers_used_p", x);
  
!       /* See if a register or subreg was modified in the same VLIW insn.  */
!     case SUBREG:
!       reg = SUBREG_REG (x);
!       if (GET_CODE (reg) == REG)
! 	{
! 	  regno = subreg_regno (x);
! 	  reg_max = REGNO (reg) + HARD_REGNO_NREGS (regno, GET_MODE (reg));
! 	  goto reg_common;
! 	}
!       break;
  
!     case REG:
!       regno = REGNO (x);
!       reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
!       /* fall through */
  
-     reg_common:
-       while (regno < reg_max)
- 	{
- 	  int rs = reg_state[regno];
  
! 	  if (rs & REGSTATE_MODIFIED)
! 	    {
! 	      int rs_if = rs & REGSTATE_IF_EITHER;
! 	      int flag_if = flag & REGSTATE_IF_EITHER;
  
! 	      /* Simple modification, no conditional execution */
! 	      if ((rs & REGSTATE_IF_EITHER) == 0)
! 		return TRUE;
  
! 	      /* See if the variable is only modified in a conditional
! 		 execution expression opposite to the conditional execution
! 		 expression that governs this expression (ie, true vs. false
! 		 for the same CC register).  If this isn't two halves of the
! 		 same conditional expression, consider the register
! 		 modified. */
! 	      if (((rs_if == REGSTATE_IF_TRUE && flag_if == REGSTATE_IF_FALSE)
! 		   || (rs_if == REGSTATE_IF_FALSE && flag_if == REGSTATE_IF_TRUE))
! 		  && ((rs & REGSTATE_CC_MASK) == (flag & REGSTATE_CC_MASK)))
! 		;
! 	      else
! 		return TRUE;
! 	    }
  
! 	  regno++;
! 	}
!       return FALSE;
      }
  
  
!   length = GET_RTX_LENGTH (GET_CODE (x));
!   format = GET_RTX_FORMAT (GET_CODE (x));
! 
!   for (j = 0; j < length; ++j)
!     {
!       switch (format[j])
! 	{
! 	case 'e':
! 	  result = frv_registers_used_p (XEXP (x, j), reg_state, flag);
! 	  if (result != 0)
! 	    return result;
! 	  break;
! 
! 	case 'V':
! 	case 'E':
! 	  if (XVEC (x, j) != 0)
! 	    {
! 	      int k;
! 	      for (k = 0; k < XVECLEN (x, j); ++k)
! 		{
! 		  result = frv_registers_used_p (XVECEXP (x, j, k), reg_state,
! 						 flag);
! 		  if (result != 0)
! 		    return result;
! 		}
! 	    }
! 	  break;
  
! 	default:
! 	  /* Nothing to do.  */
! 	  break;
! 	}
!     }
  
!   return 0;
  }
  
- /* Return if any registers in a hard register set were set in an insn.  */
  
! static int
! frv_registers_set_p (x, reg_state, modify_p)
!      rtx x;
!      unsigned char reg_state[];
!      int modify_p;
  {
!   int regno, reg_max;
!   rtx reg;
!   rtx cond;
!   const char *format;
!   int length;
!   int j;
  
!   switch (GET_CODE (x))
      {
!     default:
!       break;
  
-     case CLOBBER:
-       return frv_registers_set_p (XEXP (x, 0), reg_state, TRUE);
  
!     case PRE_MODIFY:
!     case SET:
!       return (frv_registers_set_p (XEXP (x, 0), reg_state, TRUE)
! 	      || frv_registers_set_p (XEXP (x, 1), reg_state, FALSE));
  
!     case COND_EXEC:
!       cond = XEXP (x, 0);
!       /* just to be sure, make sure it is the type of cond_exec we
!          expect.  */
!       if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
! 	  && GET_CODE (XEXP (cond, 0)) == REG
! 	  && CR_P (REGNO (XEXP (cond, 0)))
! 	  && GET_CODE (XEXP (cond, 1)) == CONST_INT
! 	  && INTVAL (XEXP (cond, 1)) == 0
! 	  && !modify_p)
! 	return frv_registers_set_p (XEXP (x, 1), reg_state, modify_p);
!       else
! 	fatal_insn ("frv_registers_set_p", x);
  
-       /* MEM resets the modification bits.  */
-     case MEM:
-       modify_p = FALSE;
-       break;
  
!       /* See if we need to set the modified modify_p.  */
!     case SUBREG:
!       reg = SUBREG_REG (x);
!       if (GET_CODE (reg) == REG)
! 	{
! 	  regno = subreg_regno (x);
! 	  reg_max = REGNO (reg) + HARD_REGNO_NREGS (regno, GET_MODE (reg));
! 	  goto reg_common;
! 	}
!       break;
  
!     case REG:
!       regno = REGNO (x);
!       reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
!       /* fall through */
  
-     reg_common:
-       if (modify_p)
- 	while (regno < reg_max)
- 	  {
- 	    int rs = reg_state[regno];
  
! 	    if (rs & REGSTATE_MODIFIED)
! 	      return TRUE;
! 	    regno++;
! 	  }
!       return FALSE;
!     }
  
  
!   length = GET_RTX_LENGTH (GET_CODE (x));
!   format = GET_RTX_FORMAT (GET_CODE (x));
  
!   for (j = 0; j < length; ++j)
!     {
!       switch (format[j])
! 	{
! 	case 'e':
! 	  if (frv_registers_set_p (XEXP (x, j), reg_state, modify_p))
! 	    return TRUE;
! 	  break;
  
! 	case 'V':
! 	case 'E':
! 	  if (XVEC (x, j) != 0)
! 	    {
! 	      int k;
! 	      for (k = 0; k < XVECLEN (x, j); ++k)
! 		if (frv_registers_set_p (XVECEXP (x, j, k), reg_state,
! 					 modify_p))
! 		  return TRUE;
! 	    }
! 	  break;
  
! 	default:
! 	  /* Nothing to do.  */
! 	  break;
! 	}
      }
  
!   return FALSE;
  }
  
- 
- /* On the FR-V, this pass is used to rescan the insn chain, and pack
-    conditional branches/calls/jumps, etc. with previous insns where it can.  It
-    does not reorder the instructions.  We assume the scheduler left the flow
-    information in a reasonable state.  */
  
! static void
! frv_pack_insns ()
  {
!   state_t frv_state;			/* frv state machine */
!   int cur_start_vliw_p;			/* current insn starts a VLIW insn */
!   int next_start_vliw_p;		/* next insn starts a VLIW insn */
!   int cur_condjump_p;			/* flag if current insn is a cond jump*/
!   int next_condjump_p;			/* flag if next insn is a cond jump */
!   rtx insn;
!   rtx link;
!   int j;
!   int num_mod = 0;			/* # of modified registers */
!   int modified[FIRST_PSEUDO_REGISTER];	/* registers modified in current VLIW */
! 					/* register state information */
!   unsigned char reg_state[FIRST_PSEUDO_REGISTER];
  
!   /* If we weren't going to pack the insns, don't bother with this pass.  */
!   if (!optimize
!       || !flag_schedule_insns_after_reload
!       || TARGET_NO_VLIW_BRANCH
!       || frv_issue_rate () == 1)
!     return;
  
!   /* Set up the instruction and register states.  */
!   dfa_start ();
!   frv_state = (state_t) xmalloc (state_size ());
!   memset (reg_state, REGSTATE_DEAD, sizeof (reg_state));
  
!   /* Go through the insns, and repack the insns.  */
!   state_reset (frv_state);
!   cur_start_vliw_p = FALSE;
!   next_start_vliw_p = TRUE;
!   cur_condjump_p = 0;
!   next_condjump_p = 0;
  
!   for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
!     {
!       enum rtx_code code = GET_CODE (insn);
!       enum rtx_code pattern_code;
  
!       /* For basic block begin notes redo the live information, and skip other
!          notes.  */
!       if (code == NOTE)
! 	{
! 	  if (NOTE_LINE_NUMBER (insn) == (int)NOTE_INSN_BASIC_BLOCK)
! 	    {
! 	      regset live;
  
! 	      for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
! 		reg_state[j] &= ~ REGSTATE_LIVE;
  
! 	      live = NOTE_BASIC_BLOCK (insn)->global_live_at_start;
! 	      EXECUTE_IF_SET_IN_REG_SET(live, 0, j,
! 					{
! 					  reg_state[j] |= REGSTATE_LIVE;
! 					});
! 	    }
  
! 	  continue;
! 	}
  
-       /* things like labels reset everything.  */
-       if (GET_RTX_CLASS (code) != 'i')
- 	{
- 	  next_start_vliw_p = TRUE;
- 	  continue;
- 	}
  
!       /* Clear the VLIW start flag on random USE and CLOBBER insns, which is
!          set on the USE insn that preceeds the return, and potentially on
!          CLOBBERs for setting multiword variables.  Also skip the ADDR_VEC
!          holding the case table labels.  */
!       pattern_code = GET_CODE (PATTERN (insn));
!       if (pattern_code == USE || pattern_code == CLOBBER
! 	  || pattern_code == ADDR_VEC || pattern_code == ADDR_DIFF_VEC)
! 	{
! 	  CLEAR_VLIW_START (insn);
! 	  continue;
! 	}
  
!       cur_start_vliw_p = next_start_vliw_p;
!       next_start_vliw_p = FALSE;
  
!       cur_condjump_p |= next_condjump_p;
!       next_condjump_p = 0;
  
!       /* Unconditional branches and calls end the current VLIW insn.  */
!       if (code == CALL_INSN)
! 	{
! 	  next_start_vliw_p = TRUE;
  
! 	  /* On a TOMCAT, calls must be alone in the VLIW insns.  */
! 	  if (frv_cpu_type == FRV_CPU_TOMCAT)
! 	    cur_start_vliw_p = TRUE;
! 	}
!       else if (code == JUMP_INSN)
! 	{
! 	  if (any_condjump_p (insn))
! 	    next_condjump_p = REGSTATE_CONDJUMP;
! 	  else
! 	    next_start_vliw_p = TRUE;
! 	}
  
!       /* Only allow setting a CCR register after a conditional branch.  */
!       else if (((cur_condjump_p & REGSTATE_CONDJUMP) != 0)
! 	       && get_attr_type (insn) != TYPE_CCR)
! 	cur_start_vliw_p = TRUE;
  
!       /* Determine if we need to start a new VLIW instruction.  */
!       if (cur_start_vliw_p
! 	  /* Do not check for register conflicts in a setlo instruction
! 	     because any output or true dependencies will be with the
! 	     partnering sethi instruction, with which it can be packed.
  
! 	     Although output dependencies are rare they are still
! 	     possible.  So check output dependencies in VLIW insn. */
! 	  || (get_attr_type (insn) != TYPE_SETLO
! 	      && (frv_registers_used_p (PATTERN (insn),
! 					reg_state,
! 					cur_condjump_p)
! 		  || frv_registers_set_p (PATTERN (insn), reg_state, FALSE)))
! 	  || state_transition (frv_state, insn) >= 0)
  	{
! 	  SET_VLIW_START (insn);
! 	  state_reset (frv_state);
! 	  state_transition (frv_state, insn);
! 	  cur_condjump_p = 0;
  
! 	  /* Update the modified registers.  */
! 	  for (j = 0; j < num_mod; j++)
! 	    reg_state[ modified[j] ] &= ~(REGSTATE_CC_MASK
! 					  | REGSTATE_IF_EITHER
! 					  | REGSTATE_MODIFIED);
  
! 	  num_mod = 0;
! 	}
!       else
! 	CLEAR_VLIW_START (insn);
  
!       /* Record which registers are modified.  */
!       frv_registers_update (PATTERN (insn), reg_state, modified, &num_mod, 0);
  
!       /* Process the death notices */
!       for (link = REG_NOTES (insn);
! 	   link != NULL_RTX;
! 	   link = XEXP (link, 1))
! 	{
! 	  rtx reg = XEXP (link, 0);
  
! 	  if (REG_NOTE_KIND (link) == REG_DEAD && GET_CODE (reg) == REG)
! 	    {
! 	      int regno = REGNO (reg);
! 	      int n = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
! 	      for (; regno < n; regno++)
! 		reg_state[regno] &= ~REGSTATE_LIVE;
! 	    }
! 	}
      }
! 
!   free (frv_state);
    dfa_finish ();
-   return;
- }
  
  
  #define def_builtin(name, type, code) \
    builtin_function ((name), (type), (code), BUILT_IN_MD, NULL, NULL)
--- 8199,8694 ----
    return true;
  }
  
! /* Loop with REG set to each hard register in rtx X.  */
! #define FOR_EACH_REGNO(REG, X)						\
!   for (REG = REGNO (X);							\
!        REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X));	\
!        REG++)
  
! /* The current state of the packing pass, implemented by frv_pack_insns.  */
! struct {
!   /* The state of the pipeline DFA.  */
!   state_t dfa_state;
! 
!   /* Which hardware registers are set within the current packet,
!      and the conditions under which they are set.  */
!   regstate_t reg_state[FIRST_PSEUDO_REGISTER];
! 
!   /* The maximum number of instructions that can be packed together.  */
!   unsigned int issue_rate;
! 
!   /* The instructions that make up the current packet.  */
!   rtx *insns;
!   unsigned int num_insns;
! } frv_packet;
! 
! /* One instruction in a packet.  Used by frv_reorder_packet when sorting
!    instructions into assembly-language order.  */
! struct frv_packet_insn {
!   /* The instruction itself.  */
!   rtx insn;
! 
!   /* The highest-numbered unit that this instruction can use.  See the
!      comment above frv_reorder_packet for details.  */
!   int unit;
! };
! 
! 
! /* Compare two packets by their unit number.  */
! 
! static int
! frv_compare_insns (const void *first, const void *second)
  {
!   return (((struct frv_packet_insn *) first)->unit
! 	  - ((struct frv_packet_insn *) second)->unit);
! }
  
  
! /* Sort the current packet into assembly-language order.
  
!    The instructions in a packet are ordered by the units they use,
!    which are in turn ordered as follows:
  
! 	I0 F0 I1 F1 B0 B1
  
!    Each packet will skip some units, leaving them unused for a cycle.
!    It isn't possible to skip a unit and use a later one of the same type.
  
!    We use the following method to sort a packet:
  
!       (1) Determine the last position in the template above
! 	  that each instruction could occupy.
  
!       (2) Sort the instructions according to this position.
  
!       (3) Go through the template.  For each integer unit, pick the first
! 	  unpacked integer instruction from the sorted list.  Likewise
! 	  for the other two instruction groups.
  
!    Perhaps the hardest part is working out (1).  We can do this by
!    resetting a temporary DFA and issuing the instruction on its own.
!    The instruction will then try to use the highest-numbered unit it
!    can (see the comment above the unit definitions in frv.md).
  
!    Since this operation is quite costly, and since the unit depends only
!    on the instruction type, we cache the result in type_to_unit[].  */
  
! static void
! frv_reorder_packet (void)
! {
!   /* Classification of instructions and units: integer, floating-point/media
!      and branch.  */
!   enum group { GROUP_I, GROUP_FM, GROUP_B, NUM_GROUPS };
  
+   /* The names of the units, in packet order.  */
+   static const char *unit_names[] = {
+     "i0", "f0",
+     "i1", "f1",
+     "b0", "b1"
+   };
  
!   /* The classification of each unit in unit_names[].  */
!   static enum group unit_groups[ARRAY_SIZE (unit_names)] = {
!     GROUP_I, GROUP_FM,
!     GROUP_I, GROUP_FM,
!     GROUP_B, GROUP_B
!   };
  
!   /* The DFA unit number for each unit in unit_names[].  */
!   static int unit_codes[ARRAY_SIZE (unit_names)];
! 
!   /* TYPE_TO_UNIT[T] is the last unit in unit_names[] that can issue
!      an instruction of type T.  The value is ARRAY_SIZE (unit_names)
!      if no instruction of type T has been seen.  */
!   static unsigned int type_to_unit[TYPE_UNKNOWN];
! 
!   /* Automatic vars...  */
!   struct frv_packet_insn *insns;
!   unsigned int cursor[NUM_GROUPS];
!   unsigned int i, index;
! 
!   if (frv_packet.num_insns == 1)
!     return;
! 
!   /* First time through, ask the DFA interface what the unit codes are.
!      Initialize type_to_unit[].  */
!   if (unit_codes[0] == unit_codes[1])
      {
!       for (i = 0; i < ARRAY_SIZE (unit_names); i++)
! 	unit_codes[i] = get_cpu_unit_code (unit_names[i]);
!       for (i = 0; i < ARRAY_SIZE (type_to_unit); i++)
! 	type_to_unit[i] = ARRAY_SIZE (unit_codes);
!     }
! 
!   /* Step (1).  Create a temporary array containing the insns and their
!      position numbers.  */
!   insns = alloca (frv_packet.num_insns * sizeof (struct frv_packet_insn));
!   for (i = 0; i < frv_packet.num_insns; i++)
!     {
!       enum attr_type type = get_attr_type (frv_packet.insns[i]);
!       if (type_to_unit[type] == ARRAY_SIZE (unit_codes))
  	{
! 	  /* We haven't seen this type of instruction before.  Fill in
! 	     its type_to_unit[] entry.  */
! 	  state_t state;
! 	  unsigned int unit;
  
! 	  /* Issue the instruction on its own.  It will take the
! 	     highest-numbered unit it can.  */
! 	  state = alloca (state_size ());
! 	  state_reset (state);
! 	  state_transition (state, frv_packet.insns[i]);
  
! 	  /* Find out which unit was taken.  */
! 	  for (unit = 0; unit < ARRAY_SIZE (unit_codes); unit++)
! 	    if (cpu_unit_reservation_p (state, unit_codes[unit]))
! 	      break;
! 
! 	  if (unit == ARRAY_SIZE (unit_codes))
! 	    abort ();
! 
! 	  type_to_unit[type] = unit;
  	}
+       insns[i].insn = frv_packet.insns[i];
+       insns[i].unit = type_to_unit[type];
      }
  
!   /* Step (2).  Sort the instructions by unit number.  */
!   qsort (insns, frv_packet.num_insns, sizeof (*insns), frv_compare_insns);
! 
!   /* Step (3).  Assign instructions to units.
! 
!      First, create a cursor for each instruction group.  Any instruction
!      in the group before the cursor has already been packed.  Any instruction
!      under or after it is still unpacked.
! 
!      In the main loop, go through each group in unit_groups[].  Pick the
!      first unpacked instruction in that group and add it to PACKET.  */
!   memset (cursor, 0, sizeof (cursor));
!   index = 0;
!   for (i = 0; i < ARRAY_SIZE (unit_groups); i++)
!     {
!       enum group group = unit_groups[i];
!       for (; cursor[group] < frv_packet.num_insns; cursor[group]++)
! 	if (unit_groups[insns[cursor[group]].unit] == group)
! 	  {
! 	    frv_packet.insns[index++] = insns[cursor[group]++].insn;
! 	    break;
! 	  }
!     }
! 
!   if (index != frv_packet.num_insns)
!     abort ();
  }
  
! 
! /* Return the regstate_t flags for the given COND_EXEC condition.
!    Abort if the condition isn't in the right form.  */
  
  static int
! frv_cond_flags (rtx cond)
  {
!   if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
!       && GET_CODE (XEXP (cond, 0)) == REG
!       && CR_P (REGNO (XEXP (cond, 0)))
!       && XEXP (cond, 1) == const0_rtx)
!     return ((REGNO (XEXP (cond, 0)) - CR_FIRST)
! 	    | (GET_CODE (cond) == NE
! 	       ? REGSTATE_IF_TRUE
! 	       : REGSTATE_IF_FALSE));
!   abort ();
! }
  
  
! /* A for_each_rtx callback.  Return 1 if *X depends on an instruction in
!    the current packet.  DATA points to a regstate_t that describes the
!    condition under which *X might be set or used.  */
  
! static int
! frv_registers_conflict_p_1 (rtx *x, void *data)
! {
!   unsigned int regno;
  
!   if (GET_CODE (*x) == REG)
!     FOR_EACH_REGNO (regno, *x)
!       if (frv_packet.reg_state[regno] & REGSTATE_MODIFIED)
  	{
! 	  /* The register was set by an instruction in the current packet.
! 	     See if this reference conflicts with it.  */
! 	  regstate_t cond1, cond2;
  
! 	  cond1 = frv_packet.reg_state[regno];
! 	  cond2 = *(regstate_t *) data;
  
! 	  /* If either reference was unconditional, we have a conflict.  */
! 	  if ((cond1 & REGSTATE_IF_EITHER) == 0
! 	      || (cond2 & REGSTATE_IF_EITHER) == 0)
! 	    return 1;
  
! 	  /* The references might conflict if they were controlled by
! 	     different CRs.  */
! 	  if ((cond1 & REGSTATE_CC_MASK) != (cond2 & REGSTATE_CC_MASK))
! 	    return 1;
  
! 	  /* They definitely conflict if they are controlled by the
! 	     same condition.  */
! 	  if ((cond1 & REGSTATE_IF_EITHER) == (cond2 & REGSTATE_IF_EITHER))
! 	    return 1;
  	}
  
!   /* The return values of calls aren't significant: they describe
!      the effect of the call as a whole, not of the insn itself.  */
!   if (GET_CODE (*x) == SET && GET_CODE (SET_SRC (*x)) == CALL)
!     {
!       if (for_each_rtx (&SET_SRC (*x), frv_registers_conflict_p_1, data))
! 	return 1;
!       return -1;
!     }
  
!   /* Check subexpressions.  */
!   return 0;
! }
  
  
! /* Return true if something in X might depend on an instruction
!    in the current packet.  */
  
! static bool
! frv_registers_conflict_p (rtx x)
! {
!   regstate_t flags;
  
!   flags = 0;
!   if (GET_CODE (x) == COND_EXEC)
!     {
!       if (for_each_rtx (&XEXP (x, 0), frv_registers_conflict_p_1, &flags))
! 	return true;
  
!       flags |= frv_cond_flags (XEXP (x, 0));
!       x = XEXP (x, 1);
      }
+   return for_each_rtx (&x, frv_registers_conflict_p_1, &flags);
+ }
  
  
! /* A note_stores callback.  If *X refers to a register, update its
!    regstate_t flags with those given by DATA.  */
  
! static void
! frv_registers_update_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
! {
!   unsigned int regno;
  
!   if (GET_CODE (x) == REG)
!     FOR_EACH_REGNO (regno, x)
!       frv_packet.reg_state[regno] |= *(regstate_t *) data;
  }
  
  
! /* Update the register state information for an instruction whose
!    body is X.  */
! 
! static void
! frv_registers_update (rtx x)
  {
!   regstate_t flags;
  
!   flags = REGSTATE_MODIFIED;
!   if (GET_CODE (x) == COND_EXEC)
      {
!       flags |= frv_cond_flags (XEXP (x, 0));
!       x = XEXP (x, 1);
!     }
!   note_stores (x, frv_registers_update_1, &flags);
! }
  
  
! /* Initialize frv_packet for the start of a new packet.  */
  
! static void
! frv_start_packet (void)
! {
!   memset (frv_packet.reg_state, 0, sizeof (frv_packet.reg_state));
!   frv_packet.num_insns = 0;
! }
  
  
! /* Likewise for the start of a new basic block.  */
  
! static void
! frv_start_packet_block (void)
! {
!   state_reset (frv_packet.dfa_state);
!   frv_start_packet ();
! }
  
  
! /* Finish the current packet, if any, and start a new one.  Return a
!    pointer to the final instruction, or null if the packet was empty.  */
  
+ static rtx
+ frv_finish_packet (void)
+ {
+   unsigned int i;
+   rtx last;
  
!   if (frv_packet.num_insns == 0)
!     return 0;
  
!   /* Sort FRV_PACKET.INSNS into assembly-language order.  */
!   frv_reorder_packet ();
  
!   /* Clear the last instruction's packing flag, thus marking
!      the end of a packet.  */
!   last = frv_packet.insns[frv_packet.num_insns - 1];
!   CLEAR_PACKING_FLAG (last);
  
!   /* Reorder the other instructions relative to the last one.
!      Set their packing bits.  */
!   for (i = 0; i < frv_packet.num_insns - 1; i++)
!     {
!       remove_insn (frv_packet.insns[i]);
!       add_insn_before (frv_packet.insns[i], last);
!       SET_PACKING_FLAG (frv_packet.insns[i]);
      }
  
!   /* Simulate one cycle.  */
!   state_transition (frv_packet.dfa_state, 0);
! 
!   /* Start a new packet.  */
!   frv_start_packet ();
! 
!   return last;
  }
  
  
! /* Return true if INSN can be added to the current packet.  Update
!    the DFA state on success.  */
! 
! static bool
! frv_pack_insn_p (rtx insn)
  {
!   /* Calls mustn't be packed on a TOMCAT.  */
!   if (GET_CODE (insn) == CALL_INSN && frv_cpu_type == FRV_CPU_TOMCAT)
!     return false;
  
!   /* See if the packet is already as long as it can be.  */
!   if (frv_packet.num_insns == frv_packet.issue_rate)
!     return false;
  
!   /* If the scheduler thought that an instruction should start a packet,
!      it's usually a good idea to believe it.  It knows much more about
!      the latencies than we do.
  
!      There are some exceptions though:
  
!        - Conditional instructions are scheduled on the assumption that
! 	 they will be executed.  This is usually a good thing, since it
! 	 tends to avoid unncessary stalls in the conditional code.
! 	 But we want to pack conditional instructions as tightly as
! 	 possible, in order to optimize the case where they aren't
! 	 executed.
  
!        - The scheduler will always put branches on their own, even
! 	 if there's no real dependency.
  
!        - There's no point putting a call in its own packet unless
! 	 we have to.  */
!   if (frv_packet.num_insns > 0
!       && GET_CODE (insn) == INSN
!       && GET_MODE (insn) == TImode
!       && GET_CODE (PATTERN (insn)) != COND_EXEC)
!     return false;
  
!   /* Check for register conflicts.  */
!   if (frv_registers_conflict_p (PATTERN (insn)))
!     return false;
  
!   return state_transition (frv_packet.dfa_state, insn) < 0;
! }
  
  
! /* Divide instructions into packets.  Reorder the contents of each
!    packet so that they are in the correct assembly-language order.
  
!    Since this pass can change the raw meaning of the rtl stream, it must
!    only be called at the last minute, just before the instructions are
!    written out.  */
  
! static void
! frv_pack_insns ()
! {
!   rtx insn;
  
!   frv_packet.issue_rate = frv_issue_rate ();
  
!   /* Early exit if we don't want to pack insns.  */
!   if (!optimize
!       || !flag_schedule_insns_after_reload
!       || TARGET_NO_VLIW_BRANCH
!       || frv_packet.issue_rate == 1)
!     {
!       frv_insn_packing_flag = -1;
!       return;
!     }
  
!   /* Set up the initial packing state.  */
!   dfa_start ();
!   frv_packet.dfa_state = alloca (state_size ());
!   frv_packet.insns = alloca (frv_packet.issue_rate * sizeof (rtx));
  
!   frv_start_packet_block ();
!   for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
!     {
!       enum rtx_code code;
  
!       code = GET_CODE (insn);
! 
!       if (code == CODE_LABEL)
  	{
! 	  frv_finish_packet ();
! 	  frv_start_packet_block ();
! 	}
  
!       if (INSN_P (insn))
! 	switch (GET_CODE (PATTERN (insn)))
! 	  {
! 	  case USE:
! 	  case CLOBBER:
! 	  case ADDR_VEC:
! 	  case ADDR_DIFF_VEC:
! 	    break;
  
! 	  default:
! 	    /* Finish the current packet if we can't add INSN to it.
! 	       Simulate cycles until INSN is ready to issue.  */
! 	    if (!frv_pack_insn_p (insn))
! 	      {
! 		frv_finish_packet ();
! 		while (!frv_pack_insn_p (insn))
! 		  state_transition (frv_packet.dfa_state, 0);
! 	      }
  
! 	    /* Add the instruction to the packet.  */
! 	    frv_packet.insns[frv_packet.num_insns++] = insn;
  
! 	    /* Record which registers are modified.  Don't do this for
! 	       SETHI since any dependency will be with the partnering
! 	       SETLO, with which it can packed.  */
! 	    if (get_attr_type (insn) != TYPE_SETHI)
! 	      frv_registers_update (PATTERN (insn));
  
! 	    /* Calls and jumps end a packet.  */
! 	    if (code == CALL_INSN || code == JUMP_INSN)
! 	      insn = frv_finish_packet ();
! 	    break;
! 	  }
      }
!   frv_finish_packet ();
    dfa_finish ();
  
+   frv_insn_packing_flag = 0;
+ }
  
  #define def_builtin(name, type, code) \
    builtin_function ((name), (type), (code), BUILT_IN_MD, NULL, NULL)
--- config/frv.fr500/frv.md	Tue Oct  7 09:09:14 2003
+++ config/frv/frv.md	Tue Oct  7 09:09:26 2003
@@ -363,212 +363,39 @@
 ;; mqsath	no		n/a	m1:2
 ;; mset		no		n/a	m1:1
 
+;; "unknown" must come last.
 (define_attr "type"
   "int,sethi,setlo,mul,div,gload,gstore,fload,fstore,movfg,movgf,branch,jump,jumpl,call,spr,trap,fsconv,fsadd,fscmp,fsmul,fsmadd,fsdiv,sqrt_single,fdconv,fdadd,fdcmp,fdmul,fdmadd,fddiv,sqrt_double,mlogic,maveh,msath,maddh,mqaddh,mpackh,munpackh,mdpackh,mbhconv,mrot,mshift,mexpdhw,mexpdhd,mwcut,mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,mcpx,mqcpx,mcut,mclracc,mclracca,mdunpackh,mbhconve,mrdacc,mwtacc,maddacc,mdaddacc,mabsh,mdrot,mcpl,mdcut,mqsath,mset,ccr,multi,unknown"
   (const_string "unknown"))
-
 
+(define_automaton "integer, float_media, branch, idiv, div")
 
-/* This is description of pipeline hazards based on DFA.  The
-   following constructions can be used for this:
-
-   o define_cpu_unit string [string]) describes a cpu functional unit
-     (separated by comma).
-
-     1st operand: Names of cpu function units.
-     2nd operand: Name of automaton (see comments for
-     DEFINE_AUTOMATON).
-
-     All define_reservations and define_cpu_units should have unique
-     names which can not be "nothing".
-
-   o (exclusion_set string string) means that each CPU function unit
-     in the first string can not be reserved simultaneously with each
-     unit whose name is in the second string and vise versa.  CPU
-     units in the string are separated by commas. For example, it is
-     useful for description CPU with fully pipelined floating point
-     functional unit which can execute simultaneously only single
-     floating point insns or only double floating point insns.
-
-   o (presence_set string string) means that each CPU function unit in
-     the first string can not be reserved unless at least one of units
-     whose names are in the second string is reserved.  This is an
-     asymmetric relation.  CPU units in the string are separated by
-     commas.  For example, it is useful for description that slot1 is
-     reserved after slot0 reservation for a VLIW processor.
-
-   o (absence_set string string) means that each CPU function unit in
-     the first string can not be reserved only if each unit whose name
-     is in the second string is not reserved.  This is an asymmetric
-     relation (actually exclusion set is analogous to this one but it
-     is symmetric).  CPU units in the string are separated by commas.
-     For example, it is useful for description that slot0 can not be
-     reserved after slot1 or slot2 reservation for a VLIW processor.
-
-   o (define_bypass number out_insn_names in_insn_names) names bypass with
-     given latency (the first number) from insns given by the first
-     string (see define_insn_reservation) into insns given by the
-     second string.  Insn names in the strings are separated by
-     commas.
-
-   o (define_automaton string) describes names of an automaton
-     generated and used for pipeline hazards recognition.  The names
-     are separated by comma.  Actually it is possibly to generate the
-     single automaton but unfortunately it can be very large.  If we
-     use more one automata, the summary size of the automata usually
-     is less than the single one.  The automaton name is used in
-     define_cpu_unit.  All automata should have unique names.
-
-   o (define_reservation string string) names reservation (the first
-     string) of cpu functional units (the 2nd string).  Sometimes unit
-     reservations for different insns contain common parts.  In such
-     case, you describe common part and use one its name (the 1st
-     parameter) in regular expression in define_insn_reservation.  All
-     define_reservations, define results and define_cpu_units should
-     have unique names which can not be "nothing".
-
-   o (define_insn_reservation name default_latency condition regexpr)
-     describes reservation of cpu functional units (the 3nd operand)
-     for instruction which is selected by the condition (the 2nd
-     parameter).  The first parameter is used for output of debugging
-     information.  The reservations are described by a regular
-     expression according the following syntax:
-
-       regexp = regexp "," oneof
-              | oneof
-
-       oneof = oneof "|" allof
-             | allof
-
-       allof = allof "+" repeat
-             | repeat
-
-       repeat = element "*" number
-              | element
-
-       element = cpu_function_name
-               | reservation_name
-               | result_name
-               | "nothing"
-               | "(" regexp ")"
-
-       1. "," is used for describing start of the next cycle in
-          reservation.
-
-       2. "|" is used for describing the reservation described by the
-          first regular expression *or* the reservation described by
-          the second regular expression *or* etc.
-
-       3. "+" is used for describing the reservation described by the
-          first regular expression *and* the reservation described by
-          the second regular expression *and* etc.
-
-       4. "*" is used for convinience and simply means sequence in
-          which the regular expression are repeated NUMBER times with
-          cycle advancing (see ",").
-
-       5. cpu function unit name which means reservation.
-
-       6. reservation name -- see define_reservation.
-
-       7. string "nothing" means no units reservation.
-
-*/
-
-(define_automaton "nodiv, idiv, div")
-
-;; An FR500 packet can contain a single control instruction or a sequence
-;; of up to four operations matching the regular expression:
-
-;;	(I FM? I? FM? | FM? FM?) B? B?
-
-;; where I denotes an integer operation, FM a floating-point or media
-;; operation, and B a branch operation.  There are two units for each type
-;; of instruction: I0 and I1, FM0 and FM1, and B0 and B1.  Units are
-;; allocated left-to-right: the first integer instruction uses I0, the
-;; second uses I1, and so on.
-
-;; The FR400 is similar to the FR500 except that it allows only 2 operations
-;; per packet and has only one branch unit.  We can use the FR500 conflict
-;; description for the FR400, but need to define different cpu_units
-;; later.
-
-;; Slot/unit combinations available on the FR400 and above:
-(define_cpu_unit "sl0_i0, sl0_fm0, sl0_b0, sl0_c" "nodiv")
-(define_cpu_unit "sl1_fm0, sl1_i1, sl1_fm1, sl1_b0" "nodiv")
-
-;; These are available on the FR500 and above:
-(define_cpu_unit "sl1_b1" "nodiv")
-(define_cpu_unit "sl2_i1, sl2_fm1, sl2_b0, sl2_b1" "nodiv")
-(define_cpu_unit "sl3_fm1, sl3_b0, sl3_b1"  "nodiv")
-
-;; The following describes conlicts by slots
-;; slot0
-(exclusion_set "sl0_i0"  "sl0_fm0,sl0_b0,sl0_c")
-(exclusion_set "sl0_fm0" "sl0_b0,sl0_c")
-(exclusion_set "sl0_b0"  "sl0_c")
-
-;; slot1
-(exclusion_set "sl1_fm0" "sl1_i1,sl1_fm1,sl1_b0,sl1_b1")
-(exclusion_set "sl1_i1"  "sl1_fm1,sl1_b0,sl1_b1")
-(exclusion_set "sl1_fm1" "sl1_b0,sl1_b1")
-(exclusion_set "sl1_b0"  "sl1_b1")
-
-;; slot2
-(exclusion_set "sl2_i1"  "sl2_fm1,sl2_b0,sl2_b1")
-(exclusion_set "sl2_fm1" "sl2_b0,sl2_b1")
-(exclusion_set "sl2_b0"  "sl2_b1")
-
-;; slot3
-(exclusion_set "sl3_fm1" "sl3_b0,sl3_b1")
-(exclusion_set "sl3_b0"  "sl3_b1")
-
-;; The following describes conlicts by units
-;; fm0
-(exclusion_set "sl0_fm0" "sl1_fm0")
-
-;; b0
-(exclusion_set "sl0_b0"  "sl1_b0,sl2_b0,sl3_b0")
-(exclusion_set "sl1_b0"  "sl2_b0,sl3_b0")
-(exclusion_set "sl2_b0"  "sl3_b0")
-
-;; i1
-(exclusion_set "sl1_i1"  "sl2_i1")
-
-;; fm1
-(exclusion_set "sl1_fm1" "sl2_fm1,sl3_fm1")
-(exclusion_set "sl2_fm1" "sl3_fm1")
-
-;; b1
-(exclusion_set "sl1_b1"  "sl2_b1,sl3_b1")
-(exclusion_set "sl2_b1"  "sl3_b1")
-
-;; The following describes remaining combinations of conflicts
-;; slot0
-(exclusion_set "sl0_i0"  "sl1_fm1,sl1_b1")
-(exclusion_set "sl0_fm0" "sl1_i1,sl1_b1,sl2_i1,sl2_fm1,sl3_fm1,sl3_b0")
-(exclusion_set "sl0_b0"  "sl1_fm0,sl1_i1,sl1_fm1,sl2_i1,sl2_fm1,sl2_b1,\
-                          sl3_fm1,sl3_b1")
-(exclusion_set "sl0_c"   "sl1_fm0,sl1_i1,sl1_fm1,sl1_b0,sl1_b1,sl2_i1,sl2_fm1,\
-                          sl2_b0,sl2_b1,sl3_fm1,sl3_b0,sl3_b1")
-
+;; The main CPU units.  Each integer instruction can issue to any unit
+;; from I0 to IX, where X varies for different types of instruction.
+;; Likewise floating-point and media instructions can issue to any unit
+;; from F0 to FX and branch instructions can issue to any unit from B0
+;; to BX.
+;;
+;; When X > 0, an insn reservation should pick the highest-numbered
+;; unit it can.  For example, if an instruction can issue to either
+;; I0 or I1, it should pick I1 when I1 is free.
+;;
+;; Note that not all units are available on all processors.
+(define_query_cpu_unit "i0,i1" "integer")
+(define_query_cpu_unit "f0,f1" "float_media")
+(define_query_cpu_unit "b0,b1" "branch")
 
-;; slot1
-(exclusion_set "sl1_fm0" "sl2_b1")
-(exclusion_set "sl1_i1"  "sl2_fm1,sl2_b1,sl3_fm1,sl3_b0")
-(exclusion_set "sl1_fm1" "sl2_i1,sl2_b1,sl3_b0")
-(exclusion_set "sl1_b0"  "sl2_i1,sl2_fm1,sl3_fm1,sl3_b1")
-(exclusion_set "sl1_b1"  "sl2_i1,sl2_fm1,sl2_b0,sl3_fm1,sl3_b0")
+;; Division units.
+(define_cpu_unit "idiv1,idiv2" "idiv")
+(define_cpu_unit "div1,div2,root" "div")
 
-;; slot2
-(exclusion_set "sl2_i1"  "sl3_b1")
-(exclusion_set "sl2_fm1" "sl3_b1")
-(exclusion_set "sl2_b0"  "sl3_fm1")
-(exclusion_set "sl2_b1"  "sl3_fm1,sl3_b0")
+;; Control instructions cannot be packed with others.
+(define_reservation "c" "i0+i1+f0+f1+b0+b1")
 
-;; slot3
-(exclusion_set "sl1_fm0" "sl2_i1,sl2_fm1,sl2_b0,sl2_b1,sl3_fm1,sl3_b0,sl3_b1")
-(exclusion_set "sl3_fm1" "sl2_i1,sl2_fm1,sl2_b0,sl2_b1,sl3_b0,sl3_b1")
+;; Generic reservation for control insns
+(define_insn_reservation "control" 1
+  (eq_attr "type" "trap,spr,unknown,multi")
+  "c")
 
 ;; ::::::::::::::::::::
 ;; ::
@@ -576,23 +403,7 @@
 ;; ::
 ;; ::::::::::::::::::::
 
-;; Define reservation in order to describe only in terms of units.
-
-(define_reservation "i0" "sl0_i0")
-(define_reservation "f0" "sl0_fm0|sl1_fm0")
-(define_reservation "m0" "f0")
-(define_reservation "b0" "sl0_b0|sl1_b0|sl2_b0|sl3_b0")
-(define_reservation "c"  "sl0_c")
-(define_reservation "i1" "sl1_i1|sl2_i1")
-(define_reservation "f1" "sl1_fm1|sl2_fm1|sl3_fm1")
-(define_reservation "m1" "f1")
-(define_reservation "b1" "sl1_b1|sl2_b1|sl3_b1")
-
 ;; Integer insns
-;; It is not possibly to issue load & store in one VLIW insn.
-(define_cpu_unit "idiv1" "idiv")
-(define_cpu_unit "idiv2" "idiv")
-
 ;; Synthetic units used to describe issue restrictions.
 (define_automaton "fr500_integer")
 (define_cpu_unit "fr500_load0,fr500_load1,fr500_store0" "fr500_integer")
@@ -604,32 +415,32 @@
 (define_insn_reservation "fr500_i1_sethi" 0
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "sethi"))
-  "i0|i1")
+  "i1|i0")
 
 (define_insn_reservation "fr500_i1_setlo" 1
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "setlo"))
-  "i0|i1")
+  "i1|i0")
 
 (define_insn_reservation "fr500_i1_int" 1
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "int"))
-  "i0|i1")
+  "i1|i0")
 
 (define_insn_reservation "fr500_i1_mul" 3
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "mul"))
-  "i0|i1")
+  "i1|i0")
 
 (define_insn_reservation "fr500_i1_div" 19
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "div"))
-  "(i0|i1),(idiv1*18|idiv2*18)")
+  "(i1|i0),(idiv1*18|idiv2*18)")
 
 (define_insn_reservation "fr500_i2" 4
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "gload,fload"))
-  "(i0|i1) + (fr500_load0|fr500_load1)")
+  "(i1|i0) + (fr500_load0|fr500_load1)")
 
 (define_insn_reservation "fr500_i3" 0
   (and (eq_attr "cpu" "generic,fr500,tomcat")
@@ -652,51 +463,41 @@
 (define_insn_reservation "fr500_branch" 0
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "jump,branch,ccr"))
-  "b0|b1")
+  "b1|b0")
 
 (define_insn_reservation "fr500_call" 0
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "call"))
   "b0")
 
-;; Control insns.
-(define_insn_reservation "fr500_control" 0
-  (and (eq_attr "cpu" "generic,fr500,tomcat")
-       (eq_attr "type" "trap,spr"))
-  "c")
-
 ;; Floating point insns.  The default latencies are for non-media
 ;; instructions; media instructions incur an extra cycle.
 
-(define_cpu_unit "div1" "div")
-(define_cpu_unit "div2" "div")
-(define_cpu_unit "root" "div")
-
 (define_bypass 4 "fr500_farith" "fr500_m1,fr500_m2,fr500_m3,
 			         fr500_m4,fr500_m5,fr500_m6")
 (define_insn_reservation "fr500_farith" 3
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "fsconv,fsadd,fsmul,fsmadd,fdconv,fdadd,fdmul,fdmadd"))
-  "(f0|f1)")
+  "(f1|f0)")
 
 (define_insn_reservation "fr500_fcmp" 4
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "fscmp,fdcmp"))
-  "(f0|f1)")
+  "(f1|f0)")
 
 (define_bypass 11 "fr500_fdiv" "fr500_m1,fr500_m2,fr500_m3,
 			        fr500_m4,fr500_m5,fr500_m6")
 (define_insn_reservation "fr500_fdiv" 10
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "fsdiv,fddiv"))
-  "(f0|f1),(div1*9 | div2*9)")
+  "(f1|f0),(div1*9 | div2*9)")
 
 (define_bypass 16 "fr500_froot" "fr500_m1,fr500_m2,fr500_m3,
 				 fr500_m4,fr500_m5,fr500_m6")
 (define_insn_reservation "fr500_froot" 15
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "sqrt_single,sqrt_double"))
-  "(f0|f1) + root*15")
+  "(f1|f0) + root*15")
 
 ;; Media insns.  Conflict table is as follows:
 ;;
@@ -740,7 +541,7 @@
 (define_insn_reservation "fr500_m1" 3
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "mlogic,maveh,msath,maddh,mqaddh"))
-  "(m0|m1)")
+  "(f1|f0)")
 
 (define_bypass 2 "fr500_m2" "fr500_m1,fr500_m2,fr500_m3,
 			     fr500_m4,fr500_m5,fr500_m6")
@@ -748,19 +549,19 @@
 (define_insn_reservation "fr500_m2" 3
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "mrdacc,mpackh,munpackh,mbhconv,mrot,mshift,mexpdhw,mexpdhd,mwcut,mcut,mdunpackh,mbhconve"))
-  "(m0|m1) + (fr500_m2_0|fr500_m2_1)")
+  "(f1|f0) + (fr500_m2_0|fr500_m2_1)")
 
 (define_bypass 1 "fr500_m3" "fr500_m4")
 (define_insn_reservation "fr500_m3" 2
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "mclracc,mwtacc"))
-  "(m0|m1) + (fr500_m3_0|fr500_m3_1)")
+  "(f1|f0) + (fr500_m3_0|fr500_m3_1)")
 
 (define_bypass 1 "fr500_m4" "fr500_m4")
 (define_insn_reservation "fr500_m4" 2
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,mcpx,mqcpx"))
-  "(m0|m1) + (fr500_m4_0|fr500_m4_1)")
+  "(f1|f0) + (fr500_m4_0|fr500_m4_1)")
 
 (define_bypass 2 "fr500_m5" "fr500_m1,fr500_m2,fr500_m3,
 			     fr500_m4,fr500_m5,fr500_m6")
@@ -768,20 +569,13 @@
 (define_insn_reservation "fr500_m5" 3
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "mdpackh"))
-  "(m0|m1) + fr500_m5")
+  "(f1|f0) + fr500_m5")
 
 (define_bypass 1 "fr500_m6" "fr500_m4")
 (define_insn_reservation "fr500_m6" 2
   (and (eq_attr "cpu" "generic,fr500,tomcat")
        (eq_attr "type" "mclracca"))
-  "(m0|m1) + fr500_m6")
-
-;; Unknown & multi insns starts on new cycle and the next insn starts
-;; on new cycle.  To describe this we consider as a control insn.
-(define_insn_reservation "unknown" 1
-  (and (eq_attr "cpu" "generic,fr500,tomcat")
-       (eq_attr "type" "unknown,multi"))
-  "c")
+  "(f1|f0) + fr500_m6")
 
 ;; ::::::::::::::::::::
 ;; ::
@@ -793,17 +587,6 @@
 ;; with non-media instructions.  Use fr400_m1unit to claim the M1 unit
 ;; without claiming a slot.
 
-(define_cpu_unit "fr400_m1unit" "nodiv")
-
-(define_reservation "fr400_i0"      "sl0_i0")
-(define_reservation "fr400_i1"      "sl1_i1")
-(define_reservation "fr400_m0"      "sl0_fm0|sl1_fm0")
-(define_reservation "fr400_m1"      "sl1_fm1")
-(define_reservation "fr400_meither" "fr400_m0|(fr400_m1+fr400_m1unit)")
-(define_reservation "fr400_mboth"   "fr400_m0+fr400_m1unit")
-(define_reservation "fr400_b"       "sl0_b0|sl1_b0")
-(define_reservation "fr400_c"       "sl0_c")
-
 ;; Name		Class	Units	Latency
 ;; ====	        =====	=====	=======
 ;; int		I1	I0/I1	1
@@ -830,67 +613,52 @@
 (define_insn_reservation "fr400_i1_int" 1
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "int"))
-  "fr400_i0|fr400_i1")
+  "i1|i0")
 
 (define_insn_reservation "fr400_i1_sethi" 0
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "sethi"))
-  "fr400_i0|fr400_i1")
+  "i1|i0")
 
 (define_insn_reservation "fr400_i1_setlo" 1
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "setlo"))
-  "fr400_i0|fr400_i1")
+  "i1|i0")
 
 (define_insn_reservation "fr400_i1_mul" 3
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "mul"))
-  "fr400_i0")
+  "i0")
 
 (define_insn_reservation "fr400_i1_div" 20
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "div"))
-  "fr400_i0+idiv1*19")
-
-(define_insn_reservation "fr400_i2_gload" 4
-  (and (eq_attr "cpu" "fr400")
-       (eq_attr "type" "gload"))
-  "fr400_i0")
-
-(define_insn_reservation "fr400_i2_fload" 4
-  (and (eq_attr "cpu" "fr400")
-       (eq_attr "type" "fload"))
-  "fr400_i0")
-
-(define_insn_reservation "fr400_i3_gstore" 0
-  (and (eq_attr "cpu" "fr400")
-       (eq_attr "type" "gstore"))
-  "fr400_i0")
+  "i0 + idiv1*19")
 
-(define_insn_reservation "fr400_i3_fstore" 0
+(define_insn_reservation "fr400_i2" 4
   (and (eq_attr "cpu" "fr400")
-       (eq_attr "type" "fstore"))
-  "fr400_i0")
+       (eq_attr "type" "gload,fload"))
+  "i0")
 
-(define_insn_reservation "fr400_i4_movfg" 3
+(define_insn_reservation "fr400_i3" 0
   (and (eq_attr "cpu" "fr400")
-       (eq_attr "type" "movfg"))
-  "fr400_i0")
+       (eq_attr "type" "gstore,fstore"))
+  "i0")
 
-(define_insn_reservation "fr400_i4_movgf" 3
+(define_insn_reservation "fr400_i4" 3
   (and (eq_attr "cpu" "fr400")
-       (eq_attr "type" "movgf"))
-  "fr400_i0")
+       (eq_attr "type" "movfg,movgf"))
+  "i0")
 
-(define_insn_reservation "fr400_i5_jumpl" 0
+(define_insn_reservation "fr400_i5" 0
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "jumpl"))
-  "fr400_i0")
+  "i0")
 
 ;; The bypass between FPR loads and media instructions, described above.
 
 (define_bypass 3
-  "fr400_i2_fload"
+  "fr400_i2"
   "fr400_m1_1,fr400_m1_2,\
    fr400_m2_1,fr400_m2_2,\
    fr400_m3_1,fr400_m3_2,\
@@ -902,22 +670,7 @@
 (define_insn_reservation "fr400_b" 0
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "jump,branch,ccr,call"))
-  "fr400_b")
-
-;; Control instructions use the C unit, which excludes all the others.
-
-(define_insn_reservation "fr400_c" 0
-  (and (eq_attr "cpu" "fr400")
-       (eq_attr "type" "spr,trap"))
-  "fr400_c")
-
-;; Unknown instructions use the C unit, since it requires single-operation
-;; packets.
-
-(define_insn_reservation "fr400_unknown" 1
-  (and (eq_attr "cpu" "fr400")
-       (eq_attr "type" "unknown,multi"))
-  "fr400_c")
+  "b0")
 
 ;; FP->FP moves are marked as "fsconv" instructions in the define_insns
 ;; below, but are implemented on the FR400 using "mlogic" instructions.
@@ -930,12 +683,12 @@
 (define_insn_reservation "fr400_m1_1" 1
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "fsconv,mlogic,maveh,msath,maddh,mabsh,mset"))
-  "fr400_meither")
+  "f1|f0")
 
 (define_insn_reservation "fr400_m1_2" 1
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "mqaddh,mqsath"))
-  "fr400_mboth")
+  "f0+f1")
 
 ;; M2 instructions store their results in accumulators, which are read
 ;; by M2 or M4 media commands.  M2 instructions can read the results in
@@ -948,12 +701,12 @@
 (define_insn_reservation "fr400_m2_1" 2
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mcpx,maddacc"))
-  "fr400_meither")
+  "f1|f0")
 
 (define_insn_reservation "fr400_m2_2" 2
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "mqmulh,mqmulxh,mqmach,mqcpx,mdaddacc"))
-  "fr400_mboth")
+  "f0+f1")
 
 ;; For our purposes, there seems to be little real difference between
 ;; M1 and M3 instructions.  Keep them separate anyway in case the distinction
@@ -962,37 +715,35 @@
 (define_insn_reservation "fr400_m3_1" 1
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "mpackh,mrot,mshift,mexpdhw"))
-  "fr400_meither")
+  "f1|f0")
 
 (define_insn_reservation "fr400_m3_2" 1
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "munpackh,mdpackh,mbhconv,mexpdhd,mwcut,mdrot,mcpl"))
-  "fr400_mboth")
+  "f0+f1")
 
 ;; M4 instructions write to accumulators or FPRs.  MOVFG and STF
 ;; instructions can read an FPR result in the following cycle, but
 ;; M-unit instructions must wait a cycle more for either kind of result.
 
-(define_bypass 1
-  "fr400_m4_1,fr400_m4_2"
-  "fr400_i3_fstore,fr400_i4_movfg")
+(define_bypass 1 "fr400_m4_1,fr400_m4_2" "fr400_i3,fr400_i4")
 
 (define_insn_reservation "fr400_m4_1" 2
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "mrdacc,mcut,mclracc"))
-  "fr400_meither")
+  "f1|f0")
 
 (define_insn_reservation "fr400_m4_2" 2
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "mclracca,mdcut"))
-  "fr400_mboth")
+  "f0+f1")
 
 ;; M5 instructions always incur a 1-cycle penalty.
 
 (define_insn_reservation "fr400_m5" 2
   (and (eq_attr "cpu" "fr400")
        (eq_attr "type" "mwtacc"))
-  "fr400_mboth")
+  "f0+f1")
 
 ;; ::::::::::::::::::::
 ;; ::


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]