(extend{qihi,qisi,hisi}2): Allow unaligned memory as arg 1 and pass to extend_{q...
authorRichard Kenner <kenner@gcc.gnu.org>
Wed, 27 Dec 1995 20:29:50 +0000 (15:29 -0500)
committerRichard Kenner <kenner@gcc.gnu.org>
Wed, 27 Dec 1995 20:29:50 +0000 (15:29 -0500)
(extend{qihi,qisi,hisi}2): Allow unaligned memory as arg 1 and pass to
extend_{q,h}idi2.
(unaligned_extend{q,h}idi): New patterns.
(extend{q,h}idi2): If unaligned memory, call above new patterns.
(ext{q,l,w}h recognizer): Update to proper RTL.
(ext define_split): Comment out for now; wrong and maybe useless.
(unaligned_{load,store}hi): Do similarly to QImode.
(movhi, reload_{in,out}hi): Call unaligned case differently.

From-SVN: r10882

gcc/config/alpha/alpha.md

index 72c54ee..1517ea3 100644 (file)
 
 (define_expand "extendqihi2"
   [(set (match_dup 2)
-       (ashift:DI (match_operand:QI 1 "register_operand" "")
+       (ashift:DI (match_operand:QI 1 "reg_or_unaligned_mem_operand" "")
                   (const_int 56)))
    (set (match_operand:HI 0 "register_operand" "")
        (ashiftrt:DI (match_dup 2)
                     (const_int 56)))]
   ""
   "
-{ operands[0] = gen_lowpart (DImode, operands[0]);
+{
+  /* If we have a MEM (must be unaligned), extend to DImode (which we do
+       specially) and then copy to the result.  */
+  if (GET_CODE (operands[1]) == MEM)
+    {
+      rtx temp = gen_reg_rtx (DImode);
+
+      emit_insn (gen_extendqidi2 (temp, operands[1]));
+      emit_move_insn (operands[0], gen_lowpart (HImode, temp));
+      DONE;
+    }
+
+  operands[0] = gen_lowpart (DImode, operands[0]);
   operands[1] = gen_lowpart (DImode, operands[1]);
   operands[2] = gen_reg_rtx (DImode);
 }")
 
 (define_expand "extendqisi2"
   [(set (match_dup 2)
-       (ashift:DI (match_operand:QI 1 "register_operand" "")
+       (ashift:DI (match_operand:QI 1 "reg_or_unaligned_mem_operand" "")
                   (const_int 56)))
    (set (match_operand:SI 0 "register_operand" "")
        (ashiftrt:DI (match_dup 2)
                     (const_int 56)))]
   ""
   "
-{ operands[0] = gen_lowpart (DImode, operands[0]);
+{
+  /* If we have a MEM (must be unaligned), extend to a DImode form of
+     the result (which we do specially).  */
+  if (GET_CODE (operands[1]) == MEM)
+    {
+      rtx temp = gen_reg_rtx (DImode);
+
+      emit_insn (gen_extendqidi2 (temp, operands[1]));
+      emit_move_insn (operands[0], gen_lowpart (SImode, temp));
+      DONE;
+    }
+
+  operands[0] = gen_lowpart (DImode, operands[0]);
   operands[1] = gen_lowpart (DImode, operands[1]);
   operands[2] = gen_reg_rtx (DImode);
 }")
 
 (define_expand "extendqidi2"
   [(set (match_dup 2)
-       (ashift:DI (match_operand:QI 1 "register_operand" "")
+       (ashift:DI (match_operand:QI 1 "reg_or_unaligned_mem_operand" "")
                   (const_int 56)))
    (set (match_operand:DI 0 "register_operand" "")
        (ashiftrt:DI (match_dup 2)
                     (const_int 56)))]
   ""
   "
-{ operands[1] = gen_lowpart (DImode, operands[1]);
+{ extern rtx get_unaligned_address ();
+  if (GET_CODE (operands[1]) == MEM)
+    {
+      rtx seq
+       = gen_unaligned_extendqidi (operands[0],
+                                   get_unaligned_address (operands[1], 1));
+
+      alpha_set_memflags (seq, operands[1]);
+      emit_insn (seq);
+      DONE;
+    }
+
+  operands[1] = gen_lowpart (DImode, operands[1]);
   operands[2] = gen_reg_rtx (DImode);
 }")
 
 (define_expand "extendhisi2"
   [(set (match_dup 2)
-       (ashift:DI (match_operand:HI 1 "register_operand" "")
+       (ashift:DI (match_operand:HI 1 "reg_or_unaligned_mem_operand" "")
                   (const_int 48)))
    (set (match_operand:SI 0 "register_operand" "")
        (ashiftrt:DI (match_dup 2)
                     (const_int 48)))]
   ""
   "
-{ operands[0] = gen_lowpart (DImode, operands[0]);
+{
+  /* If we have a MEM (must be unaligned), extend to a DImode form of
+     the result (which we do specially).  */
+  if (GET_CODE (operands[1]) == MEM)
+    {
+      rtx temp = gen_reg_rtx (DImode);
+
+      emit_insn (gen_extendhidi2 (temp, operands[1]));
+      emit_move_insn (operands[0], gen_lowpart (SImode, temp));
+      DONE;
+    }
+
+  operands[0] = gen_lowpart (DImode, operands[0]);
   operands[1] = gen_lowpart (DImode, operands[1]);
   operands[2] = gen_reg_rtx (DImode);
 }")
 
 (define_expand "extendhidi2"
   [(set (match_dup 2)
-       (ashift:DI (match_operand:HI 1 "register_operand" "")
+       (ashift:DI (match_operand:HI 1 "reg_or_unaligned_mem_operand" "")
                   (const_int 48)))
    (set (match_operand:DI 0 "register_operand" "")
        (ashiftrt:DI (match_dup 2)
                     (const_int 48)))]
   ""
   "
-{ operands[1] = gen_lowpart (DImode, operands[1]);
+{ extern rtx get_unaligned_address ();
+  if (GET_CODE (operands[1]) == MEM)
+    {
+      rtx seq
+       = gen_unaligned_extendhidi (operands[0],
+                                   get_unaligned_address (operands[1], 2));
+
+      alpha_set_memflags (seq, operands[1]);
+      emit_insn (seq);
+      DONE;
+    }
+
+  operands[1] = gen_lowpart (DImode, operands[1]);
   operands[2] = gen_reg_rtx (DImode);
 }")
 
+;; Here's how we sign extend an unaligned byte and halfword.  Doing this
+;; as a pattern saves one instruction.  The code is similar to that for
+;; the unaligned loads (see below).
+;;
+;; Operand 1 is the address + 1 (+2 for HI), operand 0 is the result.
+(define_expand "unaligned_extendqidi"
+  [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
+   (set (match_dup 3)
+       (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -1))
+                       (const_int -8))))
+   (set (match_dup 4)
+       (ashift:DI (match_dup 3)
+                  (minus:DI (const_int 56)
+                            (ashift:DI
+                             (and:DI (plus:DI (match_dup 2) (const_int -1))
+                                     (const_int 7))
+                             (const_int 3)))))
+   (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+       (ashiftrt:DI (match_dup 4) (const_int 56)))]
+  ""
+  "
+{ operands[2] = gen_reg_rtx (DImode);
+  operands[3] = gen_reg_rtx (DImode);
+  operands[4] = gen_reg_rtx (DImode);
+}")
+
+(define_expand "unaligned_extendhidi"
+  [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
+   (set (match_dup 3)
+       (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -2))
+                       (const_int -8))))
+   (set (match_dup 4)
+       (ashift:DI (match_dup 3)
+                  (minus:DI (const_int 56)
+                            (ashift:DI
+                             (and:DI (plus:DI (match_dup 2) (const_int -1))
+                                     (const_int 7))
+                             (const_int 3)))))
+   (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+       (ashiftrt:DI (match_dup 4) (const_int 48)))]
+  ""
+  "
+{ operands[2] = gen_reg_rtx (DImode);
+  operands[3] = gen_reg_rtx (DImode);
+  operands[4] = gen_reg_rtx (DImode);
+}")
+
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=r")
        (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI
-        (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
-                         (const_int 8)
-                         (ashift:DI
-                          (plus:DI
-                           (match_operand:DI 2 "reg_or_8bit_operand" "rI")
-                           (const_int -1))
-                          (const_int 3)))
-        (const_int 56)))]
+        (match_operand:DI 1 "reg_or_0_operand" "rJ")
+         (minus:DI (const_int 56)
+                   (ashift:DI
+                    (and:DI
+                     (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                              (const_int -1))
+                     (const_int 7))
+                    (const_int 3)))))]
   ""
   "extqh %r1,%2,%0")
 
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI
-        (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
-                         (const_int 16)
-                         (ashift:DI
-                          (plus:DI
-                           (match_operand:DI 2 "reg_or_8bit_operand" "rI")
-                           (const_int -2))
-                          (const_int 3)))
-        (const_int 48)))]
+        (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+                (const_int 2147483647))
+        (minus:DI (const_int 56)
+                   (ashift:DI
+                    (and:DI
+                     (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                              (const_int -1))
+                     (const_int 7))
+                    (const_int 3)))))]
   ""
-  "extwh %r1,%2,%0")
+  "extlh %r1,%2,%0")
 
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI
-        (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
-                         (const_int 32)
-                         (ashift:DI
-                          (plus:DI
-                           (match_operand:DI 2 "reg_or_8bit_operand" "rI")
-                           (const_int -4))
-                          (const_int 3)))
-        (const_int 32)))]
+        (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+                (const_int 65535))
+        (minus:DI (const_int 56)
+                   (ashift:DI
+                    (and:DI
+                     (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                              (const_int -1))
+                     (const_int 7))
+                    (const_int 3)))))]
   ""
-  "extlh %r1,%2,%0")
+  "extwh %r1,%2,%0")
+
+(define_insn ""
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (ashift:DI
+        (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+                (const_int 8))
+        (minus:DI (const_int 56)
+                   (ashift:DI
+                    (and:DI
+                     (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                              (const_int -1))
+                     (const_int 7))
+                    (const_int 3)))))]
+  ""
+  "extbh %r1,%2,%0")
 
 ;; This converts an extXl into an extXh with an appropriate adjustment
 ;; to the address calculation.
 
-(define_split
-  [(set (match_operand:DI 0 "register_operand" "")
-       (ashift:DI (zero_extract:DI (match_operand:DI 1 "register_operand" "")
-                                   (match_operand:DI 2 "mode_width_operand" "")
-                                   (ashift:DI (match_operand:DI 3 "" "")
-                                              (const_int 3)))
-                  (match_operand:DI 4 "const_int_operand" "")))
-   (clobber (match_operand:DI 5 "register_operand" ""))]
-  "INTVAL (operands[4]) == 64 - INTVAL (operands[2])"
-  [(set (match_dup 5) (match_dup 6))
-   (set (match_dup 0)
-       (ashift:DI (zero_extract:DI (match_dup 1) (match_dup 2)
-                                   (ashift:DI (plus:DI (match_dup 5)
-                                                       (match_dup 7))
-                                              (const_int 3)))
-                  (match_dup 4)))]
-  "
-{
-  operands[6] = plus_constant (operands[3], 
-                              INTVAL (operands[2]) / BITS_PER_UNIT);
-  operands[7] = GEN_INT (- INTVAL (operands[2]) / BITS_PER_UNIT);
-}")
+;;(define_split
+;;  [(set (match_operand:DI 0 "register_operand" "")
+;;     (ashift:DI (zero_extract:DI (match_operand:DI 1 "register_operand" "")
+;;                                 (match_operand:DI 2 "mode_width_operand" "")
+;;                                 (ashift:DI (match_operand:DI 3 "" "")
+;;                                            (const_int 3)))
+;;                (match_operand:DI 4 "const_int_operand" "")))
+;;   (clobber (match_operand:DI 5 "register_operand" ""))]
+;;  "INTVAL (operands[4]) == 64 - INTVAL (operands[2])"
+;;  [(set (match_dup 5) (match_dup 6))
+;;   (set (match_dup 0)
+;;     (ashift:DI (zero_extract:DI (match_dup 1) (match_dup 2)
+;;                                 (ashift:DI (plus:DI (match_dup 5)
+;;                                                     (match_dup 7))
+;;                                            (const_int 3)))
+;;                (match_dup 4)))]
+;;  "
+;;{
+;;  operands[6] = plus_constant (operands[3], 
+;;                            INTVAL (operands[2]) / BITS_PER_UNIT);
+;;  operands[7] = GEN_INT (- INTVAL (operands[2]) / BITS_PER_UNIT);
+;;}")
   
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=r")
   ""
   "")
   
-;; Similar for unaligned loads.  For QImode, we use the sequence from the
-;; Alpha Architecture manual.  However, for HImode, we do not.  HImode pointers
-;; are normally aligned to the byte boundary, so an HImode object cannot
-;; cross a longword boundary.  We could use a sequence similar to that for
-;; QImode, but that would fail if the pointer, was, in fact, not aligned.
-;; Instead, we clear bit 1 in the address and do an ldl.  If the low-order
-;; bit was not aligned, this will trap and the trap handler will do what is
-;; needed.
+;; Similar for unaligned loads, where we use the sequence from the
+;; Alpha Architecture manual.
 ;;
-;; Here operand 1 is the address.  Operands 2 and 3 are temporaries, where
+;; Operand 1 is the address.  Operands 2 and 3 are temporaries, where
 ;; operand 3 can overlap the input and output registers.
 
 (define_expand "unaligned_loadqi"
   ""
   "")
 
-;; For this, the address must already be in a register.  We also need two
-;; DImode temporaries, neither of which may overlap the input (and hence the
-;; output, since they might be the same register), but both of which may
-;; be the same.
-
 (define_expand "unaligned_loadhi"
   [(set (match_operand:DI 2 "register_operand" "")
-       (and:DI (match_operand:DI 1 "register_operand" "")
-               (const_int -7)))
+       (mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
+                       (const_int -8))))
    (set (match_operand:DI 3 "register_operand" "")
-       (mem:DI (match_dup 2)))
-   (set (match_operand:DI 4 "register_operand" "")
-       (and:DI (match_dup 1) (const_int -2)))
-   (set (subreg:DI (match_operand:HI 0 "register_operand" "") 0)
-       (zero_extract:DI (match_dup 3)
+       (match_dup 1))
+   (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+       (zero_extract:DI (match_dup 2)
                         (const_int 16)
-                        (ashift:DI (match_dup 4) (const_int 3))))]
+                        (ashift:DI (match_dup 3) (const_int 3))))]
   ""
   "")
-       
+
 ;; Storing an aligned byte or word requires two temporaries.  Operand 0 is the
 ;; aligned SImode MEM.  Operand 1 is the register containing the 
 ;; byte or word to store.  Operand 2 is the number of bits within the word that
                            << INTVAL (operands[2])));
 }")
 
-;; For the unaligned byte case, we use code similar to that in the
-;; Architecture book, but reordered to lower the number of registers
+;; For the unaligned byte and halfword cases, we use code similar to that
+;; in the ;; Architecture book, but reordered to lower the number of registers
 ;; required.  Operand 0 is the address.  Operand 1 is the data to store.
 ;; Operands 2, 3, and 4 are DImode temporaries, where operands 2 and 4 may
 ;; be the same temporary, if desired.  If the address is in a register,
   ""
   "")
 
-;; This is the code for storing into an unaligned short.  It uses the same
-;; trick as loading from an unaligned short.  It needs lots of temporaries.
-;; However, during reload, we only have two registers available.  So we
-;; repeat code so that only two temporaries are available.  During RTL
-;; generation, we can use different pseudos for each temporary and CSE
-;; will remove the redundancies.  During reload, we have to settle with
-;; what we get.  Luckily, unaligned accesses of this kind produced during
-;; reload are quite rare.
-;;
-;; Operand 0 is the address of the memory location.  Operand 1 contains the
-;; data to store.  The rest of the operands are all temporaries, with
-;; various overlap possibilities during reload.  See reload_outhi for
-;; details of this use.
-
 (define_expand "unaligned_storehi"
-  [(set (match_operand:DI 2 "register_operand" "")
-       (match_operand:DI 0 "address_operand" ""))
-   (set (match_operand:DI 3 "register_operand" "")
-       (and:DI (match_dup 2) (const_int -7)))
-   (set (match_operand:DI 4 "register_operand" "")
-       (mem:DI (match_dup 3)))
-   (set (match_operand:DI 10 "register_operand" "")
-       (and:DI (match_dup 2) (const_int -2)))
-   (set (match_operand:DI 5 "register_operand" "")
+  [(set (match_operand:DI 3 "register_operand" "")
+       (mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
+                       (const_int -8))))
+   (set (match_operand:DI 2 "register_operand" "")
+       (match_dup 0))
+   (set (match_dup 3)
        (and:DI (not:DI (ashift:DI (const_int 65535)
-                                  (ashift:DI (match_dup 10) (const_int 3))))
-               (match_dup 4)))
-   (set (match_operand:DI 6 "register_operand" "")
+                                  (ashift:DI (match_dup 2) (const_int 3))))
+               (match_dup 3)))
+   (set (match_operand:DI 4 "register_operand" "")
        (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" ""))
-                  (ashift:DI (match_dup 10) (const_int 3))))
-   (set (match_operand:DI 7 "register_operand" "")
-       (ior:DI (match_dup 5) (match_dup 6)))
-   (set (match_operand:DI 8 "register_operand" "") (match_dup 0))
-   (set (match_operand:DI 9 "register_operand" "")
-       (and:DI (match_dup 8) (const_int -7)))
-   (set (mem:DI (match_dup 9)) (match_dup 7))]
+                  (ashift:DI (match_dup 2) (const_int 3))))
+   (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
+   (set (mem:DI (and:DI (match_dup 0) (const_int -8)))
+       (match_dup 4))]
   ""
   "")
 \f
 
          rtx temp1 = gen_reg_rtx (DImode);
          rtx temp2 = gen_reg_rtx (DImode);
-         rtx seq = gen_unaligned_loadqi (operands[0],
-                                         get_unaligned_address (operands[1]),
-                                         temp1, temp2);
+         rtx seq
+           = gen_unaligned_loadqi (operands[0],
+                                   get_unaligned_address (operands[1], 0),
+                                   temp1, temp2);
 
          alpha_set_memflags (seq, operands[1]);
          emit_insn (seq);
          rtx temp1 = gen_reg_rtx (DImode);
          rtx temp2 = gen_reg_rtx (DImode);
          rtx temp3 = gen_reg_rtx (DImode);
-         rtx seq = gen_unaligned_storeqi (get_unaligned_address (operands[0]),
+         rtx seq
+           = gen_unaligned_storeqi (get_unaligned_address (operands[0], 0),
                                           operands[1], temp1, temp2, temp3);
 
          alpha_set_memflags (seq, operands[0]);
        }
       else
        {
-         rtx addr
-           = force_reg (DImode,
-                        force_operand (get_unaligned_address (operands[1]),
-                                       NULL_RTX));
-         rtx scratch1 = gen_reg_rtx (DImode);
-         rtx scratch2 = gen_reg_rtx (DImode);
-         rtx scratch3 = gen_reg_rtx (DImode);
+         /* Don't pass these as parameters since that makes the generated
+            code depend on parameter evaluation order which will cause
+            bootstrap failures.  */
 
-         rtx seq = gen_unaligned_loadhi (operands[0], addr, scratch1,
-                                         scratch2, scratch3);
+         rtx temp1 = gen_reg_rtx (DImode);
+         rtx temp2 = gen_reg_rtx (DImode);
+         rtx seq
+           = gen_unaligned_loadhi (operands[0],
+                                   get_unaligned_address (operands[1], 0),
+                                   temp1, temp2);
 
          alpha_set_memflags (seq, operands[1]);
          emit_insn (seq);
          rtx temp1 = gen_reg_rtx (DImode);
          rtx temp2 = gen_reg_rtx (DImode);
          rtx temp3 = gen_reg_rtx (DImode);
-         rtx temp4 = gen_reg_rtx (DImode);
-         rtx temp5 = gen_reg_rtx (DImode);
-         rtx temp6 = gen_reg_rtx (DImode);
-         rtx temp7 = gen_reg_rtx (DImode);
-         rtx temp8 = gen_reg_rtx (DImode);
-         rtx temp9 = gen_reg_rtx (DImode);
-
-         rtx seq = gen_unaligned_storehi (get_unaligned_address (operands[0]),
-                                          operands[1], temp1, temp2,temp3,
-                                          temp4, temp5, temp6,temp7,
-                                          temp8, temp9);
+         rtx seq
+           = gen_unaligned_storehi (get_unaligned_address (operands[0], 0),
+                                    operands[1], temp1, temp2, temp3);
 
          alpha_set_memflags (seq, operands[0]);
          emit_insn (seq);
   ""
   "
 { extern rtx get_unaligned_address ();
-  rtx addr = get_unaligned_address (operands[1]);
+  rtx addr = get_unaligned_address (operands[1], 0);
   /* It is possible that one of the registers we got for operands[2]
      might coincide with that of operands[0] (which is why we made
      it TImode).  Pick the other one to use as our scratch.  */
   ""
   "
 { extern rtx get_unaligned_address ();
-  rtx addr = get_unaligned_address (operands[1]);
-  rtx scratch1 = gen_rtx (REG, DImode, REGNO (operands[2]));
-  rtx scratch2 = gen_rtx (REG, DImode, REGNO (operands[2]) + 1);
-  rtx seq;
+  rtx addr = get_unaligned_address (operands[1], 0);
+  /* It is possible that one of the registers we got for operands[2]
+     might coincide with that of operands[0] (which is why we made
+     it TImode).  Pick the other one to use as our scratch.  */
+  rtx scratch = gen_rtx (REG, DImode,
+                        REGNO (operands[0]) == REGNO (operands[2]) 
+                        ? REGNO (operands[2]) + 1 : REGNO (operands[2]));
+  rtx seq = gen_unaligned_loadhi (operands[0], addr, scratch,
+                                 gen_rtx (REG, DImode, REGNO (operands[0])));
 
-  if (GET_CODE (addr) != REG)
-    {
-      emit_insn (gen_rtx (SET, VOIDmode, scratch2, addr));
-      addr = scratch2;
-    }
-      
-  seq = gen_unaligned_loadhi (operands[0], addr, scratch1, scratch1, scratch2);
   alpha_set_memflags (seq, operands[1]);
   emit_insn (seq);
   DONE;
     }
   else
     {
-      rtx addr = get_unaligned_address (operands[0]);
+      rtx addr = get_unaligned_address (operands[0], 0);
       rtx scratch1 = gen_rtx (REG, DImode, REGNO (operands[2]));
       rtx scratch2 = gen_rtx (REG, DImode, REGNO (operands[2]) + 1);
       rtx scratch3 = scratch1;
     }
   else
     {
-      rtx addr = get_unaligned_address (operands[0]);
+      rtx addr = get_unaligned_address (operands[0], 0);
       rtx scratch1 = gen_rtx (REG, DImode, REGNO (operands[2]));
       rtx scratch2 = gen_rtx (REG, DImode, REGNO (operands[2]) + 1);
-      rtx scratch_a = GET_CODE (addr) == REG ? addr : scratch1;
+      rtx scratch3 = scratch1;
       rtx seq;
 
-      seq = gen_unaligned_storehi (addr, operands[1], scratch_a,
-                                  scratch2, scratch2, scratch2,
-                                  scratch1, scratch2, scratch_a,
-                                  scratch1, scratch_a);
+      if (GET_CODE (addr) == REG)
+       scratch1 = addr;
+
+      seq = gen_unaligned_storehi (addr, operands[1], scratch1,
+                                  scratch2, scratch3);
       alpha_set_memflags (seq, operands[0]);
       emit_insn (seq);
     }