OSDN Git Service

(movstricthi): Remove extraneous comparisons.
[pf3gnuchains/gcc-fork.git] / gcc / config / m68k / m68k.md
index b9b3bff..fdb6eb2 100644 (file)
@@ -1,5 +1,5 @@
 ;;- Machine description for GNU compiler, Motorola 68000 Version
-;;  Copyright (C) 1987, 88, 93, 94, 95, 1996 Free Software Foundation, Inc.
+;;  Copyright (C) 1987, 88, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
 ;; This file is part of GNU CC.
 
@@ -64,6 +64,9 @@
 ;;- 'K'  all integers EXCEPT -128 .. 127
 ;;- 'L'  -8 .. -1
 ;;- 'M'  all integers EXCEPT -256 .. 255
+;;- 'N'  24 .. 31
+;;- 'O'  16
+;;- 'P'  8 .. 15
 
 ;;- Assembler specs:
 ;;- "%."    size separator ("." or "")                 move%.l d0,d1
 ;; (set (cc0) (const_int foo)) has no mode information.  Such insns will
 ;; be folded while optimizing anyway.
 
-(define_insn "tstdi"
+(define_expand "tstdi"
+  [(parallel [(set (cc0)
+                  (match_operand:DI 0 "nonimmediate_operand" ""))
+             (clobber (match_scratch:SI 1 ""))
+             (clobber (match_scratch:DI 2 ""))])]
+  ""
+  "m68k_last_compare_had_fp_operands = 0;")
+
+(define_insn ""
   [(set (cc0)
        (match_operand:DI 0 "nonimmediate_operand" "am,d"))
    (clobber (match_scratch:SI 1 "=X,d"))
     return \"sub%.l %1,%1\;tst%.l %R0\;subx%.l %1,%0\";
 }")
 
-(define_insn "tstsi"
+(define_expand "tstsi"
+  [(set (cc0)
+       (match_operand:SI 0 "nonimmediate_operand" ""))]
+  ""
+  "m68k_last_compare_had_fp_operands = 0;")
+
+(define_insn ""
   [(set (cc0)
        (match_operand:SI 0 "nonimmediate_operand" "rm"))]
   ""
 
 ;; This can't use an address register, because comparisons
 ;; with address registers as second operand always test the whole word.
-(define_insn "tsthi"
+(define_expand "tsthi"
+  [(set (cc0)
+       (match_operand:HI 0 "nonimmediate_operand" ""))]
+  ""
+  "m68k_last_compare_had_fp_operands = 0;")
+
+(define_insn ""
   [(set (cc0)
        (match_operand:HI 0 "nonimmediate_operand" "dm"))]
   ""
   "tst%.w %0")
 
-(define_insn "tstqi"
+(define_expand "tstqi"
+  [(set (cc0)
+       (match_operand:QI 0 "nonimmediate_operand" ""))]
+  ""
+  "m68k_last_compare_had_fp_operands = 0;")
+
+(define_insn ""
   [(set (cc0)
        (match_operand:QI 0 "nonimmediate_operand" "dm"))]
   ""
   "TARGET_68881 || TARGET_FPA"
   "
 {
+  m68k_last_compare_had_fp_operands = 1;
   if (TARGET_FPA)
     {
       emit_insn (gen_tstsf_fpa (operands[0]));
   "TARGET_68881 || TARGET_FPA"
   "
 {
+  m68k_last_compare_had_fp_operands = 1;
   if (TARGET_FPA)
     {
       emit_insn (gen_tstsf_fpa (operands[0]));
                   (match_operand:DI 1 "general_operand" "")))
      (clobber (match_dup 2))])]
   ""
-  "operands[2] = gen_reg_rtx (DImode);")
+  "m68k_last_compare_had_fp_operands = 0; operands[2] = gen_reg_rtx (DImode);")
 
 (define_insn ""
   [(set (cc0)
   ""
   "
 {
+  m68k_last_compare_had_fp_operands = 0;
   if (flag_pic && symbolic_operand (operands[1], SImode))
     {
       /* The source is an address which requires PIC relocation.
     }
 }")
 
-;; A composite of the cmp, cmpa, & cmpi m68000 op codes.
+;; A composite of the cmp, cmpa, cmpi & cmpm m68000 op codes.
 (define_insn ""
   [(set (cc0)
        (compare (match_operand:SI 0 "nonimmediate_operand" "rKs,mr,>")
-                (match_operand:SI 1 "general_operand" "mr,Ksr,>")))]
-  ""
+                (match_operand:SI 1 "general_operand" "mr,rKs,>")))]
+  "!TARGET_5200"
   "*
 {
   if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
 #endif
 }")
 
-(define_insn "cmphi"
+(define_insn ""
+  [(set (cc0)
+       (compare (match_operand:SI 0 "nonimmediate_operand" "mrKs,r")
+                (match_operand:SI 1 "general_operand" "r,mrKs")))]
+  "TARGET_5200"
+  "*
+{
+  if (REG_P (operands[1])
+      || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
+    { cc_status.flags |= CC_REVERSED;
+#ifdef SGS_CMP_ORDER
+      return \"cmp%.l %d1,%d0\";
+#else
+      return \"cmp%.l %d0,%d1\";
+#endif
+    }
+#ifdef SGS_CMP_ORDER
+  return \"cmp%.l %d0,%d1\";
+#else
+  return \"cmp%.l %d1,%d0\";
+#endif
+}")
+
+(define_expand "cmphi"
+  [(set (cc0)
+       (compare (match_operand:HI 0 "nonimmediate_operand" "")
+                (match_operand:HI 1 "general_operand" "")))]
+  "!TARGET_5200"
+  "m68k_last_compare_had_fp_operands = 0;")
+
+(define_insn ""
   [(set (cc0)
        (compare (match_operand:HI 0 "nonimmediate_operand" "rnm,d,n,m,>")
                 (match_operand:HI 1 "general_operand" "d,rnm,m,n,>")))]
 #endif
 }")
 
-(define_insn "cmpqi"
+(define_expand "cmpqi"
+  [(set (cc0)
+       (compare (match_operand:QI 0 "nonimmediate_operand" "")
+                (match_operand:QI 1 "general_operand" "")))]
+  "!TARGET_5200"
+  "m68k_last_compare_had_fp_operands = 0;")
+
+(define_insn ""
   [(set (cc0)
        (compare (match_operand:QI 0 "nonimmediate_operand" "dn,md,>")
                 (match_operand:QI 1 "general_operand" "dm,nd,>")))]
   "TARGET_68881 || TARGET_FPA"
   "
 {
+  m68k_last_compare_had_fp_operands = 1;
   if (TARGET_FPA)
     {
       emit_insn (gen_cmpdf_fpa (operands[0], operands[1]));
  "TARGET_68881 || TARGET_FPA"
  "
 {
+  m68k_last_compare_had_fp_operands = 1;
   if (TARGET_FPA)
     {
       emit_insn (gen_cmpsf_fpa (operands[0], operands[1]));
   "*
 {
   if (ADDRESS_REG_P (operands[0]))
-    return \"sub%.l %0,%0\";
+    {
+      /* On the '040, 'subl an,an' takes 2 clocks while lea takes only 1 */
+      if (!TARGET_68040 && !TARGET_68060)
+       return \"sub%.l %0,%0\";
+      else
+       {
+#ifdef MOTOROLA
+#ifdef SGS
+         /* Many SGS assemblers croak on size specifiers for constants. */
+         return \"lea 0,%0\";
+#else
+         return \"lea 0.w,%0\";
+#endif
+#else
+         return \"lea 0:w,%0\";
+#endif
+       }
+    }
   /* moveq is faster on the 68000.  */
   if (DATA_REG_P (operands[0]) && (!TARGET_68020 && !TARGET_5200))
 #if defined(MOTOROLA) && !defined(CRDS)
   ;; We do allow y and x regs since fixed point is allowed in them.
   [(set (match_operand:SI 0 "general_operand" "=g,da,y,!*x*r*m")
        (match_operand:SI 1 "general_operand" "daymKs,i,g,*x*r*m"))]
-  ""
+  "!TARGET_5200"
   "*
 {
   if (which_alternative == 3)
     return \"fpmove%.l %x1,fpa0\;fpmove%.l fpa0,%x0\";
   if (FPA_REG_P (operands[1]) || FPA_REG_P (operands[0]))
     return \"fpmove%.l %x1,%x0\";
-  if (GET_CODE (operands[1]) == CONST_INT)
-    return output_move_simode_const (operands);
-  else if ((GET_CODE (operands[1]) == SYMBOL_REF
-           || GET_CODE (operands[1]) == CONST)
-          && push_operand (operands[0], SImode))
-    return \"pea %a1\";
-  else if ((GET_CODE (operands[1]) == SYMBOL_REF
-           || GET_CODE (operands[1]) == CONST)
-          && ADDRESS_REG_P (operands[0]))
-    return \"lea %a1,%0\";
-  return \"move%.l %1,%0\";
+  return output_move_simode (operands);
 }")
 
-(define_insn "movhi"
+(define_insn ""
+  [(set (match_operand:SI 0 "general_operand" "=r<>,g")
+       (match_operand:SI 1 "general_operand" "g,r<>"))]
+  "TARGET_5200"
+  "* return output_move_simode (operands);")
+
+(define_expand "movhi"
+  [(set (match_operand:HI 0 "general_operand" "")
+       (match_operand:HI 1 "general_operand" ""))]
+  ""
+  "")
+
+(define_insn ""
   [(set (match_operand:HI 0 "general_operand" "=g")
        (match_operand:HI 1 "general_operand" "g"))]
-  ""
-  "*
-{
-  if (GET_CODE (operands[1]) == CONST_INT)
-    {
-      if (operands[1] == const0_rtx
-         && (DATA_REG_P (operands[0])
-             || GET_CODE (operands[0]) == MEM)
-         /* clr insns on 68000 read before writing.
-            This isn't so on the 68010, but we have no TARGET_68010.  */
-         && ((TARGET_68020 || TARGET_5200)
-             || !(GET_CODE (operands[0]) == MEM
-                  && MEM_VOLATILE_P (operands[0]))))
-       return \"clr%.w %0\";
-      else if (DATA_REG_P (operands[0])
-              && INTVAL (operands[1]) < 128
-              && INTVAL (operands[1]) >= -128)
-        {
-#if defined(MOTOROLA) && !defined(CRDS)
-          return \"moveq%.l %1,%0\";
-#else
-         return \"moveq %1,%0\";
-#endif
-       }
-      else if (INTVAL (operands[1]) < 0x8000
-              && INTVAL (operands[1]) >= -0x8000)
-       return \"move%.w %1,%0\";
-    }
-  else if (CONSTANT_P (operands[1]))
-    return \"move%.l %1,%0\";
-#ifndef SGS_NO_LI
-  /* Recognize the insn before a tablejump, one that refers
-     to a table of offsets.  Such an insn will need to refer
-     to a label on the insn.  So output one.  Use the label-number
-     of the table of offsets to generate this label.  This code,
-     and similar code below, assumes that there will be at most one
-     reference to each table.  */
-  if (GET_CODE (operands[1]) == MEM
-      && GET_CODE (XEXP (operands[1], 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF
-      && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS)
-    {
-      rtx labelref = XEXP (XEXP (operands[1], 0), 1);
-#if defined (MOTOROLA) && !defined (SGS_SWITCH_TABLES)
-#ifdef SGS
-      asm_fprintf (asm_out_file, \"\\tset %LLI%d,.+2\\n\",
-                  CODE_LABEL_NUMBER (XEXP (labelref, 0)));
-#else /* not SGS */
-      asm_fprintf (asm_out_file, \"\\t.set %LLI%d,.+2\\n\",
-                  CODE_LABEL_NUMBER (XEXP (labelref, 0)));
-#endif /* not SGS */
-#else /* SGS_SWITCH_TABLES or not MOTOROLA */
-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\",
-                                CODE_LABEL_NUMBER (XEXP (labelref, 0)));
-#ifdef SGS_SWITCH_TABLES
-      /* Set flag saying we need to define the symbol
-        LD%n (with value L%n-LI%n) at the end of the switch table.  */
-      switch_table_difference_label_flag = 1;
-#endif /* SGS_SWITCH_TABLES */
-#endif /* SGS_SWITCH_TABLES or not MOTOROLA */
-    }
-#endif /* SGS_NO_LI */
-  return \"move%.w %1,%0\";
-}")
+  "!TARGET_5200"
+  "* return output_move_himode (operands);")
+
+ (define_insn ""
+  [(set (match_operand:HI 0 "general_operand" "=r<>,g")
+       (match_operand:HI 1 "general_operand" "g,r<>"))]
+  "TARGET_5200"
+  "* return output_move_himode (operands);")
 
 (define_insn "movstricthi"
   [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm"))
   ""
   "*
 {
-  if (GET_CODE (operands[1]) == CONST_INT)
-    {
-      if (operands[1] == const0_rtx
-         && (DATA_REG_P (operands[0])
-             || GET_CODE (operands[0]) == MEM)
-         /* clr insns on 68000 read before writing.
-            This isn't so on the 68010, but we have no TARGET_68010.  */
-         && ((TARGET_68020 || TARGET_5200)
-             || !(GET_CODE (operands[0]) == MEM
-                  && MEM_VOLATILE_P (operands[0]))))
-       return \"clr%.w %0\";
-    }
+  if (operands[1] == const0_rtx
+      /* clr insns on 68000 read before writing.
+        This isn't so on the 68010, but we have no TARGET_68010.  */
+      && ((TARGET_68020 || TARGET_5200)
+         || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))
+    return \"clr%.w %0\";
   return \"move%.w %1,%0\";
 }")
 
-(define_insn "movqi"
-  [(set (match_operand:QI 0 "general_operand" "=d,*a,m")
-       (match_operand:QI 1 "general_operand" "dmi*a,di*a,dmi"))]
+(define_expand "movqi"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (match_operand:QI 1 "general_operand" ""))]
   ""
-  "*
-{
-  rtx xoperands[4];
+  "")
 
-  /* This is probably useless, since it loses for pushing a struct
-     of several bytes a byte at a time.  */
-  if (GET_CODE (operands[0]) == MEM
-      && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
-      && XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx
-      && ! ADDRESS_REG_P (operands[1]))
-    {
-      xoperands[1] = operands[1];
-      xoperands[2]
-        = gen_rtx (MEM, QImode,
-                  gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx));
-      /* Just pushing a byte puts it in the high byte of the halfword.  */
-      /* We must put it in the low-order, high-numbered byte.  */
-      output_asm_insn (\"move%.b %1,%-\;move%.b %@,%2\", xoperands);
-      return \"\";
-    }
+(define_insn ""
+  [(set (match_operand:QI 0 "general_operand" "=d,*a,m")
+       (match_operand:QI 1 "general_operand" "dmi*a,di*a,dmi"))]
+  "!TARGET_5200"
+  "* return output_move_qimode (operands);")
 
-  /* clr and st insns on 68000 read before writing.
-     This isn't so on the 68010, but we have no TARGET_68010.  */
-  if (!ADDRESS_REG_P (operands[0])
-      && (TARGET_68020
-         || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))
-    {
-      if (operands[1] == const0_rtx)
-       return \"clr%.b %0\";
-      if (GET_CODE (operands[1]) == CONST_INT
-         && INTVAL (operands[1]) == -1)
-       {
-         CC_STATUS_INIT;
-         return \"st %0\";
-       }
-    }
-  if (GET_CODE (operands[1]) == CONST_INT
-      && DATA_REG_P (operands[0])
-      && INTVAL (operands[1]) < 128
-      && INTVAL (operands[1]) >= -128)
-    {
-#if defined(MOTOROLA) && !defined(CRDS)
-      return \"moveq%.l %1,%0\";
-#else
-      return \"moveq %1,%0\";
-#endif
-    }
-  if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1]))
-    return \"move%.l %1,%0\";
-  if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1]))
-    return \"move%.w %1,%0\";
-  return \"move%.b %1,%0\";
-}")
+(define_insn ""
+  [(set (match_operand:QI 0 "general_operand" "=d<>,dm")
+       (match_operand:QI 1 "general_operand" "dmi,d<>"))]
+  "TARGET_5200"
+  "* return output_move_qimode (operands);")
 
 (define_insn "movstrictqi"
   [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm"))
   return \"move%.b %1,%0\";
 }")
 
-(define_insn "movsf"
+(define_expand "movsf"
+  [(set (match_operand:SF 0 "general_operand" "")
+       (match_operand:SF 1 "general_operand" ""))]
+  ""
+  "")
+
+(define_insn ""
   [(set (match_operand:SF 0 "general_operand" "=rmf,x,y,rm,!x,!rm")
        (match_operand:SF 1 "general_operand" "rmfF,xH,rmF,y,rm,x"))]
 ;  [(set (match_operand:SF 0 "general_operand" "=rmf")
 ;      (match_operand:SF 1 "general_operand" "rmfF"))]
-  ""
+  "!TARGET_5200"
   "*
 {
   if (which_alternative >= 4)
   return \"move%.l %1,%0\";
 }")
 
-(define_insn "movdf"
+(define_insn ""
+  [(set (match_operand:SF 0 "general_operand" "=r,g")
+       (match_operand:SF 1 "general_operand" "g,r"))]
+  "TARGET_5200"
+  "* return \"move%.l %1,%0\";")
+
+(define_expand "movdf"
+  [(set (match_operand:DF 0 "general_operand" "")
+       (match_operand:DF 1 "general_operand" ""))]
+  ""
+  "")
+
+(define_insn ""
   [(set (match_operand:DF 0 "general_operand" "=rm,rf,rf,&rof<>,y,rm,x,!x,!rm")
        (match_operand:DF 1 "general_operand" "rf,m,0,rofE<>,rmE,y,xH,rm,x"))]
 ;  [(set (match_operand:DF 0 "general_operand" "=rm,&rf,&rof<>")
 ;      (match_operand:DF 1 "general_operand" "rf,m,rofF<>"))]
-  ""
+  "!TARGET_5200"
   "*
 {
   if (which_alternative == 7)
         return \"fmove%.d %f1,%0\";
     }
   return output_move_double (operands);
-}
-")
+}")
+
+(define_insn ""
+  [(set (match_operand:DF 0 "general_operand" "=r,g")
+       (match_operand:DF 1 "general_operand" "g,r"))]
+  "TARGET_5200"
+  "* return output_move_double (operands);")
 
 (define_expand "movxf"
   [(set (match_operand:XF 0 "nonimmediate_operand" "")
 }
 ")
 
+(define_expand "movdi"
+  ;; Let's see if it really still needs to handle fp regs, and, if so, why.
+  [(set (match_operand:DI 0 "general_operand" "")
+       (match_operand:DI 1 "general_operand" ""))]
+  ""
+  "")
+
 ;; movdi can apply to fp regs in some cases
-(define_insn "movdi"
+(define_insn ""
   ;; Let's see if it really still needs to handle fp regs, and, if so, why.
   [(set (match_operand:DI 0 "general_operand" "=rm,r,&ro<>,y,rm,!*x,!rm")
        (match_operand:DI 1 "general_operand" "rF,m,roi<>F,rmiF,y,rmF,*x"))]
 ;      (match_operand:DI 1 "general_operand" "r,m,roi<>,fF,rfmF,rmi,y,rm,x"))]
 ;  [(set (match_operand:DI 0 "general_operand" "=rm,&rf,&ro<>,!&rm,!&f")
 ;      (match_operand:DI 1 "general_operand" "r,m,roi<>,fF,rfF"))]
-  ""
+  "!TARGET_5200"
   "*
 {
   if (which_alternative == 8)
         return \"fmove%.d %f1,%0\";
     }
   return output_move_double (operands);
-}
-")
+}")
+
+(define_insn ""
+  [(set (match_operand:DI 0 "general_operand" "=r,g")
+       (match_operand:DI 1 "general_operand" "g,r"))]
+  "TARGET_5200"
+  "* return output_move_double (operands);")
 
 ;; Thus goes after the move instructions
 ;; because the move instructions are better (require no spilling)
 #ifndef NO_ADDSUB_Q
       if (INTVAL (operands[2]) > 0
          && INTVAL (operands[2]) <= 8)
-       return (ADDRESS_REG_P (operands[0]) && !TARGET_5200
-               ? \"addq%.w %2,%0\"
-               : \"addq%.l %2,%0\");
+       return \"addq%.l %2,%0\";
       if (INTVAL (operands[2]) < 0
          && INTVAL (operands[2]) >= -8)
         {
          operands[2] = gen_rtx (CONST_INT, VOIDmode,
                                 - INTVAL (operands[2]));
-         return (ADDRESS_REG_P (operands[0]) && !TARGET_5200
-                 ? \"subq%.w %2,%0\"
-                 : \"subq%.l %2,%0\");
+         return \"subq%.l %2,%0\";
        }
-      /* On the 68020 it is faster to use two addqw instructions to
-        add a small integer (8 < N <= 16) to an address register.
-        Likewise for subqw. */
-      if (TARGET_68020 && !TARGET_68040 && !TARGET_68060 
-          && ADDRESS_REG_P (operands[0]))
+      /* On the CPU32 it is faster to use two addql instructions to
+        add a small integer (8 < N <= 16) to a register.
+        Likewise for subql. */
+      if (TARGET_CPU32 && REG_P (operands[0]))
        {
          if (INTVAL (operands[2]) > 8
              && INTVAL (operands[2]) <= 16)
            {
              operands[2] = gen_rtx (CONST_INT, VOIDmode, 
                                      INTVAL (operands[2]) - 8);
-             return \"addq%.w %#8,%0\;addq%.w %2,%0\";
+             return \"addq%.l %#8,%0\;addq%.l %2,%0\";
            }
          if (INTVAL (operands[2]) < -8
              && INTVAL (operands[2]) >= -16)
            {
              operands[2] = gen_rtx (CONST_INT, VOIDmode,
                                      - INTVAL (operands[2]) - 8);
-             return \"subq%.w %#8,%0\;subq%.w %2,%0\";
+             return \"subq%.l %#8,%0\;subq%.l %2,%0\";
            }
        }
 #endif
       if (ADDRESS_REG_P (operands[0])
          && INTVAL (operands[2]) >= -0x8000
-         && INTVAL (operands[2]) < 0x8000
-         && !TARGET_5200)
-       return \"add%.w %2,%0\";
+         && INTVAL (operands[2]) < 0x8000)
+       {
+         if (TARGET_68040)
+           return \"add%.w %2,%0\";
+         else
+#ifdef MOTOROLA  
+           return \"lea (%c2,%0),%0\";
+#else
+           return \"lea %0@(%c2),%0\";
+#endif
+       }
     }
   return \"add%.l %2,%0\";
 }")
   "!TARGET_5200"
   "*
 {
-#ifndef NO_ADDSUB_Q
   if (GET_CODE (operands[2]) == CONST_INT)
     {
+#ifndef NO_ADDSUB_Q
       /* If the constant would be a negative number when interpreted as
         HImode, make it negative.  This is usually, but not always, done
         elsewhere in the compiler.  First check for constants out of range,
                                 - INTVAL (operands[2]));
          return \"subq%.w %2,%0\";
        }
-      /* On the 68020 it is faster to use two addqw instructions to
-        add a small integer (8 < N <= 16) to an address register.  
+      /* On the CPU32 it is faster to use two addqw instructions to
+        add a small integer (8 < N <= 16) to a register.  
         Likewise for subqw. */
-      if (TARGET_68020 && !TARGET_68040 && !TARGET_68060 
-          && ADDRESS_REG_P (operands[0]))
+      if (TARGET_CPU32 && REG_P (operands[0]))
        {
          if (INTVAL (operands[2]) > 8
              && INTVAL (operands[2]) <= 16)
              return \"subq%.w %#8,%0\;subq%.w %2,%0\";
            }
        }
-    }
 #endif
+      if (ADDRESS_REG_P (operands[0]) && !TARGET_68040)
+#ifdef MOTOROLA  
+           return \"lea (%c2,%0),%0\";
+#else
+           return \"lea %0@(%c2),%0\";
+#endif
+    }
   return \"add%.w %2,%0\";
 }")
 
   "!TARGET_5200"
   "*
 {
-#ifndef NO_ADDSUB_Q
   if (GET_CODE (operands[1]) == CONST_INT)
     {
+#ifndef NO_ADDSUB_Q
       /* If the constant would be a negative number when interpreted as
         HImode, make it negative.  This is usually, but not always, done
         elsewhere in the compiler.  First check for constants out of range,
                                 - INTVAL (operands[1]));
          return \"subq%.w %1,%0\";
        }
-      /* On the 68020 it is faster to use two addqw instructions to
-        add a small integer (8 < N <= 16) to an address register. 
+      /* On the CPU32 it is faster to use two addqw instructions to
+        add a small integer (8 < N <= 16) to a register. 
         Likewise for subqw. */
-      if (TARGET_68020 && !TARGET_68040 && !TARGET_68060 
-          && ADDRESS_REG_P (operands[0]))
+      if (TARGET_CPU32 && REG_P (operands[0]))
        {
          if (INTVAL (operands[1]) > 8
              && INTVAL (operands[1]) <= 16)
              return \"subq%.w %#8,%0\;subq%.w %1,%0\";
            }
        }
-    }
 #endif
+      if (ADDRESS_REG_P (operands[0]) && !TARGET_68040)
+#ifdef MOTOROLA  
+           return \"lea (%c1,%0),%0\";
+#else
+           return \"lea %0@(%c1),%0\";
+#endif
+    }
   return \"add%.w %1,%0\";
 }")
 
   "!TARGET_5200"
   "*
 {
-#ifndef NO_ADDSUB_Q
   if (GET_CODE (operands[1]) == CONST_INT)
     {
+#ifndef NO_ADDSUB_Q
       /* If the constant would be a negative number when interpreted as
         HImode, make it negative.  This is usually, but not always, done
         elsewhere in the compiler.  First check for constants out of range,
                                 - INTVAL (operands[1]));
          return \"subq%.w %1,%0\";
        }
-      /* On the 68020 it is faster to use two addqw instructions to
-        add a small integer (8 < N <= 16) to an address register.
+      /* On the CPU32 it is faster to use two addqw instructions to
+        add a small integer (8 < N <= 16) to a register.
         Likewise for subqw. */
-      if (TARGET_68020 && !TARGET_68040 && !TARGET_68060 
-          && ADDRESS_REG_P (operands[0])) 
+      if (TARGET_CPU32 && REG_P (operands[0])) 
        {
          if (INTVAL (operands[1]) > 8
              && INTVAL (operands[1]) <= 16)
              return \"subq%.w %#8,%0\;subq%.w %1,%0\";
            }
        }
-    }
 #endif
+      if (ADDRESS_REG_P (operands[0]) && !TARGET_68040)
+#ifdef MOTOROLA  
+           return \"lea (%c1,%0),%0\";
+#else
+           return \"lea %0@(%c1),%0\";
+#endif
+    }
   return \"add%.w %1,%0\";
 }")
 
 #endif
 }")
 
-(define_insn "mulsi3"
+(define_expand "mulsi3"
+  [(set (match_operand:SI 0 "general_operand" "")
+       (mult:SI (match_operand:SI 1 "general_operand" "")
+                (match_operand:SI 2 "general_operand" "")))]
+  "TARGET_68020 || TARGET_5200"
+  "")
+
+(define_insn ""
   [(set (match_operand:SI 0 "general_operand" "=d")
        (mult:SI (match_operand:SI 1 "general_operand" "%0")
                 (match_operand:SI 2 "general_operand" "dmsK")))]
-  "TARGET_68020 || TARGET_5200"
+  "TARGET_68020"
+  "muls%.l %2,%0")
+
+(define_insn ""
+  [(set (match_operand:SI 0 "general_operand" "=d")
+       (mult:SI (match_operand:SI 1 "general_operand" "%0")
+                (match_operand:SI 2 "general_operand" "d<>")))]
+  "TARGET_5200"
   "muls%.l %2,%0")
 
 (define_insn "umulhisi3"
 ;; Prevent AND from being made with sp.  This doesn't exist in the machine
 ;; and reload will cause inefficient code.  Since sp is a FIXED_REG, we
 ;; can't allocate pseudos into it.
-(define_insn "andsi3"
+
+(define_expand "andsi3"
   [(set (match_operand:SI 0 "not_sp_operand" "=m,d")
        (and:SI (match_operand:SI 1 "general_operand" "%0,0")
                (match_operand:SI 2 "general_operand" "dKs,dmMs")))]
   ""
+  "")
+
+(define_insn "andsi3_internal"
+  [(set (match_operand:SI 0 "not_sp_operand" "=m,d")
+       (and:SI (match_operand:SI 1 "general_operand" "%0,0")
+               (match_operand:SI 2 "general_operand" "dKs,dmMs")))]
+  "!TARGET_5200"
   "*
 {
   int logval;
   if (GET_CODE (operands[2]) == CONST_INT
       && (INTVAL (operands[2]) | 0xffff) == 0xffffffff
       && (DATA_REG_P (operands[0])
-         || offsettable_memref_p (operands[0]))
-      && !TARGET_5200)
+         || offsettable_memref_p (operands[0])))
     {
       if (GET_CODE (operands[0]) != REG)
         operands[0] = adj_offsettable_operand (operands[0], 2);
   return \"and%.l %2,%0\";
 }")
 
+(define_insn "andsi3_5200"
+  [(set (match_operand:SI 0 "not_sp_operand" "=m,d")
+       (and:SI (match_operand:SI 1 "general_operand" "%0,0")
+               (match_operand:SI 2 "general_operand" "d,dmsK")))]
+  "TARGET_5200"
+  "and%.l %2,%0")
+
 (define_insn "andhi3"
   [(set (match_operand:HI 0 "general_operand" "=m,d")
        (and:HI (match_operand:HI 1 "general_operand" "%0,0")
 \f
 ;; inclusive-or instructions
 
-(define_insn "iorsi3"
+(define_expand "iorsi3"
+  [(set (match_operand:SI 0 "general_operand" "")
+       (ior:SI (match_operand:SI 1 "general_operand" "")
+               (match_operand:SI 2 "general_operand" "")))]
+  ""
+  "")
+
+(define_insn "iorsi3_internal"
   [(set (match_operand:SI 0 "general_operand" "=m,d")
        (ior:SI (match_operand:SI 1 "general_operand" "%0,0")
                (match_operand:SI 2 "general_operand" "dKs,dmMs")))]
-  ""
+  "!TARGET_5200"
   "*
 {
   register int logval;
   if (GET_CODE (operands[2]) == CONST_INT
       && INTVAL (operands[2]) >> 16 == 0
       && (DATA_REG_P (operands[0])
-         || offsettable_memref_p (operands[0]))
-      && !TARGET_5200)
+         || offsettable_memref_p (operands[0])))
     {
       if (GET_CODE (operands[0]) != REG)
         operands[0] = adj_offsettable_operand (operands[0], 2);
   return \"or%.l %2,%0\";
 }")
 
+(define_insn "iorsi3_5200"
+  [(set (match_operand:SI 0 "general_operand" "=m,d")
+       (ior:SI (match_operand:SI 1 "general_operand" "%0,0")
+               (match_operand:SI 2 "general_operand" "d,dmsK")))]
+  "TARGET_5200"
+  "or%.l %2,%0")
+
 (define_insn "iorhi3"
   [(set (match_operand:HI 0 "general_operand" "=m,d")
        (ior:HI (match_operand:HI 1 "general_operand" "%0,0")
   "!TARGET_5200"
   "or%.b %1,%0")
 
+;; On all 68k models, this makes faster code in a special case.
+;; See also ashlsi_16, ashrsi_16 and lshrsi_16.
+
+(define_insn "iorsi_zexthi_ashl16"
+  [(set (match_operand:SI 0 "general_operand" "=d,d")
+    (ior:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "dmn,dmn"))
+        (ashift:SI (match_operand:SI 2 "general_operand" "o,0")
+            (const_int 16))))]
+  ""
+  "*
+{
+  CC_STATUS_INIT;
+  if (GET_CODE (operands[2]) != REG)
+    {
+      operands[2] = adj_offsettable_operand (operands[2], 2);
+      output_asm_insn (\"move%.w %2,%0\", operands);
+    }
+  return \"swap %0\;mov%.w %1,%0\";
+}")
+
 (define_insn ""
   [(set (match_operand:SI 0 "general_operand" "=o,d")
     (ior:SI (zero_extend:SI (match_operand 1 "general_operand" "dn,dmn"))
 \f
 ;; xor instructions
 
-(define_insn "xorsi3"
+(define_expand "xorsi3"
+  [(set (match_operand:SI 0 "general_operand" "")
+       (xor:SI (match_operand:SI 1 "general_operand" "")
+               (match_operand:SI 2 "general_operand" "")))]
+  ""
+  "")
+
+(define_insn "xorsi3_internal"
   [(set (match_operand:SI 0 "general_operand" "=do,m")
        (xor:SI (match_operand:SI 1 "general_operand" "%0,0")
                (match_operand:SI 2 "general_operand" "di,dKs")))]
-  ""
+  "!TARGET_5200"
   "*
 {
   if (GET_CODE (operands[2]) == CONST_INT
       && INTVAL (operands[2]) >> 16 == 0
-      && (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0]))
-      && !TARGET_5200)
+      && (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0])))
     {
       if (! DATA_REG_P (operands[0]))
        operands[0] = adj_offsettable_operand (operands[0], 2);
   return \"eor%.l %2,%0\";
 }")
 
+(define_insn "xorsi3_5200"
+  [(set (match_operand:SI 0 "general_operand" "=dm,d")
+       (xor:SI (match_operand:SI 1 "general_operand" "%0,0")
+               (match_operand:SI 2 "general_operand" "d,Ks")))]
+  "TARGET_5200"
+  "eor%.l %2,%0")
+
 (define_insn "xorhi3"
   [(set (match_operand:HI 0 "general_operand" "=dm")
        (xor:HI (match_operand:HI 1 "general_operand" "%0")
   "!TARGET_5200"
   "lsl%.b %1,%0")
 
-;; On all 68k models, this makes faster code in a special case.
+;; On most 68k models, this makes faster code in a special case.
 
-(define_insn ""
+(define_insn "ashrsi_16"
   [(set (match_operand:SI 0 "register_operand" "=d")
        (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
                     (const_int 16)))]
-  ""
+  "!TARGET_68060"
   "swap %0\;ext%.l %0")
 
 ;; On the 68000, this makes faster code in a special case.
   "!TARGET_5200 
     && ((INTVAL (operands[2]) == 1 || INTVAL (operands[2]) == 2
     || INTVAL (operands[2]) == 3 || INTVAL (operands[2]) == 8
-    || INTVAL (operands[2]) == 16 || INTVAL (operands[2]) == 63))"
+    || INTVAL (operands[2]) == 16 || INTVAL (operands[2]) == 31
+    || INTVAL (operands[2]) == 63))"
   "*
 {
   operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
     return \"move%.b %0,%1\;asr%.l %#8,%0\;ror%.l %#8,%1\";
   else if (INTVAL (operands[2]) == 16)
     return \"move%.w %0,%1\;clr%.w %0\;swap %1\;ext%.l %0\";
+  else if (INTVAL (operands[2]) == 31)
+    return \"add%.l %1,%1\;addx%.l %0,%0\;move%.l %0,%1\;subx%.l %0,%0\";
   else if (INTVAL (operands[2]) == 2)
     return \"asr%.l %#1,%0\;roxr%.l %#1,%1\;asr%.l %#1,%0\;roxr%.l %#1,%1\";
   else/* if (INTVAL (operands[2]) == 3)*/
   if (GET_CODE (operands[2]) != CONST_INT
   || (INTVAL (operands[2]) != 1 && INTVAL (operands[2]) != 2
      && INTVAL (operands[2]) != 3 && INTVAL (operands[2]) != 8
-     && INTVAL (operands[2]) != 16 && INTVAL (operands[2]) != 32
-     && INTVAL (operands[2]) != 63))
+     && INTVAL (operands[2]) != 16 && INTVAL (operands[2]) != 31
+     && INTVAL (operands[2]) != 32 && INTVAL (operands[2]) != 63))
     FAIL;
 } ")
 
 (define_insn "rotlsi3"
   [(set (match_operand:SI 0 "register_operand" "=d")
        (rotate:SI (match_operand:SI 1 "register_operand" "0")
-                  (match_operand:SI 2 "general_operand" "dI")))]
+                  (match_operand:SI 2 "general_operand" "dINO")))]
   "!TARGET_5200"
-  "rol%.l %2,%0")
+  "*
+{
+  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 16)
+    return \"swap %0\";
+  else if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 16)
+    {
+      operands[2] = gen_rtx (CONST_INT, VOIDmode, 32 - INTVAL (operands[2]));
+      return \"ror%.l %2,%0\";
+    }
+  else
+    return \"rol%.l %2,%0\";
+}")
 
 (define_insn "rotlhi3"
   [(set (match_operand:HI 0 "register_operand" "=d")
        (rotate:HI (match_operand:HI 1 "register_operand" "0")
-                  (match_operand:HI 2 "general_operand" "dI")))]
+                  (match_operand:HI 2 "general_operand" "dIP")))]
   "!TARGET_5200"
-  "rol%.w %2,%0")
-
+  "*
+{
+  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 8)
+    {
+      operands[2] = gen_rtx (CONST_INT, VOIDmode, 16 - INTVAL (operands[2]));
+      return \"ror%.w %2,%0\";
+    }
+  else
+    return \"rol%.w %2,%0\";
+}")
 
 (define_insn ""
   [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d"))
        (rotate:HI (match_dup 0)
-                  (match_operand:HI 1 "general_operand" "dI")))]
+                  (match_operand:HI 1 "general_operand" "dIP")))]
   "!TARGET_5200"
-  "rol%.w %1,%0")
+  "*
+{
+  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 8)
+    {
+      operands[2] = gen_rtx (CONST_INT, VOIDmode, 16 - INTVAL (operands[2]));
+      return \"ror%.w %2,%0\";
+    }
+  else
+    return \"rol%.w %2,%0\";
+}")
 
 (define_insn "rotlqi3"
   [(set (match_operand:QI 0 "register_operand" "=d")
        (rotate:QI (match_operand:QI 1 "register_operand" "0")
                   (match_operand:QI 2 "general_operand" "dI")))]
   "!TARGET_5200"
-  "rol%.b %2,%0")
+  "*
+{
+  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 4)
+    {
+      operands[2] = gen_rtx (CONST_INT, VOIDmode, 8 - INTVAL (operands[2]));
+      return \"ror%.b %2,%0\";
+    }
+  else
+    return \"rol%.b %2,%0\";
+}")
 
 (define_insn ""
   [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d"))
        (rotate:QI (match_dup 0)
                   (match_operand:QI 1 "general_operand" "dI")))]
   "!TARGET_5200"
-  "rol%.b %1,%0")
+  "*
+{
+  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 4)
+    {
+      operands[2] = gen_rtx (CONST_INT, VOIDmode, 8 - INTVAL (operands[2]));
+      return \"ror%.b %2,%0\";
+    }
+  else
+    return \"rol%.b %2,%0\";
+}")
 
 (define_insn "rotrsi3"
   [(set (match_operand:SI 0 "register_operand" "=d")
   return output_scc_di (operands[1], operands[2], operands[3], operands[0]);
 } ")
 
-(define_insn "seq"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+(define_expand "seq"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (eq:QI (cc0) (const_int 0)))]
+  ""
+  "
+{
+  if (TARGET_68060 && m68k_last_compare_had_fp_operands)
+    {
+      m68k_last_compare_had_fp_operands = 0;
+      FAIL;
+    }
+}")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (eq:QI (cc0) (const_int 0)))]
   ""
   "*
   OUTPUT_JUMP (\"seq %0\", \"fseq %0\", \"seq %0\");
 ")
 
-(define_insn "sne"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+(define_expand "sne"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (ne:QI (cc0) (const_int 0)))]
+  ""
+  "
+{
+  if (TARGET_68060 && m68k_last_compare_had_fp_operands)
+    {
+      m68k_last_compare_had_fp_operands = 0;
+      FAIL;
+    }
+}")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (ne:QI (cc0) (const_int 0)))]
   ""
   "*
   OUTPUT_JUMP (\"sne %0\", \"fsne %0\", \"sne %0\");
 ")
 
-(define_insn "sgt"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+(define_expand "sgt"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (gt:QI (cc0) (const_int 0)))]
+  ""
+  "
+{
+  if (TARGET_68060 && m68k_last_compare_had_fp_operands)
+    {
+      m68k_last_compare_had_fp_operands = 0;
+      FAIL;
+    }
+}")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (gt:QI (cc0) (const_int 0)))]
   ""
   "*
 ")
 
 (define_insn "sgtu"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (gtu:QI (cc0) (const_int 0)))]
   ""
   "* cc_status = cc_prev_status;
      return \"shi %0\"; ")
 
-(define_insn "slt"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+(define_expand "slt"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (lt:QI (cc0) (const_int 0)))]
+  ""
+  "
+{
+  if (TARGET_68060 && m68k_last_compare_had_fp_operands)
+    {
+      m68k_last_compare_had_fp_operands = 0;
+      FAIL;
+    }
+}")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (lt:QI (cc0) (const_int 0)))]
   ""
   "* cc_status = cc_prev_status;
      OUTPUT_JUMP (\"slt %0\", \"fslt %0\", \"smi %0\"); ")
 
 (define_insn "sltu"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (ltu:QI (cc0) (const_int 0)))]
   ""
   "* cc_status = cc_prev_status;
      return \"scs %0\"; ")
 
-(define_insn "sge"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+(define_expand "sge"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (ge:QI (cc0) (const_int 0)))]
+  ""
+  "
+{
+  if (TARGET_68060 && m68k_last_compare_had_fp_operands)
+    {
+      m68k_last_compare_had_fp_operands = 0;
+      FAIL;
+    }
+}")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (ge:QI (cc0) (const_int 0)))]
   ""
   "* cc_status = cc_prev_status;
      OUTPUT_JUMP (\"sge %0\", \"fsge %0\", \"spl %0\"); ")
 
 (define_insn "sgeu"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (geu:QI (cc0) (const_int 0)))]
   ""
   "* cc_status = cc_prev_status;
      return \"scc %0\"; ")
 
-(define_insn "sle"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+(define_expand "sle"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (le:QI (cc0) (const_int 0)))]
+  ""
+  "
+{
+  if (TARGET_68060 && m68k_last_compare_had_fp_operands)
+    {
+      m68k_last_compare_had_fp_operands = 0;
+      FAIL;
+    }
+}")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (le:QI (cc0) (const_int 0)))]
   ""
   "*
 ")
 
 (define_insn "sleu"
-  [(set (match_operand:QI 0 "general_operand" "=d")
+  [(set (match_operand:QI 0 "general_operand" "=dm")
        (leu:QI (cc0) (const_int 0)))]
   ""
   "* cc_status = cc_prev_status;
     return \"move%.l %0,%2\;or%.l %3,%2\;jeq %l1\";
 #endif
   operands[4] = gen_label_rtx();
+  if (TARGET_68020 || TARGET_5200)
 #ifdef MOTOROLA
-  output_asm_insn (\"tst%.l %0\;jbne %l4\;tst%.l %3\;jbeq %l1\", operands);
+    output_asm_insn (\"tst%.l %0\;jbne %l4\;tst%.l %3\;jbeq %l1\", operands);
+#else
+    output_asm_insn (\"tst%.l %0\;jne %l4\;tst%.l %3\;jeq %l1\", operands);
+#endif
+  else
+#ifdef MOTOROLA
+#ifdef SGS_CMP_ORDER
+    output_asm_insn (\"cmp%.w %0,%#0\;jbne %l4\;cmp%.w %3,%#0\;jbeq %l1\", operands);
 #else
-  output_asm_insn (\"tst%.l %0\;jne %l4\;tst%.l %3\;jeq %l1\", operands);
+    output_asm_insn (\"cmp%.w %#0,%0\;jbne %l4\;cmp%.w %#0,%3\;jbeq %l1\", operands);
+#endif
+#else
+    output_asm_insn (\"cmp%.w %#0,%0\;jne %l4\;cmp%.w %#0,%3\;jeq %l1\", operands);
 #endif
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
                                CODE_LABEL_NUMBER (operands[4]));
     operands[3] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
   else
     operands[3] = adj_offsettable_operand (operands[0], 4);
-  if (ADDRESS_REG_P (operands[0]))
+  if (!ADDRESS_REG_P (operands[0]))
+#ifdef MOTOROLA
+    return \"move%.l %0,%2\;or%.l %3,%2\;jbne %l1\";
+#else
+    return \"move%.l %0,%2\;or%.l %3,%2\;jne %l1\";
+#endif
+  if (TARGET_68020 || TARGET_5200)
 #ifdef MOTOROLA
     return \"tst%.l %0\;jbne %l1\;tst%.l %3\;jbne %l1\";
 #else
 #endif
   else
 #ifdef MOTOROLA
-    return \"move%.l %0,%2\;or%.l %3,%2\;jbne %l1\";
+#ifdef SGS_CMP_ORDER
+    return \"cmp%.w %0,%#0\;jbne %l1\;cmp%.w %3,%#0\;jbne %l1\";
 #else
-    return \"move%.l %0,%2\;or%.l %3,%2\;jne %l1\";
+    return \"cmp%.w %#0,%0\;jbne %l1\;cmp%.w %#0,%3\;jbne %l1\";
+#endif
+#else
+    return \"cmp%.w %#0,%0\;jne %l1\;cmp%.w %#0,%3\;jne %l1\";
 #endif
 } ")
 
        }
     }
   CC_STATUS_INIT;
+  if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (operands[0]))
+    output_asm_insn(\"tst%.l %0\", operands);
+  else
+    /* On an address reg, cmpw may replace cmpl.  */
+#ifdef SGS_CMP_ORDER
+    output_asm_insn(\"cmp%.w %0,%#0\", operands);
+#else
+    output_asm_insn(\"cmp%.w %#0,%0\", operands);
+#endif
+
 #ifdef MOTOROLA
-  return \"tst%.l %0\;jbpl %l1\";
+    return \"jbpl %l1\";
 #else
-  return \"tst%.l %0\;jpl %l1\";
+    return \"jpl %l1\";
 #endif
 } ")
 
        }
     }
   CC_STATUS_INIT;
+  if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (operands[0]))
+    output_asm_insn(\"tst%.l %0\", operands);
+  else
+    /* On an address reg, cmpw may replace cmpl.  */
+#ifdef SGS_CMP_ORDER
+    output_asm_insn(\"cmp%.w %0,%#0\", operands);
+#else
+    output_asm_insn(\"cmp%.w %#0,%0\", operands);
+#endif
+
 #ifdef MOTOROLA
-  return \"tst%.l %0\;jbmi %l1\";
+  return \"jbmi %l1\";
 #else
-  return \"tst%.l %0\;jmi %l1\";
+  return \"jmi %l1\";
 #endif
 } ")
 
 #else
 #ifdef SGS
 #ifdef ASM_OUTPUT_CASE_LABEL
-  return \"jmp 6(%%pc,%0.w)\";
+  if (TARGET_5200) 
+    return \"ext%.l %0\;jmp 6(%%pc,%0.l)\";
+  else
+    return \"jmp 6(%%pc,%0.w)\";
+#else
+  if (TARGET_5200)
+    {
+#ifdef CRDS
+      return \"ext%.l %0\;jmp 2(pc,%0.l)\";
 #else
+      return \"extl %0\;jmp 2(%%pc,%0.l)\";
+#endif  /* end !CRDS */
+    }
+  else
+    {
 #ifdef CRDS
-  return \"jmp 2(pc,%0.w)\";
+      return \"jmp 2(pc,%0.w)\";
 #else
-  return \"jmp 2(%%pc,%0.w)\";
+      return \"jmp 2(%%pc,%0.w)\";
 #endif  /* end !CRDS */
+    }
 #endif
 #else /* not SGS */
+  if (TARGET_5200)
+    {
+#ifdef MOTOROLA
+      return \"ext%.l %0\;jmp (2,pc,%0.l)\";
+#else
+      return \"extl %0\;jmp pc@(2,%0:l)\";
+#endif
+    }
+  else
+    {
 #ifdef MOTOROLA
-  return \"jmp (2,pc,%0.w)\";
+      return \"jmp (2,pc,%0.w)\";
 #else
-  return \"jmp pc@(2,%0:w)\";
+      return \"jmp pc@(2,%0:w)\";
 #endif
+    }
 #endif
 #endif
 ")
          else
            output_asm_insn (\"addq%.l %1,%0\", xoperands);
        }
-      else if (INTVAL (xoperands[1]) <= 16 
-              && TARGET_68020 && !TARGET_68040 && !TARGET_68060)
+      else if (TARGET_CPU32 && INTVAL (xoperands[1]) <= 16) 
        {
          xoperands[1] = gen_rtx (CONST_INT, VOIDmode,
                                  INTVAL (xoperands[1]) - 8);
        }
       else
 #endif
-        if (INTVAL (xoperands[1]) <= 0x7FFF && !TARGET_5200)
-          output_asm_insn (\"add%.w %1,%0\", xoperands);
+        if (INTVAL (xoperands[1]) <= 0x7FFF)
+        {
+         if (TARGET_68040)
+           output_asm_insn (\"add%.w %1,%0\", xoperands);
+         else
+#ifdef MOTOROLA  
+           output_asm_insn (\"lea (%c1,%0),%0\", xoperands);
+#else
+           output_asm_insn (\"lea %0@(%c1),%0\", xoperands);
+#endif
+        }
       else
         output_asm_insn (\"add%.l %1,%0\", xoperands);
     }
          else
            output_asm_insn (\"addq%.l %1,%0\", xoperands);
        }
-      else if (INTVAL (xoperands[1]) <= 16 
-              && TARGET_68020 && !TARGET_68040 && !TARGET_68060)
+      else if (TARGET_CPU32 && INTVAL (xoperands[1]) <= 16)
        {
          xoperands[1] = gen_rtx (CONST_INT, VOIDmode,
                                  INTVAL (xoperands[1]) - 8);
        }
       else
 #endif
-        if (INTVAL (xoperands[1]) <= 0x7FFF && !TARGET_5200)
-          output_asm_insn (\"add%.w %1,%0\", xoperands);
+        if (INTVAL (xoperands[1]) <= 0x7FFF)
+        {
+         if (TARGET_68040)
+           output_asm_insn (\"add%.w %1,%0\", xoperands);
+         else
+#ifdef MOTOROLA  
+           output_asm_insn (\"lea (%c1,%0),%0\", xoperands);
+#else
+           output_asm_insn (\"lea %0@(%c1),%0\", xoperands);
+#endif
+        }
       else
         output_asm_insn (\"add%.l %1,%0\", xoperands);
     }
    fpsm%.s %x3,%2,%x1,%0
    fpsm%.s %x3,%2,%x1,%0")
 
-(define_insn "tstxf"
+(define_expand "tstxf"
+  [(set (cc0)
+       (match_operand:XF 0 "nonimmediate_operand" ""))]
+  "TARGET_68881"
+  "m68k_last_compare_had_fp_operands = 1;")
+
+(define_insn ""
   [(set (cc0)
        (match_operand:XF 0 "nonimmediate_operand" "fm"))]
   "TARGET_68881"
   return \"ftst%.x %0\";
 }")
 
-(define_insn "cmpxf"
+(define_expand "cmpxf"
+  [(set (cc0)
+       (compare (match_operand:XF 0 "nonimmediate_operand" "")
+                (match_operand:XF 1 "nonimmediate_operand" "")))]
+  "TARGET_68881"
+  "m68k_last_compare_had_fp_operands = 1;")
+
+(define_insn ""
   [(set (cc0)
        (compare (match_operand:XF 0 "nonimmediate_operand" "f,m")
                 (match_operand:XF 1 "nonimmediate_operand" "fm,f")))]