diff -ur gcc.orig/config/s390/s390-protos.h gcc/config/s390/s390-protos.h
--- gcc.orig/config/s390/s390-protos.h	2004-02-11 19:04:07.000000000 -0500
+++ gcc/config/s390/s390-protos.h	2004-02-11 19:08:21.000000000 -0500
@@ -43,6 +43,7 @@
 extern int s390_extract_hi PARAMS ((rtx, enum machine_mode, int));
 extern int s390_single_qi PARAMS ((rtx, enum machine_mode, int));
 extern int s390_extract_qi PARAMS ((rtx, enum machine_mode, int));
+extern bool s390_split_ok_p PARAMS ((rtx, rtx, enum machine_mode, int));
 extern int tls_symbolic_operand PARAMS ((rtx));
 
 extern int s390_match_ccmode PARAMS ((rtx, enum machine_mode));
@@ -61,6 +62,7 @@
 extern rtx legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
 extern enum reg_class s390_preferred_reload_class PARAMS ((rtx, enum reg_class));
 extern enum reg_class s390_secondary_input_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx));
+extern enum reg_class s390_secondary_output_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx));
 extern int s390_plus_operand PARAMS ((rtx, enum machine_mode));
 extern void s390_expand_plus_operand PARAMS ((rtx, rtx, rtx));
 extern void emit_symbolic_move PARAMS ((rtx *));
diff -ur gcc.orig/config/s390/s390.c gcc/config/s390/s390.c
--- gcc.orig/config/s390/s390.c	2004-02-11 19:04:07.000000000 -0500
+++ gcc/config/s390/s390.c	2004-02-11 19:08:21.000000000 -0500
@@ -863,6 +863,42 @@
   abort ();
 }
 
+/* Check whether we can (and want to) split a double-word 
+   move in mode MODE from SRC to DST into two single-word 
+   moves, moving the subword FIRST_SUBWORD first.  */
+
+bool
+s390_split_ok_p (dst, src, mode, first_subword)
+     rtx dst;
+     rtx src;
+     enum machine_mode mode;
+     int first_subword;
+{
+  /* Floating point registers cannot be split.  */
+  if (FP_REG_P (src) || FP_REG_P (dst))
+    return false;
+
+  /* We don't need to split if operands are directly accessable.  */
+  if (s_operand (src, mode) || s_operand (dst, mode))
+    return false;
+
+  /* Non-offsettable memory references cannot be split.  */
+  if ((GET_CODE (src) == MEM && !offsettable_memref_p (src))
+      || (GET_CODE (dst) == MEM && !offsettable_memref_p (dst)))
+    return false;
+
+  /* Moving the first subword must not clobber a register
+     needed to move the second subword.  */
+  if (register_operand (dst, mode))
+    {
+      rtx subreg = operand_subword (dst, first_subword, 0, mode);
+      if (reg_overlap_mentioned_p (subreg, src))
+        return false;
+    }
+
+  return true;
+}
+
 
 /* Change optimizations to be performed, depending on the 
    optimization level.
@@ -1755,6 +1791,29 @@
   return NO_REGS;
 }
 
+/* Return the register class of a scratch register needed to
+   store a register of class CLASS in MODE into OUT:
+
+   We need a temporary when storing a double-word to a 
+   non-offsettable memory address.  */
+
+enum reg_class
+s390_secondary_output_reload_class (class, mode, out)
+     enum reg_class class;
+     enum machine_mode mode;
+     rtx out;
+{
+  if ((TARGET_64BIT ? mode == TImode
+                    : (mode == DImode || mode == DFmode))
+      && reg_classes_intersect_p (GENERAL_REGS, class)
+      && GET_CODE (out) == MEM
+      && !offsettable_memref_p (out)
+      && !s_operand (out, VOIDmode))
+    return ADDR_REGS;
+
+  return NO_REGS;
+}
+
 /* Return true if OP is a PLUS that is not a legitimate
    operand for the LA instruction. 
    OP is the current operation.
diff -ur gcc.orig/config/s390/s390.h gcc/config/s390/s390.h
--- gcc.orig/config/s390/s390.h	2004-02-11 19:04:07.000000000 -0500
+++ gcc/config/s390/s390.h	2004-02-11 19:08:21.000000000 -0500
@@ -474,6 +474,11 @@
 #define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN)	\
   s390_secondary_input_reload_class ((CLASS), (MODE), (IN))
 
+/* We need a secondary reload when storing a double-word
+   to a non-offsettable memory address.  */
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, OUT)	\
+  s390_secondary_output_reload_class ((CLASS), (MODE), (OUT))
+
 /* We need secondary memory to move data between GPRs and FPRs.  */
 #define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
  ((CLASS1) != (CLASS2) && ((CLASS1) == FP_REGS || (CLASS2) == FP_REGS))
diff -ur gcc.orig/config/s390/s390.md gcc/config/s390/s390.md
--- gcc.orig/config/s390/s390.md	2004-02-11 19:04:08.000000000 -0500
+++ gcc/config/s390/s390.md	2004-02-11 19:08:21.000000000 -0500
@@ -939,7 +939,7 @@
 
 (define_insn "movti"
   [(set (match_operand:TI 0 "nonimmediate_operand" "=d,QS,d,o,Q")
-        (match_operand:TI 1 "general_operand" "QS,d,dKo,d,Q"))]
+        (match_operand:TI 1 "general_operand" "QS,d,dKm,d,Q"))]
   "TARGET_64BIT"
   "@
    lmg\\t%0,%N0,%1
@@ -954,36 +954,29 @@
   [(set (match_operand:TI 0 "nonimmediate_operand" "")
         (match_operand:TI 1 "general_operand" ""))]
   "TARGET_64BIT && reload_completed
-   && !s_operand (operands[0], VOIDmode)
-   && !s_operand (operands[1], VOIDmode)
-   && (register_operand (operands[0], VOIDmode)
-       || register_operand (operands[1], VOIDmode))
-   && (!register_operand (operands[0], VOIDmode)
-       || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, TImode),
-                                    operands[1])
-       || !reg_overlap_mentioned_p (operand_subword (operands[0], 1, 0, TImode),
-                                    operands[1]))"
+   && s390_split_ok_p (operands[0], operands[1], TImode, 0)"
   [(set (match_dup 2) (match_dup 4))
    (set (match_dup 3) (match_dup 5))]
-  "
 {
-  if (!register_operand (operands[0], VOIDmode)
-      || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, TImode),
-                                   operands[1]))
-    {
-      operands[2] = operand_subword (operands[0], 0, 0, TImode);
-      operands[3] = operand_subword (operands[0], 1, 0, TImode);
-      operands[4] = operand_subword (operands[1], 0, 0, TImode);
-      operands[5] = operand_subword (operands[1], 1, 0, TImode);
-    }
-  else
-    {
-      operands[2] = operand_subword (operands[0], 1, 0, TImode);
-      operands[3] = operand_subword (operands[0], 0, 0, TImode);
-      operands[4] = operand_subword (operands[1], 1, 0, TImode);
-      operands[5] = operand_subword (operands[1], 0, 0, TImode);
-    }
-}")
+  operands[2] = operand_subword (operands[0], 0, 0, TImode);
+  operands[3] = operand_subword (operands[0], 1, 0, TImode);
+  operands[4] = operand_subword (operands[1], 0, 0, TImode);
+  operands[5] = operand_subword (operands[1], 1, 0, TImode);
+})
+
+(define_split
+  [(set (match_operand:TI 0 "nonimmediate_operand" "")
+        (match_operand:TI 1 "general_operand" ""))]
+  "TARGET_64BIT && reload_completed
+   && s390_split_ok_p (operands[0], operands[1], TImode, 1)"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+{
+  operands[2] = operand_subword (operands[0], 1, 0, TImode);
+  operands[3] = operand_subword (operands[0], 0, 0, TImode);
+  operands[4] = operand_subword (operands[1], 1, 0, TImode);
+  operands[5] = operand_subword (operands[1], 0, 0, TImode);
+})
 
 (define_split
   [(set (match_operand:TI 0 "register_operand" "")
@@ -991,12 +984,23 @@
   "TARGET_64BIT && reload_completed
    && !s_operand (operands[1], VOIDmode)"
   [(set (match_dup 0) (match_dup 1))]
-  "
 {
   rtx addr = operand_subword (operands[0], 1, 0, TImode);
   s390_load_address (addr, XEXP (operands[1], 0));
   operands[1] = replace_equiv_address (operands[1], addr);
-}")
+})
+
+(define_expand "reload_outti"
+  [(parallel [(match_operand:TI 0 "memory_operand" "")
+              (match_operand:TI 1 "register_operand" "d")
+              (match_operand:DI 2 "register_operand" "=&a")])]
+  "TARGET_64BIT"
+{
+  s390_load_address (operands[2], XEXP (operands[0], 0));
+  operands[0] = replace_equiv_address (operands[0], operands[2]);
+  emit_move_insn (operands[0], operands[1]);
+  DONE;
+})
 
 ;
 ; movdi instruction pattern(s).
@@ -1091,7 +1095,7 @@
 
 (define_insn "*movdi_31"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,Q,d,o,!*f,!*f,!*f,!R,!T,Q")
-        (match_operand:DI 1 "general_operand" "Q,d,dKo,d,*f,R,T,*f,*f,Q"))]
+        (match_operand:DI 1 "general_operand" "Q,d,dKm,d,*f,R,T,*f,*f,Q"))]
   "!TARGET_64BIT"
   "@
    lm\\t%0,%N0,%1
@@ -1111,53 +1115,54 @@
   [(set (match_operand:DI 0 "nonimmediate_operand" "")
         (match_operand:DI 1 "general_operand" ""))]
   "!TARGET_64BIT && reload_completed
-   && !FP_REG_P (operands[0])
-   && !FP_REG_P (operands[1])
-   && !s_operand (operands[0], VOIDmode)
-   && !s_operand (operands[1], VOIDmode)
-   && (register_operand (operands[0], VOIDmode)
-       || register_operand (operands[1], VOIDmode))
-   && (!register_operand (operands[0], VOIDmode)
-       || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DImode),
-                                    operands[1])
-       || !reg_overlap_mentioned_p (operand_subword (operands[0], 1, 0, DImode),
-                                    operands[1]))"
+   && s390_split_ok_p (operands[0], operands[1], DImode, 0)"
   [(set (match_dup 2) (match_dup 4))
    (set (match_dup 3) (match_dup 5))]
-  "
 {
-  if (!register_operand (operands[0], VOIDmode)
-      || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DImode),
-                                   operands[1]))
-    {
-      operands[2] = operand_subword (operands[0], 0, 0, DImode);
-      operands[3] = operand_subword (operands[0], 1, 0, DImode);
-      operands[4] = operand_subword (operands[1], 0, 0, DImode);
-      operands[5] = operand_subword (operands[1], 1, 0, DImode);
-    }
-  else
-    {
-      operands[2] = operand_subword (operands[0], 1, 0, DImode);
-      operands[3] = operand_subword (operands[0], 0, 0, DImode);
-      operands[4] = operand_subword (operands[1], 1, 0, DImode);
-      operands[5] = operand_subword (operands[1], 0, 0, DImode);
-    }
-}")
+  operands[2] = operand_subword (operands[0], 0, 0, DImode);
+  operands[3] = operand_subword (operands[0], 1, 0, DImode);
+  operands[4] = operand_subword (operands[1], 0, 0, DImode);
+  operands[5] = operand_subword (operands[1], 1, 0, DImode);
+})
+
+(define_split
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+        (match_operand:DI 1 "general_operand" ""))]
+  "!TARGET_64BIT && reload_completed
+   && s390_split_ok_p (operands[0], operands[1], DImode, 1)"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+{
+  operands[2] = operand_subword (operands[0], 1, 0, DImode);
+  operands[3] = operand_subword (operands[0], 0, 0, DImode);
+  operands[4] = operand_subword (operands[1], 1, 0, DImode);
+  operands[5] = operand_subword (operands[1], 0, 0, DImode);
+})
 
 (define_split
   [(set (match_operand:DI 0 "register_operand" "")
         (match_operand:DI 1 "memory_operand" ""))]
   "!TARGET_64BIT && reload_completed
    && !FP_REG_P (operands[0])
-   && !FP_REG_P (operands[1])
    && !s_operand (operands[1], VOIDmode)"
   [(set (match_dup 0) (match_dup 1))]
-  "
 {
   rtx addr = operand_subword (operands[0], 1, 0, DImode);
   s390_load_address (addr, XEXP (operands[1], 0));
   operands[1] = replace_equiv_address (operands[1], addr);
-}")
+})
+
+(define_expand "reload_outdi"
+  [(parallel [(match_operand:DI 0 "memory_operand" "")
+              (match_operand:DI 1 "register_operand" "d")
+              (match_operand:SI 2 "register_operand" "=&a")])]
+  "!TARGET_64BIT"
+{
+  s390_load_address (operands[2], XEXP (operands[0], 0));
+  operands[0] = replace_equiv_address (operands[0], operands[2]);
+  emit_move_insn (operands[0], operands[1]);
+  DONE;
+})
 
 (define_peephole2
   [(set (match_operand:DI 0 "register_operand" "")
@@ -1429,7 +1434,7 @@
 
 (define_insn "*movdf_31"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,R,T,d,Q,d,o,Q")
-        (match_operand:DF 1 "general_operand" "f,R,T,f,f,Q,d,dKo,d,Q"))]
+        (match_operand:DF 1 "general_operand" "f,R,T,f,f,Q,d,dKm,d,Q"))]
   "!TARGET_64BIT"
   "@
    ldr\\t%0,%1
@@ -1449,53 +1454,54 @@
   [(set (match_operand:DF 0 "nonimmediate_operand" "")
         (match_operand:DF 1 "general_operand" ""))]
   "!TARGET_64BIT && reload_completed
-   && !FP_REG_P (operands[0])
-   && !FP_REG_P (operands[1])
-   && !s_operand (operands[0], VOIDmode)
-   && !s_operand (operands[1], VOIDmode)
-   && (register_operand (operands[0], VOIDmode)
-       || register_operand (operands[1], VOIDmode))
-   && (!register_operand (operands[0], VOIDmode)
-       || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DFmode),
-                                    operands[1])
-       || !reg_overlap_mentioned_p (operand_subword (operands[0], 1, 0, DFmode),
-                                    operands[1]))"
+   && s390_split_ok_p (operands[0], operands[1], DFmode, 0)"
   [(set (match_dup 2) (match_dup 4))
    (set (match_dup 3) (match_dup 5))]
-  "
 {
-  if (!register_operand (operands[0], VOIDmode)
-      || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DFmode),
-                                   operands[1]))
-    {
-      operands[2] = operand_subword (operands[0], 0, 0, DFmode);
-      operands[3] = operand_subword (operands[0], 1, 0, DFmode);
-      operands[4] = operand_subword (operands[1], 0, 0, DFmode);
-      operands[5] = operand_subword (operands[1], 1, 0, DFmode);
-    }
-  else
-    {
-      operands[2] = operand_subword (operands[0], 1, 0, DFmode);
-      operands[3] = operand_subword (operands[0], 0, 0, DFmode);
-      operands[4] = operand_subword (operands[1], 1, 0, DFmode);
-      operands[5] = operand_subword (operands[1], 0, 0, DFmode);
-    }
-}")
+  operands[2] = operand_subword (operands[0], 0, 0, DFmode);
+  operands[3] = operand_subword (operands[0], 1, 0, DFmode);
+  operands[4] = operand_subword (operands[1], 0, 0, DFmode);
+  operands[5] = operand_subword (operands[1], 1, 0, DFmode);
+})
+
+(define_split
+  [(set (match_operand:DF 0 "nonimmediate_operand" "")
+        (match_operand:DF 1 "general_operand" ""))]
+  "!TARGET_64BIT && reload_completed
+   && s390_split_ok_p (operands[0], operands[1], DFmode, 1)"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+{
+  operands[2] = operand_subword (operands[0], 1, 0, DFmode);
+  operands[3] = operand_subword (operands[0], 0, 0, DFmode);
+  operands[4] = operand_subword (operands[1], 1, 0, DFmode);
+  operands[5] = operand_subword (operands[1], 0, 0, DFmode);
+})
 
 (define_split
   [(set (match_operand:DF 0 "register_operand" "")
         (match_operand:DF 1 "memory_operand" ""))]
   "!TARGET_64BIT && reload_completed
    && !FP_REG_P (operands[0])
-   && !FP_REG_P (operands[1])
    && !s_operand (operands[1], VOIDmode)"
   [(set (match_dup 0) (match_dup 1))]
-  "
 {
   rtx addr = operand_subword (operands[0], 1, 0, DFmode);
   s390_load_address (addr, XEXP (operands[1], 0));
   operands[1] = replace_equiv_address (operands[1], addr);
-}")
+})
+
+(define_expand "reload_outdf"
+  [(parallel [(match_operand:DF 0 "memory_operand" "")
+              (match_operand:DF 1 "register_operand" "d")
+              (match_operand:SI 2 "register_operand" "=&a")])]
+  "!TARGET_64BIT"
+{
+  s390_load_address (operands[2], XEXP (operands[0], 0));
+  operands[0] = replace_equiv_address (operands[0], operands[2]);
+  emit_move_insn (operands[0], operands[1]);
+  DONE;
+})
 
 ;
 ; movsf instruction pattern(s).
diff -ur gcc.orig/testsuite/gcc.dg/20030627-1.c gcc/testsuite/gcc.dg/20030627-1.c
--- gcc.orig/testsuite/gcc.dg/20030627-1.c	2004-02-11 19:06:21.000000000 -0500
+++ gcc/testsuite/gcc.dg/20030627-1.c	2004-02-11 19:08:21.000000000 -0500
@@ -0,0 +1,20 @@
+/* This tests whether non-offsettable memory operands are reloaded 
+   correctly in certain corner cases on s390 targets.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+
+void test_inout (char *bd, int xd, char *bs, int xs)
+{
+  *(long long *)(bd + xd + 4093) = *(long long *)(bs + xs + 4093);
+}
+
+void test_in (char *bd, int xd, char *bs, int xs)
+{
+  *(long long *)(bd + xd) = *(long long *)(bs + xs + 4093);
+}
+
+void test_out (char *bd, int xd, char *bs, int xs)
+{
+  *(long long *)(bd + xd + 4093) = *(long long *)(bs + xs);
+}
+
