From f58b24831f7203e248798dce4c62bf61c51ba15d Mon Sep 17 00:00:00 2001 From: Alexey Frunze Date: Fri, 2 Sep 2016 22:14:06 -0700 Subject: [PATCH] MIPS32: Improve storing of constants in fields and array elements Test: booted MIPS32 in QEMU Test: test-art-target-run-test-optimizing on CI20 Test: test-art-host-gtest Change-Id: Ifcf8c1e215e3768711c391e8da6f663bba71f8d9 --- compiler/optimizing/code_generator_mips.cc | 185 +++++++++++++++++------------ compiler/optimizing/code_generator_mips.h | 2 + compiler/utils/mips/assembler_mips.h | 83 +++++++------ compiler/utils/mips/assembler_mips_test.cc | 79 ++++++++++++ 4 files changed, 241 insertions(+), 108 deletions(-) diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index b767aa5ef..aa81bad3d 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -905,7 +905,7 @@ void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) { } else { DCHECK(destination.IsStackSlot()) << "Cannot move " << c->DebugName() << " to " << destination; - __ StoreConst32ToOffset(value, SP, destination.GetStackIndex(), TMP); + __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP); } } else if (c->IsLongConstant()) { // Move 64 bit constant. @@ -917,7 +917,7 @@ void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) { } else { DCHECK(destination.IsDoubleStackSlot()) << "Cannot move " << c->DebugName() << " to " << destination; - __ StoreConst64ToOffset(value, SP, destination.GetStackIndex(), TMP); + __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP); } } else if (c->IsFloatConstant()) { // Move 32 bit float constant. @@ -927,7 +927,7 @@ void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) { } else { DCHECK(destination.IsStackSlot()) << "Cannot move " << c->DebugName() << " to " << destination; - __ StoreConst32ToOffset(value, SP, destination.GetStackIndex(), TMP); + __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP); } } else { // Move 64 bit double constant. @@ -939,7 +939,7 @@ void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) { } else { DCHECK(destination.IsDoubleStackSlot()) << "Cannot move " << c->DebugName() << " to " << destination; - __ StoreConst64ToOffset(value, SP, destination.GetStackIndex(), TMP); + __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP); } } } @@ -1960,6 +1960,25 @@ void InstructionCodeGeneratorMIPS::VisitArrayLength(HArrayLength* instruction) { codegen_->MaybeRecordImplicitNullCheck(instruction); } +Location LocationsBuilderMIPS::RegisterOrZeroConstant(HInstruction* instruction) { + return (instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern()) + ? Location::ConstantLocation(instruction->AsConstant()) + : Location::RequiresRegister(); +} + +Location LocationsBuilderMIPS::FpuRegisterOrConstantForStore(HInstruction* instruction) { + // We can store 0.0 directly (from the ZERO register) without loading it into an FPU register. + // We can store a non-zero float or double constant without first loading it into the FPU, + // but we should only prefer this if the constant has a single use. + if (instruction->IsConstant() && + (instruction->AsConstant()->IsZeroBitPattern() || + instruction->GetUses().HasExactlyOneElement())) { + return Location::ConstantLocation(instruction->AsConstant()); + // Otherwise fall through and require an FPU register for the constant. + } + return Location::RequiresFpuRegister(); +} + void LocationsBuilderMIPS::VisitArraySet(HArraySet* instruction) { bool needs_runtime_call = instruction->NeedsTypeCheck(); LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( @@ -1974,9 +1993,9 @@ void LocationsBuilderMIPS::VisitArraySet(HArraySet* instruction) { locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) { - locations->SetInAt(2, Location::RequiresFpuRegister()); + locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2))); } else { - locations->SetInAt(2, Location::RequiresRegister()); + locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2))); } } } @@ -1985,24 +2004,29 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) { LocationSummary* locations = instruction->GetLocations(); Register obj = locations->InAt(0).AsRegister(); Location index = locations->InAt(1); + Location value_location = locations->InAt(2); Primitive::Type value_type = instruction->GetComponentType(); bool needs_runtime_call = locations->WillCall(); bool needs_write_barrier = CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); auto null_checker = GetImplicitNullChecker(instruction); + Register base_reg = index.IsConstant() ? obj : TMP; switch (value_type) { case Primitive::kPrimBoolean: case Primitive::kPrimByte: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); - Register value = locations->InAt(2).AsRegister(); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; - __ StoreToOffset(kStoreByte, value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1; } else { - __ Addu(TMP, obj, index.AsRegister()); - __ StoreToOffset(kStoreByte, value, TMP, data_offset, null_checker); + __ Addu(base_reg, obj, index.AsRegister()); + } + if (value_location.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreByte, value, base_reg, data_offset, TMP, null_checker); + } else { + Register value = value_location.AsRegister(); + __ StoreToOffset(kStoreByte, value, base_reg, data_offset, null_checker); } break; } @@ -2010,15 +2034,18 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimShort: case Primitive::kPrimChar: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); - Register value = locations->InAt(2).AsRegister(); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; - __ StoreToOffset(kStoreHalfword, value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2; } else { - __ Sll(TMP, index.AsRegister(), TIMES_2); - __ Addu(TMP, obj, TMP); - __ StoreToOffset(kStoreHalfword, value, TMP, data_offset, null_checker); + __ Sll(base_reg, index.AsRegister(), TIMES_2); + __ Addu(base_reg, obj, base_reg); + } + if (value_location.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreHalfword, value, base_reg, data_offset, TMP, null_checker); + } else { + Register value = value_location.AsRegister(); + __ StoreToOffset(kStoreHalfword, value, base_reg, data_offset, null_checker); } break; } @@ -2027,20 +2054,23 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimNot: { if (!needs_runtime_call) { uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); - Register value = locations->InAt(2).AsRegister(); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; - __ StoreToOffset(kStoreWord, value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4; } else { - DCHECK(index.IsRegister()) << index; - __ Sll(TMP, index.AsRegister(), TIMES_4); - __ Addu(TMP, obj, TMP); - __ StoreToOffset(kStoreWord, value, TMP, data_offset, null_checker); + __ Sll(base_reg, index.AsRegister(), TIMES_4); + __ Addu(base_reg, obj, base_reg); } - if (needs_write_barrier) { - DCHECK_EQ(value_type, Primitive::kPrimNot); - codegen_->MarkGCCard(obj, value); + if (value_location.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker); + DCHECK(!needs_write_barrier); + } else { + Register value = value_location.AsRegister(); + __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker); + if (needs_write_barrier) { + DCHECK_EQ(value_type, Primitive::kPrimNot); + codegen_->MarkGCCard(obj, value); + } } } else { DCHECK_EQ(value_type, Primitive::kPrimNot); @@ -2052,47 +2082,54 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimLong: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); - Register value = locations->InAt(2).AsRegisterPairLow(); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; - __ StoreToOffset(kStoreDoubleword, value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8; } else { - __ Sll(TMP, index.AsRegister(), TIMES_8); - __ Addu(TMP, obj, TMP); - __ StoreToOffset(kStoreDoubleword, value, TMP, data_offset, null_checker); + __ Sll(base_reg, index.AsRegister(), TIMES_8); + __ Addu(base_reg, obj, base_reg); + } + if (value_location.IsConstant()) { + int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker); + } else { + Register value = value_location.AsRegisterPairLow(); + __ StoreToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker); } break; } case Primitive::kPrimFloat: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); - FRegister value = locations->InAt(2).AsFpuRegister(); - DCHECK(locations->InAt(2).IsFpuRegister()); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; - __ StoreSToOffset(value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4; } else { - __ Sll(TMP, index.AsRegister(), TIMES_4); - __ Addu(TMP, obj, TMP); - __ StoreSToOffset(value, TMP, data_offset, null_checker); + __ Sll(base_reg, index.AsRegister(), TIMES_4); + __ Addu(base_reg, obj, base_reg); + } + if (value_location.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker); + } else { + FRegister value = value_location.AsFpuRegister(); + __ StoreSToOffset(value, base_reg, data_offset, null_checker); } break; } case Primitive::kPrimDouble: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); - FRegister value = locations->InAt(2).AsFpuRegister(); - DCHECK(locations->InAt(2).IsFpuRegister()); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; - __ StoreDToOffset(value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8; } else { - __ Sll(TMP, index.AsRegister(), TIMES_8); - __ Addu(TMP, obj, TMP); - __ StoreDToOffset(value, TMP, data_offset, null_checker); + __ Sll(base_reg, index.AsRegister(), TIMES_8); + __ Addu(base_reg, obj, base_reg); + } + if (value_location.IsConstant()) { + int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker); + } else { + FRegister value = value_location.AsFpuRegister(); + __ StoreDToOffset(value, base_reg, data_offset, null_checker); } break; } @@ -3888,9 +3925,9 @@ void LocationsBuilderMIPS::HandleFieldSet(HInstruction* instruction, const Field } } else { if (Primitive::IsFloatingPointType(field_type)) { - locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1))); } else { - locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1))); } } } @@ -3901,6 +3938,7 @@ void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction, Primitive::Type type = field_info.GetFieldType(); LocationSummary* locations = instruction->GetLocations(); Register obj = locations->InAt(0).AsRegister(); + Location value_location = locations->InAt(1); StoreOperandType store_type = kStoreByte; bool is_volatile = field_info.IsVolatile(); uint32_t offset = field_info.GetFieldOffset().Uint32Value(); @@ -3941,24 +3979,24 @@ void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction, codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); if (type == Primitive::kPrimDouble) { // Pass FP parameters in core registers. - Location in = locations->InAt(1); - if (in.IsFpuRegister()) { - __ Mfc1(locations->GetTemp(1).AsRegister(), in.AsFpuRegister()); + if (value_location.IsFpuRegister()) { + __ Mfc1(locations->GetTemp(1).AsRegister(), + value_location.AsFpuRegister()); __ MoveFromFpuHigh(locations->GetTemp(2).AsRegister(), - in.AsFpuRegister()); - } else if (in.IsDoubleStackSlot()) { + value_location.AsFpuRegister()); + } else if (value_location.IsDoubleStackSlot()) { __ LoadFromOffset(kLoadWord, locations->GetTemp(1).AsRegister(), SP, - in.GetStackIndex()); + value_location.GetStackIndex()); __ LoadFromOffset(kLoadWord, locations->GetTemp(2).AsRegister(), SP, - in.GetStackIndex() + 4); + value_location.GetStackIndex() + 4); } else { - DCHECK(in.IsConstant()); - DCHECK(in.GetConstant()->IsDoubleConstant()); - int64_t value = bit_cast(in.GetConstant()->AsDoubleConstant()->GetValue()); + DCHECK(value_location.IsConstant()); + DCHECK(value_location.GetConstant()->IsDoubleConstant()); + int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant()); __ LoadConst64(locations->GetTemp(2).AsRegister(), locations->GetTemp(1).AsRegister(), value); @@ -3967,19 +4005,19 @@ void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction, codegen_->InvokeRuntime(kQuickA64Store, instruction, dex_pc); CheckEntrypointTypes(); } else { - if (!Primitive::IsFloatingPointType(type)) { + if (value_location.IsConstant()) { + int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker); + } else if (!Primitive::IsFloatingPointType(type)) { Register src; if (type == Primitive::kPrimLong) { - DCHECK(locations->InAt(1).IsRegisterPair()); - src = locations->InAt(1).AsRegisterPairLow(); + src = value_location.AsRegisterPairLow(); } else { - DCHECK(locations->InAt(1).IsRegister()); - src = locations->InAt(1).AsRegister(); + src = value_location.AsRegister(); } __ StoreToOffset(store_type, src, obj, offset, null_checker); } else { - DCHECK(locations->InAt(1).IsFpuRegister()); - FRegister src = locations->InAt(1).AsFpuRegister(); + FRegister src = value_location.AsFpuRegister(); if (type == Primitive::kPrimFloat) { __ StoreSToOffset(src, obj, offset, null_checker); } else { @@ -3990,8 +4028,7 @@ void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction, // TODO: memory barriers? if (CodeGenerator::StoreNeedsWriteBarrier(type, instruction->InputAt(1))) { - DCHECK(locations->InAt(1).IsRegister()); - Register src = locations->InAt(1).AsRegister(); + Register src = value_location.AsRegister(); codegen_->MarkGCCard(obj, src); } diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index a42374f14..553a7e667 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -191,6 +191,8 @@ class LocationsBuilderMIPS : public HGraphVisitor { void HandleShift(HBinaryOperation* operation); void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); + Location RegisterOrZeroConstant(HInstruction* instruction); + Location FpuRegisterOrConstantForStore(HInstruction* instruction); InvokeDexCallingConventionVisitorMIPS parameter_visitor_; diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index 099620ccb..e1255f7f2 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -496,46 +496,61 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler - void StoreConst32ToOffset(int32_t value, - Register base, - int32_t offset, - Register temp, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + void StoreConstToOffset(StoreOperandType type, + int64_t value, + Register base, + int32_t offset, + Register temp, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + // We permit `base` and `temp` to coincide (however, we check that neither is AT), + // in which case the `base` register may be overwritten in the process. 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 { - LoadConst32(temp, value); - } - Sw(temp, base, offset); - null_checker(); - } - - template - void StoreConst64ToOffset(int64_t value, - Register base, - int32_t offset, - Register temp, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - CHECK_NE(temp, AT); // Must not use AT as temp, so as not to overwrite the adjusted base. - AdjustBaseAndOffset(base, offset, /* is_doubleword */ true); + AdjustBaseAndOffset(base, offset, /* is_doubleword */ (type == kStoreDoubleword)); uint32_t low = Low32Bits(value); uint32_t high = High32Bits(value); + Register reg; + // If the adjustment left `base` unchanged and equal to `temp`, we can't use `temp` + // to load and hold the value but we can use AT instead as AT hasn't been used yet. + // Otherwise, `temp` can be used for the value. And if `temp` is the same as the + // original `base` (that is, `base` prior to the adjustment), the original `base` + // register will be overwritten. + if (base == temp) { + temp = AT; + } if (low == 0) { - Sw(ZERO, base, offset); + reg = ZERO; } else { - LoadConst32(temp, low); - Sw(temp, base, offset); + reg = temp; + LoadConst32(reg, low); } - null_checker(); - if (high == 0) { - Sw(ZERO, base, offset + kMipsWordSize); - } else { - if (high != low) { - LoadConst32(temp, high); - } - Sw(temp, base, offset + kMipsWordSize); + switch (type) { + case kStoreByte: + Sb(reg, base, offset); + break; + case kStoreHalfword: + Sh(reg, base, offset); + break; + case kStoreWord: + Sw(reg, base, offset); + break; + case kStoreDoubleword: + Sw(reg, base, offset); + null_checker(); + if (high == 0) { + reg = ZERO; + } else { + reg = temp; + if (high != low) { + LoadConst32(reg, high); + } + } + Sw(reg, base, offset + kMipsWordSize); + break; + default: + LOG(FATAL) << "UNREACHABLE"; + } + if (type != kStoreDoubleword) { + null_checker(); } } diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc index a92455fe6..a9abf2f86 100644 --- a/compiler/utils/mips/assembler_mips_test.cc +++ b/compiler/utils/mips/assembler_mips_test.cc @@ -1977,6 +1977,85 @@ TEST_F(AssemblerMIPSTest, StoreDToOffset) { DriverStr(expected, "StoreDToOffset"); } +TEST_F(AssemblerMIPSTest, StoreConstToOffset) { + __ StoreConstToOffset(mips::kStoreByte, 0xFF, mips::A1, +0, mips::T8); + __ StoreConstToOffset(mips::kStoreHalfword, 0xFFFF, mips::A1, +0, mips::T8); + __ StoreConstToOffset(mips::kStoreWord, 0x12345678, mips::A1, +0, mips::T8); + __ StoreConstToOffset(mips::kStoreDoubleword, 0x123456789ABCDEF0, mips::A1, +0, mips::T8); + + __ StoreConstToOffset(mips::kStoreByte, 0, mips::A1, +0, mips::T8); + __ StoreConstToOffset(mips::kStoreHalfword, 0, mips::A1, +0, mips::T8); + __ StoreConstToOffset(mips::kStoreWord, 0, mips::A1, +0, mips::T8); + __ StoreConstToOffset(mips::kStoreDoubleword, 0, mips::A1, +0, mips::T8); + + __ StoreConstToOffset(mips::kStoreDoubleword, 0x1234567812345678, mips::A1, +0, mips::T8); + __ StoreConstToOffset(mips::kStoreDoubleword, 0x1234567800000000, mips::A1, +0, mips::T8); + __ StoreConstToOffset(mips::kStoreDoubleword, 0x0000000012345678, mips::A1, +0, mips::T8); + + __ StoreConstToOffset(mips::kStoreWord, 0, mips::T8, +0, mips::T8); + __ StoreConstToOffset(mips::kStoreWord, 0x12345678, mips::T8, +0, mips::T8); + + __ StoreConstToOffset(mips::kStoreWord, 0, mips::A1, -0xFFF0, mips::T8); + __ StoreConstToOffset(mips::kStoreWord, 0x12345678, mips::A1, +0xFFF0, mips::T8); + + __ StoreConstToOffset(mips::kStoreWord, 0, mips::T8, -0xFFF0, mips::T8); + __ StoreConstToOffset(mips::kStoreWord, 0x12345678, mips::T8, +0xFFF0, mips::T8); + + const char* expected = + "ori $t8, $zero, 0xFF\n" + "sb $t8, 0($a1)\n" + "ori $t8, $zero, 0xFFFF\n" + "sh $t8, 0($a1)\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sw $t8, 0($a1)\n" + "lui $t8, 0x9ABC\n" + "ori $t8, $t8, 0xDEF0\n" + "sw $t8, 0($a1)\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sw $t8, 4($a1)\n" + + "sb $zero, 0($a1)\n" + "sh $zero, 0($a1)\n" + "sw $zero, 0($a1)\n" + "sw $zero, 0($a1)\n" + "sw $zero, 4($a1)\n" + + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sw $t8, 0($a1)\n" + "sw $t8, 4($a1)\n" + "sw $zero, 0($a1)\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sw $t8, 4($a1)\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sw $t8, 0($a1)\n" + "sw $zero, 4($a1)\n" + + "sw $zero, 0($t8)\n" + "lui $at, 0x1234\n" + "ori $at, $at, 0x5678\n" + "sw $at, 0($t8)\n" + + "addiu $at, $a1, -0x7FF8\n" + "sw $zero, -0x7FF8($at)\n" + "addiu $at, $a1, 0x7FF8\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sw $t8, 0x7FF8($at)\n" + + "addiu $at, $t8, -0x7FF8\n" + "sw $zero, -0x7FF8($at)\n" + "addiu $at, $t8, 0x7FF8\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sw $t8, 0x7FF8($at)\n"; + DriverStr(expected, "StoreConstToOffset"); +} + TEST_F(AssemblerMIPSTest, B) { mips::MipsLabel label1, label2; __ B(&label1); -- 2.11.0