OSDN Git Service

(output_addsi3): New function. From addsi3 pattern.
[pf3gnuchains/gcc-fork.git] / gcc / config / m68k / m68k.c
index 0051c97..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,16 +53,91 @@ 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 
    all PIC references were deleted from the current function.  That would 
    save an address register */
    
+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
@@ -92,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",
@@ -115,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);
@@ -126,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, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
+             asm_fprintf (stream, "\tsubq.w %OI8,%Rsp\n\tsubq.w %OI%d,%Rsp\n",
+                          fsize + 4);
 #else
-         asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
+             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));
+#else
+             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
@@ -157,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])
       {
@@ -182,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)
@@ -207,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)
     {
@@ -269,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)
@@ -281,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
@@ -292,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)
@@ -309,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
@@ -336,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",
@@ -377,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);
@@ -414,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);
@@ -453,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",
@@ -493,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);
+             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
@@ -539,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;
@@ -559,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:
@@ -676,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;
@@ -748,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
@@ -841,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
-  if (DATA_REG_P (operands[0])
-      && GET_CODE (operands[1]) == CONST_INT
+    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
+       }
+      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";
 }
 
 
@@ -884,7 +1586,9 @@ output_move_double (operands)
     } optype0, optype1;
   rtx latehalf[2];
   rtx middlehalf[2];
+  rtx xops[2];
   rtx addreg0 = 0, addreg1 = 0;
+  int dest_overlapped_low = 0;
   int size = GET_MODE_SIZE (GET_MODE (operands[0]));
 
   middlehalf[0] = 0;
@@ -1064,7 +1768,69 @@ 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
+     emit the move late-half first.  Otherwise, compute the MEM address
+     into the upper part of N and use that as a pointer to the memory
+     operand.  */
+  if (optype0 == REGOP
+      && (optype1 == OFFSOP || optype1 == MEMOP))
+    {
+      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.
+            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 %a1,%0", xops);
+         if( GET_MODE (operands[1]) == XFmode )
+           {
+             operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);
+             middlehalf[1] = adj_offsettable_operand (operands[1], size-8);
+             latehalf[1] = adj_offsettable_operand (operands[1], size-4);
+           }
+         else
+           {
+             operands[1] = gen_rtx (MEM, DImode, latehalf[0]);
+             latehalf[1] = adj_offsettable_operand (operands[1], size-4);
+           }
+       }
+      else if (size == 12
+              && reg_overlap_mentioned_p (middlehalf[0],
+                                          XEXP (operands[1], 0)))
+       {
+         /* 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 ();
+
+         /* Only the middle reg conflicts; simply put it last. */
+         output_asm_insn (singlemove_string (operands), operands);
+         output_asm_insn (singlemove_string (latehalf), latehalf);
+         output_asm_insn (singlemove_string (middlehalf), middlehalf);
+         return "";
+       }
+      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;
+    }
 
   /* If one or both operands autodecrementing,
      do the two words, high-numbered first.  */
@@ -1077,22 +1843,23 @@ output_move_double (operands)
   if (optype0 == PUSHOP || optype1 == PUSHOP
       || (optype0 == REGOP && optype1 == REGOP
          && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
-             || REGNO (operands[0]) == REGNO (latehalf[1]))))
+             || REGNO (operands[0]) == REGNO (latehalf[1])))
+      || dest_overlapped_low)
     {
       /* Make any unoffsettable addresses point at high-numbered word.  */
       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.  */
@@ -1100,17 +1867,17 @@ output_move_double (operands)
 
       /* 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.  */
@@ -1125,18 +1892,18 @@ output_move_double (operands)
   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);
@@ -1145,16 +1912,16 @@ output_move_double (operands)
   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 "";
@@ -1184,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.
@@ -1278,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;
@@ -1410,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;
     }
@@ -1429,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;
@@ -1691,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.
@@ -1720,7 +2584,7 @@ print_operand (file, op, letter)
 
   if (letter == '.')
     {
-#ifdef MOTOROLA
+#if defined (MOTOROLA) && !defined (CRDS)
       asm_fprintf (file, ".");
 #endif
     }
@@ -1776,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)
@@ -1784,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)
@@ -1797,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
@@ -1851,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. 
@@ -1860,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;
@@ -1996,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)),
-                            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)),
+               ASM_OUTPUT_CASE_FETCH (file,
                             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",
-                            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)),
+               ASM_OUTPUT_CASE_FETCH (file,
                             CODE_LABEL_NUMBER (XEXP (addr, 0)),
                             reg_names[REGNO (ireg)]);
-#endif
+               fprintf (file, "l");
              }
            if (scale != 1)
              {
@@ -2048,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",
-                        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)),
+           ASM_OUTPUT_CASE_FETCH (file,
                         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)
@@ -2141,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)",
-                        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)),
+           ASM_OUTPUT_CASE_FETCH (file,
                         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? */
@@ -2243,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));
+}