MIPS32: Improve offset calculations in loads and stores

Change-Id: I6c3773e8bc1233bcda83d5b7254438ef69e9570d
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index a1798c0..44f51c6 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -448,6 +448,11 @@
   EmitI(0xf, static_cast<Register>(0), rt, imm16);
 }
 
+void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) {
+  CHECK(IsR6());
+  EmitI(0xf, rs, rt, imm16);
+}
+
 void MipsAssembler::Sync(uint32_t stype) {
   EmitR(0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0),
         stype & 0x1f, 0xf);
@@ -1385,13 +1390,8 @@
                                          Register base,
                                          int32_t offset,
                                          Register temp) {
-  if (!IsInt<16>(offset)) {
-    CHECK_NE(temp, AT);  //  Must not use AT as temp, as not to overwrite the loaded value.
-    LoadConst32(AT, offset);
-    Addu(AT, AT, base);
-    base = AT;
-    offset = 0;
-  }
+  CHECK_NE(temp, AT);  // Must not use AT as temp, so as not to overwrite the adjusted base.
+  AdjustBaseAndOffset(base, offset, /* is_doubleword */ false);
   if (value == 0) {
     temp = ZERO;
   } else {
@@ -1404,14 +1404,8 @@
                                          Register base,
                                          int32_t offset,
                                          Register temp) {
-  // IsInt<16> must be passed a signed value.
-  if (!IsInt<16>(offset) || !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))) {
-    CHECK_NE(temp, AT);  //  Must not use AT as temp, as not to overwrite the loaded value.
-    LoadConst32(AT, offset);
-    Addu(AT, AT, base);
-    base = AT;
-    offset = 0;
-  }
+  CHECK_NE(temp, AT);  // Must not use AT as temp, so as not to overwrite the adjusted base.
+  AdjustBaseAndOffset(base, offset, /* is_doubleword */ true);
   uint32_t low = Low32Bits(value);
   uint32_t high = High32Bits(value);
   if (low == 0) {
@@ -1457,11 +1451,35 @@
 }
 
 void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) {
+  CHECK_NE(rs, temp);  // Must not overwrite the register `rs` while loading `value`.
   if (IsInt<16>(value)) {
     Addiu(rt, rs, value);
+  } else if (IsR6()) {
+    int16_t high = High16Bits(value);
+    int16_t low = Low16Bits(value);
+    high += (low < 0) ? 1 : 0;  // Account for sign extension in addiu.
+    if (low != 0) {
+      Aui(temp, rs, high);
+      Addiu(rt, temp, low);
+    } else {
+      Aui(rt, rs, high);
+    }
   } else {
-    LoadConst32(temp, value);
-    Addu(rt, rs, temp);
+    // Do not load the whole 32-bit `value` if it can be represented as
+    // a sum of two 16-bit signed values. This can save an instruction.
+    constexpr int32_t kMinValueForSimpleAdjustment = std::numeric_limits<int16_t>::min() * 2;
+    constexpr int32_t kMaxValueForSimpleAdjustment = std::numeric_limits<int16_t>::max() * 2;
+    if (0 <= value && value <= kMaxValueForSimpleAdjustment) {
+      Addiu(temp, rs, kMaxValueForSimpleAdjustment / 2);
+      Addiu(rt, temp, value - kMaxValueForSimpleAdjustment / 2);
+    } else if (kMinValueForSimpleAdjustment <= value && value < 0) {
+      Addiu(temp, rs, kMinValueForSimpleAdjustment / 2);
+      Addiu(rt, temp, value - kMinValueForSimpleAdjustment / 2);
+    } else {
+      // Now that all shorter options have been exhausted, load the full 32-bit value.
+      LoadConst32(temp, value);
+      Addu(rt, rs, temp);
+    }
   }
 }
 
@@ -2262,17 +2280,103 @@
   Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
 }
 
-void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
-                                   int32_t offset) {
-  // IsInt<16> must be passed a signed value.
-  if (!IsInt<16>(offset) ||
-      (type == kLoadDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
-    LoadConst32(AT, offset);
-    Addu(AT, AT, base);
-    base = AT;
-    offset = 0;
+void MipsAssembler::AdjustBaseAndOffset(Register& base,
+                                        int32_t& offset,
+                                        bool is_doubleword,
+                                        bool is_float) {
+  // This method is used to adjust the base register and offset pair
+  // for a load/store when the offset doesn't fit into int16_t.
+  // It is assumed that `base + offset` is sufficiently aligned for memory
+  // operands that are machine word in size or smaller. For doubleword-sized
+  // operands it's assumed that `base` is a multiple of 8, while `offset`
+  // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments
+  // and spilled variables on the stack accessed relative to the stack
+  // pointer register).
+  // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8.
+  CHECK_NE(base, AT);  // Must not overwrite the register `base` while loading `offset`.
+
+  bool doubleword_aligned = IsAligned<kMipsDoublewordSize>(offset);
+  bool two_accesses = is_doubleword && (!is_float || !doubleword_aligned);
+
+  // IsInt<16> must be passed a signed value, hence the static cast below.
+  if (IsInt<16>(offset) &&
+      (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
+    // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t.
+    return;
   }
 
+  // Remember the "(mis)alignment" of `offset`, it will be checked at the end.
+  uint32_t misalignment = offset & (kMipsDoublewordSize - 1);
+
+  // Do not load the whole 32-bit `offset` if it can be represented as
+  // a sum of two 16-bit signed offsets. This can save an instruction or two.
+  // To simplify matters, only do this for a symmetric range of offsets from
+  // about -64KB to about +64KB, allowing further addition of 4 when accessing
+  // 64-bit variables with two 32-bit accesses.
+  constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8;  // Max int16_t that's a multiple of 8.
+  constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment;
+  if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) {
+    Addiu(AT, base, kMinOffsetForSimpleAdjustment);
+    offset -= kMinOffsetForSimpleAdjustment;
+  } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) {
+    Addiu(AT, base, -kMinOffsetForSimpleAdjustment);
+    offset += kMinOffsetForSimpleAdjustment;
+  } else if (IsR6()) {
+    // On R6 take advantage of the aui instruction, e.g.:
+    //   aui   AT, base, offset_high
+    //   lw    reg_lo, offset_low(AT)
+    //   lw    reg_hi, (offset_low+4)(AT)
+    // or when offset_low+4 overflows int16_t:
+    //   aui   AT, base, offset_high
+    //   addiu AT, AT, 8
+    //   lw    reg_lo, (offset_low-8)(AT)
+    //   lw    reg_hi, (offset_low-4)(AT)
+    int16_t offset_high = High16Bits(offset);
+    int16_t offset_low = Low16Bits(offset);
+    offset_high += (offset_low < 0) ? 1 : 0;  // Account for offset sign extension in load/store.
+    Aui(AT, base, offset_high);
+    if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low + kMipsWordSize))) {
+      // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4.
+      Addiu(AT, AT, kMipsDoublewordSize);
+      offset_low -= kMipsDoublewordSize;
+    }
+    offset = offset_low;
+  } else {
+    // Do not load the whole 32-bit `offset` if it can be represented as
+    // a sum of three 16-bit signed offsets. This can save an instruction.
+    // To simplify matters, only do this for a symmetric range of offsets from
+    // about -96KB to about +96KB, allowing further addition of 4 when accessing
+    // 64-bit variables with two 32-bit accesses.
+    constexpr int32_t kMinOffsetForMediumAdjustment = 2 * kMinOffsetForSimpleAdjustment;
+    constexpr int32_t kMaxOffsetForMediumAdjustment = 3 * kMinOffsetForSimpleAdjustment;
+    if (0 <= offset && offset <= kMaxOffsetForMediumAdjustment) {
+      Addiu(AT, base, kMinOffsetForMediumAdjustment / 2);
+      Addiu(AT, AT, kMinOffsetForMediumAdjustment / 2);
+      offset -= kMinOffsetForMediumAdjustment;
+    } else if (-kMaxOffsetForMediumAdjustment <= offset && offset < 0) {
+      Addiu(AT, base, -kMinOffsetForMediumAdjustment / 2);
+      Addiu(AT, AT, -kMinOffsetForMediumAdjustment / 2);
+      offset += kMinOffsetForMediumAdjustment;
+    } else {
+      // Now that all shorter options have been exhausted, load the full 32-bit offset.
+      int32_t loaded_offset = RoundDown(offset, kMipsDoublewordSize);
+      LoadConst32(AT, loaded_offset);
+      Addu(AT, AT, base);
+      offset -= loaded_offset;
+    }
+  }
+  base = AT;
+
+  CHECK(IsInt<16>(offset));
+  if (two_accesses) {
+    CHECK(IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)));
+  }
+  CHECK_EQ(misalignment, offset & (kMipsDoublewordSize - 1));
+}
+
+void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
+                                   int32_t offset) {
+  AdjustBaseAndOffset(base, offset, /* is_doubleword */ (type == kLoadDoubleword));
   switch (type) {
     case kLoadSignedByte:
       Lb(reg, base, offset);
@@ -2306,27 +2410,12 @@
 }
 
 void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
-  if (!IsInt<16>(offset)) {
-    LoadConst32(AT, offset);
-    Addu(AT, AT, base);
-    base = AT;
-    offset = 0;
-  }
-
+  AdjustBaseAndOffset(base, offset, /* is_doubleword */ false, /* is_float */ true);
   Lwc1(reg, base, offset);
 }
 
 void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
-  // IsInt<16> must be passed a signed value.
-  if (!IsInt<16>(offset) ||
-      (!IsAligned<kMipsDoublewordSize>(offset) &&
-       !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
-    LoadConst32(AT, offset);
-    Addu(AT, AT, base);
-    base = AT;
-    offset = 0;
-  }
-
+  AdjustBaseAndOffset(base, offset, /* is_doubleword */ true, /* is_float */ true);
   if (offset & 0x7) {
     if (Is32BitFPU()) {
       Lwc1(reg, base, offset);
@@ -2365,15 +2454,10 @@
 
 void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
                                   int32_t offset) {
-  // IsInt<16> must be passed a signed value.
-  if (!IsInt<16>(offset) ||
-      (type == kStoreDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
-    LoadConst32(AT, offset);
-    Addu(AT, AT, base);
-    base = AT;
-    offset = 0;
-  }
-
+  // Must not use AT as `reg`, so as not to overwrite the value being stored
+  // with the adjusted `base`.
+  CHECK_NE(reg, AT);
+  AdjustBaseAndOffset(base, offset, /* is_doubleword */ (type == kStoreDoubleword));
   switch (type) {
     case kStoreByte:
       Sb(reg, base, offset);
@@ -2396,27 +2480,12 @@
 }
 
 void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
-  if (!IsInt<16>(offset)) {
-    LoadConst32(AT, offset);
-    Addu(AT, AT, base);
-    base = AT;
-    offset = 0;
-  }
-
+  AdjustBaseAndOffset(base, offset, /* is_doubleword */ false, /* is_float */ true);
   Swc1(reg, base, offset);
 }
 
 void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
-  // IsInt<16> must be passed a signed value.
-  if (!IsInt<16>(offset) ||
-      (!IsAligned<kMipsDoublewordSize>(offset) &&
-       !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) {
-    LoadConst32(AT, offset);
-    Addu(AT, AT, base);
-    base = AT;
-    offset = 0;
-  }
-
+  AdjustBaseAndOffset(base, offset, /* is_doubleword */ true, /* is_float */ true);
   if (offset & 0x7) {
     if (Is32BitFPU()) {
       Swc1(reg, base, offset);
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index ecb67bd..68fa6bf 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -183,6 +183,7 @@
   void Lbu(Register rt, Register rs, uint16_t imm16);
   void Lhu(Register rt, Register rs, uint16_t imm16);
   void Lui(Register rt, uint16_t imm16);
+  void Aui(Register rt, Register rs, uint16_t imm16);  // R6
   void Sync(uint32_t stype);
   void Mfhi(Register rd);  // R2
   void Mflo(Register rd);  // R2
@@ -385,6 +386,10 @@
   void Bc1nez(FRegister ft, MipsLabel* label);  // R6
 
   void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size);
+  void AdjustBaseAndOffset(Register& base,
+                           int32_t& offset,
+                           bool is_doubleword,
+                           bool is_float = false);
   void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset);
   void LoadSFromOffset(FRegister reg, Register base, int32_t offset);
   void LoadDFromOffset(FRegister reg, Register base, int32_t offset);
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index cec43ba..2f7778c 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -723,212 +723,538 @@
   DriverStr(RepeatRR(&mips::MipsAssembler::Not, "nor ${reg1}, ${reg2}, $zero"), "Not");
 }
 
-TEST_F(AssemblerMIPSTest, LoadFromOffset) {
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A0, 0);
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A1, 0);
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A1, 256);
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A1, 1000);
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A1, 0x8000);
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A1, 0x10000);
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A1, 0x12345678);
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A1, -256);
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A1, 0xFFFF8000);
-  __ LoadFromOffset(mips::kLoadSignedByte, mips::A0, mips::A1, 0xABCDEF00);
-
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A0, 0);
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A1, 0);
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A1, 256);
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A1, 1000);
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A1, 0x8000);
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A1, 0x10000);
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A1, 0x12345678);
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A1, -256);
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A1, 0xFFFF8000);
-  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A0, mips::A1, 0xABCDEF00);
-
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A0, 0);
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A1, 0);
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A1, 256);
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A1, 1000);
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A1, 0x8000);
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A1, 0x10000);
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A1, 0x12345678);
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A1, -256);
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A1, 0xFFFF8000);
-  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A0, mips::A1, 0xABCDEF00);
-
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A0, 0);
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A1, 0);
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A1, 256);
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A1, 1000);
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A1, 0x8000);
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A1, 0x10000);
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A1, 0x12345678);
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A1, -256);
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A1, 0xFFFF8000);
-  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A0, mips::A1, 0xABCDEF00);
-
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A0, 0);
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A1, 0);
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A1, 256);
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A1, 1000);
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A1, 0x8000);
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A1, 0x10000);
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A1, 0x12345678);
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A1, -256);
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A1, 0xFFFF8000);
-  __ LoadFromOffset(mips::kLoadWord, mips::A0, mips::A1, 0xABCDEF00);
-
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A0, 0);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A1, 0);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A1, mips::A0, 0);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, 0);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, 256);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, 1000);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, 0x8000);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, 0x10000);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, 0x12345678);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -256);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, 0xFFFF8000);
-  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, 0xABCDEF00);
+TEST_F(AssemblerMIPSTest, Addiu32) {
+  __ Addiu32(mips::A1, mips::A2, -0x8000);
+  __ Addiu32(mips::A1, mips::A2, +0);
+  __ Addiu32(mips::A1, mips::A2, +0x7FFF);
+  __ Addiu32(mips::A1, mips::A2, -0x10000);
+  __ Addiu32(mips::A1, mips::A2, -0x8001);
+  __ Addiu32(mips::A1, mips::A2, +0x8000);
+  __ Addiu32(mips::A1, mips::A2, +0xFFFE);
+  __ Addiu32(mips::A1, mips::A2, -0x10001);
+  __ Addiu32(mips::A1, mips::A2, +0xFFFF);
+  __ Addiu32(mips::A1, mips::A2, +0x10000);
+  __ Addiu32(mips::A1, mips::A2, +0x10001);
+  __ Addiu32(mips::A1, mips::A2, +0x12345678);
 
   const char* expected =
-      "lb $a0, 0($a0)\n"
-      "lb $a0, 0($a1)\n"
-      "lb $a0, 256($a1)\n"
-      "lb $a0, 1000($a1)\n"
-      "ori $at, $zero, 0x8000\n"
-      "addu $at, $at, $a1\n"
-      "lb $a0, 0($at)\n"
+      "addiu $a1, $a2, -0x8000\n"
+      "addiu $a1, $a2, 0\n"
+      "addiu $a1, $a2, 0x7FFF\n"
+      "addiu $at, $a2, -0x8000\n"
+      "addiu $a1, $at, -0x8000\n"
+      "addiu $at, $a2, -0x8000\n"
+      "addiu $a1, $at, -1\n"
+      "addiu $at, $a2, 0x7FFF\n"
+      "addiu $a1, $at, 1\n"
+      "addiu $at, $a2, 0x7FFF\n"
+      "addiu $a1, $at, 0x7FFF\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0xFFFF\n"
+      "addu $a1, $a2, $at\n"
+      "ori $at, $zero, 0xFFFF\n"
+      "addu $a1, $a2, $at\n"
       "lui $at, 1\n"
-      "addu $at, $at, $a1\n"
-      "lb $a0, 0($at)\n"
-      "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
-      "addu $at, $at, $a1\n"
-      "lb $a0, 0($at)\n"
-      "lb $a0, -256($a1)\n"
-      "lb $a0, 0xFFFF8000($a1)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a1\n"
-      "lb $a0, 0($at)\n"
-
-      "lbu $a0, 0($a0)\n"
-      "lbu $a0, 0($a1)\n"
-      "lbu $a0, 256($a1)\n"
-      "lbu $a0, 1000($a1)\n"
-      "ori $at, $zero, 0x8000\n"
-      "addu $at, $at, $a1\n"
-      "lbu $a0, 0($at)\n"
+      "addu $a1, $a2, $at\n"
       "lui $at, 1\n"
-      "addu $at, $at, $a1\n"
-      "lbu $a0, 0($at)\n"
+      "ori $at, $at, 1\n"
+      "addu $a1, $a2, $at\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
-      "addu $at, $at, $a1\n"
-      "lbu $a0, 0($at)\n"
-      "lbu $a0, -256($a1)\n"
-      "lbu $a0, 0xFFFF8000($a1)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a1\n"
-      "lbu $a0, 0($at)\n"
+      "ori $at, $at, 0x5678\n"
+      "addu $a1, $a2, $at\n";
+  DriverStr(expected, "Addiu32");
+}
 
-      "lh $a0, 0($a0)\n"
-      "lh $a0, 0($a1)\n"
-      "lh $a0, 256($a1)\n"
-      "lh $a0, 1000($a1)\n"
-      "ori $at, $zero, 0x8000\n"
+TEST_F(AssemblerMIPSTest, LoadFromOffset) {
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, -0x8000);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x7FF8);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x7FFB);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x7FFC);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x7FFF);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, -0xFFF0);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, -0x8008);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, -0x8001);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x8000);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0xFFF0);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, -0x17FE8);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, -0x0FFF8);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, -0x0FFF1);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x0FFF1);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x0FFF8);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x17FE8);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, -0x17FF0);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, -0x17FE9);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x17FE9);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x17FF0);
+  __ LoadFromOffset(mips::kLoadSignedByte, mips::A3, mips::A1, +0x12345678);
+
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, -0x8000);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x7FF8);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x7FFB);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x7FFC);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x7FFF);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, -0xFFF0);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, -0x8008);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, -0x8001);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x8000);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0xFFF0);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, -0x17FE8);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, -0x0FFF8);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, -0x0FFF1);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x0FFF1);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x0FFF8);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x17FE8);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, -0x17FF0);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, -0x17FE9);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x17FE9);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x17FF0);
+  __ LoadFromOffset(mips::kLoadUnsignedByte, mips::A3, mips::A1, +0x12345678);
+
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, -0x8000);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x7FF8);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x7FFB);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x7FFC);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x7FFF);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, -0xFFF0);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, -0x8008);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, -0x8001);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x8000);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0xFFF0);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, -0x17FE8);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, -0x0FFF8);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, -0x0FFF1);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x0FFF1);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x0FFF8);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x17FE8);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, -0x17FF0);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, -0x17FE9);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x17FE9);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x17FF0);
+  __ LoadFromOffset(mips::kLoadSignedHalfword, mips::A3, mips::A1, +0x12345678);
+
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, -0x8000);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x7FF8);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x7FFB);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x7FFC);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x7FFF);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, -0xFFF0);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, -0x8008);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, -0x8001);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x8000);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0xFFF0);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, -0x17FE8);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, -0x0FFF8);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, -0x0FFF1);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x0FFF1);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x0FFF8);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x17FE8);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, -0x17FF0);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, -0x17FE9);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x17FE9);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x17FF0);
+  __ LoadFromOffset(mips::kLoadUnsignedHalfword, mips::A3, mips::A1, +0x12345678);
+
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, -0x8000);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x7FF8);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x7FFB);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x7FFC);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x7FFF);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, -0xFFF0);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, -0x8008);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, -0x8001);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x8000);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0xFFF0);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, -0x17FE8);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, -0x0FFF8);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, -0x0FFF1);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x0FFF1);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x0FFF8);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x17FE8);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, -0x17FF0);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, -0x17FE9);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x17FE9);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x17FF0);
+  __ LoadFromOffset(mips::kLoadWord, mips::A3, mips::A1, +0x12345678);
+
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -0x8000);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x7FF8);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x7FFB);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x7FFC);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x7FFF);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -0xFFF0);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -0x8008);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -0x8001);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x8000);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0xFFF0);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -0x17FE8);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -0x0FFF8);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -0x0FFF1);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x0FFF1);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x0FFF8);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x17FE8);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -0x17FF0);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, -0x17FE9);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x17FE9);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x17FF0);
+  __ LoadFromOffset(mips::kLoadDoubleword, mips::A0, mips::A2, +0x12345678);
+
+  const char* expected =
+      "lb $a3, -0x8000($a1)\n"
+      "lb $a3, 0($a1)\n"
+      "lb $a3, 0x7FF8($a1)\n"
+      "lb $a3, 0x7FFB($a1)\n"
+      "lb $a3, 0x7FFC($a1)\n"
+      "lb $a3, 0x7FFF($a1)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lb $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lb $a3, -0x10($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lb $a3, -9($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lb $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lb $a3, 0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lb $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lb $a3, -8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lb $a3, -1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lb $a3, 1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lb $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lb $a3, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "lh $a0, 0($at)\n"
-      "lui $at, 1\n"
+      "lb $a3, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "lh $a0, 0($at)\n"
+      "lb $a3, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a1\n"
+      "lb $a3, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a1\n"
+      "lb $a3, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a1\n"
-      "lh $a0, 0($at)\n"
-      "lh $a0, -256($a1)\n"
-      "lh $a0, 0xFFFF8000($a1)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a1\n"
-      "lh $a0, 0($at)\n"
+      "lb $a3, 0($at)\n"
 
-      "lhu $a0, 0($a0)\n"
-      "lhu $a0, 0($a1)\n"
-      "lhu $a0, 256($a1)\n"
-      "lhu $a0, 1000($a1)\n"
-      "ori $at, $zero, 0x8000\n"
+      "lbu $a3, -0x8000($a1)\n"
+      "lbu $a3, 0($a1)\n"
+      "lbu $a3, 0x7FF8($a1)\n"
+      "lbu $a3, 0x7FFB($a1)\n"
+      "lbu $a3, 0x7FFC($a1)\n"
+      "lbu $a3, 0x7FFF($a1)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lbu $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lbu $a3, -0x10($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lbu $a3, -9($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lbu $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lbu $a3, 0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lbu $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lbu $a3, -8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lbu $a3, -1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lbu $a3, 1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lbu $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lbu $a3, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "lhu $a0, 0($at)\n"
-      "lui $at, 1\n"
+      "lbu $a3, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "lhu $a0, 0($at)\n"
+      "lbu $a3, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a1\n"
+      "lbu $a3, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a1\n"
+      "lbu $a3, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a1\n"
-      "lhu $a0, 0($at)\n"
-      "lhu $a0, -256($a1)\n"
-      "lhu $a0, 0xFFFF8000($a1)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a1\n"
-      "lhu $a0, 0($at)\n"
+      "lbu $a3, 0($at)\n"
 
-      "lw $a0, 0($a0)\n"
-      "lw $a0, 0($a1)\n"
-      "lw $a0, 256($a1)\n"
-      "lw $a0, 1000($a1)\n"
-      "ori $at, $zero, 0x8000\n"
+      "lh $a3, -0x8000($a1)\n"
+      "lh $a3, 0($a1)\n"
+      "lh $a3, 0x7FF8($a1)\n"
+      "lh $a3, 0x7FFB($a1)\n"
+      "lh $a3, 0x7FFC($a1)\n"
+      "lh $a3, 0x7FFF($a1)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lh $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lh $a3, -0x10($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lh $a3, -9($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lh $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lh $a3, 0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lh $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lh $a3, -8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lh $a3, -1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lh $a3, 1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lh $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lh $a3, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "lw $a0, 0($at)\n"
-      "lui $at, 1\n"
+      "lh $a3, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "lw $a0, 0($at)\n"
+      "lh $a3, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a1\n"
+      "lh $a3, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a1\n"
+      "lh $a3, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a1\n"
-      "lw $a0, 0($at)\n"
-      "lw $a0, -256($a1)\n"
-      "lw $a0, 0xFFFF8000($a1)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a1\n"
-      "lw $a0, 0($at)\n"
+      "lh $a3, 0($at)\n"
 
-      "lw $a1, 4($a0)\n"
-      "lw $a0, 0($a0)\n"
-      "lw $a0, 0($a1)\n"
-      "lw $a1, 4($a1)\n"
-      "lw $a1, 0($a0)\n"
-      "lw $a2, 4($a0)\n"
+      "lhu $a3, -0x8000($a1)\n"
+      "lhu $a3, 0($a1)\n"
+      "lhu $a3, 0x7FF8($a1)\n"
+      "lhu $a3, 0x7FFB($a1)\n"
+      "lhu $a3, 0x7FFC($a1)\n"
+      "lhu $a3, 0x7FFF($a1)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lhu $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lhu $a3, -0x10($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lhu $a3, -9($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lhu $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lhu $a3, 0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lhu $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lhu $a3, -8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lhu $a3, -1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lhu $a3, 1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lhu $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lhu $a3, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
+      "addu $at, $at, $a1\n"
+      "lhu $a3, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
+      "addu $at, $at, $a1\n"
+      "lhu $a3, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a1\n"
+      "lhu $a3, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a1\n"
+      "lhu $a3, 0($at)\n"
+      "lui $at, 0x1234\n"
+      "ori $at, $at, 0x5678\n"
+      "addu $at, $at, $a1\n"
+      "lhu $a3, 0($at)\n"
+
+      "lw $a3, -0x8000($a1)\n"
+      "lw $a3, 0($a1)\n"
+      "lw $a3, 0x7FF8($a1)\n"
+      "lw $a3, 0x7FFB($a1)\n"
+      "lw $a3, 0x7FFC($a1)\n"
+      "lw $a3, 0x7FFF($a1)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lw $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lw $a3, -0x10($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "lw $a3, -9($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lw $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "lw $a3, 0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lw $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lw $a3, -8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lw $a3, -1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lw $a3, 1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lw $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lw $a3, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
+      "addu $at, $at, $a1\n"
+      "lw $a3, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
+      "addu $at, $at, $a1\n"
+      "lw $a3, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a1\n"
+      "lw $a3, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a1\n"
+      "lw $a3, 0($at)\n"
+      "lui $at, 0x1234\n"
+      "ori $at, $at, 0x5678\n"
+      "addu $at, $at, $a1\n"
+      "lw $a3, 0($at)\n"
+
+      "lw $a0, -0x8000($a2)\n"
+      "lw $a1, -0x7FFC($a2)\n"
       "lw $a0, 0($a2)\n"
       "lw $a1, 4($a2)\n"
-      "lw $a0, 256($a2)\n"
-      "lw $a1, 260($a2)\n"
-      "lw $a0, 1000($a2)\n"
-      "lw $a1, 1004($a2)\n"
-      "ori $at, $zero, 0x8000\n"
+      "lw $a0, 0x7FF8($a2)\n"
+      "lw $a1, 0x7FFC($a2)\n"
+      "lw $a0, 0x7FFB($a2)\n"
+      "lw $a1, 0x7FFF($a2)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "lw $a0, 4($at)\n"
+      "lw $a1, 8($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "lw $a0, 7($at)\n"
+      "lw $a1, 11($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "lw $a0, -0x7FF8($at)\n"
+      "lw $a1, -0x7FF4($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "lw $a0, -0x10($at)\n"
+      "lw $a1, -0xC($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "lw $a0, -9($at)\n"
+      "lw $a1, -5($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "lw $a0, 8($at)\n"
+      "lw $a1, 12($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "lw $a0, 0x7FF8($at)\n"
+      "lw $a1, 0x7FFC($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lw $a0, -0x7FF8($at)\n"
+      "lw $a1, -0x7FF4($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lw $a0, -8($at)\n"
+      "lw $a1, -4($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lw $a0, -1($at)\n"
+      "lw $a1, 3($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lw $a0, 1($at)\n"
+      "lw $a1, 5($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lw $a0, 8($at)\n"
+      "lw $a1, 12($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lw $a0, 0x7FF8($at)\n"
+      "lw $a1, 0x7FFC($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a2\n"
       "lw $a0, 0($at)\n"
       "lw $a1, 4($at)\n"
-      "lui $at, 1\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
+      "addu $at, $at, $a2\n"
+      "lw $a0, 7($at)\n"
+      "lw $a1, 11($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a2\n"
+      "lw $a0, 1($at)\n"
+      "lw $a1, 5($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
       "addu $at, $at, $a2\n"
       "lw $a0, 0($at)\n"
       "lw $a1, 4($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
-      "addu $at, $at, $a2\n"
-      "lw $a0, 0($at)\n"
-      "lw $a1, 4($at)\n"
-      "lw $a0, -256($a2)\n"
-      "lw $a1, -252($a2)\n"
-      "lw $a0, 0xFFFF8000($a2)\n"
-      "lw $a1, 0xFFFF8004($a2)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a2\n"
       "lw $a0, 0($at)\n"
       "lw $a1, 4($at)\n";
@@ -936,208 +1262,513 @@
 }
 
 TEST_F(AssemblerMIPSTest, LoadSFromOffset) {
-  __ LoadSFromOffset(mips::F0, mips::A0, 0);
-  __ LoadSFromOffset(mips::F0, mips::A0, 4);
-  __ LoadSFromOffset(mips::F0, mips::A0, 256);
-  __ LoadSFromOffset(mips::F0, mips::A0, 0x8000);
-  __ LoadSFromOffset(mips::F0, mips::A0, 0x10000);
-  __ LoadSFromOffset(mips::F0, mips::A0, 0x12345678);
-  __ LoadSFromOffset(mips::F0, mips::A0, -256);
-  __ LoadSFromOffset(mips::F0, mips::A0, 0xFFFF8000);
-  __ LoadSFromOffset(mips::F0, mips::A0, 0xABCDEF00);
+  __ LoadSFromOffset(mips::F2, mips::A0, -0x8000);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x7FF8);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x7FFB);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x7FFC);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x7FFF);
+  __ LoadSFromOffset(mips::F2, mips::A0, -0xFFF0);
+  __ LoadSFromOffset(mips::F2, mips::A0, -0x8008);
+  __ LoadSFromOffset(mips::F2, mips::A0, -0x8001);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x8000);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0xFFF0);
+  __ LoadSFromOffset(mips::F2, mips::A0, -0x17FE8);
+  __ LoadSFromOffset(mips::F2, mips::A0, -0x0FFF8);
+  __ LoadSFromOffset(mips::F2, mips::A0, -0x0FFF1);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x0FFF1);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x0FFF8);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x17FE8);
+  __ LoadSFromOffset(mips::F2, mips::A0, -0x17FF0);
+  __ LoadSFromOffset(mips::F2, mips::A0, -0x17FE9);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x17FE9);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x17FF0);
+  __ LoadSFromOffset(mips::F2, mips::A0, +0x12345678);
 
   const char* expected =
-      "lwc1 $f0, 0($a0)\n"
-      "lwc1 $f0, 4($a0)\n"
-      "lwc1 $f0, 256($a0)\n"
-      "ori $at, $zero, 0x8000\n"
+      "lwc1 $f2, -0x8000($a0)\n"
+      "lwc1 $f2, 0($a0)\n"
+      "lwc1 $f2, 0x7FF8($a0)\n"
+      "lwc1 $f2, 0x7FFB($a0)\n"
+      "lwc1 $f2, 0x7FFC($a0)\n"
+      "lwc1 $f2, 0x7FFF($a0)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "lwc1 $f2, -0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "lwc1 $f2, -0x10($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "lwc1 $f2, -9($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "lwc1 $f2, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "lwc1 $f2, 0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lwc1 $f2, -0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lwc1 $f2, -8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lwc1 $f2, -1($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lwc1 $f2, 1($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lwc1 $f2, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lwc1 $f2, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a0\n"
-      "lwc1 $f0, 0($at)\n"
-      "lui $at, 1\n"
+      "lwc1 $f2, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a0\n"
-      "lwc1 $f0, 0($at)\n"
+      "lwc1 $f2, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a0\n"
+      "lwc1 $f2, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a0\n"
+      "lwc1 $f2, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a0\n"
-      "lwc1 $f0, 0($at)\n"
-      "lwc1 $f0, -256($a0)\n"
-      "lwc1 $f0, 0xFFFF8000($a0)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a0\n"
-      "lwc1 $f0, 0($at)\n";
+      "lwc1 $f2, 0($at)\n";
   DriverStr(expected, "LoadSFromOffset");
 }
 
-
 TEST_F(AssemblerMIPSTest, LoadDFromOffset) {
-  __ LoadDFromOffset(mips::F0, mips::A0, 0);
-  __ LoadDFromOffset(mips::F0, mips::A0, 4);
-  __ LoadDFromOffset(mips::F0, mips::A0, 256);
-  __ LoadDFromOffset(mips::F0, mips::A0, 0x8000);
-  __ LoadDFromOffset(mips::F0, mips::A0, 0x10000);
-  __ LoadDFromOffset(mips::F0, mips::A0, 0x12345678);
-  __ LoadDFromOffset(mips::F0, mips::A0, -256);
-  __ LoadDFromOffset(mips::F0, mips::A0, 0xFFFF8000);
-  __ LoadDFromOffset(mips::F0, mips::A0, 0xABCDEF00);
+  __ LoadDFromOffset(mips::F0, mips::A0, -0x8000);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x7FF8);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x7FFB);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x7FFC);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x7FFF);
+  __ LoadDFromOffset(mips::F0, mips::A0, -0xFFF0);
+  __ LoadDFromOffset(mips::F0, mips::A0, -0x8008);
+  __ LoadDFromOffset(mips::F0, mips::A0, -0x8001);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x8000);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0xFFF0);
+  __ LoadDFromOffset(mips::F0, mips::A0, -0x17FE8);
+  __ LoadDFromOffset(mips::F0, mips::A0, -0x0FFF8);
+  __ LoadDFromOffset(mips::F0, mips::A0, -0x0FFF1);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x0FFF1);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x0FFF8);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x17FE8);
+  __ LoadDFromOffset(mips::F0, mips::A0, -0x17FF0);
+  __ LoadDFromOffset(mips::F0, mips::A0, -0x17FE9);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x17FE9);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x17FF0);
+  __ LoadDFromOffset(mips::F0, mips::A0, +0x12345678);
 
   const char* expected =
+      "ldc1 $f0, -0x8000($a0)\n"
       "ldc1 $f0, 0($a0)\n"
-      "lwc1 $f0, 4($a0)\n"
-      "lwc1 $f1, 8($a0)\n"
-      "ldc1 $f0, 256($a0)\n"
-      "ori $at, $zero, 0x8000\n"
+      "ldc1 $f0, 0x7FF8($a0)\n"
+      "lwc1 $f0, 0x7FFB($a0)\n"
+      "lwc1 $f1, 0x7FFF($a0)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "lwc1 $f0, 4($at)\n"
+      "lwc1 $f1, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "lwc1 $f0, 7($at)\n"
+      "lwc1 $f1, 11($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "ldc1 $f0, -0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "ldc1 $f0, -0x10($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "lwc1 $f0, -9($at)\n"
+      "lwc1 $f1, -5($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "ldc1 $f0, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "ldc1 $f0, 0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "ldc1 $f0, -0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "ldc1 $f0, -8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "lwc1 $f0, -1($at)\n"
+      "lwc1 $f1, 3($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "lwc1 $f0, 1($at)\n"
+      "lwc1 $f1, 5($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "ldc1 $f0, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "ldc1 $f0, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a0\n"
       "ldc1 $f0, 0($at)\n"
-      "lui $at, 1\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
+      "addu $at, $at, $a0\n"
+      "lwc1 $f0, 7($at)\n"
+      "lwc1 $f1, 11($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a0\n"
+      "lwc1 $f0, 1($at)\n"
+      "lwc1 $f1, 5($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
       "addu $at, $at, $a0\n"
       "ldc1 $f0, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
-      "addu $at, $at, $a0\n"
-      "ldc1 $f0, 0($at)\n"
-      "ldc1 $f0, -256($a0)\n"
-      "ldc1 $f0, 0xFFFF8000($a0)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a0\n"
       "ldc1 $f0, 0($at)\n";
   DriverStr(expected, "LoadDFromOffset");
 }
 
 TEST_F(AssemblerMIPSTest, StoreToOffset) {
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A0, 0);
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A1, 0);
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A1, 256);
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A1, 1000);
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A1, 0x8000);
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A1, 0x10000);
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A1, 0x12345678);
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A1, -256);
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A1, 0xFFFF8000);
-  __ StoreToOffset(mips::kStoreByte, mips::A0, mips::A1, 0xABCDEF00);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, -0x8000);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x7FF8);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x7FFB);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x7FFC);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x7FFF);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, -0xFFF0);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, -0x8008);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, -0x8001);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x8000);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0xFFF0);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, -0x17FE8);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, -0x0FFF8);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, -0x0FFF1);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x0FFF1);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x0FFF8);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x17FE8);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, -0x17FF0);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, -0x17FE9);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x17FE9);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x17FF0);
+  __ StoreToOffset(mips::kStoreByte, mips::A3, mips::A1, +0x12345678);
 
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A0, 0);
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A1, 0);
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A1, 256);
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A1, 1000);
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A1, 0x8000);
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A1, 0x10000);
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A1, 0x12345678);
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A1, -256);
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A1, 0xFFFF8000);
-  __ StoreToOffset(mips::kStoreHalfword, mips::A0, mips::A1, 0xABCDEF00);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, -0x8000);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x7FF8);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x7FFB);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x7FFC);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x7FFF);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, -0xFFF0);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, -0x8008);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, -0x8001);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x8000);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0xFFF0);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, -0x17FE8);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, -0x0FFF8);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, -0x0FFF1);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x0FFF1);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x0FFF8);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x17FE8);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, -0x17FF0);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, -0x17FE9);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x17FE9);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x17FF0);
+  __ StoreToOffset(mips::kStoreHalfword, mips::A3, mips::A1, +0x12345678);
 
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A0, 0);
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A1, 0);
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A1, 256);
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A1, 1000);
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A1, 0x8000);
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A1, 0x10000);
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A1, 0x12345678);
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A1, -256);
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A1, 0xFFFF8000);
-  __ StoreToOffset(mips::kStoreWord, mips::A0, mips::A1, 0xABCDEF00);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, -0x8000);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x7FF8);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x7FFB);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x7FFC);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x7FFF);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, -0xFFF0);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, -0x8008);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, -0x8001);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x8000);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0xFFF0);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, -0x17FE8);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, -0x0FFF8);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, -0x0FFF1);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x0FFF1);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x0FFF8);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x17FE8);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, -0x17FF0);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, -0x17FE9);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x17FE9);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x17FF0);
+  __ StoreToOffset(mips::kStoreWord, mips::A3, mips::A1, +0x12345678);
 
-  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, 0);
-  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, 256);
-  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, 1000);
-  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, 0x8000);
-  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, 0x10000);
-  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, 0x12345678);
-  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -256);
-  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, 0xFFFF8000);
-  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, 0xABCDEF00);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -0x8000);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x7FF8);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x7FFB);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x7FFC);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x7FFF);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -0xFFF0);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -0x8008);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -0x8001);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x8000);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0xFFF0);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -0x17FE8);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -0x0FFF8);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -0x0FFF1);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x0FFF1);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x0FFF8);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x17FE8);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -0x17FF0);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, -0x17FE9);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x17FE9);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x17FF0);
+  __ StoreToOffset(mips::kStoreDoubleword, mips::A0, mips::A2, +0x12345678);
 
   const char* expected =
-      "sb $a0, 0($a0)\n"
-      "sb $a0, 0($a1)\n"
-      "sb $a0, 256($a1)\n"
-      "sb $a0, 1000($a1)\n"
-      "ori $at, $zero, 0x8000\n"
+      "sb $a3, -0x8000($a1)\n"
+      "sb $a3, 0($a1)\n"
+      "sb $a3, 0x7FF8($a1)\n"
+      "sb $a3, 0x7FFB($a1)\n"
+      "sb $a3, 0x7FFC($a1)\n"
+      "sb $a3, 0x7FFF($a1)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "sb $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "sb $a3, -0x10($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "sb $a3, -9($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "sb $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "sb $a3, 0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sb $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sb $a3, -8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sb $a3, -1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sb $a3, 1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sb $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sb $a3, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "sb $a0, 0($at)\n"
-      "lui $at, 1\n"
+      "sb $a3, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "sb $a0, 0($at)\n"
+      "sb $a3, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a1\n"
+      "sb $a3, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a1\n"
+      "sb $a3, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a1\n"
-      "sb $a0, 0($at)\n"
-      "sb $a0, -256($a1)\n"
-      "sb $a0, 0xFFFF8000($a1)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a1\n"
-      "sb $a0, 0($at)\n"
+      "sb $a3, 0($at)\n"
 
-      "sh $a0, 0($a0)\n"
-      "sh $a0, 0($a1)\n"
-      "sh $a0, 256($a1)\n"
-      "sh $a0, 1000($a1)\n"
-      "ori $at, $zero, 0x8000\n"
+      "sh $a3, -0x8000($a1)\n"
+      "sh $a3, 0($a1)\n"
+      "sh $a3, 0x7FF8($a1)\n"
+      "sh $a3, 0x7FFB($a1)\n"
+      "sh $a3, 0x7FFC($a1)\n"
+      "sh $a3, 0x7FFF($a1)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "sh $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "sh $a3, -0x10($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "sh $a3, -9($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "sh $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "sh $a3, 0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sh $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sh $a3, -8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sh $a3, -1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sh $a3, 1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sh $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sh $a3, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "sh $a0, 0($at)\n"
-      "lui $at, 1\n"
+      "sh $a3, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "sh $a0, 0($at)\n"
+      "sh $a3, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a1\n"
+      "sh $a3, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a1\n"
+      "sh $a3, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a1\n"
-      "sh $a0, 0($at)\n"
-      "sh $a0, -256($a1)\n"
-      "sh $a0, 0xFFFF8000($a1)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a1\n"
-      "sh $a0, 0($at)\n"
+      "sh $a3, 0($at)\n"
 
-      "sw $a0, 0($a0)\n"
-      "sw $a0, 0($a1)\n"
-      "sw $a0, 256($a1)\n"
-      "sw $a0, 1000($a1)\n"
-      "ori $at, $zero, 0x8000\n"
+      "sw $a3, -0x8000($a1)\n"
+      "sw $a3, 0($a1)\n"
+      "sw $a3, 0x7FF8($a1)\n"
+      "sw $a3, 0x7FFB($a1)\n"
+      "sw $a3, 0x7FFC($a1)\n"
+      "sw $a3, 0x7FFF($a1)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "sw $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "sw $a3, -0x10($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "sw $a3, -9($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "sw $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "sw $a3, 0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sw $a3, -0x7FF8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sw $a3, -8($at)\n"
+      "addiu $at, $a1, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sw $a3, -1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sw $a3, 1($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sw $a3, 8($at)\n"
+      "addiu $at, $a1, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sw $a3, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "sw $a0, 0($at)\n"
-      "lui $at, 1\n"
+      "sw $a3, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a1\n"
-      "sw $a0, 0($at)\n"
+      "sw $a3, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a1\n"
+      "sw $a3, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a1\n"
+      "sw $a3, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a1\n"
-      "sw $a0, 0($at)\n"
-      "sw $a0, -256($a1)\n"
-      "sw $a0, 0xFFFF8000($a1)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a1\n"
-      "sw $a0, 0($at)\n"
+      "sw $a3, 0($at)\n"
 
+      "sw $a0, -0x8000($a2)\n"
+      "sw $a1, -0x7FFC($a2)\n"
       "sw $a0, 0($a2)\n"
       "sw $a1, 4($a2)\n"
-      "sw $a0, 256($a2)\n"
-      "sw $a1, 260($a2)\n"
-      "sw $a0, 1000($a2)\n"
-      "sw $a1, 1004($a2)\n"
-      "ori $at, $zero, 0x8000\n"
+      "sw $a0, 0x7FF8($a2)\n"
+      "sw $a1, 0x7FFC($a2)\n"
+      "sw $a0, 0x7FFB($a2)\n"
+      "sw $a1, 0x7FFF($a2)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "sw $a0, 4($at)\n"
+      "sw $a1, 8($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "sw $a0, 7($at)\n"
+      "sw $a1, 11($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "sw $a0, -0x7FF8($at)\n"
+      "sw $a1, -0x7FF4($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "sw $a0, -0x10($at)\n"
+      "sw $a1, -0xC($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "sw $a0, -9($at)\n"
+      "sw $a1, -5($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "sw $a0, 8($at)\n"
+      "sw $a1, 12($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "sw $a0, 0x7FF8($at)\n"
+      "sw $a1, 0x7FFC($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sw $a0, -0x7FF8($at)\n"
+      "sw $a1, -0x7FF4($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sw $a0, -8($at)\n"
+      "sw $a1, -4($at)\n"
+      "addiu $at, $a2, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sw $a0, -1($at)\n"
+      "sw $a1, 3($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sw $a0, 1($at)\n"
+      "sw $a1, 5($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sw $a0, 8($at)\n"
+      "sw $a1, 12($at)\n"
+      "addiu $at, $a2, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sw $a0, 0x7FF8($at)\n"
+      "sw $a1, 0x7FFC($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a2\n"
       "sw $a0, 0($at)\n"
       "sw $a1, 4($at)\n"
-      "lui $at, 1\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
+      "addu $at, $at, $a2\n"
+      "sw $a0, 7($at)\n"
+      "sw $a1, 11($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a2\n"
+      "sw $a0, 1($at)\n"
+      "sw $a1, 5($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
       "addu $at, $at, $a2\n"
       "sw $a0, 0($at)\n"
       "sw $a1, 4($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
-      "addu $at, $at, $a2\n"
-      "sw $a0, 0($at)\n"
-      "sw $a1, 4($at)\n"
-      "sw $a0, -256($a2)\n"
-      "sw $a1, -252($a2)\n"
-      "sw $a0, 0xFFFF8000($a2)\n"
-      "sw $a1, 0xFFFF8004($a2)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a2\n"
       "sw $a0, 0($at)\n"
       "sw $a1, 4($at)\n";
@@ -1145,69 +1776,174 @@
 }
 
 TEST_F(AssemblerMIPSTest, StoreSToOffset) {
-  __ StoreSToOffset(mips::F0, mips::A0, 0);
-  __ StoreSToOffset(mips::F0, mips::A0, 4);
-  __ StoreSToOffset(mips::F0, mips::A0, 256);
-  __ StoreSToOffset(mips::F0, mips::A0, 0x8000);
-  __ StoreSToOffset(mips::F0, mips::A0, 0x10000);
-  __ StoreSToOffset(mips::F0, mips::A0, 0x12345678);
-  __ StoreSToOffset(mips::F0, mips::A0, -256);
-  __ StoreSToOffset(mips::F0, mips::A0, 0xFFFF8000);
-  __ StoreSToOffset(mips::F0, mips::A0, 0xABCDEF00);
+  __ StoreSToOffset(mips::F2, mips::A0, -0x8000);
+  __ StoreSToOffset(mips::F2, mips::A0, +0);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x7FF8);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x7FFB);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x7FFC);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x7FFF);
+  __ StoreSToOffset(mips::F2, mips::A0, -0xFFF0);
+  __ StoreSToOffset(mips::F2, mips::A0, -0x8008);
+  __ StoreSToOffset(mips::F2, mips::A0, -0x8001);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x8000);
+  __ StoreSToOffset(mips::F2, mips::A0, +0xFFF0);
+  __ StoreSToOffset(mips::F2, mips::A0, -0x17FE8);
+  __ StoreSToOffset(mips::F2, mips::A0, -0x0FFF8);
+  __ StoreSToOffset(mips::F2, mips::A0, -0x0FFF1);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x0FFF1);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x0FFF8);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x17FE8);
+  __ StoreSToOffset(mips::F2, mips::A0, -0x17FF0);
+  __ StoreSToOffset(mips::F2, mips::A0, -0x17FE9);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x17FE9);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x17FF0);
+  __ StoreSToOffset(mips::F2, mips::A0, +0x12345678);
 
   const char* expected =
-      "swc1 $f0, 0($a0)\n"
-      "swc1 $f0, 4($a0)\n"
-      "swc1 $f0, 256($a0)\n"
-      "ori $at, $zero, 0x8000\n"
+      "swc1 $f2, -0x8000($a0)\n"
+      "swc1 $f2, 0($a0)\n"
+      "swc1 $f2, 0x7FF8($a0)\n"
+      "swc1 $f2, 0x7FFB($a0)\n"
+      "swc1 $f2, 0x7FFC($a0)\n"
+      "swc1 $f2, 0x7FFF($a0)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "swc1 $f2, -0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "swc1 $f2, -0x10($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "swc1 $f2, -9($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "swc1 $f2, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "swc1 $f2, 0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "swc1 $f2, -0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "swc1 $f2, -8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "swc1 $f2, -1($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "swc1 $f2, 1($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "swc1 $f2, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "swc1 $f2, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a0\n"
-      "swc1 $f0, 0($at)\n"
-      "lui $at, 1\n"
+      "swc1 $f2, 0($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a0\n"
-      "swc1 $f0, 0($at)\n"
+      "swc1 $f2, 7($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a0\n"
+      "swc1 $f2, 1($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
+      "addu $at, $at, $a0\n"
+      "swc1 $f2, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a0\n"
-      "swc1 $f0, 0($at)\n"
-      "swc1 $f0, -256($a0)\n"
-      "swc1 $f0, 0xFFFF8000($a0)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
-      "addu $at, $at, $a0\n"
-      "swc1 $f0, 0($at)\n";
+      "swc1 $f2, 0($at)\n";
   DriverStr(expected, "StoreSToOffset");
 }
 
 TEST_F(AssemblerMIPSTest, StoreDToOffset) {
-  __ StoreDToOffset(mips::F0, mips::A0, 0);
-  __ StoreDToOffset(mips::F0, mips::A0, 4);
-  __ StoreDToOffset(mips::F0, mips::A0, 256);
-  __ StoreDToOffset(mips::F0, mips::A0, 0x8000);
-  __ StoreDToOffset(mips::F0, mips::A0, 0x10000);
-  __ StoreDToOffset(mips::F0, mips::A0, 0x12345678);
-  __ StoreDToOffset(mips::F0, mips::A0, -256);
-  __ StoreDToOffset(mips::F0, mips::A0, 0xFFFF8000);
-  __ StoreDToOffset(mips::F0, mips::A0, 0xABCDEF00);
+  __ StoreDToOffset(mips::F0, mips::A0, -0x8000);
+  __ StoreDToOffset(mips::F0, mips::A0, +0);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x7FF8);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x7FFB);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x7FFC);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x7FFF);
+  __ StoreDToOffset(mips::F0, mips::A0, -0xFFF0);
+  __ StoreDToOffset(mips::F0, mips::A0, -0x8008);
+  __ StoreDToOffset(mips::F0, mips::A0, -0x8001);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x8000);
+  __ StoreDToOffset(mips::F0, mips::A0, +0xFFF0);
+  __ StoreDToOffset(mips::F0, mips::A0, -0x17FE8);
+  __ StoreDToOffset(mips::F0, mips::A0, -0x0FFF8);
+  __ StoreDToOffset(mips::F0, mips::A0, -0x0FFF1);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x0FFF1);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x0FFF8);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x17FE8);
+  __ StoreDToOffset(mips::F0, mips::A0, -0x17FF0);
+  __ StoreDToOffset(mips::F0, mips::A0, -0x17FE9);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x17FE9);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x17FF0);
+  __ StoreDToOffset(mips::F0, mips::A0, +0x12345678);
 
   const char* expected =
+      "sdc1 $f0, -0x8000($a0)\n"
       "sdc1 $f0, 0($a0)\n"
-      "swc1 $f0, 4($a0)\n"
-      "swc1 $f1, 8($a0)\n"
-      "sdc1 $f0, 256($a0)\n"
-      "ori $at, $zero, 0x8000\n"
+      "sdc1 $f0, 0x7FF8($a0)\n"
+      "swc1 $f0, 0x7FFB($a0)\n"
+      "swc1 $f1, 0x7FFF($a0)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "swc1 $f0, 4($at)\n"
+      "swc1 $f1, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "swc1 $f0, 7($at)\n"
+      "swc1 $f1, 11($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "sdc1 $f0, -0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "sdc1 $f0, -0x10($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "swc1 $f0, -9($at)\n"
+      "swc1 $f1, -5($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "sdc1 $f0, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "sdc1 $f0, 0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sdc1 $f0, -0x7FF8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "sdc1 $f0, -8($at)\n"
+      "addiu $at, $a0, -0x7FF8\n"
+      "addiu $at, $at, -0x7FF8\n"
+      "swc1 $f0, -1($at)\n"
+      "swc1 $f1, 3($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "swc1 $f0, 1($at)\n"
+      "swc1 $f1, 5($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sdc1 $f0, 8($at)\n"
+      "addiu $at, $a0, 0x7FF8\n"
+      "addiu $at, $at, 0x7FF8\n"
+      "sdc1 $f0, 0x7FF8($at)\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
       "addu $at, $at, $a0\n"
       "sdc1 $f0, 0($at)\n"
-      "lui $at, 1\n"
+      "lui $at, 0xFFFE\n"
+      "ori $at, $at, 0x8010\n"
+      "addu $at, $at, $a0\n"
+      "swc1 $f0, 7($at)\n"
+      "swc1 $f1, 11($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FE8\n"
+      "addu $at, $at, $a0\n"
+      "swc1 $f0, 1($at)\n"
+      "swc1 $f1, 5($at)\n"
+      "lui $at, 0x1\n"
+      "ori $at, $at, 0x7FF0\n"
       "addu $at, $at, $a0\n"
       "sdc1 $f0, 0($at)\n"
       "lui $at, 0x1234\n"
-      "ori $at, 0x5678\n"
-      "addu $at, $at, $a0\n"
-      "sdc1 $f0, 0($at)\n"
-      "sdc1 $f0, -256($a0)\n"
-      "sdc1 $f0, 0xFFFF8000($a0)\n"
-      "lui $at, 0xABCD\n"
-      "ori $at, 0xEF00\n"
+      "ori $at, $at, 0x5678\n"
       "addu $at, $at, $a0\n"
       "sdc1 $f0, 0($at)\n";
   DriverStr(expected, "StoreDToOffset");