OSDN Git Service

(output_addsi3): New function. From addsi3 pattern.
[pf3gnuchains/gcc-fork.git] / gcc / config / m68k / m68k.c
index 51e4bd9..2b3022e 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for Motorola 68000 family.
-   Copyright (C) 1987, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1987, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* Some output-actions in m68k.md need these.  */
@@ -52,6 +53,76 @@ static rtx find_addr_reg ();
 rtx legitimize_pic_address ();
 \f
 
+/* Alignment to use for loops and jumps */
+/* Specify power of two alignment used for loops. */
+char *m68k_align_loops_string;
+/* Specify power of two alignment used for non-loop jumps. */
+char *m68k_align_jumps_string;
+/* Specify power of two alignment used for functions. */
+char *m68k_align_funcs_string;
+
+/* Specify power of two alignment used for loops. */
+int m68k_align_loops;
+/* Specify power of two alignment used for non-loop jumps. */
+int m68k_align_jumps;
+/* Specify power of two alignment used for functions. */
+int m68k_align_funcs;
+
+/* Nonzero if the last compare/test insn had FP operands.  The
+   sCC expanders peek at this to determine what to do for the
+   68060, which has no fsCC instructions.  */
+int m68k_last_compare_had_fp_operands;
+
+/* Sometimes certain combinations of command options do not make
+   sense on a particular target machine.  You can define a macro
+   `OVERRIDE_OPTIONS' to take account of this.  This macro, if
+   defined, is executed once just after all the command options have
+   been parsed.
+
+   Don't use this macro to turn on various extra optimizations for
+   `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
+
+void
+override_options ()
+{
+  int def_align;
+
+  def_align = 1;
+
+  /* Validate -malign-loops= value, or provide default */
+  if (m68k_align_loops_string)
+    {
+      m68k_align_loops = atoi (m68k_align_loops_string);
+      if (m68k_align_loops < 1 || m68k_align_loops > MAX_CODE_ALIGN)
+       fatal ("-malign-loops=%d is not between 1 and %d",
+              m68k_align_loops, MAX_CODE_ALIGN);
+    }
+  else
+    m68k_align_loops = def_align;
+
+  /* Validate -malign-jumps= value, or provide default */
+  if (m68k_align_jumps_string)
+    {
+      m68k_align_jumps = atoi (m68k_align_jumps_string);
+      if (m68k_align_jumps < 1 || m68k_align_jumps > MAX_CODE_ALIGN)
+       fatal ("-malign-jumps=%d is not between 1 and %d",
+              m68k_align_jumps, MAX_CODE_ALIGN);
+    }
+  else
+    m68k_align_jumps = def_align;
+
+  /* Validate -malign-functions= value, or provide default */
+  if (m68k_align_funcs_string)
+    {
+      m68k_align_funcs = atoi (m68k_align_funcs_string);
+      if (m68k_align_funcs < 1 || m68k_align_funcs > MAX_CODE_ALIGN)
+       fatal ("-malign-functions=%d is not between 1 and %d",
+              m68k_align_funcs, MAX_CODE_ALIGN);
+    }
+  else
+    m68k_align_funcs = def_align;
+}
+\f
 /* Emit a (use pic_offset_table_rtx) if we used PIC relocation in the 
    function at any time during the compilation process.  In the future 
    we should try and eliminate the USE if we can easily determine that 
@@ -62,7 +133,11 @@ void
 finalize_pic ()
 {
   if (flag_pic && current_function_uses_pic_offset_table)
-    emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
+    {
+      rtx insn = gen_rtx (USE, VOIDmode, pic_offset_table_rtx);
+      emit_insn_after (insn, get_insns ());
+      emit_insn (insn);
+    }
 }
 
 \f
@@ -93,8 +168,20 @@ output_function_prologue (stream, size)
 
   if (frame_pointer_needed)
     {
-      /* Adding negative number is faster on the 68040.  */
-      if (fsize < 0x8000 && !TARGET_68040)
+      if (fsize == 0 && TARGET_68040)
+       {
+       /* on the 68040, pea + move is faster than link.w 0 */
+#ifdef MOTOROLA
+         asm_fprintf (stream, "\tpea (%s)\n\tmove.l %s,%s\n",
+              reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM],
+              reg_names[FRAME_POINTER_REGNUM]);
+#else
+         asm_fprintf (stream, "\tpea %s@\n\tmovel %s,%s\n",
+              reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM],
+              reg_names[FRAME_POINTER_REGNUM]);
+#endif
+       }
+      else if (fsize < 0x8000)
        {
 #ifdef MOTOROLA
          asm_fprintf (stream, "\tlink.w %s,%0I%d\n",
@@ -116,6 +203,7 @@ output_function_prologue (stream, size)
        }
       else
        {
+      /* Adding negative number is faster on the 68040.  */
 #ifdef MOTOROLA
          asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n",
                       reg_names[FRAME_POINTER_REGNUM], -fsize);
@@ -127,17 +215,67 @@ output_function_prologue (stream, size)
     }
   else if (fsize)
     {
-      /* Adding negative number is faster on the 68040.  */
       if (fsize + 4 < 0x8000)
        {
+#ifdef NO_ADDSUB_Q
+         if (fsize + 4 <= 8)
+           {
+             if (!TARGET_5200)
+               {
+                 /* asm_fprintf() cannot handle %. */
+#ifdef MOTOROLA
+                 asm_fprintf (stream, "\tsubq.w %OI%d,%Rsp\n", fsize + 4);
+#else
+                 asm_fprintf (stream, "\tsubqw %OI%d,%Rsp\n", fsize + 4);
+#endif
+               }
+             else
+               {
+                 /* asm_fprintf() cannot handle %. */
+#ifdef MOTOROLA
+                 asm_fprintf (stream, "\tsubq.l %OI%d,%Rsp\n", fsize + 4);
+#else
+                 asm_fprintf (stream, "\tsubql %OI%d,%Rsp\n", fsize + 4);
+#endif
+               }
+           }
+         else if (fsize + 4 <= 16 && TARGET_CPU32)
+           {
+             /* On the CPU32 it is faster to use two subqw instructions to
+                subtract a small integer (8 < N <= 16) to a register. */
+             /* asm_fprintf() cannot handle %. */
+#ifdef MOTOROLA
+             asm_fprintf (stream, "\tsubq.w %OI8,%Rsp\n\tsubq.w %OI%d,%Rsp\n",
+                          fsize + 4);
+#else
+             asm_fprintf (stream, "\tsubqw %OI8,%Rsp\n\tsubqw %OI%d,%Rsp\n",
+                          fsize + 4);
+#endif
+           }
+         else 
+#endif /* NO_ADDSUB_Q */
+         if (TARGET_68040)
+           {
+             /* Adding negative number is faster on the 68040.  */
+             /* asm_fprintf() cannot handle %. */
 #ifdef MOTOROLA
-         asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
+             asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
 #else
-         asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
+             asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
 #endif
+           }
+         else
+           {
+#ifdef MOTOROLA
+             asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", - (fsize + 4));
+#else
+             asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", - (fsize + 4));
+#endif
+           }
        }
       else
        {
+       /* asm_fprintf() cannot handle %. */
 #ifdef MOTOROLA
          asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4));
 #else
@@ -158,18 +296,21 @@ output_function_prologue (stream, size)
 #endif
       }
 #endif
-  for (regno = 16; regno < 24; regno++)
-    if (regs_ever_live[regno] && ! call_used_regs[regno])
-       mask |= 1 << (regno - 16);
-  if ((mask & 0xff) != 0)
+  if (TARGET_68881)
     {
+      for (regno = 16; regno < 24; regno++)
+       if (regs_ever_live[regno] && ! call_used_regs[regno])
+          mask |= 1 << (regno - 16);
+      if ((mask & 0xff) != 0)
+       {
 #ifdef MOTOROLA
-      asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);
+         asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);
 #else
-      asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
+         asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
 #endif
+       }
+      mask = 0;
     }
-  mask = 0;
   for (regno = 0; regno < 16; regno++)
     if (regs_ever_live[regno] && ! call_used_regs[regno])
       {
@@ -183,7 +324,15 @@ output_function_prologue (stream, size)
     }
 
 #if NEED_PROBE
-  fprintf (stream, "\ttstl sp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
+#ifdef MOTOROLA
+#ifdef CRDS
+  asm_fprintf (stream, "\ttstl %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4);
+#else
+  asm_fprintf (stream, "\ttst.l %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4);
+#endif
+#else
+  asm_fprintf (stream, "\ttstl %Rsp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
+#endif
 #endif
 
   if (num_saved_regs <= 2)
@@ -208,11 +357,41 @@ output_function_prologue (stream, size)
     }
   else if (mask)
     {
+      if (TARGET_5200)
+       {
+         /* The coldfire does not support the predecrement form of the 
+            movml instruction, so we must adjust the stack pointer and
+            then use the plain address register indirect mode.  We also
+            have to invert the register save mask to use the new mode.
+
+            FIXME: if num_saved_regs was calculated earlier, we could
+            combine the stack pointer adjustment with any adjustment
+            done when the initial stack frame is created.  This would
+            save an instruction */
+            
+         int newmask = 0;
+         int i;
+
+         for (i = 0; i < 16; i++)
+           if (mask & (1 << i))
+               newmask |= (1 << (15-i));
+
+#ifdef MOTOROLA
+         asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", -num_saved_regs*4);
+         asm_fprintf (stream, "\tmovm.l %0I0x%x,(%Rsp)\n", newmask);
+#else
+         asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", -num_saved_regs*4);
+         asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@\n", newmask);
+#endif
+       }
+      else
+       {
 #ifdef MOTOROLA
-      asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);
+         asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);
 #else
-      asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
+         asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
 #endif
+       }
     }
   if (flag_pic && current_function_uses_pic_offset_table)
     {
@@ -270,6 +449,7 @@ output_function_epilogue (stream, size)
   int fsize = (size + 3) & -4;
   int big = 0;
   rtx insn = get_last_insn ();
+  int restore_from_sp = 0;
   
   /* If the last insn was a BARRIER, we don't have to write any code.  */
   if (GET_CODE (insn) == NOTE)
@@ -282,6 +462,13 @@ output_function_epilogue (stream, size)
       return;
     }
 
+#ifdef FUNCTION_BLOCK_PROFILER_EXIT
+  if (profile_block_flag == 2)
+    {
+      FUNCTION_BLOCK_PROFILER_EXIT (stream);
+    }
+#endif
+
 #ifdef FUNCTION_EXTRA_EPILOGUE
   FUNCTION_EXTRA_EPILOGUE (stream, size);
 #endif
@@ -293,12 +480,15 @@ output_function_epilogue (stream, size)
   fpoffset = nregs * 8;
 #endif
   nregs = 0;
-  for (regno = 16; regno < 24; regno++)
-    if (regs_ever_live[regno] && ! call_used_regs[regno])
-      {
-        nregs++;
-       fmask |= 1 << (23 - regno);
-      }
+  if (TARGET_68881)
+    {
+      for (regno = 16; regno < 24; regno++)
+       if (regs_ever_live[regno] && ! call_used_regs[regno])
+         {
+           nregs++;
+           fmask |= 1 << (23 - regno);
+         }
+    }
   foffset = fpoffset + nregs * 12;
   nregs = 0;  mask = 0;
   if (frame_pointer_needed)
@@ -310,18 +500,23 @@ output_function_epilogue (stream, size)
        mask |= 1 << regno;
       }
   offset = foffset + nregs * 4;
+  /* FIXME : leaf_function_p below is too strong.
+     What we really need to know there is if there could be pending
+     stack adjustment needed at that point. */
+  restore_from_sp = ! frame_pointer_needed
+            || (! current_function_calls_alloca && leaf_function_p ());
   if (offset + fsize >= 0x8000
-      && frame_pointer_needed
+      && ! restore_from_sp
       && (mask || fmask || fpoffset))
     {
 #ifdef MOTOROLA
-      asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra0\n", -fsize);
+      asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra1\n", -fsize);
 #else
-      asm_fprintf (stream, "\tmovel %0I%d,%Ra0\n", -fsize);
+      asm_fprintf (stream, "\tmovel %0I%d,%Ra1\n", -fsize);
 #endif
       fsize = 0, big = 1;
     }
-  if (nregs <= 2)
+  if (TARGET_5200 || nregs <= 2)
     {
       /* Restore each separately in the same order moveml does.
          Using two movel instructions instead of a single moveml
@@ -337,17 +532,17 @@ output_function_epilogue (stream, size)
             if (big)
              {
 #ifdef MOTOROLA
-               asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra0.l),%s\n",
+               asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra1.l),%s\n",
                             offset + fsize,
                             reg_names[FRAME_POINTER_REGNUM],
                             reg_names[i]);
 #else
-               asm_fprintf (stream, "\tmovel %s@(-%d,%Ra0:l),%s\n",
+               asm_fprintf (stream, "\tmovel %s@(-%d,%Ra1:l),%s\n",
                             reg_names[FRAME_POINTER_REGNUM],
                             offset + fsize, reg_names[i]);
 #endif
              }
-            else if (! frame_pointer_needed)
+            else if (restore_from_sp)
              {
 #ifdef MOTOROLA
                asm_fprintf (stream, "\t%Omove.l (%Rsp)+,%s\n",
@@ -378,17 +573,17 @@ output_function_epilogue (stream, size)
       if (big)
        {
 #ifdef MOTOROLA
-         asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra0.l),%0I0x%x\n",
+         asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra1.l),%0I0x%x\n",
                       offset + fsize,
                       reg_names[FRAME_POINTER_REGNUM],
                       mask);
 #else
-         asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra0:l),%0I0x%x\n",
+         asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n",
                       reg_names[FRAME_POINTER_REGNUM],
                       offset + fsize, mask);
 #endif
        }
-      else if (! frame_pointer_needed)
+      else if (restore_from_sp)
        {
 #ifdef MOTOROLA
          asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask);
@@ -415,17 +610,17 @@ output_function_epilogue (stream, size)
       if (big)
        {
 #ifdef MOTOROLA
-         asm_fprintf (stream, "\tfmovm -%d(%s,%Ra0.l),%0I0x%x\n",
+         asm_fprintf (stream, "\tfmovm -%d(%s,%Ra1.l),%0I0x%x\n",
                       foffset + fsize,
                       reg_names[FRAME_POINTER_REGNUM],
                       fmask);
 #else
-         asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra0:l),%0I0x%x\n",
+         asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra1:l),%0I0x%x\n",
                       reg_names[FRAME_POINTER_REGNUM],
                       foffset + fsize, fmask);
 #endif
        }
-      else if (! frame_pointer_needed)
+      else if (restore_from_sp)
        {
 #ifdef MOTOROLA
          asm_fprintf (stream, "\tfmovm (%Rsp)+,%0I0x%x\n", fmask);
@@ -454,17 +649,17 @@ output_function_epilogue (stream, size)
          if (big)
            {
 #ifdef MOTOROLA
-             asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra0.l), %s\n",
+             asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra1.l), %s\n",
                           fpoffset + fsize,
                           reg_names[FRAME_POINTER_REGNUM],
                           reg_names[regno]);
 #else
-             asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra0:l), %s\n",
+             asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra1:l), %s\n",
                           reg_names[FRAME_POINTER_REGNUM],
                           fpoffset + fsize, reg_names[regno]);
 #endif
            }
-         else if (! frame_pointer_needed)
+         else if (restore_from_sp)
            {
 #ifdef MOTOROLA
              asm_fprintf (stream, "\tfpmovd (%Rsp)+,%s\n",
@@ -494,16 +689,64 @@ output_function_epilogue (stream, size)
             reg_names[FRAME_POINTER_REGNUM]);
   else if (fsize)
     {
+#ifdef NO_ADDSUB_Q
+      if (fsize + 4 <= 8) 
+       {
+         if (!TARGET_5200)
+           {
+#ifdef MOTOROLA
+             asm_fprintf (stream, "\taddq.w %OI%d,%Rsp\n", fsize + 4);
+#else
+             asm_fprintf (stream, "\taddqw %OI%d,%Rsp\n", fsize + 4);
+#endif
+           }
+         else
+           {
+#ifdef MOTOROLA
+             asm_fprintf (stream, "\taddq.l %OI%d,%Rsp\n", fsize + 4);
+#else
+             asm_fprintf (stream, "\taddql %OI%d,%Rsp\n", fsize + 4);
+#endif
+           }
+       }
+      else if (fsize + 4 <= 16 && TARGET_CPU32)
+       {
+         /* On the CPU32 it is faster to use two addqw instructions to
+            add a small integer (8 < N <= 16) to a register. */
+         /* asm_fprintf() cannot handle %. */
+#ifdef MOTOROLA
+         asm_fprintf (stream, "\taddq.w %OI8,%Rsp\n\taddq.w %OI%d,%Rsp\n",
+                      fsize + 4);
+#else
+         asm_fprintf (stream, "\taddqw %OI8,%Rsp\n\taddqw %OI%d,%Rsp\n",
+                      fsize + 4);
+#endif
+       }
+      else
+#endif /* NO_ADDSUB_Q */
       if (fsize + 4 < 0x8000)
        {
+         if (TARGET_68040)
+           { 
+             /* asm_fprintf() cannot handle %. */
+#ifdef MOTOROLA
+             asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", fsize + 4);
+#else
+             asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", fsize + 4);
+#endif
+           }
+         else
+           {
 #ifdef MOTOROLA
-         asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", fsize + 4);
+             asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", fsize + 4);
 #else
-         asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", fsize + 4);
+             asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", fsize + 4);
 #endif
+           }
        }
       else
        {
+       /* asm_fprintf() cannot handle %. */
 #ifdef MOTOROLA
          asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", fsize + 4);
 #else
@@ -540,13 +783,8 @@ valid_dbcc_comparison_p (x, mode)
      rtx x;
      enum machine_mode mode;
 {
-  /* We could add support for these in the future */
-  if (cc_prev_status.flags & CC_IN_68881)
-    return 0;
-
   switch (GET_CODE (x))
     {
-
       case EQ: case NE: case GTU: case LTU:
       case GEU: case LEU:
         return 1;
@@ -560,16 +798,23 @@ valid_dbcc_comparison_p (x, mode)
     }
 }
 
+/* Return non-zero if flags are currently in the 68881 flag register.  */
+int
+flags_in_68881 ()
+{
+  /* We could add support for these in the future */
+  return cc_status.flags & CC_IN_68881;
+}
+
 /* Output a dbCC; jCC sequence.  Note we do not handle the 
    floating point version of this sequence (Fdbcc).  We also
    do not handle alternative conditions when CC_NO_OVERFLOW is
-   set.  It is assumed that valid_dbcc_comparison_p will kick
-   those out before we get here.  */
+   set.  It is assumed that valid_dbcc_comparison_p and flags_in_68881 will
+   kick those out before we get here.  */
 
 output_dbcc_and_branch (operands)
      rtx *operands;
 {
   switch (GET_CODE (operands[3]))
     {
       case EQ:
@@ -677,6 +922,166 @@ output_dbcc_and_branch (operands)
 }
 
 char *
+output_scc_di(op, operand1, operand2, dest)
+     rtx op;
+     rtx operand1;
+     rtx operand2;
+     rtx dest;
+{
+  rtx loperands[7];
+  enum rtx_code op_code = GET_CODE (op);
+
+  /* This does not produce a usefull cc.  */
+  CC_STATUS_INIT;
+
+  /* The m68k cmp.l instruction requires operand1 to be a reg as used
+     below.  Swap the operands and change the op if these requirements
+     are not fulfilled.  */
+  if (GET_CODE (operand2) == REG && GET_CODE (operand1) != REG)
+    {
+      rtx tmp = operand1;
+
+      operand1 = operand2;
+      operand2 = tmp;
+      op_code = swap_condition (op_code);
+    }
+  loperands[0] = operand1;
+  if (GET_CODE (operand1) == REG)
+    loperands[1] = gen_rtx (REG, SImode, REGNO (operand1) + 1);
+  else
+    loperands[1] = adj_offsettable_operand (operand1, 4);
+  if (operand2 != const0_rtx)
+    {
+      loperands[2] = operand2;
+      if (GET_CODE (operand2) == REG)
+       loperands[3] = gen_rtx (REG, SImode, REGNO (operand2) + 1);
+      else
+       loperands[3] = adj_offsettable_operand (operand2, 4);
+    }
+  loperands[4] = gen_label_rtx();
+  if (operand2 != const0_rtx)
+#ifdef MOTOROLA
+#ifdef SGS_CMP_ORDER
+    output_asm_insn ("cmp%.l %0,%2\n\tjbne %l4\n\tcmp%.l %1,%3", loperands);
+#else
+    output_asm_insn ("cmp%.l %2,%0\n\tjbne %l4\n\tcmp%.l %3,%1", loperands);
+#endif
+#else
+#ifdef SGS_CMP_ORDER
+    output_asm_insn ("cmp%.l %0,%2\n\tjne %l4\n\tcmp%.l %1,%3", loperands);
+#else
+    output_asm_insn ("cmp%.l %2,%0\n\tjne %l4\n\tcmp%.l %3,%1", loperands);
+#endif
+#endif
+  else
+#ifdef MOTOROLA
+    output_asm_insn ("tst%.l %0\n\tjbne %l4\n\ttst%.l %1", loperands);
+#else
+    output_asm_insn ("tst%.l %0\n\tjne %l4\n\ttst%.l %1", loperands);
+#endif
+  loperands[5] = dest;
+  
+  switch (op_code)
+    {
+      case EQ:
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("seq %5", loperands);
+        break;
+
+      case NE:
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("sne %5", loperands);
+        break;
+
+      case GT:
+        loperands[6] = gen_label_rtx();
+#ifdef MOTOROLA
+        output_asm_insn ("shi %5\n\tjbra %l6", loperands);
+#else
+        output_asm_insn ("shi %5\n\tjra %l6", loperands);
+#endif
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("sgt %5", loperands);
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[6]));
+        break;
+
+      case GTU:
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("shi %5", loperands);
+        break;
+
+      case LT:
+        loperands[6] = gen_label_rtx();
+#ifdef MOTOROLA
+        output_asm_insn ("scs %5\n\tjbra %l6", loperands);
+#else
+        output_asm_insn ("scs %5\n\tjra %l6", loperands);
+#endif
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("slt %5", loperands);
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[6]));
+        break;
+
+      case LTU:
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("scs %5", loperands);
+        break;
+
+      case GE:
+        loperands[6] = gen_label_rtx();
+#ifdef MOTOROLA
+        output_asm_insn ("scc %5\n\tjbra %l6", loperands);
+#else
+        output_asm_insn ("scc %5\n\tjra %l6", loperands);
+#endif
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("sge %5", loperands);
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[6]));
+        break;
+
+      case GEU:
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("scc %5", loperands);
+        break;
+
+      case LE:
+        loperands[6] = gen_label_rtx();
+#ifdef MOTOROLA
+        output_asm_insn ("sls %5\n\tjbra %l6", loperands);
+#else
+        output_asm_insn ("sls %5\n\tjra %l6", loperands);
+#endif
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("sle %5", loperands);
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[6]));
+        break;
+
+      case LEU:
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (loperands[4]));
+        output_asm_insn ("sls %5", loperands);
+        break;
+
+      default:
+       abort ();
+    }
+  return "";
+}
+
+char *
 output_btst (operands, countop, dataop, insn, signpos)
      rtx *operands;
      rtx countop, dataop;
@@ -749,6 +1154,25 @@ symbolic_operand (op, mode)
       return 0;
     }
 }
+\f
+/* Check for sign_extend or zero_extend.  Used for bit-count operands. */
+
+int
+extend_operator(x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+    if (mode != VOIDmode && GET_MODE(x) != mode)
+       return 0;
+    switch (GET_CODE(x))
+       {
+       case SIGN_EXTEND :
+       case ZERO_EXTEND :
+           return 1;
+       default :
+           return 0;
+       }
+}
 
 \f
 /* Legitimize PIC addresses.  If the address is already
@@ -842,33 +1266,310 @@ legitimize_pic_address (orig, mode, reg)
 }
 
 \f
-/* Return the best assembler insn template
-   for moving operands[1] into operands[0] as a fullword.  */
+typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ } CONST_METHOD;
 
-static char *
-singlemove_string (operands)
+#define USE_MOVQ(i)    ((unsigned)((i) + 128) <= 255)
+
+CONST_METHOD
+const_method (constant)
+     rtx constant;
+{
+  int i;
+  unsigned u;
+
+  i = INTVAL (constant);
+  if (USE_MOVQ (i))
+    return MOVQ;
+
+  /* The Coldfire doesn't have byte or word operations. */
+  /* FIXME: This may not be useful for the m68060 either */
+  if (!TARGET_5200) 
+    {
+      /* if -256 < N < 256 but N is not in range for a moveq
+        N^ff will be, so use moveq #N^ff, dreg; not.b dreg. */
+      if (USE_MOVQ (i ^ 0xff))
+       return NOTB;
+      /* Likewise, try with not.w */
+      if (USE_MOVQ (i ^ 0xffff))
+       return NOTW;
+      /* This is the only value where neg.w is useful */
+      if (i == -65408)
+       return NEGW;
+      /* Try also with swap */
+      u = i;
+      if (USE_MOVQ ((u >> 16) | (u << 16)))
+       return SWAP;
+    }
+  /* Otherwise, use move.l */
+  return MOVL;
+}
+
+const_int_cost (constant)
+     rtx constant;
+{
+  switch (const_method (constant))
+    {
+      case MOVQ :
+      /* Constants between -128 and 127 are cheap due to moveq */
+       return 0;
+      case NOTB :
+      case NOTW :
+      case NEGW :
+      case SWAP :
+      /* Constants easily generated by moveq + not.b/not.w/neg.w/swap  */
+        return 1;
+      case MOVL :
+       return 2;
+      default :
+        abort ();
+    }
+}
+
+char *
+output_move_const_into_data_reg (operands)
      rtx *operands;
 {
-#ifdef SUPPORT_SUN_FPA
-  if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1]))
-    return "fpmoves %1,%0";
+  int i;
+
+  i = INTVAL (operands[1]);
+  switch (const_method (operands[1]))
+    {
+    case MOVQ :
+#if defined (MOTOROLA) && !defined (CRDS)
+      return "moveq%.l %1,%0";
+#else
+      return "moveq %1,%0";
+#endif
+    case NOTB :
+      operands[1] = gen_rtx (CONST_INT, VOIDmode, i ^ 0xff);
+#if defined (MOTOROLA) && !defined (CRDS)
+      return "moveq%.l %1,%0\n\tnot%.b %0";
+#else
+      return "moveq %1,%0\n\tnot%.b %0";
+#endif  
+    case NOTW :
+      operands[1] = gen_rtx (CONST_INT, VOIDmode, i ^ 0xffff);
+#if defined (MOTOROLA) && !defined (CRDS)
+      return "moveq%.l %1,%0\n\tnot%.w %0";
+#else
+      return "moveq %1,%0\n\tnot%.w %0";
+#endif  
+    case NEGW :
+#if defined (MOTOROLA) && !defined (CRDS)
+      return "moveq%.l %#-128,%0\n\tneg%.w %0";
+#else
+      return "moveq %#-128,%0\n\tneg%.w %0";
+#endif  
+    case SWAP :
+      {
+       unsigned u = i;
+
+       operands[1] = gen_rtx (CONST_INT, VOIDmode, (u << 16) | (u >> 16));
+#if defined (MOTOROLA) && !defined (CRDS)
+       return "moveq%.l %1,%0\n\tswap %0";
+#else
+       return "moveq %1,%0\n\tswap %0";
+#endif  
+      }
+    case MOVL :
+       return "move%.l %1,%0";
+    default :
+       abort ();
+    }
+}
+
+char *
+output_move_simode_const (operands)
+     rtx *operands;
+{
+  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%.l %0";
+  else if (DATA_REG_P (operands[0]))
+    return output_move_const_into_data_reg (operands);
+  else if (ADDRESS_REG_P (operands[0])
+          && INTVAL (operands[1]) < 0x8000
+          && INTVAL (operands[1]) >= -0x8000)
+    return "move%.w %1,%0";
+  else if (GET_CODE (operands[0]) == MEM
+      && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
+      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
+          && INTVAL (operands[1]) < 0x8000
+          && INTVAL (operands[1]) >= -0x8000)
+    return "pea %a1";
+  return "move%.l %1,%0";
+}
+
+char *
+output_move_simode (operands)
+     rtx *operands;
+{
+  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";
+}
+
+char *
+output_move_himode (operands)
+     rtx *operands;
+{
+ 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";
+}
+
+char *
+output_move_qimode (operands)
+     rtx *operands;
+{
+  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.  */
+      if (!reg_mentioned_p (stack_pointer_rtx, operands[1]))
+       {
+         xoperands[3] = stack_pointer_rtx;
+#ifndef NO_ADDSUB_Q
+         output_asm_insn ("subq%.l %#2,%3\n\tmove%.b %1,%2", xoperands);
+#else
+         output_asm_insn ("sub%.l %#2,%3\n\tmove%.b %1,%2", xoperands);
 #endif
-  if (DATA_REG_P (operands[0])
-      && GET_CODE (operands[1]) == CONST_INT
+       }
+      else
+       output_asm_insn ("move%.b %1,%-\n\tmove%.b %@,%2", xoperands);
+      return "";
+    }
+
+  /* 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 || TARGET_5200)
+         || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))
+    {
+      if (operands[1] == const0_rtx)
+       return "clr%.b %0";
+      if ((!TARGET_5200 || DATA_REG_P (operands[0]))
+         && GET_CODE (operands[1]) == CONST_INT
+         && (INTVAL (operands[1]) & 255) == 255)
+       {
+         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)
+#if defined(MOTOROLA) && !defined(CRDS)
       return "moveq%.l %1,%0";
 #else
       return "moveq %1,%0";
 #endif
     }
-  if (operands[1] != const0_rtx)
+  if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1]))
     return "move%.l %1,%0";
-  if (! ADDRESS_REG_P (operands[0]))
-    return "clr%.l %0";
-  return "sub%.l %0,%0";
+  if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1]))
+    return "move%.w %1,%0";
+  return "move%.b %1,%0";
+}
+
+/* Return the best assembler insn template
+   for moving operands[1] into operands[0] as a fullword.  */
+
+static char *
+singlemove_string (operands)
+     rtx *operands;
+{
+#ifdef SUPPORT_SUN_FPA
+  if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1]))
+    return "fpmoves %1,%0";
+#endif
+  if (GET_CODE (operands[1]) == CONST_INT)
+    return output_move_simode_const (operands);
+  return "move%.l %1,%0";
 }
 
 
@@ -1067,7 +1768,7 @@ output_move_double (operands)
   if (optype0 == PUSHOP
       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
-    operands[1] = latehalf[1];
+    operands[1] = middlehalf[1] = latehalf[1];
 
   /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)),
      if the upper part of reg N does not appear in the MEM, arrange to
@@ -1077,15 +1778,18 @@ output_move_double (operands)
   if (optype0 == REGOP
       && (optype1 == OFFSOP || optype1 == MEMOP))
     {
-      if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
-         && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
+      rtx testlow = gen_rtx (REG, SImode, REGNO (operands[0]));
+
+      if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))
+         && reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
        {
          /* If both halves of dest are used in the src memory address,
-            compute the address into latehalf of dest.  */
+            compute the address into latehalf of dest.
+            Note that this can't happen if the dest is two data regs.  */
 compadr:
          xops[0] = latehalf[0];
          xops[1] = XEXP (operands[1], 0);
-         output_asm_insn ("lea%L0,%a1,%0", xops);
+         output_asm_insn ("lea %a1,%0", xops);
          if( GET_MODE (operands[1]) == XFmode )
            {
              operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);
@@ -1099,16 +1803,22 @@ compadr:
            }
        }
       else if (size == 12
-                && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0)))
+              && reg_overlap_mentioned_p (middlehalf[0],
+                                          XEXP (operands[1], 0)))
        {
-         /* Check for two regs used by both source and dest. */
-         if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
-               || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
-               goto compadr;
+         /* Check for two regs used by both source and dest.
+            Note that this can't happen if the dest is all data regs.
+            It can happen if the dest is d6, d7, a0.
+            But in that case, latehalf is an addr reg, so
+            the code at compadr does ok.  */
+
+         if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))
+             || reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
+           goto compadr;
 
          /* JRV says this can't happen: */
          if (addreg0 || addreg1)
-             abort();
+           abort ();
 
          /* Only the middle reg conflicts; simply put it last. */
          output_asm_insn (singlemove_string (operands), operands);
@@ -1116,7 +1826,7 @@ compadr:
          output_asm_insn (singlemove_string (middlehalf), middlehalf);
          return "";
        }
-      else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
+      else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)))
        /* If the low half of dest is mentioned in the source memory
           address, the arrange to emit the move late half first.  */
        dest_overlapped_low = 1;
@@ -1140,16 +1850,16 @@ compadr:
       if (addreg0)
        {
          if (size == 12)
-           output_asm_insn ("addql %#8,%0", &addreg0);
+           output_asm_insn ("addq%.l %#8,%0", &addreg0);
          else
-           output_asm_insn ("addql %#4,%0", &addreg0);
+           output_asm_insn ("addq%.l %#4,%0", &addreg0);
        }
       if (addreg1)
        {
          if (size == 12)
-           output_asm_insn ("addql %#8,%0", &addreg1);
+           output_asm_insn ("addq%.l %#8,%0", &addreg1);
          else
-           output_asm_insn ("addql %#4,%0", &addreg1);
+           output_asm_insn ("addq%.l %#4,%0", &addreg1);
        }
 
       /* Do that word.  */
@@ -1157,17 +1867,17 @@ compadr:
 
       /* Undo the adds we just did.  */
       if (addreg0)
-       output_asm_insn ("subql %#4,%0", &addreg0);
+       output_asm_insn ("subq%.l %#4,%0", &addreg0);
       if (addreg1)
-       output_asm_insn ("subql %#4,%0", &addreg1);
+       output_asm_insn ("subq%.l %#4,%0", &addreg1);
 
       if (size == 12)
        {
          output_asm_insn (singlemove_string (middlehalf), middlehalf);
          if (addreg0)
-           output_asm_insn ("subql %#4,%0", &addreg0);
+           output_asm_insn ("subq%.l %#4,%0", &addreg0);
          if (addreg1)
-           output_asm_insn ("subql %#4,%0", &addreg1);
+           output_asm_insn ("subq%.l %#4,%0", &addreg1);
        }
 
       /* Do low-numbered word.  */
@@ -1182,18 +1892,18 @@ compadr:
   if (size == 12)
     {
       if (addreg0)
-       output_asm_insn ("addql %#4,%0", &addreg0);
+       output_asm_insn ("addq%.l %#4,%0", &addreg0);
       if (addreg1)
-       output_asm_insn ("addql %#4,%0", &addreg1);
+       output_asm_insn ("addq%.l %#4,%0", &addreg1);
 
       output_asm_insn (singlemove_string (middlehalf), middlehalf);
     }
 
   /* Make any unoffsettable addresses point at high-numbered word.  */
   if (addreg0)
-    output_asm_insn ("addql %#4,%0", &addreg0);
+    output_asm_insn ("addq%.l %#4,%0", &addreg0);
   if (addreg1)
-    output_asm_insn ("addql %#4,%0", &addreg1);
+    output_asm_insn ("addq%.l %#4,%0", &addreg1);
 
   /* Do that word.  */
   output_asm_insn (singlemove_string (latehalf), latehalf);
@@ -1202,16 +1912,16 @@ compadr:
   if (addreg0)
     {
       if (size == 12)
-        output_asm_insn ("subql %#8,%0", &addreg0);
+        output_asm_insn ("subq%.l %#8,%0", &addreg0);
       else
-        output_asm_insn ("subql %#4,%0", &addreg0);
+        output_asm_insn ("subq%.l %#4,%0", &addreg0);
     }
   if (addreg1)
     {
       if (size == 12)
-        output_asm_insn ("subql %#8,%0", &addreg1);
+        output_asm_insn ("subq%.l %#8,%0", &addreg1);
       else
-        output_asm_insn ("subql %#4,%0", &addreg1);
+        output_asm_insn ("subq%.l %#4,%0", &addreg1);
     }
 
   return "";
@@ -1241,6 +1951,97 @@ find_addr_reg (addr)
     return addr;
   abort ();
 }
+
+/* Output assembler code to perform a 32 bit 3 operand add.  */
+
+char *
+output_addsi3 (operands)
+     rtx *operands;
+{
+  if (! operands_match_p (operands[0], operands[1]))
+    {
+      if (!ADDRESS_REG_P (operands[1]))
+       {
+         rtx tmp = operands[1];
+
+         operands[1] = operands[2];
+         operands[2] = tmp;
+       }
+
+      /* These insns can result from reloads to access
+        stack slots over 64k from the frame pointer.  */
+      if (GET_CODE (operands[2]) == CONST_INT
+         && INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000)
+        return "move%.l %2,%0\\;add%.l %1,%0";
+#ifdef SGS
+      if (GET_CODE (operands[2]) == REG)
+       return "lea 0(%1,%2.l),%0";
+      else
+       return "lea %c2(%1),%0";
+#else /* not SGS */
+#ifdef MOTOROLA
+      if (GET_CODE (operands[2]) == REG)
+       return "lea (%1,%2.l),%0";
+      else
+       return "lea (%c2,%1),%0";
+#else /* not MOTOROLA (MIT syntax) */
+      if (GET_CODE (operands[2]) == REG)
+       return "lea %1@(0,%2:l),%0";
+      else
+       return "lea %1@(%c2),%0";
+#endif /* not MOTOROLA */
+#endif /* not SGS */
+    }
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+#ifndef NO_ADDSUB_Q
+      if (INTVAL (operands[2]) > 0
+         && INTVAL (operands[2]) <= 8)
+       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 "subq%.l %2,%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%.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%.l %#8,%0\\;subq%.l %2,%0";
+           }
+       }
+#endif
+      if (ADDRESS_REG_P (operands[0])
+         && INTVAL (operands[2]) >= -0x8000
+         && 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";
+}
 \f
 /* Store in cc_status the expressions that the condition codes will
    describe after execution of an instruction whose pattern is EXP.
@@ -1335,8 +2136,10 @@ notice_update_cc (exp, insn)
       {
       case PLUS: case MINUS: case MULT:
       case DIV: case UDIV: case MOD: case UMOD: case NEG:
-      case ASHIFT: case LSHIFT: case ASHIFTRT: case LSHIFTRT:
+#if 0 /* These instructions always clear the overflow bit */
+      case ASHIFT: case ASHIFTRT: case LSHIFTRT:
       case ROTATE: case ROTATERT:
+#endif
        if (GET_MODE (cc_status.value2) != VOIDmode)
          cc_status.flags |= CC_NO_OVERFLOW;
        break;
@@ -1467,11 +2270,11 @@ init_68881_table ()
   REAL_VALUE_TYPE r;
   enum machine_mode mode;
 
-  mode = DFmode;
+  mode = SFmode;
   for (i = 0; i < 7; i++)
     {
       if (i == 6)
-        mode = SFmode;
+        mode = DFmode;
       r = REAL_VALUE_ATOF (strings_68881[i], mode);
       values_68881[i] = r;
     }
@@ -1486,6 +2289,10 @@ standard_68881_constant_p (x)
   int i;
   enum machine_mode mode;
 
+#ifdef NO_ASM_FMOVECR
+  return 0;
+#endif
+
   /* fmovecr must be emulated on the 68040, so it shouldn't be used at all. */
   if (TARGET_68040)
     return 0;
@@ -1748,7 +2555,7 @@ standard_sun_fpa_constant_p (x)
    '@' for a reference to the top word on the stack:
        sp@, (sp) or (%sp) depending on the style of syntax.
    '#' for an immediate operand prefix (# in MIT and Motorola syntax
-       but & in SGS syntax).
+       but & in SGS syntax, $ in CRDS/UNOS syntax).
    '!' for the cc register (used in an `and to cc' insn).
    '$' for the letter `s' in an op code, but only on the 68040.
    '&' for the letter `d' in an op code, but only on the 68040.
@@ -1777,7 +2584,7 @@ print_operand (file, op, letter)
 
   if (letter == '.')
     {
-#ifdef MOTOROLA
+#if defined (MOTOROLA) && !defined (CRDS)
       asm_fprintf (file, ".");
 #endif
     }
@@ -1833,6 +2640,7 @@ print_operand (file, op, letter)
     }
   else if (GET_CODE (op) == REG)
     {
+#ifdef SUPPORT_SUN_FPA
       if (REGNO (op) < 16
          && (letter == 'y' || letter == 'x')
          && GET_MODE (op) == DFmode)
@@ -1841,8 +2649,14 @@ print_operand (file, op, letter)
                   reg_names[REGNO (op)+1]);
        }
       else
+#endif
        {
-         fprintf (file, "%s", reg_names[REGNO (op)]);
+         if (letter == 'R')
+           /* Print out the second register name of a register pair.
+              I.e., R (6) => 7.  */
+           fputs (reg_names[REGNO (op) + 1], file);
+         else
+           fputs (reg_names[REGNO (op)], file);
        }
     }
   else if (GET_CODE (op) == MEM)
@@ -1854,7 +2668,11 @@ print_operand (file, op, letter)
               && INTVAL (XEXP (op, 0)) < 0x8000
               && INTVAL (XEXP (op, 0)) >= -0x8000))
        {
+#ifdef MOTOROLA
+         fprintf (file, ".l");
+#else
          fprintf (file, ":l");
+#endif
        }
     }
 #ifdef SUPPORT_SUN_FPA
@@ -1908,6 +2726,9 @@ print_operand (file, op, letter)
    define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other
    string, as necessary.  This is accomplished via the ASM_OUTPUT_CASE_END
    macro.  See m68k/sgs.h for an example; for versions without the bug.
+   Some assemblers refuse all the above solutions.  The workaround is to
+   emit "K(pc,d0.l*2)" with K being a small constant known to give the
+   right behaviour.
 
    They also do not like things like "pea 1.w", so we simple leave off
    the .w on small constants. 
@@ -1917,6 +2738,21 @@ print_operand (file, op, letter)
    offset is output in word mode (eg movel a5@(_foo:w), a0).  When generating
    -fPIC code the offset is output in long mode (eg movel a5@(_foo:l), a0) */
 
+#ifndef ASM_OUTPUT_CASE_FETCH
+#ifdef MOTOROLA
+#ifdef SGS
+#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
+       asm_fprintf (file, "%LLD%d(%Rpc,%s.", labelno, regname)
+#else
+#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
+       asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.", labelno, labelno, regname)
+#endif
+#else
+#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
+       asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:", labelno, labelno, regname)
+#endif
+#endif /* ASM_OUTPUT_CASE_FETCH */
+
 void
 print_operand_address (file, addr)
      FILE *file;
@@ -2053,43 +2889,17 @@ print_operand_address (file, addr)
              }
            if (GET_CODE (ireg) == SIGN_EXTEND)
              {
-#ifdef MOTOROLA
-#ifdef SGS
-               asm_fprintf (file, "%LLD%d(%Rpc,%s.w",
-                            CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                            reg_names[REGNO (XEXP (ireg, 0))]);
-#else
-               asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.w",
-                            CODE_LABEL_NUMBER (XEXP (addr, 0)),
+               ASM_OUTPUT_CASE_FETCH (file,
                             CODE_LABEL_NUMBER (XEXP (addr, 0)),
                             reg_names[REGNO (XEXP (ireg, 0))]);
-#endif
-#else
-               asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:w",
-                            CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                            CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                            reg_names[REGNO (XEXP (ireg, 0))]);
-#endif
+               fprintf (file, "w");
              }
            else
              {
-#ifdef MOTOROLA
-#ifdef SGS
-               asm_fprintf (file, "%LLD%d(%Rpc,%s.l",
+               ASM_OUTPUT_CASE_FETCH (file,
                             CODE_LABEL_NUMBER (XEXP (addr, 0)),
                             reg_names[REGNO (ireg)]);
-#else
-               asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l",
-                            CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                            CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                            reg_names[REGNO (ireg)]);
-#endif
-#else
-               asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l",
-                            CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                            CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                            reg_names[REGNO (ireg)]);
-#endif
+               fprintf (file, "l");
              }
            if (scale != 1)
              {
@@ -2105,24 +2915,10 @@ print_operand_address (file, addr)
        if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF
            && ! (flag_pic && breg == pic_offset_table_rtx))
          {
-#ifdef MOTOROLA
-#ifdef SGS
-           asm_fprintf (file, "%LLD%d(%Rpc,%s.l",
+           ASM_OUTPUT_CASE_FETCH (file,
                         CODE_LABEL_NUMBER (XEXP (addr, 0)),
                         reg_names[REGNO (breg)]);
-#else
-           asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l",
-                        CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                        CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                        reg_names[REGNO (breg)]);
-#endif
-#else
-           asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l",
-                        CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                        CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                        reg_names[REGNO (breg)]);
-#endif
-           putc (')', file);
+           fprintf (file, "l)");
            break;
          }
        if (ireg != 0 || breg != 0)
@@ -2198,23 +2994,10 @@ print_operand_address (file, addr)
        else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF
                 && ! (flag_pic && reg1 == pic_offset_table_rtx))       
          {
-#ifdef MOTOROLA
-#ifdef SGS
-           asm_fprintf (file, "%LLD%d(%Rpc,%s.l)",
+           ASM_OUTPUT_CASE_FETCH (file,
                         CODE_LABEL_NUMBER (XEXP (addr, 0)),
                         reg_names[REGNO (reg1)]);
-#else
-           asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l)",
-                        CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                        CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                        reg_names[REGNO (reg1)]);
-#endif
-#else
-           asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l)",
-                        CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                        CODE_LABEL_NUMBER (XEXP (addr, 0)),
-                        reg_names[REGNO (reg1)]);
-#endif
+           fprintf (file, "l)");
            break;
          }
        /* FALL-THROUGH (is this really what we want? */
@@ -2300,3 +3083,36 @@ strict_low_part_peephole_ok (mode, first_insn, target)
 
   return 0;
 }
+
+/* Accept integer operands in the range 0..0xffffffff.  We have to check the
+   range carefully since this predicate is used in DImode contexts.  Also, we
+   need some extra crud to make it work when hosted on 64-bit machines.  */
+
+int
+const_uint32_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+#if HOST_BITS_PER_WIDE_INT > 32
+  /* All allowed constants will fit a CONST_INT.  */
+  return (GET_CODE (op) == CONST_INT
+         && (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL));
+#else
+  return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0)
+         || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0));
+#endif
+}
+
+/* Accept integer operands in the range -0x80000000..0x7fffffff.  We have
+   to check the range carefully since this predicate is used in DImode
+   contexts.  */
+
+int
+const_sint32_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  /* All allowed constants will fit a CONST_INT.  */
+  return (GET_CODE (op) == CONST_INT
+         && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff));
+}