diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 6cdda3b..f07e433 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -2354,6 +2354,38 @@ mips_valid_lo_sum_p (enum mips_symbol_type symbol_type, machine_mode mode)
   return true;
 }
 
+/* Return true if X in LO_SUM (REG, X) is a valid.  */
+
+bool
+mips_valid_lo_sum_lo_part_p (machine_mode mode, rtx reg, rtx x)
+{
+   rtx symbol = NULL;
+
+   if (mips_abi != ABI_32)
+     return true;
+
+   if (mode == BLKmode)
+     return true;
+
+   if (reg && REG_P (reg) && REGNO (reg) == GLOBAL_POINTER_REGNUM)
+     return true;
+
+   if (GET_CODE (x) == CONST
+       && GET_CODE (XEXP (x, 0)) == PLUS
+       && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
+     symbol = XEXP (XEXP (x, 0), 0);
+   else if (GET_CODE (x) == SYMBOL_REF)
+     symbol = x;
+
+   if (symbol
+       && SYMBOL_REF_DECL (symbol)
+       && (GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT) >
+	   (DECL_ALIGN_UNIT (SYMBOL_REF_DECL (symbol))))
+     return false;
+
+   return true;
+}
+
 /* Return true if X is a valid address for machine mode MODE.  If it is,
    fill in INFO appropriately.  STRICT_P is true if REG_OK_STRICT is in
    effect.  */
@@ -2394,7 +2426,8 @@ mips_classify_address (struct mips_address_info *info, rtx x,
       info->symbol_type
 	= mips_classify_symbolic_expression (info->offset, SYMBOL_CONTEXT_MEM);
       return (mips_valid_base_register_p (info->reg, mode, strict_p)
-	      && mips_valid_lo_sum_p (info->symbol_type, mode));
+	      && mips_valid_lo_sum_p (info->symbol_type, mode)
+	      && mips_valid_lo_sum_lo_part_p (mode, info->reg, info->offset));
 
     case CONST_INT:
       /* Small-integer addresses don't occur very often, but they
@@ -3143,6 +3176,8 @@ mips_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out)
 		high = gen_rtx_HIGH (Pmode, copy_rtx (addr));
 		high = mips_force_temporary (temp, high);
 		*low_out = gen_rtx_LO_SUM (Pmode, high, addr);
+                if (!mips_valid_lo_sum_lo_part_p (mode, NULL, addr))
+		  *low_out = mips_force_temporary (temp, *low_out);
 		break;
 	      }
 	  return true;
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset1.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset1.c
new file mode 100644
index 0000000..dc81fd9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset1.c
@@ -0,0 +1,14 @@
+/* { dg-options "-mcode-readable=no -mno-gpopt -mabi=32" } */
+/* { dg-final { scan-assembler-not "%lo\\(h\\+6\\)" } } */
+
+struct __attribute__((packed))
+{
+ short s;
+ unsigned long long l;
+} h;
+
+void foo (void)
+{
+ h.l = 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset10.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset10.c
new file mode 100644
index 0000000..da80b67
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset10.c
@@ -0,0 +1,19 @@
+/* { dg-options "-mcode-readable=no -mno-gpopt -mabi=32 -mfpxx isa=2" } */
+/* { dg-final { scan-assembler "%lo\\(d\\+4\\)" } } */
+/* { dg-final { scan-assembler "%lo\\(f\\)" } } */
+/* { dg-final { scan-assembler-not "\tsw\t\\\$\[0-9\],%lo\\(a_f\\)" } } */
+/* { dg-final { scan-assembler-not "\tsw\t\\\$\[0-9\],%lo\\(a_d\\)" } } */
+
+double d;
+double __attribute__((aligned(1))) a_d;
+float f;
+float __attribute__((aligned(1))) a_f;
+
+void foo (void)
+{
+ d = 0;
+ f = 0;
+ a_d = 0;
+ a_f = 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset11.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset11.c
new file mode 100644
index 0000000..b2679f9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset11.c
@@ -0,0 +1,17 @@
+/* { dg-options "-mcode-readable=no -mno-gpopt -mabi=32" } */
+/* { dg-final { scan-assembler-not "%lo\\(h\\+\[1-9\]\\)" } } */
+
+struct __attribute__((packed))
+{
+ char c;
+ short s;
+ int i;
+} h;
+
+void foo (void)
+{
+ h.c = 0;
+ h.s = 0;
+ h.i = 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset2.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset2.c
new file mode 100644
index 0000000..1b9a0b1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset2.c
@@ -0,0 +1,13 @@
+/* { dg-options "-mcode-readable=no -mno-gpopt -mabi=32" } */
+/* { dg-final { scan-assembler-not "%lo\\(a_l\\+4\\)" } } */
+/* { dg-final { scan-assembler "%lo\\(l\\+4\\)" } } */
+
+unsigned long long l;
+unsigned long long __attribute__((aligned(1))) a_l;
+
+void foo (void)
+{
+ l = 0;
+ a_l = 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset3.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset3.c
new file mode 100644
index 0000000..a01c1d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset3.c
@@ -0,0 +1,15 @@
+/* { dg-options "-mcode-readable=no -mno-gpopt -mabi=32" } */
+/* { dg-final { scan-assembler-not "%lo\\(a_l\\+4\\)" } } */
+/* { dg-final { scan-assembler "%lo\\(l\\+4\\)" } } */
+
+long long l;
+double d;
+
+long long __attribute__((aligned(1))) a_l;
+double __attribute__((aligned(1))) a_d;
+
+void foo (void)
+{
+   d = (double) l;
+   a_d = (double) a_l;
+}
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset4.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset4.c
new file mode 100644
index 0000000..496c078
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset4.c
@@ -0,0 +1,16 @@
+/* { dg-options "-mcode-readable=no -mno-gpopt -mabi=32" } */
+/* { dg-final { scan-assembler-not "%lo\\(h\\+\[1-9\]\\)" } } */
+
+struct __attribute__((packed))
+{
+ short s;
+ double d;
+ float f;
+} h;
+
+void foo (void)
+{
+ h.d = 0;
+ h.f = 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset5.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset5.c
new file mode 100644
index 0000000..828c328
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset5.c
@@ -0,0 +1,20 @@
+/* { dg-options "-mcode-readable=no -mno-gpopt -mabi=32" } */
+/* { dg-final { scan-assembler "%lo\\(d\\+4\\)" } } */
+/* { dg-final { scan-assembler "\tsw\t\\\$\[0-9\],%lo\\(f\\)" } } */
+/* { dg-final { scan-assembler-not "%lo\\(a_d\\+4\\)" } } */
+/* { dg-final { scan-assembler-not "\tsw\t\\\$\[0-9\],%lo\\(a_f\\)" } } */
+
+double d;
+double __attribute__((aligned(1))) a_d;
+
+float f;
+float __attribute__((aligned(1))) a_f;
+
+void foo (void)
+{
+ d = 0;
+ f = 0;
+ a_d = 0;
+ a_f = 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset6.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset6.c
new file mode 100644
index 0000000..2eb8f9a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset6.c
@@ -0,0 +1,25 @@
+/* { dg-options "-mcode-readable=no -mno-gpopt -mabi=32" } */
+/* { dg-final { scan-assembler "\tsb\t\\\$\[0-9\],%lo\\(c\\)" } } */
+/* { dg-final { scan-assembler "\tsh\t\\\$\[0-9\],%lo\\(s\\)" } } */
+/* { dg-final { scan-assembler "\tsw\t\\\$\[0-9\],%lo\\(i\\)" } } */
+/* { dg-final { scan-assembler "\tsb\t\\\$\[0-9\],%lo\\(a_c\\)" } } */
+/* { dg-final { scan-assembler-not "\tsh\t\\\$\[0-9\],%lo\\(a_s\\)" } } */
+/* { dg-final { scan-assembler-not "\tsw\t\\\$\[0-9\],%lo\\(a_i\\)" } } */
+
+char __attribute__((aligned(1))) a_c;
+short __attribute__((aligned(1))) a_s;
+int __attribute__((aligned(1))) a_i;
+char c;
+short s;
+int i;
+
+void foo (void)
+{
+ c = 0;
+ s = 0;
+ i = 0;
+ a_c = 0;
+ a_s = 0;
+ a_i = 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset7.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset7.c
new file mode 100644
index 0000000..8f348fb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset7.c
@@ -0,0 +1,16 @@
+/* { dg-options "-mcode-readable=no -mabi=32 -mfp32 isa=1" } */
+/* { dg-final { scan-assembler-not "%lo\\(h\\+\[1-9\]\\)" } } */
+
+struct __attribute__((packed))
+{
+ short s;
+ double d;
+ float f;
+} h;
+
+void foo (void)
+{
+ h.d = 0;
+ h.f = 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset8.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset8.c
new file mode 100644
index 0000000..9070b53
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset8.c
@@ -0,0 +1,20 @@
+/* { dg-options "-mcode-readable=no -mno-gpopt -mabi=32 -mfp32 isa=1" } */
+/* { dg-final { scan-assembler "%lo\\(d\\+4\\)" } } */
+/* { dg-final { scan-assembler "\tsw\t\\\$\[0-9\],%lo\\(f\\)" } } */
+/* { dg-final { scan-assembler-not "\tsw\t\\\$\[0-9\],%lo\\(a_d\\)" } } */
+/* { dg-final { scan-assembler-not "\tsw\t\\\$\[0-9\],%lo\\(a_f\\)" } } */
+
+double d;
+double __attribute__((aligned(1))) a_d;
+
+float f;
+float __attribute__((aligned(1))) a_f;
+
+void foo (void)
+{
+ d = 0;
+ f = 0;
+ a_d = 0;
+ a_f = 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset9.c b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset9.c
new file mode 100644
index 0000000..ee11366
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/hi-lo-reloc-offset9.c
@@ -0,0 +1,16 @@
+/* { dg-options "-mcode-readable=no -mabi=32 -mfpxx isa=2" } */
+/* { dg-final { scan-assembler-not "%lo\\(h\\+\[1-9\]\\)" } } */
+
+struct __attribute__((packed))
+{
+ short s;
+ double d;
+ float f;
+} h;
+
+void foo (void)
+{
+ h.d = 0;
+ h.f = 0;
+}
+
