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]

[PATCH][2/3] Instruction patterns changes and instruction attributes


Hello Jeff,
Hello Andreas,

This patch updates most frequently used instructions in m68k so that
they would be recognized by scheduler DFA.  Along with that it clean ups
m68k machine description.

This patch has two logically independent part that would be hard to
separate in practice:

1. Splits.
m68k backend is the eldest in gcc.  It employs several techniques that
are now considered obsolete, one of such things, that makes scheduling
impossible, is using C code to emit best asm statement for a given rtl
insn.  This patch converts the most frequently used (on CFv2) patterns
to use constraints and alternatives instead of falling back to C.

2. Attributes.
In order to facilitate pipeline model with information about
instructions, several instruction attributes were added.  Due to
genattrtab limitations not all attributes are written in lisp-like
language, but rather in C.  Attributes can be optimized later, when the
whole set of them is stable (that is after adding scheduling support for
other processors).

This patch was tested on m68k-elf with V2 and V4 cores.

Ok for trunk?


Thanks,


Maxim
2007-08-09  Maxim Kuvyrkov  <maxim@codesourcery.com>

	* config/m68k/predicates.md (movsi_const0_operand,
	non_symbolic_call_operand): New predicates.

	* config/m68k/constraints.md: (Cs, Ci, C0, Cj, CQ, CW, CZ, CS, Ap, Ac):
	New constraints.
	* doc/md.texi (Constraints for Particular Machines: Motorola 680x0):
	Document constraints N, O, P, R, S, T, Q, U, W, Cs, Ci, C0, Cj, CQ,
	CW, CZ, CS, Ap and Ac.

	* config/m68k/m68k.md (UNSPEC_IB): New constant.
	(constraints.md): New include.
	(cpu, type, type1, opx, opy, opx_type, opy_type, size, opx_access,
	opx_mem, opy_mem, op_mem, guess, split): New attributes.
	(movdf_internal): Name pattern.  Fix to use alternatives.  Add split.
	Specify attributes.
	(pushdi): Add split.
	(tstsi_internal): Name pattern.  Fix to use alternatives.  Specify
	attributes.  Split tstsi_internal_68020_cf from it.
	(tstsi_internal_68020_cf): New pattern.
	(tsthi_internal, tstqi_internal): Name pattern.  Specify attributes.
	(tst<mode>_cf): Specify attributea.
	(cmpsi_cf): Name pattern.  Specify attributes.
	(cmp<mode>_68881, cmp<mode>_cf): Specify type attribute.
	(pushexthisi_const): Fix to use alternatives.  Specify
	attributes.
	(movsi_const0): Split movsi_const0_68000_10 and movsi_const0_68040_60
	from it.  Fix to use alternatives.  Specify attributes.
	(movsi_const0_68040_10, movsi_const0_68040_60): New patterns.
	(movsi_cf, movstrictqi_cf): Fix to use alternatives.  Specify
	attributes.
	(movsf_cf_soft): Specify attributes.
	(movdf_cf_soft): Add split.
	(pushasi, zero_extendhisi2_cf, zero_extendqisi2_cfv4,
	cfv4_extendhisi2, 68k_extendhisi2, extendqihi2, cfv4_extendqisi2,
	68k_extendqisi2, truncdfsf2_cf): Specify attributes.
	(truncdfsf2_68881): Name pattern.  Specify attributes.
	(floatsi<mode>2_cf, floathi<mode>2_68881, floathi<mode>2_cf,
	floatqi<mode>2_68881, floatqi<mode>2_cf, ftrunc<mode>2_cf,
	fix<mode>qi2_cf, fix<mode>hi2_cf, fix<mode>si2_cf, adddi_dishl32):
	Specify attributes.
	(addsi3_5200): Fix to use alternatives.  Specify attributes.
	Add splits.
	(add<mode>3_cf, subdi_dishl32): Specify attributes.
	(subsi3): Add alternative for subq.l.  Specify attributes.
	(sub<mode>3_cf, mulhi3, mulhisi3): Specify attributes.
	(mulhisisi3_s, mulsi3_68020, mulsi3_cf): Name pattern.  Specify
	attributes.
	(umulhisi3): Specify attributes.
	(mulhisisi3_z): Name pattern.  Specify attributes.
	(fmul<mode>3_cf, div<mode>3_cf, negsi2_internal, negsi2_5200,
	sqrt<mode>2_68881, clzsi2, one_cmplsi2_5200, subreghi1ashrdi_const32,
	subregsi1ashrdi_const32, ashrsi3, subreg1lshrdi_const32, lshrsi3,
	bsetmemqi): Specify attributes.
	(bsetmemqi_ext): Name pattern.  Specify attributes.
	(bclrmemqi): Specify attributes.
	(bclrmemqi_ext, scc, sls): Name pattern.  Specify attributes.
	(beq, bne, bgt, bgtu, blt, bltu, bge, bgeu, ble, bleu): Specify
	attributes.
	(beq2, bne2, bgt2, bgtu2, blt2, bltu2, bge2, bgeu2, ble2, bleu2): Name
	pattern.  Specify attributes.
	(jump): Specify attributes.
	(tablejump_internal): Name pattern.  Specify attributes.
	(call_value): Split into non_symbolic_call_value,
	symbolic_call_value_jsr, symbolic_call_value_bsr.  Fix to use
	alternatives.  Specify attributes.
	(non_symbolic_call_value, symbolic_call_value_jsr,
	symbolic_call_value_bsr): New patterns.
	(nop, return, unlink, indirect_jump): Specify attributes.
	(trap): Fix condition.  Specify attributes.
	(ib): New pattern.

	* config/m68k/m68k.c (m68k_symbolic_call_var): New variable.
	(override_options): Initialize it.  Initialize m68k_sched_cpu.
	(CONST_METHOD): Rename to M68K_CONST_METHOD, move to m68k.h.
	(const_method): Make global, rename to m68k_const_method.
	(const_int_cost, output_move_const_into_data_reg): Update.
	(output_move_double): Parametrize to emit rtl code, rename to
	handle_move_double.
	(output_reg_adjust, emit_reg_adjust, output_compadr, output_movsi,
	emit_movsi): New static functions.
	(output_move_double): New function with semantics of old
	output_move_double.
	(m68k_emit_move_double): New function.
	(m68k_sched_cpu): New variable.
	(attr_op_type): New enum.
	(sched_guess_p): New variable.
	(sched_address_type, sched_operand_type, sched_attr_op_type):
	New static functions.
	(m68k_sched_attr_opx_type, m68k_sched_attr_opy_type,
	m68k_sched_attr_size, m68k_sched_attr_op_mem): New functions.
	(sched_branch_type): New static variable.
	(m68k_sched_branch_type): New function.
	* config/m68k/m68k.h (M68K_SYMBOLIC_CALL): New enum.
	(m68k_symbolic_call_var): Declare.
	(M68K_CONST_METHOD): Rename from CONST_METHOD.  Move here from m68k.c.
	(m68k_const_method, m68k_emit_move_double, m68k_sched_cpu,
	m68k_sched_attr_opx_type, m68k_sched_attr_opy_type,
	m68k_sched_attr_size, m68k_sched_attr_op_mem, m68k_sched_branch_type):
	Declare.
diff -rup -x '*rej*' -x '*orig' -x '*.svn*' gnu2/gcc/config/m68k/constraints.md gnu/gcc/config/m68k/constraints.md
--- gnu2/gcc/config/m68k/constraints.md	2007-08-20 07:19:21.000000000 -0700
+++ gnu/gcc/config/m68k/constraints.md	2007-08-20 10:05:26.000000000 -0700
@@ -104,3 +104,51 @@
 (define_constraint "W"
   "Used for const_call_operands."
   (match_operand 0 "const_call_operand"))
+
+(define_constraint "Cs"
+  "symbol_ref or const."
+  (match_code "symbol_ref,const"))
+
+(define_constraint "Ci"
+  "const_int."
+  (and (match_code "const_int")
+       (match_test "true")))
+
+(define_constraint "C0"
+  "const_int 0."
+  (and (match_code "const_int")
+       (match_test "ival == 0")))
+
+(define_constraint "Cj"
+  "Range of signed numbers that don't fit in 16 bits."
+  (and (match_code "const_int")
+       (match_test "ival < -0x8000 || ival > 0x7FFF")))
+
+(define_constraint "CQ"
+  "Integers valid for mvq."
+  (and (match_code "const_int")
+       (match_test "m68k_const_method (ival) == MOVQ")))
+
+(define_constraint "CW"
+  "Integers valid for a moveq followed by a swap."
+  (and (match_code "const_int")
+       (match_test "m68k_const_method (ival) == SWAP")))
+
+(define_constraint "CZ"
+  "Integers valid for mvz."
+  (and (match_code "const_int")
+       (match_test "m68k_const_method (ival) == MVZ")))
+
+(define_constraint "CS"
+  "Integers valid for mvs."
+  (and (match_code "const_int")
+       (match_test "m68k_const_method (ival) == MVS")))
+
+(define_constraint "Ap"
+  "push_operand."
+  (match_operand 0 "push_operand"))
+
+(define_constraint "Ac"
+  "Non-register operands allowed in clr."
+  (and (match_operand 0 "movsi_const0_operand")
+       (match_test "!REG_P (op)")))
diff -rup -x '*rej*' -x '*orig' -x '*.svn*' gnu2/gcc/config/m68k/m68k.c gnu/gcc/config/m68k/m68k.c
--- gnu2/gcc/config/m68k/m68k.c	2007-08-20 07:19:21.000000000 -0700
+++ gnu/gcc/config/m68k/m68k.c	2007-08-20 09:56:30.000000000 -0700
@@ -347,6 +347,10 @@ unsigned int m68k_cpu_flags;
    in operand 0.  */
 const char *m68k_symbolic_call;
 const char *m68k_symbolic_jump;
+
+/* Enum variable that corresponds to m68k_symbolic_call values.  */
+enum M68K_SYMBOLIC_CALL m68k_symbolic_call_var;
+
 
 /* See whether TABLE has an entry with name NAME.  Return true and
    store the entry in *ENTRY if so, otherwise return false and
@@ -552,11 +556,11 @@ override_options (void)
 
   if (!flag_pic)
     {
+      m68k_symbolic_call_var = M68K_SYMBOLIC_CALL_JSR;
+
 #if MOTOROLA && !defined (USE_GAS)
-      m68k_symbolic_call = "jsr %a0";
       m68k_symbolic_jump = "jmp %a0";
 #else
-      m68k_symbolic_call = "jbsr %a0";
       m68k_symbolic_jump = "jra %a0";
 #endif
     }
@@ -566,15 +570,10 @@ override_options (void)
   else if (TARGET_68020 || TARGET_ISAB || TARGET_ISAC)
     {
       if (TARGET_PCREL)
-	m68k_symbolic_call = "bsr.l %c0";
+	m68k_symbolic_call_var = M68K_SYMBOLIC_CALL_BSR_C;
       else
-	{
-#if defined(USE_GAS)
-	  m68k_symbolic_call = "bsr.l %p0";
-#else
-	  m68k_symbolic_call = "bsr %p0";
-#endif
-	}
+	m68k_symbolic_call_var = M68K_SYMBOLIC_CALL_BSR_P;
+
       if (TARGET_ISAC)
 	/* No unconditional long branch */;
       else if (TARGET_PCREL)
@@ -594,7 +593,48 @@ override_options (void)
       flag_no_function_cse = 1;
     }
 
+  switch (m68k_symbolic_call_var)
+    {
+    case M68K_SYMBOLIC_CALL_JSR:
+#if MOTOROLA && !defined (USE_GAS)
+      m68k_symbolic_call = "jsr %a0";
+#else
+      m68k_symbolic_call = "jbsr %a0";
+#endif
+      break;
+
+    case M68K_SYMBOLIC_CALL_BSR_C:
+      m68k_symbolic_call = "bsr.l %c0";
+      break;
+
+    case M68K_SYMBOLIC_CALL_BSR_P:
+#if defined(USE_GAS)
+      m68k_symbolic_call = "bsr.l %p0";
+#else
+      m68k_symbolic_call = "bsr %p0";
+#endif
+      break;
+
+    case M68K_SYMBOLIC_CALL_NONE:
+      gcc_assert (m68k_symbolic_call == NULL);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
   SUBTARGET_OVERRIDE_OPTIONS;
+
+  /* Setup scheduling options.  */
+  if (TUNE_CFV2)
+    m68k_sched_cpu = CPU_CF_V2;
+  else
+    {
+      m68k_sched_cpu = CPU_UNKNOWN;
+      flag_schedule_insns = 0;
+      flag_schedule_insns_after_reload = 0;
+      flag_modulo_sched = 0;
+    }
 }
 
 /* Generate a macro of the form __mPREFIX_cpu_NAME, where PREFIX is the
@@ -2013,14 +2053,13 @@ legitimize_pic_address (rtx orig, enum m
 }
 
 
-typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ, MVS, MVZ } CONST_METHOD;
 
 #define USE_MOVQ(i)	((unsigned) ((i) + 128) <= 255)
 
 /* Return the type of move that should be used for integer I.  */
 
-static CONST_METHOD
-const_method (HOST_WIDE_INT i)
+M68K_CONST_METHOD
+m68k_const_method (HOST_WIDE_INT i)
 {
   unsigned u;
 
@@ -2066,7 +2105,7 @@ const_method (HOST_WIDE_INT i)
 static int
 const_int_cost (HOST_WIDE_INT i)
 {
-  switch (const_method (i))
+  switch (m68k_const_method (i))
     {
     case MOVQ:
       /* Constants between -128 and 127 are cheap due to moveq.  */
@@ -2230,7 +2269,7 @@ output_move_const_into_data_reg (rtx *op
   HOST_WIDE_INT i;
 
   i = INTVAL (operands[1]);
-  switch (const_method (i))
+  switch (m68k_const_method (i))
     {
     case MVZ:
       return "mvzw %1,%0";
@@ -2454,11 +2493,18 @@ singlemove_string (rtx *operands)
 }
 
 
-/* Output assembler code to perform a doubleword move insn
-   with operands OPERANDS.  */
+/* Output assembler or rtl code to perform a doubleword move insn
+   with operands OPERANDS.
+   Pointers to 3 helper functions should be specified:
+   HANDLE_REG_ADJUST to adjust a register by a small value,
+   HANDLE_COMPADR to compute an address and
+   HANDLE_MOVSI to move 4 bytes.  */
 
-const char *
-output_move_double (rtx *operands)
+static void
+handle_move_double (rtx operands[2],
+		    void (*handle_reg_adjust) (rtx, int),
+		    void (*handle_compadr) (rtx [2]),
+		    void (*handle_movsi) (rtx [2]))
 {
   enum
     {
@@ -2516,10 +2562,9 @@ output_move_double (rtx *operands)
   if (optype0 == PUSHOP && optype1 == POPOP)
     {
       operands[0] = XEXP (XEXP (operands[0], 0), 0);
-      if (size == 12)
-        output_asm_insn ("sub%.l #12,%0", operands);
-      else
-        output_asm_insn ("subq%.l #8,%0", operands);
+
+      handle_reg_adjust (operands[0], -size);
+
       if (GET_MODE (operands[1]) == XFmode)
 	operands[0] = gen_rtx_MEM (XFmode, operands[0]);
       else if (GET_MODE (operands[0]) == DFmode)
@@ -2531,10 +2576,9 @@ output_move_double (rtx *operands)
   if (optype0 == POPOP && optype1 == PUSHOP)
     {
       operands[1] = XEXP (XEXP (operands[1], 0), 0);
-      if (size == 12)
-        output_asm_insn ("sub%.l #12,%1", operands);
-      else
-        output_asm_insn ("subq%.l #8,%1", operands);
+
+      handle_reg_adjust (operands[1], -size);
+
       if (GET_MODE (operands[1]) == XFmode)
 	operands[1] = gen_rtx_MEM (XFmode, operands[1]);
       else if (GET_MODE (operands[1]) == DFmode)
@@ -2576,8 +2620,8 @@ output_move_double (rtx *operands)
 	}
       else
 	{
-	  middlehalf[0] = operands[0];
-	  latehalf[0] = operands[0];
+	  middlehalf[0] = adjust_address (operands[0], SImode, 0);
+	  latehalf[0] = adjust_address (operands[0], SImode, 0);
 	}
 
       if (optype1 == REGOP)
@@ -2612,8 +2656,8 @@ output_move_double (rtx *operands)
 	}
       else
 	{
-	  middlehalf[1] = operands[1];
-	  latehalf[1] = operands[1];
+	  middlehalf[1] = adjust_address (operands[1], SImode, 0);
+	  latehalf[1] = adjust_address (operands[1], SImode, 0);
 	}
     }
   else
@@ -2624,7 +2668,7 @@ output_move_double (rtx *operands)
       else if (optype0 == OFFSOP)
 	latehalf[0] = adjust_address (operands[0], SImode, size - 4);
       else
-	latehalf[0] = operands[0];
+	latehalf[0] = adjust_address (operands[0], SImode, 0);
 
       if (optype1 == REGOP)
 	latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
@@ -2633,7 +2677,7 @@ output_move_double (rtx *operands)
       else if (optype1 == CNSTOP)
 	split_double (operands[1], &operands[1], &latehalf[1]);
       else
-	latehalf[1] = operands[1];
+	latehalf[1] = adjust_address (operands[1], SImode, 0);
     }
 
   /* If insn is effectively movd N(sp),-(sp) then we will do the
@@ -2663,8 +2707,9 @@ output_move_double (rtx *operands)
 	compadr:
 	  xops[0] = latehalf[0];
 	  xops[1] = XEXP (operands[1], 0);
-	  output_asm_insn ("lea %a1,%0", xops);
-	  if (GET_MODE (operands[1]) == XFmode )
+
+	  handle_compadr (xops);
+	  if (GET_MODE (operands[1]) == XFmode)
 	    {
 	      operands[1] = gen_rtx_MEM (XFmode, latehalf[0]);
 	      middlehalf[1] = adjust_address (operands[1], DImode, size - 8);
@@ -2694,10 +2739,11 @@ output_move_double (rtx *operands)
 	  gcc_assert (!addreg0 && !addreg1);
 
 	  /* Only the middle reg conflicts; simply put it last.  */
-	  output_asm_insn (singlemove_string (operands), operands);
-	  output_asm_insn (singlemove_string (latehalf), latehalf);
-	  output_asm_insn (singlemove_string (middlehalf), middlehalf);
-	  return "";
+	  handle_movsi (operands);
+	  handle_movsi (latehalf);
+	  handle_movsi (middlehalf);
+
+	  return;
 	}
       else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)))
 	/* If the low half of dest is mentioned in the source memory
@@ -2721,85 +2767,194 @@ output_move_double (rtx *operands)
     {
       /* Make any unoffsettable addresses point at high-numbered word.  */
       if (addreg0)
-	{
-	  if (size == 12)
-	    output_asm_insn ("addq%.l #8,%0", &addreg0);
-	  else
-	    output_asm_insn ("addq%.l #4,%0", &addreg0);
-	}
+	handle_reg_adjust (addreg0, size - 4);
       if (addreg1)
-	{
-	  if (size == 12)
-	    output_asm_insn ("addq%.l #8,%0", &addreg1);
-	  else
-	    output_asm_insn ("addq%.l #4,%0", &addreg1);
-	}
+	handle_reg_adjust (addreg1, size - 4);
 
       /* Do that word.  */
-      output_asm_insn (singlemove_string (latehalf), latehalf);
+      handle_movsi (latehalf);
 
       /* Undo the adds we just did.  */
       if (addreg0)
-	output_asm_insn ("subq%.l #4,%0", &addreg0);
+	handle_reg_adjust (addreg0, -4);
       if (addreg1)
-	output_asm_insn ("subq%.l #4,%0", &addreg1);
+	handle_reg_adjust (addreg1, -4);
 
       if (size == 12)
 	{
-	  output_asm_insn (singlemove_string (middlehalf), middlehalf);
+	  handle_movsi (middlehalf);
+
 	  if (addreg0)
-	    output_asm_insn ("subq%.l #4,%0", &addreg0);
+	    handle_reg_adjust (addreg0, -4);
 	  if (addreg1)
-	    output_asm_insn ("subq%.l #4,%0", &addreg1);
+	    handle_reg_adjust (addreg1, -4);
 	}
 
       /* Do low-numbered word.  */
-      return singlemove_string (operands);
+
+      handle_movsi (operands);
+      return;
     }
 
   /* Normal case: do the two words, low-numbered first.  */
 
-  output_asm_insn (singlemove_string (operands), operands);
+  handle_movsi (operands);
 
   /* Do the middle one of the three words for long double */
   if (size == 12)
     {
       if (addreg0)
-	output_asm_insn ("addq%.l #4,%0", &addreg0);
+	handle_reg_adjust (addreg0, 4);
       if (addreg1)
-	output_asm_insn ("addq%.l #4,%0", &addreg1);
+	handle_reg_adjust (addreg1, 4);
 
-      output_asm_insn (singlemove_string (middlehalf), middlehalf);
+      handle_movsi (middlehalf);
     }
 
   /* Make any unoffsettable addresses point at high-numbered word.  */
   if (addreg0)
-    output_asm_insn ("addq%.l #4,%0", &addreg0);
+    handle_reg_adjust (addreg0, 4);
   if (addreg1)
-    output_asm_insn ("addq%.l #4,%0", &addreg1);
+    handle_reg_adjust (addreg1, 4);
 
   /* Do that word.  */
-  output_asm_insn (singlemove_string (latehalf), latehalf);
+  handle_movsi (latehalf);
 
   /* Undo the adds we just did.  */
   if (addreg0)
+    handle_reg_adjust (addreg0, -(size - 4));
+  if (addreg1)
+    handle_reg_adjust (addreg1, -(size - 4));
+
+  return;
+}
+
+/* Output assembler code to adjust REG by N.  */
+static void
+output_reg_adjust (rtx reg, int n)
+{
+  const char *s;
+
+  gcc_assert (GET_MODE (reg) == SImode
+	      && -12 <= n && n != 0 && n <= 12);
+
+  switch (n)
     {
-      if (size == 12)
-        output_asm_insn ("subq%.l #8,%0", &addreg0);
-      else
-        output_asm_insn ("subq%.l #4,%0", &addreg0);
+    case 12:
+      s = "add%.l #12,%0";
+      break;
+
+    case 8:
+      s = "addq%.l #8,%0";
+      break;
+
+    case 4:
+      s = "addq%.l #4,%0";
+      break;
+
+    case -12:
+      s = "sub%.l #12,%0";
+      break;
+
+    case -8:
+      s = "subq%.l #8,%0";
+      break;
+
+    case -4:
+      s = "subq%.l #4,%0";
+      break;
+
+    default:
+      gcc_unreachable ();
+      s = NULL;
     }
-  if (addreg1)
+
+  output_asm_insn (s, &reg);
+}
+
+/* Emit rtl code to adjust REG by N.  */
+static void
+emit_reg_adjust (rtx reg1, int n)
+{
+  rtx reg2;
+
+  gcc_assert (GET_MODE (reg1) == SImode
+	      && -12 <= n && n != 0 && n <= 12);
+
+  reg1 = copy_rtx (reg1);
+  reg2 = copy_rtx (reg1);
+
+  if (n < 0)
+    emit_insn (gen_subsi3 (reg1, reg2, GEN_INT (-n)));
+  else if (n > 0)
+    emit_insn (gen_addsi3 (reg1, reg2, GEN_INT (n)));
+  else
+    gcc_unreachable ();
+}
+
+/* Output assembler to load address OPERANDS[0] to register OPERANDS[1].  */
+static void
+output_compadr (rtx operands[2])
+{
+  output_asm_insn ("lea %a1,%0", operands);
+}
+
+/* Output the best assembler insn for moving operands[1] into operands[0]
+   as a fullword.  */
+static void
+output_movsi (rtx operands[2])
+{
+  output_asm_insn (singlemove_string (operands), operands);
+}
+
+/* Copy OP and change its mode to MODE.  */
+static rtx
+copy_operand (rtx op, enum machine_mode mode)
+{
+  /* ??? This looks really ugly.  There must be a better way
+     to change a mode on the operand.  */
+  if (GET_MODE (op) != VOIDmode)
     {
-      if (size == 12)
-        output_asm_insn ("subq%.l #8,%0", &addreg1);
+      if (REG_P (op))
+	op = gen_rtx_REG (mode, REGNO (op));
       else
-        output_asm_insn ("subq%.l #4,%0", &addreg1);
+	{
+	  op = copy_rtx (op);
+	  PUT_MODE (op, mode);
+	}
     }
 
+  return op;
+}
+
+/* Emit rtl code for moving operands[1] into operands[0] as a fullword.  */
+static void
+emit_movsi (rtx operands[2])
+{
+  operands[0] = copy_operand (operands[0], SImode);
+  operands[1] = copy_operand (operands[1], SImode);
+
+  emit_insn (gen_movsi (operands[0], operands[1]));
+}
+
+/* Output assembler code to perform a doubleword move insn
+   with operands OPERANDS.  */
+const char *
+output_move_double (rtx *operands)
+{
+  handle_move_double (operands,
+		      output_reg_adjust, output_compadr, output_movsi);
+
   return "";
 }
 
+/* Output rtl code to perform a doubleword move insn
+   with operands OPERANDS.  */
+void
+m68k_emit_move_double (rtx operands[2])
+{
+  handle_move_double (operands, emit_reg_adjust, emit_movsi, emit_movsi);
+}
 
 /* Ensure mode of ORIG, a REG rtx, is MODE.  Returns either ORIG or a
    new rtx with the correct mode.  */
@@ -4386,3 +4541,455 @@ m68k_function_value (tree valtype, tree 
   else
     return gen_rtx_REG (mode, D0_REG);
 }
+
+/* CPU to schedule the program for.  */
+enum attr_cpu m68k_sched_cpu;
+
+/* Operand type.  */
+enum attr_op_type
+  {
+    /* No operand.  */
+    OP_TYPE_NONE,
+
+    /* Register.  */
+    OP_TYPE_REG,
+
+    /* Implicit mem reference (e.g. stack).  */
+    OP_TYPE_MEM1,
+
+    /* Memory without offset or indexing.  EA modes 2, 3 and 4.  */
+    OP_TYPE_MEM234,
+
+    /* Memory with offset but without indexing.  EA mode 5.  */
+    OP_TYPE_MEM5,
+
+    /* Memory with indexing.  EA mode 6.  */
+    OP_TYPE_MEM6,
+
+    /* Memory referenced by absolute address.  EA mode 7.  */
+    OP_TYPE_MEM7,
+
+    /* Immediate operand that doesn't require extension word.  */
+    OP_TYPE_IMM_Q,
+
+    /* Immediate 16 bit operand.  */
+    OP_TYPE_IMM_W,
+
+    /* Immediate 32 bit operand.  */
+    OP_TYPE_IMM_L
+  };
+
+/* True if current insn doesn't have complete pipeline description.  */
+static bool sched_guess_p;
+
+/* Return type of memory ADDR_RTX refers to.  */
+static enum attr_op_type
+sched_address_type (enum machine_mode mode, rtx addr_rtx)
+{
+  struct m68k_address address;
+
+  if (!m68k_decompose_address (mode, addr_rtx,
+			       reload_completed, &address))
+    {
+      gcc_assert (sched_guess_p);
+      /* Reload will likely fix the address to be in the register.  */
+      return OP_TYPE_MEM234;
+    }
+
+  if (address.scale != 0)
+    return OP_TYPE_MEM6;
+
+  if (address.base != NULL_RTX)
+    {
+      if (address.offset == NULL_RTX)
+	return OP_TYPE_MEM234;
+
+      return OP_TYPE_MEM5;
+    }
+
+  gcc_assert (address.offset != NULL_RTX);
+
+  return OP_TYPE_MEM7;
+}
+
+/* Return type of the operand OP.
+   If ADDRESS_P is true, return type of memory location OP refers to.  */
+static enum attr_op_type
+sched_operand_type (rtx op, bool address_p)
+{
+  gcc_assert (op != NULL_RTX);
+
+  if (address_p)
+    return sched_address_type (QImode, op);
+
+  if (memory_operand (op, VOIDmode))
+    return sched_address_type (GET_MODE (op), XEXP (op, 0));
+
+  if (register_operand (op, VOIDmode))
+    return OP_TYPE_REG;
+
+  if (GET_CODE (op) == CONST_INT)
+    {
+      /* ??? Below condition should probably check if the operation is
+	 signed or unsigned.  */
+      if (IN_RANGE (INTVAL (op), -0x8000, 0x7fff))
+	return OP_TYPE_IMM_W;
+
+      return OP_TYPE_IMM_L;
+    }
+
+  if (GET_CODE (op) == CONST_DOUBLE)
+    {
+      switch (GET_MODE (op))
+	{
+	case SFmode:
+	  return OP_TYPE_IMM_W;
+
+	case VOIDmode:
+	case DFmode:
+	  return OP_TYPE_IMM_L;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+  if (symbolic_operand (op, VOIDmode)
+      || LABEL_P (op))
+    {
+      switch (GET_MODE (op))
+	{
+	case QImode:
+	  return OP_TYPE_IMM_Q;
+
+	case HImode:
+	  return OP_TYPE_IMM_W;
+
+	case SImode:
+	  return OP_TYPE_IMM_L;
+
+	default:
+	  if (GET_CODE (op) == SYMBOL_REF)
+	    /* ??? Just a guess.  Probably we can guess better using length
+	       attribute of the instructions.  */
+	    return OP_TYPE_IMM_W;
+
+	  return OP_TYPE_IMM_L;
+	}
+    }
+
+  gcc_assert (sched_guess_p);
+
+  return OP_TYPE_REG;
+}
+
+/* Return type of INSN's operand X (if OPX_P) or operand Y (if !OPX_P).
+   If ADDRESS_P is true, return type of memory location operand refers to.  */
+static enum attr_op_type
+sched_attr_op_type (rtx insn, bool opx_p, bool address_p)
+{
+  int i;
+
+  extract_constrain_insn_cached (insn);
+
+  if (opx_p)
+    i = get_attr_opx (insn);
+  else
+    i = get_attr_opy (insn);
+
+  if (i >= recog_data.n_operands)
+    {
+      gcc_assert (sched_guess_p);
+      return OP_TYPE_REG;
+    }
+
+  return sched_operand_type (recog_data.operand[i], address_p);
+}
+
+/* Implement opx_type attribute.
+   Return type of INSN's operand X.
+   If ADDRESS_P is true, return type of memory location operand refers to.  */
+enum attr_opx_type
+m68k_sched_attr_opx_type (rtx insn, int address_p)
+{
+  sched_guess_p = (get_attr_guess (insn) == GUESS_YES);
+
+  switch (sched_attr_op_type (insn, true, address_p != 0))
+    {
+    case OP_TYPE_REG:
+      return OPX_TYPE_REG;
+
+    case OP_TYPE_MEM1:
+      return OPX_TYPE_MEM1;
+
+    case OP_TYPE_MEM234:
+      return OPX_TYPE_MEM234;
+
+    case OP_TYPE_MEM5:
+      return OPX_TYPE_MEM5;
+
+    case OP_TYPE_MEM6:
+      return OPX_TYPE_MEM6;
+
+    case OP_TYPE_MEM7:
+      return OPX_TYPE_MEM7;
+
+    case OP_TYPE_IMM_Q:
+      return OPX_TYPE_IMM_Q;
+
+    case OP_TYPE_IMM_W:
+      return OPX_TYPE_IMM_W;
+
+    case OP_TYPE_IMM_L:
+      return OPX_TYPE_IMM_L;
+
+    default:
+      gcc_unreachable ();
+      return 0;
+    }
+}
+
+/* Implement opy_type attribute.
+   Return type of INSN's operand Y.
+   If ADDRESS_P is true, return type of memory location operand refers to.  */
+enum attr_opy_type
+m68k_sched_attr_opy_type (rtx insn, int address_p)
+{
+  sched_guess_p = (get_attr_guess (insn) == GUESS_YES);
+
+  switch (sched_attr_op_type (insn, false, address_p != 0))
+    {
+    case OP_TYPE_REG:
+      return OPY_TYPE_REG;
+
+    case OP_TYPE_MEM1:
+      return OPY_TYPE_MEM1;
+
+    case OP_TYPE_MEM234:
+      return OPY_TYPE_MEM234;
+
+    case OP_TYPE_MEM5:
+      return OPY_TYPE_MEM5;
+
+    case OP_TYPE_MEM6:
+      return OPY_TYPE_MEM6;
+
+    case OP_TYPE_MEM7:
+      return OPY_TYPE_MEM7;
+
+    case OP_TYPE_IMM_Q:
+      return OPY_TYPE_IMM_Q;
+
+    case OP_TYPE_IMM_W:
+      return OPY_TYPE_IMM_W;
+
+    case OP_TYPE_IMM_L:
+      return OPY_TYPE_IMM_L;
+
+    default:
+      gcc_unreachable ();
+      return 0;
+    }
+}
+
+/* Return the size of INSN.  */
+int
+m68k_sched_attr_size (rtx insn)
+{
+  int size;
+
+  sched_guess_p = (get_attr_guess (insn) == GUESS_YES);
+
+  switch (get_attr_type1 (insn))
+    {
+    case TYPE1_MUL_L:
+      size = 2;
+      break;
+
+    default:
+      size = 1;
+      break;
+    }
+
+  switch (get_attr_opx_type (insn))
+    {
+    case OPX_TYPE_NONE:
+    case OPX_TYPE_REG:
+    case OPX_TYPE_MEM1:
+    case OPX_TYPE_MEM234:
+    case OPY_TYPE_IMM_Q:
+      break;
+
+    case OPX_TYPE_MEM5:
+    case OPX_TYPE_MEM6:
+      /* Here we assume that most absolute references are short.  */
+    case OPX_TYPE_MEM7:
+    case OPY_TYPE_IMM_W:
+      ++size;
+      break;
+
+    case OPY_TYPE_IMM_L:
+      size += 2;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  switch (get_attr_opy_type (insn))
+    {
+    case OPY_TYPE_NONE:
+    case OPY_TYPE_REG:
+    case OPY_TYPE_MEM1:
+    case OPY_TYPE_MEM234:
+    case OPY_TYPE_IMM_Q:
+      break;
+
+    case OPY_TYPE_MEM5:
+    case OPY_TYPE_MEM6:
+      /* Here we assume that most absolute references are short.  */
+    case OPY_TYPE_MEM7:
+    case OPY_TYPE_IMM_W:
+      ++size;
+      break;
+
+    case OPY_TYPE_IMM_L:
+      size += 2;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  if (size > 3)
+    {
+      gcc_assert (sched_guess_p);
+
+      size = 3;
+    }
+
+  return size;
+}
+
+/* Implement op_mem attribute.  */
+enum attr_op_mem
+m68k_sched_attr_op_mem (rtx insn)
+{
+  enum attr_opy_mem opy;
+  enum attr_opx_mem opx;
+
+  sched_guess_p = (get_attr_guess (insn) == GUESS_YES);
+
+  opy = get_attr_opy_mem (insn);
+  opx = get_attr_opx_mem (insn);
+
+  if (opy == OPY_MEM_R && opx == OPX_MEM_R)
+    return OP_MEM_00;
+
+  if (opy == OPY_MEM_R && opx == OPX_MEM_M)
+    {
+      switch (get_attr_opx_access (insn))
+	{
+	case OPX_ACCESS_R:
+	  return OP_MEM_10;
+
+	case OPX_ACCESS_W:
+	  return OP_MEM_01;
+
+	case OPX_ACCESS_RW:
+	  return OP_MEM_11;
+
+	default:
+	  gcc_assert (sched_guess_p);
+	  return OP_MEM_UNKNOWN;
+	}
+    }
+
+  if (opy == OPY_MEM_R && opx == OPX_MEM_I)
+    {
+      switch (get_attr_opx_access (insn))
+	{
+	case OPX_ACCESS_R:
+	  return OP_MEM_I0;
+
+	case OPX_ACCESS_W:
+	  return OP_MEM_0I;
+
+	case OPX_ACCESS_RW:
+	  return OP_MEM_I1;
+
+	default:
+	  gcc_assert (sched_guess_p);
+	  return OP_MEM_UNKNOWN;
+	}
+    }
+
+  if (opy == OPY_MEM_M && opx == OPX_MEM_R)
+    return OP_MEM_10;
+
+  if (opy == OPY_MEM_M && opx == OPX_MEM_M)
+    {
+      switch (get_attr_opx_access (insn))
+	{
+	case OPX_ACCESS_W:
+	  return OP_MEM_11;
+
+	default:
+	  gcc_assert (sched_guess_p);
+	  return OP_MEM_UNKNOWN;
+	}
+    }
+
+  if (opy == OPY_MEM_M && opx == OPX_MEM_I)
+    {
+      switch (get_attr_opx_access (insn))
+	{
+	case OPX_ACCESS_W:
+	  return OP_MEM_1I;
+
+	default:
+	  gcc_assert (sched_guess_p);
+	  return OP_MEM_UNKNOWN;
+	}
+    }
+
+  if (opy == OPY_MEM_I && opx == OPX_MEM_R)
+    return OP_MEM_I0;
+
+
+  if (opy == OPY_MEM_I && opx == OPX_MEM_M)
+    {
+      switch (get_attr_opx_access (insn))
+	{
+	case OPX_ACCESS_W:
+	  return OP_MEM_I1;
+
+	default:
+	  gcc_assert (sched_guess_p);
+	  return OP_MEM_UNKNOWN;
+	}
+    }
+
+  gcc_assert (sched_guess_p);
+  return OP_MEM_UNKNOWN;
+}
+
+/* Jump instructions types.  Indexed by INSN_UID.
+   The same rtl insn can be expanded into different asm instructions
+   depending on the cc0_status.  To properly determine type of jump
+   instructions we scan instruction stream and map jumps types to this
+   array.  */
+static enum attr_type *sched_branch_type;
+
+/* Return the type of the jump insn.  */
+enum attr_type
+m68k_sched_branch_type (rtx insn)
+{
+  enum attr_type type;
+
+  type = sched_branch_type[INSN_UID (insn)];
+
+  gcc_assert (type != 0);
+
+  return type;
+}
diff -rup -x '*rej*' -x '*orig' -x '*.svn*' gnu2/gcc/config/m68k/m68k.h gnu/gcc/config/m68k/m68k.h
--- gnu2/gcc/config/m68k/m68k.h	2007-08-20 07:11:06.000000000 -0700
+++ gnu/gcc/config/m68k/m68k.h	2007-08-20 09:42:16.000000000 -0700
@@ -1125,3 +1125,27 @@ extern enum fpu_type m68k_fpu;
 extern unsigned int m68k_cpu_flags;
 extern const char *m68k_symbolic_call;
 extern const char *m68k_symbolic_jump;
+
+enum M68K_SYMBOLIC_CALL { M68K_SYMBOLIC_CALL_NONE, M68K_SYMBOLIC_CALL_JSR,
+			  M68K_SYMBOLIC_CALL_BSR_C, M68K_SYMBOLIC_CALL_BSR_P };
+
+extern enum M68K_SYMBOLIC_CALL m68k_symbolic_call_var;
+
+/* ??? HOST_WIDE_INT is not being defined for auto-generated files.
+   Workaround that.  */
+#ifdef HOST_WIDE_INT
+typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ, MVS, MVZ }
+  M68K_CONST_METHOD;
+
+extern M68K_CONST_METHOD m68k_const_method (HOST_WIDE_INT);
+#endif
+
+extern void m68k_emit_move_double (rtx [2]);
+
+extern enum attr_cpu m68k_sched_cpu;
+
+extern enum attr_opx_type m68k_sched_attr_opx_type (rtx, int);
+extern enum attr_opy_type m68k_sched_attr_opy_type (rtx, int);
+extern int m68k_sched_attr_size (rtx);
+extern enum attr_op_mem m68k_sched_attr_op_mem (rtx);
+extern enum attr_type m68k_sched_branch_type (rtx);
diff -rup -x '*rej*' -x '*orig' -x '*.svn*' gnu2/gcc/config/m68k/m68k.md gnu/gcc/config/m68k/m68k.md
--- gnu2/gcc/config/m68k/m68k.md	2007-08-20 07:19:21.000000000 -0700
+++ gnu/gcc/config/m68k/m68k.md	2007-08-20 10:08:37.000000000 -0700
@@ -114,6 +114,7 @@
   [(UNSPEC_SIN 1)
    (UNSPEC_COS 2)
    (UNSPEC_GOT 3)
+   (UNSPEC_IB 4)
   ])
 
 ;; UNSPEC_VOLATILE usage:
@@ -136,6 +137,205 @@
 (include "predicates.md")
 (include "constraints.md")
 
+;; ::::::::::::::::::::
+;; ::
+;; :: Attributes
+;; ::
+;; ::::::::::::::::::::
+
+;; Processor type.
+(define_attr "cpu" "cf_v2, unknown" (const (symbol_ref "m68k_sched_cpu")))
+
+;; Instruction type.
+;; Basically, an asm pattern.
+(define_attr "type"
+  "add_l, addq_l, asr_l, bcc, bclr, bra, bset, bsr,
+   clr_b, clr_w, clr_l, cmp_l,
+   ext_w, extb_l, ext_l,
+   fadd, fcmp, fdiv, ff1, fintrz, fmove, fmul, fsqrt, fsub, ftst, jmp, jsr,
+   ib,
+   lea, lsr_l,
+   move_b, move_w, move_l, moveq_l, mov3q_l, mvs_b, mvs_w, mvz_b, mvz_w,
+   muls_w, muls_l, mulu_w, mulu_l,
+   neg_l, nop, not_l,
+   pea, rts,
+   scc, sub_l, subq_l,
+   trap, tst_b, tst_l, tst_w,
+   unlk, unknown"
+  (const_string "unknown"))
+
+;; Instruction type for use in scheduling description.
+;; _l and _w suffixes indicate size of the operands of instruction.
+;; alu - usual arithmetic or logic instruction.
+;; alu_reg1 - arithmetic or logic instruction with one operand that is
+;;            a register.
+;; alu_regx - arithmetic or logic instruction which has a register for its
+;;            X operand.
+;; aluq - arithmetic or logic instruction which has a quick immediate (the one
+;;        that is encoded in the instruction word) for its Y operand.
+;; <all other values> - corresponding asm instructions.
+(define_attr "type1"
+  "alu_l, alu_reg1, alu_regx, aluq_l, bcc, bra, bsr, clr, cmp_l, jmp, jsr, lea,
+   mov3q_l, move, move_l, moveq_l, mul_l, mul_w, pea, rts, tst, tst_l, unlk,
+   unknown"
+  (cond [(eq_attr "type" "add_l,sub_l") (const_string "alu_l")
+	 (eq_attr "type" "ext_w,extb_l,ext_l,neg_l,not_l")
+	 (const_string "alu_reg1")
+	 (eq_attr "type" "asr_l,lsr_l") (const_string "alu_regx")
+	 (eq_attr "type" "addq_l,subq_l") (const_string "aluq_l")
+	 (eq_attr "type" "bcc") (const_string "bcc")
+	 (eq_attr "type" "bra") (const_string "bra")
+	 (eq_attr "type" "bsr") (const_string "bsr")
+	 (eq_attr "type" "clr_b,clr_l,clr_w") (const_string "clr")
+	 (eq_attr "type" "cmp_l") (const_string "cmp_l")
+	 (eq_attr "type" "jmp") (const_string "jmp")
+	 (eq_attr "type" "jsr") (const_string "jsr")
+	 (eq_attr "type" "lea") (const_string "lea")
+	 (eq_attr "type" "mov3q_l") (const_string "mov3q_l")
+	 (eq_attr "type" "move_b,move_w") (const_string "move")
+	 (eq_attr "type" "move_l") (const_string "move_l")
+	 (eq_attr "type" "moveq_l") (const_string "moveq_l")
+	 (eq_attr "type" "muls_l,mulu_l") (const_string "mul_l")
+	 (eq_attr "type" "muls_w,mulu_w") (const_string "mul_w")
+	 (eq_attr "type" "pea") (const_string "pea")
+	 (eq_attr "type" "rts") (const_string "rts")
+	 (eq_attr "type" "tst_b,tst_w") (const_string "tst")
+	 (eq_attr "type" "tst_l") (const_string "tst_l")
+	 (eq_attr "type" "unlk") (const_string "unlk")]
+	(const_string "unknown")))
+
+;; Index of the X or Y operand in recog_data.operand[].
+;; Should be used only within opx_type and opy_type.
+(define_attr "opx" "" (const_int 0))
+(define_attr "opy" "" (const_int 1))
+
+;; Type of the X operand.
+;; See m68k.c: enum attr_op_type.
+(define_attr "opx_type"
+  "none, reg, mem1, mem234, mem5, mem6, mem7, imm_q, imm_w, imm_l"
+  (cond [(eq_attr "type1" "rts,unlk") (const_string "none")
+	 (eq_attr "type1" "alu_reg1,alu_regx,lea,moveq_l,mul_l,mul_w")
+	 (const_string "reg")
+	 (eq_attr "type1" "pea") (const_string "mem1")
+	 (eq_attr "type1" "bcc") (const_string "imm_q")
+	 (eq_attr "type1" "bra,bsr") (const_string "imm_w")
+	 (eq_attr "type1" "jmp,jsr")
+	 (symbol_ref "m68k_sched_attr_opx_type (insn, 1)")]
+	(symbol_ref "m68k_sched_attr_opx_type (insn, 0)")))
+
+;; Type of the Y operand.
+;; See m68k.c: enum attr_op_type.
+(define_attr "opy_type"
+  "none, reg, mem1, mem234, mem5, mem6, mem7, imm_q, imm_w, imm_l"
+  (cond [(eq_attr "type1" "alu_reg1,bcc,bra,bsr,clr,jmp,jsr,rts,tst,tst_l,
+                           unlk") (const_string "none")
+	 (eq_attr "type1" "mov3q_l,moveq_l,aluq_l") (const_string "imm_q")
+	 (eq_attr "type1" "lea,pea")
+	 (symbol_ref "m68k_sched_attr_opy_type (insn, 1)")]
+	(symbol_ref "m68k_sched_attr_opy_type (insn, 0)")))
+
+;; Instruction size in words.
+(define_attr "size" ""
+  (cond [(eq_attr "type1" "alu_reg1,moveq_l,rts,unlk") (const_int 1)]
+	(symbol_ref "m68k_sched_attr_size (insn)")))
+
+;; Access to the X operand: none, read, write, read/write, unknown.
+;; Access to the Y operand is either none (if opy_type is none)
+;; or read otherwise.
+(define_attr "opx_access" "none, r, w, rw, unknown"
+  (cond [(eq_attr "type1" "rts,unlk") (const_string "none")
+	 (eq_attr "type1" "bcc,bra,bsr,cmp_l,jmp,jsr,tst,tst_l")
+	 (const_string "r")
+	 (eq_attr "type1" "clr,lea,mov3q_l,move,move_l,moveq_l,pea")
+	 (const_string "w")
+	 (eq_attr "type1" "alu_l,alu_reg1,alu_regx,aluq_l")
+	 (const_string "rw")]
+	(const_string "unknown")))
+
+;; Memory relation of operands:
+;; r - register or immediate operand
+;; m - non-indexed memory location
+;; i - indexed memory location
+
+(define_attr "opx_mem" "r, m, i, unknown"
+  (cond [(eq_attr "opx_type" "none,reg,imm_q,imm_w,imm_l") (const_string "r")
+	 (eq_attr "opx_type" "mem1,mem234,mem5,mem7") (const_string "m")
+	 (eq_attr "opx_type" "mem6") (const_string "i")]
+	(const_string "unknown")))
+
+(define_attr "opy_mem" "r, m, i, unknown"
+  (cond [(eq_attr "opy_type" "none,reg,imm_q,imm_w,imm_l") (const_string "r")
+	 (eq_attr "opy_type" "mem1,mem234,mem5,mem7") (const_string "m")
+	 (eq_attr "opy_type" "mem6") (const_string "i")]
+	(const_string "unknown")))
+
+;; Memory accesses of the insn.
+;; 00 - no memory references
+;; 10 - memory is read
+;; i10 - indexed memory is read
+;; 01 - memory is written
+;; 0i1 - indexed memory is written
+;; 11 - memory is read, memory is written
+;; i11 - indexed memory is read, memory is written
+;; 1i1 - memory is read, indexed memory is written
+;;
+;; unknown - should now occur on normal insn.
+;; ??? This attribute is implemented in C to spare genattrtab from
+;; ??? optimizing it.
+(define_attr "op_mem" "00, 10, i0, 01, 0i, 11, i1, 1i, unknown"
+;  (cond [(and (eq_attr "opy_mem" "r") (eq_attr "opx_mem" "r"))
+;	 (const_string "00")
+;
+;	 (and (eq_attr "opy_mem" "r") (eq_attr "opx_mem" "m"))
+;	 (cond [(eq_attr "opx_access" "r") (const_string "10")
+;	        (eq_attr "opx_access" "w") (const_string "01")
+;	        (eq_attr "opx_access" "rw") (const_string "11")]
+;	       (const_string "unknown"))
+;
+;	 (and (eq_attr "opy_mem" "r") (eq_attr "opx_mem" "i"))
+;	 (cond [(eq_attr "opx_access" "r") (const_string "i0")
+;	        (eq_attr "opx_access" "w") (const_string "0i")
+;		(eq_attr "opx_access" "rw") (const_string "i1")]
+;	       (const_string "unknown"))
+;
+;	 (and (eq_attr "opy_mem" "m") (eq_attr "opx_mem" "r"))
+;	 (const_string "10")
+;
+;	 (and (eq_attr "opy_mem" "m") (eq_attr "opx_mem" "m"))
+;	 (cond [(eq_attr "opx_access" "w") (const_string "11")]
+;	       (const_string "unknown"))
+;
+;	 (and (eq_attr "opy_mem" "m") (eq_attr "opx_mem" "i"))
+;	 (cond [(eq_attr "opx_access" "w") (const_string "1i")]
+;	       (const_string "unknown"))
+;
+;	 (and (eq_attr "opy_mem" "i") (eq_attr "opx_mem" "r"))
+;	 (const_string "i0")
+;
+;	 (and (eq_attr "opy_mem" "i") (eq_attr "opx_mem" "m"))
+;	 (cond [(eq_attr "opx_access" "w") (const_string "i1")]
+;	       (const_string "unknown"))]
+;	(const_string "unknown"))
+  (symbol_ref "m68k_sched_attr_op_mem (insn)"))
+
+;; Attribute to support partial automata description.
+;; This attribute has value 'yes' for instructions that are not
+;; fully handled yet.
+(define_attr "guess" "yes, no"
+  (cond [(ior (eq (symbol_ref "reload_completed") (const_int 0))
+	      (eq_attr "type1" "unknown"))
+	 (const_string "yes")]
+	(const_string "no")))
+
+;; Attribute to support statistics gathering.
+;; Todo means that insn lacks something to get pipeline description.
+;; Done means that insn was transformed to suit pipeline description.
+;; Nothing means that insn was originally good enough for scheduling. 
+(define_attr "split" "todo, done, nothing"
+  (if_then_else (eq_attr "type" "unknown")
+		(const_string "todo")
+		(const_string "nothing")))
+
 ;; Mode macros for floating point operations.
 ;; Valid floating point modes
 (define_mode_macro FP [SF DF (XF "TARGET_68881")])
@@ -150,22 +350,33 @@
 ;; Allowable 68881 constant constraints
 (define_mode_attr const [(SF "F") (DF "G") (XF "")])
 
-(define_insn ""
-  [(set (match_operand:DF 0 "push_operand" "=m")
-	(match_operand:DF 1 "general_operand" "ro<>fE"))]
+
+(define_insn_and_split "*movdf_internal"
+  [(set (match_operand:DF 0 "push_operand"   "=m, m")
+	(match_operand:DF 1 "general_operand" "f, ro<>E"))]
   ""
+  "@
+   fmove%.d %f1,%0
+   #"
+  "&& reload_completed && (extract_constrain_insn_cached (insn), which_alternative == 1)"
+  [(const_int 0)]
 {
-  if (FP_REG_P (operands[1]))
-    return "fmove%.d %f1,%0";
-  return output_move_double (operands);
-})
+  m68k_emit_move_double (operands);
+  DONE;
+}
+  [(set_attr "type" "fmove,*")
+   (set_attr "split" "done,*")])
 
-(define_insn "pushdi"
+(define_insn_and_split "pushdi"
   [(set (match_operand:DI 0 "push_operand" "=m")
 	(match_operand:DI 1 "general_operand" "ro<>Fi"))]
   ""
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
 {
-  return output_move_double (operands);
+  m68k_emit_move_double (operands);
+  DONE;
 })
 
 ;; We don't want to allow a constant operand for test insns because
@@ -194,12 +405,12 @@
       xoperands[0] = operands[2];
       xoperands[1] = operands[0];
       output_move_double (xoperands);
-      cc_status.flags |= CC_REVERSED;
+      cc_status.flags |= CC_REVERSED; /*|*/
       return "neg%.l %R2\;negx%.l %2";
     }
   if (find_reg_note (insn, REG_DEAD, operands[0]))
     {
-      cc_status.flags |= CC_REVERSED;
+      cc_status.flags |= CC_REVERSED; /*|*/
       return "neg%.l %R0\;negx%.l %0";
     }
   else
@@ -217,18 +428,24 @@
   ""
   "m68k_last_compare_had_fp_operands = 0;")
 
-(define_insn ""
+;; If you think that the 68020 does not support tstl a0,
+;; reread page B-167 of the 68020 manual more carefully.
+(define_insn "*tstsi_internal_68020_cf"
+  [(set (cc0)
+	(match_operand:SI 0 "nonimmediate_operand" "a"))]
+  "TARGET_68020 || TARGET_COLDFIRE"
+  "tst%.l %0"
+  [(set_attr "type" "tst_l")])
+
+;; On an address reg, cmpw may replace cmpl.
+(define_insn "*tstsi_internal"
   [(set (cc0)
-	(match_operand:SI 0 "nonimmediate_operand" "rm"))]
+	(match_operand:SI 0 "nonimmediate_operand" "dm,r"))]
   ""
-{
-  if (TARGET_68020 || TARGET_COLDFIRE || ! ADDRESS_REG_P (operands[0]))
-    return "tst%.l %0";
-  /* If you think that the 68020 does not support tstl a0,
-     reread page B-167 of the 68020 manual more carefully.  */
-  /* On an address reg, cmpw may replace cmpl.  */
-  return "cmp%.w #0,%0";
-})
+  "@
+   tst%.l %0
+   cmp%.w #0,%0"
+  [(set_attr "type" "tst_l,*")])
 
 ;; This can't use an address register, because comparisons
 ;; with address registers as second operand always test the whole word.
@@ -238,11 +455,12 @@
   ""
   "m68k_last_compare_had_fp_operands = 0;")
 
-(define_insn ""
+(define_insn "*tsthi_internal"
   [(set (cc0)
 	(match_operand:HI 0 "nonimmediate_operand" "dm"))]
   ""
-  "tst%.w %0")
+  "tst%.w %0"
+  [(set_attr "type" "tst_w")])
 
 (define_expand "tstqi"
   [(set (cc0)
@@ -250,11 +468,12 @@
   ""
   "m68k_last_compare_had_fp_operands = 0;")
 
-(define_insn ""
+(define_insn "*tstqi_internal"
   [(set (cc0)
 	(match_operand:QI 0 "nonimmediate_operand" "dm"))]
   ""
-  "tst%.b %0")
+  "tst%.b %0"
+  [(set_attr "type" "tst_b")])
 
 (define_expand "tst<mode>"
   [(set (cc0)
@@ -284,7 +503,8 @@
   if (FP_REG_P (operands[0]))
     return "ftst%.d %0";
   return "ftst%.<FP:prec> %0";
-})
+}
+  [(set_attr "type" "ftst")])
 
 
 ;; compare instructions.
@@ -309,7 +529,7 @@
     return "sub%.l %R2,%R0\;subx%.l %2,%0";
   else
     {
-      cc_status.flags |= CC_REVERSED;
+      cc_status.flags |= CC_REVERSED; /*|*/
       return "sub%.l %R1,%R0\;subx%.l %1,%0";
     }
 })
@@ -335,7 +555,7 @@
   if (REG_P (operands[1])
       || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
     {
-      cc_status.flags |= CC_REVERSED;
+      cc_status.flags |= CC_REVERSED; /*|*/
       return "cmp%.l %d0,%d1";
     }
   if (ADDRESS_REG_P (operands[0])
@@ -346,7 +566,7 @@
   return "cmp%.l %d1,%d0";
 })
 
-(define_insn ""
+(define_insn "*cmpsi_cf"
   [(set (cc0)
 	(compare (match_operand:SI 0 "nonimmediate_operand" "mrKs,r")
 		 (match_operand:SI 1 "general_operand" "r,mrKs")))]
@@ -355,11 +575,12 @@
   if (REG_P (operands[1])
       || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
     {
-      cc_status.flags |= CC_REVERSED;
+      cc_status.flags |= CC_REVERSED; /*|*/
       return "cmp%.l %d0,%d1";
     }
   return "cmp%.l %d1,%d0";
-})
+}
+  [(set_attr "type" "cmp_l")])
 
 (define_expand "cmphi"
   [(set (cc0)
@@ -403,7 +624,7 @@
   if (REG_P (operands[1])
       || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
     {
-      cc_status.flags |= CC_REVERSED;
+      cc_status.flags |= CC_REVERSED; /*|*/
       return "cmp%.b %d0,%d1";
     }
   return "cmp%.b %d1,%d0";
@@ -434,9 +655,10 @@
       else
         return "fcmp%.<FP:prec> %f1,%0";
     }
-  cc_status.flags |= CC_REVERSED;
+  cc_status.flags |= CC_REVERSED; /*|*/
   return "fcmp%.<FP:prec> %f0,%1";
-})
+}
+  [(set_attr "type" "fcmp")])
 
 (define_insn "cmp<mode>_cf"
   [(set (cc0)
@@ -452,9 +674,10 @@
       else
 	return "fcmp%.<FP:prec> %f1,%0";
     }
-  cc_status.flags |= CC_REVERSED;
+  cc_status.flags |= CC_REVERSED; /*|*/
   return "fcmp%.<FP:prec> %f0,%1";
-})
+}
+  [(set_attr "type" "fcmp")])
 
 ;; Recognizers for btst instructions.
 
@@ -578,16 +801,15 @@
 ;; A special case in which it is not desirable
 ;; to reload the constant into a data register.
 (define_insn "pushexthisi_const"
-  [(set (match_operand:SI 0 "push_operand" "=m")
-	(match_operand:SI 1 "const_int_operand" "J"))]
+  [(set (match_operand:SI 0 "push_operand" "=m,m,m")
+	(match_operand:SI 1 "const_int_operand" "C0,R,J"))]
   "INTVAL (operands[1]) >= -0x8000 && INTVAL (operands[1]) < 0x8000"
-{
-  if (operands[1] == const0_rtx)
-    return "clr%.l %0";
-  if (valid_mov3q_const (INTVAL (operands[1])))
-    return "mov3q%.l %1,%-";
-  return "pea %a1";
-})
+  "@
+   clr%.l %0
+   mov3q%.l %1,%-
+   pea %a1"
+  [(set_attr "type" "clr_l,mov3q_l,pea")
+   (set_attr "split" "done")])
 
 ;This is never used.
 ;(define_insn "swapsi"
@@ -597,30 +819,39 @@
 ;  ""
 ;  "exg %1,%0")
 
-;; Special case of fullword move when source is zero.
-;; The reason this is special is to avoid loading a zero
-;; into a data reg with moveq in order to store it elsewhere.
+;; Special case of fullword move when source is zero for 68000_10.
+;; moveq is faster on the 68000.
+(define_insn "*movsi_const0_68000_10"
+  [(set (match_operand:SI 0 "movsi_const0_operand" "=d")
+	(const_int 0))]
+  "TUNE_68000_10"
+  "moveq #0,%0"
+  [(set_attr "type" "moveq_l")
+   (set_attr "opy_type" "imm_q")
+   (set_attr "split" "done")])
+
+;; Special case of fullword move when source is zero for 68040_60.
+;; On the '040, 'subl an,an' takes 2 clocks while lea takes only 1
+(define_insn "*movsi_const0_68040_60"
+  [(set (match_operand:SI 0 "movsi_const0_operand" "=a")
+	(const_int 0))]
+  "TUNE_68040_60"
+  "* return MOTOROLA ? \"lea 0.w,%0\" : \"lea 0:w,%0\";"
+  [(set_attr "type" "lea")
+   (set_attr "opy_type" "imm_w")
+   (set_attr "split" "done")])
 
-(define_insn "movsi_const0"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
+;; Special case of fullword move when source is zero.
+(define_insn "*movsi_const0"
+  [(set (match_operand:SI 0 "movsi_const0_operand" "=a,g")
 	(const_int 0))]
-  ;; clr insns on 68000 read before writing.
-  "((TARGET_68010 || TARGET_COLDFIRE)
-    || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))"
-{
-  if (ADDRESS_REG_P (operands[0]))
-    {
-      /* On the '040, 'subl an,an' takes 2 clocks while lea takes only 1 */
-      if (TUNE_68040_60)
-	return MOTOROLA ? "lea 0.w,%0" : "lea 0:w,%0";
-      else
-	return "sub%.l %0,%0";
-    }
-  /* moveq is faster on the 68000.  */
-  if (DATA_REG_P (operands[0]) && TUNE_68000_10)
-    return "moveq #0,%0";
-  return "clr%.l %0";
-})
+  ""
+  "@
+   sub%.l %0,%0
+   clr%.l %0"
+  [(set_attr "type" "sub_l,clr_l")
+   (set_attr "opy_type" "reg,*")
+   (set_attr "split" "done")])
 
 ;; General case of fullword move.
 ;;
@@ -688,10 +919,59 @@
 
 ;; ColdFire move instructions can have at most one operand of mode >= 6.
 (define_insn "*movsi_cf"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r<Q>,g,U")
-	(match_operand:SI 1 "general_operand" "g,Rr<Q>,U"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=g,d, d, d, d, d, a,Ap,  a,  r<Q>,g,    U")
+	(match_operand:SI 1 "general_operand"      " R,CQ,CW,CZ,CS,Ci,J,J Cs,Cs, g,   Rr<Q>,U"))]
   "TARGET_COLDFIRE"
-  "* return output_move_simode (operands);")
+{
+  switch (which_alternative)
+    {
+    case 0:
+      return "mov3q%.l %1,%0";
+
+    case 1:
+      return "moveq %1,%0";
+
+    case 2:
+      {
+	unsigned u = INTVAL (operands[1]);
+
+	operands[1] = GEN_INT ((u << 16) | (u >> 16));  /*|*/
+	return "moveq %1,%0\n\tswap %0";
+      }
+
+    case 3:
+      return "mvz%.w %1,%0";
+
+    case 4:
+      return "mvs%.w %1,%0";
+
+    case 5:
+      return "move%.l %1,%0";
+
+    case 6:
+      return "move%.w %1,%0";
+
+    case 7:
+      return "pea %a1";
+
+    case 8:
+      return "lea %a1,%0";
+
+    case 9:
+    case 10:
+    case 11:
+      return "move%.l %1,%0";
+
+    default:
+      gcc_unreachable ();
+      return "";
+    }
+}
+  [(set_attr "type" "mov3q_l, moveq_l,*, mvz_w, mvs_w, move_l, move_w, pea, lea, move_l, move_l, move_l")
+   (set (attr "split")
+	(if_then_else (eq_attr "alternative" "2")
+		      (const_string "*")
+		      (const_string "done")))])
 
 ;; Special case of fullword move, where we need to get a non-GOT PIC
 ;; reference into an address register.
@@ -771,11 +1051,17 @@
   "!TARGET_COLDFIRE"
   "* return output_move_strictqi (operands);")
 
-(define_insn ""
-  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+d,m"))
-	(match_operand:QI 1 "general_src_operand" "dmn,d"))]
+(define_insn "*movstrictqi_cf"
+  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+d, Ac, d,m"))
+	(match_operand:QI 1 "general_src_operand"                    "C0,C0, dmn,d"))]
   "TARGET_COLDFIRE"
-  "* return output_move_strictqi (operands);")
+  "@
+   clr%.b %0
+   clr%.b %0
+   move%.b %1,%0
+   move%.b %1,%0"
+  [(set_attr "type" "clr_b,clr_b,move_b,move_b")
+   (set_attr "split" "done")])
 
 (define_expand "pushqi1"
   [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -2)))
@@ -864,9 +1150,8 @@
   [(set (match_operand:SF 0 "nonimmediate_operand" "=r<Q>,g,U")
 	(match_operand:SF 1 "general_operand" "g,r<Q>,U"))]
   "TARGET_COLDFIRE && !TARGET_COLDFIRE_FPU"
-{
-  return "move%.l %1,%0";
-})
+  "move%.l %1,%0"
+  [(set_attr "type" "move_l")])
 
 ;; SFmode MEMs are restricted to modes 2-4 if TARGET_COLDFIRE_FPU.
 ;; The move instructions can handle all combinations.
@@ -1003,12 +1288,16 @@
   return output_move_double (operands);
 })
 
-(define_insn "movdf_cf_soft"
+(define_insn_and_split "movdf_cf_soft"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=r,g")
 	(match_operand:DF 1 "general_operand" "g,r"))]
   "TARGET_COLDFIRE && !TARGET_COLDFIRE_FPU"
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
 {
-  return output_move_double (operands);
+  m68k_emit_move_double (operands);
+  DONE;
 })
 
 (define_insn "movdf_cf_hard"
@@ -1230,7 +1519,8 @@
   [(set (match_operand:SI 0 "push_operand" "=m")
 	(match_operand:SI 1 "address_operand" "p"))]
   ""
-  "pea %a1")
+  "pea %a1"
+  [(set_attr "type" "pea")])
 
 ;; truncation instructions
 (define_insn "truncsiqi2"
@@ -1391,7 +1681,8 @@
   [(set (match_operand:SI 0 "register_operand" "=d")
 	(zero_extend:SI (match_operand:HI 1 "nonimmediate_src_operand" "rmS")))]
   "ISA_HAS_MVS_MVZ"
-  "mvz%.w %1,%0")
+  "mvz%.w %1,%0"
+  [(set_attr "type" "mvz_w")])
 
 (define_insn "zero_extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "=d")
@@ -1415,7 +1706,8 @@
   [(set (match_operand:SI 0 "register_operand" "=d")
 	(zero_extend:SI (match_operand:QI 1 "nonimmediate_src_operand" "dmS")))]
   "ISA_HAS_MVS_MVZ"
-  "mvz%.b %1,%0")
+  "mvz%.b %1,%0"
+  [(set_attr "type" "mvz_b")])
 
 (define_insn "zero_extendqisi2"
   [(set (match_operand:SI 0 "register_operand" "=d")
@@ -1567,24 +1859,25 @@
 	(sign_extend:SI
 	 (match_operand:HI 1 "nonimmediate_src_operand" "rmS")))]
   "ISA_HAS_MVS_MVZ"
-  "mvs%.w %1,%0")
+  "mvs%.w %1,%0"
+  [(set_attr "type" "mvs_w")])
 
 (define_insn "*68k_extendhisi2"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=*d,a")
 	(sign_extend:SI
 	 (match_operand:HI 1 "nonimmediate_src_operand" "0,rmS")))]
   "!ISA_HAS_MVS_MVZ"
-{
-  if (ADDRESS_REG_P (operands[0]))
-    return "move%.w %1,%0";
-  return "ext%.l %0";
-})
+  "@
+   ext%.l %0
+   move%.w %1,%0"
+  [(set_attr "type" "ext_l,move_w")])
 
 (define_insn "extendqihi2"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=d")
 	(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0")))]
   ""
-  "ext%.w %0")
+  "ext%.w %0"
+  [(set_attr "type" "ext_w")])
 
 (define_expand "extendqisi2"
   [(set (match_operand:SI 0 "nonimmediate_operand" "")
@@ -1596,13 +1889,15 @@
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
 	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rms")))]
   "ISA_HAS_MVS_MVZ"
-  "mvs%.b %1,%0")
+  "mvs%.b %1,%0"
+  [(set_attr "type" "mvs_b")])
 
 (define_insn "*68k_extendqisi2"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
 	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0")))]
   "TARGET_68020 || (TARGET_COLDFIRE && !ISA_HAS_MVS_MVZ)"
-  "extb%.l %0")
+  "extb%.l %0"
+  [(set_attr "type" "extb_l")])
 
 ;; Conversions between float and double.
 
@@ -1691,14 +1986,16 @@
   "TARGET_COLDFIRE_FPU"
   "@
   fsmove%.d %1,%0
-  fmove%.s %1,%0")
+  fmove%.s %1,%0"
+  [(set_attr "type" "fmove")])
 
-(define_insn ""
+(define_insn "*truncdfsf2_68881"
   [(set (match_operand:SF 0 "nonimmediate_operand" "=dm")
 	(float_truncate:SF
 	  (match_operand:DF 1 "general_operand" "f")))]
   "TARGET_68881"
-  "fmove%.s %f1,%0")
+  "fmove%.s %f1,%0"
+  [(set_attr "type" "fmove")])
 
 ;; Conversion between fixed point and floating point.
 ;; Note that among the fix-to-float insns
@@ -1724,7 +2021,8 @@
   [(set (match_operand:FP 0 "nonimmediate_operand" "=f")
 	(float:FP (match_operand:SI 1 "general_operand" "d<Q>U")))]
   "TARGET_COLDFIRE_FPU"
-  "f<FP:prec>move%.l %1,%0")
+  "f<FP:prec>move%.l %1,%0"
+  [(set_attr "type" "fmove")])
 
 
 (define_expand "floathi<mode>2"
@@ -1737,13 +2035,15 @@
   [(set (match_operand:FP 0 "nonimmediate_operand" "=f")
 	(float:FP (match_operand:HI 1 "general_operand" "dmn")))]
   "TARGET_68881"
-  "fmove%.w %1,%0")
+  "fmove%.w %1,%0"
+  [(set_attr "type" "fmove")])
 
 (define_insn "floathi<mode>2_cf"
   [(set (match_operand:FP 0 "nonimmediate_operand" "=f")
         (float:FP (match_operand:HI 1 "general_operand" "d<Q>U")))]
   "TARGET_COLDFIRE_FPU"
-  "fmove%.w %1,%0")
+  "fmove%.w %1,%0"
+  [(set_attr "type" "fmove")])
 
 
 (define_expand "floatqi<mode>2"
@@ -1756,13 +2056,15 @@
   [(set (match_operand:FP 0 "nonimmediate_operand" "=f")
 	(float:FP (match_operand:QI 1 "general_operand" "dmn")))]
   "TARGET_68881"
-  "fmove%.b %1,%0")
+  "fmove%.b %1,%0"
+  [(set_attr "type" "fmove")])
 
 (define_insn "floatqi<mode>2_cf"
   [(set (match_operand:FP 0 "nonimmediate_operand" "=f")
 	(float:FP (match_operand:QI 1 "general_operand" "d<Q>U")))]
   "TARGET_COLDFIRE_FPU"
-  "fmove%.b %1,%0")
+  "fmove%.b %1,%0"
+  [(set_attr "type" "fmove")])
 
 
 ;; New routines to convert floating-point values to integers
@@ -1830,7 +2132,8 @@
   if (FP_REG_P (operands[1]))
     return "fintrz%.d %f1,%0";
   return "fintrz%.<FP:prec> %f1,%0";
-})
+}
+  [(set_attr "type" "fintrz")])
 
 ;; Convert a float whose value is an integer
 ;; to an actual integer.  Second stage of converting float to integer type.
@@ -1850,7 +2153,8 @@
   [(set (match_operand:QI 0 "nonimmediate_operand" "=d<Q>U")
 	(fix:QI (match_operand:FP 1 "general_operand" "f")))]
   "TARGET_COLDFIRE_FPU"
-  "fmove%.b %1,%0")
+  "fmove%.b %1,%0"
+  [(set_attr "type" "fmove")])
 
 (define_expand "fix<mode>hi2"
   [(set (match_operand:HI 0 "nonimmediate_operand" "")
@@ -1868,7 +2172,8 @@
   [(set (match_operand:HI 0 "nonimmediate_operand" "=d<Q>U")
 	(fix:HI (match_operand:FP 1 "general_operand" "f")))]
   "TARGET_COLDFIRE_FPU"
-  "fmove%.w %1,%0")
+  "fmove%.w %1,%0"
+  [(set_attr "type" "fmove")])
 
 (define_expand "fix<mode>si2"
   [(set (match_operand:SI 0 "nonimmediate_operand" "")
@@ -1886,7 +2191,8 @@
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d<Q>U")
 	(fix:SI (match_operand:FP 1 "general_operand" "f")))]
   "TARGET_COLDFIRE_FPU"
-  "fmove%.l %1,%0")
+  "fmove%.l %1,%0"
+  [(set_attr "type" "fmove")])
 
 
 ;; add instructions
@@ -1984,7 +2290,8 @@
   else
     operands[1] = adjust_address (operands[1], SImode, 4);
   return "add%.l %1,%0";
-})
+}
+  [(set_attr "type" "add_l")])
 
 (define_insn "adddi3"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=o<>,d,d,d")
@@ -2107,12 +2414,54 @@
   "! TARGET_COLDFIRE"
   "* return output_addsi3 (operands);")
 
-(define_insn "*addsi3_5200"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?a,?a,r")
-	(plus:SI (match_operand:SI 1 "general_operand" "%0,a,rJK,0")
-		 (match_operand:SI 2 "general_src_operand" "dIL,rJK,a,mrIKLi")))]
+(define_insn_and_split "*addsi3_5200"
+  [(set (match_operand:SI 0 "nonimmediate_operand"         "=mr,mr,m,r,  ?a,?a,?a,?a")
+	(plus:SI (match_operand:SI 1 "general_operand"     "%0, 0, 0,0,   a, a, r, a")
+		 (match_operand:SI 2 "general_src_operand" " I, L, d,mrKi,Cj,r, a, J")))]
   "TARGET_COLDFIRE"
-  "* return output_addsi3 (operands);")
+{
+  switch (which_alternative)
+    {
+    case 0:
+      return "addq%.l %2,%0";
+
+    case 1:
+      operands[2] = GEN_INT (- INTVAL (operands[2]));
+      return "subq%.l %2,%0";
+
+    case 2:
+    case 3:
+      return "add%.l %2,%0";
+
+    case 4:
+      /* move%.l %2,%0\n\tadd%.l %1,%0 */
+      return "#";
+
+    case 5:
+      return MOTOROLA ? "lea (%1,%2.l),%0" : "lea %1@(0,%2:l),%0";
+
+    case 6:
+      return MOTOROLA ? "lea (%2,%1.l),%0" : "lea %2@(0,%1:l),%0";
+
+    case 7:
+      return MOTOROLA ? "lea (%c2,%1),%0" : "lea %1@(%c2),%0";
+
+    default:
+      gcc_unreachable ();
+      return "";
+    }
+}
+  "reload_completed && (extract_constrain_insn_cached (insn), which_alternative == 4)"
+  [(set (match_dup 0)
+	(match_dup 2))
+   (set (match_dup 0)
+	(plus:SI (match_dup 0)
+		 (match_dup 1)))]
+  ""
+  [(set_attr "type" "addq_l,subq_l,add_l,add_l,*,lea,lea,lea")
+   (set_attr "opy" "2,2,2,2,*,*,*,*")
+   (set_attr "opy_type" "*,*,*,*,*,mem6,mem6,mem5")
+   (set_attr "split" "done,done,done,done,*,done,done,done")])
 
 (define_insn ""
   [(set (match_operand:SI 0 "nonimmediate_operand" "=a")
@@ -2392,7 +2741,8 @@
   if (FP_REG_P (operands[2]))
     return "f<FP:prec>add%.d %2,%0";
   return "f<FP:prec>add%.<FP:prec> %2,%0";
-})
+}
+  [(set_attr "type" "fadd")])
 
 ;; subtract instructions
 
@@ -2426,7 +2776,8 @@
   else
     operands[1] = adjust_address (operands[1], SImode, 4);
   return "sub%.l %1,%0";
-})
+}
+  [(set_attr "type" "sub_l")])
 
 (define_insn "subdi3"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=o<>,d,d,d")
@@ -2508,11 +2859,17 @@
 })
 
 (define_insn "subsi3"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=m,d,a")
-	(minus:SI (match_operand:SI 1 "general_operand" "0,0,0")
-		  (match_operand:SI 2 "general_src_operand" "dT,mSrT,mSrs")))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=mda,m,d,a")
+	(minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0")
+		  (match_operand:SI 2 "general_src_operand" "I,dT,mSrT,mSrs")))]
   ""
-  "sub%.l %2,%0")
+  "@
+   subq%.l %2, %0
+   sub%.l %2,%0
+   sub%.l %2,%0
+   sub%.l %2,%0"
+  [(set_attr "type" "subq_l,sub_l,sub_l,sub_l")
+   (set_attr "opy" "2")])
 
 (define_insn ""
   [(set (match_operand:SI 0 "nonimmediate_operand" "=a")
@@ -2598,7 +2955,8 @@
   if (FP_REG_P (operands[2]))
     return "f<FP:prec>sub%.d %2,%0";
   return "f<FP:prec>sub%.<FP:prec> %2,%0";
-})
+}
+  [(set_attr "type" "fsub")])
 
 ;; multiply instructions
 
@@ -2609,7 +2967,9 @@
   ""
 {
   return MOTOROLA ? "muls%.w %2,%0" : "muls %2,%0";
-})
+}
+  [(set_attr "type" "muls_w")
+   (set_attr "opy" "2")])
 
 (define_insn "mulhisi3"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
@@ -2620,9 +2980,11 @@
   ""
 {
   return MOTOROLA ? "muls%.w %2,%0" : "muls %2,%0";
-})
+}
+  [(set_attr "type" "muls_w")
+   (set_attr "opy" "2")])
 
-(define_insn ""
+(define_insn "*mulhisisi3_s"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
 	(mult:SI (sign_extend:SI
 		  (match_operand:HI 1 "nonimmediate_operand" "%0"))
@@ -2630,7 +2992,9 @@
   "INTVAL (operands[2]) >= -0x8000 && INTVAL (operands[2]) <= 0x7fff"
 {
   return MOTOROLA ? "muls%.w %2,%0" : "muls %2,%0";
-})
+}
+  [(set_attr "type" "muls_w")
+   (set_attr "opy" "2")])
 
 (define_expand "mulsi3"
   [(set (match_operand:SI 0 "nonimmediate_operand" "")
@@ -2639,20 +3003,24 @@
   "TARGET_68020 || TARGET_COLDFIRE"
   "")
 
-(define_insn ""
+(define_insn "*mulsi3_68020"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
 	(mult:SI (match_operand:SI 1 "general_operand" "%0")
                  (match_operand:SI 2 "general_src_operand" "dmSTK")))]
 
   "TARGET_68020"
-  "muls%.l %2,%0")
+  "muls%.l %2,%0"
+  [(set_attr "type" "muls_l")
+   (set_attr "opy" "2")])
 
-(define_insn ""
+(define_insn "*mulsi3_cf"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
 	(mult:SI (match_operand:SI 1 "general_operand" "%0")
 		 (match_operand:SI 2 "general_operand" "d<Q>")))]
   "TARGET_COLDFIRE"
-  "muls%.l %2,%0")
+  "muls%.l %2,%0"
+  [(set_attr "type" "muls_l")
+   (set_attr "opy" "2")])
 
 (define_insn "umulhisi3"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
@@ -2663,9 +3031,11 @@
   ""
 {
   return MOTOROLA ? "mulu%.w %2,%0" : "mulu %2,%0";
-})
+}
+  [(set_attr "type" "mulu_w")
+   (set_attr "opy" "2")])
 
-(define_insn ""
+(define_insn "*mulhisisi3_z"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
 	(mult:SI (zero_extend:SI
 		  (match_operand:HI 1 "nonimmediate_operand" "%0"))
@@ -2673,7 +3043,9 @@
   "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) <= 0xffff"
 {
   return MOTOROLA ? "mulu%.w %2,%0" : "mulu %2,%0";
-})
+}
+  [(set_attr "type" "mulu_w")
+   (set_attr "opy" "2")])
 
 ;; We need a separate DEFINE_EXPAND for u?mulsidi3 to be able to use the
 ;; proper matching constraint.  This is because the matching is between
@@ -2932,7 +3304,8 @@
   if (FP_REG_P (operands[2]))
     return "f<FP:prec>mul%.d %2,%0";
   return "f<FP:prec>mul%.<FP:prec> %2,%0";
-})
+}
+  [(set_attr "type" "fmul")])
 
 ;; divide instructions
 
@@ -3000,7 +3373,8 @@
   if (FP_REG_P (operands[2]))
     return "f<FP:prec>div%.d %2,%0";
   return "f<FP:prec>div%.<FP:prec> %2,%0";
-})
+}
+  [(set_attr "type" "fdiv")])
 
 ;; Remainder instructions.
 
@@ -3692,13 +4066,15 @@
   [(set (match_operand:SI 0 "nonimmediate_operand" "=dm")
 	(neg:SI (match_operand:SI 1 "general_operand" "0")))]
   "!TARGET_COLDFIRE"
-  "neg%.l %0")
+  "neg%.l %0"
+  [(set_attr "type" "neg_l")])
 
 (define_insn "negsi2_5200"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
 	(neg:SI (match_operand:SI 1 "general_operand" "0")))]
   "TARGET_COLDFIRE"
-  "neg%.l %0")
+  "neg%.l %0"
+  [(set_attr "type" "neg_l")])
 
 (define_insn "neghi2"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=dm")
@@ -3863,7 +4239,8 @@
   if (FP_REG_P (operands[1]))
     return "f<FP:round>sqrt%.x %1,%0";
   return "f<FP:round>sqrt%.<FP:prec> %1,%0";
-})
+}
+  [(set_attr "type" "fsqrt")])
 
 (define_insn "sqrt<mode>2_cf"
   [(set (match_operand:FP 0 "nonimmediate_operand" "=f")
@@ -4005,7 +4382,8 @@
   [(set (match_operand:SI 0 "register_operand" "=d")
  	(clz:SI (match_operand:SI 1 "register_operand" "0")))]
   "ISA_HAS_FF1"
-  "ff1 %0")
+  "ff1 %0"
+  [(set_attr "type" "ff1")])
 
 ;; one complement instructions
 
@@ -4048,7 +4426,8 @@
   [(set (match_operand:SI 0 "nonimmediate_operand" "=d")
 	(not:SI (match_operand:SI 1 "general_operand" "0")))]
   "TARGET_COLDFIRE"
-  "not%.l %0")
+  "not%.l %0"
+  [(set_attr "type" "not_l")])
 
 (define_insn "one_cmplhi2"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=dm")
@@ -4399,7 +4778,8 @@
   if (GET_CODE (operands[1]) != REG)
     operands[1] = adjust_address (operands[1], HImode, 2);
   return "move%.w %1,%0";
-})
+}
+  [(set_attr "type" "move_w")])
 
 (define_insn "subregsi1ashrdi_const32"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
@@ -4408,7 +4788,8 @@
   ""
 {
   return "move%.l %1,%0";
-})
+}
+  [(set_attr "type" "move_l")])
 
 (define_insn "*ashrdi3_const1"
   [(set (match_operand:DI 0 "register_operand" "=d")
@@ -4577,7 +4958,9 @@
 	(ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
 		     (match_operand:SI 2 "general_operand" "dI")))]
   ""
-  "asr%.l %2,%0")
+  "asr%.l %2,%0"
+  [(set_attr "type" "asr_l")
+   (set_attr "opy" "2")])
 
 (define_insn "ashrhi3"
   [(set (match_operand:HI 0 "register_operand" "=d")
@@ -4643,9 +5026,8 @@
     (subreg:SI (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro")
             (const_int 32)) 4))]
   ""
-{
-  return "move%.l %1,%0";
-})
+  "move%.l %1,%0"
+  [(set_attr "type" "move_l")])
 
 (define_insn "*lshrdi3_const1"
   [(set (match_operand:DI 0 "register_operand" "=d")
@@ -4872,7 +5254,9 @@
 	(lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
 		     (match_operand:SI 2 "general_operand" "dI")))]
   ""
-  "lsr%.l %2,%0")
+  "lsr%.l %2,%0"
+  [(set_attr "type" "lsr_l")
+   (set_attr "opy" "2")])
 
 (define_insn "lshrhi3"
   [(set (match_operand:HI 0 "register_operand" "=d")
@@ -5029,10 +5413,11 @@
 {
   CC_STATUS_INIT;
   return "bset %1,%0";
-})
+}
+  [(set_attr "type" "bset")])
 
 ;; set bit, bit number is (sign/zero)_extended from HImode/QImode
-(define_insn ""
+(define_insn "*bsetmemqi_ext"
   [(set (match_operand:QI 0 "memory_operand" "+m")
 	(ior:QI (subreg:QI (ashift:SI (const_int 1)
 	    (match_operator:SI 2 "extend_operator"
@@ -5042,7 +5427,8 @@
 {
   CC_STATUS_INIT;
   return "bset %1,%0";
-})
+}
+  [(set_attr "type" "bset")])
 
 ;; clear bit, bit number is int
 (define_insn "bclrmemqi"
@@ -5055,10 +5441,11 @@
 {
   CC_STATUS_INIT;
   return "bclr %1,%0";
-})
+}
+  [(set_attr "type" "bclr")])
 
 ;; clear bit, bit number is (sign/zero)_extended from HImode/QImode
-(define_insn ""
+(define_insn "*bclrmemqi_ext"
   [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+m")
 	(const_int 1)
 	(minus:SI (const_int 7)
@@ -5069,7 +5456,8 @@
 {
   CC_STATUS_INIT;
   return "bclr %1,%0";
-})
+}
+  [(set_attr "type" "bclr")])
 
 ;; Special cases of bit-field insns which we should
 ;; recognize in preference to the general case.
@@ -5641,14 +6029,15 @@
   ""
   "")
 
-(define_insn ""
+(define_insn "*scc"
   [(set (match_operand:QI 0 "register_operand" "=d")
 	(geu:QI (cc0) (const_int 0)))]
   ""
 {
    cc_status = cc_prev_status;
    return "scc %0";
-})
+}
+  [(set_attr "type" "scc")])
 
 (define_expand "sle"
   [(set (match_operand:QI 0 "register_operand" "")
@@ -5678,14 +6067,15 @@
   ""
   "")
 
-(define_insn ""
+(define_insn "*sls"
   [(set (match_operand:QI 0 "register_operand" "=d")
 	(leu:QI (cc0) (const_int 0)))]
   ""
 {
    cc_status = cc_prev_status;
    return "sls %0";
-})
+}
+  [(set_attr "type" "scc")])
 
 (define_expand "sordered"
   [(set (match_operand:QI 0 "register_operand" "")
@@ -6085,7 +6475,9 @@
     OUTPUT_JUMP ("jbeq %l0", "fbeq %l0", "jbeq %l0");
   else
     OUTPUT_JUMP ("jeq %l0", "fjeq %l0", "jeq %l0");
-})
+}
+  [(set (attr "type") (symbol_ref "m68k_sched_branch_type (insn)"))
+   (set_attr "split" "done")])
 
 (define_insn "bne"
   [(set (pc)
@@ -6099,7 +6491,9 @@
     OUTPUT_JUMP ("jbne %l0", "fbne %l0", "jbne %l0");
   else
     OUTPUT_JUMP ("jne %l0", "fjne %l0", "jne %l0");
-})
+}
+  [(set (attr "type") (symbol_ref "m68k_sched_branch_type (insn)"))
+   (set_attr "split" "done")])
 
 (define_insn "bgt"
   [(set (pc)
@@ -6113,7 +6507,9 @@
     OUTPUT_JUMP ("jbgt %l0", "fbgt %l0", 0);
   else
     OUTPUT_JUMP ("jgt %l0", "fjgt %l0", 0);
-})
+}
+  [(set (attr "type") (symbol_ref "m68k_sched_branch_type (insn)"))
+   (set_attr "split" "done")])
 
 (define_insn "bgtu"
   [(set (pc)
@@ -6124,7 +6520,8 @@
   ""
 {
   return MOTOROLA ? "jbhi %l0" : "jhi %l0";
-})
+}
+  [(set_attr "type" "bcc")])
 
 (define_insn "blt"
   [(set (pc)
@@ -6138,7 +6535,9 @@
     OUTPUT_JUMP ("jblt %l0", "fblt %l0", "jbmi %l0");
   else
     OUTPUT_JUMP ("jlt %l0", "fjlt %l0", "jmi %l0");
-})
+}
+  [(set (attr "type") (symbol_ref "m68k_sched_branch_type (insn)"))
+   (set_attr "split" "done")])
 
 (define_insn "bltu"
   [(set (pc)
@@ -6149,7 +6548,8 @@
   ""
 {
   return MOTOROLA ? "jbcs %l0" : "jcs %l0";
-})
+}
+  [(set_attr "type" "bcc")])
 
 (define_insn "bge"
   [(set (pc)
@@ -6174,7 +6574,8 @@
   ""
 {
   return MOTOROLA ? "jbcc %l0" : "jcc %l0";
-})
+}
+  [(set_attr "type" "bcc")])
 
 (define_insn "ble"
   [(set (pc)
@@ -6188,7 +6589,8 @@
     OUTPUT_JUMP ("jble %l0", "fble %l0", 0);
   else
     OUTPUT_JUMP ("jle %l0", "fjle %l0", 0);
-})
+}
+  [(set_attr "type" "bcc")])
 
 (define_insn "bleu"
   [(set (pc)
@@ -6199,7 +6601,8 @@
   ""
 {
   return MOTOROLA ? "jbls %l0" : "jls %l0";
-})
+}
+  [(set_attr "type" "bcc")])
 
 (define_insn "bordered"
   [(set (pc)
@@ -6291,7 +6694,7 @@
 
 ;; Negated conditional jump instructions.
 
-(define_insn ""
+(define_insn "*beq2"
   [(set (pc)
 	(if_then_else (eq (cc0)
 			  (const_int 0))
@@ -6303,9 +6706,10 @@
     OUTPUT_JUMP ("jbne %l0", "fbne %l0", "jbne %l0");
   else
     OUTPUT_JUMP ("jne %l0", "fjne %l0", "jne %l0");
-})
+}
+  [(set_attr "type" "bcc")])
 
-(define_insn ""
+(define_insn "*bne2"
   [(set (pc)
 	(if_then_else (ne (cc0)
 			  (const_int 0))
@@ -6317,9 +6721,10 @@
     OUTPUT_JUMP ("jbeq %l0", "fbeq %l0", "jbeq %l0");
   else
     OUTPUT_JUMP ("jeq %l0", "fjeq %l0", "jeq %l0");
-})
+}
+  [(set_attr "type" "bcc")])
 
-(define_insn ""
+(define_insn "*bgt2"
   [(set (pc)
 	(if_then_else (gt (cc0)
 			  (const_int 0))
@@ -6331,9 +6736,10 @@
     OUTPUT_JUMP ("jble %l0", "fbngt %l0", 0);
   else
     OUTPUT_JUMP ("jle %l0", "fjngt %l0", 0);
-})
+}
+  [(set_attr "type" "bcc")])
 
-(define_insn ""
+(define_insn "*bgtu2"
   [(set (pc)
 	(if_then_else (gtu (cc0)
 			   (const_int 0))
@@ -6342,9 +6748,10 @@
   ""
 {
   return MOTOROLA ? "jbls %l0" : "jls %l0";
-})
+}
+  [(set_attr "type" "bcc")])
 
-(define_insn ""
+(define_insn "*blt2"
   [(set (pc)
 	(if_then_else (lt (cc0)
 			  (const_int 0))
@@ -6356,9 +6763,10 @@
     OUTPUT_JUMP ("jbge %l0", "fbnlt %l0", "jbpl %l0");
   else
     OUTPUT_JUMP ("jge %l0", "fjnlt %l0", "jpl %l0");
-})
+}
+  [(set_attr "type" "bcc")])
 
-(define_insn ""
+(define_insn "*bltu2"
   [(set (pc)
 	(if_then_else (ltu (cc0)
 			   (const_int 0))
@@ -6367,9 +6775,10 @@
   ""
 {
   return MOTOROLA ? "jbcc %l0" : "jcc %l0";
-})
+}
+  [(set_attr "type" "bcc")])
 
-(define_insn ""
+(define_insn "*bge2"
   [(set (pc)
 	(if_then_else (ge (cc0)
 			  (const_int 0))
@@ -6381,9 +6790,10 @@
     OUTPUT_JUMP ("jblt %l0", "fbnge %l0", "jbmi %l0");
   else
     OUTPUT_JUMP ("jlt %l0", "fjnge %l0", "jmi %l0");
-})
+}
+  [(set_attr "type" "bcc")])
 
-(define_insn ""
+(define_insn "*bgeu2"
   [(set (pc)
 	(if_then_else (geu (cc0)
 			   (const_int 0))
@@ -6392,9 +6802,10 @@
   ""
 {
   return MOTOROLA ? "jbcs %l0" : "jcs %l0";
-})
+}
+  [(set_attr "type" "bcc")])
 
-(define_insn ""
+(define_insn "*ble2"
   [(set (pc)
 	(if_then_else (le (cc0)
 			  (const_int 0))
@@ -6406,9 +6817,10 @@
     OUTPUT_JUMP ("jbgt %l0", "fbnle %l0", 0);
   else
     OUTPUT_JUMP ("jgt %l0", "fjnle %l0", 0);
-})
+}
+  [(set_attr "type" "bcc")])
 
-(define_insn ""
+(define_insn "*bleu2"
   [(set (pc)
 	(if_then_else (leu (cc0)
 			   (const_int 0))
@@ -6417,7 +6829,8 @@
   ""
 {
   return MOTOROLA ? "jbhi %l0" : "jhi %l0";
-})
+}
+  [(set_attr "type" "bcc")])
 
 (define_insn "*bordered_rev"
   [(set (pc)
@@ -6514,7 +6927,8 @@
   ""
 {
   return MOTOROLA ? "jbra %l0" : "jra %l0";
-})
+}
+  [(set_attr "type" "bra")])
 
 (define_expand "tablejump"
   [(parallel [(set (pc) (match_operand 0 "" ""))
@@ -6528,13 +6942,14 @@
 })
 
 ;; Jump to variable address from dispatch table of absolute addresses.
-(define_insn ""
+(define_insn "*tablejump_internal"
   [(set (pc) (match_operand:SI 0 "register_operand" "a"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
 {
   return MOTOROLA ? "jmp (%0)" : "jmp %0@";
-})
+}
+  [(set_attr "type" "bra")])
 
 ;; Jump to variable address from dispatch table of relative addresses.
 (define_insn ""
@@ -6746,16 +7161,46 @@
   operands[1] = m68k_legitimize_call_address (operands[1]);
 })
 
-(define_insn "*call_value"
+(define_insn "*non_symbolic_call_value"
   [(set (match_operand 0 "" "=rf,rf")
-	(call (mem:QI (match_operand:SI 1 "call_operand" "a,W"))
+	(call (mem:QI (match_operand:SI 1 "non_symbolic_call_operand" "a,W"))
 	      (match_operand:SI 2 "general_operand" "g,g")))]
   ;; Operand 2 not really used on the m68000.
   "!SIBLING_CALL_P (insn)"
+  "jsr %a1"
+  [(set_attr "type" "jsr")
+   (set_attr "split" "done")
+   (set_attr "opx" "1")])
+
+(define_insn "*symbolic_call_value_jsr"
+  [(set (match_operand 0 "" "=rf,rf")
+	(call (mem:QI (match_operand:SI 1 "symbolic_operand" "a,W"))
+	      (match_operand:SI 2 "general_operand" "g,g")))]
+  ;; Operand 2 not really used on the m68000.
+  "!SIBLING_CALL_P (insn) && m68k_symbolic_call_var == M68K_SYMBOLIC_CALL_JSR"
 {
   operands[0] = operands[1];
-  return output_call (operands[0]);
-})
+  return m68k_symbolic_call;
+}
+  [(set_attr "type" "jsr")
+   (set_attr "split" "done")
+   (set_attr "opx" "1")])
+
+(define_insn "*symbolic_call_value_bsr"
+  [(set (match_operand 0 "" "=rf,rf")
+	(call (mem:QI (match_operand:SI 1 "symbolic_operand" "a,W"))
+	      (match_operand:SI 2 "general_operand" "g,g")))]
+  ;; Operand 2 not really used on the m68000.
+  "!SIBLING_CALL_P (insn)
+   && (m68k_symbolic_call_var == M68K_SYMBOLIC_CALL_BSR_C
+       || m68k_symbolic_call_var == M68K_SYMBOLIC_CALL_BSR_P)"
+{
+  operands[0] = operands[1];
+  return m68k_symbolic_call;
+}
+  [(set_attr "type" "bsr")
+   (set_attr "split" "done")
+   (set_attr "opx" "1")])
 
 ;; Call subroutine returning any type.
 
@@ -6796,7 +7241,8 @@
 (define_insn "nop"
   [(const_int 0)]
   ""
-  "nop")
+  "nop"
+  [(set_attr "type" "nop")])
 
 (define_expand "prologue"
   [(const_int 0)]
@@ -6849,7 +7295,8 @@
       else
 	return "rts";
     }
-})
+}
+  [(set_attr "type" "rts")])
 
 (define_insn "*m68k_store_multiple"
   [(match_parallel 0 "" [(match_operand 1 "")])]
@@ -6939,7 +7386,8 @@
 	(plus:SI (match_dup 0)
 		 (const_int 4)))]
   ""
-  "unlk %0")
+  "unlk %0"
+  [(set_attr "type" "unlk")])
 
 (define_insn "load_got"
   [(set (match_operand:SI 0 "register_operand" "=a")
@@ -6971,7 +7419,8 @@
 (define_insn "indirect_jump"
   [(set (pc) (match_operand:SI 0 "address_operand" "p"))]
   ""
-  "jmp %a0")
+  "jmp %a0"
+  [(set_attr "type" "jmp")])
 
 ;; This should not be used unless the add/sub insns can't be.
 
@@ -7373,10 +7822,12 @@
     return "fcos%.<FP:prec> %1,%0";
 })
 
+;; Unconditional traps are assumed to have (const_int 1) for the condition.
 (define_insn "trap"
-  [(trap_if (const_int -1) (const_int 7))]
+  [(trap_if (const_int 1) (const_int 7))]
   ""
-  "trap #7")
+  "trap #7"
+  [(set_attr "type" "trap")])
 
 (define_insn "conditional_trap"
   [(trap_if (match_operator 0 "valid_dbcc_comparison_p"
@@ -7399,3 +7850,12 @@
   default: gcc_unreachable ();
   }
 })
+
+;; Instruction that subscribes one word in ColdFire instruction buffer.
+;; This instruction is used within scheduler only and should not appear
+;; in the instruction stream.
+(define_insn "ib"
+  [(unspec [(const_int 0)] UNSPEC_IB)]
+  ""
+  "#"
+  [(set_attr "type" "ib")])
diff -rup -x '*rej*' -x '*orig' -x '*.svn*' gnu2/gcc/config/m68k/predicates.md gnu/gcc/config/m68k/predicates.md
--- gnu2/gcc/config/m68k/predicates.md	2007-08-20 07:11:06.000000000 -0700
+++ gnu/gcc/config/m68k/predicates.md	2007-08-20 07:39:04.000000000 -0700
@@ -192,3 +192,17 @@
 (define_predicate "pre_dec_operand"
   (and (match_code "mem")
        (match_test "GET_CODE (XEXP (op, 0)) == PRE_DEC")))
+
+;; An operand for movsi_const0 pattern.
+(define_predicate "movsi_const0_operand"
+  (and (match_operand 0 "nonimmediate_operand")
+       (match_test "(TARGET_68010 || TARGET_COLDFIRE)
+                    || !(MEM_P (op) && MEM_VOLATILE_P (op))")))
+ 
+;; A non-symbolic call operand.
+;; We need to special case 'const_int' to ignore its mode while matching.
+(define_predicate "non_symbolic_call_operand"
+  (and (match_operand 0 "call_operand")
+       (ior (and (match_code "const_int")
+ 		 (match_test "!symbolic_operand (op, mode)"))
+ 	    (match_test "!symbolic_operand (op,mode)"))))
diff -rup -x '*rej*' -x '*orig' -x '*.svn*' gnu2/gcc/doc/md.texi gnu/gcc/doc/md.texi
--- gnu2/gcc/doc/md.texi	2007-08-20 07:17:35.000000000 -0700
+++ gnu/gcc/doc/md.texi	2007-08-20 07:22:02.000000000 -0700
@@ -2542,7 +2542,7 @@ Floating-point zero.
 An address that can be used in a non-macro load or store.
 @end table
 
-@item Motorola 680x0---@file{config/m68k/m68k.h}
+@item Motorola 680x0---@file{config/m68k/constraints.md}
 @table @code
 @item a
 Address register
@@ -2568,8 +2568,66 @@ Integer in the range @minus{}8 to @minus
 @item M
 Signed number whose magnitude is greater than 0x100
 
+@item N
+Range 24 to 31, rotatert:SI 8 to 1 expressed as rotate
+
+@item O
+16 (for rotate using swap)
+
+@item P
+Range 8 to 15, rotatert:HI 8 to 1 expressed as rotate
+
+@item R
+Numbers that mov3q can handle
+
 @item G
 Floating point constant that is not a 68881 constant
+
+@item S
+Operands that satisfy 'm' when -mpcrel is in effect
+
+@item T
+Operands that satisfy 's' when -mpcrel is not in effect
+
+@item Q
+Address register indirect addressing mode
+
+@item U
+Register offset addressing
+
+@item W
+const_call_operand
+
+@item Cs
+symbol_ref or const
+
+@item Ci
+const_int
+
+@item C0
+const_int 0
+
+@item Cj
+Range of signed numbers that don't fit in 16 bits
+
+@item Cmvq
+Integers valid for mvq
+
+@item Capsw
+Integers valid for a moveq followed by a swap
+
+@item Cmvz
+Integers valid for mvz
+
+@item Cmvs
+Integers valid for mvs
+
+@item Ap
+push_operand
+
+@item Ac
+Non-register operands allowed in clr
+
 @end table
 
 @item Motorola 68HC11 & 68HC12 families---@file{config/m68hc11/m68hc11.h}

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