mn10300.h (RETURN_ADDR_RTX): Define.
authorJeff Law <law@gcc.gnu.org>
Tue, 8 Apr 1997 18:41:49 +0000 (12:41 -0600)
committerJeff Law <law@gcc.gnu.org>
Tue, 8 Apr 1997 18:41:49 +0000 (12:41 -0600)
        * mn10300.h (RETURN_ADDR_RTX): Define.

        * mn10300.c (count_tst_insns): New function.
        (expand_prologue): Load zero into data and/or address registers
        if any are free and the function has optimizable tst insns.
        (output_tst): If a suitable register is known to have the
        value zero, use it instead of searching for a suitable register.
        * mn10300.h (zero_dreg, zero_areg): Declare.
        (FRAME_POINTER_NEEDED): Frame pointers are not needed if the
        outgoing argument size is zero.
        * mn10300.md (movXX): Optimize loading zero i        register if possible.  Optimize loading a DF/DI mode value
        into an address register from a constant memory address.
        (addsi3): Provide alternative which doesn't require a matching
        inout operand.
        (return): Optimize consecutive return instructions.

From-SVN: r13845

gcc/config/mn10300/mn10300.c
gcc/config/mn10300/mn10300.h
gcc/config/mn10300/mn10300.md

index 1ae2a27..10e7ae3 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for Matsushita MN10300 series
-   Copyright (C) 1996 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
    Contributed by Jeff Law (law@cygnus.com).
 
 This file is part of GNU CC.
@@ -36,6 +36,26 @@ Boston, MA 02111-1307, USA.  */
 #include "tree.h"
 #include "obstack.h"
 
+/* Global registers known to hold the value zero.
+
+   Normally we'd depend on CSE and combine to put zero into a
+   register and re-use it.
+
+   However, on the mn10x00 processors we implicitly use the constant
+   zero in tst instructions, so we might be able to do better by
+   loading the value into a register in the prologue, then re-useing
+   that register throughout the function.
+
+   We could perform similar optimizations for other constants, but with
+   gcse due soon, it doesn't seem worth the effort.
+
+   These variables hold a rtx for a register known to hold the value
+   zero throughout the entire function, or NULL if no register of
+   the appropriate class has such a value throughout the life of the
+   function.  */
+rtx zero_dreg;
+rtx zero_areg;
+
 void
 asm_file_start (file)
      FILE *file;
@@ -339,15 +359,124 @@ can_use_return_insn ()
          && !frame_pointer_needed);
 }
 
+/* Count the number of tst insns which compare a data or address
+   register with zero.  */
+static void 
+count_tst_insns (dreg_countp, areg_countp)
+     int *dreg_countp;
+     int *areg_countp;
+{
+  rtx insn;
+
+  /* Assume no tst insns exist.  */
+  *dreg_countp = 0;
+  *areg_countp = 0;
+
+  /* If not optimizing, then quit now.  */
+  if (!optimize)
+    return;
+
+  /* Walk through all the insns.  */
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      rtx pat;
+
+      /* Ignore anything that is not a normal INSN.  */
+      if (GET_CODE (insn) != INSN)
+       continue;
+
+      /* Ignore anything that isn't a SET.  */
+      pat = PATTERN (insn);
+      if (GET_CODE (pat) != SET)
+       continue;
+
+      /* Check for a tst insn.  */
+      if (SET_DEST (pat) == cc0_rtx
+         && GET_CODE (SET_SRC (pat)) == REG)
+       {
+         if (REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == DATA_REGS)
+           (*dreg_countp)++;
+    
+         if (REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == ADDRESS_REGS)
+           (*areg_countp)++;
+       }
+
+      /* Setting an address register to zero can also be optimized,
+        so count it just like a tst insn.  */
+      if (GET_CODE (SET_DEST (pat)) == REG
+         && GET_CODE (SET_SRC (pat)) == CONST_INT
+         && INTVAL (SET_SRC (pat)) == 0
+         && REGNO_REG_CLASS (REGNO (SET_DEST (pat))) == ADDRESS_REGS)
+       (*areg_countp)++;
+    }
+}
+
 void
 expand_prologue ()
 {
   unsigned int size;
 
-  /* We have to end the current sequence so leaf_function_p will
-     work.  We then start a new sequence to hold the prologue/epilogue.  */
+  /* We have to end the current sequence so leaf_function_p and
+     count_tst_insns will work.  We then start a new sequence to
+     hold the prologue/epilogue.  */
   end_sequence ();
 
+  /* Determine if it is profitable to put the value zero into a register
+     for the entire function.  If so, set ZERO_DREG and ZERO_AREG.  */
+  if (regs_ever_live[2] || regs_ever_live[3]
+       || regs_ever_live[6] || regs_ever_live[7]
+       || frame_pointer_needed)
+    {
+      int dreg_count, areg_count;
+
+      /* Get a count of the number of tst insns which use address and
+        data registers.  */
+      count_tst_insns (&dreg_count, &areg_count);
+
+      /* If there's more than one tst insn using a data register, then
+        this optimization is a win.  */
+      if (dreg_count > 1
+         && (!regs_ever_live[2] || !regs_ever_live[3]))
+       {
+         if (!regs_ever_live[2])
+           {
+             regs_ever_live[2] = 1;
+             zero_dreg = gen_rtx (REG, SImode, 2);
+           }
+         else
+           {
+             regs_ever_live[3] = 1;
+             zero_dreg = gen_rtx (REG, SImode, 3);
+           }
+       }
+      else
+       zero_dreg = NULL_RTX;
+
+      /* If there's more than two tst insns using an address register,
+        then this optimization is a win.  */
+      if (areg_count > 2
+         && (!regs_ever_live[6] || !regs_ever_live[7]))
+       {
+         if (!regs_ever_live[6])
+           {
+             regs_ever_live[6] = 1;
+             zero_areg = gen_rtx (REG, SImode, 6);
+           }
+         else
+           {
+             regs_ever_live[7] = 1;
+             zero_areg = gen_rtx (REG, SImode, 7);
+           }
+       }
+      else
+       zero_areg = NULL_RTX;
+    }
+  else
+    {
+      zero_dreg = NULL_RTX;
+      zero_areg = NULL_RTX;
+    }
+
   /* SIZE includes the fixed stack space needed for function calls.  */
   size = get_frame_size () + (!leaf_function_p () ? 12 : 0);
 
@@ -384,6 +513,13 @@ expand_prologue ()
     emit_insn (gen_addsi3 (stack_pointer_rtx,
                           stack_pointer_rtx,
                           GEN_INT (-size)));
+
+  /* Load zeros into registers as needed.  */
+  if (zero_dreg)
+    emit_move_insn (zero_dreg, const0_rtx);
+
+  if (zero_areg)
+    emit_move_insn (zero_areg, const0_rtx);
 }
 
 void
@@ -713,14 +849,36 @@ char *
 output_tst (operand, insn)
      rtx operand, insn;
 {
-  
   rtx temp;
   int past_call = 0;
 
+  /* If we have a data register which is known to be zero throughout
+     the function, then use it instead of doing a search.  */
+  if (zero_dreg && REGNO_REG_CLASS (REGNO (operand)) == DATA_REGS)
+    {
+      rtx xoperands[2];
+      xoperands[0] = operand;
+      xoperands[1] = zero_dreg;
+
+      output_asm_insn ("cmp %1,%0", xoperands);
+      return "";
+    }
+
+  /* Similarly for address registers.  */
+  if (zero_areg && REGNO_REG_CLASS (REGNO (operand)) == ADDRESS_REGS)
+    {
+      rtx xoperands[2];
+      xoperands[0] = operand;
+      xoperands[1] = zero_areg;
+
+      output_asm_insn ("cmp %1,%0", xoperands);
+      return "";
+    }
+
   /* We can save a byte if we can find a register which has the value
      zero in it.  */
   temp = PREV_INSN (insn);
-  while (temp)
+  while (optimize && temp)
     {
       rtx set;
 
@@ -759,7 +917,8 @@ output_tst (operand, insn)
       if (REG_P (SET_DEST (set))
          && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set)))
          && !reg_set_between_p (SET_DEST (set), temp, insn)
-         && REGNO_REG_CLASS (REGNO (SET_DEST (set))) == DATA_REGS
+         && (REGNO_REG_CLASS (REGNO (SET_DEST (set)))
+             == REGNO_REG_CLASS (REGNO (operand)))
          && REGNO (SET_DEST (set)) != REGNO (operand)
          && (!past_call 
              || !call_used_regs[REGNO (SET_DEST (set))]))
index d850641..c36c6c4 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions of target machine for GNU compiler. 
    Matsushita MN10300 series
-   Copyright (C) 1996 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
    Contributed by Jeff Law (law@cygnus.com).
 
 This file is part of GNU CC.
@@ -37,6 +37,10 @@ Boston, MA 02111-1307, USA.  */
 
 extern int target_flags;
 
+/* Global registers known to hold the value zero.  */
+extern struct rtx_def *zero_dreg;
+extern struct rtx_def *zero_areg;
+
 /* Macros used in the machine description to test the flags.  */
 
 /* Macro to define tables used to set the flags.
@@ -404,8 +408,7 @@ enum reg_class {
   OFFSET = initial_offset (FROM, TO)
 
 #define FRAME_POINTER_REQUIRED \
-  !(leaf_function_p ())
-
+  !(leaf_function_p () || current_function_outgoing_args_size == 0)
 #define CAN_DEBUG_WITHOUT_FP
 
 /* A guess for the MN10300.  */
@@ -562,6 +565,20 @@ extern struct rtx_def *function_arg ();
   emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 0x18)),        \
                 (FNADDR));                                             \
 }
+/* A C expression whose value is RTL representing the value of the return
+   address for the frame COUNT steps up from the current frame.
+
+   On the mn10300, the return address is not at a constant location
+   due to the frame layout.  Luckily, it is at a constant offset from
+   the argument pointer, so we define RETURN_ADDR_RTX to return a
+   MEM using arg_pointer_rtx.  Reload will replace arg_pointer_rtx
+   with a reference to the stack/frame pointer + an appropriate offset.  */
+
+#define RETURN_ADDR_RTX(COUNT, FRAME)   \
+  ((COUNT == 0)                         \
+   ? gen_rtx (MEM, Pmode, arg_pointer_rtx) \
+   : (rtx) 0)
+
 /* Emit code for a call to builtin_saveregs.  We must emit USE insns which
    reference the 2 integer arg registers.
    Ordinarily they are not call used registers, but they are for
index 98f4536..13628ec 100644 (file)
@@ -1,4 +1,4 @@
-;; GCC machine description for Matsushita MN10300
+; GCC machine description for Matsushita MN10300
 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
 
 ;;   Contributed by Jeff Law (law@cygnus.com).
 }")
 
 (define_insn ""
-  [(set (match_operand:QI 0 "general_operand" "=d,a,d,d,a,d,a,d,m")
-       (match_operand:QI 1 "general_operand" "0,0,I,a,d,di,ia,m,d"))]
+  [(set (match_operand:QI 0 "general_operand" "=d,a,d,a,d,a,d,a,d,m")
+       (match_operand:QI 1 "general_operand" "0,0,I,I,a,d,di,ia,m,d"))]
   "register_operand (operands[0], QImode)
    || register_operand (operands[1], QImode)"
-  "@
-  nop
-  nop
-  clr %0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  movbu %1,%0
-  movbu %1,%0"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+    case 1:
+      return \"nop\";
+    case 2:
+      return \"clr %0\";
+    case 3:
+      if (zero_areg)
+       {
+         rtx xoperands[2];
+
+         xoperands[0] = operands[0];
+         xoperands[1] = zero_areg;
+         if (rtx_equal_p (xoperands[0], xoperands[1]))
+           output_asm_insn (\"sub %1,%0\", xoperands);
+         else
+           output_asm_insn (\"mov %1,%0\", xoperands);
+         return \"\";
+       }
+
+      /* FALLTHROUGH */
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+      return \"mov %1,%0\";
+    case 8:
+    case 9:
+      return \"movbu %1,%0\";
+    }
+}"
+  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
 
 ;; movhi
 
 }")
 
 (define_insn ""
-  [(set (match_operand:HI 0 "general_operand" "=d,a,d,d,a,d,a,d,m")
-       (match_operand:HI 1 "general_operand" "0,0,I,a,d,di,ia,m,d"))]
+  [(set (match_operand:HI 0 "general_operand" "=d,a,d,a,d,a,d,a,d,m")
+       (match_operand:HI 1 "general_operand" "0,0,I,I,a,d,di,ia,m,d"))]
   "register_operand (operands[0], HImode)
    || register_operand (operands[1], HImode)"
-  "@
-  nop
-  nop
-  clr %0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  movhu %1,%0
-  movhu %1,%0"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+    case 1:
+      return \"nop\";
+    case 2:
+      return \"clr %0\";
+    case 3:
+      if (zero_areg)
+       {
+         rtx xoperands[2];
+
+         xoperands[0] = operands[0];
+         xoperands[1] = zero_areg;
+         if (rtx_equal_p (xoperands[0], xoperands[1]))
+           output_asm_insn (\"sub %1,%0\", xoperands);
+         else
+           output_asm_insn (\"mov %1,%0\", xoperands);
+         return \"\";
+       }
+
+      /* FALLTHROUGH */
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+      return \"mov %1,%0\";
+    case 8:
+    case 9:
+      return \"movhu %1,%0\";
+    }
+}"
+  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
 
 ;; movsi and helpers
 
 }")
 
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a,aR,x")
-       (match_operand:SI 1 "general_operand" "0,0,I,d,a,d,a,dim,aim,dim,aim,x,aR"))]
+  [(set (match_operand:SI 0 "general_operand"
+                               "=d,a,d,a,dm,dm,am,am,d,d,a,a,aR,x")
+       (match_operand:SI 1 "general_operand"
+                               "0,0,I,I,d,a,d,a,dim,aim,dim,aim,x,aR"))]
   "register_operand (operands[0], SImode)
    || register_operand (operands[1], SImode)"
-  "@
-  nop
-  nop
-  clr %0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0
-  mov %1,%0"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+    case 1:
+      return \"nop\";
+    case 2:
+      return \"clr %0\";
+    case 3:
+      if (zero_areg)
+       {
+         rtx xoperands[2];
+
+         xoperands[0] = operands[0];
+         xoperands[1] = zero_areg;
+         if (rtx_equal_p (xoperands[0], xoperands[1]))
+           output_asm_insn (\"sub %1,%0\", xoperands);
+         else
+           output_asm_insn (\"mov %1,%0\", xoperands);
+         return \"\";
+       }
+
+      /* FALLTHROUGH */
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+      return \"mov %1,%0\";
+    }
+}"
+  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
 
 (define_expand "movsf"
   [(set (match_operand:SF 0 "general_operand" "")
 }")
 
 (define_insn ""
-  [(set (match_operand:SF 0 "general_operand" "=d,a,d,dam,da")
-       (match_operand:SF 1 "general_operand" "0,0,G,da,daim"))]
+  [(set (match_operand:SF 0 "general_operand" "=d,a,d,a,dam,da")
+       (match_operand:SF 1 "general_operand" "0,0,G,G,da,daim"))]
   "register_operand (operands[0], SFmode)
    || register_operand (operands[1], SFmode)"
-  "@
-  nop
-  nop
-  clr %0
-  mov %1,%0
-  mov %1,%0"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit")])
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+    case 1:
+      return \"nop\";
+    case 2:
+      return \"clr %0\";
+    case 3:
+      if (zero_areg)
+       {
+         rtx xoperands[2];
+
+         xoperands[0] = operands[0];
+         xoperands[1] = zero_areg;
+         if (rtx_equal_p (xoperands[0], xoperands[1]))
+           output_asm_insn (\"sub %1,%0\", xoperands);
+         else
+           output_asm_insn (\"mov %1,%0\", xoperands);
+         return \"\";
+       }
+
+      /* FALLTHROUGH */
+    case 4:
+    case 5:
+      return \"mov %1,%0\";
+    }
+}"
+  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit")])
 
 (define_expand "movdi"
   [(set (match_operand:DI 0 "general_operand" "")
 }")
 
 (define_insn ""
-  [(set (match_operand:DI 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a")
-       (match_operand:DI 1 "general_operand" "0,0,I,d,a,d,a,dim,aim,dim,aim"))]
+  [(set (match_operand:DI 0 "general_operand"
+                               "=d,a,d,a,dm,dm,am,am,d,d,a,a")
+       (match_operand:DI 1 "general_operand"
+                               "0,0,I,I,d,a,d,a,dim,aim,dim,aim"))]
   "register_operand (operands[0], DImode)
    || register_operand (operands[1], DImode)"
   "*
        return \"clr %L0\;clr %H0\";
 
       case 3:
+         {
+           rtx xoperands[2];
+
+           xoperands[0] = operands[0];
+           xoperands[1] = zero_areg ? zero_areg : operands[1];
+           if (rtx_equal_p (xoperands[0], xoperands[1]))
+             output_asm_insn (\"sub %L1,%L0\;mov %L0,%H0\", xoperands);
+           else
+             output_asm_insn (\"mov %1,%L0\;mov %L0,%H0\", xoperands);
+           return \"\";
+         }
       case 4:
       case 5:
       case 6:
       case 8:
       case 9:
       case 10:
+      case 11:
        if (GET_CODE (operands[1]) == CONST_INT)
          {
            val[0] = INTVAL (operands[1]);
              return \"mov %L1,%L0\;mov %H1,%H0\";
              
          }
+       else if (GET_CODE (operands[1]) == MEM
+                && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
+                && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
+         {
+           rtx xoperands[2];
+
+           xoperands[0] = operands[0];
+           xoperands[1] = XEXP (operands[1], 0);
+
+           output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
+                            xoperands);
+           return \"\";
+         }
        else
          {
            if ((GET_CODE (operands[1]) == CONST_INT
                 || GET_CODE (operands[1]) == CONST_DOUBLE)
-               && val[0] == 0
-               && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-             output_asm_insn (\"clr %L0\", operands);
+               && val[0] == 0)
+             {
+               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
+                 output_asm_insn (\"clr %L0\", operands);
+               else if (zero_areg)
+                 {
+                   rtx xoperands[2];
+
+                   xoperands[0] = operands[0];
+                   xoperands[1] = zero_areg;
+                   if (rtx_equal_p (xoperands[0], xoperands[1]))
+                     output_asm_insn (\"sub %L0,%L0\", xoperands);
+                   else
+                     output_asm_insn (\"mov %1,%L0\", xoperands);
+                 }
+               else
+                 output_asm_insn (\"mov %L1,%L0\", operands);
+             }
            else
              output_asm_insn (\"mov %L1,%L0\", operands);
 
            if ((GET_CODE (operands[1]) == CONST_INT
                 || GET_CODE (operands[1]) == CONST_DOUBLE)
-               && val[1] == 0
-               && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-             output_asm_insn (\"clr %H0\", operands);
+               && val[1] == 0)
+             {
+               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
+                 output_asm_insn (\"clr %H0\", operands);
+               else if (zero_areg)
+                 {
+                   rtx xoperands[2];
+
+                   xoperands[0] = operands[0];
+                   xoperands[1] = zero_areg;
+                   if (rtx_equal_p (xoperands[0], xoperands[1]))
+                     output_asm_insn (\"sub %H0,%H0\", xoperands);
+                   else
+                     output_asm_insn (\"mov %1,%H0\", xoperands);
+                 }
+               else
+                 output_asm_insn (\"mov %H1,%H0\", operands);
+             }
+           else if ((GET_CODE (operands[1]) == CONST_INT
+                     || GET_CODE (operands[1]) == CONST_DOUBLE)
+                    && val[0] == val[1])
+             output_asm_insn (\"mov %L0,%H0\", operands);
            else
              output_asm_insn (\"mov %H1,%H0\", operands);
            return \"\";
          }
     }
 }"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
 
 (define_expand "movdf"
   [(set (match_operand:DF 0 "general_operand" "")
 }")
 
 (define_insn ""
-  [(set (match_operand:DF 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a")
-       (match_operand:DF 1 "general_operand" "0,0,G,d,a,d,a,dim,aim,dim,aim"))]
+  [(set (match_operand:DF 0 "general_operand"
+                               "=d,a,d,a,dm,dm,am,am,d,d,a,a")
+       (match_operand:DF 1 "general_operand"
+                               "0,0,G,G,d,a,d,a,dim,aim,dim,aim"))]
   "register_operand (operands[0], DFmode)
    || register_operand (operands[1], DFmode)"
   "*
        return \"clr %L0\;clr %H0\";
 
       case 3:
+         {
+           rtx xoperands[2];
+
+           xoperands[0] = operands[0];
+           xoperands[1] = zero_areg ? zero_areg : operands[1];
+           if (rtx_equal_p (xoperands[0], xoperands[1]))
+             output_asm_insn (\"sub %L1,%L0\;mov %L0,%H0\", xoperands);
+           else
+             output_asm_insn (\"mov %1,%L0\;mov %L0,%H0\", xoperands);
+           return \"\";
+         }
       case 4:
       case 5:
       case 6:
       case 8:
       case 9:
       case 10:
+      case 11:
        if (GET_CODE (operands[1]) == CONST_INT)
          {
            val[0] = INTVAL (operands[1]);
              return \"mov %L1,%L0\;mov %H1,%H0\";
              
          }
+       else if (GET_CODE (operands[1]) == MEM
+                && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
+                && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
+         {
+           rtx xoperands[2];
+
+           xoperands[0] = operands[0];
+           xoperands[1] = XEXP (operands[1], 0);
+
+           output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
+                            xoperands);
+           return \"\";
+         }
        else
          {
            if ((GET_CODE (operands[1]) == CONST_INT
                 || GET_CODE (operands[1]) == CONST_DOUBLE)
-               && val[0] == 0
-               && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-             output_asm_insn (\"clr %L0\", operands);
+               && val[0] == 0)
+             {
+               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
+                 output_asm_insn (\"clr %L0\", operands);
+               else if (zero_areg)
+                 {
+                   rtx xoperands[2];
+
+                   xoperands[0] = operands[0];
+                   xoperands[1] = zero_areg;
+                   if (rtx_equal_p (xoperands[0], xoperands[1]))
+                     output_asm_insn (\"sub %L0,%L0\", xoperands);
+                   else
+                     output_asm_insn (\"mov %1,%L0\", xoperands);
+                 }
+               else
+                 output_asm_insn (\"mov %L1,%L0\", operands);
+             }
            else
              output_asm_insn (\"mov %L1,%L0\", operands);
 
            if ((GET_CODE (operands[1]) == CONST_INT
                 || GET_CODE (operands[1]) == CONST_DOUBLE)
-               && val[1] == 0
-               && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-             output_asm_insn (\"clr %H0\", operands);
+               && val[1] == 0)
+             {
+               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
+                 output_asm_insn (\"clr %H0\", operands);
+               else if (zero_areg)
+                 {
+                   rtx xoperands[2];
+
+                   xoperands[0] = operands[0];
+                   xoperands[1] = zero_areg;
+                   if (rtx_equal_p (xoperands[0], xoperands[1]))
+                     output_asm_insn (\"sub %H0,%H0\", xoperands);
+                   else
+                     output_asm_insn (\"mov %1,%H0\", xoperands);
+                 }
+               else
+                 output_asm_insn (\"mov %H1,%H0\", operands);
+             }
+           else if ((GET_CODE (operands[1]) == CONST_INT
+                     || GET_CODE (operands[1]) == CONST_DOUBLE)
+                    && val[0] == val[1])
+             output_asm_insn (\"mov %L0,%H0\", operands);
            else
              output_asm_insn (\"mov %H1,%H0\", operands);
            return \"\";
          }
     }
 }"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
   
 
 \f
 }")
 
 (define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=d,a,a,da,x")
-       (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0")
-                (match_operand:SI 2 "nonmemory_operand" "J,J,L,dai,i")))]
+  [(set (match_operand:SI 0 "register_operand" "=d,a,a,da,x,!&da")
+       (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,da")
+                (match_operand:SI 2 "nonmemory_operand" "J,J,L,dai,i,da")))]
   ""
   "@
   inc %0
   inc %0
   inc4 %0
   add %2,%0
-  add %2,%0"
-  [(set_attr "cc" "set_zn_c0,none_0hit,none_0hit,set_zn_c0,none_0hit")])
+  add %2,%0
+  mov %2,%0\;add %1,%0"
+  [(set_attr "cc" "set_zn_c0,none_0hit,none_0hit,set_zn_c0,none_0hit,none_0hit")])
 
 (define_expand "adddi3"
   [(set (reg:DI 0) (match_operand:DI 1 "register_operand" ""))
 (define_insn "return"
   [(return)]
   "can_use_return_insn ()"
-  "rets"
+  "*
+{
+  rtx next = next_active_insn (insn);
+
+  if (next
+      && GET_CODE (next) == JUMP_INSN
+      && GET_CODE (PATTERN (next)) == RETURN)
+    return \"\";
+  else
+    return \"rets\";
+}"
   [(set_attr "cc" "clobber")])
 
 ;; Try to combine consecutive updates of the stack pointer (or any