From: Lazar Trsic Date: Thu, 3 Sep 2015 15:33:01 +0000 (+0200) Subject: MIPS64: Remove unaligned memory access from art generated code X-Git-Tag: android-x86-7.1-r1~424^2~67^2^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=d967266cdfc8011c81ba6e9857a247c4a73bd0fc;p=android-x86%2Fart.git MIPS64: Remove unaligned memory access from art generated code Unaligned memory access was caused by sd, ld, ldc1 and sdc1 instructions. Check if offset is unaligned and replace it with two 32 bit memory accesses, if so. Added assembler tests for new instructions, as well as assembler tests for LoadFromOffset, LoadFpuFromOffset, StoreToOffset and StoreFpuToOffset. Change-Id: I0228a4a2ce6c801eeb5b46952b8330e14468deb3 --- diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc index 372fe2b59..4d6c058bd 100644 --- a/compiler/dex/quick/mips/utility_mips.cc +++ b/compiler/dex/quick/mips/utility_mips.cc @@ -28,6 +28,8 @@ namespace art { +static constexpr size_t kMips64DoublewordSize = 8; + /* This file contains codegen for the Mips ISA */ LIR* MipsMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) { int opcode; @@ -760,7 +762,25 @@ LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStora if (cu_->target64) { if (short_form) { - load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg()); + if (!IsAligned(displacement) && opcode == kMips64Ld) { + RegStorage r_tmp = AllocTemp(); + load = res = NewLIR3(kMips64Lwu, r_dest.GetReg(), displacement + LOWORD_OFFSET, + r_base.GetReg()); + load2 = NewLIR3(kMips64Lwu, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg()); + NewLIR3(kMips64Dsll32, r_tmp.GetReg(), r_tmp.GetReg(), 0x0); + NewLIR3(kMipsOr, r_dest.GetReg(), r_dest.GetReg(), r_tmp.GetReg()); + FreeTemp(r_tmp); + } else if (!IsAligned(displacement) && opcode == kMipsFldc1) { + RegStorage r_tmp = AllocTemp(); + r_dest = Fp64ToSolo32(r_dest); + load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), displacement + LOWORD_OFFSET, + r_base.GetReg()); + load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg()); + NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg()); + FreeTemp(r_tmp); + } else { + load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg()); + } } else { RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest; res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement); @@ -771,7 +791,12 @@ LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStora if (mem_ref_type_ == ResourceMask::kDalvikReg) { DCHECK_EQ(r_base, TargetPtrReg(kSp)); - AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit()); + AnnotateDalvikRegAccess(load, (displacement + LOWORD_OFFSET) >> 2, + true /* is_load */, r_dest.Is64Bit() /* is64bit */); + if (load2 != nullptr) { + AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2, + true /* is_load */, r_dest.Is64Bit() /* is64bit */); + } } return res; } @@ -932,7 +957,24 @@ LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStor if (cu_->target64) { if (short_form) { - store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg()); + if (!IsAligned(displacement) && opcode == kMips64Sd) { + RegStorage r_tmp = AllocTemp(); + res = NewLIR2(kMipsMove, r_tmp.GetReg(), r_src.GetReg()); + store = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + LOWORD_OFFSET, r_base.GetReg()); + NewLIR3(kMips64Dsrl32, r_tmp.GetReg(), r_tmp.GetReg(), 0x0); + store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg()); + FreeTemp(r_tmp); + } else if (!IsAligned(displacement) && opcode == kMipsFsdc1) { + RegStorage r_tmp = AllocTemp(); + r_src = Fp64ToSolo32(r_src); + store = res = NewLIR3(kMipsFswc1, r_src.GetReg(), displacement + LOWORD_OFFSET, + r_base.GetReg()); + NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg()); + store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg()); + FreeTemp(r_tmp); + } else { + store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg()); + } } else { RegStorage r_scratch = AllocTemp(); res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement); @@ -942,7 +984,12 @@ LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStor if (mem_ref_type_ == ResourceMask::kDalvikReg) { DCHECK_EQ(r_base, TargetPtrReg(kSp)); - AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit()); + AnnotateDalvikRegAccess(store, (displacement + LOWORD_OFFSET) >> 2, + false /* is_load */, r_src.Is64Bit() /* is64bit */); + if (store2 != nullptr) { + AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2, + false /* is_load */, r_src.Is64Bit() /* is64bit */); + } } return res; } diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 3c928dedd..cefcb95c1 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -106,7 +106,7 @@ Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type) } #define __ down_cast(codegen)->GetAssembler()-> -#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, x).Int32Value() +#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, x).Int32Value() class BoundsCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 { public: @@ -437,7 +437,7 @@ CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph, #undef __ #define __ down_cast(GetAssembler())-> -#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, x).Int32Value() +#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, x).Int32Value() void CodeGeneratorMIPS64::Finalize(CodeAllocator* allocator) { // Ensure that we fix up branches. @@ -486,12 +486,12 @@ void ParallelMoveResolverMIPS64::EmitSwap(size_t index) { void ParallelMoveResolverMIPS64::RestoreScratch(int reg) { // Pop reg __ Ld(GpuRegister(reg), SP, 0); - __ DecreaseFrameSize(kMips64WordSize); + __ DecreaseFrameSize(kMips64DoublewordSize); } void ParallelMoveResolverMIPS64::SpillScratch(int reg) { // Push reg - __ IncreaseFrameSize(kMips64WordSize); + __ IncreaseFrameSize(kMips64DoublewordSize); __ Sd(GpuRegister(reg), SP, 0); } @@ -503,7 +503,7 @@ void ParallelMoveResolverMIPS64::Exchange(int index1, int index2, bool double_sl // automatically unspilled when the scratch scope object is destroyed). ScratchRegisterScope ensure_scratch(this, TMP, V0, codegen_->GetNumberOfCoreRegisters()); // If V0 spills onto the stack, SP-relative offsets need to be adjusted. - int stack_offset = ensure_scratch.IsSpilled() ? kMips64WordSize : 0; + int stack_offset = ensure_scratch.IsSpilled() ? kMips64DoublewordSize : 0; __ LoadFromOffset(load_type, GpuRegister(ensure_scratch.GetRegister()), SP, @@ -562,7 +562,7 @@ void CodeGeneratorMIPS64::GenerateFrameEntry() { for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) { GpuRegister reg = kCoreCalleeSaves[i]; if (allocated_registers_.ContainsCoreRegister(reg)) { - ofs -= kMips64WordSize; + ofs -= kMips64DoublewordSize; __ Sd(reg, SP, ofs); __ cfi().RelOffset(DWARFReg(reg), ofs); } @@ -571,7 +571,7 @@ void CodeGeneratorMIPS64::GenerateFrameEntry() { for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) { FpuRegister reg = kFpuCalleeSaves[i]; if (allocated_registers_.ContainsFloatingPointRegister(reg)) { - ofs -= kMips64WordSize; + ofs -= kMips64DoublewordSize; __ Sdc1(reg, SP, ofs); // TODO: __ cfi().RelOffset(DWARFReg(reg), ofs); } @@ -609,7 +609,7 @@ void CodeGeneratorMIPS64::GenerateFrameExit() { FpuRegister reg = kFpuCalleeSaves[i]; if (allocated_registers_.ContainsFloatingPointRegister(reg)) { __ Ldc1(reg, SP, ofs); - ofs += kMips64WordSize; + ofs += kMips64DoublewordSize; // TODO: __ cfi().Restore(DWARFReg(reg)); } } @@ -618,7 +618,7 @@ void CodeGeneratorMIPS64::GenerateFrameExit() { GpuRegister reg = kCoreCalleeSaves[i]; if (allocated_registers_.ContainsCoreRegister(reg)) { __ Ld(reg, SP, ofs); - ofs += kMips64WordSize; + ofs += kMips64DoublewordSize; __ cfi().Restore(DWARFReg(reg)); } } @@ -976,7 +976,7 @@ void CodeGeneratorMIPS64::MarkGCCard(GpuRegister object, __ LoadFromOffset(kLoadDoubleword, card, TR, - Thread::CardTableOffset().Int32Value()); + Thread::CardTableOffset().Int32Value()); __ Dsrl(temp, object, gc::accounting::CardTable::kCardShift); __ Daddu(temp, card, temp); __ Sb(card, temp, 0); @@ -994,10 +994,11 @@ void CodeGeneratorMIPS64::SetupBlockedRegisters() const { blocked_core_registers_[SP] = true; blocked_core_registers_[RA] = true; - // AT and TMP(T8) are used as temporary/scratch registers - // (similar to how AT is used by MIPS assemblers). + // AT, TMP(T8) and TMP2(T3) are used as temporary/scratch + // registers (similar to how AT is used by MIPS assemblers). blocked_core_registers_[AT] = true; blocked_core_registers_[TMP] = true; + blocked_core_registers_[TMP2] = true; blocked_fpu_registers_[FTMP] = true; // Reserve suspend and thread registers. @@ -1021,22 +1022,22 @@ void CodeGeneratorMIPS64::SetupBlockedRegisters() const { size_t CodeGeneratorMIPS64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) { __ StoreToOffset(kStoreDoubleword, GpuRegister(reg_id), SP, stack_index); - return kMips64WordSize; + return kMips64DoublewordSize; } size_t CodeGeneratorMIPS64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) { __ LoadFromOffset(kLoadDoubleword, GpuRegister(reg_id), SP, stack_index); - return kMips64WordSize; + return kMips64DoublewordSize; } size_t CodeGeneratorMIPS64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) { __ StoreFpuToOffset(kStoreDoubleword, FpuRegister(reg_id), SP, stack_index); - return kMips64WordSize; + return kMips64DoublewordSize; } size_t CodeGeneratorMIPS64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) { __ LoadFpuFromOffset(kLoadDoubleword, FpuRegister(reg_id), SP, stack_index); - return kMips64WordSize; + return kMips64DoublewordSize; } void CodeGeneratorMIPS64::DumpCoreRegister(std::ostream& stream, int reg) const { @@ -1051,7 +1052,7 @@ void CodeGeneratorMIPS64::InvokeRuntime(QuickEntrypointEnum entrypoint, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path) { - InvokeRuntime(GetThreadOffset(entrypoint).Int32Value(), + InvokeRuntime(GetThreadOffset(entrypoint).Int32Value(), instruction, dex_pc, slow_path); @@ -1091,7 +1092,7 @@ void InstructionCodeGeneratorMIPS64::GenerateSuspendCheck(HSuspendCheck* instruc __ LoadFromOffset(kLoadUnsignedHalfword, TMP, TR, - Thread::ThreadFlagsOffset().Int32Value()); + Thread::ThreadFlagsOffset().Int32Value()); if (successor == nullptr) { __ Bnezc(TMP, slow_path->GetEntryLabel()); __ Bind(slow_path->GetReturnLabel()); @@ -3014,7 +3015,7 @@ void InstructionCodeGeneratorMIPS64::VisitInvokeInterface(HInvokeInterface* invo invoke->GetImtIndex() % mirror::Class::kImtSize, kMips64PointerSize).Uint32Value(); Location receiver = invoke->GetLocations()->InAt(0); uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); - Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize); + Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64DoublewordSize); // Set the hidden argument. __ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister(), @@ -3190,7 +3191,7 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo T9, callee_method.AsRegister(), ArtMethod::EntryPointFromQuickCompiledCodeOffset( - kMips64WordSize).Int32Value()); + kMips64DoublewordSize).Int32Value()); // T9() __ Jalr(T9); __ Nop(); @@ -3228,7 +3229,7 @@ void CodeGeneratorMIPS64::GenerateVirtualCall(HInvokeVirtual* invoke, Location t size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset( invoke->GetVTableIndex(), kMips64PointerSize).SizeValue(); uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); - Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize); + Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64DoublewordSize); // temp = object->GetClass(); __ LoadFromOffset(kLoadUnsignedWord, temp, receiver, class_offset); @@ -3306,7 +3307,7 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) { } static int32_t GetExceptionTlsOffset() { - return Thread::ExceptionOffset().Int32Value(); + return Thread::ExceptionOffset().Int32Value(); } void LocationsBuilderMIPS64::VisitLoadException(HLoadException* load) { @@ -3546,7 +3547,8 @@ void InstructionCodeGeneratorMIPS64::VisitNewInstance(HNewInstance* instruction) if (instruction->IsStringAlloc()) { // String is allocated through StringFactory. Call NewEmptyString entry point. GpuRegister temp = instruction->GetLocations()->GetTemp(0).AsRegister(); - MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize); + MemberOffset code_offset = + ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64DoublewordSize); __ LoadFromOffset(kLoadDoubleword, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString)); __ LoadFromOffset(kLoadDoubleword, T9, temp, code_offset.Int32Value()); __ Jalr(T9); diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index 08e56158b..c836f837d 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -27,10 +27,6 @@ namespace art { namespace mips64 { -// Use a local definition to prevent copying mistakes. -static constexpr size_t kMips64WordSize = kMips64PointerSize; - - // InvokeDexCallingConvention registers static constexpr GpuRegister kParameterCoreRegisters[] = @@ -274,9 +270,9 @@ class CodeGeneratorMIPS64 : public CodeGenerator { void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; - size_t GetWordSize() const OVERRIDE { return kMips64WordSize; } + size_t GetWordSize() const OVERRIDE { return kMips64DoublewordSize; } - size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64WordSize; } + size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64DoublewordSize; } uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE { return assembler_.GetLabelLocation(GetLabelOf(block)); diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index cba84fa3e..f681d1fd5 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -1429,8 +1429,7 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringCompareTo(HInvoke* invoke) { __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, - pStringCompareTo).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pStringCompareTo).Int32Value()); __ Jalr(TMP); __ Nop(); __ Bind(slow_path->GetExitLabel()); @@ -1583,7 +1582,7 @@ static void GenerateStringIndexOf(HInvoke* invoke, __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pIndexOf).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pIndexOf).Int32Value()); __ Jalr(TMP); __ Nop(); @@ -1659,7 +1658,8 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pAllocStringFromBytes).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, + pAllocStringFromBytes).Int32Value()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); __ Jalr(TMP); __ Nop(); @@ -1685,7 +1685,8 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromChars(HInvoke* invoke __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pAllocStringFromChars).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, + pAllocStringFromChars).Int32Value()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); __ Jalr(TMP); __ Nop(); @@ -1716,7 +1717,8 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromString(HInvoke* invok __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pAllocStringFromString).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, + pAllocStringFromString).Int32Value()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); __ Jalr(TMP); __ Nop(); diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc index f9ff2df8b..ab480cafd 100644 --- a/compiler/utils/mips64/assembler_mips64.cc +++ b/compiler/utils/mips64/assembler_mips64.cc @@ -300,10 +300,17 @@ void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) { EmitRtd(0x1f, rt, rd, 0x5, 0x24); } -void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size_less_one) { - DCHECK(0 <= pos && pos < 32) << pos; - DCHECK(0 <= size_less_one && size_less_one < 32) << size_less_one; - EmitR(0x1f, rs, rt, static_cast(size_less_one), pos, 3); +void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) { + CHECK(IsUint<5>(pos)) << pos; + CHECK(IsUint<5>(size - 1)) << size; + EmitR(0x1f, rs, rt, static_cast(size - 1), pos, 0x3); +} + +void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) { + CHECK(IsUint<5>(pos - 32)) << pos; + CHECK(IsUint<5>(size - 1)) << size; + CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size; + EmitR(0x1f, rs, rt, static_cast(pos + size - 33), pos - 32, 0x6); } void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) { @@ -311,22 +318,22 @@ void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) { } void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) { - DCHECK((-256 <= imm9) && (imm9 < 256)); + CHECK(IsInt<9>(imm9)); EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26); } void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) { - DCHECK((-256 <= imm9) && (imm9 < 256)); + CHECK(IsInt<9>(imm9)); EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27); } void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) { - DCHECK((-256 <= imm9) && (imm9 < 256)); + CHECK(IsInt<9>(imm9)); EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36); } void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) { - DCHECK((-256 <= imm9) && (imm9 < 256)); + CHECK(IsInt<9>(imm9)); EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37); } @@ -967,10 +974,18 @@ void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) { EmitFR(0x11, 0x00, static_cast(rt), fs, static_cast(0), 0x0); } +void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) { + EmitFR(0x11, 0x03, static_cast(rt), fs, static_cast(0), 0x0); +} + void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) { EmitFR(0x11, 0x04, static_cast(rt), fs, static_cast(0), 0x0); } +void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) { + EmitFR(0x11, 0x07, static_cast(rt), fs, static_cast(0), 0x0); +} + void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) { EmitFR(0x11, 0x01, static_cast(rt), fs, static_cast(0), 0x0); } @@ -1787,11 +1802,13 @@ void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) { void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base, int32_t offset) { - if (!IsInt<16>(offset)) { - LoadConst32(AT, offset); + if (!IsInt<16>(offset) || + (type == kLoadDoubleword && !IsAligned(offset) && + !IsInt<16>(static_cast(offset + kMips64WordSize)))) { + LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1)); Daddu(AT, AT, base); base = AT; - offset = 0; + offset &= (kMips64DoublewordSize - 1); } switch (type) { @@ -1808,32 +1825,51 @@ void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuR Lhu(reg, base, offset); break; case kLoadWord: + CHECK_ALIGNED(offset, kMips64WordSize); Lw(reg, base, offset); break; case kLoadUnsignedWord: + CHECK_ALIGNED(offset, kMips64WordSize); Lwu(reg, base, offset); break; case kLoadDoubleword: - Ld(reg, base, offset); + if (!IsAligned(offset)) { + CHECK_ALIGNED(offset, kMips64WordSize); + Lwu(reg, base, offset); + Lwu(TMP2, base, offset + kMips64WordSize); + Dinsu(reg, TMP2, 32, 32); + } else { + Ld(reg, base, offset); + } break; } } void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base, int32_t offset) { - if (!IsInt<16>(offset)) { - LoadConst32(AT, offset); + if (!IsInt<16>(offset) || + (type == kLoadDoubleword && !IsAligned(offset) && + !IsInt<16>(static_cast(offset + kMips64WordSize)))) { + LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1)); Daddu(AT, AT, base); base = AT; - offset = 0; + offset &= (kMips64DoublewordSize - 1); } switch (type) { case kLoadWord: + CHECK_ALIGNED(offset, kMips64WordSize); Lwc1(reg, base, offset); break; case kLoadDoubleword: - Ldc1(reg, base, offset); + if (!IsAligned(offset)) { + CHECK_ALIGNED(offset, kMips64WordSize); + Lwc1(reg, base, offset); + Lw(TMP2, base, offset + kMips64WordSize); + Mthc1(TMP2, reg); + } else { + Ldc1(reg, base, offset); + } break; default: LOG(FATAL) << "UNREACHABLE"; @@ -1869,11 +1905,13 @@ void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base, int32_t offset) { - if (!IsInt<16>(offset)) { - LoadConst32(AT, offset); + if (!IsInt<16>(offset) || + (type == kStoreDoubleword && !IsAligned(offset) && + !IsInt<16>(static_cast(offset + kMips64WordSize)))) { + LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1)); Daddu(AT, AT, base); base = AT; - offset = 0; + offset &= (kMips64DoublewordSize - 1); } switch (type) { @@ -1884,10 +1922,18 @@ void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuR Sh(reg, base, offset); break; case kStoreWord: + CHECK_ALIGNED(offset, kMips64WordSize); Sw(reg, base, offset); break; case kStoreDoubleword: - Sd(reg, base, offset); + if (!IsAligned(offset)) { + CHECK_ALIGNED(offset, kMips64WordSize); + Sw(reg, base, offset); + Dsrl32(TMP2, reg, 0); + Sw(TMP2, base, offset + kMips64WordSize); + } else { + Sd(reg, base, offset); + } break; default: LOG(FATAL) << "UNREACHABLE"; @@ -1896,19 +1942,29 @@ void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuR void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base, int32_t offset) { - if (!IsInt<16>(offset)) { - LoadConst32(AT, offset); + if (!IsInt<16>(offset) || + (type == kStoreDoubleword && !IsAligned(offset) && + !IsInt<16>(static_cast(offset + kMips64WordSize)))) { + LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1)); Daddu(AT, AT, base); base = AT; - offset = 0; + offset &= (kMips64DoublewordSize - 1); } switch (type) { case kStoreWord: + CHECK_ALIGNED(offset, kMips64WordSize); Swc1(reg, base, offset); break; case kStoreDoubleword: - Sdc1(reg, base, offset); + if (!IsAligned(offset)) { + CHECK_ALIGNED(offset, kMips64WordSize); + Mfhc1(TMP2, reg); + Swc1(reg, base, offset); + Sw(TMP2, base, offset + kMips64WordSize); + } else { + Sdc1(reg, base, offset); + } break; default: LOG(FATAL) << "UNREACHABLE"; @@ -2053,7 +2109,7 @@ void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value()); } -void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset thr_offs, +void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset thr_offs, FrameOffset fr_offs, ManagedRegister mscratch) { Mips64ManagedRegister scratch = mscratch.AsMips64(); @@ -2062,7 +2118,7 @@ void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset thr_offs) { +void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset thr_offs) { StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value()); } @@ -2080,7 +2136,7 @@ void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) } void Mips64Assembler::LoadFromThread64(ManagedRegister mdest, - ThreadOffset src, + ThreadOffset src, size_t size) { return EmitLoad(mdest, S1, src.Int32Value(), size); } @@ -2102,7 +2158,7 @@ void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, Membe // Negate the 32-bit ref Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister()); // And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64 - Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 31); + Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32); } } @@ -2115,7 +2171,7 @@ void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, } void Mips64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest, - ThreadOffset offs) { + ThreadOffset offs) { Mips64ManagedRegister dest = mdest.AsMips64(); CHECK(dest.IsGpuRegister()); LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value()); @@ -2160,7 +2216,7 @@ void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src, } void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs, - ThreadOffset thr_offs, + ThreadOffset thr_offs, ManagedRegister mscratch) { Mips64ManagedRegister scratch = mscratch.AsMips64(); CHECK(scratch.IsGpuRegister()) << scratch; @@ -2168,7 +2224,7 @@ void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs, StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value()); } -void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset thr_offs, +void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset thr_offs, FrameOffset fr_offs, ManagedRegister mscratch) { Mips64ManagedRegister scratch = mscratch.AsMips64(); @@ -2372,7 +2428,7 @@ void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscr // TODO: place reference map on call } -void Mips64Assembler::CallFromThread64(ThreadOffset offset ATTRIBUTE_UNUSED, +void Mips64Assembler::CallFromThread64(ThreadOffset offset ATTRIBUTE_UNUSED, ManagedRegister mscratch ATTRIBUTE_UNUSED) { UNIMPLEMENTED(FATAL) << "No MIPS64 implementation"; } @@ -2392,7 +2448,7 @@ void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjus LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, - Thread::ExceptionOffset().Int32Value()); + Thread::ExceptionOffset().Int32Value()); Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry()); } @@ -2409,7 +2465,7 @@ void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) { LoadFromOffset(kLoadDoubleword, T9, S1, - QUICK_ENTRYPOINT_OFFSET(kMipsDoublewordSize, pDeliverException).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pDeliverException).Int32Value()); Jr(T9); Nop(); diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h index 3262640ce..71f5e0016 100644 --- a/compiler/utils/mips64/assembler_mips64.h +++ b/compiler/utils/mips64/assembler_mips64.h @@ -31,7 +31,8 @@ namespace art { namespace mips64 { -static constexpr size_t kMipsDoublewordSize = 8; +static constexpr size_t kMips64WordSize = 4; +static constexpr size_t kMips64DoublewordSize = 8; enum LoadOperandType { kLoadSignedByte, @@ -151,7 +152,8 @@ class Mips64Assembler FINAL : public Assembler { void Seh(GpuRegister rd, GpuRegister rt); void Dsbh(GpuRegister rd, GpuRegister rt); void Dshd(GpuRegister rd, GpuRegister rt); - void Dext(GpuRegister rs, GpuRegister rt, int pos, int size_less_one); // MIPS64 + void Dext(GpuRegister rs, GpuRegister rt, int pos, int size); // MIPS64 + void Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64 void Wsbh(GpuRegister rd, GpuRegister rt); void Sc(GpuRegister rt, GpuRegister base, int16_t imm9 = 0); void Scd(GpuRegister rt, GpuRegister base, int16_t imm9 = 0); @@ -301,7 +303,9 @@ class Mips64Assembler FINAL : public Assembler { void Cvtdl(FpuRegister fd, FpuRegister fs); void Mfc1(GpuRegister rt, FpuRegister fs); + void Mfhc1(GpuRegister rt, FpuRegister fs); void Mtc1(GpuRegister rt, FpuRegister fs); + void Mthc1(GpuRegister rt, FpuRegister fs); void Dmfc1(GpuRegister rt, FpuRegister fs); // MIPS64 void Dmtc1(GpuRegister rt, FpuRegister fs); // MIPS64 void Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16); @@ -378,10 +382,10 @@ class Mips64Assembler FINAL : public Assembler { void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE; - void StoreStackOffsetToThread64(ThreadOffset thr_offs, FrameOffset fr_offs, + void StoreStackOffsetToThread64(ThreadOffset thr_offs, FrameOffset fr_offs, ManagedRegister mscratch) OVERRIDE; - void StoreStackPointerToThread64(ThreadOffset thr_offs) OVERRIDE; + void StoreStackPointerToThread64(ThreadOffset thr_offs) OVERRIDE; void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off, ManagedRegister mscratch) OVERRIDE; @@ -390,7 +394,7 @@ class Mips64Assembler FINAL : public Assembler { void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE; void LoadFromThread64(ManagedRegister mdest, - ThreadOffset src, + ThreadOffset src, size_t size) OVERRIDE; void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE; @@ -401,15 +405,15 @@ class Mips64Assembler FINAL : public Assembler { void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE; void LoadRawPtrFromThread64(ManagedRegister mdest, - ThreadOffset offs) OVERRIDE; + ThreadOffset offs) OVERRIDE; // Copying routines. void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE; - void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset thr_offs, + void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset thr_offs, ManagedRegister mscratch) OVERRIDE; - void CopyRawPtrToThread64(ThreadOffset thr_offs, FrameOffset fr_offs, + void CopyRawPtrToThread64(ThreadOffset thr_offs, FrameOffset fr_offs, ManagedRegister mscratch) OVERRIDE; void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE; @@ -466,7 +470,7 @@ class Mips64Assembler FINAL : public Assembler { // Call to address held at [base+offset]. void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE; void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE; - void CallFromThread64(ThreadOffset offset, + void CallFromThread64(ThreadOffset offset, ManagedRegister mscratch) OVERRIDE; // Generate code to check if Thread::Current()->exception_ is non-null diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc index 7d79be273..b758d64c1 100644 --- a/compiler/utils/mips64/assembler_mips64_test.cc +++ b/compiler/utils/mips64/assembler_mips64_test.cc @@ -543,6 +543,30 @@ TEST_F(AssemblerMIPS64Test, TruncLD) { DriverStr(RepeatFF(&mips64::Mips64Assembler::TruncLD, "trunc.l.d ${reg1}, ${reg2}"), "trunc.l.d"); } +TEST_F(AssemblerMIPS64Test, Mfc1) { + DriverStr(RepeatRF(&mips64::Mips64Assembler::Mfc1, "mfc1 ${reg1}, ${reg2}"), "Mfc1"); +} + +TEST_F(AssemblerMIPS64Test, Mfhc1) { + DriverStr(RepeatRF(&mips64::Mips64Assembler::Mfhc1, "mfhc1 ${reg1}, ${reg2}"), "Mfhc1"); +} + +TEST_F(AssemblerMIPS64Test, Mtc1) { + DriverStr(RepeatRF(&mips64::Mips64Assembler::Mtc1, "mtc1 ${reg1}, ${reg2}"), "Mtc1"); +} + +TEST_F(AssemblerMIPS64Test, Mthc1) { + DriverStr(RepeatRF(&mips64::Mips64Assembler::Mthc1, "mthc1 ${reg1}, ${reg2}"), "Mthc1"); +} + +TEST_F(AssemblerMIPS64Test, Dmfc1) { + DriverStr(RepeatRF(&mips64::Mips64Assembler::Dmfc1, "dmfc1 ${reg1}, ${reg2}"), "Dmfc1"); +} + +TEST_F(AssemblerMIPS64Test, Dmtc1) { + DriverStr(RepeatRF(&mips64::Mips64Assembler::Dmtc1, "dmtc1 ${reg1}, ${reg2}"), "Dmtc1"); +} + //////////////// // CALL / JMP // //////////////// @@ -827,6 +851,44 @@ TEST_F(AssemblerMIPS64Test, Dshd) { DriverStr(RepeatRR(&mips64::Mips64Assembler::Dshd, "dshd ${reg1}, ${reg2}"), "dshd"); } +TEST_F(AssemblerMIPS64Test, Dext) { + std::vector reg1_registers = GetRegisters(); + std::vector reg2_registers = GetRegisters(); + WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 33 * 16); + std::ostringstream expected; + for (mips64::GpuRegister* reg1 : reg1_registers) { + for (mips64::GpuRegister* reg2 : reg2_registers) { + for (int32_t pos = 0; pos < 32; pos++) { + for (int32_t size = 1; size <= 32; size++) { + __ Dext(*reg1, *reg2, pos, size); + expected << "dext $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n"; + } + } + } + } + + DriverStr(expected.str(), "Dext"); +} + +TEST_F(AssemblerMIPS64Test, Dinsu) { + std::vector reg1_registers = GetRegisters(); + std::vector reg2_registers = GetRegisters(); + WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 33 * 16); + std::ostringstream expected; + for (mips64::GpuRegister* reg1 : reg1_registers) { + for (mips64::GpuRegister* reg2 : reg2_registers) { + for (int32_t pos = 32; pos < 64; pos++) { + for (int32_t size = 1; pos + size <= 64; size++) { + __ Dinsu(*reg1, *reg2, pos, size); + expected << "dinsu $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n"; + } + } + } + } + + DriverStr(expected.str(), "Dinsu"); +} + TEST_F(AssemblerMIPS64Test, Wsbh) { DriverStr(RepeatRR(&mips64::Mips64Assembler::Wsbh, "wsbh ${reg1}, ${reg2}"), "wsbh"); } @@ -942,4 +1004,638 @@ TEST_F(AssemblerMIPS64Test, Dclo) { DriverStr(RepeatRR(&mips64::Mips64Assembler::Dclo, "dclo ${reg1}, ${reg2}"), "dclo"); } +TEST_F(AssemblerMIPS64Test, LoadFromOffset) { + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A0, 0); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 1); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 256); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 1000); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x7FFF); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x8000); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x8001); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x10000); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x12345678); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, -256); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, -32768); + __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0xABCDEF00); + + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A0, 0); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 1); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 256); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 1000); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x7FFF); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x8000); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x8001); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x10000); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x12345678); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, -256); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, -32768); + __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0xABCDEF00); + + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A0, 0); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 2); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 256); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 1000); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x7FFE); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x8000); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x8002); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x10000); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x12345678); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, -256); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, -32768); + __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0xABCDEF00); + + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A0, 0); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 2); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 256); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 1000); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x7FFE); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x8000); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x8002); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x10000); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x12345678); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, -256); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, -32768); + __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0xABCDEF00); + + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A0, 0); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 4); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 256); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 1000); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x7FFC); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x8000); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x8004); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x10000); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x12345678); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, -256); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, -32768); + __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0xABCDEF00); + + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A0, 0); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 4); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 256); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 1000); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x7FFC); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x8000); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x8004); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x10000); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x12345678); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, -256); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, -32768); + __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0xABCDEF00); + + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A0, 0); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 4); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 256); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 1000); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x7FFC); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x8000); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x8004); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x10000); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x12345678); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, -256); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, -32768); + __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0xABCDEF00); + + const char* expected = + "lb $a0, 0($a0)\n" + "lb $a0, 0($a1)\n" + "lb $a0, 1($a1)\n" + "lb $a0, 256($a1)\n" + "lb $a0, 1000($a1)\n" + "lb $a0, 0x7FFF($a1)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lb $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lb $a0, 1($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "lb $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "lb $a0, 0($at)\n" + "lb $a0, -256($a1)\n" + "lb $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "lb $a0, 0($at)\n" + + "lbu $a0, 0($a0)\n" + "lbu $a0, 0($a1)\n" + "lbu $a0, 1($a1)\n" + "lbu $a0, 256($a1)\n" + "lbu $a0, 1000($a1)\n" + "lbu $a0, 0x7FFF($a1)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lbu $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lbu $a0, 1($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "lbu $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "lbu $a0, 0($at)\n" + "lbu $a0, -256($a1)\n" + "lbu $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "lbu $a0, 0($at)\n" + + "lh $a0, 0($a0)\n" + "lh $a0, 0($a1)\n" + "lh $a0, 2($a1)\n" + "lh $a0, 256($a1)\n" + "lh $a0, 1000($a1)\n" + "lh $a0, 0x7FFE($a1)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lh $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lh $a0, 2($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "lh $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "lh $a0, 0($at)\n" + "lh $a0, -256($a1)\n" + "lh $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "lh $a0, 0($at)\n" + + "lhu $a0, 0($a0)\n" + "lhu $a0, 0($a1)\n" + "lhu $a0, 2($a1)\n" + "lhu $a0, 256($a1)\n" + "lhu $a0, 1000($a1)\n" + "lhu $a0, 0x7FFE($a1)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lhu $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lhu $a0, 2($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "lhu $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "lhu $a0, 0($at)\n" + "lhu $a0, -256($a1)\n" + "lhu $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "lhu $a0, 0($at)\n" + + "lw $a0, 0($a0)\n" + "lw $a0, 0($a1)\n" + "lw $a0, 4($a1)\n" + "lw $a0, 256($a1)\n" + "lw $a0, 1000($a1)\n" + "lw $a0, 0x7FFC($a1)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lw $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lw $a0, 4($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "lw $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "lw $a0, 0($at)\n" + "lw $a0, -256($a1)\n" + "lw $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "lw $a0, 0($at)\n" + + "lwu $a0, 0($a0)\n" + "lwu $a0, 0($a1)\n" + "lwu $a0, 4($a1)\n" + "lwu $a0, 256($a1)\n" + "lwu $a0, 1000($a1)\n" + "lwu $a0, 0x7FFC($a1)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lwu $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lwu $a0, 4($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "lwu $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "lwu $a0, 0($at)\n" + "lwu $a0, -256($a1)\n" + "lwu $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "lwu $a0, 0($at)\n" + + "ld $a0, 0($a0)\n" + "ld $a0, 0($a1)\n" + "lwu $a0, 4($a1)\n" + "lwu $t3, 8($a1)\n" + "dins $a0, $t3, 32, 32\n" + "ld $a0, 256($a1)\n" + "ld $a0, 1000($a1)\n" + "ori $at, $zero, 0x7FF8\n" + "daddu $at, $at, $a1\n" + "lwu $a0, 4($at)\n" + "lwu $t3, 8($at)\n" + "dins $a0, $t3, 32, 32\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "ld $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "lwu $a0, 4($at)\n" + "lwu $t3, 8($at)\n" + "dins $a0, $t3, 32, 32\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "ld $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "ld $a0, 0($at)\n" + "ld $a0, -256($a1)\n" + "ld $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "ld $a0, 0($at)\n"; + DriverStr(expected, "LoadFromOffset"); +} + +TEST_F(AssemblerMIPS64Test, LoadFpuFromOffset) { + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 4); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 256); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x7FFC); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x8000); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x8004); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x10000); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x12345678); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, -256); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, -32768); + __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0xABCDEF00); + + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 4); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 256); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x7FFC); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x8000); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x8004); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x10000); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x12345678); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, -256); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, -32768); + __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0xABCDEF00); + + const char* expected = + "lwc1 $f0, 0($a0)\n" + "lwc1 $f0, 4($a0)\n" + "lwc1 $f0, 256($a0)\n" + "lwc1 $f0, 0x7FFC($a0)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a0\n" + "lwc1 $f0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a0\n" + "lwc1 $f0, 4($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a0\n" + "lwc1 $f0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a0\n" + "lwc1 $f0, 0($at)\n" + "lwc1 $f0, -256($a0)\n" + "lwc1 $f0, -32768($a0)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a0\n" + "lwc1 $f0, 0($at)\n" + + "ldc1 $f0, 0($a0)\n" + "lwc1 $f0, 4($a0)\n" + "lw $t3, 8($a0)\n" + "mthc1 $t3, $f0\n" + "ldc1 $f0, 256($a0)\n" + "ori $at, $zero, 0x7FF8\n" + "daddu $at, $at, $a0\n" + "lwc1 $f0, 4($at)\n" + "lw $t3, 8($at)\n" + "mthc1 $t3, $f0\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a0\n" + "ldc1 $f0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a0\n" + "lwc1 $f0, 4($at)\n" + "lw $t3, 8($at)\n" + "mthc1 $t3, $f0\n" + "lui $at, 1\n" + "daddu $at, $at, $a0\n" + "ldc1 $f0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a0\n" + "ldc1 $f0, 0($at)\n" + "ldc1 $f0, -256($a0)\n" + "ldc1 $f0, -32768($a0)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a0\n" + "ldc1 $f0, 0($at)\n"; + DriverStr(expected, "LoadFpuFromOffset"); +} + +TEST_F(AssemblerMIPS64Test, StoreToOffset) { + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A0, 0); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 1); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 256); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 1000); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x7FFF); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x8000); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x8001); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x10000); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x12345678); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, -256); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, -32768); + __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0xABCDEF00); + + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A0, 0); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 2); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 256); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 1000); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x7FFE); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x8000); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x8002); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x10000); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x12345678); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, -256); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, -32768); + __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0xABCDEF00); + + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A0, 0); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 4); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 256); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 1000); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x7FFC); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x8000); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x8004); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x10000); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x12345678); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, -256); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, -32768); + __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0xABCDEF00); + + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A0, 0); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 4); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 256); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 1000); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x7FFC); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x8000); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x8004); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x10000); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x12345678); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, -256); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, -32768); + __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0xABCDEF00); + + const char* expected = + "sb $a0, 0($a0)\n" + "sb $a0, 0($a1)\n" + "sb $a0, 1($a1)\n" + "sb $a0, 256($a1)\n" + "sb $a0, 1000($a1)\n" + "sb $a0, 0x7FFF($a1)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "sb $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "sb $a0, 1($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "sb $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "sb $a0, 0($at)\n" + "sb $a0, -256($a1)\n" + "sb $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "sb $a0, 0($at)\n" + + "sh $a0, 0($a0)\n" + "sh $a0, 0($a1)\n" + "sh $a0, 2($a1)\n" + "sh $a0, 256($a1)\n" + "sh $a0, 1000($a1)\n" + "sh $a0, 0x7FFE($a1)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "sh $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "sh $a0, 2($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "sh $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "sh $a0, 0($at)\n" + "sh $a0, -256($a1)\n" + "sh $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "sh $a0, 0($at)\n" + + "sw $a0, 0($a0)\n" + "sw $a0, 0($a1)\n" + "sw $a0, 4($a1)\n" + "sw $a0, 256($a1)\n" + "sw $a0, 1000($a1)\n" + "sw $a0, 0x7FFC($a1)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "sw $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "sw $a0, 4($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "sw $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "sw $a0, 0($at)\n" + "sw $a0, -256($a1)\n" + "sw $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "sw $a0, 0($at)\n" + + "sd $a0, 0($a0)\n" + "sd $a0, 0($a1)\n" + "sw $a0, 4($a1)\n" + "dsrl32 $t3, $a0, 0\n" + "sw $t3, 8($a1)\n" + "sd $a0, 256($a1)\n" + "sd $a0, 1000($a1)\n" + "ori $at, $zero, 0x7FF8\n" + "daddu $at, $at, $a1\n" + "sw $a0, 4($at)\n" + "dsrl32 $t3, $a0, 0\n" + "sw $t3, 8($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "sd $a0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a1\n" + "sw $a0, 4($at)\n" + "dsrl32 $t3, $a0, 0\n" + "sw $t3, 8($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a1\n" + "sd $a0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a1\n" + "sd $a0, 0($at)\n" + "sd $a0, -256($a1)\n" + "sd $a0, -32768($a1)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a1\n" + "sd $a0, 0($at)\n"; + DriverStr(expected, "StoreToOffset"); +} + +TEST_F(AssemblerMIPS64Test, StoreFpuToOffset) { + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 4); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 256); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x7FFC); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x8000); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x8004); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x10000); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x12345678); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, -256); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, -32768); + __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0xABCDEF00); + + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 4); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 256); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x7FFC); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x8000); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x8004); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x10000); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x12345678); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, -256); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, -32768); + __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0xABCDEF00); + + const char* expected = + "swc1 $f0, 0($a0)\n" + "swc1 $f0, 4($a0)\n" + "swc1 $f0, 256($a0)\n" + "swc1 $f0, 0x7FFC($a0)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a0\n" + "swc1 $f0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a0\n" + "swc1 $f0, 4($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a0\n" + "swc1 $f0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a0\n" + "swc1 $f0, 0($at)\n" + "swc1 $f0, -256($a0)\n" + "swc1 $f0, -32768($a0)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a0\n" + "swc1 $f0, 0($at)\n" + + "sdc1 $f0, 0($a0)\n" + "mfhc1 $t3, $f0\n" + "swc1 $f0, 4($a0)\n" + "sw $t3, 8($a0)\n" + "sdc1 $f0, 256($a0)\n" + "ori $at, $zero, 0x7FF8\n" + "daddu $at, $at, $a0\n" + "mfhc1 $t3, $f0\n" + "swc1 $f0, 4($at)\n" + "sw $t3, 8($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a0\n" + "sdc1 $f0, 0($at)\n" + "ori $at, $zero, 0x8000\n" + "daddu $at, $at, $a0\n" + "mfhc1 $t3, $f0\n" + "swc1 $f0, 4($at)\n" + "sw $t3, 8($at)\n" + "lui $at, 1\n" + "daddu $at, $at, $a0\n" + "sdc1 $f0, 0($at)\n" + "lui $at, 0x1234\n" + "ori $at, 0x5678\n" + "daddu $at, $at, $a0\n" + "sdc1 $f0, 0($at)\n" + "sdc1 $f0, -256($a0)\n" + "sdc1 $f0, -32768($a0)\n" + "lui $at, 0xABCD\n" + "ori $at, 0xEF00\n" + "daddu $at, $at, $a0\n" + "sdc1 $f0, 0($at)\n"; + DriverStr(expected, "StoreFpuToOffset"); +} + +#undef __ + } // namespace art diff --git a/runtime/arch/mips64/registers_mips64.h b/runtime/arch/mips64/registers_mips64.h index 1d07d47a7..b027c955b 100644 --- a/runtime/arch/mips64/registers_mips64.h +++ b/runtime/arch/mips64/registers_mips64.h @@ -61,6 +61,7 @@ enum GpuRegister { RA = 31, // Return address. TR = S1, // ART Thread Register TMP = T8, // scratch register (in addition to AT) + TMP2 = T3, // scratch register (in addition to AT, reserved for assembler) kNumberOfGpuRegisters = 32, kNoGpuRegister = -1 // Signals an illegal register. };