OSDN Git Service

* config/m68k/m68k.c (split_di): New.
authorzippel <zippel@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 18 Feb 2007 01:30:58 +0000 (01:30 +0000)
committerzippel <zippel@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 18 Feb 2007 01:30:58 +0000 (01:30 +0000)
* config/m68k/m68k-protos.h: Declare split_di.
* config/m68k/m68k.md (extendsidi2*,ashldi3*,ashrdi3*,lshrdi3*):
  Improve predicate handling and split constant shifts.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@122084 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/m68k/m68k-protos.h
gcc/config/m68k/m68k.c
gcc/config/m68k/m68k.md

index f0be35c..8e10471 100644 (file)
@@ -1,5 +1,12 @@
 2007-02-18  Roman Zippel <zippel@linux-m68k.org>
 
+       * config/m68k/m68k.c (split_di): New.
+       * config/m68k/m68k-protos.h: Declare split_di.
+       * config/m68k/m68k.md (extendsidi2*,ashldi3*,ashrdi3*,lshrdi3*):
+         Improve predicate handling and split constant shifts.
+
+2007-02-18  Roman Zippel <zippel@linux-m68k.org>
+
        * config/m68k/m68k.md (extv,extzv,insv): disable dynamic
        parameter for register bitfield operations, general predicates
        cleanup
index 14a9e2c..85a5376 100644 (file)
@@ -22,6 +22,9 @@ Boston, MA 02110-1301, USA.  */
 
 #ifdef RTX_CODE
 extern HOST_WIDE_INT m68k_initial_elimination_offset (int from, int to);
+
+extern void split_di (rtx[], int, rtx[], rtx[]);
+
 extern bool valid_mov3q_const (HOST_WIDE_INT);
 extern const char *output_move_simode (rtx *);
 extern const char *output_move_himode (rtx *);
index 225baed..08ebbd2 100644 (file)
@@ -2722,6 +2722,38 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
   return 0;
 }
 
+/* Split one or more DImode RTL references into pairs of SImode
+   references.  The RTL can be REG, offsettable MEM, integer constant, or
+   CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
+   split and "num" is its length.  lo_half and hi_half are output arrays
+   that parallel "operands".  */
+
+void
+split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
+{
+  while (num--)
+    {
+      rtx op = operands[num];
+
+      /* simplify_subreg refuses to split volatile memory addresses,
+        but we still have to handle it.  */
+      if (GET_CODE (op) == MEM)
+       {
+         lo_half[num] = adjust_address (op, SImode, 4);
+         hi_half[num] = adjust_address (op, SImode, 0);
+       }
+      else
+       {
+         lo_half[num] = simplify_gen_subreg (SImode, op,
+                                             GET_MODE (op) == VOIDmode
+                                             ? DImode : GET_MODE (op), 4);
+         hi_half[num] = simplify_gen_subreg (SImode, op,
+                                             GET_MODE (op) == VOIDmode
+                                             ? DImode : GET_MODE (op), 0);
+       }
+    }
+}
+
 /* Return a REG that occurs in ADDR with coefficient 1.
    ADDR can be effectively incremented by incrementing REG.  */
 
index 285abf1..42e5f21 100644 (file)
 })
 
 (define_insn "extendsidi2"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d")
-       (sign_extend:DI
-        (match_operand:SI 1 "general_operand" "rm")))]
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (sign_extend:DI (match_operand:SI 1 "nonimmediate_src_operand" "rm")))]
   ""
 {
   CC_STATUS_INIT;
-  operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
   if (TARGET_68020 || TARGET_COLDFIRE)
-    return "move%.l %1,%2\;smi %0\;extb%.l %0";
+    return "move%.l %1,%R0\;smi %0\;extb%.l %0";
+  else
+    return "move%.l %1,%R0\;smi %0\;ext%.w %0\;ext%.l %0";
+})
+
+(define_insn "*extendsidi2_mem"
+  [(set (match_operand:DI 0 "memory_operand" "=o,<")
+       (sign_extend:DI (match_operand:SI 1 "nonimmediate_src_operand" "rm,rm")))
+   (clobber (match_scratch:SI 2 "=d,d"))]
+   ""
+{
+  CC_STATUS_INIT;
+  operands[3] = adjust_address (operands[0], SImode,
+                               which_alternative == 0 ? 4 : 0);
+  operands[0] = adjust_address (operands[0], SImode, 0);
+  if (TARGET_68020 || TARGET_COLDFIRE)
+    return "move%.l %1,%3\;smi %2\;extb%.l %2\;move%.l %2,%0";
   else
-    return "move%.l %1,%2\;smi %0\;ext%.w %0\;ext%.l %0";
+    return "move%.l %1,%3\;smi %2\;ext%.w %2\;ext%.l %2\;move%.l %2,%0";
 })
 
 ;; Special case when one can avoid register clobbering, copy and test
     return "move%.w %1,%0\;sub%.l %R0,%R0";
 })
 
-(define_insn "ashldi_const32"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
-       (ashift:DI (match_operand:DI 1 "general_operand" "ro")
-                    (const_int 32)))]
+(define_insn "*ashldi3_const1"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (ashift:DI (match_operand:DI 1 "register_operand" "0")
+                  (const_int 1)))]
+  "!TARGET_COLDFIRE"
+  "add%.l %R0,%R0\;addx%.l %0,%0")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashift:DI (match_operand:DI 1 "register_operand" "")
+                  (const_int 2)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 0)
+       (ashift:DI (match_dup 1) (const_int 1)))
+   (set (match_dup 0)
+       (ashift:DI (match_dup 0) (const_int 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashift:DI (match_operand:DI 1 "register_operand" "")
+                  (const_int 3)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 0)
+       (ashift:DI (match_dup 1) (const_int 2)))
+   (set (match_dup 0)
+       (ashift:DI (match_dup 0) (const_int 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashift:DI (match_operand:DI 1 "register_operand" "")
+                  (const_int 8)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 2)
+       (rotate:SI (match_dup 2) (const_int 8)))
+   (set (match_dup 3)
+       (rotate:SI (match_dup 3) (const_int 8)))
+   (set (strict_low_part (subreg:QI (match_dup 0) 3))
+       (subreg:QI (match_dup 0) 7))
+   (set (strict_low_part (subreg:QI (match_dup 0) 7))
+       (const_int 0))]
+{
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashift:DI (match_operand:DI 1 "register_operand" "")
+                  (const_int 16)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 2)
+       (rotate:SI (match_dup 2) (const_int 16)))
+   (set (match_dup 3)
+       (rotate:SI (match_dup 3) (const_int 16)))
+   (set (strict_low_part (subreg:HI (match_dup 0) 2))
+       (subreg:HI (match_dup 0) 6))
+   (set (strict_low_part (subreg:HI (match_dup 0) 6))
+       (const_int 0))]
+{
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "pre_dec_operand" "")
+       (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "")
+                  (const_int 32)))]
+  "reload_completed"
+  [(set (match_dup 0) (const_int 0))
+   (set (match_dup 0) (match_dup 1))]
+{
+  operands[0] = adjust_address(operands[0], SImode, 0);
+  operands[1] = gen_lowpart(SImode, operands[1]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "post_inc_operand" "")
+       (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "")
+                  (const_int 32)))]
+  "reload_completed"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 0) (const_int 0))]
+{
+  operands[0] = adjust_address(operands[0], SImode, 0);
+  operands[1] = gen_lowpart(SImode, operands[1]);
+})
+
+(define_insn_and_split "*ashldi3_const32"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=ro<>")
+       (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "ro")
+                  (const_int 32)))]
   ""
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 4) (match_dup 3))
+   (set (match_dup 2) (const_int 0))]
+  "split_di(operands, 2, operands + 2, operands + 4);")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashift:DI (match_operand:DI 1 "register_operand" "")
+                  (match_operand 2 "const_int_operand" "")))]
+  "reload_completed && !TARGET_COLDFIRE
+   && INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 40"
+  [(set (match_dup 4) (ashift:SI (match_dup 4) (match_dup 2)))
+   (set (match_dup 3) (match_dup 4))
+   (set (match_dup 4) (const_int 0))]
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) - 32);
+  operands[3] = gen_highpart (SImode, operands[0]);
+  operands[4] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashift:DI (match_operand:DI 1 "register_operand" "")
+                  (const_int 48)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 2)
+       (rotate:SI (match_dup 2) (const_int 16)))
+   (set (match_dup 3) (const_int 0))
+   (set (strict_low_part (subreg:HI (match_dup 0) 2))
+       (const_int 0))]
 {
-  CC_STATUS_INIT;
-  if (GET_CODE (operands[1]) == REG)
-    operands[3] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
-  else
-    operands[3] = adjust_address (operands[1], SImode, 4);
-  if (GET_CODE (operands[0]) == REG)
-    operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
-  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
-    return "clr%.l %0\;move%.l %3,%0";
-  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
-    return "move%.l %3,%0\;clr%.l %0";
-  else
-    operands[2] = adjust_address (operands[0], SImode, 4);
-  if (ADDRESS_REG_P (operands[2]))
-    return "move%.l %3,%0\;sub%.l %2,%2";
-  else
-    return "move%.l %3,%0\;clr%.l %2";
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_lowpart (SImode, operands[0]);
 })
 
-;; The predicate below must be general_operand, because ashldi3 allows that
-(define_insn "ashldi_const"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d")
-       (ashift:DI (match_operand:DI 1 "general_operand" "0")
-                    (match_operand 2 "const_int_operand" "n")))]
-  "(!TARGET_COLDFIRE
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashift:DI (match_operand:DI 1 "register_operand" "")
+                  (match_operand 2 "const_int_operand" "")))]
+  "reload_completed && !TARGET_COLDFIRE
+   && INTVAL (operands[2]) > 40 && INTVAL (operands[2]) <= 63"
+  [(set (match_dup 3) (match_dup 2))
+   (set (match_dup 4) (ashift:SI (match_dup 4) (match_dup 3)))
+   (set (match_dup 3) (match_dup 4))
+   (set (match_dup 4) (const_int 0))]
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) - 32);
+  operands[3] = gen_highpart (SImode, operands[0]);
+  operands[4] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_insn "*ashldi3"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (ashift:DI (match_operand:DI 1 "register_operand" "0")
+                  (match_operand 2 "const_int_operand" "n")))]
+  "!TARGET_COLDFIRE
     && ((INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 3)
        || INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16
-       || (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63)))"
-{
-  operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
-  if (INTVAL (operands[2]) == 1)
-    return "add%.l %1,%1\;addx%.l %0,%0";
-  else if (INTVAL (operands[2]) == 8)
-    return "rol%.l #8,%1\;rol%.l #8,%0\;move%.b %1,%0\;clr%.b %1";
-  else if (INTVAL (operands[2]) == 16)
-    return "swap %1\;swap %0\;move%.w %1,%0\;clr%.w %1";
-  else if (INTVAL (operands[2]) == 48)
-    return "mov%.l %1,%0\;swap %0\;clr%.l %1\;clr%.w %0";
-  else if (INTVAL (operands[2]) == 2)
-    return "add%.l %1,%1\;addx%.l %0,%0\;add%.l %1,%1\;addx%.l %0,%0";
-  else if (INTVAL (operands[2]) == 3)
-    return "add%.l %1,%1\;addx%.l %0,%0\;add%.l %1,%1\;addx%.l %0,%0\;add%.l %1,%1\;addx%.l %0,%0";
-  else /* 32 < INTVAL (operands[2]) <= 63 */
-    {
-      operands[2] = GEN_INT (INTVAL (operands[2]) - 32);
-      output_asm_insn (INTVAL (operands[2]) <= 8 ? "asl%.l %2,%1" :
-                       "moveq %2,%0\;asl%.l %0,%1", operands);
-      return "mov%.l %1,%0\;moveq #0,%1";
-    }
-})
+       || (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63))"
+  "#")
 
 (define_expand "ashldi3"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (ashift:DI (match_operand:DI 1 "general_operand" "")
-                    (match_operand 2 "const_int_operand" "")))]
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashift:DI (match_operand:DI 1 "register_operand" "")
+                  (match_operand 2 "const_int_operand" "")))]
   "!TARGET_COLDFIRE"
-  "
 {
   /* ???  This is a named pattern like this is not allowed to FAIL based
      on its operands.  */
          && INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16
          && (INTVAL (operands[2]) < 32 || INTVAL (operands[2]) > 63)))
     FAIL;
-} ")
+})
 
 ;; On most 68k models, this makes faster code in a special case.
 
   return "move%.l %1,%0";
 })
 
-(define_insn "ashrdi_const32"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,o,<")
-       (ashiftrt:DI (match_operand:DI 1 "general_operand" "ro,ro,ro")
+(define_insn "*ashrdi3_const1"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
+                    (const_int 1)))]
+  "!TARGET_COLDFIRE"
+{
+  operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
+  return "asr%.l #1,%0\;roxr%.l #1,%1";
+})
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 2)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 0)
+       (ashiftrt:DI (match_dup 1) (const_int 1)))
+   (set (match_dup 0)
+       (ashiftrt:DI (match_dup 0) (const_int 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 3)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 0)
+       (ashiftrt:DI (match_dup 1) (const_int 2)))
+   (set (match_dup 0)
+       (ashiftrt:DI (match_dup 0) (const_int 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 8)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (strict_low_part (subreg:QI (match_dup 0) 7))
+       (subreg:QI (match_dup 0) 3))
+   (set (match_dup 2)
+       (ashiftrt:SI (match_dup 2) (const_int 8)))
+   (set (match_dup 3)
+       (rotatert:SI (match_dup 3) (const_int 8)))]
+{
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 16)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (strict_low_part (subreg:HI (match_dup 0) 6))
+       (subreg:HI (match_dup 0) 2))
+   (set (match_dup 2)
+       (rotate:SI (match_dup 2) (const_int 16)))
+   (set (match_dup 3)
+       (rotate:SI (match_dup 3) (const_int 16)))
+   (set (match_dup 2)
+       (sign_extend:SI (subreg:HI (match_dup 2) 2)))]
+{
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_insn "*ashrdi_const32"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (ashiftrt:DI (match_operand:DI 1 "nonimmediate_src_operand" "ro")
+                    (const_int 32)))]
+  ""
+{
+  CC_STATUS_INIT;
+  if (TARGET_68020)
+    return "move%.l %1,%R0\;smi %0\;extb%.l %0";
+  else
+    return "move%.l %1,%R0\;smi %0\;ext%.w %0\;ext%.l %0";
+})
+
+(define_insn "*ashrdi_const32_mem"
+  [(set (match_operand:DI 0 "memory_operand" "=o,<")
+       (ashiftrt:DI (match_operand:DI 1 "nonimmediate_src_operand" "ro,ro")
                     (const_int 32)))
-   (clobber (match_scratch:SI 2 "=X,d,d"))]
+   (clobber (match_scratch:SI 2 "=d,d"))]
   ""
 {
   CC_STATUS_INIT;
-  if (which_alternative == 0)
-    {
-      operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
-      if (TARGET_68020)
-       return "move%.l %1,%2\;smi %0\;extb%.l %0";
-      else
-       return "move%.l %1,%2\;smi %0\;ext%.w %0\;ext%.l %0";
-    }
+  operands[3] = adjust_address (operands[0], SImode,
+                               which_alternative == 0 ? 4 : 0);
+  operands[0] = adjust_address (operands[0], SImode, 0);
+  if (TARGET_68020 || TARGET_COLDFIRE)
+    return "move%.l %1,%3\;smi %2\;extb%.l %2\;move%.l %2,%0";
   else
-    {
-      if (which_alternative == 2)
-       operands[3] = operands[0];
-      else if (which_alternative == 1)
-       operands[3] = adjust_address (operands[0], SImode, 4);
-      if (TARGET_68020)
-       return "move%.l %1,%3\;smi %2\;extb%.l %2\;move%.l %2,%0";
-      else
-       return "move%.l %1,%3\;smi %2\;ext%.w %2\;ext%.l %2\;move%.l %2,%0";
-    }
+    return "move%.l %1,%3\;smi %2\;ext%.w %2\;ext%.l %2\;move%.l %2,%0";
 })
 
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 63)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 3)
+       (ashiftrt:SI (match_dup 3) (const_int 31)))
+   (set (match_dup 2)
+       (match_dup 3))]
+  "split_di(operands, 1, operands + 2, operands + 3);")
+
 ;; The predicate below must be general_operand, because ashrdi3 allows that
 (define_insn "ashrdi_const"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d")
-       (ashiftrt:DI (match_operand:DI 1 "general_operand" "0")
-                    (match_operand 2 "const_int_operand" "n")))
-   (clobber (match_scratch:SI 3 "=X"))]
-  "(!TARGET_COLDFIRE 
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
+                    (match_operand 2 "const_int_operand" "n")))]
+  "!TARGET_COLDFIRE
     && ((INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 3)
        || INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16
        || INTVAL (operands[2]) == 31
-       || (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63)))"
+       || (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63))"
 {
   operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
-  if (INTVAL (operands[2]) == 63)
-    return "add%.l %0,%0\;subx%.l %0,%0\;move%.l %0,%1";
   CC_STATUS_INIT;
-  if (INTVAL (operands[2]) == 1)
-    return "asr%.l #1,%0\;roxr%.l #1,%1";
-  else if (INTVAL (operands[2]) == 8)
-    return "move%.b %0,%1\;asr%.l #8,%0\;ror%.l #8,%1";
-  else if (INTVAL (operands[2]) == 16)
-    return "move%.w %0,%1\;swap %0\;ext%.l %0\;swap %1";
-  else if (INTVAL (operands[2]) == 48)
+  if (INTVAL (operands[2]) == 48)
     return "swap %0\;ext%.l %0\;move%.l %0,%1\;smi %0\;ext%.w %0";
-  else if (INTVAL (operands[2]) == 31)
+  if (INTVAL (operands[2]) == 31)
     return "add%.l %1,%1\;addx%.l %0,%0\;move%.l %0,%1\;subx%.l %0,%0";
-  else if (INTVAL (operands[2]) == 2)
-    return "asr%.l #1,%0\;roxr%.l #1,%1\;asr%.l #1,%0\;roxr%.l #1,%1";
-  else if (INTVAL (operands[2]) == 3)
-    return "asr%.l #1,%0\;roxr%.l #1,%1\;asr%.l #1,%0\;roxr%.l #1,%1\;asr%.l #1,%0\;roxr%.l #1,%1";
-  else /* 32 < INTVAL (operands[2]) <= 63 */
+  if (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63)
     {
       operands[2] = GEN_INT (INTVAL (operands[2]) - 32);
       output_asm_insn (INTVAL (operands[2]) <= 8 ? "asr%.l %2,%0" :
       return INTVAL (operands[2]) >= 15 ? "ext%.w %d0" :
             TARGET_68020 ? "extb%.l %0" : "ext%.w %0\;ext%.l %0";
     }
+  return "#";
 })
 
 (define_expand "ashrdi3"
-  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
-                  (ashiftrt:DI (match_operand:DI 1 "general_operand" "")
-                               (match_operand 2 "const_int_operand" "")))
-             (clobber (match_scratch:SI 3 ""))])]
+  [(set (match_operand:DI 0 "register_operand" "")
+       (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (match_operand 2 "const_int_operand" "")))]
   "!TARGET_COLDFIRE"
-  "
 {
   /* ???  This is a named pattern like this is not allowed to FAIL based
      on its operands.  */
          && INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16
          && (INTVAL (operands[2]) < 31 || INTVAL (operands[2]) > 63)))
     FAIL;
-  operands[3] = gen_rtx_SCRATCH (SImode);
-} ")
+})
 
 ;; On all 68k models, this makes faster code in a special case.
 
   return "move%.l %1,%0";
 })
 
-(define_insn "lshrdi_const32"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=ro,<,>")
-       (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro,ro,ro")
+(define_insn "*lshrdi3_const1"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
+                    (const_int 1)))]
+  "!TARGET_COLDFIRE"
+  "lsr%.l #1,%0\;roxr%.l #1,%R0")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 2)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 0)
+       (lshiftrt:DI (match_dup 1) (const_int 1)))
+   (set (match_dup 0)
+       (lshiftrt:DI (match_dup 0) (const_int 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 3)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (match_dup 0)
+       (lshiftrt:DI (match_dup 1) (const_int 2)))
+   (set (match_dup 0)
+       (lshiftrt:DI (match_dup 0) (const_int 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 8)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (strict_low_part (subreg:QI (match_dup 0) 7))
+       (subreg:QI (match_dup 0) 3))
+   (set (match_dup 2)
+       (lshiftrt:SI (match_dup 2) (const_int 8)))
+   (set (match_dup 3)
+       (rotatert:SI (match_dup 3) (const_int 8)))]
+{
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 16)))]
+  "reload_completed && !TARGET_COLDFIRE"
+  [(set (strict_low_part (subreg:HI (match_dup 0) 6))
+       (subreg:HI (match_dup 0) 2))
+   (set (strict_low_part (subreg:HI (match_dup 0) 2))
+       (const_int 0))
+   (set (match_dup 3)
+       (rotate:SI (match_dup 3) (const_int 16)))
+   (set (match_dup 2)
+       (rotate:SI (match_dup 2) (const_int 16)))]
+{
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "pre_dec_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "")
+                    (const_int 32)))]
+  "reload_completed"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 0) (const_int 0))]
+{
+  operands[0] = adjust_address(operands[0], SImode, 0);
+  operands[1] = gen_highpart(SImode, operands[1]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "post_inc_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "")
+                    (const_int 32)))]
+  "reload_completed"
+  [(set (match_dup 0) (const_int 0))
+   (set (match_dup 0) (match_dup 1))]
+{
+  operands[0] = adjust_address(operands[0], SImode, 0);
+  operands[1] = gen_highpart(SImode, operands[1]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "")
+                    (const_int 32)))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 5))
+   (set (match_dup 4) (const_int 0))]
+  "split_di(operands, 2, operands + 2, operands + 4);")
+
+(define_insn "*lshrdi_const32"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=ro<>")
+       (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro")
                     (const_int 32)))]
   ""
+  "#")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (match_operand 2 "const_int_operand" "")))]
+  "reload_completed && !TARGET_COLDFIRE
+   && INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 40"
+  [(set (match_dup 3) (lshiftrt:SI (match_dup 3) (match_dup 2)))
+   (set (match_dup 4) (match_dup 3))
+   (set (match_dup 3) (const_int 0))]
 {
-  CC_STATUS_INIT;
-  if (which_alternative == 1)
-    return "move%.l %1,%0\;clr%.l %0";
-  if (which_alternative == 2)
-    return "clr%.l %0\;move%.l %1,%0";
-  if (GET_CODE (operands[0]) == REG)
-    operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
-  else
-    operands[2] = adjust_address (operands[0], SImode, 4);
-  if (GET_CODE (operands[1]) == REG)
-    operands[3] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
-  else
-    operands[3] = adjust_address (operands[1], SImode, 4);
-  if (ADDRESS_REG_P (operands[0]))
-    return "move%.l %1,%2\;sub%.l %0,%0";
-  else
-    return "move%.l %1,%2\;clr%.l %0";
+  operands[2] = GEN_INT (INTVAL (operands[2]) - 32);
+  operands[3] = gen_highpart (SImode, operands[0]);
+  operands[4] = gen_lowpart (SImode, operands[0]);
 })
 
-;; The predicate below must be general_operand, because lshrdi3 allows that
-(define_insn "lshrdi_const"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=d")
-       (lshiftrt:DI (match_operand:DI 1 "general_operand" "0")
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (const_int 48)))]
+  "reload_completed"
+  [(set (match_dup 3) (match_dup 2))
+   (set (strict_low_part (subreg:HI (match_dup 0) 6))
+       (const_int 0))
+   (set (match_dup 2) (const_int 0))
+   (set (match_dup 3)
+       (rotate:SI (match_dup 3) (const_int 16)))]
+{
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
+                    (match_operand 2 "const_int_operand" "")))]
+  "reload_completed && !TARGET_COLDFIRE
+   && INTVAL (operands[2]) > 40 && INTVAL (operands[2]) <= 62"
+  [(set (match_dup 4) (match_dup 2))
+   (set (match_dup 3) (lshiftrt:SI (match_dup 3) (match_dup 4)))
+   (set (match_dup 4) (match_dup 3))
+   (set (match_dup 3) (const_int 0))]
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) - 32);
+  operands[3] = gen_highpart (SImode, operands[0]);
+  operands[4] = gen_lowpart (SImode, operands[0]);
+})
+
+(define_insn "*lshrdi_const63"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
+                    (const_int 63)))]
+  ""
+  "add%.l %0,%0\;clr%.l %0\;clr%.l %R1\;addx%.l %R1,%R1")
+
+(define_insn "*lshrdi3_const"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
                     (match_operand 2 "const_int_operand" "n")))]
   "(!TARGET_COLDFIRE
-    && ((INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 3)
+    && ((INTVAL (operands[2]) >= 2 && INTVAL (operands[2]) <= 3)
         || INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16
         || (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63)))"
-{
-  operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
-  if (INTVAL (operands[2]) == 63)
-    return "add%.l %0,%0\;clr%.l %0\;clr%.l %1\;addx%.l %1,%1";
-  CC_STATUS_INIT;
-  if (INTVAL (operands[2]) == 1)
-    return "lsr%.l #1,%0\;roxr%.l #1,%1";
-  else if (INTVAL (operands[2]) == 8)
-    return "move%.b %0,%1\;lsr%.l #8,%0\;ror%.l #8,%1";
-  else if (INTVAL (operands[2]) == 16)
-    return "move%.w %0,%1\;clr%.w %0\;swap %1\;swap %0";
-  else if (INTVAL (operands[2]) == 48)
-    return "move%.l %0,%1\;clr%.w %1\;clr%.l %0\;swap %1";
-  else if (INTVAL (operands[2]) == 2)
-    return "lsr%.l #1,%0\;roxr%.l #1,%1\;lsr%.l #1,%0\;roxr%.l #1,%1";
-  else if (INTVAL (operands[2]) == 3)
-    return "lsr%.l #1,%0\;roxr%.l #1,%1\;lsr%.l #1,%0\;roxr%.l #1,%1\;lsr%.l #1,%0\;roxr%.l #1,%1";
-  else /* 32 < INTVAL (operands[2]) <= 63 */
-    {
-      operands[2] = GEN_INT (INTVAL (operands[2]) - 32);
-      output_asm_insn (INTVAL (operands[2]) <= 8 ? "lsr%.l %2,%0" :
-                       "moveq %2,%1\;lsr%.l %1,%0", operands);
-      return "mov%.l %0,%1\;moveq #0,%0";
-    }
-})
+  "#")
 
 (define_expand "lshrdi3"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (lshiftrt:DI (match_operand:DI 1 "general_operand" "")
+  [(set (match_operand:DI 0 "register_operand" "")
+       (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
                     (match_operand 2 "const_int_operand" "")))]
   "!TARGET_COLDFIRE"
 {