OSDN Git Service

* config/mcore/mcore-protos.h (mcore_r15_operand_p): Declare.
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 12 Sep 2003 09:57:11 +0000 (09:57 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 12 Sep 2003 09:57:11 +0000 (09:57 +0000)
(mcore_secondary_reload_class): Declare.
(mcore_output_inline_const_forced): Remove.
* config/mcore/mcore.md (movsi): Remove the code that forced
non-inlineable constants into a register if the target was r15
or the stack pointer.  Remove constant restrictions from the main
define_insn.  Remove r <- I, r <- M and r <- N alternatives in favor
of an r <- P alternative.  Remove fallback define_insn for reload.
(movhi, movqi): Use gen_lowpart rather than gen_SUBREG.  Remove reload
define_insn.  Use mcore_output_move in the remaining define_insn.
Adjust condition and constraints in the way as for movsi.
(movdi): Always split unacceptable constants into two.  Use
simplify_gen_subreg instead of operand_subword{,_force}.
* config/mcore/mcore.c (mcore_output_inline_const_forced): Remove.
(mcore_output_move): Support HImode and QImode moves as well.
(mcore_m15_operand_p): New function.
(mcore_reload_class): Use it to detect cases where LRW_REGS are better.
(mcore_secondary_reload_class): New function.
* config/mcore/mcore.h (SECONDARY_RELOAD_CLASS): Redefine in
terms of mcore_secondary_reload_class.

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

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

index 885a40f..6a17614 100644 (file)
@@ -1,3 +1,26 @@
+2003-09-12  Richard Sandiford  <rsandifo@redhat.com>
+
+       * config/mcore/mcore-protos.h (mcore_r15_operand_p): Declare.
+       (mcore_secondary_reload_class): Declare.
+       (mcore_output_inline_const_forced): Remove.
+       * config/mcore/mcore.md (movsi): Remove the code that forced
+       non-inlineable constants into a register if the target was r15
+       or the stack pointer.  Remove constant restrictions from the main
+       define_insn.  Remove r <- I, r <- M and r <- N alternatives in favor
+       of an r <- P alternative.  Remove fallback define_insn for reload.
+       (movhi, movqi): Use gen_lowpart rather than gen_SUBREG.  Remove reload
+       define_insn.  Use mcore_output_move in the remaining define_insn.
+       Adjust condition and constraints in the way as for movsi.
+       (movdi): Always split unacceptable constants into two.  Use
+       simplify_gen_subreg instead of operand_subword{,_force}.
+       * config/mcore/mcore.c (mcore_output_inline_const_forced): Remove.
+       (mcore_output_move): Support HImode and QImode moves as well.
+       (mcore_m15_operand_p): New function.
+       (mcore_reload_class): Use it to detect cases where LRW_REGS are better.
+       (mcore_secondary_reload_class): New function.
+       * config/mcore/mcore.h (SECONDARY_RELOAD_CLASS): Redefine in
+       terms of mcore_secondary_reload_class.
+
 2003-09-11  Mike Stump  <mrs@apple.com>
 
        * c-lex.c (fe_file_change): Don't transform to_line with SOURCE_LINE.
index 7152a57..ae9f402 100644 (file)
@@ -65,6 +65,8 @@ extern void         mcore_print_operand_address       PARAMS ((FILE *, rtx));
 extern void         mcore_print_operand                PARAMS ((FILE *, rtx, int));
 extern rtx          mcore_gen_compare_reg              PARAMS ((RTX_CODE));
 extern int          mcore_symbolic_address_p           PARAMS ((rtx));
+extern bool         mcore_r15_operand_p                        PARAMS ((rtx));
+extern enum reg_class mcore_secondary_reload_class     PARAMS ((enum reg_class, enum machine_mode, rtx));
 extern enum reg_class mcore_reload_class               PARAMS ((rtx, enum reg_class));
 extern int          mcore_is_same_reg                  PARAMS ((rtx, rtx));
 extern int          mcore_arith_S_operand              PARAMS ((rtx));
@@ -72,7 +74,6 @@ extern int          mcore_arith_S_operand             PARAMS ((rtx));
 #ifdef HAVE_MACHINE_MODES
 extern const char * mcore_output_move                          PARAMS ((rtx, rtx *, enum machine_mode));
 extern const char * mcore_output_movedouble                    PARAMS ((rtx *, enum machine_mode));
-extern const char * mcore_output_inline_const_forced   PARAMS ((rtx, rtx *, enum machine_mode));
 extern int          mcore_arith_reg_operand            PARAMS ((rtx, enum machine_mode));
 extern int          mcore_general_movsrc_operand       PARAMS ((rtx, enum machine_mode));
 extern int          mcore_general_movdst_operand       PARAMS ((rtx, enum machine_mode));
index 786ce0c..b148c27 100644 (file)
@@ -1270,7 +1270,17 @@ mcore_output_move (insn, operands, mode)
          if (GET_CODE (XEXP (src, 0)) == LABEL_REF) 
             return "lrw\t%0,[%1]";              /* a-R */
          else
-            return "ldw\t%0,%1";                 /* r-m */
+           switch (GET_MODE (src))             /* r-m */
+             {
+             case SImode:
+               return "ldw\t%0,%1";
+             case HImode:
+               return "ld.h\t%0,%1";
+             case QImode:
+               return "ld.b\t%0,%1";
+             default:
+               abort ();
+             }
        }
       else if (GET_CODE (src) == CONST_INT)
        {
@@ -1291,100 +1301,21 @@ mcore_output_move (insn, operands, mode)
        return "lrw\t%0, %1";                /* Into the literal pool.  */
     }
   else if (GET_CODE (dst) == MEM)               /* m-r */
-    return "stw\t%1,%0";
+    switch (GET_MODE (dst))
+      {
+      case SImode:
+       return "stw\t%1,%0";
+      case HImode:
+       return "st.h\t%1,%0";
+      case QImode:
+       return "st.b\t%1,%0";
+      default:
+       abort ();
+      }
 
   abort ();
 }
 
-/* Outputs a constant inline -- regardless of the cost.
-   Useful for things where we've gotten into trouble and think we'd
-   be doing an lrw into r15 (forbidden). This lets us get out of
-   that pickle even after register allocation.  */
-
-const char *
-mcore_output_inline_const_forced (insn, operands, mode)
-     rtx insn ATTRIBUTE_UNUSED;
-     rtx operands[];
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  unsigned long value = INTVAL (operands[1]);
-  unsigned long ovalue = value;
-  struct piece
-  {
-    int low;
-    int shift;
-  }
-  part[6];
-  int i;
-
-  if (mcore_const_ok_for_inline (value))
-    return output_inline_const (SImode, operands);
-
-  for (i = 0; (unsigned) i < ARRAY_SIZE (part); i++)
-    {
-      part[i].shift = 0;
-      part[i].low = (value & 0x1F);
-      value -= part[i].low;
-      
-      if (mcore_const_ok_for_inline (value))
-       break;
-      else
-       {
-         value >>= 5;
-         part[i].shift = 5;
-         
-         while ((value & 1) == 0)
-           {
-             part[i].shift++;
-             value >>= 1;
-           }
-         
-         if (mcore_const_ok_for_inline (value))
-           break;
-       }
-    }
-  
-  /* 5 bits per iteration, a maximum of 5 times == 25 bits and leaves
-     7 bits left in the constant -- which we know we can cover with
-     a movi.  The final value can't be zero otherwise we'd have stopped
-     in the previous iteration.   */
-  if (value == 0 || ! mcore_const_ok_for_inline (value))
-    abort ();
-
-  /* Now, work our way backwards emitting the constant.  */
-
-  /* Emit the value that remains -- it will be nonzero.  */
-  operands[1] = GEN_INT (value);
-  output_asm_insn (output_inline_const (SImode, operands), operands);
-  while (i >= 0)
-    {
-      /* Shift anything we've already loaded.  */
-      if (part[i].shift)
-        {
-         operands[2] = GEN_INT (part[i].shift);
-         output_asm_insn ("lsli       %0,%2", operands);
-         value <<= part[i].shift;
-        }
-      
-      /* Add anything we need into the low 5 bits.  */
-      if (part[i].low != 0)
-        {
-         operands[2] = GEN_INT (part[i].low);
-         output_asm_insn ("addi      %0,%2", operands);
-         value += part[i].low;
-        }
-      
-      i--;
-    }
-  
-  if (value != ovalue)          /* sanity */
-    abort ();
-  /* We've output all the instructions.  */
-  return "";
-}
-
 /* Return a sequence of instructions to perform DI or DF move.
    Since the MCORE cannot move a DI or DF in one instruction, we have
    to take care when we see overlapping source and dest registers.  */
@@ -3064,36 +2995,53 @@ mcore_reorg ()
 }
 
 \f
-/* Return the reg_class to use when reloading the rtx X into the class
-   CLASS.  */
+/* Return true if X is something that can be moved directly into r15.  */
 
-/* If the input is (PLUS REG CONSTANT) representing a stack slot address,
-   then we want to restrict the class to LRW_REGS since that ensures that
-   will be able to safely load the constant.
+bool
+mcore_r15_operand_p (x)
+     rtx x;
+{
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      return mcore_const_ok_for_inline (INTVAL (x));
 
-   If the input is a constant that should be loaded with mvir1, then use
-   ONLYR1_REGS.
+    case REG:
+    case SUBREG:
+    case MEM:
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+/* Implement SECONDARY_RELOAD_CLASS.  If CLASS contains r15, and we can't
+   directly move X into it, use r1-r14 as a temporary.  */
+enum reg_class
+mcore_secondary_reload_class (class, mode, x)
+     enum reg_class class;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     rtx x;
+{
+  if (TEST_HARD_REG_BIT (reg_class_contents[class], 15)
+      && !mcore_r15_operand_p (x))
+    return LRW_REGS;
+  return NO_REGS;
+}
 
-   ??? We don't handle the case where we have (PLUS REG CONSTANT) and
-   the constant should be loaded with mvir1, because that can lead to cases
-   where an instruction needs two ONLYR1_REGS reloads.  */
+/* Return the reg_class to use when reloading the rtx X into the class
+   CLASS.  If X is too complex to move directly into r15, prefer to
+   use LRW_REGS instead.  */
 enum reg_class
 mcore_reload_class (x, class)
      rtx x;
      enum reg_class class;
 {
-  enum reg_class new_class;
-
-  if (class == GENERAL_REGS && CONSTANT_P (x)
-      && (GET_CODE (x) != CONST_INT
-         || (   ! CONST_OK_FOR_I (INTVAL (x))
-             && ! CONST_OK_FOR_M (INTVAL (x))
-             && ! CONST_OK_FOR_N (INTVAL (x)))))
-    new_class = LRW_REGS;
-  else
-    new_class = class;
+  if (reg_class_subset_p (LRW_REGS, class) && !mcore_r15_operand_p (x))
+    return LRW_REGS;
 
-  return new_class;
+  return class;
 }
 
 /* Tell me if a pair of reg/subreg rtx's actually refer to the same
index 7a33f77..6a489e9 100644 (file)
@@ -603,7 +603,8 @@ extern const enum reg_class reg_class_from_letter[];
 /* Return the register class of a scratch register needed to copy IN into
    or out of a register in CLASS in MODE.  If it can be done directly,
    NO_REGS is returned.  */
-#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) NO_REGS
+#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) \
+  mcore_secondary_reload_class (CLASS, MODE, X)
 
 /* Return the maximum number of consecutive registers
    needed to represent mode MODE in a register of class CLASS. 
index bfdd844..700dcb2 100644 (file)
 {
   if (GET_CODE (operands[0]) == MEM)
     operands[1] = force_reg (SImode, operands[1]);
-  else if (CONSTANT_P (operands[1])
-          && (GET_CODE (operands[1]) != CONST_INT
-              || (   ! CONST_OK_FOR_I (INTVAL (operands[1]))
-                  && ! CONST_OK_FOR_M (INTVAL (operands[1]))
-                  && ! CONST_OK_FOR_N (INTVAL (operands[1]))
-                   && (! TARGET_HARDLIT ||
-                       ! mcore_const_ok_for_inline (INTVAL (operands[1])))))
-          && ! reload_completed
-          && ! reload_in_progress
-          && GET_CODE (operands[0]) == REG
-          && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
-          && (REGNO (operands[0]) == STACK_POINTER_REGNUM
-              || REGNO (operands[0]) == LK_REG))
-    operands[1] = force_reg (SImode, operands[1]);
 }")
 
-;;; Must put a/i before r/r so that it will be preferred when the dest is
-;;; a hard register.  Must put a/R before r/m.
-;;; DO WE NEED a/i ANYMORE?
-
 (define_insn ""
-  [(set (match_operand:SI 0 "mcore_general_movdst_operand" "=r,r,r,a,r,r,a,r,m")
-       (match_operand:SI 1 "mcore_general_movsrc_operand"  "I,M,N,i,r,c,R,m,r"))]
+  [(set (match_operand:SI 0 "mcore_general_movdst_operand" "=r,r,a,r,a,r,m")
+       (match_operand:SI 1 "mcore_general_movsrc_operand"  "r,P,i,c,R,m,r"))]
   "(register_operand (operands[0], SImode)
-       || register_operand (operands[1], SImode))
-   && ! (CONSTANT_P (operands[1])
-         && (GET_CODE (operands[1]) != CONST_INT
-            || (   ! CONST_OK_FOR_I (INTVAL (operands[1]))
-                 && ! CONST_OK_FOR_M (INTVAL (operands[1]))
-                 && ! CONST_OK_FOR_N (INTVAL (operands[1]))))
-        && GET_CODE (operands[0]) == REG
-        && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
-         && (REGNO (operands[0]) == STACK_POINTER_REGNUM
-            || REGNO (operands[0]) == LK_REG))"
+    || register_operand (operands[1], SImode))"
   "* return mcore_output_move (insn, operands, SImode);"
-  [(set_attr "type" "move,move,move,move,move,move,load,load,store")])
+  [(set_attr "type" "move,move,move,move,load,load,store")])
 
-;; This is to work around a bug in reload.
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (match_operand:SI 1 "immediate_operand" "i"))]
-  "((reload_in_progress || reload_completed)
-   && CONSTANT_P (operands[1])
-   && GET_CODE (operands[1]) == CONST_INT
-   && ! CONST_OK_FOR_I (INTVAL (operands[1]))
-   && ! CONST_OK_FOR_M (INTVAL (operands[1]))
-   && ! CONST_OK_FOR_N (INTVAL (operands[1]))
-   && GET_CODE (operands[0]) == REG
-   && REGNO (operands[0]) == LK_REG)"
-  "* return mcore_output_inline_const_forced (insn, operands, SImode);"
-  [(set_attr "type" "load")])
-
-;; (define_expand "reload_insi"
-;;   [(parallel [(match_operand:SI 0 "register_operand" "=r")
-;;           (match_operand:SI 1 "general_operand"  "")
-;;           (match_operand:DI 2 "register_operand" "=&r")])]
-;;   ""
-;;   "
-;;   {
-;;     if (CONSTANT_P (operands[1])
-;;        && GET_CODE (operands[1]) == CONST_INT
-;;        && ! CONST_OK_FOR_I (INTVAL (operands[1]))
-;;        && ! CONST_OK_FOR_M (INTVAL (operands[1]))
-;;        && ! CONST_OK_FOR_N (INTVAL (operands[1]))
-;;        && GET_CODE (operands[0]) == REG
-;;        && (REGNO (operands[0]) == STACK_POINTER_REGNUM
-;;           || REGNO (operands[0]) == LK_REG))
-;;       {
-;;         rtx tmp;
-;; 
-;;     if (   REGNO (operands[2]) == REGNO (operands[0])
-;;             || REGNO (operands[2]) == STACK_POINTER_REGNUM
-;;         || REGNO (operands[2]) == LK_REG)
-;;           tmp = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
-;;     else
-;;           tmp = gen_rtx_REG (SImode, REGNO (operands[2]));
-;;     
-;;         emit_insn (gen_movsi (tmp, operands[1]));
-;;         emit_insn (gen_movsi (operands[0], tmp));
-;;         DONE;
-;;       }
-;;     emit_insn (gen_movsi (operands[0], operands[1]));
-;;     DONE;
-;;   }"
-;; )
-                              
-           
-                              
 ;;
 ;; HImode
 ;;
 
-;;; ??? This isn't guaranteed to work.  It should be more like the SImode
-;;; patterns.
-
 (define_expand "movhi"
   [(set (match_operand:HI 0 "general_operand" "")
        (match_operand:HI 1 "general_operand"  ""))]
     {
       rtx reg = gen_reg_rtx (SImode);
       emit_insn (gen_movsi (reg, operands[1]));
-      operands[1] = gen_rtx (SUBREG, HImode, reg, 0);
+      operands[1] = gen_lowpart (HImode, reg);
     }
 }")
   
 (define_insn ""
-  [(set (match_operand:HI 0 "mcore_general_movdst_operand" "=r,r,r,r,r,r,m")
-       (match_operand:HI 1 "mcore_general_movsrc_operand"  "r,I,M,N,c,m,r"))]
+  [(set (match_operand:HI 0 "mcore_general_movdst_operand" "=r,r,a,r,r,m")
+       (match_operand:HI 1 "mcore_general_movsrc_operand"  "r,P,i,c,m,r"))]
   "(register_operand (operands[0], HImode)
-       || register_operand (operands[1], HImode))
-   && (GET_CODE (operands[1]) != CONST_INT
-       || CONST_OK_FOR_M (INTVAL (operands[1]))
-       || CONST_OK_FOR_N (INTVAL (operands[1]))
-       || CONST_OK_FOR_I (INTVAL (operands[1])))"
-  "@
-       mov     %0,%1
-       movi    %0,%1
-       bgeni   %0,%P1
-       bmaski  %0,%N1
-       mvc     %0
-       ld.h    %0,%1
-       st.h    %1,%0"
-  [(set_attr "type" "move,move,move,move,move,load,store")])
-
-;; Like movhi, but the const_int source can't be synthesized in
-;; a single-instruction.  Fall back to the same things that 
-;; are done for movsi in such cases.  Presumes that we can
-;; modify any parts of the register that we wish.
-
-(define_insn ""
-  [(set (match_operand:HI 0 "mcore_general_movdst_operand" "=r,a")
-       (match_operand:HI 1 "const_int_operand"  "P,i"))]
-  "GET_CODE (operands[1]) == CONST_INT
-    && INTVAL (operands[1]) > 127 && INTVAL (operands[1]) < 65536"
-  "*
-{
-  if (GET_CODE (operands[0])== REG && REGNO (operands[0]) == 15
-      && !mcore_const_ok_for_inline (INTVAL (operands[1])))
-    {
-      /* mcore_output_move would generate lrw r15 -- a forbidden combo */
-      return mcore_output_inline_const_forced (insn, operands, SImode);
-    }
-  else
-    return mcore_output_move (insn, operands, SImode);
-}"
-  [(set_attr "type" "move")])
-
-
-;; if we're still looking around for things to use, here's a last
-;; ditch effort that just calls the move. We only let this happen
-;; if we're in the reload pass.
-;;
-(define_insn ""
-  [(set (match_operand:HI 0 "mcore_general_movdst_operand" "=r,a")
-       (match_operand:HI 1 "const_int_operand"  "P,i"))]
-  "reload_in_progress || reload_completed"
-  "*
-{
-  if (GET_CODE (operands[0])== REG && REGNO (operands[0]) == 15
-      && !mcore_const_ok_for_inline (INTVAL (operands[1])))
-    {
-      /* mcore_output_move would generate lrw r15 -- a forbidden combo */
-      return mcore_output_inline_const_forced (insn, operands, SImode);
-    }
-  else
-    return mcore_output_move (insn, operands, HImode);
-}"
-  [(set_attr "type" "move")])
+    || register_operand (operands[1], HImode))"
+  "* return mcore_output_move (insn, operands, HImode);"
+  [(set_attr "type" "move,move,move,move,load,store")])
 
 ;;
 ;; QImode
     {
       rtx reg = gen_reg_rtx (SImode);
       emit_insn (gen_movsi (reg, operands[1]));
-      operands[1] = gen_rtx (SUBREG, QImode, reg, 0);
+      operands[1] = gen_lowpart (QImode, reg);
     }
 }")
   
 (define_insn ""
-  [(set (match_operand:QI 0 "mcore_general_movdst_operand" "=r,r,r,r,r,r,m")
-       (match_operand:QI 1 "mcore_general_movsrc_operand"  "r,I,M,N,c,m,r"))]
+  [(set (match_operand:QI 0 "mcore_general_movdst_operand" "=r,r,a,r,r,m")
+       (match_operand:QI 1 "mcore_general_movsrc_operand"  "r,P,i,c,m,r"))]
   "(register_operand (operands[0], QImode)
-       || register_operand (operands[1], QImode))
-   && (GET_CODE (operands[1]) != CONST_INT
-       || CONST_OK_FOR_M (INTVAL (operands[1]))
-       || CONST_OK_FOR_N (INTVAL (operands[1]))
-       || CONST_OK_FOR_I (INTVAL (operands[1])))"
-  "@
-       mov     %0,%1
-       movi    %0,%1
-       bgeni   %0,%P1
-       bmaski  %0,%N1
-       mvc     %0
-       ld.b    %0,%1
-       st.b    %1,%0" 
-   [(set_attr "type" "move,move,move,move,move,load,store")])
-
-;; cover the case where the constant is 128..255; this isn't handled
-;; in the above case. We could if we wanted to mess with adding a 
-;; new constraint class like M,N,I.
-(define_insn ""
-  [(set (match_operand:QI 0 "mcore_general_movdst_operand" "=r")
-       (match_operand:QI 1 "const_int_operand"  ""))]
-  "GET_CODE (operands[1]) == CONST_INT
-    && INTVAL (operands[1]) > 127 && INTVAL (operands[1]) < 256"
-  "*
-{
-   /* have a constant in range 128..255; have to do 2 insns; we can
-    * do this with a movi followed by a bseti
-    */
-   operands[2] = GEN_INT (INTVAL (operands[1]) & 0x7f);
-   return \"movi\\t%0,%2\;bseti\\t%0,7\";
-}"
-  [(set_attr "type" "move")])
+    || register_operand (operands[1], QImode))"
+  "* return mcore_output_move (insn, operands, QImode);"
+   [(set_attr "type" "move,move,move,move,load,store")])
 
-;; if we're still looking around for things to use, here's a last
-;; ditch effort that just calls the move. We only let this happen
-;; if we're in the reload pass.
-;;
-(define_insn ""
-  [(set (match_operand:QI 0 "mcore_general_movdst_operand" "=r,a")
-       (match_operand:QI 1 "const_int_operand"  "P,i"))]
-  "(reload_in_progress || reload_completed)"
-  "*
-{
-  if (GET_CODE (operands[0])== REG && REGNO (operands[0]) == 15
-      && ! mcore_const_ok_for_inline (INTVAL (operands[1])))
-    {
-      /* mcore_output_move would generate lrw r15 -- a forbidden combo */
-      return mcore_output_inline_const_forced (insn, operands, SImode);
-    }
-  else
-    return mcore_output_move (insn, operands, QImode);
-}"
-  [(set_attr "type" "move")])
 
 ;; DImode
 
   else if (GET_CODE (operands[1]) == CONST_INT
            && ! CONST_OK_FOR_I (INTVAL (operands[1]))
           && ! CONST_OK_FOR_M (INTVAL (operands[1]))
-          && ! CONST_OK_FOR_N (INTVAL (operands[1]))
-          && ! reload_completed
-          && ! reload_in_progress
-          && GET_CODE (operands[0]) == REG)
+          && ! CONST_OK_FOR_N (INTVAL (operands[1])))
     {
-      emit_move_insn (operand_subword (operands[0], 0, 1, DImode),
-                     operand_subword_force (operands[1], 0, DImode));
-      emit_move_insn (operand_subword (operands[0], 1, 1, DImode),
-                     operand_subword_force (operands[1], 1, DImode));
+      int i;
+      for (i = 0; i < UNITS_PER_WORD * 2; i += UNITS_PER_WORD)
+        emit_move_insn (simplify_gen_subreg (SImode, operands[0], DImode, i),
+                       simplify_gen_subreg (SImode, operands[1], DImode, i));
       DONE;
     }
 }")