diff options
Diffstat (limited to 'compiler/utils')
41 files changed, 3711 insertions, 25813 deletions
diff --git a/compiler/utils/arm/assembler_arm_vixl.h b/compiler/utils/arm/assembler_arm_vixl.h index 98c0191679..59d7eddc63 100644 --- a/compiler/utils/arm/assembler_arm_vixl.h +++ b/compiler/utils/arm/assembler_arm_vixl.h @@ -22,6 +22,7 @@ #include "base/arena_containers.h" #include "base/macros.h" #include "constants_arm.h" +#include "dwarf/register.h" #include "offsets.h" #include "utils/arm/assembler_arm_shared.h" #include "utils/arm/managed_register_arm.h" @@ -39,6 +40,14 @@ namespace vixl32 = vixl::aarch32; namespace art { namespace arm { +inline dwarf::Reg DWARFReg(vixl32::Register reg) { + return dwarf::Reg::ArmCore(static_cast<int>(reg.GetCode())); +} + +inline dwarf::Reg DWARFReg(vixl32::SRegister reg) { + return dwarf::Reg::ArmFp(static_cast<int>(reg.GetCode())); +} + class ArmVIXLMacroAssembler final : public vixl32::MacroAssembler { public: // Most methods fit in a 1KB code buffer, which results in more optimal alloc/realloc and diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc index c6c764e3a9..ffb58aca54 100644 --- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc +++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc @@ -37,6 +37,10 @@ namespace arm { #define ___ asm_.GetVIXLAssembler()-> #endif +// The AAPCS requires 8-byte alignement. This is not as strict as the Managed ABI stack alignment. +static constexpr size_t kAapcsStackAlignment = 8u; +static_assert(kAapcsStackAlignment < kStackAlignment); + vixl::aarch32::Register AsVIXLRegister(ArmManagedRegister reg) { CHECK(reg.IsCoreRegister()); return vixl::aarch32::Register(reg.RegId()); @@ -68,25 +72,22 @@ void ArmVIXLJNIMacroAssembler::FinalizeCode() { asm_.FinalizeCode(); } -static dwarf::Reg DWARFReg(vixl32::Register reg) { - return dwarf::Reg::ArmCore(static_cast<int>(reg.GetCode())); -} - -static dwarf::Reg DWARFReg(vixl32::SRegister reg) { - return dwarf::Reg::ArmFp(static_cast<int>(reg.GetCode())); -} - static constexpr size_t kFramePointerSize = static_cast<size_t>(kArmPointerSize); void ArmVIXLJNIMacroAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, ArrayRef<const ManagedRegister> callee_save_regs, const ManagedRegisterEntrySpills& entry_spills) { - CHECK_ALIGNED(frame_size, kStackAlignment); - CHECK(r0.Is(AsVIXLRegister(method_reg.AsArm()))); + // If we're creating an actual frame with the method, enforce managed stack alignment, + // otherwise only the native stack alignment. + if (method_reg.IsNoRegister()) { + CHECK_ALIGNED_PARAM(frame_size, kAapcsStackAlignment); + } else { + CHECK_ALIGNED_PARAM(frame_size, kStackAlignment); + } // Push callee saves and link register. - RegList core_spill_mask = 1 << LR; + RegList core_spill_mask = 0; uint32_t fp_spill_mask = 0; for (const ManagedRegister& reg : callee_save_regs) { if (reg.AsArm().IsCoreRegister()) { @@ -95,9 +96,11 @@ void ArmVIXLJNIMacroAssembler::BuildFrame(size_t frame_size, fp_spill_mask |= 1 << reg.AsArm().AsSRegister(); } } - ___ Push(RegisterList(core_spill_mask)); - cfi().AdjustCFAOffset(POPCOUNT(core_spill_mask) * kFramePointerSize); - cfi().RelOffsetForMany(DWARFReg(r0), 0, core_spill_mask, kFramePointerSize); + if (core_spill_mask != 0u) { + ___ Push(RegisterList(core_spill_mask)); + cfi().AdjustCFAOffset(POPCOUNT(core_spill_mask) * kFramePointerSize); + cfi().RelOffsetForMany(DWARFReg(r0), 0, core_spill_mask, kFramePointerSize); + } if (fp_spill_mask != 0) { uint32_t first = CTZ(fp_spill_mask); @@ -111,12 +114,15 @@ void ArmVIXLJNIMacroAssembler::BuildFrame(size_t frame_size, // Increase frame to required size. int pushed_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask); - // Must at least have space for Method*. - CHECK_GT(frame_size, pushed_values * kFramePointerSize); + // Must at least have space for Method* if we're going to spill it. + CHECK_GE(frame_size, (pushed_values + (method_reg.IsRegister() ? 1u : 0u)) * kFramePointerSize); IncreaseFrameSize(frame_size - pushed_values * kFramePointerSize); // handles CFI as well. - // Write out Method*. - asm_.StoreToOffset(kStoreWord, r0, sp, 0); + if (method_reg.IsRegister()) { + // Write out Method*. + CHECK(r0.Is(AsVIXLRegister(method_reg.AsArm()))); + asm_.StoreToOffset(kStoreWord, r0, sp, 0); + } // Write out entry spills. int32_t offset = frame_size + kFramePointerSize; @@ -141,27 +147,27 @@ void ArmVIXLJNIMacroAssembler::BuildFrame(size_t frame_size, void ArmVIXLJNIMacroAssembler::RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs, bool may_suspend) { - CHECK_ALIGNED(frame_size, kStackAlignment); + CHECK_ALIGNED(frame_size, kAapcsStackAlignment); cfi().RememberState(); - // Compute callee saves to pop and LR. - RegList core_spill_mask = 1 << LR; - uint32_t fp_spill_mask = 0; + // Compute callee saves to pop. + RegList core_spill_mask = 0u; + uint32_t fp_spill_mask = 0u; for (const ManagedRegister& reg : callee_save_regs) { if (reg.AsArm().IsCoreRegister()) { - core_spill_mask |= 1 << reg.AsArm().AsCoreRegister(); + core_spill_mask |= 1u << reg.AsArm().AsCoreRegister(); } else { - fp_spill_mask |= 1 << reg.AsArm().AsSRegister(); + fp_spill_mask |= 1u << reg.AsArm().AsSRegister(); } } // Decrease frame to start of callee saves. - int pop_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask); - CHECK_GT(frame_size, pop_values * kFramePointerSize); + size_t pop_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask); + CHECK_GE(frame_size, pop_values * kFramePointerSize); DecreaseFrameSize(frame_size - (pop_values * kFramePointerSize)); // handles CFI as well. // Pop FP callee saves. - if (fp_spill_mask != 0) { + if (fp_spill_mask != 0u) { uint32_t first = CTZ(fp_spill_mask); // Check that list is contiguous. DCHECK_EQ(fp_spill_mask >> CTZ(fp_spill_mask), ~0u >> (32 - POPCOUNT(fp_spill_mask))); @@ -172,7 +178,9 @@ void ArmVIXLJNIMacroAssembler::RemoveFrame(size_t frame_size, } // Pop core callee saves and LR. - ___ Pop(RegisterList(core_spill_mask)); + if (core_spill_mask != 0u) { + ___ Pop(RegisterList(core_spill_mask)); + } if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) { if (may_suspend) { @@ -181,11 +189,8 @@ void ArmVIXLJNIMacroAssembler::RemoveFrame(size_t frame_size, } else { // The method shall not be suspended; no need to refresh the Marking Register. - // Check that the Marking Register is a callee-save register, - // and thus has been preserved by native code following the - // AAPCS calling convention. - DCHECK_NE(core_spill_mask & (1 << MR), 0) - << "core_spill_mask should contain Marking Register R" << MR; + // The Marking Register is a callee-save register, and thus has been + // preserved by native code following the AAPCS calling convention. // The following condition is a compile-time one, so it does not have a run-time cost. if (kIsDebugBuild) { @@ -214,13 +219,17 @@ void ArmVIXLJNIMacroAssembler::RemoveFrame(size_t frame_size, void ArmVIXLJNIMacroAssembler::IncreaseFrameSize(size_t adjust) { - asm_.AddConstant(sp, -adjust); - cfi().AdjustCFAOffset(adjust); + if (adjust != 0u) { + asm_.AddConstant(sp, -adjust); + cfi().AdjustCFAOffset(adjust); + } } void ArmVIXLJNIMacroAssembler::DecreaseFrameSize(size_t adjust) { - asm_.AddConstant(sp, adjust); - cfi().AdjustCFAOffset(-adjust); + if (adjust != 0u) { + asm_.AddConstant(sp, adjust); + cfi().AdjustCFAOffset(-adjust); + } } void ArmVIXLJNIMacroAssembler::Store(FrameOffset dest, ManagedRegister m_src, size_t size) { @@ -570,6 +579,17 @@ void ArmVIXLJNIMacroAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED, // TODO: not validating references. } +void ArmVIXLJNIMacroAssembler::Jump(ManagedRegister mbase, + Offset offset, + ManagedRegister mscratch) { + vixl::aarch32::Register base = AsVIXLRegister(mbase.AsArm()); + vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm()); + UseScratchRegisterScope temps(asm_.GetVIXLAssembler()); + temps.Exclude(scratch); + asm_.LoadFromOffset(kLoadWord, scratch, base, offset.Int32Value()); + ___ Bx(scratch); +} + void ArmVIXLJNIMacroAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) { @@ -610,7 +630,7 @@ void ArmVIXLJNIMacroAssembler::GetCurrentThread(FrameOffset dest_offset, } void ArmVIXLJNIMacroAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) { - CHECK_ALIGNED(stack_adjust, kStackAlignment); + CHECK_ALIGNED(stack_adjust, kAapcsStackAlignment); vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm()); UseScratchRegisterScope temps(asm_.GetVIXLAssembler()); temps.Exclude(scratch); diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.h b/compiler/utils/arm/jni_macro_assembler_arm_vixl.h index 0b1b6d2ba9..1724671fde 100644 --- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.h +++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.h @@ -181,6 +181,9 @@ class ArmVIXLJNIMacroAssembler final void VerifyObject(ManagedRegister src, bool could_be_null) override; void VerifyObject(FrameOffset src, bool could_be_null) override; + // Jump to address held at [base+offset] (used for tail calls). + void Jump(ManagedRegister base, Offset offset, ManagedRegister scratch) override; + // Call to address held at [base+offset]. void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) override; void Call(FrameOffset base, Offset offset, ManagedRegister scratch) override; diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc index d7ade058a4..d722e00646 100644 --- a/compiler/utils/arm64/assembler_arm64.cc +++ b/compiler/utils/arm64/assembler_arm64.cc @@ -49,6 +49,7 @@ static void SetVIXLCPUFeaturesFromART(vixl::aarch64::MacroAssembler* vixl_masm_, } if (art_features->HasFP16()) { features->Combine(vixl::CPUFeatures::kFPHalf); + features->Combine(vixl::CPUFeatures::kNEONHalf); } if (art_features->HasLSE()) { features->Combine(vixl::CPUFeatures::kAtomics); @@ -103,15 +104,6 @@ void Arm64Assembler::JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister ___ Br(reg_x(scratch.AsXRegister())); } -static inline dwarf::Reg DWARFReg(CPURegister reg) { - if (reg.IsFPRegister()) { - return dwarf::Reg::Arm64Fp(reg.GetCode()); - } else { - DCHECK_LT(reg.GetCode(), 31u); // X0 - X30. - return dwarf::Reg::Arm64Core(reg.GetCode()); - } -} - void Arm64Assembler::SpillRegisters(CPURegList registers, int offset) { int size = registers.GetRegisterSizeInBytes(); const Register sp = vixl_masm_.StackPointer(); diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h index 9e01a70ea9..fe2f1766c2 100644 --- a/compiler/utils/arm64/assembler_arm64.h +++ b/compiler/utils/arm64/assembler_arm64.h @@ -25,6 +25,7 @@ #include "base/arena_containers.h" #include "base/macros.h" +#include "dwarf/register.h" #include "offsets.h" #include "utils/arm64/managed_register_arm64.h" #include "utils/assembler.h" @@ -42,6 +43,15 @@ class Arm64InstructionSetFeatures; namespace arm64 { +static inline dwarf::Reg DWARFReg(vixl::aarch64::CPURegister reg) { + if (reg.IsFPRegister()) { + return dwarf::Reg::Arm64Fp(reg.GetCode()); + } else { + DCHECK_LT(reg.GetCode(), 31u); // X0 - X30. + return dwarf::Reg::Arm64Core(reg.GetCode()); + } +} + #define MEM_OP(...) vixl::aarch64::MemOperand(__VA_ARGS__) enum LoadOperandType { @@ -140,12 +150,12 @@ class Arm64Assembler final : public Assembler { return vixl::aarch64::Register::GetWRegFromCode(code); } - static vixl::aarch64::FPRegister reg_d(int code) { - return vixl::aarch64::FPRegister::GetDRegFromCode(code); + static vixl::aarch64::VRegister reg_d(int code) { + return vixl::aarch64::VRegister::GetDRegFromCode(code); } - static vixl::aarch64::FPRegister reg_s(int code) { - return vixl::aarch64::FPRegister::GetSRegFromCode(code); + static vixl::aarch64::VRegister reg_s(int code) { + return vixl::aarch64::VRegister::GetSRegFromCode(code); } private: diff --git a/compiler/utils/arm64/jni_macro_assembler_arm64.cc b/compiler/utils/arm64/jni_macro_assembler_arm64.cc index d6ce03387c..5b46971a09 100644 --- a/compiler/utils/arm64/jni_macro_assembler_arm64.cc +++ b/compiler/utils/arm64/jni_macro_assembler_arm64.cc @@ -37,6 +37,10 @@ namespace arm64 { #define reg_d(D) Arm64Assembler::reg_d(D) #define reg_s(S) Arm64Assembler::reg_s(S) +// The AAPCS64 requires 16-byte alignement. This is the same as the Managed ABI stack alignment. +static constexpr size_t kAapcs64StackAlignment = 16u; +static_assert(kAapcs64StackAlignment == kStackAlignment); + Arm64JNIMacroAssembler::~Arm64JNIMacroAssembler() { } @@ -57,16 +61,20 @@ void Arm64JNIMacroAssembler::GetCurrentThread(FrameOffset offset, ManagedRegiste // See Arm64 PCS Section 5.2.2.1. void Arm64JNIMacroAssembler::IncreaseFrameSize(size_t adjust) { - CHECK_ALIGNED(adjust, kStackAlignment); - AddConstant(SP, -adjust); - cfi().AdjustCFAOffset(adjust); + if (adjust != 0u) { + CHECK_ALIGNED(adjust, kStackAlignment); + AddConstant(SP, -adjust); + cfi().AdjustCFAOffset(adjust); + } } // See Arm64 PCS Section 5.2.2.1. void Arm64JNIMacroAssembler::DecreaseFrameSize(size_t adjust) { - CHECK_ALIGNED(adjust, kStackAlignment); - AddConstant(SP, adjust); - cfi().AdjustCFAOffset(-adjust); + if (adjust != 0u) { + CHECK_ALIGNED(adjust, kStackAlignment); + AddConstant(SP, adjust); + cfi().AdjustCFAOffset(-adjust); + } } void Arm64JNIMacroAssembler::AddConstant(XRegister rd, int32_t value, Condition cond) { @@ -531,6 +539,15 @@ void Arm64JNIMacroAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_n // TODO: not validating references. } +void Arm64JNIMacroAssembler::Jump(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch) { + Arm64ManagedRegister base = m_base.AsArm64(); + Arm64ManagedRegister scratch = m_scratch.AsArm64(); + CHECK(base.IsXRegister()) << base; + CHECK(scratch.IsXRegister()) << scratch; + LoadFromOffset(scratch.AsXRegister(), base.AsXRegister(), offs.Int32Value()); + ___ Br(reg_x(scratch.AsXRegister())); +} + void Arm64JNIMacroAssembler::Call(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch) { Arm64ManagedRegister base = m_base.AsArm64(); Arm64ManagedRegister scratch = m_scratch.AsArm64(); @@ -689,7 +706,7 @@ void Arm64JNIMacroAssembler::BuildFrame(size_t frame_size, const ManagedRegisterEntrySpills& entry_spills) { // Setup VIXL CPURegList for callee-saves. CPURegList core_reg_list(CPURegister::kRegister, kXRegSize, 0); - CPURegList fp_reg_list(CPURegister::kFPRegister, kDRegSize, 0); + CPURegList fp_reg_list(CPURegister::kVRegister, kDRegSize, 0); for (auto r : callee_save_regs) { Arm64ManagedRegister reg = r.AsArm64(); if (reg.IsXRegister()) { @@ -704,18 +721,20 @@ void Arm64JNIMacroAssembler::BuildFrame(size_t frame_size, // Increase frame to required size. DCHECK_ALIGNED(frame_size, kStackAlignment); - DCHECK_GE(frame_size, core_reg_size + fp_reg_size + static_cast<size_t>(kArm64PointerSize)); + // Must at least have space for Method* if we're going to spill it. + DCHECK_GE(frame_size, + core_reg_size + fp_reg_size + (method_reg.IsRegister() ? kXRegSizeInBytes : 0u)); IncreaseFrameSize(frame_size); // Save callee-saves. asm_.SpillRegisters(core_reg_list, frame_size - core_reg_size); asm_.SpillRegisters(fp_reg_list, frame_size - core_reg_size - fp_reg_size); - DCHECK(core_reg_list.IncludesAliasOf(reg_x(TR))); - - // Write ArtMethod* - DCHECK(X0 == method_reg.AsArm64().AsXRegister()); - StoreToOffset(X0, SP, 0); + if (method_reg.IsRegister()) { + // Write ArtMethod* + DCHECK(X0 == method_reg.AsArm64().AsXRegister()); + StoreToOffset(X0, SP, 0); + } // Write out entry spills int32_t offset = frame_size + static_cast<size_t>(kArm64PointerSize); @@ -745,7 +764,7 @@ void Arm64JNIMacroAssembler::RemoveFrame(size_t frame_size, bool may_suspend) { // Setup VIXL CPURegList for callee-saves. CPURegList core_reg_list(CPURegister::kRegister, kXRegSize, 0); - CPURegList fp_reg_list(CPURegister::kFPRegister, kDRegSize, 0); + CPURegList fp_reg_list(CPURegister::kVRegister, kDRegSize, 0); for (auto r : callee_save_regs) { Arm64ManagedRegister reg = r.AsArm64(); if (reg.IsXRegister()) { @@ -760,10 +779,8 @@ void Arm64JNIMacroAssembler::RemoveFrame(size_t frame_size, // For now we only check that the size of the frame is large enough to hold spills and method // reference. - DCHECK_GE(frame_size, core_reg_size + fp_reg_size + static_cast<size_t>(kArm64PointerSize)); - DCHECK_ALIGNED(frame_size, kStackAlignment); - - DCHECK(core_reg_list.IncludesAliasOf(reg_x(TR))); + DCHECK_GE(frame_size, core_reg_size + fp_reg_size); + DCHECK_ALIGNED(frame_size, kAapcs64StackAlignment); cfi().RememberState(); @@ -781,11 +798,8 @@ void Arm64JNIMacroAssembler::RemoveFrame(size_t frame_size, } else { // The method shall not be suspended; no need to refresh the Marking Register. - // Check that the Marking Register is a callee-save register, - // and thus has been preserved by native code following the - // AAPCS64 calling convention. - DCHECK(core_reg_list.IncludesAliasOf(mr)) - << "core_reg_list should contain Marking Register X" << mr.GetCode(); + // The Marking Register is a callee-save register and thus has been + // preserved by native code following the AAPCS64 calling convention. // The following condition is a compile-time one, so it does not have a run-time cost. if (kIsDebugBuild) { diff --git a/compiler/utils/arm64/jni_macro_assembler_arm64.h b/compiler/utils/arm64/jni_macro_assembler_arm64.h index 45316ed88e..54592a3fcb 100644 --- a/compiler/utils/arm64/jni_macro_assembler_arm64.h +++ b/compiler/utils/arm64/jni_macro_assembler_arm64.h @@ -162,6 +162,9 @@ class Arm64JNIMacroAssembler final : public JNIMacroAssemblerFwd<Arm64Assembler, void VerifyObject(ManagedRegister src, bool could_be_null) override; void VerifyObject(FrameOffset src, bool could_be_null) override; + // Jump to address held at [base+offset] (used for tail calls). + void Jump(ManagedRegister base, Offset offset, ManagedRegister scratch) override; + // Call to address held at [base+offset]. void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) override; void Call(FrameOffset base, Offset offset, ManagedRegister scratch) override; diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h index aa21f862de..0744aec2f7 100644 --- a/compiler/utils/assembler.h +++ b/compiler/utils/assembler.h @@ -33,7 +33,6 @@ #include "dwarf/debug_frame_opcode_writer.h" #include "label.h" #include "managed_register.h" -#include "mips/constants_mips.h" #include "offsets.h" #include "x86/constants_x86.h" #include "x86_64/constants_x86_64.h" diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc index 842716fac3..6475607076 100644 --- a/compiler/utils/assembler_thumb_test_expected.cc.inc +++ b/compiler/utils/assembler_thumb_test_expected.cc.inc @@ -76,7 +76,7 @@ const char* const VixlJniHelpersResults[] = { " f0: f1bc 0f00 cmp.w ip, #0\n", " f4: bf18 it ne\n", " f6: f20d 4c01 addwne ip, sp, #1025 ; 0x401\n", - " fa: f8d9 c09c ldr.w ip, [r9, #156] ; 0x9c\n", + " fa: f8d9 c0a4 ldr.w ip, [r9, #164] ; 0xa4\n", " fe: f1bc 0f00 cmp.w ip, #0\n", " 102: d171 bne.n 1e8 <VixlJniHelpers+0x1e8>\n", " 104: f8cd c7ff str.w ip, [sp, #2047] ; 0x7ff\n", @@ -153,7 +153,7 @@ const char* const VixlJniHelpersResults[] = { " 21c: f8d9 8034 ldr.w r8, [r9, #52] ; 0x34\n", " 220: 4770 bx lr\n", " 222: 4660 mov r0, ip\n", - " 224: f8d9 c2e4 ldr.w ip, [r9, #740] ; 0x2e4\n", + " 224: f8d9 c2e8 ldr.w ip, [r9, #744] ; 0x2e8\n", " 228: 47e0 blx ip\n", nullptr }; diff --git a/compiler/utils/intrusive_forward_list.h b/compiler/utils/intrusive_forward_list.h deleted file mode 100644 index ccdd32aad4..0000000000 --- a/compiler/utils/intrusive_forward_list.h +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_UTILS_INTRUSIVE_FORWARD_LIST_H_ -#define ART_COMPILER_UTILS_INTRUSIVE_FORWARD_LIST_H_ - -#include <stdint.h> -#include <functional> -#include <iterator> -#include <memory> -#include <type_traits> - -#include <android-base/logging.h> - -#include "base/casts.h" -#include "base/macros.h" - -namespace art { - -struct IntrusiveForwardListHook { - IntrusiveForwardListHook() : next_hook(nullptr) { } - explicit IntrusiveForwardListHook(const IntrusiveForwardListHook* hook) : next_hook(hook) { } - - // Allow copyable values but do not copy the hook, it is not part of the value. - IntrusiveForwardListHook(const IntrusiveForwardListHook& other ATTRIBUTE_UNUSED) - : next_hook(nullptr) { } - IntrusiveForwardListHook& operator=(const IntrusiveForwardListHook& src ATTRIBUTE_UNUSED) { - return *this; - } - - mutable const IntrusiveForwardListHook* next_hook; -}; - -template <typename Derived, typename Tag = void> -struct IntrusiveForwardListNode : public IntrusiveForwardListHook { -}; - -template <typename T, IntrusiveForwardListHook T::* NextPtr = &T::hook> -class IntrusiveForwardListMemberHookTraits; - -template <typename T, typename Tag = void> -class IntrusiveForwardListBaseHookTraits; - -template <typename T, - typename HookTraits = - IntrusiveForwardListBaseHookTraits<typename std::remove_const<T>::type>> -class IntrusiveForwardList; - -template <typename T, typename HookTraits> -class IntrusiveForwardListIterator : public std::iterator<std::forward_iterator_tag, T> { - public: - // Construct/copy/destroy (except the private constructor used by IntrusiveForwardList<>). - IntrusiveForwardListIterator() : hook_(nullptr) { } - IntrusiveForwardListIterator(const IntrusiveForwardListIterator& src) = default; - IntrusiveForwardListIterator& operator=(const IntrusiveForwardListIterator& src) = default; - - // Conversion from iterator to const_iterator. - template <typename OtherT, - typename = typename std::enable_if<std::is_same<T, const OtherT>::value>::type> - IntrusiveForwardListIterator(const IntrusiveForwardListIterator<OtherT, HookTraits>& src) // NOLINT, implicit - : hook_(src.hook_) { } - - // Iteration. - IntrusiveForwardListIterator& operator++() { - DCHECK(hook_ != nullptr); - hook_ = hook_->next_hook; - return *this; - } - IntrusiveForwardListIterator operator++(int) { - IntrusiveForwardListIterator tmp(*this); - ++*this; - return tmp; - } - - // Dereference - T& operator*() const { - DCHECK(hook_ != nullptr); - return *HookTraits::GetValue(hook_); - } - T* operator->() const { - return &**this; - } - - private: - explicit IntrusiveForwardListIterator(const IntrusiveForwardListHook* hook) : hook_(hook) { } - - const IntrusiveForwardListHook* hook_; - - template <typename OtherT, typename OtherTraits> - friend class IntrusiveForwardListIterator; - - template <typename OtherT, typename OtherTraits> - friend class IntrusiveForwardList; - - template <typename OtherT1, typename OtherT2, typename OtherTraits> - friend typename std::enable_if<std::is_same<const OtherT1, const OtherT2>::value, bool>::type - operator==(const IntrusiveForwardListIterator<OtherT1, OtherTraits>& lhs, - const IntrusiveForwardListIterator<OtherT2, OtherTraits>& rhs); -}; - -template <typename T, typename OtherT, typename HookTraits> -typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator==( - const IntrusiveForwardListIterator<T, HookTraits>& lhs, - const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) { - return lhs.hook_ == rhs.hook_; -} - -template <typename T, typename OtherT, typename HookTraits> -typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator!=( - const IntrusiveForwardListIterator<T, HookTraits>& lhs, - const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) { - return !(lhs == rhs); -} - -// Intrusive version of std::forward_list<>. See also slist<> in Boost.Intrusive. -// -// This class template provides the same interface as std::forward_list<> as long -// as the functions are meaningful for an intrusive container; this excludes emplace -// functions and functions taking an std::initializer_list<> as the container does -// not construct elements. -template <typename T, typename HookTraits> -class IntrusiveForwardList { - public: - typedef HookTraits hook_traits; - typedef T value_type; - typedef T& reference; - typedef const T& const_reference; - typedef T* pointer; - typedef const T* const_pointer; - typedef IntrusiveForwardListIterator< T, hook_traits> iterator; - typedef IntrusiveForwardListIterator<const T, hook_traits> const_iterator; - - // Construct/copy/destroy. - IntrusiveForwardList() = default; - template <typename InputIterator> - IntrusiveForwardList(InputIterator first, InputIterator last) : IntrusiveForwardList() { - insert_after(before_begin(), first, last); - } - IntrusiveForwardList(IntrusiveForwardList&& src) : first_(src.first_.next_hook) { - src.first_.next_hook = nullptr; - } - IntrusiveForwardList& operator=(const IntrusiveForwardList& src) = delete; - IntrusiveForwardList& operator=(IntrusiveForwardList&& src) { - IntrusiveForwardList tmp(std::move(src)); - tmp.swap(*this); - return *this; - } - ~IntrusiveForwardList() = default; - - // Iterators. - iterator before_begin() { return iterator(&first_); } - const_iterator before_begin() const { return const_iterator(&first_); } - iterator begin() { return iterator(first_.next_hook); } - const_iterator begin() const { return const_iterator(first_.next_hook); } - iterator end() { return iterator(nullptr); } - const_iterator end() const { return const_iterator(nullptr); } - const_iterator cbefore_begin() const { return const_iterator(&first_); } - const_iterator cbegin() const { return const_iterator(first_.next_hook); } - const_iterator cend() const { return const_iterator(nullptr); } - - // Capacity. - bool empty() const { return begin() == end(); } - size_t max_size() { return static_cast<size_t>(-1); } - - // Element access. - reference front() { return *begin(); } - const_reference front() const { return *begin(); } - - // Modifiers. - template <typename InputIterator> - void assign(InputIterator first, InputIterator last) { - IntrusiveForwardList tmp(first, last); - tmp.swap(*this); - } - void push_front(value_type& value) { - insert_after(before_begin(), value); - } - void pop_front() { - DCHECK(!empty()); - erase_after(before_begin()); - } - iterator insert_after(const_iterator position, value_type& value) { - const IntrusiveForwardListHook* new_hook = hook_traits::GetHook(&value); - new_hook->next_hook = position.hook_->next_hook; - position.hook_->next_hook = new_hook; - return iterator(new_hook); - } - template <typename InputIterator> - iterator insert_after(const_iterator position, InputIterator first, InputIterator last) { - while (first != last) { - position = insert_after(position, *first++); - } - return iterator(position.hook_); - } - iterator erase_after(const_iterator position) { - const_iterator last = position; - std::advance(last, 2); - return erase_after(position, last); - } - iterator erase_after(const_iterator position, const_iterator last) { - DCHECK(position != last); - position.hook_->next_hook = last.hook_; - return iterator(last.hook_); - } - void swap(IntrusiveForwardList& other) { - std::swap(first_.next_hook, other.first_.next_hook); - } - void clear() { - first_.next_hook = nullptr; - } - - // Operations. - void splice_after(const_iterator position, IntrusiveForwardList& src) { - DCHECK(position != end()); - splice_after(position, src, src.before_begin(), src.end()); - } - void splice_after(const_iterator position, IntrusiveForwardList&& src) { - splice_after(position, src); // Use l-value overload. - } - // Splice the element after `i`. - void splice_after(const_iterator position, IntrusiveForwardList& src, const_iterator i) { - // The standard specifies that this version does nothing if `position == i` - // or `position == ++i`. We must handle the latter here because the overload - // `splice_after(position, src, first, last)` does not allow `position` inside - // the range `(first, last)`. - if (++const_iterator(i) == position) { - return; - } - const_iterator last = i; - std::advance(last, 2); - splice_after(position, src, i, last); - } - // Splice the element after `i`. - void splice_after(const_iterator position, IntrusiveForwardList&& src, const_iterator i) { - splice_after(position, src, i); // Use l-value overload. - } - // Splice elements between `first` and `last`, i.e. open range `(first, last)`. - void splice_after(const_iterator position, - IntrusiveForwardList& src, - const_iterator first, - const_iterator last) { - DCHECK(position != end()); - DCHECK(first != last); - if (++const_iterator(first) == last) { - // Nothing to do. - return; - } - // If position is just before end() and last is src.end(), we can finish this quickly. - if (++const_iterator(position) == end() && last == src.end()) { - position.hook_->next_hook = first.hook_->next_hook; - first.hook_->next_hook = nullptr; - return; - } - // Otherwise we need to find the position before last to fix up the hook. - const_iterator before_last = first; - while (++const_iterator(before_last) != last) { - ++before_last; - } - // Detach (first, last). - const IntrusiveForwardListHook* first_taken = first.hook_->next_hook; - first.hook_->next_hook = last.hook_; - // Attach the sequence to the new position. - before_last.hook_->next_hook = position.hook_->next_hook; - position.hook_->next_hook = first_taken; - } - // Splice elements between `first` and `last`, i.e. open range `(first, last)`. - void splice_after(const_iterator position, - IntrusiveForwardList&& src, - const_iterator first, - const_iterator last) { - splice_after(position, src, first, last); // Use l-value overload. - } - void remove(const value_type& value) { - remove_if([value](const value_type& v) { return value == v; }); - } - template <typename Predicate> - void remove_if(Predicate pred) { - iterator prev = before_begin(); - for (iterator current = begin(); current != end(); ++current) { - if (pred(*current)) { - erase_after(prev); - current = prev; - } else { - prev = current; - } - } - } - void unique() { - unique(std::equal_to<value_type>()); - } - template <typename BinaryPredicate> - void unique(BinaryPredicate pred) { - if (!empty()) { - iterator prev = begin(); - iterator current = prev; - ++current; - for (; current != end(); ++current) { - if (pred(*prev, *current)) { - erase_after(prev); - current = prev; - } else { - prev = current; - } - } - } - } - void merge(IntrusiveForwardList& other) { - merge(other, std::less<value_type>()); - } - void merge(IntrusiveForwardList&& other) { - merge(other); // Use l-value overload. - } - template <typename Compare> - void merge(IntrusiveForwardList& other, Compare cmp) { - iterator prev = before_begin(); - iterator current = begin(); - iterator other_prev = other.before_begin(); - iterator other_current = other.begin(); - while (current != end() && other_current != other.end()) { - if (cmp(*other_current, *current)) { - ++other_current; - splice_after(prev, other, other_prev); - ++prev; - } else { - prev = current; - ++current; - } - DCHECK(++const_iterator(prev) == current); - DCHECK(++const_iterator(other_prev) == other_current); - } - splice_after(prev, other); - } - template <typename Compare> - void merge(IntrusiveForwardList&& other, Compare cmp) { - merge(other, cmp); // Use l-value overload. - } - void sort() { - sort(std::less<value_type>()); - } - template <typename Compare> - void sort(Compare cmp) { - size_t n = std::distance(begin(), end()); - if (n >= 2u) { - const_iterator middle = before_begin(); - std::advance(middle, n / 2u); - IntrusiveForwardList second_half; - second_half.splice_after(second_half.before_begin(), *this, middle, end()); - sort(cmp); - second_half.sort(cmp); - merge(second_half, cmp); - } - } - void reverse() { - IntrusiveForwardList reversed; - while (!empty()) { - value_type& value = front(); - erase_after(before_begin()); - reversed.insert_after(reversed.before_begin(), value); - } - reversed.swap(*this); - } - - // Extensions. - bool HasExactlyOneElement() const { - return !empty() && ++begin() == end(); - } - size_t SizeSlow() const { - return std::distance(begin(), end()); - } - bool ContainsNode(const_reference node) const { - for (auto&& n : *this) { - if (std::addressof(n) == std::addressof(node)) { - return true; - } - } - return false; - } - - private: - static IntrusiveForwardListHook* ModifiableHook(const IntrusiveForwardListHook* hook) { - return const_cast<IntrusiveForwardListHook*>(hook); - } - - IntrusiveForwardListHook first_; -}; - -template <typename T, typename HookTraits> -void swap(IntrusiveForwardList<T, HookTraits>& lhs, IntrusiveForwardList<T, HookTraits>& rhs) { - lhs.swap(rhs); -} - -template <typename T, typename HookTraits> -bool operator==(const IntrusiveForwardList<T, HookTraits>& lhs, - const IntrusiveForwardList<T, HookTraits>& rhs) { - auto lit = lhs.begin(); - auto rit = rhs.begin(); - for (; lit != lhs.end() && rit != rhs.end(); ++lit, ++rit) { - if (*lit != *rit) { - return false; - } - } - return lit == lhs.end() && rit == rhs.end(); -} - -template <typename T, typename HookTraits> -bool operator!=(const IntrusiveForwardList<T, HookTraits>& lhs, - const IntrusiveForwardList<T, HookTraits>& rhs) { - return !(lhs == rhs); -} - -template <typename T, typename HookTraits> -bool operator<(const IntrusiveForwardList<T, HookTraits>& lhs, - const IntrusiveForwardList<T, HookTraits>& rhs) { - return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); -} - -template <typename T, typename HookTraits> -bool operator>(const IntrusiveForwardList<T, HookTraits>& lhs, - const IntrusiveForwardList<T, HookTraits>& rhs) { - return rhs < lhs; -} - -template <typename T, typename HookTraits> -bool operator<=(const IntrusiveForwardList<T, HookTraits>& lhs, - const IntrusiveForwardList<T, HookTraits>& rhs) { - return !(rhs < lhs); -} - -template <typename T, typename HookTraits> -bool operator>=(const IntrusiveForwardList<T, HookTraits>& lhs, - const IntrusiveForwardList<T, HookTraits>& rhs) { - return !(lhs < rhs); -} - -template <typename T, IntrusiveForwardListHook T::* NextPtr> -class IntrusiveForwardListMemberHookTraits { - public: - static const IntrusiveForwardListHook* GetHook(const T* value) { - return &(value->*NextPtr); - } - - static T* GetValue(const IntrusiveForwardListHook* hook) { - return reinterpret_cast<T*>( - reinterpret_cast<uintptr_t>(hook) - OFFSETOF_MEMBERPTR(T, NextPtr)); - } -}; - -template <typename T, typename Tag> -class IntrusiveForwardListBaseHookTraits { - public: - static const IntrusiveForwardListHook* GetHook(const T* value) { - // Explicit conversion to the "node" followed by implicit conversion to the "hook". - return static_cast<const IntrusiveForwardListNode<T, Tag>*>(value); - } - - static T* GetValue(const IntrusiveForwardListHook* hook) { - return down_cast<T*>(down_cast<IntrusiveForwardListNode<T, Tag>*>( - const_cast<IntrusiveForwardListHook*>(hook))); - } -}; - -} // namespace art - -#endif // ART_COMPILER_UTILS_INTRUSIVE_FORWARD_LIST_H_ diff --git a/compiler/utils/intrusive_forward_list_test.cc b/compiler/utils/intrusive_forward_list_test.cc deleted file mode 100644 index e97c3044d0..0000000000 --- a/compiler/utils/intrusive_forward_list_test.cc +++ /dev/null @@ -1,779 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <algorithm> -#include <forward_list> -#include <vector> - -#include "gtest/gtest.h" -#include "intrusive_forward_list.h" - -namespace art { - -struct IFLTestValue : public IntrusiveForwardListNode<IFLTestValue> { - // Deliberately not explicit. - IFLTestValue(int v) : value(v) { } // NOLINT(runtime/explicit) - - int value; -}; -using IFLTestValueList = IntrusiveForwardList<IFLTestValue>; -using ConstIFLTestValueList = IntrusiveForwardList<const IFLTestValue>; - -bool operator==(const IFLTestValue& lhs, const IFLTestValue& rhs) { - return lhs.value == rhs.value; -} - -bool operator<(const IFLTestValue& lhs, const IFLTestValue& rhs) { - return lhs.value < rhs.value; -} - -struct IFLTestValue2 { - // Deliberately not explicit. - IFLTestValue2(int v) : hook(), value(v) { } // NOLINT(runtime/explicit) - - IntrusiveForwardListHook hook; - int value; -}; -using IFLTestValue2List = - IntrusiveForwardList<IFLTestValue2, IntrusiveForwardListMemberHookTraits<IFLTestValue2>>; - -bool operator==(const IFLTestValue2& lhs, const IFLTestValue2& rhs) { - return lhs.value == rhs.value; -} - -bool operator<(const IFLTestValue2& lhs, const IFLTestValue2& rhs) { - return lhs.value < rhs.value; -} - -#define ASSERT_LISTS_EQUAL(expected, value) \ - do { \ - ASSERT_EQ((expected).empty(), (value).empty()); \ - ASSERT_EQ(std::distance((expected).begin(), (expected).end()), \ - std::distance((value).begin(), (value).end())); \ - ASSERT_TRUE(std::equal((expected).begin(), (expected).end(), (value).begin())); \ - } while (false) - -class IntrusiveForwardListTest : public testing::Test { - public: - template <typename ListType> - void IteratorToConstIterator(); - - template <typename ListType> - void IteratorOperators(); - - template <typename ListType> - void ConstructRange(); - - template <typename ListType> - void Assign(); - - template <typename ListType> - void PushPop(); - - template <typename ListType> - void InsertAfter1(); - - template <typename ListType> - void InsertAfter2(); - - template <typename ListType> - void EraseAfter1(); - - template <typename ListType> - void EraseAfter2(); - - template <typename ListType> - void SwapClear(); - - template <typename ListType> - void SpliceAfter(); - - template <typename ListType> - void Remove(); - - template <typename ListType> - void Unique(); - - template <typename ListType> - void Merge(); - - template <typename ListType> - void Sort1(); - - template <typename ListType> - void Sort2(); - - template <typename ListType> - void Reverse(); - - template <typename ListType> - void ModifyValue(); -}; - -template <typename ListType> -void IntrusiveForwardListTest::IteratorToConstIterator() { - ListType ifl; - typename ListType::iterator begin = ifl.begin(); - typename ListType::const_iterator cbegin = ifl.cbegin(); - typename ListType::const_iterator converted_begin = begin; - ASSERT_TRUE(converted_begin == cbegin); -} - -TEST_F(IntrusiveForwardListTest, IteratorToConstIterator) { - IteratorToConstIterator<IFLTestValueList>(); - IteratorToConstIterator<ConstIFLTestValueList>(); - IteratorToConstIterator<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::IteratorOperators() { - using ValueType = typename ListType::value_type; - ListType ifl; - ASSERT_TRUE(ifl.begin() == ifl.cbegin()); - ASSERT_FALSE(ifl.begin() != ifl.cbegin()); - ASSERT_TRUE(ifl.end() == ifl.cend()); - ASSERT_FALSE(ifl.end() != ifl.cend()); - - ASSERT_TRUE(ifl.begin() == ifl.end()); // Empty. - ASSERT_FALSE(ifl.begin() != ifl.end()); // Empty. - - ValueType value(1); - ifl.insert_after(ifl.cbefore_begin(), value); - - ASSERT_FALSE(ifl.begin() == ifl.end()); // Not empty. - ASSERT_TRUE(ifl.begin() != ifl.end()); // Not empty. -} - -TEST_F(IntrusiveForwardListTest, IteratorOperators) { - IteratorOperators<IFLTestValueList>(); - IteratorOperators<ConstIFLTestValueList>(); - IteratorOperators<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::ConstructRange() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref({ 1, 2, 7 }); - std::vector<ValueType> storage(ref.begin(), ref.end()); - ListType ifl(storage.begin(), storage.end()); - ASSERT_LISTS_EQUAL(ref, ifl); -} - -TEST_F(IntrusiveForwardListTest, ConstructRange) { - ConstructRange<IFLTestValueList>(); - ConstructRange<ConstIFLTestValueList>(); - ConstructRange<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::Assign() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref1({ 2, 8, 5 }); - std::vector<ValueType> storage1(ref1.begin(), ref1.end()); - ListType ifl; - ifl.assign(storage1.begin(), storage1.end()); - ASSERT_LISTS_EQUAL(ref1, ifl); - std::forward_list<int> ref2({ 7, 1, 3 }); - std::vector<ValueType> storage2(ref2.begin(), ref2.end()); - ifl.assign(storage2.begin(), storage2.end()); - ASSERT_LISTS_EQUAL(ref2, ifl); -} - -TEST_F(IntrusiveForwardListTest, Assign) { - Assign<IFLTestValueList>(); - Assign<ConstIFLTestValueList>(); - Assign<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::PushPop() { - using ValueType = typename ListType::value_type; - ValueType value3(3); - ValueType value7(7); - std::forward_list<int> ref; - ListType ifl; - ASSERT_LISTS_EQUAL(ref, ifl); - ref.push_front(3); - ifl.push_front(value3); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(3, ifl.front()); - ref.push_front(7); - ifl.push_front(value7); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(7, ifl.front()); - ref.pop_front(); - ifl.pop_front(); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(3, ifl.front()); - ref.pop_front(); - ifl.pop_front(); - ASSERT_LISTS_EQUAL(ref, ifl); -} - -TEST_F(IntrusiveForwardListTest, PushPop) { - PushPop<IFLTestValueList>(); - PushPop<ConstIFLTestValueList>(); - PushPop<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::InsertAfter1() { - using ValueType = typename ListType::value_type; - ValueType value4(4); - ValueType value8(8); - ValueType value5(5); - ValueType value3(3); - std::forward_list<int> ref; - ListType ifl; - - auto ref_it = ref.insert_after(ref.before_begin(), 4); - auto ifl_it = ifl.insert_after(ifl.before_begin(), value4); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(*ref_it, *ifl_it); - CHECK(ref_it == ref.begin()); - ASSERT_TRUE(ifl_it == ifl.begin()); - - ref_it = ref.insert_after(ref.begin(), 8); - ifl_it = ifl.insert_after(ifl.begin(), value8); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(*ref_it, *ifl_it); - CHECK(ref_it != ref.end()); - ASSERT_TRUE(ifl_it != ifl.end()); - CHECK(++ref_it == ref.end()); - ASSERT_TRUE(++ifl_it == ifl.end()); - - ref_it = ref.insert_after(ref.begin(), 5); - ifl_it = ifl.insert_after(ifl.begin(), value5); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(*ref_it, *ifl_it); - - ref_it = ref.insert_after(ref_it, 3); - ifl_it = ifl.insert_after(ifl_it, value3); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(*ref_it, *ifl_it); -} - -TEST_F(IntrusiveForwardListTest, InsertAfter1) { - InsertAfter1<IFLTestValueList>(); - InsertAfter1<ConstIFLTestValueList>(); - InsertAfter1<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::InsertAfter2() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref; - ListType ifl; - - auto ref_it = ref.insert_after(ref.before_begin(), { 2, 8, 5 }); - std::vector<ValueType> storage1({ { 2 }, { 8 }, { 5 } }); - auto ifl_it = ifl.insert_after(ifl.before_begin(), storage1.begin(), storage1.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(*ref_it, *ifl_it); - - std::vector<ValueType> storage2({ { 7 }, { 2 } }); - ref_it = ref.insert_after(ref.begin(), { 7, 2 }); - ifl_it = ifl.insert_after(ifl.begin(), storage2.begin(), storage2.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(*ref_it, *ifl_it); - - std::vector<ValueType> storage3({ { 1 }, { 3 }, { 4 }, { 9 } }); - ref_it = ref.begin(); - ifl_it = ifl.begin(); - std::advance(ref_it, std::distance(ref.begin(), ref.end()) - 1); - std::advance(ifl_it, std::distance(ifl.begin(), ifl.end()) - 1); - ref_it = ref.insert_after(ref_it, { 1, 3, 4, 9 }); - ifl_it = ifl.insert_after(ifl_it, storage3.begin(), storage3.end()); - ASSERT_LISTS_EQUAL(ref, ifl); -} - -TEST_F(IntrusiveForwardListTest, InsertAfter2) { - InsertAfter2<IFLTestValueList>(); - InsertAfter2<ConstIFLTestValueList>(); - InsertAfter2<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::EraseAfter1() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref({ 1, 2, 7, 4, 5 }); - std::vector<ValueType> storage(ref.begin(), ref.end()); - ListType ifl(storage.begin(), storage.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 5); - - auto ref_it = ref.begin(); - auto ifl_it = ifl.begin(); - std::advance(ref_it, 2); - std::advance(ifl_it, 2); - ref_it = ref.erase_after(ref_it); - ifl_it = ifl.erase_after(ifl_it); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 4); - CHECK(ref_it != ref.end()); - ASSERT_TRUE(ifl_it != ifl.end()); - CHECK(++ref_it == ref.end()); - ASSERT_TRUE(++ifl_it == ifl.end()); - - ref_it = ref.begin(); - ifl_it = ifl.begin(); - std::advance(ref_it, 2); - std::advance(ifl_it, 2); - ref_it = ref.erase_after(ref_it); - ifl_it = ifl.erase_after(ifl_it); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 3); - CHECK(ref_it == ref.end()); - ASSERT_TRUE(ifl_it == ifl.end()); - - ref_it = ref.erase_after(ref.begin()); - ifl_it = ifl.erase_after(ifl.begin()); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 2); - CHECK(ref_it != ref.end()); - ASSERT_TRUE(ifl_it != ifl.end()); - CHECK(++ref_it == ref.end()); - ASSERT_TRUE(++ifl_it == ifl.end()); - - ref_it = ref.erase_after(ref.before_begin()); - ifl_it = ifl.erase_after(ifl.before_begin()); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 1); - CHECK(ref_it == ref.begin()); - ASSERT_TRUE(ifl_it == ifl.begin()); - - ref_it = ref.erase_after(ref.before_begin()); - ifl_it = ifl.erase_after(ifl.before_begin()); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 0); - CHECK(ref_it == ref.begin()); - ASSERT_TRUE(ifl_it == ifl.begin()); -} - -TEST_F(IntrusiveForwardListTest, EraseAfter1) { - EraseAfter1<IFLTestValueList>(); - EraseAfter1<ConstIFLTestValueList>(); - EraseAfter1<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::EraseAfter2() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref({ 1, 2, 7, 4, 5, 3, 2, 8, 9 }); - std::vector<ValueType> storage(ref.begin(), ref.end()); - ListType ifl(storage.begin(), storage.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 9); - - auto ref_it = ref.begin(); - auto ifl_it = ifl.begin(); - std::advance(ref_it, 3); - std::advance(ifl_it, 3); - ref_it = ref.erase_after(ref.begin(), ref_it); - ifl_it = ifl.erase_after(ifl.begin(), ifl_it); - ASSERT_LISTS_EQUAL(ref, ifl); - ASSERT_EQ(std::distance(ref.begin(), ref_it), std::distance(ifl.begin(), ifl_it)); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 7); - - ref_it = ref.erase_after(ref_it, ref.end()); - ifl_it = ifl.erase_after(ifl_it, ifl.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK(ref_it == ref.end()); - ASSERT_TRUE(ifl_it == ifl.end()); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 2); - - ref_it = ref.erase_after(ref.before_begin(), ref.end()); - ifl_it = ifl.erase_after(ifl.before_begin(), ifl.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK(ref_it == ref.end()); - ASSERT_TRUE(ifl_it == ifl.end()); - CHECK_EQ(std::distance(ref.begin(), ref.end()), 0); -} - -TEST_F(IntrusiveForwardListTest, EraseAfter2) { - EraseAfter2<IFLTestValueList>(); - EraseAfter2<ConstIFLTestValueList>(); - EraseAfter2<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::SwapClear() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref1({ 1, 2, 7 }); - std::vector<ValueType> storage1(ref1.begin(), ref1.end()); - ListType ifl1(storage1.begin(), storage1.end()); - std::forward_list<int> ref2({ 3, 8, 6 }); - std::vector<ValueType> storage2(ref2.begin(), ref2.end()); - ListType ifl2(storage2.begin(), storage2.end()); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - ref1.swap(ref2); - ifl1.swap(ifl2); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - ref1.clear(); - ifl1.clear(); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - swap(ref1, ref2); - swap(ifl1, ifl2); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - ref1.clear(); - ifl1.clear(); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); -} - -TEST_F(IntrusiveForwardListTest, SwapClear) { - SwapClear<IFLTestValueList>(); - SwapClear<ConstIFLTestValueList>(); - SwapClear<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::SpliceAfter() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref1({ 3, 1, 2, 7, 4, 5, 4, 8, 7 }); - std::forward_list<int> ref2; - std::vector<ValueType> storage(ref1.begin(), ref1.end()); - ListType ifl1(storage.begin(), storage.end()); - ListType ifl2; - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - - // Move everything to ref2/ifl2. - ref2.splice_after(ref2.before_begin(), ref1); - ifl2.splice_after(ifl2.before_begin(), ifl1); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - - // Move first element (3) to ref1/ifl1. - ref1.splice_after(ref1.before_begin(), ref2, ref2.before_begin()); - ifl1.splice_after(ifl1.before_begin(), ifl2, ifl2.before_begin()); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - - // Move second element (2) to ref1/ifl1 after the first element (3). - ref1.splice_after(ref1.begin(), ref2, ref2.begin()); - ifl1.splice_after(ifl1.begin(), ifl2, ifl2.begin()); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - - // Move everything from ref2/ifl2 between the 2 elements now in ref1/ifl1. - ref1.splice_after(ref1.begin(), ref2); - ifl1.splice_after(ifl1.begin(), ifl2); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - - std::forward_list<int> check({ 3, 1, 7, 4, 5, 4, 8, 7, 2 }); - ASSERT_LISTS_EQUAL(check, ifl1); - ASSERT_TRUE(ifl2.empty()); - - // Empty splice_after(). - ref2.splice_after( - ref2.before_begin(), ref1, ref1.before_begin(), ref1.begin()); - ifl2.splice_after(ifl2.before_begin(), ifl1, ifl1.before_begin(), ifl1.begin()); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - - // Move { 1, 7 } to ref2/ifl2. - auto ref_it = ref1.begin(); - auto ifl_it = ifl1.begin(); - std::advance(ref_it, 3); - std::advance(ifl_it, 3); - ref2.splice_after(ref2.before_begin(), ref1, ref1.begin(), ref_it); - ifl2.splice_after(ifl2.before_begin(), ifl1, ifl1.begin(), ifl_it); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - - // Move { 8, 7, 2 } to the beginning of ref1/ifl1. - ref_it = ref1.begin(); - ifl_it = ifl1.begin(); - std::advance(ref_it, 3); - std::advance(ifl_it, 3); - ref1.splice_after(ref1.before_begin(), ref1, ref_it, ref1.end()); - ifl1.splice_after(ifl1.before_begin(), ifl1, ifl_it, ifl1.end()); - ASSERT_LISTS_EQUAL(ref1, ifl1); - - check.assign({ 8, 7, 2, 3, 4, 5, 4 }); - ASSERT_LISTS_EQUAL(check, ifl1); - check.assign({ 1, 7 }); - ASSERT_LISTS_EQUAL(check, ifl2); - - // Move all but the first element to ref2/ifl2. - ref_it = ref2.begin(); - ifl_it = ifl2.begin(); - std::advance(ref_it, 1); - std::advance(ifl_it, 1); - ref2.splice_after(ref_it, ref1, ref1.begin(), ref1.end()); - ifl2.splice_after(ifl_it, ifl1, ifl1.begin(), ifl1.end()); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - - check.assign({8}); - ASSERT_LISTS_EQUAL(check, ifl1); - - // Move the first element of ref1/ifl1 to the beginning of ref1/ifl1 (do nothing). - ref1.splice_after(ref1.before_begin(), ref1, ref1.before_begin()); - ifl1.splice_after(ifl1.before_begin(), ifl1, ifl1.before_begin()); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(check, ifl1); - - // Move the first element of ref2/ifl2 after itself (do nothing). - ref1.splice_after(ref1.begin(), ref1, ref1.before_begin()); - ifl1.splice_after(ifl1.begin(), ifl1, ifl1.before_begin()); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(check, ifl1); - - check.assign({ 1, 7, 7, 2, 3, 4, 5, 4 }); - ASSERT_LISTS_EQUAL(check, ifl2); - - // Move the first element of ref2/ifl2 to the beginning of ref2/ifl2 (do nothing). - ref2.splice_after(ref2.before_begin(), ref2, ref2.before_begin()); - ifl2.splice_after(ifl2.before_begin(), ifl2, ifl2.before_begin()); - ASSERT_LISTS_EQUAL(ref2, ifl2); - ASSERT_LISTS_EQUAL(check, ifl2); - - // Move the first element of ref2/ifl2 after itself (do nothing). - ref2.splice_after(ref2.begin(), ref2, ref2.before_begin()); - ifl2.splice_after(ifl2.begin(), ifl2, ifl2.before_begin()); - ASSERT_LISTS_EQUAL(ref2, ifl2); - ASSERT_LISTS_EQUAL(check, ifl2); -} - -TEST_F(IntrusiveForwardListTest, SpliceAfter) { - SpliceAfter<IFLTestValueList>(); - SpliceAfter<ConstIFLTestValueList>(); - SpliceAfter<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::Remove() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref({ 3, 1, 2, 7, 4, 5, 4, 8, 7 }); - std::vector<ValueType> storage(ref.begin(), ref.end()); - ListType ifl(storage.begin(), storage.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - ref.remove(1); - ifl.remove(1); - ASSERT_LISTS_EQUAL(ref, ifl); - ref.remove(4); - ifl.remove(4); - ASSERT_LISTS_EQUAL(ref, ifl); - auto odd = [](ValueType value) { return (value.value & 1) != 0; }; - ref.remove_if(odd); - ifl.remove_if(odd); - ASSERT_LISTS_EQUAL(ref, ifl); - auto all = [](ValueType value ATTRIBUTE_UNUSED) { return true; }; - ref.remove_if(all); - ifl.remove_if(all); - ASSERT_LISTS_EQUAL(ref, ifl); -} - -TEST_F(IntrusiveForwardListTest, Remove) { - Remove<IFLTestValueList>(); - Remove<ConstIFLTestValueList>(); - Remove<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::Unique() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref({ 3, 1, 1, 2, 3, 3, 7, 7, 4, 4, 5, 7 }); - std::vector<ValueType> storage(ref.begin(), ref.end()); - ListType ifl(storage.begin(), storage.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - ref.unique(); - ifl.unique(); - ASSERT_LISTS_EQUAL(ref, ifl); - std::forward_list<int> check({ 3, 1, 2, 3, 7, 4, 5, 7 }); - ASSERT_LISTS_EQUAL(check, ifl); - - auto bin_pred = [](const ValueType& lhs, const ValueType& rhs) { - return (lhs.value & ~1) == (rhs.value & ~1); - }; - ref.unique(bin_pred); - ifl.unique(bin_pred); - ASSERT_LISTS_EQUAL(ref, ifl); - check.assign({ 3, 1, 2, 7, 4, 7 }); - ASSERT_LISTS_EQUAL(check, ifl); -} - -TEST_F(IntrusiveForwardListTest, Unique) { - Unique<IFLTestValueList>(); - Unique<ConstIFLTestValueList>(); - Unique<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::Merge() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref1({ 1, 4, 8, 8, 12 }); - std::vector<ValueType> storage1(ref1.begin(), ref1.end()); - ListType ifl1(storage1.begin(), storage1.end()); - std::forward_list<int> ref2({ 3, 5, 6, 7, 9 }); - std::vector<ValueType> storage2(ref2.begin(), ref2.end()); - ListType ifl2(storage2.begin(), storage2.end()); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - CHECK(std::is_sorted(ref1.begin(), ref1.end())); - CHECK(std::is_sorted(ref2.begin(), ref2.end())); - ref1.merge(ref2); - ifl1.merge(ifl2); - ASSERT_LISTS_EQUAL(ref1, ifl1); - ASSERT_LISTS_EQUAL(ref2, ifl2); - CHECK(ref2.empty()); - std::forward_list<int> check({ 1, 3, 4, 5, 6, 7, 8, 8, 9, 12 }); - ASSERT_LISTS_EQUAL(check, ifl1); -} - -TEST_F(IntrusiveForwardListTest, Merge) { - Merge<IFLTestValueList>(); - Merge<ConstIFLTestValueList>(); - Merge<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::Sort1() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref({ 2, 9, 8, 3, 7, 4, 1, 5, 3, 0 }); - std::vector<ValueType> storage(ref.begin(), ref.end()); - ListType ifl(storage.begin(), storage.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK(!std::is_sorted(ref.begin(), ref.end())); - ref.sort(); - ifl.sort(); - ASSERT_LISTS_EQUAL(ref, ifl); - std::forward_list<int> check({ 0, 1, 2, 3, 3, 4, 5, 7, 8, 9 }); - ASSERT_LISTS_EQUAL(check, ifl); -} - -TEST_F(IntrusiveForwardListTest, Sort1) { - Sort1<IFLTestValueList>(); - Sort1<ConstIFLTestValueList>(); - Sort1<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::Sort2() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref({ 2, 9, 8, 3, 7, 4, 1, 5, 3, 0 }); - std::vector<ValueType> storage(ref.begin(), ref.end()); - ListType ifl(storage.begin(), storage.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - auto cmp = [](const ValueType& lhs, const ValueType& rhs) { - return (lhs.value & ~1) < (rhs.value & ~1); - }; - CHECK(!std::is_sorted(ref.begin(), ref.end(), cmp)); - ref.sort(cmp); - ifl.sort(cmp); - ASSERT_LISTS_EQUAL(ref, ifl); - std::forward_list<int> check({ 1, 0, 2, 3, 3, 4, 5, 7, 9, 8 }); - ASSERT_LISTS_EQUAL(check, ifl); -} - -TEST_F(IntrusiveForwardListTest, Sort2) { - Sort2<IFLTestValueList>(); - Sort2<ConstIFLTestValueList>(); - Sort2<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::Reverse() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref({ 8, 3, 5, 4, 1, 3 }); - std::vector<ValueType> storage(ref.begin(), ref.end()); - ListType ifl(storage.begin(), storage.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - CHECK(!std::is_sorted(ref.begin(), ref.end())); - ref.reverse(); - ifl.reverse(); - ASSERT_LISTS_EQUAL(ref, ifl); - std::forward_list<int> check({ 3, 1, 4, 5, 3, 8 }); - ASSERT_LISTS_EQUAL(check, ifl); -} - -TEST_F(IntrusiveForwardListTest, Reverse) { - Reverse<IFLTestValueList>(); - Reverse<ConstIFLTestValueList>(); - Reverse<IFLTestValue2List>(); -} - -template <typename ListType> -void IntrusiveForwardListTest::ModifyValue() { - using ValueType = typename ListType::value_type; - std::forward_list<int> ref({ 3, 7, 42 }); - std::vector<ValueType> storage(ref.begin(), ref.end()); - ListType ifl(storage.begin(), storage.end()); - ASSERT_LISTS_EQUAL(ref, ifl); - - auto add1 = [](const ValueType& value) { return value.value + 1; }; - std::transform(ref.begin(), ref.end(), ref.begin(), add1); - std::transform(ifl.begin(), ifl.end(), ifl.begin(), add1); - ASSERT_LISTS_EQUAL(ref, ifl); -} - -TEST_F(IntrusiveForwardListTest, ModifyValue) { - ModifyValue<IFLTestValueList>(); - // Does not compile with ConstIFLTestValueList because LHS of the assignment is const. - // ModifyValue<ConstIFLTestValueList>(); - static_assert(std::is_const<ConstIFLTestValueList::iterator::value_type>::value, "Const check."); - ModifyValue<IFLTestValue2List>(); -} - -struct Tag1; -struct Tag2; -struct TwoListsValue : public IntrusiveForwardListNode<TwoListsValue, Tag1>, - public IntrusiveForwardListNode<TwoListsValue, Tag2> { - // Deliberately not explicit. - TwoListsValue(int v) : value(v) { } // NOLINT(runtime/explicit) - - int value; -}; -using FirstList = - IntrusiveForwardList<TwoListsValue, IntrusiveForwardListBaseHookTraits<TwoListsValue, Tag1>>; -using SecondList = - IntrusiveForwardList<TwoListsValue, IntrusiveForwardListBaseHookTraits<TwoListsValue, Tag2>>; - -bool operator==(const TwoListsValue& lhs, const TwoListsValue& rhs) { - return lhs.value == rhs.value; -} - -TEST_F(IntrusiveForwardListTest, TwoLists) { - // Test that a value can be in two lists at the same time and the hooks do not interfere. - std::vector<TwoListsValue> storage({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); // storage[i] = i - - std::vector<int> order1({ 3, 1, 7, 2, 8, 9, 4, 0, 6, 5 }); - FirstList list1; - auto pos1 = list1.before_begin(); - for (size_t idx : order1) { - pos1 = list1.insert_after(pos1, storage[idx]); - } - - std::vector<int> order2({ 8, 5, 1, 6, 7, 2, 9, 3, 0, 4 }); - SecondList list2; - auto pos2 = list2.before_begin(); - for (size_t idx : order2) { - pos2 = list2.insert_after(pos2, storage[idx]); - } - - // Using `storage[i] = i`, we can easily compare that nodes of each list are in the right order. - ASSERT_LISTS_EQUAL(order1, list1); - ASSERT_LISTS_EQUAL(order2, list2); -} - -} // namespace art diff --git a/compiler/utils/jni_macro_assembler.cc b/compiler/utils/jni_macro_assembler.cc index 5f405f348c..d6d49f8faa 100644 --- a/compiler/utils/jni_macro_assembler.cc +++ b/compiler/utils/jni_macro_assembler.cc @@ -25,12 +25,6 @@ #ifdef ART_ENABLE_CODEGEN_arm64 #include "arm64/jni_macro_assembler_arm64.h" #endif -#ifdef ART_ENABLE_CODEGEN_mips -#include "mips/assembler_mips.h" -#endif -#ifdef ART_ENABLE_CODEGEN_mips64 -#include "mips64/assembler_mips64.h" -#endif #ifdef ART_ENABLE_CODEGEN_x86 #include "x86/jni_macro_assembler_x86.h" #endif @@ -50,9 +44,8 @@ MacroAsm32UniquePtr JNIMacroAssembler<PointerSize::k32>::Create( ArenaAllocator* allocator, InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features) { -#ifndef ART_ENABLE_CODEGEN_mips + // TODO: Remove the parameter from API (not needed after Mips target was removed). UNUSED(instruction_set_features); -#endif switch (instruction_set) { #ifdef ART_ENABLE_CODEGEN_arm @@ -60,14 +53,6 @@ MacroAsm32UniquePtr JNIMacroAssembler<PointerSize::k32>::Create( case InstructionSet::kThumb2: return MacroAsm32UniquePtr(new (allocator) arm::ArmVIXLJNIMacroAssembler(allocator)); #endif -#ifdef ART_ENABLE_CODEGEN_mips - case InstructionSet::kMips: - return MacroAsm32UniquePtr(new (allocator) mips::MipsAssembler( - allocator, - instruction_set_features != nullptr - ? instruction_set_features->AsMipsInstructionSetFeatures() - : nullptr)); -#endif #ifdef ART_ENABLE_CODEGEN_x86 case InstructionSet::kX86: return MacroAsm32UniquePtr(new (allocator) x86::X86JNIMacroAssembler(allocator)); @@ -85,23 +70,14 @@ MacroAsm64UniquePtr JNIMacroAssembler<PointerSize::k64>::Create( ArenaAllocator* allocator, InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features) { -#ifndef ART_ENABLE_CODEGEN_mips64 + // TODO: Remove the parameter from API (not needed after Mips64 target was removed). UNUSED(instruction_set_features); -#endif switch (instruction_set) { #ifdef ART_ENABLE_CODEGEN_arm64 case InstructionSet::kArm64: return MacroAsm64UniquePtr(new (allocator) arm64::Arm64JNIMacroAssembler(allocator)); #endif -#ifdef ART_ENABLE_CODEGEN_mips64 - case InstructionSet::kMips64: - return MacroAsm64UniquePtr(new (allocator) mips64::Mips64Assembler( - allocator, - instruction_set_features != nullptr - ? instruction_set_features->AsMips64InstructionSetFeatures() - : nullptr)); -#endif #ifdef ART_ENABLE_CODEGEN_x86_64 case InstructionSet::kX86_64: return MacroAsm64UniquePtr(new (allocator) x86_64::X86_64JNIMacroAssembler(allocator)); diff --git a/compiler/utils/jni_macro_assembler.h b/compiler/utils/jni_macro_assembler.h index e6130cfc4c..bbe0f734ba 100644 --- a/compiler/utils/jni_macro_assembler.h +++ b/compiler/utils/jni_macro_assembler.h @@ -197,6 +197,9 @@ class JNIMacroAssembler : public DeletableArenaObject<kArenaAllocAssembler> { virtual void VerifyObject(ManagedRegister src, bool could_be_null) = 0; virtual void VerifyObject(FrameOffset src, bool could_be_null) = 0; + // Jump to address held at [base+offset] (used for tail calls). + virtual void Jump(ManagedRegister base, Offset offset, ManagedRegister scratch) = 0; + // Call to address held at [base+offset] virtual void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) = 0; virtual void Call(FrameOffset base, Offset offset, ManagedRegister scratch) = 0; diff --git a/compiler/utils/label.h b/compiler/utils/label.h index 3c91b2ffd1..9586a1996a 100644 --- a/compiler/utils/label.h +++ b/compiler/utils/label.h @@ -29,14 +29,6 @@ class AssemblerFixup; namespace arm64 { class Arm64Assembler; } // namespace arm64 -namespace mips { -class MipsAssembler; -class MipsLabel; -} // namespace mips -namespace mips64 { -class Mips64Assembler; -class Mips64Label; -} // namespace mips64 namespace x86 { class X86Assembler; class NearLabel; @@ -115,10 +107,6 @@ class Label { } friend class arm64::Arm64Assembler; - friend class mips::MipsAssembler; - friend class mips::MipsLabel; - friend class mips64::Mips64Assembler; - friend class mips64::Mips64Label; friend class x86::X86Assembler; friend class x86::NearLabel; friend class x86_64::X86_64Assembler; diff --git a/compiler/utils/managed_register.h b/compiler/utils/managed_register.h index db9c36cc75..f20750bb22 100644 --- a/compiler/utils/managed_register.h +++ b/compiler/utils/managed_register.h @@ -30,12 +30,6 @@ class ArmManagedRegister; namespace arm64 { class Arm64ManagedRegister; } // namespace arm64 -namespace mips { -class MipsManagedRegister; -} // namespace mips -namespace mips64 { -class Mips64ManagedRegister; -} // namespace mips64 namespace x86 { class X86ManagedRegister; @@ -56,8 +50,6 @@ class ManagedRegister : public ValueObject { constexpr arm::ArmManagedRegister AsArm() const; constexpr arm64::Arm64ManagedRegister AsArm64() const; - constexpr mips::MipsManagedRegister AsMips() const; - constexpr mips64::Mips64ManagedRegister AsMips64() const; constexpr x86::X86ManagedRegister AsX86() const; constexpr x86_64::X86_64ManagedRegister AsX86_64() const; @@ -66,6 +58,10 @@ class ManagedRegister : public ValueObject { return id_ == other.id_; } + constexpr bool IsRegister() const { + return id_ != kNoRegister; + } + constexpr bool IsNoRegister() const { return id_ == kNoRegister; } diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc deleted file mode 100644 index a9d1a25530..0000000000 --- a/compiler/utils/mips/assembler_mips.cc +++ /dev/null @@ -1,5260 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "assembler_mips.h" - -#include "base/bit_utils.h" -#include "base/casts.h" -#include "base/memory_region.h" -#include "entrypoints/quick/quick_entrypoints.h" -#include "entrypoints/quick/quick_entrypoints_enum.h" -#include "thread.h" - -namespace art { -namespace mips { - -static_assert(static_cast<size_t>(kMipsPointerSize) == kMipsWordSize, - "Unexpected Mips pointer size."); -static_assert(kMipsPointerSize == PointerSize::k32, "Unexpected Mips pointer size."); - - -std::ostream& operator<<(std::ostream& os, const DRegister& rhs) { - if (rhs >= D0 && rhs < kNumberOfDRegisters) { - os << "d" << static_cast<int>(rhs); - } else { - os << "DRegister[" << static_cast<int>(rhs) << "]"; - } - return os; -} - -MipsAssembler::DelaySlot::DelaySlot() - : instruction_(0), - patcher_label_(nullptr) {} - -InOutRegMasks& MipsAssembler::DsFsmInstr(uint32_t instruction, MipsLabel* patcher_label) { - if (!reordering_) { - CHECK_EQ(ds_fsm_state_, kExpectingLabel); - CHECK_EQ(delay_slot_.instruction_, 0u); - return delay_slot_.masks_; - } - switch (ds_fsm_state_) { - case kExpectingLabel: - break; - case kExpectingInstruction: - CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size()); - // If the last instruction is not suitable for delay slots, drop - // the PC of the label preceding it so that no unconditional branch - // uses this instruction to fill its delay slot. - if (instruction == 0) { - DsFsmDropLabel(); // Sets ds_fsm_state_ = kExpectingLabel. - } else { - // Otherwise wait for another instruction or label before we can - // commit the label PC. The label PC will be dropped if instead - // of another instruction or label there's a call from the code - // generator to CodePosition() to record the buffer size. - // Instructions after which the buffer size is recorded cannot - // be moved into delay slots or anywhere else because they may - // trigger signals and the signal handlers expect these signals - // to be coming from the instructions immediately preceding the - // recorded buffer locations. - ds_fsm_state_ = kExpectingCommit; - } - break; - case kExpectingCommit: - CHECK_EQ(ds_fsm_target_pc_ + 2 * sizeof(uint32_t), buffer_.Size()); - DsFsmCommitLabel(); // Sets ds_fsm_state_ = kExpectingLabel. - break; - } - delay_slot_.instruction_ = instruction; - delay_slot_.masks_ = InOutRegMasks(); - delay_slot_.patcher_label_ = patcher_label; - return delay_slot_.masks_; -} - -void MipsAssembler::DsFsmLabel() { - if (!reordering_) { - CHECK_EQ(ds_fsm_state_, kExpectingLabel); - CHECK_EQ(delay_slot_.instruction_, 0u); - return; - } - switch (ds_fsm_state_) { - case kExpectingLabel: - ds_fsm_target_pc_ = buffer_.Size(); - ds_fsm_state_ = kExpectingInstruction; - break; - case kExpectingInstruction: - // Allow consecutive labels. - CHECK_EQ(ds_fsm_target_pc_, buffer_.Size()); - break; - case kExpectingCommit: - CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size()); - DsFsmCommitLabel(); - ds_fsm_target_pc_ = buffer_.Size(); - ds_fsm_state_ = kExpectingInstruction; - break; - } - // We cannot move instructions into delay slots across labels. - delay_slot_.instruction_ = 0; -} - -void MipsAssembler::DsFsmCommitLabel() { - if (ds_fsm_state_ == kExpectingCommit) { - ds_fsm_target_pcs_.emplace_back(ds_fsm_target_pc_); - } - ds_fsm_state_ = kExpectingLabel; -} - -void MipsAssembler::DsFsmDropLabel() { - ds_fsm_state_ = kExpectingLabel; -} - -bool MipsAssembler::SetReorder(bool enable) { - bool last_state = reordering_; - if (last_state != enable) { - DsFsmCommitLabel(); - DsFsmInstrNop(0); - } - reordering_ = enable; - return last_state; -} - -size_t MipsAssembler::CodePosition() { - // The last instruction cannot be used in a delay slot, do not commit - // the label before it (if any) and clear the delay slot. - DsFsmDropLabel(); - DsFsmInstrNop(0); - size_t size = buffer_.Size(); - // In theory we can get the following sequence: - // label1: - // instr - // label2: # label1 gets committed when label2 is seen - // CodePosition() call - // and we need to uncommit label1. - if (ds_fsm_target_pcs_.size() != 0 && ds_fsm_target_pcs_.back() + sizeof(uint32_t) == size) { - ds_fsm_target_pcs_.pop_back(); - } - return size; -} - -void MipsAssembler::DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED) { - DsFsmInstr(0); -} - -void MipsAssembler::FinalizeCode() { - for (auto& exception_block : exception_blocks_) { - EmitExceptionPoll(&exception_block); - } - // Commit the last branch target label (if any) and disable instruction reordering. - DsFsmCommitLabel(); - SetReorder(false); - EmitLiterals(); - ReserveJumpTableSpace(); - PromoteBranches(); -} - -void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) { - size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs(); - EmitBranches(); - EmitJumpTables(); - Assembler::FinalizeInstructions(region); - PatchCFI(number_of_delayed_adjust_pcs); -} - -void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) { - if (cfi().NumberOfDelayedAdvancePCs() == 0u) { - DCHECK_EQ(number_of_delayed_adjust_pcs, 0u); - return; - } - - using DelayedAdvancePC = DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC; - const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC(); - const std::vector<uint8_t>& old_stream = data.first; - const std::vector<DelayedAdvancePC>& advances = data.second; - - // PCs recorded before EmitBranches() need to be adjusted. - // PCs recorded during EmitBranches() are already adjusted. - // Both ranges are separately sorted but they may overlap. - if (kIsDebugBuild) { - auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) { - return lhs.pc < rhs.pc; - }; - CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp)); - CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp)); - } - - // Append initial CFI data if any. - size_t size = advances.size(); - DCHECK_NE(size, 0u); - cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos); - // Emit PC adjustments interleaved with the old CFI stream. - size_t adjust_pos = 0u; - size_t late_emit_pos = number_of_delayed_adjust_pcs; - while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) { - size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs) - ? GetAdjustedPosition(advances[adjust_pos].pc) - : static_cast<size_t>(-1); - size_t late_emit_pc = (late_emit_pos != size) - ? advances[late_emit_pos].pc - : static_cast<size_t>(-1); - size_t advance_pc = std::min(adjusted_pc, late_emit_pc); - DCHECK_NE(advance_pc, static_cast<size_t>(-1)); - size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos; - if (adjusted_pc <= late_emit_pc) { - ++adjust_pos; - } else { - ++late_emit_pos; - } - cfi().AdvancePC(advance_pc); - size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos; - cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos); - } -} - -void MipsAssembler::EmitBranches() { - CHECK(!overwriting_); - CHECK(!reordering_); - // Now that everything has its final position in the buffer (the branches have - // been promoted), adjust the target label PCs. - for (size_t cnt = ds_fsm_target_pcs_.size(), i = 0; i < cnt; i++) { - ds_fsm_target_pcs_[i] = GetAdjustedPosition(ds_fsm_target_pcs_[i]); - } - // Switch from appending instructions at the end of the buffer to overwriting - // existing instructions (branch placeholders) in the buffer. - overwriting_ = true; - for (size_t id = 0; id < branches_.size(); id++) { - EmitBranch(id); - } - overwriting_ = false; -} - -void MipsAssembler::Emit(uint32_t value) { - if (overwriting_) { - // Branches to labels are emitted into their placeholders here. - buffer_.Store<uint32_t>(overwrite_location_, value); - overwrite_location_ += sizeof(uint32_t); - } else { - // Other instructions are simply appended at the end here. - AssemblerBuffer::EnsureCapacity ensured(&buffer_); - buffer_.Emit<uint32_t>(value); - } -} - -uint32_t MipsAssembler::EmitR(int opcode, - Register rs, - Register rt, - Register rd, - int shamt, - int funct) { - CHECK_NE(rs, kNoRegister); - CHECK_NE(rt, kNoRegister); - CHECK_NE(rd, kNoRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - static_cast<uint32_t>(rs) << kRsShift | - static_cast<uint32_t>(rt) << kRtShift | - static_cast<uint32_t>(rd) << kRdShift | - shamt << kShamtShift | - funct; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) { - CHECK_NE(rs, kNoRegister); - CHECK_NE(rt, kNoRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - static_cast<uint32_t>(rs) << kRsShift | - static_cast<uint32_t>(rt) << kRtShift | - imm; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) { - CHECK_NE(rs, kNoRegister); - CHECK(IsUint<21>(imm21)) << imm21; - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - static_cast<uint32_t>(rs) << kRsShift | - imm21; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitI26(int opcode, uint32_t imm26) { - CHECK(IsUint<26>(imm26)) << imm26; - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitFR(int opcode, - int fmt, - FRegister ft, - FRegister fs, - FRegister fd, - int funct) { - CHECK_NE(ft, kNoFRegister); - CHECK_NE(fs, kNoFRegister); - CHECK_NE(fd, kNoFRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - fmt << kFmtShift | - static_cast<uint32_t>(ft) << kFtShift | - static_cast<uint32_t>(fs) << kFsShift | - static_cast<uint32_t>(fd) << kFdShift | - funct; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) { - CHECK_NE(ft, kNoFRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - fmt << kFmtShift | - static_cast<uint32_t>(ft) << kFtShift | - imm; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitMsa3R(int operation, - int df, - VectorRegister wt, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(wt, kNoVectorRegister); - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsaOperationShift | - df << kDfShift | - static_cast<uint32_t>(wt) << kWtShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitMsaBIT(int operation, - int df_m, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsaOperationShift | - df_m << kDfMShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitMsaELM(int operation, - int df_n, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsaELMOperationShift | - df_n << kDfNShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitMsaMI10(int s10, - Register rs, - VectorRegister wd, - int minor_opcode, - int df) { - CHECK_NE(rs, kNoRegister); - CHECK_NE(wd, kNoVectorRegister); - CHECK(IsUint<10>(s10)) << s10; - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - s10 << kS10Shift | - static_cast<uint32_t>(rs) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode << kS10MinorShift | - df; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitMsaI10(int operation, - int df, - int i10, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(wd, kNoVectorRegister); - CHECK(IsUint<10>(i10)) << i10; - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsaOperationShift | - df << kDfShift | - i10 << kI10Shift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitMsa2R(int operation, - int df, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsa2ROperationShift | - df << kDf2RShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); - return encoding; -} - -uint32_t MipsAssembler::EmitMsa2RF(int operation, - int df, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsa2RFOperationShift | - df << kDf2RShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); - return encoding; -} - -void MipsAssembler::Addu(Register rd, Register rs, Register rt) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x21)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) { - if (patcher_label != nullptr) { - Bind(patcher_label); - } - DsFsmInstr(EmitI(0x9, rs, rt, imm16), patcher_label).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) { - Addiu(rt, rs, imm16, /* patcher_label= */ nullptr); -} - -void MipsAssembler::Subu(Register rd, Register rs, Register rt) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x23)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::MultR2(Register rs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18)).GprIns(rs, rt); -} - -void MipsAssembler::MultuR2(Register rs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19)).GprIns(rs, rt); -} - -void MipsAssembler::DivR2(Register rs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a)).GprIns(rs, rt); -} - -void MipsAssembler::DivuR2(Register rs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b)).GprIns(rs, rt); -} - -void MipsAssembler::MulR2(Register rd, Register rs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0x1c, rs, rt, rd, 0, 2)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::DivR2(Register rd, Register rs, Register rt) { - CHECK(!IsR6()); - DivR2(rs, rt); - Mflo(rd); -} - -void MipsAssembler::ModR2(Register rd, Register rs, Register rt) { - CHECK(!IsR6()); - DivR2(rs, rt); - Mfhi(rd); -} - -void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) { - CHECK(!IsR6()); - DivuR2(rs, rt); - Mflo(rd); -} - -void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) { - CHECK(!IsR6()); - DivuR2(rs, rt); - Mfhi(rd); -} - -void MipsAssembler::MulR6(Register rd, Register rs, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x18)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x18)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x19)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::DivR6(Register rd, Register rs, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x1a)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::ModR6(Register rd, Register rs, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x1a)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x1b)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x1b)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::And(Register rd, Register rs, Register rt) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x24)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0xc, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Or(Register rd, Register rs, Register rt) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x25)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0xd, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Xor(Register rd, Register rs, Register rt) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x26)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0xe, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Nor(Register rd, Register rs, Register rt) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x27)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Movz(Register rd, Register rs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x0A)).GprInOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Movn(Register rd, Register rs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x0B)).GprInOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x35)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Selnez(Register rd, Register rs, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x37)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::ClzR6(Register rd, Register rs) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10)).GprOuts(rd).GprIns(rs); -} - -void MipsAssembler::ClzR2(Register rd, Register rs) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0x1C, rs, rd, rd, 0, 0x20)).GprOuts(rd).GprIns(rs); -} - -void MipsAssembler::CloR6(Register rd, Register rs) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11)).GprOuts(rd).GprIns(rs); -} - -void MipsAssembler::CloR2(Register rd, Register rs) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0x1C, rs, rd, rd, 0, 0x21)).GprOuts(rd).GprIns(rs); -} - -void MipsAssembler::Seb(Register rd, Register rt) { - DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20)).GprOuts(rd).GprIns(rt); -} - -void MipsAssembler::Seh(Register rd, Register rt) { - DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20)).GprOuts(rd).GprIns(rt); -} - -void MipsAssembler::Wsbh(Register rd, Register rt) { - DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20)).GprOuts(rd).GprIns(rt); -} - -void MipsAssembler::Bitswap(Register rd, Register rt) { - CHECK(IsR6()); - DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20)).GprOuts(rd).GprIns(rt); -} - -void MipsAssembler::Sll(Register rd, Register rt, int shamt) { - CHECK(IsUint<5>(shamt)) << shamt; - DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00)).GprOuts(rd).GprIns(rt); -} - -void MipsAssembler::Srl(Register rd, Register rt, int shamt) { - CHECK(IsUint<5>(shamt)) << shamt; - DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02)).GprOuts(rd).GprIns(rt); -} - -void MipsAssembler::Rotr(Register rd, Register rt, int shamt) { - CHECK(IsUint<5>(shamt)) << shamt; - DsFsmInstr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02)).GprOuts(rd).GprIns(rt); -} - -void MipsAssembler::Sra(Register rd, Register rt, int shamt) { - CHECK(IsUint<5>(shamt)) << shamt; - DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03)).GprOuts(rd).GprIns(rt); -} - -void MipsAssembler::Sllv(Register rd, Register rt, Register rs) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x04)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Srlv(Register rd, Register rt, Register rs) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x06)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) { - DsFsmInstr(EmitR(0, rs, rt, rd, 1, 0x06)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Srav(Register rd, Register rt, Register rs) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x07)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) { - CHECK(IsUint<5>(pos)) << pos; - CHECK(0 < size && size <= 32) << size; - CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size; - DsFsmInstr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00)) - .GprOuts(rd).GprIns(rt); -} - -void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) { - CHECK(IsUint<5>(pos)) << pos; - CHECK(0 < size && size <= 32) << size; - CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size; - DsFsmInstr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04)) - .GprInOuts(rd).GprIns(rt); -} - -void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) { - CHECK(IsR6() || HasMsa()); - CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne; - int sa = saPlusOne - 1; - DsFsmInstr(EmitR(0x0, rs, rt, rd, sa, 0x05)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::ShiftAndAdd(Register dst, - Register src_idx, - Register src_base, - int shamt, - Register tmp) { - CHECK(0 <= shamt && shamt <= 4) << shamt; - CHECK_NE(src_base, tmp); - if (shamt == TIMES_1) { - // Catch the special case where the shift amount is zero (0). - Addu(dst, src_base, src_idx); - } else if (IsR6() || HasMsa()) { - Lsa(dst, src_idx, src_base, shamt); - } else { - Sll(tmp, src_idx, shamt); - Addu(dst, src_base, tmp); - } -} - -void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0x20, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0x21, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) { - if (patcher_label != nullptr) { - Bind(patcher_label); - } - DsFsmInstr(EmitI(0x23, rs, rt, imm16), patcher_label).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) { - Lw(rt, rs, imm16, /* patcher_label= */ nullptr); -} - -void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) { - CHECK(!IsR6()); - DsFsmInstr(EmitI(0x22, rs, rt, imm16)).GprInOuts(rt).GprIns(rs); -} - -void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) { - CHECK(!IsR6()); - DsFsmInstr(EmitI(0x26, rs, rt, imm16)).GprInOuts(rt).GprIns(rs); -} - -void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0x24, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0x25, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Lwpc(Register rs, uint32_t imm19) { - CHECK(IsR6()); - CHECK(IsUint<19>(imm19)) << imm19; - DsFsmInstrNop(EmitI21(0x3B, rs, (0x01 << 19) | imm19)); -} - -void MipsAssembler::Lui(Register rt, uint16_t imm16) { - DsFsmInstr(EmitI(0xf, static_cast<Register>(0), rt, imm16)).GprOuts(rt); -} - -void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) { - CHECK(IsR6()); - DsFsmInstr(EmitI(0xf, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::AddUpper(Register rt, Register rs, uint16_t imm16, Register tmp) { - bool increment = (rs == rt); - if (increment) { - CHECK_NE(rs, tmp); - } - if (IsR6()) { - Aui(rt, rs, imm16); - } else if (increment) { - Lui(tmp, imm16); - Addu(rt, rs, tmp); - } else { - Lui(rt, imm16); - Addu(rt, rs, rt); - } -} - -void MipsAssembler::Sync(uint32_t stype) { - DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, stype & 0x1f, 0xf)); -} - -void MipsAssembler::Mfhi(Register rd) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0, ZERO, ZERO, rd, 0, 0x10)).GprOuts(rd); -} - -void MipsAssembler::Mflo(Register rd) { - CHECK(!IsR6()); - DsFsmInstr(EmitR(0, ZERO, ZERO, rd, 0, 0x12)).GprOuts(rd); -} - -void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0x28, rs, rt, imm16)).GprIns(rt, rs); -} - -void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0x29, rs, rt, imm16)).GprIns(rt, rs); -} - -void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) { - if (patcher_label != nullptr) { - Bind(patcher_label); - } - DsFsmInstr(EmitI(0x2b, rs, rt, imm16), patcher_label).GprIns(rt, rs); -} - -void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) { - Sw(rt, rs, imm16, /* patcher_label= */ nullptr); -} - -void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) { - CHECK(!IsR6()); - DsFsmInstr(EmitI(0x2a, rs, rt, imm16)).GprIns(rt, rs); -} - -void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) { - CHECK(!IsR6()); - DsFsmInstr(EmitI(0x2e, rs, rt, imm16)).GprIns(rt, rs); -} - -void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) { - CHECK(!IsR6()); - DsFsmInstr(EmitI(0x30, base, rt, imm16)).GprOuts(rt).GprIns(base); -} - -void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) { - CHECK(!IsR6()); - DsFsmInstr(EmitI(0x38, base, rt, imm16)).GprInOuts(rt).GprIns(base); -} - -void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) { - CHECK(IsR6()); - CHECK(IsInt<9>(imm9)); - DsFsmInstr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36)).GprOuts(rt).GprIns(base); -} - -void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) { - CHECK(IsR6()); - CHECK(IsInt<9>(imm9)); - DsFsmInstr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26)).GprInOuts(rt).GprIns(base); -} - -void MipsAssembler::Slt(Register rd, Register rs, Register rt) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x2a)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Sltu(Register rd, Register rs, Register rt) { - DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x2b)).GprOuts(rd).GprIns(rs, rt); -} - -void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0xa, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0xb, rs, rt, imm16)).GprOuts(rt).GprIns(rs); -} - -void MipsAssembler::B(uint16_t imm16) { - DsFsmInstrNop(EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16)); -} - -void MipsAssembler::Bal(uint16_t imm16) { - DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x11), imm16)); -} - -void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) { - DsFsmInstrNop(EmitI(0x4, rs, rt, imm16)); -} - -void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) { - DsFsmInstrNop(EmitI(0x5, rs, rt, imm16)); -} - -void MipsAssembler::Beqz(Register rt, uint16_t imm16) { - Beq(rt, ZERO, imm16); -} - -void MipsAssembler::Bnez(Register rt, uint16_t imm16) { - Bne(rt, ZERO, imm16); -} - -void MipsAssembler::Bltz(Register rt, uint16_t imm16) { - DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0), imm16)); -} - -void MipsAssembler::Bgez(Register rt, uint16_t imm16) { - DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0x1), imm16)); -} - -void MipsAssembler::Blez(Register rt, uint16_t imm16) { - DsFsmInstrNop(EmitI(0x6, rt, static_cast<Register>(0), imm16)); -} - -void MipsAssembler::Bgtz(Register rt, uint16_t imm16) { - DsFsmInstrNop(EmitI(0x7, rt, static_cast<Register>(0), imm16)); -} - -void MipsAssembler::Bc1f(uint16_t imm16) { - Bc1f(0, imm16); -} - -void MipsAssembler::Bc1f(int cc, uint16_t imm16) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstrNop(EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16)); -} - -void MipsAssembler::Bc1t(uint16_t imm16) { - Bc1t(0, imm16); -} - -void MipsAssembler::Bc1t(int cc, uint16_t imm16) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstrNop(EmitI(0x11, - static_cast<Register>(0x8), - static_cast<Register>((cc << 2) | 1), - imm16)); -} - -void MipsAssembler::J(uint32_t addr26) { - DsFsmInstrNop(EmitI26(0x2, addr26)); -} - -void MipsAssembler::Jal(uint32_t addr26) { - DsFsmInstrNop(EmitI26(0x3, addr26)); -} - -void MipsAssembler::Jalr(Register rd, Register rs) { - uint32_t last_instruction = delay_slot_.instruction_; - MipsLabel* patcher_label = delay_slot_.patcher_label_; - bool exchange = (last_instruction != 0 && - (delay_slot_.masks_.gpr_outs_ & (1u << rs)) == 0 && - ((delay_slot_.masks_.gpr_ins_ | delay_slot_.masks_.gpr_outs_) & (1u << rd)) == 0); - if (exchange) { - // The last instruction cannot be used in a different delay slot, - // do not commit the label before it (if any). - DsFsmDropLabel(); - } - DsFsmInstrNop(EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09)); - if (exchange) { - // Exchange the last two instructions in the assembler buffer. - size_t size = buffer_.Size(); - CHECK_GE(size, 2 * sizeof(uint32_t)); - size_t pos1 = size - 2 * sizeof(uint32_t); - size_t pos2 = size - sizeof(uint32_t); - uint32_t instr1 = buffer_.Load<uint32_t>(pos1); - uint32_t instr2 = buffer_.Load<uint32_t>(pos2); - CHECK_EQ(instr1, last_instruction); - buffer_.Store<uint32_t>(pos1, instr2); - buffer_.Store<uint32_t>(pos2, instr1); - // Move the patcher label along with the patched instruction. - if (patcher_label != nullptr) { - patcher_label->AdjustBoundPosition(sizeof(uint32_t)); - } - } else if (reordering_) { - Nop(); - } -} - -void MipsAssembler::Jalr(Register rs) { - Jalr(RA, rs); -} - -void MipsAssembler::Jr(Register rs) { - Jalr(ZERO, rs); -} - -void MipsAssembler::Nal() { - DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0)); -} - -void MipsAssembler::Auipc(Register rs, uint16_t imm16) { - CHECK(IsR6()); - DsFsmInstrNop(EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16)); -} - -void MipsAssembler::Addiupc(Register rs, uint32_t imm19) { - CHECK(IsR6()); - CHECK(IsUint<19>(imm19)) << imm19; - DsFsmInstrNop(EmitI21(0x3B, rs, imm19)); -} - -void MipsAssembler::Bc(uint32_t imm26) { - CHECK(IsR6()); - DsFsmInstrNop(EmitI26(0x32, imm26)); -} - -void MipsAssembler::Balc(uint32_t imm26) { - CHECK(IsR6()); - DsFsmInstrNop(EmitI26(0x3A, imm26)); -} - -void MipsAssembler::Jic(Register rt, uint16_t imm16) { - CHECK(IsR6()); - DsFsmInstrNop(EmitI(0x36, static_cast<Register>(0), rt, imm16)); -} - -void MipsAssembler::Jialc(Register rt, uint16_t imm16) { - CHECK(IsR6()); - DsFsmInstrNop(EmitI(0x3E, static_cast<Register>(0), rt, imm16)); -} - -void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - DsFsmInstrNop(EmitI(0x17, rs, rt, imm16)); -} - -void MipsAssembler::Bltzc(Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rt, ZERO); - DsFsmInstrNop(EmitI(0x17, rt, rt, imm16)); -} - -void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rt, ZERO); - DsFsmInstrNop(EmitI(0x17, static_cast<Register>(0), rt, imm16)); -} - -void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - DsFsmInstrNop(EmitI(0x16, rs, rt, imm16)); -} - -void MipsAssembler::Bgezc(Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rt, ZERO); - DsFsmInstrNop(EmitI(0x16, rt, rt, imm16)); -} - -void MipsAssembler::Blezc(Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rt, ZERO); - DsFsmInstrNop(EmitI(0x16, static_cast<Register>(0), rt, imm16)); -} - -void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - DsFsmInstrNop(EmitI(0x7, rs, rt, imm16)); -} - -void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - DsFsmInstrNop(EmitI(0x6, rs, rt, imm16)); -} - -void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - DsFsmInstrNop(EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16)); -} - -void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) { - CHECK(IsR6()); - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - DsFsmInstrNop(EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16)); -} - -void MipsAssembler::Beqzc(Register rs, uint32_t imm21) { - CHECK(IsR6()); - CHECK_NE(rs, ZERO); - DsFsmInstrNop(EmitI21(0x36, rs, imm21)); -} - -void MipsAssembler::Bnezc(Register rs, uint32_t imm21) { - CHECK(IsR6()); - CHECK_NE(rs, ZERO); - DsFsmInstrNop(EmitI21(0x3E, rs, imm21)); -} - -void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) { - CHECK(IsR6()); - DsFsmInstrNop(EmitFI(0x11, 0x9, ft, imm16)); -} - -void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) { - CHECK(IsR6()); - DsFsmInstrNop(EmitFI(0x11, 0xD, ft, imm16)); -} - -void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) { - switch (cond) { - case kCondLTZ: - CHECK_EQ(rt, ZERO); - Bltz(rs, imm16); - break; - case kCondGEZ: - CHECK_EQ(rt, ZERO); - Bgez(rs, imm16); - break; - case kCondLEZ: - CHECK_EQ(rt, ZERO); - Blez(rs, imm16); - break; - case kCondGTZ: - CHECK_EQ(rt, ZERO); - Bgtz(rs, imm16); - break; - case kCondEQ: - Beq(rs, rt, imm16); - break; - case kCondNE: - Bne(rs, rt, imm16); - break; - case kCondEQZ: - CHECK_EQ(rt, ZERO); - Beqz(rs, imm16); - break; - case kCondNEZ: - CHECK_EQ(rt, ZERO); - Bnez(rs, imm16); - break; - case kCondF: - CHECK_EQ(rt, ZERO); - Bc1f(static_cast<int>(rs), imm16); - break; - case kCondT: - CHECK_EQ(rt, ZERO); - Bc1t(static_cast<int>(rs), imm16); - break; - case kCondLT: - case kCondGE: - case kCondLE: - case kCondGT: - case kCondLTU: - case kCondGEU: - case kUncond: - // We don't support synthetic R2 branches (preceded with slt[u]) at this level - // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). - LOG(FATAL) << "Unexpected branch condition " << cond; - UNREACHABLE(); - } -} - -void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) { - switch (cond) { - case kCondLT: - Bltc(rs, rt, imm16_21); - break; - case kCondGE: - Bgec(rs, rt, imm16_21); - break; - case kCondLE: - Bgec(rt, rs, imm16_21); - break; - case kCondGT: - Bltc(rt, rs, imm16_21); - break; - case kCondLTZ: - CHECK_EQ(rt, ZERO); - Bltzc(rs, imm16_21); - break; - case kCondGEZ: - CHECK_EQ(rt, ZERO); - Bgezc(rs, imm16_21); - break; - case kCondLEZ: - CHECK_EQ(rt, ZERO); - Blezc(rs, imm16_21); - break; - case kCondGTZ: - CHECK_EQ(rt, ZERO); - Bgtzc(rs, imm16_21); - break; - case kCondEQ: - Beqc(rs, rt, imm16_21); - break; - case kCondNE: - Bnec(rs, rt, imm16_21); - break; - case kCondEQZ: - CHECK_EQ(rt, ZERO); - Beqzc(rs, imm16_21); - break; - case kCondNEZ: - CHECK_EQ(rt, ZERO); - Bnezc(rs, imm16_21); - break; - case kCondLTU: - Bltuc(rs, rt, imm16_21); - break; - case kCondGEU: - Bgeuc(rs, rt, imm16_21); - break; - case kCondF: - CHECK_EQ(rt, ZERO); - Bc1eqz(static_cast<FRegister>(rs), imm16_21); - break; - case kCondT: - CHECK_EQ(rt, ZERO); - Bc1nez(static_cast<FRegister>(rs), imm16_21); - break; - case kUncond: - LOG(FATAL) << "Unexpected branch condition " << cond; - UNREACHABLE(); - } -} - -void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) { - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x0)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) { - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) { - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x2)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) { - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x3)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) { - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x0)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) { - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) { - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x2)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) { - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x3)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::SqrtS(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::SqrtD(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::AbsS(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::AbsD(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::MovS(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::MovD(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::NegS(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::NegD(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::CunS(FRegister fs, FRegister ft) { - CunS(0, fs, ft); -} - -void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CeqS(FRegister fs, FRegister ft) { - CeqS(0, fs, ft); -} - -void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CueqS(FRegister fs, FRegister ft) { - CueqS(0, fs, ft); -} - -void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::ColtS(FRegister fs, FRegister ft) { - ColtS(0, fs, ft); -} - -void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CultS(FRegister fs, FRegister ft) { - CultS(0, fs, ft); -} - -void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::ColeS(FRegister fs, FRegister ft) { - ColeS(0, fs, ft); -} - -void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CuleS(FRegister fs, FRegister ft) { - CuleS(0, fs, ft); -} - -void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CunD(FRegister fs, FRegister ft) { - CunD(0, fs, ft); -} - -void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CeqD(FRegister fs, FRegister ft) { - CeqD(0, fs, ft); -} - -void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CueqD(FRegister fs, FRegister ft) { - CueqD(0, fs, ft); -} - -void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::ColtD(FRegister fs, FRegister ft) { - ColtD(0, fs, ft); -} - -void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CultD(FRegister fs, FRegister ft) { - CultD(0, fs, ft); -} - -void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::ColeD(FRegister fs, FRegister ft) { - ColeD(0, fs, ft); -} - -void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CuleD(FRegister fs, FRegister ft) { - CuleD(0, fs, ft); -} - -void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37)) - .CcOuts(cc).FprIns(fs, ft); -} - -void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x01)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x02)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x03)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x04)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x05)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x06)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x07)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x11)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x12)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x13)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x01)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x02)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x03)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x04)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x05)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x06)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x07)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x11)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x12)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x13)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::Movf(Register rd, Register rs, int cc) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01)) - .GprInOuts(rd).GprIns(rs).CcIns(cc); -} - -void MipsAssembler::Movt(Register rd, Register rs, int cc) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01)) - .GprInOuts(rd).GprIns(rs).CcIns(cc); -} - -void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11)) - .FprInOuts(fd).FprIns(fs).CcIns(cc); -} - -void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11)) - .FprInOuts(fd).FprIns(fs).CcIns(cc); -} - -void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11)) - .FprInOuts(fd).FprIns(fs).CcIns(cc); -} - -void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) { - CHECK(!IsR6()); - CHECK(IsUint<3>(cc)) << cc; - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11)) - .FprInOuts(fd).FprIns(fs).CcIns(cc); -} - -void MipsAssembler::MovzS(FRegister fd, FRegister fs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12)) - .FprInOuts(fd).FprIns(fs).GprIns(rt); -} - -void MipsAssembler::MovzD(FRegister fd, FRegister fs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12)) - .FprInOuts(fd).FprIns(fs).GprIns(rt); -} - -void MipsAssembler::MovnS(FRegister fd, FRegister fs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13)) - .FprInOuts(fd).FprIns(fs).GprIns(rt); -} - -void MipsAssembler::MovnD(FRegister fd, FRegister fs, Register rt) { - CHECK(!IsR6()); - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13)) - .FprInOuts(fd).FprIns(fs).GprIns(rt); -} - -void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x10)).FprInOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x10)).FprInOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::SeleqzS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x14)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::SeleqzD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x14)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::SelnezS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x17)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::SelnezD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x17)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::ClassS(FRegister fd, FRegister fs) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::ClassD(FRegister fd, FRegister fs) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) { - CHECK(IsR6()); - DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e)).FprOuts(fd).FprIns(fs, ft); -} - -void MipsAssembler::TruncLS(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::TruncLD(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::TruncWS(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::TruncWD(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::Cvtds(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::FloorWS(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf)).FprOuts(fd).FprIns(fs); -} - -void MipsAssembler::FloorWD(FRegister fd, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf)).FprOuts(fd).FprIns(fs); -} - -FRegister MipsAssembler::GetFpuRegLow(FRegister reg) { - // If FPRs are 32-bit (and get paired to hold 64-bit values), accesses to - // odd-numbered FPRs are reattributed to even-numbered FPRs. This lets us - // use only even-numbered FPRs irrespective of whether we're doing single- - // or double-precision arithmetic. (We don't use odd-numbered 32-bit FPRs - // to hold single-precision values). - return Is32BitFPU() ? static_cast<FRegister>(reg & ~1u) : reg; -} - -void MipsAssembler::Mfc1(Register rt, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0)) - .GprOuts(rt).FprIns(GetFpuRegLow(fs)); -} - -// Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs -// when loading the value as 32-bit halves. -void MipsAssembler::Mtc1(Register rt, FRegister fs) { - uint32_t encoding = - EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); - if (Is32BitFPU() && (fs % 2 != 0)) { - // If mtc1 is used to simulate mthc1 by writing to the odd-numbered FPR in - // a pair of 32-bit FPRs, the associated even-numbered FPR is an in/out. - DsFsmInstr(encoding).FprInOuts(GetFpuRegLow(fs)).GprIns(rt); - } else { - // Otherwise (the FPR is 64-bit or even-numbered), the FPR is an out. - DsFsmInstr(encoding).FprOuts(fs).GprIns(rt); - } -} - -void MipsAssembler::Mfhc1(Register rt, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0)) - .GprOuts(rt).FprIns(fs); -} - -// Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs -// when loading the value as 32-bit halves. -void MipsAssembler::Mthc1(Register rt, FRegister fs) { - DsFsmInstr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0)) - .FprInOuts(fs).GprIns(rt); -} - -void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) { - if (Is32BitFPU()) { - CHECK_EQ(fs % 2, 0) << fs; - Mfc1(rt, static_cast<FRegister>(fs + 1)); - } else { - Mfhc1(rt, fs); - } -} - -void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) { - if (Is32BitFPU()) { - CHECK_EQ(fs % 2, 0) << fs; - Mtc1(rt, static_cast<FRegister>(fs + 1)); - } else { - Mthc1(rt, fs); - } -} - -// Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs -// when loading the value as 32-bit halves. -void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) { - uint32_t encoding = EmitI(0x31, rs, static_cast<Register>(ft), imm16); - if (Is32BitFPU() && (ft % 2 != 0)) { - // If lwc1 is used to load the odd-numbered FPR in a pair of 32-bit FPRs, - // the associated even-numbered FPR is an in/out. - DsFsmInstr(encoding).FprInOuts(GetFpuRegLow(ft)).GprIns(rs); - } else { - // Otherwise (the FPR is 64-bit or even-numbered), the FPR is an out. - DsFsmInstr(encoding).FprOuts(ft).GprIns(rs); - } -} - -void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0x35, rs, static_cast<Register>(ft), imm16)).FprOuts(ft).GprIns(rs); -} - -void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0x39, rs, static_cast<Register>(ft), imm16)).FprIns(GetFpuRegLow(ft)).GprIns(rs); -} - -void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) { - DsFsmInstr(EmitI(0x3d, rs, static_cast<Register>(ft), imm16)).FprIns(ft).GprIns(rs); -} - -void MipsAssembler::Break() { - DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, 0, 0xD)); -} - -void MipsAssembler::Nop() { - DsFsmInstrNop(EmitR(0x0, ZERO, ZERO, ZERO, 0, 0x0)); -} - -void MipsAssembler::NopIfNoReordering() { - if (!reordering_) { - Nop(); - } -} - -void MipsAssembler::Move(Register rd, Register rs) { - Or(rd, rs, ZERO); -} - -void MipsAssembler::Clear(Register rd) { - Move(rd, ZERO); -} - -void MipsAssembler::Not(Register rd, Register rs) { - Nor(rd, rs, ZERO); -} - -void MipsAssembler::Push(Register rs) { - IncreaseFrameSize(kStackAlignment); - Sw(rs, SP, 0); -} - -void MipsAssembler::Pop(Register rd) { - Lw(rd, SP, 0); - DecreaseFrameSize(kStackAlignment); -} - -void MipsAssembler::PopAndReturn(Register rd, Register rt) { - bool reordering = SetReorder(false); - Lw(rd, SP, 0); - Jr(rt); - DecreaseFrameSize(kStackAlignment); // Single instruction in delay slot. - SetReorder(reordering); -} - -void MipsAssembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Ffint_sW(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::Ffint_sD(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::Ftint_sW(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::Ftint_sD(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(shamt3)) << shamt3; - DsFsmInstr(EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(shamt4)) << shamt4; - DsFsmInstr(EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) { - CHECK(HasMsa()); - CHECK(IsUint<5>(shamt5)) << shamt5; - DsFsmInstr(EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) { - CHECK(HasMsa()); - CHECK(IsUint<6>(shamt6)) << shamt6; - DsFsmInstr(EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(shamt3)) << shamt3; - DsFsmInstr(EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(shamt4)) << shamt4; - DsFsmInstr(EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) { - CHECK(HasMsa()); - CHECK(IsUint<5>(shamt5)) << shamt5; - DsFsmInstr(EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) { - CHECK(HasMsa()); - CHECK(IsUint<6>(shamt6)) << shamt6; - DsFsmInstr(EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(shamt3)) << shamt3; - DsFsmInstr(EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(shamt4)) << shamt4; - DsFsmInstr(EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) { - CHECK(HasMsa()); - CHECK(IsUint<5>(shamt5)) << shamt5; - DsFsmInstr(EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) { - CHECK(HasMsa()); - CHECK(IsUint<6>(shamt6)) << shamt6; - DsFsmInstr(EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::MoveV(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(n4)) << n4; - DsFsmInstr(EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(n3)) << n3; - DsFsmInstr(EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) { - CHECK(HasMsa()); - CHECK(IsUint<2>(n2)) << n2; - DsFsmInstr(EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) { - CHECK(HasMsa()); - CHECK(IsUint<1>(n1)) << n1; - DsFsmInstr(EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::Copy_sB(Register rd, VectorRegister ws, int n4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(n4)) << n4; - DsFsmInstr(EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19)) - .GprOuts(rd).FprIns(ws); -} - -void MipsAssembler::Copy_sH(Register rd, VectorRegister ws, int n3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(n3)) << n3; - DsFsmInstr(EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19)) - .GprOuts(rd).FprIns(ws); -} - -void MipsAssembler::Copy_sW(Register rd, VectorRegister ws, int n2) { - CHECK(HasMsa()); - CHECK(IsUint<2>(n2)) << n2; - DsFsmInstr(EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19)) - .GprOuts(rd).FprIns(ws); -} - -void MipsAssembler::Copy_uB(Register rd, VectorRegister ws, int n4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(n4)) << n4; - DsFsmInstr(EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19)) - .GprOuts(rd).FprIns(ws); -} - -void MipsAssembler::Copy_uH(Register rd, VectorRegister ws, int n3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(n3)) << n3; - DsFsmInstr(EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19)) - .GprOuts(rd).FprIns(ws); -} - -void MipsAssembler::InsertB(VectorRegister wd, Register rs, int n4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(n4)) << n4; - DsFsmInstr(EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19)) - .FprInOuts(wd).GprIns(rs); -} - -void MipsAssembler::InsertH(VectorRegister wd, Register rs, int n3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(n3)) << n3; - DsFsmInstr(EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19)) - .FprInOuts(wd).GprIns(rs); -} - -void MipsAssembler::InsertW(VectorRegister wd, Register rs, int n2) { - CHECK(HasMsa()); - CHECK(IsUint<2>(n2)) << n2; - DsFsmInstr(EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19)) - .FprInOuts(wd).GprIns(rs); -} - -void MipsAssembler::FillB(VectorRegister wd, Register rs) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e)) - .FprOuts(wd).GprIns(rs); -} - -void MipsAssembler::FillH(VectorRegister wd, Register rs) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e)) - .FprOuts(wd).GprIns(rs); -} - -void MipsAssembler::FillW(VectorRegister wd, Register rs) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e)) - .FprOuts(wd).GprIns(rs); -} - -void MipsAssembler::LdiB(VectorRegister wd, int imm8) { - CHECK(HasMsa()); - CHECK(IsInt<8>(imm8)) << imm8; - DsFsmInstr(EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7)).FprOuts(wd); -} - -void MipsAssembler::LdiH(VectorRegister wd, int imm10) { - CHECK(HasMsa()); - CHECK(IsInt<10>(imm10)) << imm10; - DsFsmInstr(EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd); -} - -void MipsAssembler::LdiW(VectorRegister wd, int imm10) { - CHECK(HasMsa()); - CHECK(IsInt<10>(imm10)) << imm10; - DsFsmInstr(EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd); -} - -void MipsAssembler::LdiD(VectorRegister wd, int imm10) { - CHECK(HasMsa()); - CHECK(IsInt<10>(imm10)) << imm10; - DsFsmInstr(EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd); -} - -void MipsAssembler::LdB(VectorRegister wd, Register rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<10>(offset)) << offset; - DsFsmInstr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0)).FprOuts(wd).GprIns(rs); -} - -void MipsAssembler::LdH(VectorRegister wd, Register rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<11>(offset)) << offset; - CHECK_ALIGNED(offset, kMipsHalfwordSize); - DsFsmInstr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1)) - .FprOuts(wd).GprIns(rs); -} - -void MipsAssembler::LdW(VectorRegister wd, Register rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<12>(offset)) << offset; - CHECK_ALIGNED(offset, kMipsWordSize); - DsFsmInstr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2)) - .FprOuts(wd).GprIns(rs); -} - -void MipsAssembler::LdD(VectorRegister wd, Register rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<13>(offset)) << offset; - CHECK_ALIGNED(offset, kMipsDoublewordSize); - DsFsmInstr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3)) - .FprOuts(wd).GprIns(rs); -} - -void MipsAssembler::StB(VectorRegister wd, Register rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<10>(offset)) << offset; - DsFsmInstr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0)).FprIns(wd).GprIns(rs); -} - -void MipsAssembler::StH(VectorRegister wd, Register rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<11>(offset)) << offset; - CHECK_ALIGNED(offset, kMipsHalfwordSize); - DsFsmInstr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1)) - .FprIns(wd).GprIns(rs); -} - -void MipsAssembler::StW(VectorRegister wd, Register rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<12>(offset)) << offset; - CHECK_ALIGNED(offset, kMipsWordSize); - DsFsmInstr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2)) - .FprIns(wd).GprIns(rs); -} - -void MipsAssembler::StD(VectorRegister wd, Register rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<13>(offset)) << offset; - CHECK_ALIGNED(offset, kMipsDoublewordSize); - DsFsmInstr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3)) - .FprIns(wd).GprIns(rs); -} - -void MipsAssembler::IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Asub_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Asub_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Asub_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Asub_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Asub_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Asub_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Asub_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Asub_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); -} - -void MipsAssembler::PcntB(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2R(0xc1, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::PcntH(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2R(0xc1, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::PcntW(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2R(0xc1, 0x2, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::PcntD(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - DsFsmInstr(EmitMsa2R(0xc1, 0x3, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); -} - -void MipsAssembler::ReplicateFPToVectorRegister(VectorRegister dst, - FRegister src, - bool is_double) { - // Float or double in FPU register Fx can be considered as 0th element in vector register Wx. - if (is_double) { - SplatiD(dst, static_cast<VectorRegister>(src), 0); - } else { - SplatiW(dst, static_cast<VectorRegister>(src), 0); - } -} - -void MipsAssembler::LoadConst32(Register rd, int32_t value) { - if (IsUint<16>(value)) { - // Use OR with (unsigned) immediate to encode 16b unsigned int. - Ori(rd, ZERO, value); - } else if (IsInt<16>(value)) { - // Use ADD with (signed) immediate to encode 16b signed int. - Addiu(rd, ZERO, value); - } else { - Lui(rd, High16Bits(value)); - if (value & 0xFFFF) - Ori(rd, rd, Low16Bits(value)); - } -} - -void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) { - uint32_t low = Low32Bits(value); - uint32_t high = High32Bits(value); - LoadConst32(reg_lo, low); - if (high != low) { - LoadConst32(reg_hi, high); - } else { - Move(reg_hi, reg_lo); - } -} - -void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) { - if (value == 0) { - temp = ZERO; - } else { - LoadConst32(temp, value); - } - Mtc1(temp, r); -} - -void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) { - uint32_t low = Low32Bits(value); - uint32_t high = High32Bits(value); - if (low == 0) { - Mtc1(ZERO, rd); - } else { - LoadConst32(temp, low); - Mtc1(temp, rd); - } - if (high == 0) { - MoveToFpuHigh(ZERO, rd); - } else { - LoadConst32(temp, high); - MoveToFpuHigh(temp, rd); - } -} - -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 { - // 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); - } - } -} - -void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size, - MipsAssembler::Branch::Type short_type, - MipsAssembler::Branch::Type long_type) { - type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type; -} - -void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) { - OffsetBits offset_size_needed = GetOffsetSizeNeeded(location_, target_); - if (is_r6) { - // R6 - switch (initial_type) { - case kLabel: - CHECK(!IsResolved()); - type_ = kR6Label; - break; - case kLiteral: - CHECK(!IsResolved()); - type_ = kR6Literal; - break; - case kCall: - InitShortOrLong(offset_size_needed, kR6Call, kR6LongCall); - break; - case kCondBranch: - switch (condition_) { - case kUncond: - InitShortOrLong(offset_size_needed, kR6UncondBranch, kR6LongUncondBranch); - break; - case kCondEQZ: - case kCondNEZ: - // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions. - type_ = (offset_size_needed <= kOffset23) ? kR6CondBranch : kR6LongCondBranch; - break; - default: - InitShortOrLong(offset_size_needed, kR6CondBranch, kR6LongCondBranch); - break; - } - break; - case kBareCall: - type_ = kR6BareCall; - CHECK_LE(offset_size_needed, GetOffsetSize()); - break; - case kBareCondBranch: - type_ = (condition_ == kUncond) ? kR6BareUncondBranch : kR6BareCondBranch; - CHECK_LE(offset_size_needed, GetOffsetSize()); - break; - default: - LOG(FATAL) << "Unexpected branch type " << initial_type; - UNREACHABLE(); - } - } else { - // R2 - switch (initial_type) { - case kLabel: - CHECK(!IsResolved()); - type_ = kLabel; - break; - case kLiteral: - CHECK(!IsResolved()); - type_ = kLiteral; - break; - case kCall: - InitShortOrLong(offset_size_needed, kCall, kLongCall); - break; - case kCondBranch: - switch (condition_) { - case kUncond: - InitShortOrLong(offset_size_needed, kUncondBranch, kLongUncondBranch); - break; - default: - InitShortOrLong(offset_size_needed, kCondBranch, kLongCondBranch); - break; - } - break; - case kBareCall: - type_ = kBareCall; - CHECK_LE(offset_size_needed, GetOffsetSize()); - break; - case kBareCondBranch: - type_ = (condition_ == kUncond) ? kBareUncondBranch : kBareCondBranch; - CHECK_LE(offset_size_needed, GetOffsetSize()); - break; - default: - LOG(FATAL) << "Unexpected branch type " << initial_type; - UNREACHABLE(); - } - } - old_type_ = type_; -} - -bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) { - switch (condition) { - case kCondLT: - case kCondGT: - case kCondNE: - case kCondLTU: - return lhs == rhs; - default: - return false; - } -} - -bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) { - switch (condition) { - case kUncond: - return true; - case kCondGE: - case kCondLE: - case kCondEQ: - case kCondGEU: - return lhs == rhs; - default: - return false; - } -} - -MipsAssembler::Branch::Branch(bool is_r6, - uint32_t location, - uint32_t target, - bool is_call, - bool is_bare) - : old_location_(location), - location_(location), - target_(target), - lhs_reg_(0), - rhs_reg_(0), - condition_(kUncond), - delayed_instruction_(kUnfilledDelaySlot), - patcher_label_(nullptr) { - InitializeType( - (is_call ? (is_bare ? kBareCall : kCall) : (is_bare ? kBareCondBranch : kCondBranch)), - is_r6); -} - -MipsAssembler::Branch::Branch(bool is_r6, - uint32_t location, - uint32_t target, - MipsAssembler::BranchCondition condition, - Register lhs_reg, - Register rhs_reg, - bool is_bare) - : old_location_(location), - location_(location), - target_(target), - lhs_reg_(lhs_reg), - rhs_reg_(rhs_reg), - condition_(condition), - delayed_instruction_(kUnfilledDelaySlot), - patcher_label_(nullptr) { - CHECK_NE(condition, kUncond); - switch (condition) { - case kCondLT: - case kCondGE: - case kCondLE: - case kCondGT: - case kCondLTU: - case kCondGEU: - // We don't support synthetic R2 branches (preceded with slt[u]) at this level - // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). - // We leave this up to the caller. - CHECK(is_r6); - FALLTHROUGH_INTENDED; - case kCondEQ: - case kCondNE: - // Require registers other than 0 not only for R6, but also for R2 to catch errors. - // To compare with 0, use dedicated kCond*Z conditions. - CHECK_NE(lhs_reg, ZERO); - CHECK_NE(rhs_reg, ZERO); - break; - case kCondLTZ: - case kCondGEZ: - case kCondLEZ: - case kCondGTZ: - case kCondEQZ: - case kCondNEZ: - // Require registers other than 0 not only for R6, but also for R2 to catch errors. - CHECK_NE(lhs_reg, ZERO); - CHECK_EQ(rhs_reg, ZERO); - break; - case kCondF: - case kCondT: - CHECK_EQ(rhs_reg, ZERO); - break; - case kUncond: - UNREACHABLE(); - } - CHECK(!IsNop(condition, lhs_reg, rhs_reg)); - if (IsUncond(condition, lhs_reg, rhs_reg)) { - // Branch condition is always true, make the branch unconditional. - condition_ = kUncond; - } - InitializeType((is_bare ? kBareCondBranch : kCondBranch), is_r6); -} - -MipsAssembler::Branch::Branch(bool is_r6, - uint32_t location, - Register dest_reg, - Register base_reg, - Type label_or_literal_type) - : old_location_(location), - location_(location), - target_(kUnresolved), - lhs_reg_(dest_reg), - rhs_reg_(base_reg), - condition_(kUncond), - delayed_instruction_(kUnfilledDelaySlot), - patcher_label_(nullptr) { - CHECK_NE(dest_reg, ZERO); - if (is_r6) { - CHECK_EQ(base_reg, ZERO); - } - InitializeType(label_or_literal_type, is_r6); -} - -MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition( - MipsAssembler::BranchCondition cond) { - switch (cond) { - case kCondLT: - return kCondGE; - case kCondGE: - return kCondLT; - case kCondLE: - return kCondGT; - case kCondGT: - return kCondLE; - case kCondLTZ: - return kCondGEZ; - case kCondGEZ: - return kCondLTZ; - case kCondLEZ: - return kCondGTZ; - case kCondGTZ: - return kCondLEZ; - case kCondEQ: - return kCondNE; - case kCondNE: - return kCondEQ; - case kCondEQZ: - return kCondNEZ; - case kCondNEZ: - return kCondEQZ; - case kCondLTU: - return kCondGEU; - case kCondGEU: - return kCondLTU; - case kCondF: - return kCondT; - case kCondT: - return kCondF; - case kUncond: - LOG(FATAL) << "Unexpected branch condition " << cond; - } - UNREACHABLE(); -} - -MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const { - return type_; -} - -MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const { - return condition_; -} - -Register MipsAssembler::Branch::GetLeftRegister() const { - return static_cast<Register>(lhs_reg_); -} - -Register MipsAssembler::Branch::GetRightRegister() const { - return static_cast<Register>(rhs_reg_); -} - -uint32_t MipsAssembler::Branch::GetTarget() const { - return target_; -} - -uint32_t MipsAssembler::Branch::GetLocation() const { - return location_; -} - -uint32_t MipsAssembler::Branch::GetOldLocation() const { - return old_location_; -} - -uint32_t MipsAssembler::Branch::GetPrecedingInstructionLength(Type type) const { - // Short branches with delay slots always consist of two instructions, the branch - // and the delay slot, irrespective of whether the delay slot is filled with a - // useful instruction or not. - // Long composite branches may have a length longer by one instruction than - // specified in branch_info_[].length. This happens when an instruction is taken - // to fill the short branch delay slot, but the branch eventually becomes long - // and formally has no delay slot to fill. This instruction is placed at the - // beginning of the long composite branch and this needs to be accounted for in - // the branch length and the location of the offset encoded in the branch. - switch (type) { - case kLongUncondBranch: - case kLongCondBranch: - case kLongCall: - case kR6LongCondBranch: - return (delayed_instruction_ != kUnfilledDelaySlot && - delayed_instruction_ != kUnfillableDelaySlot) ? 1 : 0; - default: - return 0; - } -} - -uint32_t MipsAssembler::Branch::GetPrecedingInstructionSize(Type type) const { - return GetPrecedingInstructionLength(type) * sizeof(uint32_t); -} - -uint32_t MipsAssembler::Branch::GetLength() const { - return GetPrecedingInstructionLength(type_) + branch_info_[type_].length; -} - -uint32_t MipsAssembler::Branch::GetOldLength() const { - return GetPrecedingInstructionLength(old_type_) + branch_info_[old_type_].length; -} - -uint32_t MipsAssembler::Branch::GetSize() const { - return GetLength() * sizeof(uint32_t); -} - -uint32_t MipsAssembler::Branch::GetOldSize() const { - return GetOldLength() * sizeof(uint32_t); -} - -uint32_t MipsAssembler::Branch::GetEndLocation() const { - return GetLocation() + GetSize(); -} - -uint32_t MipsAssembler::Branch::GetOldEndLocation() const { - return GetOldLocation() + GetOldSize(); -} - -bool MipsAssembler::Branch::IsBare() const { - switch (type_) { - // R2 short branches (can't be promoted to long), delay slots filled manually. - case kBareUncondBranch: - case kBareCondBranch: - case kBareCall: - // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. - case kR6BareUncondBranch: - case kR6BareCondBranch: - case kR6BareCall: - return true; - default: - return false; - } -} - -bool MipsAssembler::Branch::IsLong() const { - switch (type_) { - // R2 short branches (can be promoted to long). - case kUncondBranch: - case kCondBranch: - case kCall: - // R2 short branches (can't be promoted to long), delay slots filled manually. - case kBareUncondBranch: - case kBareCondBranch: - case kBareCall: - // R2 near label. - case kLabel: - // R2 near literal. - case kLiteral: - // R6 short branches (can be promoted to long). - case kR6UncondBranch: - case kR6CondBranch: - case kR6Call: - // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. - case kR6BareUncondBranch: - case kR6BareCondBranch: - case kR6BareCall: - // R6 near label. - case kR6Label: - // R6 near literal. - case kR6Literal: - return false; - // R2 long branches. - case kLongUncondBranch: - case kLongCondBranch: - case kLongCall: - // R2 far label. - case kFarLabel: - // R2 far literal. - case kFarLiteral: - // R6 long branches. - case kR6LongUncondBranch: - case kR6LongCondBranch: - case kR6LongCall: - // R6 far label. - case kR6FarLabel: - // R6 far literal. - case kR6FarLiteral: - return true; - } - UNREACHABLE(); -} - -bool MipsAssembler::Branch::IsResolved() const { - return target_ != kUnresolved; -} - -MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const { - bool r6_cond_branch = (type_ == kR6CondBranch || type_ == kR6BareCondBranch); - OffsetBits offset_size = - (r6_cond_branch && (condition_ == kCondEQZ || condition_ == kCondNEZ)) - ? kOffset23 - : branch_info_[type_].offset_size; - return offset_size; -} - -MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location, - uint32_t target) { - // For unresolved targets assume the shortest encoding - // (later it will be made longer if needed). - if (target == kUnresolved) - return kOffset16; - int64_t distance = static_cast<int64_t>(target) - location; - // To simplify calculations in composite branches consisting of multiple instructions - // bump up the distance by a value larger than the max byte size of a composite branch. - distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize; - if (IsInt<kOffset16>(distance)) - return kOffset16; - else if (IsInt<kOffset18>(distance)) - return kOffset18; - else if (IsInt<kOffset21>(distance)) - return kOffset21; - else if (IsInt<kOffset23>(distance)) - return kOffset23; - else if (IsInt<kOffset28>(distance)) - return kOffset28; - return kOffset32; -} - -void MipsAssembler::Branch::Resolve(uint32_t target) { - target_ = target; -} - -void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) { - if (location_ > expand_location) { - location_ += delta; - } - if (!IsResolved()) { - return; // Don't know the target yet. - } - if (target_ > expand_location) { - target_ += delta; - } -} - -void MipsAssembler::Branch::PromoteToLong() { - CHECK(!IsBare()); // Bare branches do not promote. - switch (type_) { - // R2 short branches (can be promoted to long). - case kUncondBranch: - type_ = kLongUncondBranch; - break; - case kCondBranch: - type_ = kLongCondBranch; - break; - case kCall: - type_ = kLongCall; - break; - // R2 near label. - case kLabel: - type_ = kFarLabel; - break; - // R2 near literal. - case kLiteral: - type_ = kFarLiteral; - break; - // R6 short branches (can be promoted to long). - case kR6UncondBranch: - type_ = kR6LongUncondBranch; - break; - case kR6CondBranch: - type_ = kR6LongCondBranch; - break; - case kR6Call: - type_ = kR6LongCall; - break; - // R6 near label. - case kR6Label: - type_ = kR6FarLabel; - break; - // R6 near literal. - case kR6Literal: - type_ = kR6FarLiteral; - break; - default: - // Note: 'type_' is already long. - break; - } - CHECK(IsLong()); -} - -uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const { - switch (branch->GetType()) { - case Branch::kLabel: - case Branch::kFarLabel: - case Branch::kLiteral: - case Branch::kFarLiteral: - if (branch->GetRightRegister() != ZERO) { - return GetLabelLocation(&pc_rel_base_label_); - } - // For those label/literal loads which come with their own NAL instruction - // and don't depend on `pc_rel_base_label_` we can simply use the location - // of the "branch" (the NAL precedes the "branch" immediately). The location - // is close enough for the user of the returned location, PromoteIfNeeded(), - // to not miss needed promotion to a far load. - // (GetOffsetSizeNeeded() provides a little leeway by means of kMaxBranchSize, - // which is larger than all composite branches and label/literal loads: it's - // OK to promote a bit earlier than strictly necessary, it makes things - // simpler.) - FALLTHROUGH_INTENDED; - default: - return branch->GetLocation(); - } -} - -uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) { - // `location` comes from GetBranchLocationOrPcRelBase() and is either the location - // of the PC-relative branch or (for some R2 label and literal loads) the location - // of `pc_rel_base_label_`. The PC-relative offset of the branch/load is relative - // to this location. - // If the branch is still unresolved or already long, nothing to do. - if (IsLong() || !IsResolved()) { - return 0; - } - // Promote the short branch to long if the offset size is too small - // to hold the distance between location and target_. - if (GetOffsetSizeNeeded(location, target_) > GetOffsetSize()) { - PromoteToLong(); - uint32_t old_size = GetOldSize(); - uint32_t new_size = GetSize(); - CHECK_GT(new_size, old_size); - return new_size - old_size; - } - // The following logic is for debugging/testing purposes. - // Promote some short branches to long when it's not really required. - if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max() && !IsBare())) { - int64_t distance = static_cast<int64_t>(target_) - location; - distance = (distance >= 0) ? distance : -distance; - if (distance >= max_short_distance) { - PromoteToLong(); - uint32_t old_size = GetOldSize(); - uint32_t new_size = GetSize(); - CHECK_GT(new_size, old_size); - return new_size - old_size; - } - } - return 0; -} - -uint32_t MipsAssembler::Branch::GetOffsetLocation() const { - return location_ + GetPrecedingInstructionSize(type_) + - branch_info_[type_].instr_offset * sizeof(uint32_t); -} - -uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const { - switch (branch->GetType()) { - case Branch::kLabel: - case Branch::kFarLabel: - case Branch::kLiteral: - case Branch::kFarLiteral: - if (branch->GetRightRegister() == ZERO) { - // These loads don't use `pc_rel_base_label_` and instead rely on their own - // NAL instruction (it immediately precedes the "branch"). Therefore the - // effective PC-relative base register is RA and it corresponds to the 2nd - // instruction after the NAL. - return branch->GetLocation() + sizeof(uint32_t); - } else { - return GetLabelLocation(&pc_rel_base_label_); - } - default: - return branch->GetOffsetLocation() + - Branch::branch_info_[branch->GetType()].pc_org * sizeof(uint32_t); - } -} - -uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const { - // `location` comes from GetBranchOrPcRelBaseForEncoding() and is either a location - // within/near the PC-relative branch or (for some R2 label and literal loads) the - // location of `pc_rel_base_label_`. The PC-relative offset of the branch/load is - // relative to this location. - CHECK(IsResolved()); - uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize()); - // Calculate the byte distance between instructions and also account for - // different PC-relative origins. - uint32_t offset = target_ - location; - // Prepare the offset for encoding into the instruction(s). - offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift; - return offset; -} - -MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) { - CHECK_LT(branch_id, branches_.size()); - return &branches_[branch_id]; -} - -const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const { - CHECK_LT(branch_id, branches_.size()); - return &branches_[branch_id]; -} - -void MipsAssembler::BindRelativeToPrecedingBranch(MipsLabel* label, - uint32_t prev_branch_id_plus_one, - uint32_t position) { - if (prev_branch_id_plus_one != 0) { - const Branch* branch = GetBranch(prev_branch_id_plus_one - 1); - position -= branch->GetEndLocation(); - } - label->prev_branch_id_plus_one_ = prev_branch_id_plus_one; - label->BindTo(position); -} - -void MipsAssembler::Bind(MipsLabel* label) { - CHECK(!label->IsBound()); - uint32_t bound_pc = buffer_.Size(); - - // Make the delay slot FSM aware of the new label. - DsFsmLabel(); - - // Walk the list of branches referring to and preceding this label. - // Store the previously unknown target addresses in them. - while (label->IsLinked()) { - uint32_t branch_id = label->Position(); - Branch* branch = GetBranch(branch_id); - branch->Resolve(bound_pc); - - uint32_t branch_location = branch->GetLocation(); - // Extract the location of the previous branch in the list (walking the list backwards; - // the previous branch ID was stored in the space reserved for this branch). - uint32_t prev = buffer_.Load<uint32_t>(branch_location); - - // On to the previous branch in the list... - label->position_ = prev; - } - - // Now make the label object contain its own location (relative to the end of the preceding - // branch, if any; it will be used by the branches referring to and following this label). - BindRelativeToPrecedingBranch(label, branches_.size(), bound_pc); -} - -uint32_t MipsAssembler::GetLabelLocation(const MipsLabel* label) const { - CHECK(label->IsBound()); - uint32_t target = label->Position(); - if (label->prev_branch_id_plus_one_ != 0) { - // Get label location based on the branch preceding it. - const Branch* branch = GetBranch(label->prev_branch_id_plus_one_ - 1); - target += branch->GetEndLocation(); - } - return target; -} - -uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) { - // We can reconstruct the adjustment by going through all the branches from the beginning - // up to the old_position. Since we expect AdjustedPosition() to be called in a loop - // with increasing old_position, we can use the data from last AdjustedPosition() to - // continue where we left off and the whole loop should be O(m+n) where m is the number - // of positions to adjust and n is the number of branches. - if (old_position < last_old_position_) { - last_position_adjustment_ = 0; - last_old_position_ = 0; - last_branch_id_ = 0; - } - while (last_branch_id_ != branches_.size()) { - const Branch* branch = GetBranch(last_branch_id_); - if (branch->GetLocation() >= old_position + last_position_adjustment_) { - break; - } - last_position_adjustment_ += branch->GetSize() - branch->GetOldSize(); - ++last_branch_id_; - } - last_old_position_ = old_position; - return old_position + last_position_adjustment_; -} - -void MipsAssembler::BindPcRelBaseLabel() { - Bind(&pc_rel_base_label_); -} - -uint32_t MipsAssembler::GetPcRelBaseLabelLocation() const { - return GetLabelLocation(&pc_rel_base_label_); -} - -void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) { - uint32_t length = branches_.back().GetLength(); - // Commit the last branch target label (if any). - DsFsmCommitLabel(); - if (!label->IsBound()) { - // Branch forward (to a following label), distance is unknown. - // The first branch forward will contain 0, serving as the terminator of - // the list of forward-reaching branches. - Emit(label->position_); - // Nothing for the delay slot (yet). - DsFsmInstrNop(0); - length--; - // Now make the label object point to this branch - // (this forms a linked list of branches preceding this label). - uint32_t branch_id = branches_.size() - 1; - label->LinkTo(branch_id); - } - // Reserve space for the branch. - for (; length != 0u; --length) { - Nop(); - } -} - -bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slot) const { - if (delay_slot.instruction_ == 0) { - // NOP or no instruction for the delay slot. - return false; - } - switch (type_) { - // R2 unconditional branches. - case kUncondBranch: - case kLongUncondBranch: - // There are no register interdependencies. - return true; - - // R2 calls. - case kCall: - case kLongCall: - // Instructions depending on or modifying RA should not be moved into delay slots - // of branches modifying RA. - return ((delay_slot.masks_.gpr_ins_ | delay_slot.masks_.gpr_outs_) & (1u << RA)) == 0; - - // R2 conditional branches. - case kCondBranch: - case kLongCondBranch: - switch (condition_) { - // Branches with one GPR source. - case kCondLTZ: - case kCondGEZ: - case kCondLEZ: - case kCondGTZ: - case kCondEQZ: - case kCondNEZ: - return (delay_slot.masks_.gpr_outs_ & (1u << lhs_reg_)) == 0; - - // Branches with two GPR sources. - case kCondEQ: - case kCondNE: - return (delay_slot.masks_.gpr_outs_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0; - - // Branches with one FPU condition code source. - case kCondF: - case kCondT: - return (delay_slot.masks_.cc_outs_ & (1u << lhs_reg_)) == 0; - - default: - // We don't support synthetic R2 branches (preceded with slt[u]) at this level - // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). - LOG(FATAL) << "Unexpected branch condition " << condition_; - UNREACHABLE(); - } - - // R6 unconditional branches. - case kR6UncondBranch: - case kR6LongUncondBranch: - // R6 calls. - case kR6Call: - case kR6LongCall: - // There are no delay slots. - return false; - - // R6 conditional branches. - case kR6CondBranch: - case kR6LongCondBranch: - switch (condition_) { - // Branches with one FPU register source. - case kCondF: - case kCondT: - return (delay_slot.masks_.fpr_outs_ & (1u << lhs_reg_)) == 0; - // Others have a forbidden slot instead of a delay slot. - default: - return false; - } - - // Literals. - default: - LOG(FATAL) << "Unexpected branch type " << type_; - UNREACHABLE(); - } -} - -uint32_t MipsAssembler::Branch::GetDelayedInstruction() const { - return delayed_instruction_; -} - -MipsLabel* MipsAssembler::Branch::GetPatcherLabel() const { - return patcher_label_; -} - -void MipsAssembler::Branch::SetDelayedInstruction(uint32_t instruction, MipsLabel* patcher_label) { - CHECK_NE(instruction, kUnfilledDelaySlot); - CHECK_EQ(delayed_instruction_, kUnfilledDelaySlot); - delayed_instruction_ = instruction; - patcher_label_ = patcher_label; -} - -void MipsAssembler::Branch::DecrementLocations() { - // We first create a branch object, which gets its type and locations initialized, - // and then we check if the branch can actually have the preceding instruction moved - // into its delay slot. If it can, the branch locations need to be decremented. - // - // We could make the check before creating the branch object and avoid the location - // adjustment, but the check is cleaner when performed on an initialized branch - // object. - // - // If the branch is backwards (to a previously bound label), reducing the locations - // cannot cause a short branch to exceed its offset range because the offset reduces. - // And this is not at all a problem for a long branch backwards. - // - // If the branch is forward (not linked to any label yet), reducing the locations - // is harmless. The branch will be promoted to long if needed when the target is known. - CHECK_EQ(location_, old_location_); - CHECK_GE(old_location_, sizeof(uint32_t)); - old_location_ -= sizeof(uint32_t); - location_ = old_location_; -} - -void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) { - if (branch.IsBare()) { - // Delay slots are filled manually in bare branches. - return; - } - if (branch.CanHaveDelayedInstruction(delay_slot_)) { - // The last instruction cannot be used in a different delay slot, - // do not commit the label before it (if any). - DsFsmDropLabel(); - // Remove the last emitted instruction. - size_t size = buffer_.Size(); - CHECK_GE(size, sizeof(uint32_t)); - size -= sizeof(uint32_t); - CHECK_EQ(buffer_.Load<uint32_t>(size), delay_slot_.instruction_); - buffer_.Resize(size); - // Attach it to the branch and adjust the branch locations. - branch.DecrementLocations(); - branch.SetDelayedInstruction(delay_slot_.instruction_, delay_slot_.patcher_label_); - } else if (!reordering_ && branch.GetType() == Branch::kUncondBranch) { - // If reordefing is disabled, prevent absorption of the target instruction. - branch.SetDelayedInstruction(Branch::kUnfillableDelaySlot); - } -} - -void MipsAssembler::Buncond(MipsLabel* label, bool is_r6, bool is_bare) { - uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; - branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call= */ false, is_bare); - MoveInstructionToDelaySlot(branches_.back()); - FinalizeLabeledBranch(label); -} - -void MipsAssembler::Bcond(MipsLabel* label, - bool is_r6, - bool is_bare, - BranchCondition condition, - Register lhs, - Register rhs) { - // If lhs = rhs, this can be a NOP. - if (Branch::IsNop(condition, lhs, rhs)) { - return; - } - uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; - branches_.emplace_back(is_r6, buffer_.Size(), target, condition, lhs, rhs, is_bare); - MoveInstructionToDelaySlot(branches_.back()); - FinalizeLabeledBranch(label); -} - -void MipsAssembler::Call(MipsLabel* label, bool is_r6, bool is_bare) { - uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; - branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call= */ true, is_bare); - MoveInstructionToDelaySlot(branches_.back()); - FinalizeLabeledBranch(label); -} - -void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) { - // Label address loads are treated as pseudo branches since they require very similar handling. - DCHECK(!label->IsBound()); - // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we - // may generate an individual NAL instruction to simulate PC-relative addressing on R2 - // by specifying `base_reg` of `ZERO`. Check for it. - if (base_reg == ZERO && !IsR6()) { - Nal(); - } - branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel); - FinalizeLabeledBranch(label); -} - -Literal* MipsAssembler::NewLiteral(size_t size, const uint8_t* data) { - DCHECK(size == 4u || size == 8u) << size; - literals_.emplace_back(size, data); - return &literals_.back(); -} - -void MipsAssembler::LoadLiteral(Register dest_reg, Register base_reg, Literal* literal) { - // Literal loads are treated as pseudo branches since they require very similar handling. - DCHECK_EQ(literal->GetSize(), 4u); - MipsLabel* label = literal->GetLabel(); - DCHECK(!label->IsBound()); - // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we - // may generate an individual NAL instruction to simulate PC-relative addressing on R2 - // by specifying `base_reg` of `ZERO`. Check for it. - if (base_reg == ZERO && !IsR6()) { - Nal(); - } - branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral); - FinalizeLabeledBranch(label); -} - -JumpTable* MipsAssembler::CreateJumpTable(std::vector<MipsLabel*>&& labels) { - jump_tables_.emplace_back(std::move(labels)); - JumpTable* table = &jump_tables_.back(); - DCHECK(!table->GetLabel()->IsBound()); - return table; -} - -void MipsAssembler::EmitLiterals() { - if (!literals_.empty()) { - // We don't support byte and half-word literals. - // TODO: proper alignment for 64-bit literals when they're implemented. - for (Literal& literal : literals_) { - MipsLabel* label = literal.GetLabel(); - Bind(label); - AssemblerBuffer::EnsureCapacity ensured(&buffer_); - DCHECK(literal.GetSize() == 4u || literal.GetSize() == 8u); - for (size_t i = 0, size = literal.GetSize(); i != size; ++i) { - buffer_.Emit<uint8_t>(literal.GetData()[i]); - } - } - } -} - -void MipsAssembler::ReserveJumpTableSpace() { - if (!jump_tables_.empty()) { - for (JumpTable& table : jump_tables_) { - MipsLabel* label = table.GetLabel(); - Bind(label); - - // Bulk ensure capacity, as this may be large. - size_t orig_size = buffer_.Size(); - size_t required_capacity = orig_size + table.GetSize(); - if (required_capacity > buffer_.Capacity()) { - buffer_.ExtendCapacity(required_capacity); - } -#ifndef NDEBUG - buffer_.has_ensured_capacity_ = true; -#endif - - // Fill the space with dummy data as the data is not final - // until the branches have been promoted. And we shouldn't - // be moving uninitialized data during branch promotion. - for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) { - buffer_.Emit<uint32_t>(0x1abe1234u); - } - -#ifndef NDEBUG - buffer_.has_ensured_capacity_ = false; -#endif - } - } -} - -void MipsAssembler::EmitJumpTables() { - if (!jump_tables_.empty()) { - CHECK(!overwriting_); - // Switch from appending instructions at the end of the buffer to overwriting - // existing instructions (here, jump tables) in the buffer. - overwriting_ = true; - - for (JumpTable& table : jump_tables_) { - MipsLabel* table_label = table.GetLabel(); - uint32_t start = GetLabelLocation(table_label); - overwrite_location_ = start; - - for (MipsLabel* target : table.GetData()) { - CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u); - // The table will contain target addresses relative to the table start. - uint32_t offset = GetLabelLocation(target) - start; - Emit(offset); - } - } - - overwriting_ = false; - } -} - -void MipsAssembler::PromoteBranches() { - // Promote short branches to long as necessary. - bool changed; - do { - changed = false; - for (auto& branch : branches_) { - CHECK(branch.IsResolved()); - uint32_t base = GetBranchLocationOrPcRelBase(&branch); - uint32_t delta = branch.PromoteIfNeeded(base); - // If this branch has been promoted and needs to expand in size, - // relocate all branches by the expansion size. - if (delta) { - changed = true; - uint32_t expand_location = branch.GetLocation(); - for (auto& branch2 : branches_) { - branch2.Relocate(expand_location, delta); - } - } - } - } while (changed); - - // Account for branch expansion by resizing the code buffer - // and moving the code in it to its final location. - size_t branch_count = branches_.size(); - if (branch_count > 0) { - // Resize. - Branch& last_branch = branches_[branch_count - 1]; - uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation(); - uint32_t old_size = buffer_.Size(); - buffer_.Resize(old_size + size_delta); - // Move the code residing between branch placeholders. - uint32_t end = old_size; - for (size_t i = branch_count; i > 0; ) { - Branch& branch = branches_[--i]; - CHECK_GE(end, branch.GetOldEndLocation()); - uint32_t size = end - branch.GetOldEndLocation(); - buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size); - end = branch.GetOldLocation(); - } - } -} - -// Note: make sure branch_info_[] and EmitBranch() are kept synchronized. -const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = { - // R2 short branches (can be promoted to long). - { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch - { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch - { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCall - // R2 short branches (can't be promoted to long), delay slots filled manually. - { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareUncondBranch - { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCondBranch - { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCall - // R2 near label. - { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLabel - // R2 near literal. - { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLiteral - // R2 long branches. - { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch - { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch - { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall - // R2 far label. - { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLabel - // R2 far literal. - { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLiteral - // R6 short branches (can be promoted to long). - { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch - { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch - // Exception: kOffset23 for beqzc/bnezc. - { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6Call - // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. - { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareUncondBranch - { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6BareCondBranch - // Exception: kOffset23 for beqzc/bnezc. - { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareCall - // R6 near label. - { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Label - // R6 near literal. - { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Literal - // R6 long branches. - { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch - { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch - { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall - // R6 far label. - { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLabel - // R6 far literal. - { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLiteral -}; - -static inline bool IsAbsorbableInstruction(uint32_t instruction) { - // The relative patcher patches addiu, lw and sw with an immediate operand of 0x5678. - // We want to make sure that these instructions do not get absorbed into delay slots - // of unconditional branches on R2. Absorption would otherwise make copies of - // unpatched instructions. - if ((instruction & 0xFFFF) != 0x5678) { - return true; - } - switch (instruction >> kOpcodeShift) { - case 0x09: // Addiu. - case 0x23: // Lw. - case 0x2B: // Sw. - return false; - default: - return true; - } -} - -static inline Register GetR2PcRelBaseRegister(Register reg) { - // LoadLabelAddress() and LoadLiteral() generate individual NAL - // instructions on R2 when the specified base register is ZERO - // and so the effective PC-relative base register is RA, not ZERO. - return (reg == ZERO) ? RA : reg; -} - -// Note: make sure branch_info_[] and EmitBranch() are kept synchronized. -void MipsAssembler::EmitBranch(uint32_t branch_id) { - CHECK_EQ(overwriting_, true); - Branch* branch = GetBranch(branch_id); - overwrite_location_ = branch->GetLocation(); - uint32_t offset = branch->GetOffset(GetBranchOrPcRelBaseForEncoding(branch)); - BranchCondition condition = branch->GetCondition(); - Register lhs = branch->GetLeftRegister(); - Register rhs = branch->GetRightRegister(); - uint32_t delayed_instruction = branch->GetDelayedInstruction(); - MipsLabel* patcher_label = branch->GetPatcherLabel(); - if (patcher_label != nullptr) { - // Update the patcher label location to account for branch promotion and - // delay slot filling. - CHECK(patcher_label->IsBound()); - uint32_t bound_pc = branch->GetLocation(); - if (!branch->IsLong()) { - // Short branches precede delay slots. - // Long branches follow "delay slots". - bound_pc += sizeof(uint32_t); - } - // Rebind the label. - patcher_label->Reinitialize(); - BindRelativeToPrecedingBranch(patcher_label, branch_id, bound_pc); - } - switch (branch->GetType()) { - // R2 short branches. - case Branch::kUncondBranch: - if (delayed_instruction == Branch::kUnfillableDelaySlot) { - // The branch was created when reordering was disabled, do not absorb the target - // instruction. - delayed_instruction = 0; // NOP. - } else if (delayed_instruction == Branch::kUnfilledDelaySlot) { - // Try to absorb the target instruction into the delay slot. - delayed_instruction = 0; // NOP. - // Incrementing the signed 16-bit offset past the target instruction must not - // cause overflow into the negative subrange, check for the max offset. - if (offset != 0x7FFF) { - uint32_t target = branch->GetTarget(); - if (std::binary_search(ds_fsm_target_pcs_.begin(), ds_fsm_target_pcs_.end(), target)) { - uint32_t target_instruction = buffer_.Load<uint32_t>(target); - if (IsAbsorbableInstruction(target_instruction)) { - delayed_instruction = target_instruction; - offset++; - } - } - } - } - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - B(offset); - Emit(delayed_instruction); - break; - case Branch::kCondBranch: - DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); - if (delayed_instruction == Branch::kUnfilledDelaySlot) { - delayed_instruction = 0; // NOP. - } - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - EmitBcondR2(condition, lhs, rhs, offset); - Emit(delayed_instruction); - break; - case Branch::kCall: - DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); - if (delayed_instruction == Branch::kUnfilledDelaySlot) { - delayed_instruction = 0; // NOP. - } - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Bal(offset); - Emit(delayed_instruction); - break; - case Branch::kBareUncondBranch: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - B(offset); - break; - case Branch::kBareCondBranch: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - EmitBcondR2(condition, lhs, rhs, offset); - break; - case Branch::kBareCall: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Bal(offset); - break; - - // R2 near label. - case Branch::kLabel: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Addiu(lhs, GetR2PcRelBaseRegister(rhs), offset); - break; - // R2 near literal. - case Branch::kLiteral: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Lw(lhs, GetR2PcRelBaseRegister(rhs), offset); - break; - - // R2 long branches. - case Branch::kLongUncondBranch: - // To get the value of the PC register we need to use the NAL instruction. - // NAL clobbers the RA register. However, RA must be preserved if the - // method is compiled without the entry/exit sequences that would take care - // of preserving RA (typically, leaf methods don't preserve RA explicitly). - // So, we need to preserve RA in some temporary storage ourselves. The AT - // register can't be used for this because we need it to load a constant - // which will be added to the value that NAL stores in RA. And we can't - // use T9 for this in the context of the JNI compiler, which uses it - // as a scratch register (see InterproceduralScratchRegister()). - // If we were to add a 32-bit constant to RA using two ADDIU instructions, - // we'd also need to use the ROTR instruction, which requires no less than - // MIPSR2. - // Perhaps, we could use T8 or one of R2's multiplier/divider registers - // (LO or HI) or even a floating-point register, but that doesn't seem - // like a nice solution. We may want this to work on both R6 and pre-R6. - // For now simply use the stack for RA. This should be OK since for the - // vast majority of code a short PC-relative branch is sufficient. - // TODO: can this be improved? - // TODO: consider generation of a shorter sequence when we know that RA - // is explicitly preserved by the method entry/exit code. - if (delayed_instruction != Branch::kUnfilledDelaySlot && - delayed_instruction != Branch::kUnfillableDelaySlot) { - Emit(delayed_instruction); - } - Push(RA); - Nal(); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Lui(AT, High16Bits(offset)); - Ori(AT, AT, Low16Bits(offset)); - Addu(AT, AT, RA); - Lw(RA, SP, 0); - Jr(AT); - DecreaseFrameSize(kStackAlignment); - break; - case Branch::kLongCondBranch: - // The comment on case 'Branch::kLongUncondBranch' applies here as well. - DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); - if (delayed_instruction != Branch::kUnfilledDelaySlot) { - Emit(delayed_instruction); - } - // Note: the opposite condition branch encodes 8 as the distance, which is equal to the - // number of instructions skipped: - // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR). - EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8); - Push(RA); - Nal(); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Lui(AT, High16Bits(offset)); - Ori(AT, AT, Low16Bits(offset)); - Addu(AT, AT, RA); - Lw(RA, SP, 0); - Jr(AT); - DecreaseFrameSize(kStackAlignment); - break; - case Branch::kLongCall: - DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); - if (delayed_instruction != Branch::kUnfilledDelaySlot) { - Emit(delayed_instruction); - } - Nal(); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Lui(AT, High16Bits(offset)); - Ori(AT, AT, Low16Bits(offset)); - Addu(AT, AT, RA); - Jalr(AT); - Nop(); - break; - - // R2 far label. - case Branch::kFarLabel: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Lui(AT, High16Bits(offset)); - Ori(AT, AT, Low16Bits(offset)); - Addu(lhs, AT, GetR2PcRelBaseRegister(rhs)); - break; - // R2 far literal. - case Branch::kFarLiteral: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - offset += (offset & 0x8000) << 1; // Account for sign extension in lw. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Lui(AT, High16Bits(offset)); - Addu(AT, AT, GetR2PcRelBaseRegister(rhs)); - Lw(lhs, AT, Low16Bits(offset)); - break; - - // R6 short branches. - case Branch::kR6UncondBranch: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Bc(offset); - break; - case Branch::kR6CondBranch: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - EmitBcondR6(condition, lhs, rhs, offset); - DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); - if (delayed_instruction != Branch::kUnfilledDelaySlot) { - Emit(delayed_instruction); - } else { - // TODO: improve by filling the forbidden slot (IFF this is - // a forbidden and not a delay slot). - Nop(); - } - break; - case Branch::kR6Call: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Balc(offset); - break; - case Branch::kR6BareUncondBranch: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Bc(offset); - break; - case Branch::kR6BareCondBranch: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - EmitBcondR6(condition, lhs, rhs, offset); - break; - case Branch::kR6BareCall: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Balc(offset); - break; - - // R6 near label. - case Branch::kR6Label: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Addiupc(lhs, offset); - break; - // R6 near literal. - case Branch::kR6Literal: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Lwpc(lhs, offset); - break; - - // R6 long branches. - case Branch::kR6LongUncondBranch: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - offset += (offset & 0x8000) << 1; // Account for sign extension in jic. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Jic(AT, Low16Bits(offset)); - break; - case Branch::kR6LongCondBranch: - DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); - if (delayed_instruction != Branch::kUnfilledDelaySlot) { - Emit(delayed_instruction); - } - EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2); - offset += (offset & 0x8000) << 1; // Account for sign extension in jic. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Jic(AT, Low16Bits(offset)); - break; - case Branch::kR6LongCall: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - offset += (offset & 0x8000) << 1; // Account for sign extension in jialc. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Jialc(AT, Low16Bits(offset)); - break; - - // R6 far label. - case Branch::kR6FarLabel: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - offset += (offset & 0x8000) << 1; // Account for sign extension in addiu. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Addiu(lhs, AT, Low16Bits(offset)); - break; - // R6 far literal. - case Branch::kR6FarLiteral: - DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); - offset += (offset & 0x8000) << 1; // Account for sign extension in lw. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Lw(lhs, AT, Low16Bits(offset)); - break; - } - CHECK_EQ(overwrite_location_, branch->GetEndLocation()); - CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize)); - if (patcher_label != nullptr) { - // The patched instruction should look like one. - uint32_t patched_instruction = buffer_.Load<uint32_t>(GetLabelLocation(patcher_label)); - CHECK(!IsAbsorbableInstruction(patched_instruction)); - } -} - -void MipsAssembler::B(MipsLabel* label, bool is_bare) { - Buncond(label, /* is_r6= */ (IsR6() && !is_bare), is_bare); -} - -void MipsAssembler::Bal(MipsLabel* label, bool is_bare) { - Call(label, /* is_r6= */ (IsR6() && !is_bare), is_bare); -} - -void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ (IsR6() && !is_bare), is_bare, kCondEQ, rs, rt); -} - -void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ (IsR6() && !is_bare), is_bare, kCondNE, rs, rt); -} - -void MipsAssembler::Beqz(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ (IsR6() && !is_bare), is_bare, kCondEQZ, rt); -} - -void MipsAssembler::Bnez(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ (IsR6() && !is_bare), is_bare, kCondNEZ, rt); -} - -void MipsAssembler::Bltz(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ (IsR6() && !is_bare), is_bare, kCondLTZ, rt); -} - -void MipsAssembler::Bgez(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ (IsR6() && !is_bare), is_bare, kCondGEZ, rt); -} - -void MipsAssembler::Blez(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ (IsR6() && !is_bare), is_bare, kCondLEZ, rt); -} - -void MipsAssembler::Bgtz(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ (IsR6() && !is_bare), is_bare, kCondGTZ, rt); -} - -bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const { - // If the instruction modifies AT, `rs` or `rt`, it can't be exchanged with the slt[u] - // instruction because either slt[u] depends on `rs` or `rt` or the following - // conditional branch depends on AT set by slt[u]. - // Likewise, if the instruction depends on AT, it can't be exchanged with slt[u] - // because slt[u] changes AT. - return (delay_slot_.instruction_ != 0 && - (delay_slot_.masks_.gpr_outs_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 && - (delay_slot_.masks_.gpr_ins_ & (1u << AT)) == 0); -} - -void MipsAssembler::ExchangeWithSlt(const DelaySlot& forwarded_slot) { - // Exchange the last two instructions in the assembler buffer. - size_t size = buffer_.Size(); - CHECK_GE(size, 2 * sizeof(uint32_t)); - size_t pos1 = size - 2 * sizeof(uint32_t); - size_t pos2 = size - sizeof(uint32_t); - uint32_t instr1 = buffer_.Load<uint32_t>(pos1); - uint32_t instr2 = buffer_.Load<uint32_t>(pos2); - CHECK_EQ(instr1, forwarded_slot.instruction_); - CHECK_EQ(instr2, delay_slot_.instruction_); - buffer_.Store<uint32_t>(pos1, instr2); - buffer_.Store<uint32_t>(pos2, instr1); - // Set the current delay slot information to that of the last instruction - // in the buffer. - delay_slot_ = forwarded_slot; -} - -void MipsAssembler::GenerateSltForCondBranch(bool unsigned_slt, Register rs, Register rt) { - // If possible, exchange the slt[u] instruction with the preceding instruction, - // so it can fill the delay slot. - DelaySlot forwarded_slot = delay_slot_; - bool exchange = CanExchangeWithSlt(rs, rt); - if (exchange) { - // The last instruction cannot be used in a different delay slot, - // do not commit the label before it (if any). - DsFsmDropLabel(); - } - if (unsigned_slt) { - Sltu(AT, rs, rt); - } else { - Slt(AT, rs, rt); - } - if (exchange) { - ExchangeWithSlt(forwarded_slot); - } -} - -void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label, bool is_bare) { - if (IsR6() && !is_bare) { - Bcond(label, IsR6(), is_bare, kCondLT, rs, rt); - } else if (!Branch::IsNop(kCondLT, rs, rt)) { - // Synthesize the instruction (not available on R2). - GenerateSltForCondBranch(/* unsigned_slt= */ false, rs, rt); - Bnez(AT, label, is_bare); - } -} - -void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label, bool is_bare) { - if (IsR6() && !is_bare) { - Bcond(label, IsR6(), is_bare, kCondGE, rs, rt); - } else if (Branch::IsUncond(kCondGE, rs, rt)) { - B(label, is_bare); - } else { - // Synthesize the instruction (not available on R2). - GenerateSltForCondBranch(/* unsigned_slt= */ false, rs, rt); - Beqz(AT, label, is_bare); - } -} - -void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label, bool is_bare) { - if (IsR6() && !is_bare) { - Bcond(label, IsR6(), is_bare, kCondLTU, rs, rt); - } else if (!Branch::IsNop(kCondLTU, rs, rt)) { - // Synthesize the instruction (not available on R2). - GenerateSltForCondBranch(/* unsigned_slt= */ true, rs, rt); - Bnez(AT, label, is_bare); - } -} - -void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label, bool is_bare) { - if (IsR6() && !is_bare) { - Bcond(label, IsR6(), is_bare, kCondGEU, rs, rt); - } else if (Branch::IsUncond(kCondGEU, rs, rt)) { - B(label, is_bare); - } else { - // Synthesize the instruction (not available on R2). - GenerateSltForCondBranch(/* unsigned_slt= */ true, rs, rt); - Beqz(AT, label, is_bare); - } -} - -void MipsAssembler::Bc1f(MipsLabel* label, bool is_bare) { - Bc1f(0, label, is_bare); -} - -void MipsAssembler::Bc1f(int cc, MipsLabel* label, bool is_bare) { - CHECK(IsUint<3>(cc)) << cc; - Bcond(label, /* is_r6= */ false, is_bare, kCondF, static_cast<Register>(cc), ZERO); -} - -void MipsAssembler::Bc1t(MipsLabel* label, bool is_bare) { - Bc1t(0, label, is_bare); -} - -void MipsAssembler::Bc1t(int cc, MipsLabel* label, bool is_bare) { - CHECK(IsUint<3>(cc)) << cc; - Bcond(label, /* is_r6= */ false, is_bare, kCondT, static_cast<Register>(cc), ZERO); -} - -void MipsAssembler::Bc(MipsLabel* label, bool is_bare) { - Buncond(label, /* is_r6= */ true, is_bare); -} - -void MipsAssembler::Balc(MipsLabel* label, bool is_bare) { - Call(label, /* is_r6= */ true, is_bare); -} - -void MipsAssembler::Beqc(Register rs, Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondEQ, rs, rt); -} - -void MipsAssembler::Bnec(Register rs, Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondNE, rs, rt); -} - -void MipsAssembler::Beqzc(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondEQZ, rt); -} - -void MipsAssembler::Bnezc(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondNEZ, rt); -} - -void MipsAssembler::Bltzc(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondLTZ, rt); -} - -void MipsAssembler::Bgezc(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondGEZ, rt); -} - -void MipsAssembler::Blezc(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondLEZ, rt); -} - -void MipsAssembler::Bgtzc(Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondGTZ, rt); -} - -void MipsAssembler::Bltc(Register rs, Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondLT, rs, rt); -} - -void MipsAssembler::Bgec(Register rs, Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondGE, rs, rt); -} - -void MipsAssembler::Bltuc(Register rs, Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondLTU, rs, rt); -} - -void MipsAssembler::Bgeuc(Register rs, Register rt, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondGEU, rs, rt); -} - -void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondF, static_cast<Register>(ft), ZERO); -} - -void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondT, static_cast<Register>(ft), ZERO); -} - -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::AdjustBaseOffsetAndElementSizeShift(Register& base, - int32_t& offset, - int& element_size_shift) { - // This method is used to adjust the base register, offset and element_size_shift - // for a vector load/store when the offset doesn't fit into allowed number of bits. - // MSA ld.df and st.df instructions take signed offsets as arguments, but maximum - // offset is dependant on the size of the data format df (10-bit offsets for ld.b, - // 11-bit for ld.h, 12-bit for ld.w and 13-bit for ld.d). - // If element_size_shift is non-negative at entry, it won't be changed, but offset - // will be checked for appropriate alignment. If negative at entry, it will be - // adjusted based on offset for maximum fit. - // It's assumed that `base` is a multiple of 8. - CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`. - - if (element_size_shift >= 0) { - CHECK_LE(element_size_shift, TIMES_8); - CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift); - } else if (IsAligned<kMipsDoublewordSize>(offset)) { - element_size_shift = TIMES_8; - } else if (IsAligned<kMipsWordSize>(offset)) { - element_size_shift = TIMES_4; - } else if (IsAligned<kMipsHalfwordSize>(offset)) { - element_size_shift = TIMES_2; - } else { - element_size_shift = TIMES_1; - } - - const int low_len = 10 + element_size_shift; // How many low bits of `offset` ld.df/st.df - // will take. - int16_t low = offset & ((1 << low_len) - 1); // Isolate these bits. - low -= (low & (1 << (low_len - 1))) << 1; // Sign-extend these bits. - if (low == offset) { - return; // `offset` fits into ld.df/st.df. - } - - // First, see if `offset` can be represented as a sum of two or three signed offsets. - // This can save an instruction or two. - - // Max int16_t that's a multiple of element size. - const int32_t kMaxDeltaForSimpleAdjustment = 0x8000 - (1 << element_size_shift); - // Max ld.df/st.df offset that's a multiple of element size. - const int32_t kMaxLoadStoreOffset = 0x1ff << element_size_shift; - const int32_t kMaxOffsetForSimpleAdjustment = kMaxDeltaForSimpleAdjustment + kMaxLoadStoreOffset; - const int32_t kMinOffsetForMediumAdjustment = 2 * kMaxDeltaForSimpleAdjustment; - const int32_t kMaxOffsetForMediumAdjustment = kMinOffsetForMediumAdjustment + kMaxLoadStoreOffset; - - if (IsInt<16>(offset)) { - Addiu(AT, base, offset); - offset = 0; - } else if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) { - Addiu(AT, base, kMaxDeltaForSimpleAdjustment); - offset -= kMaxDeltaForSimpleAdjustment; - } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) { - Addiu(AT, base, -kMaxDeltaForSimpleAdjustment); - offset += kMaxDeltaForSimpleAdjustment; - } else if (!IsR6() && 0 <= offset && offset <= kMaxOffsetForMediumAdjustment) { - Addiu(AT, base, kMaxDeltaForSimpleAdjustment); - if (offset <= kMinOffsetForMediumAdjustment) { - Addiu(AT, AT, offset - kMaxDeltaForSimpleAdjustment); - offset = 0; - } else { - Addiu(AT, AT, kMaxDeltaForSimpleAdjustment); - offset -= kMinOffsetForMediumAdjustment; - } - } else if (!IsR6() && -kMaxOffsetForMediumAdjustment <= offset && offset < 0) { - Addiu(AT, base, -kMaxDeltaForSimpleAdjustment); - if (-kMinOffsetForMediumAdjustment <= offset) { - Addiu(AT, AT, offset + kMaxDeltaForSimpleAdjustment); - offset = 0; - } else { - Addiu(AT, AT, -kMaxDeltaForSimpleAdjustment); - offset += kMinOffsetForMediumAdjustment; - } - } else { - // 16-bit or smaller parts of `offset`: - // |31 hi 16|15 mid 13-10|12-9 low 0| - // - // Instructions that supply each part as a signed integer addend: - // |aui |addiu |ld.df/st.df | - uint32_t tmp = static_cast<uint32_t>(offset) - low; // Exclude `low` from the rest of `offset` - // (accounts for sign of `low`). - tmp += (tmp & (UINT32_C(1) << 15)) << 1; // Account for sign extension in addiu. - int16_t mid = Low16Bits(tmp); - int16_t hi = High16Bits(tmp); - if (IsR6()) { - Aui(AT, base, hi); - } else { - Lui(AT, hi); - Addu(AT, AT, base); - } - if (mid != 0) { - Addiu(AT, AT, mid); - } - offset = low; - } - base = AT; - CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift); - CHECK(IsInt<10>(offset >> element_size_shift)); -} - -void MipsAssembler::LoadFromOffset(LoadOperandType type, - Register reg, - Register base, - int32_t offset) { - LoadFromOffset<>(type, reg, base, offset); -} - -void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) { - LoadSFromOffset<>(reg, base, offset); -} - -void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) { - LoadDFromOffset<>(reg, base, offset); -} - -void MipsAssembler::LoadQFromOffset(FRegister reg, Register base, int32_t offset) { - LoadQFromOffset<>(reg, base, offset); -} - -void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, - size_t size) { - MipsManagedRegister dst = m_dst.AsMips(); - if (dst.IsNoRegister()) { - CHECK_EQ(0u, size) << dst; - } else if (dst.IsCoreRegister()) { - CHECK_EQ(kMipsWordSize, size) << dst; - LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset); - } else if (dst.IsRegisterPair()) { - CHECK_EQ(kMipsDoublewordSize, size) << dst; - LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset); - } else if (dst.IsFRegister()) { - if (size == kMipsWordSize) { - LoadSFromOffset(dst.AsFRegister(), src_register, src_offset); - } else { - CHECK_EQ(kMipsDoublewordSize, size) << dst; - LoadDFromOffset(dst.AsFRegister(), src_register, src_offset); - } - } else if (dst.IsDRegister()) { - CHECK_EQ(kMipsDoublewordSize, size) << dst; - LoadDFromOffset(dst.AsOverlappingDRegisterLow(), src_register, src_offset); - } -} - -void MipsAssembler::StoreToOffset(StoreOperandType type, - Register reg, - Register base, - int32_t offset) { - StoreToOffset<>(type, reg, base, offset); -} - -void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) { - StoreSToOffset<>(reg, base, offset); -} - -void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) { - StoreDToOffset<>(reg, base, offset); -} - -void MipsAssembler::StoreQToOffset(FRegister reg, Register base, int32_t offset) { - StoreQToOffset<>(reg, base, offset); -} - -static dwarf::Reg DWARFReg(Register reg) { - return dwarf::Reg::MipsCore(static_cast<int>(reg)); -} - -constexpr size_t kFramePointerSize = 4; - -void MipsAssembler::BuildFrame(size_t frame_size, - ManagedRegister method_reg, - ArrayRef<const ManagedRegister> callee_save_regs, - const ManagedRegisterEntrySpills& entry_spills) { - CHECK_ALIGNED(frame_size, kStackAlignment); - DCHECK(!overwriting_); - - // Increase frame to required size. - IncreaseFrameSize(frame_size); - - // Push callee saves and return address. - int stack_offset = frame_size - kFramePointerSize; - StoreToOffset(kStoreWord, RA, SP, stack_offset); - cfi_.RelOffset(DWARFReg(RA), stack_offset); - for (int i = callee_save_regs.size() - 1; i >= 0; --i) { - stack_offset -= kFramePointerSize; - Register reg = callee_save_regs[i].AsMips().AsCoreRegister(); - StoreToOffset(kStoreWord, reg, SP, stack_offset); - cfi_.RelOffset(DWARFReg(reg), stack_offset); - } - - // Write out Method*. - StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0); - - // Write out entry spills. - int32_t offset = frame_size + kFramePointerSize; - for (const ManagedRegisterSpill& spill : entry_spills) { - MipsManagedRegister reg = spill.AsMips(); - if (reg.IsNoRegister()) { - offset += spill.getSize(); - } else if (reg.IsCoreRegister()) { - StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset); - offset += kMipsWordSize; - } else if (reg.IsFRegister()) { - StoreSToOffset(reg.AsFRegister(), SP, offset); - offset += kMipsWordSize; - } else if (reg.IsDRegister()) { - StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset); - offset += kMipsDoublewordSize; - } - } -} - -void MipsAssembler::RemoveFrame(size_t frame_size, - ArrayRef<const ManagedRegister> callee_save_regs, - bool may_suspend ATTRIBUTE_UNUSED) { - CHECK_ALIGNED(frame_size, kStackAlignment); - DCHECK(!overwriting_); - cfi_.RememberState(); - - // Pop callee saves and return address. - int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; - for (size_t i = 0; i < callee_save_regs.size(); ++i) { - Register reg = callee_save_regs[i].AsMips().AsCoreRegister(); - LoadFromOffset(kLoadWord, reg, SP, stack_offset); - cfi_.Restore(DWARFReg(reg)); - stack_offset += kFramePointerSize; - } - LoadFromOffset(kLoadWord, RA, SP, stack_offset); - cfi_.Restore(DWARFReg(RA)); - - // Adjust the stack pointer in the delay slot if doing so doesn't break CFI. - bool exchange = IsInt<16>(static_cast<int32_t>(frame_size)); - bool reordering = SetReorder(false); - if (exchange) { - // Jump to the return address. - Jr(RA); - // Decrease frame to required size. - DecreaseFrameSize(frame_size); // Single instruction in delay slot. - } else { - // Decrease frame to required size. - DecreaseFrameSize(frame_size); - // Jump to the return address. - Jr(RA); - Nop(); // In delay slot. - } - SetReorder(reordering); - - // The CFI should be restored for any code that follows the exit block. - cfi_.RestoreState(); - cfi_.DefCFAOffset(frame_size); -} - -void MipsAssembler::IncreaseFrameSize(size_t adjust) { - CHECK_ALIGNED(adjust, kFramePointerSize); - Addiu32(SP, SP, -adjust); - cfi_.AdjustCFAOffset(adjust); - if (overwriting_) { - cfi_.OverrideDelayedPC(overwrite_location_); - } -} - -void MipsAssembler::DecreaseFrameSize(size_t adjust) { - CHECK_ALIGNED(adjust, kFramePointerSize); - Addiu32(SP, SP, adjust); - cfi_.AdjustCFAOffset(-adjust); - if (overwriting_) { - cfi_.OverrideDelayedPC(overwrite_location_); - } -} - -void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { - MipsManagedRegister src = msrc.AsMips(); - if (src.IsNoRegister()) { - CHECK_EQ(0u, size); - } else if (src.IsCoreRegister()) { - CHECK_EQ(kMipsWordSize, size); - StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); - } else if (src.IsRegisterPair()) { - CHECK_EQ(kMipsDoublewordSize, size); - StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value()); - StoreToOffset(kStoreWord, src.AsRegisterPairHigh(), - SP, dest.Int32Value() + kMipsWordSize); - } else if (src.IsFRegister()) { - if (size == kMipsWordSize) { - StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value()); - } else { - CHECK_EQ(kMipsDoublewordSize, size); - StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value()); - } - } else if (src.IsDRegister()) { - CHECK_EQ(kMipsDoublewordSize, size); - StoreDToOffset(src.AsOverlappingDRegisterLow(), SP, dest.Int32Value()); - } -} - -void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { - MipsManagedRegister src = msrc.AsMips(); - CHECK(src.IsCoreRegister()); - StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); -} - -void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { - MipsManagedRegister src = msrc.AsMips(); - CHECK(src.IsCoreRegister()); - StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); -} - -void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, - ManagedRegister mscratch) { - MipsManagedRegister scratch = mscratch.AsMips(); - CHECK(scratch.IsCoreRegister()) << scratch; - LoadConst32(scratch.AsCoreRegister(), imm); - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); -} - -void MipsAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs, - FrameOffset fr_offs, - ManagedRegister mscratch) { - MipsManagedRegister scratch = mscratch.AsMips(); - CHECK(scratch.IsCoreRegister()) << scratch; - Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value()); - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), - S1, thr_offs.Int32Value()); -} - -void MipsAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) { - StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value()); -} - -void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc, - FrameOffset in_off, ManagedRegister mscratch) { - MipsManagedRegister src = msrc.AsMips(); - MipsManagedRegister scratch = mscratch.AsMips(); - StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value()); - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); -} - -void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { - return EmitLoad(mdest, SP, src.Int32Value(), size); -} - -void MipsAssembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) { - return EmitLoad(mdest, S1, src.Int32Value(), size); -} - -void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) { - MipsManagedRegister dest = mdest.AsMips(); - CHECK(dest.IsCoreRegister()); - LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value()); -} - -void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, - bool unpoison_reference) { - MipsManagedRegister dest = mdest.AsMips(); - CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); - LoadFromOffset(kLoadWord, dest.AsCoreRegister(), - base.AsMips().AsCoreRegister(), offs.Int32Value()); - if (unpoison_reference) { - MaybeUnpoisonHeapReference(dest.AsCoreRegister()); - } -} - -void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) { - MipsManagedRegister dest = mdest.AsMips(); - CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); - LoadFromOffset(kLoadWord, dest.AsCoreRegister(), - base.AsMips().AsCoreRegister(), offs.Int32Value()); -} - -void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) { - MipsManagedRegister dest = mdest.AsMips(); - CHECK(dest.IsCoreRegister()); - LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value()); -} - -void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) { - UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips"; -} - -void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) { - UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips"; -} - -void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) { - MipsManagedRegister dest = mdest.AsMips(); - MipsManagedRegister src = msrc.AsMips(); - if (!dest.Equals(src)) { - if (dest.IsCoreRegister()) { - CHECK(src.IsCoreRegister()) << src; - Move(dest.AsCoreRegister(), src.AsCoreRegister()); - } else if (dest.IsFRegister()) { - CHECK(src.IsFRegister()) << src; - if (size == kMipsWordSize) { - MovS(dest.AsFRegister(), src.AsFRegister()); - } else { - CHECK_EQ(kMipsDoublewordSize, size); - MovD(dest.AsFRegister(), src.AsFRegister()); - } - } else if (dest.IsDRegister()) { - CHECK(src.IsDRegister()) << src; - MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow()); - } else { - CHECK(dest.IsRegisterPair()) << dest; - CHECK(src.IsRegisterPair()) << src; - // Ensure that the first move doesn't clobber the input of the second. - if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) { - Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); - Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); - } else { - Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); - Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); - } - } - } -} - -void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) { - MipsManagedRegister scratch = mscratch.AsMips(); - CHECK(scratch.IsCoreRegister()) << scratch; - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); -} - -void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs, - ThreadOffset32 thr_offs, - ManagedRegister mscratch) { - MipsManagedRegister scratch = mscratch.AsMips(); - CHECK(scratch.IsCoreRegister()) << scratch; - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), - S1, thr_offs.Int32Value()); - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), - SP, fr_offs.Int32Value()); -} - -void MipsAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs, - FrameOffset fr_offs, - ManagedRegister mscratch) { - MipsManagedRegister scratch = mscratch.AsMips(); - CHECK(scratch.IsCoreRegister()) << scratch; - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), - SP, fr_offs.Int32Value()); - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), - S1, thr_offs.Int32Value()); -} - -void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) { - MipsManagedRegister scratch = mscratch.AsMips(); - CHECK(scratch.IsCoreRegister()) << scratch; - CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size; - if (size == kMipsWordSize) { - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); - } else if (size == kMipsDoublewordSize) { - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize); - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); - } -} - -void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, - ManagedRegister mscratch, size_t size) { - Register scratch = mscratch.AsMips().AsCoreRegister(); - CHECK_EQ(size, kMipsWordSize); - LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value()); - StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value()); -} - -void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, - ManagedRegister mscratch, size_t size) { - Register scratch = mscratch.AsMips().AsCoreRegister(); - CHECK_EQ(size, kMipsWordSize); - LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value()); - StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value()); -} - -void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, - FrameOffset src_base ATTRIBUTE_UNUSED, - Offset src_offset ATTRIBUTE_UNUSED, - ManagedRegister mscratch ATTRIBUTE_UNUSED, - size_t size ATTRIBUTE_UNUSED) { - UNIMPLEMENTED(FATAL) << "no MIPS implementation"; -} - -void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset, - ManagedRegister src, Offset src_offset, - ManagedRegister mscratch, size_t size) { - CHECK_EQ(size, kMipsWordSize); - Register scratch = mscratch.AsMips().AsCoreRegister(); - LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value()); - StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value()); -} - -void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, - Offset dest_offset ATTRIBUTE_UNUSED, - FrameOffset src ATTRIBUTE_UNUSED, - Offset src_offset ATTRIBUTE_UNUSED, - ManagedRegister mscratch ATTRIBUTE_UNUSED, - size_t size ATTRIBUTE_UNUSED) { - UNIMPLEMENTED(FATAL) << "no MIPS implementation"; -} - -void MipsAssembler::MemoryBarrier(ManagedRegister) { - // TODO: sync? - UNIMPLEMENTED(FATAL) << "no MIPS implementation"; -} - -void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, - FrameOffset handle_scope_offset, - ManagedRegister min_reg, - bool null_allowed) { - MipsManagedRegister out_reg = mout_reg.AsMips(); - MipsManagedRegister in_reg = min_reg.AsMips(); - CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg; - CHECK(out_reg.IsCoreRegister()) << out_reg; - if (null_allowed) { - MipsLabel null_arg; - // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is - // the address in the handle scope holding the reference. - // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset). - if (in_reg.IsNoRegister()) { - LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), - SP, handle_scope_offset.Int32Value()); - in_reg = out_reg; - } - if (!out_reg.Equals(in_reg)) { - LoadConst32(out_reg.AsCoreRegister(), 0); - } - Beqz(in_reg.AsCoreRegister(), &null_arg); - Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); - Bind(&null_arg); - } else { - Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); - } -} - -void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off, - FrameOffset handle_scope_offset, - ManagedRegister mscratch, - bool null_allowed) { - MipsManagedRegister scratch = mscratch.AsMips(); - CHECK(scratch.IsCoreRegister()) << scratch; - if (null_allowed) { - MipsLabel null_arg; - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); - // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is - // the address in the handle scope holding the reference. - // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset). - Beqz(scratch.AsCoreRegister(), &null_arg); - Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); - Bind(&null_arg); - } else { - Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); - } - StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value()); -} - -// Given a handle scope entry, load the associated reference. -void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, - ManagedRegister min_reg) { - MipsManagedRegister out_reg = mout_reg.AsMips(); - MipsManagedRegister in_reg = min_reg.AsMips(); - CHECK(out_reg.IsCoreRegister()) << out_reg; - CHECK(in_reg.IsCoreRegister()) << in_reg; - MipsLabel null_arg; - if (!out_reg.Equals(in_reg)) { - LoadConst32(out_reg.AsCoreRegister(), 0); - } - Beqz(in_reg.AsCoreRegister(), &null_arg); - LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), - in_reg.AsCoreRegister(), 0); - Bind(&null_arg); -} - -void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED, - bool could_be_null ATTRIBUTE_UNUSED) { - // TODO: not validating references. -} - -void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED, - bool could_be_null ATTRIBUTE_UNUSED) { - // TODO: not validating references. -} - -void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) { - MipsManagedRegister base = mbase.AsMips(); - MipsManagedRegister scratch = mscratch.AsMips(); - CHECK(base.IsCoreRegister()) << base; - CHECK(scratch.IsCoreRegister()) << scratch; - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), - base.AsCoreRegister(), offset.Int32Value()); - Jalr(scratch.AsCoreRegister()); - NopIfNoReordering(); - // TODO: place reference map on call. -} - -void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { - MipsManagedRegister scratch = mscratch.AsMips(); - CHECK(scratch.IsCoreRegister()) << scratch; - // Call *(*(SP + base) + offset) - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value()); - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), - scratch.AsCoreRegister(), offset.Int32Value()); - Jalr(scratch.AsCoreRegister()); - NopIfNoReordering(); - // TODO: place reference map on call. -} - -void MipsAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED, - ManagedRegister mscratch ATTRIBUTE_UNUSED) { - UNIMPLEMENTED(FATAL) << "no mips implementation"; -} - -void MipsAssembler::GetCurrentThread(ManagedRegister tr) { - Move(tr.AsMips().AsCoreRegister(), S1); -} - -void MipsAssembler::GetCurrentThread(FrameOffset offset, - ManagedRegister mscratch ATTRIBUTE_UNUSED) { - StoreToOffset(kStoreWord, S1, SP, offset.Int32Value()); -} - -void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) { - MipsManagedRegister scratch = mscratch.AsMips(); - exception_blocks_.emplace_back(scratch, stack_adjust); - LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), - S1, Thread::ExceptionOffset<kMipsPointerSize>().Int32Value()); - Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry()); -} - -void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) { - Bind(exception->Entry()); - if (exception->stack_adjust_ != 0) { // Fix up the frame. - DecreaseFrameSize(exception->stack_adjust_); - } - // Pass exception object as argument. - // Don't care about preserving A0 as this call won't return. - CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>(); - Move(A0, exception->scratch_.AsCoreRegister()); - // Set up call to Thread::Current()->pDeliverException. - LoadFromOffset(kLoadWord, T9, S1, - QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, pDeliverException).Int32Value()); - Jr(T9); - NopIfNoReordering(); - - // Call never returns. - Break(); -} - -} // namespace mips -} // namespace art diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h deleted file mode 100644 index a24071d694..0000000000 --- a/compiler/utils/mips/assembler_mips.h +++ /dev/null @@ -1,1826 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_ -#define ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_ - -#include <deque> -#include <utility> -#include <vector> - -#include "arch/mips/instruction_set_features_mips.h" -#include "base/arena_containers.h" -#include "base/enums.h" -#include "base/globals.h" -#include "base/macros.h" -#include "base/stl_util_identity.h" -#include "constants_mips.h" -#include "heap_poisoning.h" -#include "managed_register_mips.h" -#include "offsets.h" -#include "utils/assembler.h" -#include "utils/jni_macro_assembler.h" -#include "utils/label.h" - -namespace art { -namespace mips { - -static constexpr size_t kMipsHalfwordSize = 2; -static constexpr size_t kMipsWordSize = 4; -static constexpr size_t kMipsDoublewordSize = 8; - -enum LoadOperandType { - kLoadSignedByte, - kLoadUnsignedByte, - kLoadSignedHalfword, - kLoadUnsignedHalfword, - kLoadWord, - kLoadDoubleword, - kLoadQuadword -}; - -enum StoreOperandType { - kStoreByte, - kStoreHalfword, - kStoreWord, - kStoreDoubleword, - kStoreQuadword -}; - -// Used to test the values returned by ClassS/ClassD. -enum FPClassMaskType { - kSignalingNaN = 0x001, - kQuietNaN = 0x002, - kNegativeInfinity = 0x004, - kNegativeNormal = 0x008, - kNegativeSubnormal = 0x010, - kNegativeZero = 0x020, - kPositiveInfinity = 0x040, - kPositiveNormal = 0x080, - kPositiveSubnormal = 0x100, - kPositiveZero = 0x200, -}; - -// Instruction description in terms of input and output registers. -// Used for instruction reordering. -struct InOutRegMasks { - InOutRegMasks() - : gpr_outs_(0), gpr_ins_(0), fpr_outs_(0), fpr_ins_(0), cc_outs_(0), cc_ins_(0) {} - - inline InOutRegMasks& GprOuts(Register reg) { - gpr_outs_ |= (1u << reg); - gpr_outs_ &= ~1u; // Ignore register ZERO. - return *this; - } - template<typename T, typename... Ts> - inline InOutRegMasks& GprOuts(T one, Ts... more) { GprOuts(one); GprOuts(more...); return *this; } - - inline InOutRegMasks& GprIns(Register reg) { - gpr_ins_ |= (1u << reg); - gpr_ins_ &= ~1u; // Ignore register ZERO. - return *this; - } - template<typename T, typename... Ts> - inline InOutRegMasks& GprIns(T one, Ts... more) { GprIns(one); GprIns(more...); return *this; } - - inline InOutRegMasks& GprInOuts(Register reg) { GprIns(reg); GprOuts(reg); return *this; } - template<typename T, typename... Ts> - inline InOutRegMasks& GprInOuts(T one, Ts... more) { - GprInOuts(one); - GprInOuts(more...); - return *this; - } - - inline InOutRegMasks& FprOuts(FRegister reg) { fpr_outs_ |= (1u << reg); return *this; } - inline InOutRegMasks& FprOuts(VectorRegister reg) { return FprOuts(static_cast<FRegister>(reg)); } - template<typename T, typename... Ts> - inline InOutRegMasks& FprOuts(T one, Ts... more) { FprOuts(one); FprOuts(more...); return *this; } - - inline InOutRegMasks& FprIns(FRegister reg) { fpr_ins_ |= (1u << reg); return *this; } - inline InOutRegMasks& FprIns(VectorRegister reg) { return FprIns(static_cast<FRegister>(reg)); } - template<typename T, typename... Ts> - inline InOutRegMasks& FprIns(T one, Ts... more) { FprIns(one); FprIns(more...); return *this; } - - inline InOutRegMasks& FprInOuts(FRegister reg) { FprIns(reg); FprOuts(reg); return *this; } - inline InOutRegMasks& FprInOuts(VectorRegister reg) { - return FprInOuts(static_cast<FRegister>(reg)); - } - template<typename T, typename... Ts> - inline InOutRegMasks& FprInOuts(T one, Ts... more) { - FprInOuts(one); - FprInOuts(more...); - return *this; - } - - inline InOutRegMasks& CcOuts(int cc) { cc_outs_ |= (1u << cc); return *this; } - template<typename T, typename... Ts> - inline InOutRegMasks& CcOuts(T one, Ts... more) { CcOuts(one); CcOuts(more...); return *this; } - - inline InOutRegMasks& CcIns(int cc) { cc_ins_ |= (1u << cc); return *this; } - template<typename T, typename... Ts> - inline InOutRegMasks& CcIns(T one, Ts... more) { CcIns(one); CcIns(more...); return *this; } - - // Mask of output GPRs for the instruction. - uint32_t gpr_outs_; - // Mask of input GPRs for the instruction. - uint32_t gpr_ins_; - // Mask of output FPRs for the instruction. - uint32_t fpr_outs_; - // Mask of input FPRs for the instruction. - uint32_t fpr_ins_; - // Mask of output FPU condition code flags for the instruction. - uint32_t cc_outs_; - // Mask of input FPU condition code flags for the instruction. - uint32_t cc_ins_; - - // TODO: add LO and HI. -}; - -class MipsLabel : public Label { - public: - MipsLabel() : prev_branch_id_plus_one_(0) {} - - MipsLabel(MipsLabel&& src) - : Label(std::move(src)), prev_branch_id_plus_one_(src.prev_branch_id_plus_one_) {} - - void AdjustBoundPosition(int delta) { - CHECK(IsBound()); - // Bound label's position is negative, hence decrementing it. - position_ -= delta; - } - - private: - uint32_t prev_branch_id_plus_one_; // To get distance from preceding branch, if any. - - friend class MipsAssembler; - DISALLOW_COPY_AND_ASSIGN(MipsLabel); -}; - -// Assembler literal is a value embedded in code, retrieved using a PC-relative load. -class Literal { - public: - static constexpr size_t kMaxSize = 8; - - Literal(uint32_t size, const uint8_t* data) - : label_(), size_(size) { - DCHECK_LE(size, Literal::kMaxSize); - memcpy(data_, data, size); - } - - template <typename T> - T GetValue() const { - DCHECK_EQ(size_, sizeof(T)); - T value; - memcpy(&value, data_, sizeof(T)); - return value; - } - - uint32_t GetSize() const { - return size_; - } - - const uint8_t* GetData() const { - return data_; - } - - MipsLabel* GetLabel() { - return &label_; - } - - const MipsLabel* GetLabel() const { - return &label_; - } - - private: - MipsLabel label_; - const uint32_t size_; - uint8_t data_[kMaxSize]; - - DISALLOW_COPY_AND_ASSIGN(Literal); -}; - -// Jump table: table of labels emitted after the literals. Similar to literals. -class JumpTable { - public: - explicit JumpTable(std::vector<MipsLabel*>&& labels) - : label_(), labels_(std::move(labels)) { - } - - uint32_t GetSize() const { - return static_cast<uint32_t>(labels_.size()) * sizeof(uint32_t); - } - - const std::vector<MipsLabel*>& GetData() const { - return labels_; - } - - MipsLabel* GetLabel() { - return &label_; - } - - const MipsLabel* GetLabel() const { - return &label_; - } - - private: - MipsLabel label_; - std::vector<MipsLabel*> labels_; - - DISALLOW_COPY_AND_ASSIGN(JumpTable); -}; - -// Slowpath entered when Thread::Current()->_exception is non-null. -class MipsExceptionSlowPath { - public: - explicit MipsExceptionSlowPath(MipsManagedRegister scratch, size_t stack_adjust) - : scratch_(scratch), stack_adjust_(stack_adjust) {} - - MipsExceptionSlowPath(MipsExceptionSlowPath&& src) - : scratch_(src.scratch_), - stack_adjust_(src.stack_adjust_), - exception_entry_(std::move(src.exception_entry_)) {} - - private: - MipsLabel* Entry() { return &exception_entry_; } - const MipsManagedRegister scratch_; - const size_t stack_adjust_; - MipsLabel exception_entry_; - - friend class MipsAssembler; - DISALLOW_COPY_AND_ASSIGN(MipsExceptionSlowPath); -}; - -class MipsAssembler final : public Assembler, public JNIMacroAssembler<PointerSize::k32> { - public: - using JNIBase = JNIMacroAssembler<PointerSize::k32>; - - explicit MipsAssembler(ArenaAllocator* allocator, - const MipsInstructionSetFeatures* instruction_set_features = nullptr) - : Assembler(allocator), - overwriting_(false), - overwrite_location_(0), - reordering_(true), - ds_fsm_state_(kExpectingLabel), - ds_fsm_target_pc_(0), - literals_(allocator->Adapter(kArenaAllocAssembler)), - jump_tables_(allocator->Adapter(kArenaAllocAssembler)), - last_position_adjustment_(0), - last_old_position_(0), - last_branch_id_(0), - has_msa_(instruction_set_features != nullptr ? instruction_set_features->HasMsa() : false), - isa_features_(instruction_set_features) { - cfi().DelayEmittingAdvancePCs(); - } - - size_t CodeSize() const override { return Assembler::CodeSize(); } - size_t CodePosition() override; - DebugFrameOpCodeWriterForAssembler& cfi() override { return Assembler::cfi(); } - - virtual ~MipsAssembler() { - for (auto& branch : branches_) { - CHECK(branch.IsResolved()); - } - } - - // Emit Machine Instructions. - void Addu(Register rd, Register rs, Register rt); - void Addiu(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label); - void Addiu(Register rt, Register rs, uint16_t imm16); - void Subu(Register rd, Register rs, Register rt); - - void MultR2(Register rs, Register rt); // R2 - void MultuR2(Register rs, Register rt); // R2 - void DivR2(Register rs, Register rt); // R2 - void DivuR2(Register rs, Register rt); // R2 - void MulR2(Register rd, Register rs, Register rt); // R2 - void DivR2(Register rd, Register rs, Register rt); // R2 - void ModR2(Register rd, Register rs, Register rt); // R2 - void DivuR2(Register rd, Register rs, Register rt); // R2 - void ModuR2(Register rd, Register rs, Register rt); // R2 - void MulR6(Register rd, Register rs, Register rt); // R6 - void MuhR6(Register rd, Register rs, Register rt); // R6 - void MuhuR6(Register rd, Register rs, Register rt); // R6 - void DivR6(Register rd, Register rs, Register rt); // R6 - void ModR6(Register rd, Register rs, Register rt); // R6 - void DivuR6(Register rd, Register rs, Register rt); // R6 - void ModuR6(Register rd, Register rs, Register rt); // R6 - - void And(Register rd, Register rs, Register rt); - void Andi(Register rt, Register rs, uint16_t imm16); - void Or(Register rd, Register rs, Register rt); - void Ori(Register rt, Register rs, uint16_t imm16); - void Xor(Register rd, Register rs, Register rt); - void Xori(Register rt, Register rs, uint16_t imm16); - void Nor(Register rd, Register rs, Register rt); - - void Movz(Register rd, Register rs, Register rt); // R2 - void Movn(Register rd, Register rs, Register rt); // R2 - void Seleqz(Register rd, Register rs, Register rt); // R6 - void Selnez(Register rd, Register rs, Register rt); // R6 - void ClzR6(Register rd, Register rs); - void ClzR2(Register rd, Register rs); - void CloR6(Register rd, Register rs); - void CloR2(Register rd, Register rs); - - void Seb(Register rd, Register rt); // R2+ - void Seh(Register rd, Register rt); // R2+ - void Wsbh(Register rd, Register rt); // R2+ - void Bitswap(Register rd, Register rt); // R6 - - void Sll(Register rd, Register rt, int shamt); - void Srl(Register rd, Register rt, int shamt); - void Rotr(Register rd, Register rt, int shamt); // R2+ - void Sra(Register rd, Register rt, int shamt); - void Sllv(Register rd, Register rt, Register rs); - void Srlv(Register rd, Register rt, Register rs); - void Rotrv(Register rd, Register rt, Register rs); // R2+ - void Srav(Register rd, Register rt, Register rs); - void Ext(Register rd, Register rt, int pos, int size); // R2+ - void Ins(Register rd, Register rt, int pos, int size); // R2+ - void Lsa(Register rd, Register rs, Register rt, int saPlusOne); // R6 - void ShiftAndAdd(Register dst, Register src_idx, Register src_base, int shamt, Register tmp = AT); - - void Lb(Register rt, Register rs, uint16_t imm16); - void Lh(Register rt, Register rs, uint16_t imm16); - void Lw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label); - void Lw(Register rt, Register rs, uint16_t imm16); - void Lwl(Register rt, Register rs, uint16_t imm16); - void Lwr(Register rt, Register rs, uint16_t imm16); - void Lbu(Register rt, Register rs, uint16_t imm16); - void Lhu(Register rt, Register rs, uint16_t imm16); - void Lwpc(Register rs, uint32_t imm19); // R6 - void Lui(Register rt, uint16_t imm16); - void Aui(Register rt, Register rs, uint16_t imm16); // R6 - void AddUpper(Register rt, Register rs, uint16_t imm16, Register tmp = AT); - void Sync(uint32_t stype); - void Mfhi(Register rd); // R2 - void Mflo(Register rd); // R2 - - void Sb(Register rt, Register rs, uint16_t imm16); - void Sh(Register rt, Register rs, uint16_t imm16); - void Sw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label); - void Sw(Register rt, Register rs, uint16_t imm16); - void Swl(Register rt, Register rs, uint16_t imm16); - void Swr(Register rt, Register rs, uint16_t imm16); - - void LlR2(Register rt, Register base, int16_t imm16 = 0); - void ScR2(Register rt, Register base, int16_t imm16 = 0); - void LlR6(Register rt, Register base, int16_t imm9 = 0); - void ScR6(Register rt, Register base, int16_t imm9 = 0); - - void Slt(Register rd, Register rs, Register rt); - void Sltu(Register rd, Register rs, Register rt); - void Slti(Register rt, Register rs, uint16_t imm16); - void Sltiu(Register rt, Register rs, uint16_t imm16); - - // Branches and jumps to immediate offsets/addresses do not take care of their - // delay/forbidden slots and generally should not be used directly. This applies - // to the following R2 and R6 branch/jump instructions with imm16, imm21, addr26 - // offsets/addresses. - // Use branches/jumps to labels instead. - void B(uint16_t imm16); - void Bal(uint16_t imm16); - void Beq(Register rs, Register rt, uint16_t imm16); - void Bne(Register rs, Register rt, uint16_t imm16); - void Beqz(Register rt, uint16_t imm16); - void Bnez(Register rt, uint16_t imm16); - void Bltz(Register rt, uint16_t imm16); - void Bgez(Register rt, uint16_t imm16); - void Blez(Register rt, uint16_t imm16); - void Bgtz(Register rt, uint16_t imm16); - void Bc1f(uint16_t imm16); // R2 - void Bc1f(int cc, uint16_t imm16); // R2 - void Bc1t(uint16_t imm16); // R2 - void Bc1t(int cc, uint16_t imm16); // R2 - void J(uint32_t addr26); - void Jal(uint32_t addr26); - // Jalr() and Jr() fill their delay slots when reordering is enabled. - // When reordering is disabled, the delay slots must be filled manually. - // You may use NopIfNoReordering() to fill them when reordering is disabled. - void Jalr(Register rd, Register rs); - void Jalr(Register rs); - void Jr(Register rs); - // Nal() does not fill its delay slot. It must be filled manually. - void Nal(); - void Auipc(Register rs, uint16_t imm16); // R6 - void Addiupc(Register rs, uint32_t imm19); // R6 - void Bc(uint32_t imm26); // R6 - void Balc(uint32_t imm26); // R6 - void Jic(Register rt, uint16_t imm16); // R6 - void Jialc(Register rt, uint16_t imm16); // R6 - void Bltc(Register rs, Register rt, uint16_t imm16); // R6 - void Bltzc(Register rt, uint16_t imm16); // R6 - void Bgtzc(Register rt, uint16_t imm16); // R6 - void Bgec(Register rs, Register rt, uint16_t imm16); // R6 - void Bgezc(Register rt, uint16_t imm16); // R6 - void Blezc(Register rt, uint16_t imm16); // R6 - void Bltuc(Register rs, Register rt, uint16_t imm16); // R6 - void Bgeuc(Register rs, Register rt, uint16_t imm16); // R6 - void Beqc(Register rs, Register rt, uint16_t imm16); // R6 - void Bnec(Register rs, Register rt, uint16_t imm16); // R6 - void Beqzc(Register rs, uint32_t imm21); // R6 - void Bnezc(Register rs, uint32_t imm21); // R6 - void Bc1eqz(FRegister ft, uint16_t imm16); // R6 - void Bc1nez(FRegister ft, uint16_t imm16); // R6 - - void AddS(FRegister fd, FRegister fs, FRegister ft); - void SubS(FRegister fd, FRegister fs, FRegister ft); - void MulS(FRegister fd, FRegister fs, FRegister ft); - void DivS(FRegister fd, FRegister fs, FRegister ft); - void AddD(FRegister fd, FRegister fs, FRegister ft); - void SubD(FRegister fd, FRegister fs, FRegister ft); - void MulD(FRegister fd, FRegister fs, FRegister ft); - void DivD(FRegister fd, FRegister fs, FRegister ft); - void SqrtS(FRegister fd, FRegister fs); - void SqrtD(FRegister fd, FRegister fs); - void AbsS(FRegister fd, FRegister fs); - void AbsD(FRegister fd, FRegister fs); - void MovS(FRegister fd, FRegister fs); - void MovD(FRegister fd, FRegister fs); - void NegS(FRegister fd, FRegister fs); - void NegD(FRegister fd, FRegister fs); - - void CunS(FRegister fs, FRegister ft); // R2 - void CunS(int cc, FRegister fs, FRegister ft); // R2 - void CeqS(FRegister fs, FRegister ft); // R2 - void CeqS(int cc, FRegister fs, FRegister ft); // R2 - void CueqS(FRegister fs, FRegister ft); // R2 - void CueqS(int cc, FRegister fs, FRegister ft); // R2 - void ColtS(FRegister fs, FRegister ft); // R2 - void ColtS(int cc, FRegister fs, FRegister ft); // R2 - void CultS(FRegister fs, FRegister ft); // R2 - void CultS(int cc, FRegister fs, FRegister ft); // R2 - void ColeS(FRegister fs, FRegister ft); // R2 - void ColeS(int cc, FRegister fs, FRegister ft); // R2 - void CuleS(FRegister fs, FRegister ft); // R2 - void CuleS(int cc, FRegister fs, FRegister ft); // R2 - void CunD(FRegister fs, FRegister ft); // R2 - void CunD(int cc, FRegister fs, FRegister ft); // R2 - void CeqD(FRegister fs, FRegister ft); // R2 - void CeqD(int cc, FRegister fs, FRegister ft); // R2 - void CueqD(FRegister fs, FRegister ft); // R2 - void CueqD(int cc, FRegister fs, FRegister ft); // R2 - void ColtD(FRegister fs, FRegister ft); // R2 - void ColtD(int cc, FRegister fs, FRegister ft); // R2 - void CultD(FRegister fs, FRegister ft); // R2 - void CultD(int cc, FRegister fs, FRegister ft); // R2 - void ColeD(FRegister fs, FRegister ft); // R2 - void ColeD(int cc, FRegister fs, FRegister ft); // R2 - void CuleD(FRegister fs, FRegister ft); // R2 - void CuleD(int cc, FRegister fs, FRegister ft); // R2 - void CmpUnS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpEqS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpUeqS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpLtS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpUltS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpLeS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpUleS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpOrS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpUneS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpNeS(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpUnD(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpEqD(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpUeqD(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpLtD(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpUltD(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpLeD(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpUleD(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpOrD(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpUneD(FRegister fd, FRegister fs, FRegister ft); // R6 - void CmpNeD(FRegister fd, FRegister fs, FRegister ft); // R6 - void Movf(Register rd, Register rs, int cc = 0); // R2 - void Movt(Register rd, Register rs, int cc = 0); // R2 - void MovfS(FRegister fd, FRegister fs, int cc = 0); // R2 - void MovfD(FRegister fd, FRegister fs, int cc = 0); // R2 - void MovtS(FRegister fd, FRegister fs, int cc = 0); // R2 - void MovtD(FRegister fd, FRegister fs, int cc = 0); // R2 - void MovzS(FRegister fd, FRegister fs, Register rt); // R2 - void MovzD(FRegister fd, FRegister fs, Register rt); // R2 - void MovnS(FRegister fd, FRegister fs, Register rt); // R2 - void MovnD(FRegister fd, FRegister fs, Register rt); // R2 - void SelS(FRegister fd, FRegister fs, FRegister ft); // R6 - void SelD(FRegister fd, FRegister fs, FRegister ft); // R6 - void SeleqzS(FRegister fd, FRegister fs, FRegister ft); // R6 - void SeleqzD(FRegister fd, FRegister fs, FRegister ft); // R6 - void SelnezS(FRegister fd, FRegister fs, FRegister ft); // R6 - void SelnezD(FRegister fd, FRegister fs, FRegister ft); // R6 - void ClassS(FRegister fd, FRegister fs); // R6 - void ClassD(FRegister fd, FRegister fs); // R6 - void MinS(FRegister fd, FRegister fs, FRegister ft); // R6 - void MinD(FRegister fd, FRegister fs, FRegister ft); // R6 - void MaxS(FRegister fd, FRegister fs, FRegister ft); // R6 - void MaxD(FRegister fd, FRegister fs, FRegister ft); // R6 - - void TruncLS(FRegister fd, FRegister fs); // R2+, FR=1 - void TruncLD(FRegister fd, FRegister fs); // R2+, FR=1 - void TruncWS(FRegister fd, FRegister fs); - void TruncWD(FRegister fd, FRegister fs); - void Cvtsw(FRegister fd, FRegister fs); - void Cvtdw(FRegister fd, FRegister fs); - void Cvtsd(FRegister fd, FRegister fs); - void Cvtds(FRegister fd, FRegister fs); - void Cvtsl(FRegister fd, FRegister fs); // R2+, FR=1 - void Cvtdl(FRegister fd, FRegister fs); // R2+, FR=1 - void FloorWS(FRegister fd, FRegister fs); - void FloorWD(FRegister fd, FRegister fs); - - // Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs - // when loading the value as 32-bit halves. This applies to all 32-bit FPR loads: - // Mtc1(), Mthc1(), MoveToFpuHigh(), Lwc1(). Even if you need two Mtc1()'s or two - // Lwc1()'s to load a pair of 32-bit FPRs and these loads do not interfere with one - // another (unlike Mtc1() and Mthc1() with 64-bit FPRs), maintain the order: - // low then high. - // - // Also, prefer MoveFromFpuHigh()/MoveToFpuHigh() over Mfhc1()/Mthc1() and Mfc1()/Mtc1(). - // This will save you some if statements. - FRegister GetFpuRegLow(FRegister reg); - void Mfc1(Register rt, FRegister fs); - void Mtc1(Register rt, FRegister fs); - void Mfhc1(Register rt, FRegister fs); - void Mthc1(Register rt, FRegister fs); - void MoveFromFpuHigh(Register rt, FRegister fs); - void MoveToFpuHigh(Register rt, FRegister fs); - void Lwc1(FRegister ft, Register rs, uint16_t imm16); - void Ldc1(FRegister ft, Register rs, uint16_t imm16); - void Swc1(FRegister ft, Register rs, uint16_t imm16); - void Sdc1(FRegister ft, Register rs, uint16_t imm16); - - void Break(); - void Nop(); - void NopIfNoReordering(); - void Move(Register rd, Register rs); - void Clear(Register rd); - void Not(Register rd, Register rs); - - // MSA instructions. - void AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void Ffint_sW(VectorRegister wd, VectorRegister ws); - void Ffint_sD(VectorRegister wd, VectorRegister ws); - void Ftint_sW(VectorRegister wd, VectorRegister ws); - void Ftint_sD(VectorRegister wd, VectorRegister ws); - - void SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - // Immediate shift instructions, where shamtN denotes shift amount (must be between 0 and 2^N-1). - void SlliB(VectorRegister wd, VectorRegister ws, int shamt3); - void SlliH(VectorRegister wd, VectorRegister ws, int shamt4); - void SlliW(VectorRegister wd, VectorRegister ws, int shamt5); - void SlliD(VectorRegister wd, VectorRegister ws, int shamt6); - void SraiB(VectorRegister wd, VectorRegister ws, int shamt3); - void SraiH(VectorRegister wd, VectorRegister ws, int shamt4); - void SraiW(VectorRegister wd, VectorRegister ws, int shamt5); - void SraiD(VectorRegister wd, VectorRegister ws, int shamt6); - void SrliB(VectorRegister wd, VectorRegister ws, int shamt3); - void SrliH(VectorRegister wd, VectorRegister ws, int shamt4); - void SrliW(VectorRegister wd, VectorRegister ws, int shamt5); - void SrliD(VectorRegister wd, VectorRegister ws, int shamt6); - - void MoveV(VectorRegister wd, VectorRegister ws); - void SplatiB(VectorRegister wd, VectorRegister ws, int n4); - void SplatiH(VectorRegister wd, VectorRegister ws, int n3); - void SplatiW(VectorRegister wd, VectorRegister ws, int n2); - void SplatiD(VectorRegister wd, VectorRegister ws, int n1); - void Copy_sB(Register rd, VectorRegister ws, int n4); - void Copy_sH(Register rd, VectorRegister ws, int n3); - void Copy_sW(Register rd, VectorRegister ws, int n2); - void Copy_uB(Register rd, VectorRegister ws, int n4); - void Copy_uH(Register rd, VectorRegister ws, int n3); - void InsertB(VectorRegister wd, Register rs, int n4); - void InsertH(VectorRegister wd, Register rs, int n3); - void InsertW(VectorRegister wd, Register rs, int n2); - void FillB(VectorRegister wd, Register rs); - void FillH(VectorRegister wd, Register rs); - void FillW(VectorRegister wd, Register rs); - - void LdiB(VectorRegister wd, int imm8); - void LdiH(VectorRegister wd, int imm10); - void LdiW(VectorRegister wd, int imm10); - void LdiD(VectorRegister wd, int imm10); - void LdB(VectorRegister wd, Register rs, int offset); - void LdH(VectorRegister wd, Register rs, int offset); - void LdW(VectorRegister wd, Register rs, int offset); - void LdD(VectorRegister wd, Register rs, int offset); - void StB(VectorRegister wd, Register rs, int offset); - void StH(VectorRegister wd, Register rs, int offset); - void StW(VectorRegister wd, Register rs, int offset); - void StD(VectorRegister wd, Register rs, int offset); - - void IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void PcntB(VectorRegister wd, VectorRegister ws); - void PcntH(VectorRegister wd, VectorRegister ws); - void PcntW(VectorRegister wd, VectorRegister ws); - void PcntD(VectorRegister wd, VectorRegister ws); - - // Helper for replicating floating point value in all destination elements. - void ReplicateFPToVectorRegister(VectorRegister dst, FRegister src, bool is_double); - - // Higher level composite instructions. - void LoadConst32(Register rd, int32_t value); - void LoadConst64(Register reg_hi, Register reg_lo, int64_t value); - void LoadDConst64(FRegister rd, int64_t value, Register temp); - void LoadSConst32(FRegister r, int32_t value, Register temp); - void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT); - - void Bind(MipsLabel* label); - // When `is_bare` is false, the branches will promote to long (if the range - // of the individual branch instruction is insufficient) and the delay/ - // forbidden slots will be taken care of. - // Use `is_bare = false` when the branch target may be out of reach of the - // individual branch instruction. IOW, this is for general purpose use. - // - // When `is_bare` is true, just the branch instructions will be generated - // leaving delay/forbidden slot filling up to the caller and the branches - // won't promote to long if the range is insufficient (you'll get a - // compilation error when the range is exceeded). - // Use `is_bare = true` when the branch target is known to be within reach - // of the individual branch instruction. This is intended for small local - // optimizations around delay/forbidden slots. - // Also prefer using `is_bare = true` if the code near the branch is to be - // patched or analyzed at run time (e.g. introspection) to - // - show the intent and - // - fail during compilation rather than during patching/execution if the - // bare branch range is insufficent but the code size and layout are - // expected to remain unchanged - // - // R2 branches with delay slots that are also available on R6. - // On R6 when `is_bare` is false these convert to equivalent R6 compact - // branches (to reduce code size). On R2 or when `is_bare` is true they - // remain R2 branches with delay slots. - void B(MipsLabel* label, bool is_bare = false); - void Bal(MipsLabel* label, bool is_bare = false); - void Beq(Register rs, Register rt, MipsLabel* label, bool is_bare = false); - void Bne(Register rs, Register rt, MipsLabel* label, bool is_bare = false); - void Beqz(Register rt, MipsLabel* label, bool is_bare = false); - void Bnez(Register rt, MipsLabel* label, bool is_bare = false); - void Bltz(Register rt, MipsLabel* label, bool is_bare = false); - void Bgez(Register rt, MipsLabel* label, bool is_bare = false); - void Blez(Register rt, MipsLabel* label, bool is_bare = false); - void Bgtz(Register rt, MipsLabel* label, bool is_bare = false); - void Blt(Register rs, Register rt, MipsLabel* label, bool is_bare = false); - void Bge(Register rs, Register rt, MipsLabel* label, bool is_bare = false); - void Bltu(Register rs, Register rt, MipsLabel* label, bool is_bare = false); - void Bgeu(Register rs, Register rt, MipsLabel* label, bool is_bare = false); - // R2-only branches with delay slots. - void Bc1f(MipsLabel* label, bool is_bare = false); // R2 - void Bc1f(int cc, MipsLabel* label, bool is_bare = false); // R2 - void Bc1t(MipsLabel* label, bool is_bare = false); // R2 - void Bc1t(int cc, MipsLabel* label, bool is_bare = false); // R2 - // R6-only compact branches without delay/forbidden slots. - void Bc(MipsLabel* label, bool is_bare = false); // R6 - void Balc(MipsLabel* label, bool is_bare = false); // R6 - // R6-only compact branches with forbidden slots. - void Beqc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Bnec(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Beqzc(Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Bnezc(Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Bltzc(Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Bgezc(Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Blezc(Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Bgtzc(Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Bltc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Bgec(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Bltuc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6 - void Bgeuc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6 - // R6-only branches with delay slots. - void Bc1eqz(FRegister ft, MipsLabel* label, bool is_bare = false); // R6 - void Bc1nez(FRegister ft, MipsLabel* label, bool is_bare = false); // 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 AdjustBaseOffsetAndElementSizeShift(Register& base, - int32_t& offset, - int& element_size_shift); - - private: - // This will be used as an argument for loads/stores - // when there is no need for implicit null checks. - struct NoImplicitNullChecker { - void operator()() const {} - }; - - public: - template <typename ImplicitNullChecker = 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= */ (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) { - reg = ZERO; - } else { - reg = temp; - LoadConst32(reg, low); - } - 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(); - } - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void LoadFromOffset(LoadOperandType type, - Register reg, - Register base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - AdjustBaseAndOffset(base, offset, /* is_doubleword= */ (type == kLoadDoubleword)); - switch (type) { - case kLoadSignedByte: - Lb(reg, base, offset); - break; - case kLoadUnsignedByte: - Lbu(reg, base, offset); - break; - case kLoadSignedHalfword: - Lh(reg, base, offset); - break; - case kLoadUnsignedHalfword: - Lhu(reg, base, offset); - break; - case kLoadWord: - Lw(reg, base, offset); - break; - case kLoadDoubleword: - if (reg == base) { - // This will clobber the base when loading the lower register. Since we have to load the - // higher register as well, this will fail. Solution: reverse the order. - Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); - null_checker(); - Lw(reg, base, offset); - } else { - Lw(reg, base, offset); - null_checker(); - Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); - } - break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - if (type != kLoadDoubleword) { - null_checker(); - } - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void LoadSFromOffset(FRegister reg, - Register base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - AdjustBaseAndOffset(base, offset, /* is_doubleword= */ false, /* is_float= */ true); - Lwc1(reg, base, offset); - null_checker(); - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void LoadDFromOffset(FRegister reg, - Register base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - AdjustBaseAndOffset(base, offset, /* is_doubleword= */ true, /* is_float= */ true); - if (IsAligned<kMipsDoublewordSize>(offset)) { - Ldc1(reg, base, offset); - null_checker(); - } else { - if (Is32BitFPU()) { - Lwc1(reg, base, offset); - null_checker(); - Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize); - } else { - // 64-bit FPU. - Lwc1(reg, base, offset); - null_checker(); - Lw(T8, base, offset + kMipsWordSize); - Mthc1(T8, reg); - } - } - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void LoadQFromOffset(FRegister reg, - Register base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - int element_size_shift = -1; - AdjustBaseOffsetAndElementSizeShift(base, offset, element_size_shift); - switch (element_size_shift) { - case TIMES_1: LdB(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_2: LdH(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_4: LdW(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_8: LdD(static_cast<VectorRegister>(reg), base, offset); break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - null_checker(); - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void StoreToOffset(StoreOperandType type, - Register reg, - Register base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - // 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); - break; - case kStoreHalfword: - Sh(reg, base, offset); - break; - case kStoreWord: - Sw(reg, base, offset); - break; - case kStoreDoubleword: - CHECK_NE(reg, base); - CHECK_NE(static_cast<Register>(reg + 1), base); - Sw(reg, base, offset); - null_checker(); - Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); - break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - if (type != kStoreDoubleword) { - null_checker(); - } - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void StoreSToOffset(FRegister reg, - Register base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - AdjustBaseAndOffset(base, offset, /* is_doubleword= */ false, /* is_float= */ true); - Swc1(reg, base, offset); - null_checker(); - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void StoreDToOffset(FRegister reg, - Register base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - AdjustBaseAndOffset(base, offset, /* is_doubleword= */ true, /* is_float= */ true); - if (IsAligned<kMipsDoublewordSize>(offset)) { - Sdc1(reg, base, offset); - null_checker(); - } else { - if (Is32BitFPU()) { - Swc1(reg, base, offset); - null_checker(); - Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize); - } else { - // 64-bit FPU. - Mfhc1(T8, reg); - Swc1(reg, base, offset); - null_checker(); - Sw(T8, base, offset + kMipsWordSize); - } - } - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void StoreQToOffset(FRegister reg, - Register base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - int element_size_shift = -1; - AdjustBaseOffsetAndElementSizeShift(base, offset, element_size_shift); - switch (element_size_shift) { - case TIMES_1: StB(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_2: StH(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_4: StW(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_8: StD(static_cast<VectorRegister>(reg), base, offset); break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - null_checker(); - } - - 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); - void LoadQFromOffset(FRegister reg, Register base, int32_t offset); - void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset); - void StoreSToOffset(FRegister reg, Register base, int32_t offset); - void StoreDToOffset(FRegister reg, Register base, int32_t offset); - void StoreQToOffset(FRegister reg, Register base, int32_t offset); - - // Emit data (e.g. encoded instruction or immediate) to the instruction stream. - void Emit(uint32_t value); - - // Push/pop composite routines. - void Push(Register rs); - void Pop(Register rd); - void PopAndReturn(Register rd, Register rt); - - // - // Heap poisoning. - // - - // Poison a heap reference contained in `src` and store it in `dst`. - void PoisonHeapReference(Register dst, Register src) { - // dst = -src. - Subu(dst, ZERO, src); - } - // Poison a heap reference contained in `reg`. - void PoisonHeapReference(Register reg) { - // reg = -reg. - PoisonHeapReference(reg, reg); - } - // Unpoison a heap reference contained in `reg`. - void UnpoisonHeapReference(Register reg) { - // reg = -reg. - Subu(reg, ZERO, reg); - } - // Poison a heap reference contained in `reg` if heap poisoning is enabled. - void MaybePoisonHeapReference(Register reg) { - if (kPoisonHeapReferences) { - PoisonHeapReference(reg); - } - } - // Unpoison a heap reference contained in `reg` if heap poisoning is enabled. - void MaybeUnpoisonHeapReference(Register reg) { - if (kPoisonHeapReferences) { - UnpoisonHeapReference(reg); - } - } - - void Bind(Label* label) override { - Bind(down_cast<MipsLabel*>(label)); - } - void Jump(Label* label ATTRIBUTE_UNUSED) override { - UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS"; - } - - // Don't warn about a different virtual Bind/Jump in the base class. - using JNIBase::Bind; - using JNIBase::Jump; - - // Create a new label that can be used with Jump/Bind calls. - std::unique_ptr<JNIMacroLabel> CreateLabel() override { - LOG(FATAL) << "Not implemented on MIPS32"; - UNREACHABLE(); - } - // Emit an unconditional jump to the label. - void Jump(JNIMacroLabel* label ATTRIBUTE_UNUSED) override { - LOG(FATAL) << "Not implemented on MIPS32"; - UNREACHABLE(); - } - // Emit a conditional jump to the label by applying a unary condition test to the register. - void Jump(JNIMacroLabel* label ATTRIBUTE_UNUSED, - JNIMacroUnaryCondition cond ATTRIBUTE_UNUSED, - ManagedRegister test ATTRIBUTE_UNUSED) override { - LOG(FATAL) << "Not implemented on MIPS32"; - UNREACHABLE(); - } - - // Code at this offset will serve as the target for the Jump call. - void Bind(JNIMacroLabel* label ATTRIBUTE_UNUSED) override { - LOG(FATAL) << "Not implemented on MIPS32"; - UNREACHABLE(); - } - - // Create a new literal with a given value. - // NOTE: Force the template parameter to be explicitly specified. - template <typename T> - Literal* NewLiteral(typename Identity<T>::type value) { - static_assert(std::is_integral<T>::value, "T must be an integral type."); - return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value)); - } - - // Load label address using PC-relative addressing. - // To be used with data labels in the literal / jump table area only and not - // with regular code labels. - // - // For R6 base_reg must be ZERO. - // - // On R2 there are two possible uses w.r.t. base_reg: - // - // - base_reg = ZERO: - // The NAL instruction will be generated as part of the load and it will - // clobber the RA register. - // - // - base_reg != ZERO: - // The RA-clobbering NAL instruction won't be generated as part of the load. - // The label pc_rel_base_label_ must be bound (with BindPcRelBaseLabel()) - // and base_reg must hold the address of the label. Example: - // __ Nal(); - // __ Move(S3, RA); - // __ BindPcRelBaseLabel(); // S3 holds the address of pc_rel_base_label_. - // __ LoadLabelAddress(A0, S3, label1); - // __ LoadLabelAddress(A1, S3, label2); - // __ LoadLiteral(V0, S3, literal1); - // __ LoadLiteral(V1, S3, literal2); - void LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label); - - // Create a new literal with the given data. - Literal* NewLiteral(size_t size, const uint8_t* data); - - // Load literal using PC-relative addressing. - // See the above comments for LoadLabelAddress() on the value of base_reg. - void LoadLiteral(Register dest_reg, Register base_reg, Literal* literal); - - // Create a jump table for the given labels that will be emitted when finalizing. - // When the table is emitted, offsets will be relative to the location of the table. - // The table location is determined by the location of its label (the label precedes - // the table data) and should be loaded using LoadLabelAddress(). - JumpTable* CreateJumpTable(std::vector<MipsLabel*>&& labels); - - // - // Overridden common assembler high-level functionality. - // - - // Emit code that will create an activation on the stack. - void BuildFrame(size_t frame_size, - ManagedRegister method_reg, - ArrayRef<const ManagedRegister> callee_save_regs, - const ManagedRegisterEntrySpills& entry_spills) override; - - // Emit code that will remove an activation from the stack. - void RemoveFrame(size_t frame_size, - ArrayRef<const ManagedRegister> callee_save_regs, - bool may_suspend) override; - - void IncreaseFrameSize(size_t adjust) override; - void DecreaseFrameSize(size_t adjust) override; - - // Store routines. - void Store(FrameOffset offs, ManagedRegister msrc, size_t size) override; - void StoreRef(FrameOffset dest, ManagedRegister msrc) override; - void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) override; - - void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) override; - - void StoreStackOffsetToThread(ThreadOffset32 thr_offs, - FrameOffset fr_offs, - ManagedRegister mscratch) override; - - void StoreStackPointerToThread(ThreadOffset32 thr_offs) override; - - void StoreSpanning(FrameOffset dest, - ManagedRegister msrc, - FrameOffset in_off, - ManagedRegister mscratch) override; - - // Load routines. - void Load(ManagedRegister mdest, FrameOffset src, size_t size) override; - - void LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) override; - - void LoadRef(ManagedRegister dest, FrameOffset src) override; - - void LoadRef(ManagedRegister mdest, - ManagedRegister base, - MemberOffset offs, - bool unpoison_reference) override; - - void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) override; - - void LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) override; - - // Copying routines. - void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) override; - - void CopyRawPtrFromThread(FrameOffset fr_offs, - ThreadOffset32 thr_offs, - ManagedRegister mscratch) override; - - void CopyRawPtrToThread(ThreadOffset32 thr_offs, - FrameOffset fr_offs, - ManagedRegister mscratch) override; - - void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) override; - - void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) override; - - void Copy(FrameOffset dest, - ManagedRegister src_base, - Offset src_offset, - ManagedRegister mscratch, - size_t size) override; - - void Copy(ManagedRegister dest_base, - Offset dest_offset, - FrameOffset src, - ManagedRegister mscratch, - size_t size) override; - - void Copy(FrameOffset dest, - FrameOffset src_base, - Offset src_offset, - ManagedRegister mscratch, - size_t size) override; - - void Copy(ManagedRegister dest, - Offset dest_offset, - ManagedRegister src, - Offset src_offset, - ManagedRegister mscratch, - size_t size) override; - - void Copy(FrameOffset dest, - Offset dest_offset, - FrameOffset src, - Offset src_offset, - ManagedRegister mscratch, - size_t size) override; - - void MemoryBarrier(ManagedRegister) override; - - // Sign extension. - void SignExtend(ManagedRegister mreg, size_t size) override; - - // Zero extension. - void ZeroExtend(ManagedRegister mreg, size_t size) override; - - // Exploit fast access in managed code to Thread::Current(). - void GetCurrentThread(ManagedRegister tr) override; - void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) override; - - // Set up out_reg to hold a Object** into the handle scope, or to be null if the - // value is null and null_allowed. in_reg holds a possibly stale reference - // that can be used to avoid loading the handle scope entry to see if the value is - // null. - void CreateHandleScopeEntry(ManagedRegister out_reg, - FrameOffset handlescope_offset, - ManagedRegister in_reg, - bool null_allowed) override; - - // Set up out_off to hold a Object** into the handle scope, or to be null if the - // value is null and null_allowed. - void CreateHandleScopeEntry(FrameOffset out_off, - FrameOffset handlescope_offset, - ManagedRegister mscratch, - bool null_allowed) override; - - // src holds a handle scope entry (Object**) load this into dst. - void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) override; - - // Heap::VerifyObject on src. In some cases (such as a reference to this) we - // know that src may not be null. - void VerifyObject(ManagedRegister src, bool could_be_null) override; - void VerifyObject(FrameOffset src, bool could_be_null) override; - - // 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 CallFromThread(ThreadOffset32 offset, ManagedRegister mscratch) override; - - // Generate code to check if Thread::Current()->exception_ is non-null - // and branch to a ExceptionSlowPath if it is. - void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) override; - - // Emit slow paths queued during assembly and promote short branches to long if needed. - void FinalizeCode() override; - - // Emit branches and finalize all instructions. - void FinalizeInstructions(const MemoryRegion& region) override; - - // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS, - // must be used instead of MipsLabel::GetPosition()). - uint32_t GetLabelLocation(const MipsLabel* label) const; - - // Get the final position of a label after local fixup based on the old position - // recorded before FinalizeCode(). - uint32_t GetAdjustedPosition(uint32_t old_position); - - // R2 doesn't have PC-relative addressing, which we need to access literals. We simulate it by - // reading the PC value into a general-purpose register with the NAL instruction and then loading - // literals through this base register. The code generator calls this method (at most once per - // method being compiled) to bind a label to the location for which the PC value is acquired. - // The assembler then computes literal offsets relative to this label. - void BindPcRelBaseLabel(); - - // Returns the location of the label bound with BindPcRelBaseLabel(). - uint32_t GetPcRelBaseLabelLocation() const; - - // Note that PC-relative literal loads are handled as pseudo branches because they need very - // similar relocation and may similarly expand in size to accomodate for larger offsets relative - // to PC. - enum BranchCondition { - kCondLT, - kCondGE, - kCondLE, - kCondGT, - kCondLTZ, - kCondGEZ, - kCondLEZ, - kCondGTZ, - kCondEQ, - kCondNE, - kCondEQZ, - kCondNEZ, - kCondLTU, - kCondGEU, - kCondF, // Floating-point predicate false. - kCondT, // Floating-point predicate true. - kUncond, - }; - friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs); - - // Enables or disables instruction reordering (IOW, automatic filling of delay slots) - // similarly to ".set reorder" / ".set noreorder" in traditional MIPS assembly. - // Returns the last state, which may be useful for temporary enabling/disabling of - // reordering. - bool SetReorder(bool enable); - - private: - // Description of the last instruction in terms of input and output registers. - // Used to make the decision of moving the instruction into a delay slot. - struct DelaySlot { - DelaySlot(); - - // Encoded instruction that may be used to fill the delay slot or 0 - // (0 conveniently represents NOP). - uint32_t instruction_; - - // Input/output register masks. - InOutRegMasks masks_; - - // Label for patchable instructions to allow moving them into delay slots. - MipsLabel* patcher_label_; - }; - - // Delay slot finite state machine's (DS FSM's) state. The FSM state is updated - // upon every new instruction and label generated. The FSM detects instructions - // suitable for delay slots and immediately preceded with labels. These are target - // instructions for branches. If an unconditional R2 branch does not get its delay - // slot filled with the immediately preceding instruction, it may instead get the - // slot filled with the target instruction (the branch will need its offset - // incremented past the target instruction). We call this "absorption". The FSM - // records PCs of the target instructions suitable for this optimization. - enum DsFsmState { - kExpectingLabel, - kExpectingInstruction, - kExpectingCommit - }; - friend std::ostream& operator<<(std::ostream& os, const DsFsmState& rhs); - - class Branch { - public: - enum Type { - // R2 short branches (can be promoted to long). - kUncondBranch, - kCondBranch, - kCall, - // R2 short branches (can't be promoted to long), delay slots filled manually. - kBareUncondBranch, - kBareCondBranch, - kBareCall, - // R2 near label. - kLabel, - // R2 near literal. - kLiteral, - // R2 long branches. - kLongUncondBranch, - kLongCondBranch, - kLongCall, - // R2 far label. - kFarLabel, - // R2 far literal. - kFarLiteral, - // R6 short branches (can be promoted to long). - kR6UncondBranch, - kR6CondBranch, - kR6Call, - // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. - kR6BareUncondBranch, - kR6BareCondBranch, - kR6BareCall, - // R6 near label. - kR6Label, - // R6 near literal. - kR6Literal, - // R6 long branches. - kR6LongUncondBranch, - kR6LongCondBranch, - kR6LongCall, - // R6 far label. - kR6FarLabel, - // R6 far literal. - kR6FarLiteral, - }; - // Bit sizes of offsets defined as enums to minimize chance of typos. - enum OffsetBits { - kOffset16 = 16, - kOffset18 = 18, - kOffset21 = 21, - kOffset23 = 23, - kOffset28 = 28, - kOffset32 = 32, - }; - - static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_ - static constexpr int32_t kMaxBranchLength = 32; - static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t); - // The following two instruction encodings can never legally occur in branch delay - // slots and are used as markers. - // - // kUnfilledDelaySlot means that the branch may use either the preceding or the target - // instruction to fill its delay slot (the latter is only possible with unconditional - // R2 branches and is termed here as "absorption"). - static constexpr uint32_t kUnfilledDelaySlot = 0x10000000; // beq zero, zero, 0. - // kUnfillableDelaySlot means that the branch cannot use an instruction (other than NOP) - // to fill its delay slot. This is only used for unconditional R2 branches to prevent - // absorption of the target instruction when reordering is disabled. - static constexpr uint32_t kUnfillableDelaySlot = 0x13FF0000; // beq ra, ra, 0. - - struct BranchInfo { - // Branch length as a number of 4-byte-long instructions. - uint32_t length; - // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's - // PC-relative offset (or its most significant 16-bit half, which goes first). - uint32_t instr_offset; - // Different MIPS instructions with PC-relative offsets apply said offsets to slightly - // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte - // instructions) from the instruction containing the offset. - uint32_t pc_org; - // How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch - // and kR6BareCondBranch are an exception: use kOffset23 for beqzc/bnezc). - OffsetBits offset_size; - // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift - // count. - int offset_shift; - }; - static const BranchInfo branch_info_[/* Type */]; - - // Unconditional branch or call. - Branch(bool is_r6, uint32_t location, uint32_t target, bool is_call, bool is_bare); - // Conditional branch. - Branch(bool is_r6, - uint32_t location, - uint32_t target, - BranchCondition condition, - Register lhs_reg, - Register rhs_reg, - bool is_bare); - // Label address (in literal area) or literal. - Branch(bool is_r6, - uint32_t location, - Register dest_reg, - Register base_reg, - Type label_or_literal_type); - - // Some conditional branches with lhs = rhs are effectively NOPs, while some - // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs. - // So, we need a way to identify such branches in order to emit no instructions for them - // or change them to unconditional. - static bool IsNop(BranchCondition condition, Register lhs, Register rhs); - static bool IsUncond(BranchCondition condition, Register lhs, Register rhs); - - static BranchCondition OppositeCondition(BranchCondition cond); - - Type GetType() const; - BranchCondition GetCondition() const; - Register GetLeftRegister() const; - Register GetRightRegister() const; - uint32_t GetTarget() const; - uint32_t GetLocation() const; - uint32_t GetOldLocation() const; - uint32_t GetPrecedingInstructionLength(Type type) const; - uint32_t GetPrecedingInstructionSize(Type type) const; - uint32_t GetLength() const; - uint32_t GetOldLength() const; - uint32_t GetSize() const; - uint32_t GetOldSize() const; - uint32_t GetEndLocation() const; - uint32_t GetOldEndLocation() const; - bool IsBare() const; - bool IsLong() const; - bool IsResolved() const; - - // Various helpers for branch delay slot management. - bool CanHaveDelayedInstruction(const DelaySlot& delay_slot) const; - void SetDelayedInstruction(uint32_t instruction, MipsLabel* patcher_label = nullptr); - uint32_t GetDelayedInstruction() const; - MipsLabel* GetPatcherLabel() const; - void DecrementLocations(); - - // Returns the bit size of the signed offset that the branch instruction can handle. - OffsetBits GetOffsetSize() const; - - // Calculates the distance between two byte locations in the assembler buffer and - // returns the number of bits needed to represent the distance as a signed integer. - // - // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc), - // and 26 (bc) bits, which are additionally shifted left 2 positions at run time. - // - // Composite branches (made of several instructions) with longer reach have 32-bit - // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first). - // The composite branches cover the range of PC + +/-2GB on MIPS32 CPUs. However, - // the range is not end-to-end on MIPS64 (unless addresses are forced to zero- or - // sign-extend from 32 to 64 bits by the appropriate CPU configuration). - // Consider the following implementation of a long unconditional branch, for - // example: - // - // auipc at, offset_31_16 // at = pc + sign_extend(offset_31_16) << 16 - // jic at, offset_15_0 // pc = at + sign_extend(offset_15_0) - // - // Both of the above instructions take 16-bit signed offsets as immediate operands. - // When bit 15 of offset_15_0 is 1, it effectively causes subtraction of 0x10000 - // due to sign extension. This must be compensated for by incrementing offset_31_16 - // by 1. offset_31_16 can only be incremented by 1 if it's not 0x7FFF. If it is - // 0x7FFF, adding 1 will overflow the positive offset into the negative range. - // Therefore, the long branch range is something like from PC - 0x80000000 to - // PC + 0x7FFF7FFF, IOW, shorter by 32KB on one side. - // - // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special - // case with the addiu instruction and a 16 bit offset. - static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target); - - // Resolve a branch when the target is known. - void Resolve(uint32_t target); - - // Relocate a branch by a given delta if needed due to expansion of this or another - // branch at a given location by this delta (just changes location_ and target_). - void Relocate(uint32_t expand_location, uint32_t delta); - - // If the branch is short, changes its type to long. - void PromoteToLong(); - - // If necessary, updates the type by promoting a short branch to a long branch - // based on the branch location and target. Returns the amount (in bytes) by - // which the branch size has increased. - // max_short_distance caps the maximum distance between location_ and target_ - // that is allowed for short branches. This is for debugging/testing purposes. - // max_short_distance = 0 forces all short branches to become long. - // Use the implicit default argument when not debugging/testing. - uint32_t PromoteIfNeeded(uint32_t location, - uint32_t max_short_distance = std::numeric_limits<uint32_t>::max()); - - // Returns the location of the instruction(s) containing the offset. - uint32_t GetOffsetLocation() const; - - // Calculates and returns the offset ready for encoding in the branch instruction(s). - uint32_t GetOffset(uint32_t location) const; - - private: - // Completes branch construction by determining and recording its type. - void InitializeType(Type initial_type, bool is_r6); - // Helper for the above. - void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type); - - uint32_t old_location_; // Offset into assembler buffer in bytes. - uint32_t location_; // Offset into assembler buffer in bytes. - uint32_t target_; // Offset into assembler buffer in bytes. - - uint32_t lhs_reg_; // Left-hand side register in conditional branches or - // FPU condition code. Destination register in literals. - uint32_t rhs_reg_; // Right-hand side register in conditional branches. - // Base register in literals (ZERO on R6). - BranchCondition condition_; // Condition for conditional branches. - - Type type_; // Current type of the branch. - Type old_type_; // Initial type of the branch. - - uint32_t delayed_instruction_; // Encoded instruction for the delay slot or - // kUnfilledDelaySlot if none but fillable or - // kUnfillableDelaySlot if none and unfillable - // (the latter is only used for unconditional R2 - // branches). - - MipsLabel* patcher_label_; // Patcher label for the instruction in the delay slot. - }; - friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs); - friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs); - - uint32_t EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct); - uint32_t EmitI(int opcode, Register rs, Register rt, uint16_t imm); - uint32_t EmitI21(int opcode, Register rs, uint32_t imm21); - uint32_t EmitI26(int opcode, uint32_t imm26); - uint32_t EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct); - uint32_t EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm); - void EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16); - void EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21); - uint32_t EmitMsa3R(int operation, - int df, - VectorRegister wt, - VectorRegister ws, - VectorRegister wd, - int minor_opcode); - uint32_t EmitMsaBIT(int operation, - int df_m, - VectorRegister ws, - VectorRegister wd, - int minor_opcode); - uint32_t EmitMsaELM(int operation, - int df_n, - VectorRegister ws, - VectorRegister wd, - int minor_opcode); - uint32_t EmitMsaMI10(int s10, Register rs, VectorRegister wd, int minor_opcode, int df); - uint32_t EmitMsaI10(int operation, int df, int i10, VectorRegister wd, int minor_opcode); - uint32_t EmitMsa2R(int operation, int df, VectorRegister ws, VectorRegister wd, int minor_opcode); - uint32_t EmitMsa2RF(int operation, - int df, - VectorRegister ws, - VectorRegister wd, - int minor_opcode); - - void Buncond(MipsLabel* label, bool is_r6, bool is_bare); - void Bcond(MipsLabel* label, - bool is_r6, - bool is_bare, - BranchCondition condition, - Register lhs, - Register rhs = ZERO); - void Call(MipsLabel* label, bool is_r6, bool is_bare); - void FinalizeLabeledBranch(MipsLabel* label); - - // Various helpers for branch delay slot management. - InOutRegMasks& DsFsmInstr(uint32_t instruction, MipsLabel* patcher_label = nullptr); - void DsFsmInstrNop(uint32_t instruction); - void DsFsmLabel(); - void DsFsmCommitLabel(); - void DsFsmDropLabel(); - void MoveInstructionToDelaySlot(Branch& branch); - bool CanExchangeWithSlt(Register rs, Register rt) const; - void ExchangeWithSlt(const DelaySlot& forwarded_slot); - void GenerateSltForCondBranch(bool unsigned_slt, Register rs, Register rt); - - Branch* GetBranch(uint32_t branch_id); - const Branch* GetBranch(uint32_t branch_id) const; - uint32_t GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const; - uint32_t GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const; - void BindRelativeToPrecedingBranch(MipsLabel* label, - uint32_t prev_branch_id_plus_one, - uint32_t position); - - void EmitLiterals(); - void ReserveJumpTableSpace(); - void EmitJumpTables(); - void PromoteBranches(); - void EmitBranch(uint32_t branch_id); - void EmitBranches(); - void PatchCFI(size_t number_of_delayed_adjust_pcs); - - // Emits exception block. - void EmitExceptionPoll(MipsExceptionSlowPath* exception); - - bool HasMsa() const { - return has_msa_; - } - - bool IsR6() const { - if (isa_features_ != nullptr) { - return isa_features_->IsR6(); - } else { - return false; - } - } - - bool Is32BitFPU() const { - if (isa_features_ != nullptr) { - return isa_features_->Is32BitFloatingPoint(); - } else { - return true; - } - } - - // List of exception blocks to generate at the end of the code cache. - std::vector<MipsExceptionSlowPath> exception_blocks_; - - std::vector<Branch> branches_; - - // Whether appending instructions at the end of the buffer or overwriting the existing ones. - bool overwriting_; - // The current overwrite location. - uint32_t overwrite_location_; - - // Whether instruction reordering (IOW, automatic filling of delay slots) is enabled. - bool reordering_; - // Information about the last instruction that may be used to fill a branch delay slot. - DelaySlot delay_slot_; - // Delay slot FSM state. - DsFsmState ds_fsm_state_; - // PC of the current labeled target instruction. - uint32_t ds_fsm_target_pc_; - // PCs of labeled target instructions. - std::vector<uint32_t> ds_fsm_target_pcs_; - - // Use std::deque<> for literal labels to allow insertions at the end - // without invalidating pointers and references to existing elements. - ArenaDeque<Literal> literals_; - - // Jump table list. - ArenaDeque<JumpTable> jump_tables_; - - // There's no PC-relative addressing on MIPS32R2. So, in order to access literals relative to PC - // we get PC using the NAL instruction. This label marks the position within the assembler buffer - // that PC (from NAL) points to. - MipsLabel pc_rel_base_label_; - - // Data for GetAdjustedPosition(), see the description there. - uint32_t last_position_adjustment_; - uint32_t last_old_position_; - uint32_t last_branch_id_; - - const bool has_msa_; - - const MipsInstructionSetFeatures* isa_features_; - - DISALLOW_COPY_AND_ASSIGN(MipsAssembler); -}; - -} // namespace mips -} // namespace art - -#endif // ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_ diff --git a/compiler/utils/mips/assembler_mips32r5_test.cc b/compiler/utils/mips/assembler_mips32r5_test.cc deleted file mode 100644 index 98fc44ba5d..0000000000 --- a/compiler/utils/mips/assembler_mips32r5_test.cc +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "assembler_mips.h" - -#include <map> - -#include "base/stl_util.h" -#include "utils/assembler_test.h" - -#define __ GetAssembler()-> - -namespace art { - -struct MIPSCpuRegisterCompare { - bool operator()(const mips::Register& a, const mips::Register& b) const { - return a < b; - } -}; - -class AssemblerMIPS32r5Test : public AssemblerTest<mips::MipsAssembler, - mips::MipsLabel, - mips::Register, - mips::FRegister, - uint32_t, - mips::VectorRegister> { - public: - using Base = AssemblerTest<mips::MipsAssembler, - mips::MipsLabel, - mips::Register, - mips::FRegister, - uint32_t, - mips::VectorRegister>; - - // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<> - // and reimplement it without the verification against `assembly_string`. b/73903608 - void DriverStr(const std::string& assembly_string ATTRIBUTE_UNUSED, - const std::string& test_name ATTRIBUTE_UNUSED) { - GetAssembler()->FinalizeCode(); - std::vector<uint8_t> data(GetAssembler()->CodeSize()); - MemoryRegion code(data.data(), data.size()); - GetAssembler()->FinalizeInstructions(code); - } - - AssemblerMIPS32r5Test() : - instruction_set_features_(MipsInstructionSetFeatures::FromVariant("mips32r5", nullptr)) { - } - - protected: - // Get the typically used name for this architecture, e.g., aarch64, x86-64, ... - std::string GetArchitectureString() override { - return "mips"; - } - - std::string GetAssemblerParameters() override { - return " --no-warn -32 -march=mips32r5 -mmsa"; - } - - void Pad(std::vector<uint8_t>& data) override { - // The GNU linker unconditionally pads the code segment with NOPs to a size that is a multiple - // of 16 and there doesn't appear to be a way to suppress this padding. Our assembler doesn't - // pad, so, in order for two assembler outputs to match, we need to match the padding as well. - // NOP is encoded as four zero bytes on MIPS. - size_t pad_size = RoundUp(data.size(), 16u) - data.size(); - data.insert(data.end(), pad_size, 0); - } - - std::string GetDisassembleParameters() override { - return " -D -bbinary -mmips:isa32r5"; - } - - mips::MipsAssembler* CreateAssembler(ArenaAllocator* allocator) override { - return new (allocator) mips::MipsAssembler(allocator, instruction_set_features_.get()); - } - - void SetUpHelpers() override { - if (registers_.size() == 0) { - registers_.push_back(new mips::Register(mips::ZERO)); - registers_.push_back(new mips::Register(mips::AT)); - registers_.push_back(new mips::Register(mips::V0)); - registers_.push_back(new mips::Register(mips::V1)); - registers_.push_back(new mips::Register(mips::A0)); - registers_.push_back(new mips::Register(mips::A1)); - registers_.push_back(new mips::Register(mips::A2)); - registers_.push_back(new mips::Register(mips::A3)); - registers_.push_back(new mips::Register(mips::T0)); - registers_.push_back(new mips::Register(mips::T1)); - registers_.push_back(new mips::Register(mips::T2)); - registers_.push_back(new mips::Register(mips::T3)); - registers_.push_back(new mips::Register(mips::T4)); - registers_.push_back(new mips::Register(mips::T5)); - registers_.push_back(new mips::Register(mips::T6)); - registers_.push_back(new mips::Register(mips::T7)); - registers_.push_back(new mips::Register(mips::S0)); - registers_.push_back(new mips::Register(mips::S1)); - registers_.push_back(new mips::Register(mips::S2)); - registers_.push_back(new mips::Register(mips::S3)); - registers_.push_back(new mips::Register(mips::S4)); - registers_.push_back(new mips::Register(mips::S5)); - registers_.push_back(new mips::Register(mips::S6)); - registers_.push_back(new mips::Register(mips::S7)); - registers_.push_back(new mips::Register(mips::T8)); - registers_.push_back(new mips::Register(mips::T9)); - registers_.push_back(new mips::Register(mips::K0)); - registers_.push_back(new mips::Register(mips::K1)); - registers_.push_back(new mips::Register(mips::GP)); - registers_.push_back(new mips::Register(mips::SP)); - registers_.push_back(new mips::Register(mips::FP)); - registers_.push_back(new mips::Register(mips::RA)); - - secondary_register_names_.emplace(mips::Register(mips::ZERO), "zero"); - secondary_register_names_.emplace(mips::Register(mips::AT), "at"); - secondary_register_names_.emplace(mips::Register(mips::V0), "v0"); - secondary_register_names_.emplace(mips::Register(mips::V1), "v1"); - secondary_register_names_.emplace(mips::Register(mips::A0), "a0"); - secondary_register_names_.emplace(mips::Register(mips::A1), "a1"); - secondary_register_names_.emplace(mips::Register(mips::A2), "a2"); - secondary_register_names_.emplace(mips::Register(mips::A3), "a3"); - secondary_register_names_.emplace(mips::Register(mips::T0), "t0"); - secondary_register_names_.emplace(mips::Register(mips::T1), "t1"); - secondary_register_names_.emplace(mips::Register(mips::T2), "t2"); - secondary_register_names_.emplace(mips::Register(mips::T3), "t3"); - secondary_register_names_.emplace(mips::Register(mips::T4), "t4"); - secondary_register_names_.emplace(mips::Register(mips::T5), "t5"); - secondary_register_names_.emplace(mips::Register(mips::T6), "t6"); - secondary_register_names_.emplace(mips::Register(mips::T7), "t7"); - secondary_register_names_.emplace(mips::Register(mips::S0), "s0"); - secondary_register_names_.emplace(mips::Register(mips::S1), "s1"); - secondary_register_names_.emplace(mips::Register(mips::S2), "s2"); - secondary_register_names_.emplace(mips::Register(mips::S3), "s3"); - secondary_register_names_.emplace(mips::Register(mips::S4), "s4"); - secondary_register_names_.emplace(mips::Register(mips::S5), "s5"); - secondary_register_names_.emplace(mips::Register(mips::S6), "s6"); - secondary_register_names_.emplace(mips::Register(mips::S7), "s7"); - secondary_register_names_.emplace(mips::Register(mips::T8), "t8"); - secondary_register_names_.emplace(mips::Register(mips::T9), "t9"); - secondary_register_names_.emplace(mips::Register(mips::K0), "k0"); - secondary_register_names_.emplace(mips::Register(mips::K1), "k1"); - secondary_register_names_.emplace(mips::Register(mips::GP), "gp"); - secondary_register_names_.emplace(mips::Register(mips::SP), "sp"); - secondary_register_names_.emplace(mips::Register(mips::FP), "fp"); - secondary_register_names_.emplace(mips::Register(mips::RA), "ra"); - - fp_registers_.push_back(new mips::FRegister(mips::F0)); - fp_registers_.push_back(new mips::FRegister(mips::F1)); - fp_registers_.push_back(new mips::FRegister(mips::F2)); - fp_registers_.push_back(new mips::FRegister(mips::F3)); - fp_registers_.push_back(new mips::FRegister(mips::F4)); - fp_registers_.push_back(new mips::FRegister(mips::F5)); - fp_registers_.push_back(new mips::FRegister(mips::F6)); - fp_registers_.push_back(new mips::FRegister(mips::F7)); - fp_registers_.push_back(new mips::FRegister(mips::F8)); - fp_registers_.push_back(new mips::FRegister(mips::F9)); - fp_registers_.push_back(new mips::FRegister(mips::F10)); - fp_registers_.push_back(new mips::FRegister(mips::F11)); - fp_registers_.push_back(new mips::FRegister(mips::F12)); - fp_registers_.push_back(new mips::FRegister(mips::F13)); - fp_registers_.push_back(new mips::FRegister(mips::F14)); - fp_registers_.push_back(new mips::FRegister(mips::F15)); - fp_registers_.push_back(new mips::FRegister(mips::F16)); - fp_registers_.push_back(new mips::FRegister(mips::F17)); - fp_registers_.push_back(new mips::FRegister(mips::F18)); - fp_registers_.push_back(new mips::FRegister(mips::F19)); - fp_registers_.push_back(new mips::FRegister(mips::F20)); - fp_registers_.push_back(new mips::FRegister(mips::F21)); - fp_registers_.push_back(new mips::FRegister(mips::F22)); - fp_registers_.push_back(new mips::FRegister(mips::F23)); - fp_registers_.push_back(new mips::FRegister(mips::F24)); - fp_registers_.push_back(new mips::FRegister(mips::F25)); - fp_registers_.push_back(new mips::FRegister(mips::F26)); - fp_registers_.push_back(new mips::FRegister(mips::F27)); - fp_registers_.push_back(new mips::FRegister(mips::F28)); - fp_registers_.push_back(new mips::FRegister(mips::F29)); - fp_registers_.push_back(new mips::FRegister(mips::F30)); - fp_registers_.push_back(new mips::FRegister(mips::F31)); - - vec_registers_.push_back(new mips::VectorRegister(mips::W0)); - vec_registers_.push_back(new mips::VectorRegister(mips::W1)); - vec_registers_.push_back(new mips::VectorRegister(mips::W2)); - vec_registers_.push_back(new mips::VectorRegister(mips::W3)); - vec_registers_.push_back(new mips::VectorRegister(mips::W4)); - vec_registers_.push_back(new mips::VectorRegister(mips::W5)); - vec_registers_.push_back(new mips::VectorRegister(mips::W6)); - vec_registers_.push_back(new mips::VectorRegister(mips::W7)); - vec_registers_.push_back(new mips::VectorRegister(mips::W8)); - vec_registers_.push_back(new mips::VectorRegister(mips::W9)); - vec_registers_.push_back(new mips::VectorRegister(mips::W10)); - vec_registers_.push_back(new mips::VectorRegister(mips::W11)); - vec_registers_.push_back(new mips::VectorRegister(mips::W12)); - vec_registers_.push_back(new mips::VectorRegister(mips::W13)); - vec_registers_.push_back(new mips::VectorRegister(mips::W14)); - vec_registers_.push_back(new mips::VectorRegister(mips::W15)); - vec_registers_.push_back(new mips::VectorRegister(mips::W16)); - vec_registers_.push_back(new mips::VectorRegister(mips::W17)); - vec_registers_.push_back(new mips::VectorRegister(mips::W18)); - vec_registers_.push_back(new mips::VectorRegister(mips::W19)); - vec_registers_.push_back(new mips::VectorRegister(mips::W20)); - vec_registers_.push_back(new mips::VectorRegister(mips::W21)); - vec_registers_.push_back(new mips::VectorRegister(mips::W22)); - vec_registers_.push_back(new mips::VectorRegister(mips::W23)); - vec_registers_.push_back(new mips::VectorRegister(mips::W24)); - vec_registers_.push_back(new mips::VectorRegister(mips::W25)); - vec_registers_.push_back(new mips::VectorRegister(mips::W26)); - vec_registers_.push_back(new mips::VectorRegister(mips::W27)); - vec_registers_.push_back(new mips::VectorRegister(mips::W28)); - vec_registers_.push_back(new mips::VectorRegister(mips::W29)); - vec_registers_.push_back(new mips::VectorRegister(mips::W30)); - vec_registers_.push_back(new mips::VectorRegister(mips::W31)); - } - } - - void TearDown() override { - AssemblerTest::TearDown(); - STLDeleteElements(®isters_); - STLDeleteElements(&fp_registers_); - STLDeleteElements(&vec_registers_); - } - - std::vector<mips::MipsLabel> GetAddresses() override { - UNIMPLEMENTED(FATAL) << "Feature not implemented yet"; - UNREACHABLE(); - } - - std::vector<mips::Register*> GetRegisters() override { - return registers_; - } - - std::vector<mips::FRegister*> GetFPRegisters() override { - return fp_registers_; - } - - std::vector<mips::VectorRegister*> GetVectorRegisters() override { - return vec_registers_; - } - - uint32_t CreateImmediate(int64_t imm_value) override { - return imm_value; - } - - std::string GetSecondaryRegisterName(const mips::Register& reg) override { - CHECK(secondary_register_names_.find(reg) != secondary_register_names_.end()); - return secondary_register_names_[reg]; - } - - std::string RepeatInsn(size_t count, const std::string& insn) { - std::string result; - for (; count != 0u; --count) { - result += insn; - } - return result; - } - - private: - std::vector<mips::Register*> registers_; - std::map<mips::Register, std::string, MIPSCpuRegisterCompare> secondary_register_names_; - - std::vector<mips::FRegister*> fp_registers_; - std::vector<mips::VectorRegister*> vec_registers_; - std::unique_ptr<const MipsInstructionSetFeatures> instruction_set_features_; -}; - -TEST_F(AssemblerMIPS32r5Test, Toolchain) { - EXPECT_TRUE(CheckTools()); -} - -TEST_F(AssemblerMIPS32r5Test, LoadQFromOffset) { - __ LoadQFromOffset(mips::F0, mips::A0, 0); - __ LoadQFromOffset(mips::F0, mips::A0, 1); - __ LoadQFromOffset(mips::F0, mips::A0, 2); - __ LoadQFromOffset(mips::F0, mips::A0, 4); - __ LoadQFromOffset(mips::F0, mips::A0, 8); - __ LoadQFromOffset(mips::F0, mips::A0, 511); - __ LoadQFromOffset(mips::F0, mips::A0, 512); - __ LoadQFromOffset(mips::F0, mips::A0, 513); - __ LoadQFromOffset(mips::F0, mips::A0, 514); - __ LoadQFromOffset(mips::F0, mips::A0, 516); - __ LoadQFromOffset(mips::F0, mips::A0, 1022); - __ LoadQFromOffset(mips::F0, mips::A0, 1024); - __ LoadQFromOffset(mips::F0, mips::A0, 1025); - __ LoadQFromOffset(mips::F0, mips::A0, 1026); - __ LoadQFromOffset(mips::F0, mips::A0, 1028); - __ LoadQFromOffset(mips::F0, mips::A0, 2044); - __ LoadQFromOffset(mips::F0, mips::A0, 2048); - __ LoadQFromOffset(mips::F0, mips::A0, 2049); - __ LoadQFromOffset(mips::F0, mips::A0, 2050); - __ LoadQFromOffset(mips::F0, mips::A0, 2052); - __ LoadQFromOffset(mips::F0, mips::A0, 4088); - __ LoadQFromOffset(mips::F0, mips::A0, 4096); - __ LoadQFromOffset(mips::F0, mips::A0, 4097); - __ LoadQFromOffset(mips::F0, mips::A0, 4098); - __ LoadQFromOffset(mips::F0, mips::A0, 4100); - __ LoadQFromOffset(mips::F0, mips::A0, 4104); - __ LoadQFromOffset(mips::F0, mips::A0, 0x7FFC); - __ LoadQFromOffset(mips::F0, mips::A0, 0x8000); - __ LoadQFromOffset(mips::F0, mips::A0, 0x10000); - __ LoadQFromOffset(mips::F0, mips::A0, 0x12345678); - __ LoadQFromOffset(mips::F0, mips::A0, 0x12350078); - __ LoadQFromOffset(mips::F0, mips::A0, -256); - __ LoadQFromOffset(mips::F0, mips::A0, -511); - __ LoadQFromOffset(mips::F0, mips::A0, -513); - __ LoadQFromOffset(mips::F0, mips::A0, -1022); - __ LoadQFromOffset(mips::F0, mips::A0, -1026); - __ LoadQFromOffset(mips::F0, mips::A0, -2044); - __ LoadQFromOffset(mips::F0, mips::A0, -2052); - __ LoadQFromOffset(mips::F0, mips::A0, -4096); - __ LoadQFromOffset(mips::F0, mips::A0, -4104); - __ LoadQFromOffset(mips::F0, mips::A0, -32768); - __ LoadQFromOffset(mips::F0, mips::A0, -36856); - __ LoadQFromOffset(mips::F0, mips::A0, 36856); - __ LoadQFromOffset(mips::F0, mips::A0, -69608); - __ LoadQFromOffset(mips::F0, mips::A0, 69608); - __ LoadQFromOffset(mips::F0, mips::A0, 0xABCDEF00); - __ LoadQFromOffset(mips::F0, mips::A0, 0x7FFFABCD); - - const char* expected = - "ld.d $w0, 0($a0)\n" - "ld.b $w0, 1($a0)\n" - "ld.h $w0, 2($a0)\n" - "ld.w $w0, 4($a0)\n" - "ld.d $w0, 8($a0)\n" - "ld.b $w0, 511($a0)\n" - "ld.d $w0, 512($a0)\n" - "addiu $at, $a0, 513\n" - "ld.b $w0, 0($at)\n" - "ld.h $w0, 514($a0)\n" - "ld.w $w0, 516($a0)\n" - "ld.h $w0, 1022($a0)\n" - "ld.d $w0, 1024($a0)\n" - "addiu $at, $a0, 1025\n" - "ld.b $w0, 0($at)\n" - "addiu $at, $a0, 1026\n" - "ld.h $w0, 0($at)\n" - "ld.w $w0, 1028($a0)\n" - "ld.w $w0, 2044($a0)\n" - "ld.d $w0, 2048($a0)\n" - "addiu $at, $a0, 2049\n" - "ld.b $w0, 0($at)\n" - "addiu $at, $a0, 2050\n" - "ld.h $w0, 0($at)\n" - "addiu $at, $a0, 2052\n" - "ld.w $w0, 0($at)\n" - "ld.d $w0, 4088($a0)\n" - "addiu $at, $a0, 4096\n" - "ld.d $w0, 0($at)\n" - "addiu $at, $a0, 4097\n" - "ld.b $w0, 0($at)\n" - "addiu $at, $a0, 4098\n" - "ld.h $w0, 0($at)\n" - "addiu $at, $a0, 4100\n" - "ld.w $w0, 0($at)\n" - "addiu $at, $a0, 4104\n" - "ld.d $w0, 0($at)\n" - "addiu $at, $a0, 0x7FFC\n" - "ld.w $w0, 0($at)\n" - "addiu $at, $a0, 0x7FF8\n" - "ld.d $w0, 8($at)\n" - "addiu $at, $a0, 32760\n" - "addiu $at, $at, 32760\n" - "ld.d $w0, 16($at)\n" - "lui $at, 4660\n" - "addu $at, $at, $a0\n" - "addiu $at, $at, 24576\n" - "ld.d $w0, -2440($at) # 0xF678\n" - "lui $at, 4661\n" - "addu $at, $at, $a0\n" - "ld.d $w0, 120($at)\n" - "ld.d $w0, -256($a0)\n" - "ld.b $w0, -511($a0)\n" - "addiu $at, $a0, -513\n" - "ld.b $w0, 0($at)\n" - "ld.h $w0, -1022($a0)\n" - "addiu $at, $a0, -1026\n" - "ld.h $w0, 0($at)\n" - "ld.w $w0, -2044($a0)\n" - "addiu $at, $a0, -2052\n" - "ld.w $w0, 0($at)\n" - "ld.d $w0, -4096($a0)\n" - "addiu $at, $a0, -4104\n" - "ld.d $w0, 0($at)\n" - "addiu $at, $a0, -32768\n" - "ld.d $w0, 0($at)\n" - "addiu $at, $a0, -32760\n" - "addiu $at, $at, -4096\n" - "ld.d $w0, 0($at)\n" - "addiu $at, $a0, 32760\n" - "addiu $at, $at, 4096\n" - "ld.d $w0, 0($at)\n" - "addiu $at, $a0, -32760\n" - "addiu $at, $at, -32760\n" - "ld.d $w0, -4088($at)\n" - "addiu $at, $a0, 32760\n" - "addiu $at, $at, 32760\n" - "ld.d $w0, 4088($at)\n" - "lui $at, 0xABCE\n" - "addu $at, $at, $a0\n" - "addiu $at, $at, -8192 # 0xE000\n" - "ld.d $w0, 0xF00($at)\n" - "lui $at, 0x8000\n" - "addu $at, $at, $a0\n" - "addiu $at, $at, -21504 # 0xAC00\n" - "ld.b $w0, -51($at) # 0xFFCD\n"; - DriverStr(expected, "LoadQFromOffset"); -} - -TEST_F(AssemblerMIPS32r5Test, StoreQToOffset) { - __ StoreQToOffset(mips::F0, mips::A0, 0); - __ StoreQToOffset(mips::F0, mips::A0, 1); - __ StoreQToOffset(mips::F0, mips::A0, 2); - __ StoreQToOffset(mips::F0, mips::A0, 4); - __ StoreQToOffset(mips::F0, mips::A0, 8); - __ StoreQToOffset(mips::F0, mips::A0, 511); - __ StoreQToOffset(mips::F0, mips::A0, 512); - __ StoreQToOffset(mips::F0, mips::A0, 513); - __ StoreQToOffset(mips::F0, mips::A0, 514); - __ StoreQToOffset(mips::F0, mips::A0, 516); - __ StoreQToOffset(mips::F0, mips::A0, 1022); - __ StoreQToOffset(mips::F0, mips::A0, 1024); - __ StoreQToOffset(mips::F0, mips::A0, 1025); - __ StoreQToOffset(mips::F0, mips::A0, 1026); - __ StoreQToOffset(mips::F0, mips::A0, 1028); - __ StoreQToOffset(mips::F0, mips::A0, 2044); - __ StoreQToOffset(mips::F0, mips::A0, 2048); - __ StoreQToOffset(mips::F0, mips::A0, 2049); - __ StoreQToOffset(mips::F0, mips::A0, 2050); - __ StoreQToOffset(mips::F0, mips::A0, 2052); - __ StoreQToOffset(mips::F0, mips::A0, 4088); - __ StoreQToOffset(mips::F0, mips::A0, 4096); - __ StoreQToOffset(mips::F0, mips::A0, 4097); - __ StoreQToOffset(mips::F0, mips::A0, 4098); - __ StoreQToOffset(mips::F0, mips::A0, 4100); - __ StoreQToOffset(mips::F0, mips::A0, 4104); - __ StoreQToOffset(mips::F0, mips::A0, 0x7FFC); - __ StoreQToOffset(mips::F0, mips::A0, 0x8000); - __ StoreQToOffset(mips::F0, mips::A0, 0x10000); - __ StoreQToOffset(mips::F0, mips::A0, 0x12345678); - __ StoreQToOffset(mips::F0, mips::A0, 0x12350078); - __ StoreQToOffset(mips::F0, mips::A0, -256); - __ StoreQToOffset(mips::F0, mips::A0, -511); - __ StoreQToOffset(mips::F0, mips::A0, -513); - __ StoreQToOffset(mips::F0, mips::A0, -1022); - __ StoreQToOffset(mips::F0, mips::A0, -1026); - __ StoreQToOffset(mips::F0, mips::A0, -2044); - __ StoreQToOffset(mips::F0, mips::A0, -2052); - __ StoreQToOffset(mips::F0, mips::A0, -4096); - __ StoreQToOffset(mips::F0, mips::A0, -4104); - __ StoreQToOffset(mips::F0, mips::A0, -32768); - __ StoreQToOffset(mips::F0, mips::A0, -36856); - __ StoreQToOffset(mips::F0, mips::A0, 36856); - __ StoreQToOffset(mips::F0, mips::A0, -69608); - __ StoreQToOffset(mips::F0, mips::A0, 69608); - __ StoreQToOffset(mips::F0, mips::A0, 0xABCDEF00); - __ StoreQToOffset(mips::F0, mips::A0, 0x7FFFABCD); - - const char* expected = - "st.d $w0, 0($a0)\n" - "st.b $w0, 1($a0)\n" - "st.h $w0, 2($a0)\n" - "st.w $w0, 4($a0)\n" - "st.d $w0, 8($a0)\n" - "st.b $w0, 511($a0)\n" - "st.d $w0, 512($a0)\n" - "addiu $at, $a0, 513\n" - "st.b $w0, 0($at)\n" - "st.h $w0, 514($a0)\n" - "st.w $w0, 516($a0)\n" - "st.h $w0, 1022($a0)\n" - "st.d $w0, 1024($a0)\n" - "addiu $at, $a0, 1025\n" - "st.b $w0, 0($at)\n" - "addiu $at, $a0, 1026\n" - "st.h $w0, 0($at)\n" - "st.w $w0, 1028($a0)\n" - "st.w $w0, 2044($a0)\n" - "st.d $w0, 2048($a0)\n" - "addiu $at, $a0, 2049\n" - "st.b $w0, 0($at)\n" - "addiu $at, $a0, 2050\n" - "st.h $w0, 0($at)\n" - "addiu $at, $a0, 2052\n" - "st.w $w0, 0($at)\n" - "st.d $w0, 4088($a0)\n" - "addiu $at, $a0, 4096\n" - "st.d $w0, 0($at)\n" - "addiu $at, $a0, 4097\n" - "st.b $w0, 0($at)\n" - "addiu $at, $a0, 4098\n" - "st.h $w0, 0($at)\n" - "addiu $at, $a0, 4100\n" - "st.w $w0, 0($at)\n" - "addiu $at, $a0, 4104\n" - "st.d $w0, 0($at)\n" - "addiu $at, $a0, 0x7FFC\n" - "st.w $w0, 0($at)\n" - "addiu $at, $a0, 0x7FF8\n" - "st.d $w0, 8($at)\n" - "addiu $at, $a0, 32760\n" - "addiu $at, $at, 32760\n" - "st.d $w0, 16($at)\n" - "lui $at, 4660\n" - "addu $at, $at, $a0\n" - "addiu $at, $at, 24576\n" - "st.d $w0, -2440($at) # 0xF678\n" - "lui $at, 4661\n" - "addu $at, $at, $a0\n" - "st.d $w0, 120($at)\n" - "st.d $w0, -256($a0)\n" - "st.b $w0, -511($a0)\n" - "addiu $at, $a0, -513\n" - "st.b $w0, 0($at)\n" - "st.h $w0, -1022($a0)\n" - "addiu $at, $a0, -1026\n" - "st.h $w0, 0($at)\n" - "st.w $w0, -2044($a0)\n" - "addiu $at, $a0, -2052\n" - "st.w $w0, 0($at)\n" - "st.d $w0, -4096($a0)\n" - "addiu $at, $a0, -4104\n" - "st.d $w0, 0($at)\n" - "addiu $at, $a0, -32768\n" - "st.d $w0, 0($at)\n" - "addiu $at, $a0, -32760\n" - "addiu $at, $at, -4096\n" - "st.d $w0, 0($at)\n" - "addiu $at, $a0, 32760\n" - "addiu $at, $at, 4096\n" - "st.d $w0, 0($at)\n" - "addiu $at, $a0, -32760\n" - "addiu $at, $at, -32760\n" - "st.d $w0, -4088($at)\n" - "addiu $at, $a0, 32760\n" - "addiu $at, $at, 32760\n" - "st.d $w0, 4088($at)\n" - "lui $at, 0xABCE\n" - "addu $at, $at, $a0\n" - "addiu $at, $at, -8192 # 0xE000\n" - "st.d $w0, 0xF00($at)\n" - "lui $at, 0x8000\n" - "addu $at, $at, $a0\n" - "addiu $at, $at, -21504 # 0xAC00\n" - "st.b $w0, -51($at) # 0xFFCD\n"; - DriverStr(expected, "StoreQToOffset"); -} - -#undef __ -} // namespace art diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc deleted file mode 100644 index 4e27bbf28d..0000000000 --- a/compiler/utils/mips/assembler_mips32r6_test.cc +++ /dev/null @@ -1,2524 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "assembler_mips.h" - -#include <map> - -#include "base/stl_util.h" -#include "utils/assembler_test.h" - -#define __ GetAssembler()-> - -namespace art { - -struct MIPSCpuRegisterCompare { - bool operator()(const mips::Register& a, const mips::Register& b) const { - return a < b; - } -}; - -class AssemblerMIPS32r6Test : public AssemblerTest<mips::MipsAssembler, - mips::MipsLabel, - mips::Register, - mips::FRegister, - uint32_t, - mips::VectorRegister> { - public: - using Base = AssemblerTest<mips::MipsAssembler, - mips::MipsLabel, - mips::Register, - mips::FRegister, - uint32_t, - mips::VectorRegister>; - - // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<> - // and reimplement it without the verification against `assembly_string`. b/73903608 - void DriverStr(const std::string& assembly_string ATTRIBUTE_UNUSED, - const std::string& test_name ATTRIBUTE_UNUSED) { - GetAssembler()->FinalizeCode(); - std::vector<uint8_t> data(GetAssembler()->CodeSize()); - MemoryRegion code(data.data(), data.size()); - GetAssembler()->FinalizeInstructions(code); - } - - AssemblerMIPS32r6Test() : - instruction_set_features_(MipsInstructionSetFeatures::FromVariant("mips32r6", nullptr)) { - } - - protected: - // Get the typically used name for this architecture, e.g., aarch64, x86-64, ... - std::string GetArchitectureString() override { - return "mips"; - } - - std::string GetAssemblerCmdName() override { - // We assemble and link for MIPS32R6. See GetAssemblerParameters() for details. - return "gcc"; - } - - std::string GetAssemblerParameters() override { - // We assemble and link for MIPS32R6. The reason is that object files produced for MIPS32R6 - // (and MIPS64R6) with the GNU assembler don't have correct final offsets in PC-relative - // branches in the .text section and so they require a relocation pass (there's a relocation - // section, .rela.text, that has the needed info to fix up the branches). - // We use "-modd-spreg" so we can use odd-numbered single precision FPU registers. - // We put the code at address 0x1000000 (instead of 0) to avoid overlapping with the - // .MIPS.abiflags section (there doesn't seem to be a way to suppress its generation easily). - return " -march=mips32r6 -mmsa -modd-spreg -Wa,--no-warn" - " -Wl,-Ttext=0x1000000 -Wl,-e0x1000000 -nostdlib"; - } - - void Pad(std::vector<uint8_t>& data) override { - // The GNU linker unconditionally pads the code segment with NOPs to a size that is a multiple - // of 16 and there doesn't appear to be a way to suppress this padding. Our assembler doesn't - // pad, so, in order for two assembler outputs to match, we need to match the padding as well. - // NOP is encoded as four zero bytes on MIPS. - size_t pad_size = RoundUp(data.size(), 16u) - data.size(); - data.insert(data.end(), pad_size, 0); - } - - std::string GetDisassembleParameters() override { - return " -D -bbinary -mmips:isa32r6"; - } - - mips::MipsAssembler* CreateAssembler(ArenaAllocator* allocator) override { - return new (allocator) mips::MipsAssembler(allocator, instruction_set_features_.get()); - } - - void SetUpHelpers() override { - if (registers_.size() == 0) { - registers_.push_back(new mips::Register(mips::ZERO)); - registers_.push_back(new mips::Register(mips::AT)); - registers_.push_back(new mips::Register(mips::V0)); - registers_.push_back(new mips::Register(mips::V1)); - registers_.push_back(new mips::Register(mips::A0)); - registers_.push_back(new mips::Register(mips::A1)); - registers_.push_back(new mips::Register(mips::A2)); - registers_.push_back(new mips::Register(mips::A3)); - registers_.push_back(new mips::Register(mips::T0)); - registers_.push_back(new mips::Register(mips::T1)); - registers_.push_back(new mips::Register(mips::T2)); - registers_.push_back(new mips::Register(mips::T3)); - registers_.push_back(new mips::Register(mips::T4)); - registers_.push_back(new mips::Register(mips::T5)); - registers_.push_back(new mips::Register(mips::T6)); - registers_.push_back(new mips::Register(mips::T7)); - registers_.push_back(new mips::Register(mips::S0)); - registers_.push_back(new mips::Register(mips::S1)); - registers_.push_back(new mips::Register(mips::S2)); - registers_.push_back(new mips::Register(mips::S3)); - registers_.push_back(new mips::Register(mips::S4)); - registers_.push_back(new mips::Register(mips::S5)); - registers_.push_back(new mips::Register(mips::S6)); - registers_.push_back(new mips::Register(mips::S7)); - registers_.push_back(new mips::Register(mips::T8)); - registers_.push_back(new mips::Register(mips::T9)); - registers_.push_back(new mips::Register(mips::K0)); - registers_.push_back(new mips::Register(mips::K1)); - registers_.push_back(new mips::Register(mips::GP)); - registers_.push_back(new mips::Register(mips::SP)); - registers_.push_back(new mips::Register(mips::FP)); - registers_.push_back(new mips::Register(mips::RA)); - - secondary_register_names_.emplace(mips::Register(mips::ZERO), "zero"); - secondary_register_names_.emplace(mips::Register(mips::AT), "at"); - secondary_register_names_.emplace(mips::Register(mips::V0), "v0"); - secondary_register_names_.emplace(mips::Register(mips::V1), "v1"); - secondary_register_names_.emplace(mips::Register(mips::A0), "a0"); - secondary_register_names_.emplace(mips::Register(mips::A1), "a1"); - secondary_register_names_.emplace(mips::Register(mips::A2), "a2"); - secondary_register_names_.emplace(mips::Register(mips::A3), "a3"); - secondary_register_names_.emplace(mips::Register(mips::T0), "t0"); - secondary_register_names_.emplace(mips::Register(mips::T1), "t1"); - secondary_register_names_.emplace(mips::Register(mips::T2), "t2"); - secondary_register_names_.emplace(mips::Register(mips::T3), "t3"); - secondary_register_names_.emplace(mips::Register(mips::T4), "t4"); - secondary_register_names_.emplace(mips::Register(mips::T5), "t5"); - secondary_register_names_.emplace(mips::Register(mips::T6), "t6"); - secondary_register_names_.emplace(mips::Register(mips::T7), "t7"); - secondary_register_names_.emplace(mips::Register(mips::S0), "s0"); - secondary_register_names_.emplace(mips::Register(mips::S1), "s1"); - secondary_register_names_.emplace(mips::Register(mips::S2), "s2"); - secondary_register_names_.emplace(mips::Register(mips::S3), "s3"); - secondary_register_names_.emplace(mips::Register(mips::S4), "s4"); - secondary_register_names_.emplace(mips::Register(mips::S5), "s5"); - secondary_register_names_.emplace(mips::Register(mips::S6), "s6"); - secondary_register_names_.emplace(mips::Register(mips::S7), "s7"); - secondary_register_names_.emplace(mips::Register(mips::T8), "t8"); - secondary_register_names_.emplace(mips::Register(mips::T9), "t9"); - secondary_register_names_.emplace(mips::Register(mips::K0), "k0"); - secondary_register_names_.emplace(mips::Register(mips::K1), "k1"); - secondary_register_names_.emplace(mips::Register(mips::GP), "gp"); - secondary_register_names_.emplace(mips::Register(mips::SP), "sp"); - secondary_register_names_.emplace(mips::Register(mips::FP), "fp"); - secondary_register_names_.emplace(mips::Register(mips::RA), "ra"); - - fp_registers_.push_back(new mips::FRegister(mips::F0)); - fp_registers_.push_back(new mips::FRegister(mips::F1)); - fp_registers_.push_back(new mips::FRegister(mips::F2)); - fp_registers_.push_back(new mips::FRegister(mips::F3)); - fp_registers_.push_back(new mips::FRegister(mips::F4)); - fp_registers_.push_back(new mips::FRegister(mips::F5)); - fp_registers_.push_back(new mips::FRegister(mips::F6)); - fp_registers_.push_back(new mips::FRegister(mips::F7)); - fp_registers_.push_back(new mips::FRegister(mips::F8)); - fp_registers_.push_back(new mips::FRegister(mips::F9)); - fp_registers_.push_back(new mips::FRegister(mips::F10)); - fp_registers_.push_back(new mips::FRegister(mips::F11)); - fp_registers_.push_back(new mips::FRegister(mips::F12)); - fp_registers_.push_back(new mips::FRegister(mips::F13)); - fp_registers_.push_back(new mips::FRegister(mips::F14)); - fp_registers_.push_back(new mips::FRegister(mips::F15)); - fp_registers_.push_back(new mips::FRegister(mips::F16)); - fp_registers_.push_back(new mips::FRegister(mips::F17)); - fp_registers_.push_back(new mips::FRegister(mips::F18)); - fp_registers_.push_back(new mips::FRegister(mips::F19)); - fp_registers_.push_back(new mips::FRegister(mips::F20)); - fp_registers_.push_back(new mips::FRegister(mips::F21)); - fp_registers_.push_back(new mips::FRegister(mips::F22)); - fp_registers_.push_back(new mips::FRegister(mips::F23)); - fp_registers_.push_back(new mips::FRegister(mips::F24)); - fp_registers_.push_back(new mips::FRegister(mips::F25)); - fp_registers_.push_back(new mips::FRegister(mips::F26)); - fp_registers_.push_back(new mips::FRegister(mips::F27)); - fp_registers_.push_back(new mips::FRegister(mips::F28)); - fp_registers_.push_back(new mips::FRegister(mips::F29)); - fp_registers_.push_back(new mips::FRegister(mips::F30)); - fp_registers_.push_back(new mips::FRegister(mips::F31)); - - vec_registers_.push_back(new mips::VectorRegister(mips::W0)); - vec_registers_.push_back(new mips::VectorRegister(mips::W1)); - vec_registers_.push_back(new mips::VectorRegister(mips::W2)); - vec_registers_.push_back(new mips::VectorRegister(mips::W3)); - vec_registers_.push_back(new mips::VectorRegister(mips::W4)); - vec_registers_.push_back(new mips::VectorRegister(mips::W5)); - vec_registers_.push_back(new mips::VectorRegister(mips::W6)); - vec_registers_.push_back(new mips::VectorRegister(mips::W7)); - vec_registers_.push_back(new mips::VectorRegister(mips::W8)); - vec_registers_.push_back(new mips::VectorRegister(mips::W9)); - vec_registers_.push_back(new mips::VectorRegister(mips::W10)); - vec_registers_.push_back(new mips::VectorRegister(mips::W11)); - vec_registers_.push_back(new mips::VectorRegister(mips::W12)); - vec_registers_.push_back(new mips::VectorRegister(mips::W13)); - vec_registers_.push_back(new mips::VectorRegister(mips::W14)); - vec_registers_.push_back(new mips::VectorRegister(mips::W15)); - vec_registers_.push_back(new mips::VectorRegister(mips::W16)); - vec_registers_.push_back(new mips::VectorRegister(mips::W17)); - vec_registers_.push_back(new mips::VectorRegister(mips::W18)); - vec_registers_.push_back(new mips::VectorRegister(mips::W19)); - vec_registers_.push_back(new mips::VectorRegister(mips::W20)); - vec_registers_.push_back(new mips::VectorRegister(mips::W21)); - vec_registers_.push_back(new mips::VectorRegister(mips::W22)); - vec_registers_.push_back(new mips::VectorRegister(mips::W23)); - vec_registers_.push_back(new mips::VectorRegister(mips::W24)); - vec_registers_.push_back(new mips::VectorRegister(mips::W25)); - vec_registers_.push_back(new mips::VectorRegister(mips::W26)); - vec_registers_.push_back(new mips::VectorRegister(mips::W27)); - vec_registers_.push_back(new mips::VectorRegister(mips::W28)); - vec_registers_.push_back(new mips::VectorRegister(mips::W29)); - vec_registers_.push_back(new mips::VectorRegister(mips::W30)); - vec_registers_.push_back(new mips::VectorRegister(mips::W31)); - } - } - - void TearDown() override { - AssemblerTest::TearDown(); - STLDeleteElements(®isters_); - STLDeleteElements(&fp_registers_); - STLDeleteElements(&vec_registers_); - } - - std::vector<mips::MipsLabel> GetAddresses() override { - UNIMPLEMENTED(FATAL) << "Feature not implemented yet"; - UNREACHABLE(); - } - - std::vector<mips::Register*> GetRegisters() override { - return registers_; - } - - std::vector<mips::FRegister*> GetFPRegisters() override { - return fp_registers_; - } - - std::vector<mips::VectorRegister*> GetVectorRegisters() override { - return vec_registers_; - } - - uint32_t CreateImmediate(int64_t imm_value) override { - return imm_value; - } - - std::string GetSecondaryRegisterName(const mips::Register& reg) override { - CHECK(secondary_register_names_.find(reg) != secondary_register_names_.end()); - return secondary_register_names_[reg]; - } - - std::string RepeatInsn(size_t count, const std::string& insn) { - std::string result; - for (; count != 0u; --count) { - result += insn; - } - return result; - } - - void BranchHelper(void (mips::MipsAssembler::*f)(mips::MipsLabel*, - bool), - const std::string& instr_name, - bool has_slot, - bool is_bare = false) { - __ SetReorder(false); - mips::MipsLabel label1, label2; - (Base::GetAssembler()->*f)(&label1, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label1); - (Base::GetAssembler()->*f)(&label2, is_bare); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label2); - (Base::GetAssembler()->*f)(&label1, is_bare); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " 1f\n" + - ((is_bare || !has_slot) ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - instr_name + " 2f\n" + - ((is_bare || !has_slot) ? "" : "nop\n") + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "2:\n" + - instr_name + " 1b\n" + - ((is_bare || !has_slot) ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - void BranchCondOneRegHelper(void (mips::MipsAssembler::*f)(mips::Register, - mips::MipsLabel*, - bool), - const std::string& instr_name, - bool is_bare = false) { - __ SetReorder(false); - mips::MipsLabel label; - (Base::GetAssembler()->*f)(mips::A0, &label, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - (Base::GetAssembler()->*f)(mips::A1, &label, is_bare); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " $a0, 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - instr_name + " $a1, 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - void BranchCondTwoRegsHelper(void (mips::MipsAssembler::*f)(mips::Register, - mips::Register, - mips::MipsLabel*, - bool), - const std::string& instr_name, - bool is_bare = false) { - __ SetReorder(false); - mips::MipsLabel label; - (Base::GetAssembler()->*f)(mips::A0, mips::A1, &label, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - (Base::GetAssembler()->*f)(mips::A2, mips::A3, &label, is_bare); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " $a0, $a1, 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - instr_name + " $a2, $a3, 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - void BranchFpuCondHelper(void (mips::MipsAssembler::*f)(mips::FRegister, - mips::MipsLabel*, - bool), - const std::string& instr_name, - bool is_bare = false) { - __ SetReorder(false); - mips::MipsLabel label; - (Base::GetAssembler()->*f)(mips::F0, &label, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - (Base::GetAssembler()->*f)(mips::F30, &label, is_bare); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " $f0, 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - instr_name + " $f30, 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - private: - std::vector<mips::Register*> registers_; - std::map<mips::Register, std::string, MIPSCpuRegisterCompare> secondary_register_names_; - - std::vector<mips::FRegister*> fp_registers_; - std::vector<mips::VectorRegister*> vec_registers_; - std::unique_ptr<const MipsInstructionSetFeatures> instruction_set_features_; -}; - - -TEST_F(AssemblerMIPS32r6Test, Toolchain) { - EXPECT_TRUE(CheckTools()); -} - -TEST_F(AssemblerMIPS32r6Test, MulR6) { - DriverStr(RepeatRRR(&mips::MipsAssembler::MulR6, "mul ${reg1}, ${reg2}, ${reg3}"), "MulR6"); -} - -TEST_F(AssemblerMIPS32r6Test, MuhR6) { - DriverStr(RepeatRRR(&mips::MipsAssembler::MuhR6, "muh ${reg1}, ${reg2}, ${reg3}"), "MuhR6"); -} - -TEST_F(AssemblerMIPS32r6Test, MuhuR6) { - DriverStr(RepeatRRR(&mips::MipsAssembler::MuhuR6, "muhu ${reg1}, ${reg2}, ${reg3}"), "MuhuR6"); -} - -TEST_F(AssemblerMIPS32r6Test, DivR6) { - DriverStr(RepeatRRR(&mips::MipsAssembler::DivR6, "div ${reg1}, ${reg2}, ${reg3}"), "DivR6"); -} - -TEST_F(AssemblerMIPS32r6Test, ModR6) { - DriverStr(RepeatRRR(&mips::MipsAssembler::ModR6, "mod ${reg1}, ${reg2}, ${reg3}"), "ModR6"); -} - -TEST_F(AssemblerMIPS32r6Test, DivuR6) { - DriverStr(RepeatRRR(&mips::MipsAssembler::DivuR6, "divu ${reg1}, ${reg2}, ${reg3}"), "DivuR6"); -} - -TEST_F(AssemblerMIPS32r6Test, ModuR6) { - DriverStr(RepeatRRR(&mips::MipsAssembler::ModuR6, "modu ${reg1}, ${reg2}, ${reg3}"), "ModuR6"); -} - -////////// -// MISC // -////////// - -TEST_F(AssemblerMIPS32r6Test, Aui) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Aui, 16, "aui ${reg1}, ${reg2}, {imm}"), "Aui"); -} - -TEST_F(AssemblerMIPS32r6Test, Auipc) { - DriverStr(RepeatRIb(&mips::MipsAssembler::Auipc, 16, "auipc ${reg}, {imm}"), "Auipc"); -} - -TEST_F(AssemblerMIPS32r6Test, Lwpc) { - // Lwpc() takes an unsigned 19-bit immediate, while the GNU assembler needs a signed offset, - // hence the sign extension from bit 18 with `imm - ((imm & 0x40000) << 1)`. - // The GNU assembler also wants the offset to be a multiple of 4, which it will shift right - // by 2 positions when encoding, hence `<< 2` to compensate for that shift. - // We capture the value of the immediate with `.set imm, {imm}` because the value is needed - // twice for the sign extension, but `{imm}` is substituted only once. - const char* code = ".set imm, {imm}\nlw ${reg}, ((imm - ((imm & 0x40000) << 1)) << 2)($pc)"; - DriverStr(RepeatRIb(&mips::MipsAssembler::Lwpc, 19, code), "Lwpc"); -} - -TEST_F(AssemblerMIPS32r6Test, Addiupc) { - // The comment from the Lwpc() test applies to this Addiupc() test as well. - const char* code = ".set imm, {imm}\naddiupc ${reg}, (imm - ((imm & 0x40000) << 1)) << 2"; - DriverStr(RepeatRIb(&mips::MipsAssembler::Addiupc, 19, code), "Addiupc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bitswap) { - DriverStr(RepeatRR(&mips::MipsAssembler::Bitswap, "bitswap ${reg1}, ${reg2}"), "bitswap"); -} - -TEST_F(AssemblerMIPS32r6Test, Lsa) { - DriverStr(RepeatRRRIb(&mips::MipsAssembler::Lsa, - 2, - "lsa ${reg1}, ${reg2}, ${reg3}, {imm}", - 1), - "lsa"); -} - -TEST_F(AssemblerMIPS32r6Test, Seleqz) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Seleqz, "seleqz ${reg1}, ${reg2}, ${reg3}"), "seleqz"); -} - -TEST_F(AssemblerMIPS32r6Test, Selnez) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Selnez, "selnez ${reg1}, ${reg2}, ${reg3}"), "selnez"); -} - -TEST_F(AssemblerMIPS32r6Test, ClzR6) { - DriverStr(RepeatRR(&mips::MipsAssembler::ClzR6, "clz ${reg1}, ${reg2}"), "clzR6"); -} - -TEST_F(AssemblerMIPS32r6Test, CloR6) { - DriverStr(RepeatRR(&mips::MipsAssembler::CloR6, "clo ${reg1}, ${reg2}"), "cloR6"); -} - -//////////////////// -// FLOATING POINT // -//////////////////// - -TEST_F(AssemblerMIPS32r6Test, SelS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::SelS, "sel.s ${reg1}, ${reg2}, ${reg3}"), "sel.s"); -} - -TEST_F(AssemblerMIPS32r6Test, SelD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::SelD, "sel.d ${reg1}, ${reg2}, ${reg3}"), "sel.d"); -} - -TEST_F(AssemblerMIPS32r6Test, SeleqzS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::SeleqzS, "seleqz.s ${reg1}, ${reg2}, ${reg3}"), - "seleqz.s"); -} - -TEST_F(AssemblerMIPS32r6Test, SeleqzD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::SeleqzD, "seleqz.d ${reg1}, ${reg2}, ${reg3}"), - "seleqz.d"); -} - -TEST_F(AssemblerMIPS32r6Test, SelnezS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::SelnezS, "selnez.s ${reg1}, ${reg2}, ${reg3}"), - "selnez.s"); -} - -TEST_F(AssemblerMIPS32r6Test, SelnezD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::SelnezD, "selnez.d ${reg1}, ${reg2}, ${reg3}"), - "selnez.d"); -} - -TEST_F(AssemblerMIPS32r6Test, ClassS) { - DriverStr(RepeatFF(&mips::MipsAssembler::ClassS, "class.s ${reg1}, ${reg2}"), "class.s"); -} - -TEST_F(AssemblerMIPS32r6Test, ClassD) { - DriverStr(RepeatFF(&mips::MipsAssembler::ClassD, "class.d ${reg1}, ${reg2}"), "class.d"); -} - -TEST_F(AssemblerMIPS32r6Test, MinS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::MinS, "min.s ${reg1}, ${reg2}, ${reg3}"), "min.s"); -} - -TEST_F(AssemblerMIPS32r6Test, MinD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::MinD, "min.d ${reg1}, ${reg2}, ${reg3}"), "min.d"); -} - -TEST_F(AssemblerMIPS32r6Test, MaxS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::MaxS, "max.s ${reg1}, ${reg2}, ${reg3}"), "max.s"); -} - -TEST_F(AssemblerMIPS32r6Test, MaxD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::MaxD, "max.d ${reg1}, ${reg2}, ${reg3}"), "max.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUnS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUnS, "cmp.un.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.un.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpEqS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpEqS, "cmp.eq.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.eq.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUeqS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUeqS, "cmp.ueq.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.ueq.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpLtS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpLtS, "cmp.lt.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.lt.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUltS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUltS, "cmp.ult.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.ult.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpLeS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpLeS, "cmp.le.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.le.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUleS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUleS, "cmp.ule.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.ule.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpOrS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpOrS, "cmp.or.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.or.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUneS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUneS, "cmp.une.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.une.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpNeS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpNeS, "cmp.ne.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.ne.s"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUnD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUnD, "cmp.un.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.un.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpEqD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpEqD, "cmp.eq.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.eq.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUeqD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUeqD, "cmp.ueq.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.ueq.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpLtD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpLtD, "cmp.lt.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.lt.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUltD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUltD, "cmp.ult.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.ult.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpLeD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpLeD, "cmp.le.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.le.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUleD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUleD, "cmp.ule.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.ule.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpOrD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpOrD, "cmp.or.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.or.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpUneD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpUneD, "cmp.une.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.une.d"); -} - -TEST_F(AssemblerMIPS32r6Test, CmpNeD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::CmpNeD, "cmp.ne.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.ne.d"); -} - -TEST_F(AssemblerMIPS32r6Test, LoadDFromOffset) { - __ 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" - "ldc1 $f0, 0x7FF8($a0)\n" - "lwc1 $f0, 0x7FFB($a0)\n" - "lw $t8, 0x7FFF($a0)\n" - "mthc1 $t8, $f0\n" - "addiu $at, $a0, 0x7FF8\n" - "lwc1 $f0, 4($at)\n" - "lw $t8, 8($at)\n" - "mthc1 $t8, $f0\n" - "addiu $at, $a0, 0x7FF8\n" - "lwc1 $f0, 7($at)\n" - "lw $t8, 11($at)\n" - "mthc1 $t8, $f0\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" - "lw $t8, -5($at)\n" - "mthc1 $t8, $f0\n" - "addiu $at, $a0, 0x7FF8\n" - "ldc1 $f0, 8($at)\n" - "addiu $at, $a0, 0x7FF8\n" - "ldc1 $f0, 0x7FF8($at)\n" - "aui $at, $a0, 0xFFFF\n" - "ldc1 $f0, -0x7FE8($at)\n" - "aui $at, $a0, 0xFFFF\n" - "ldc1 $f0, 0x8($at)\n" - "aui $at, $a0, 0xFFFF\n" - "lwc1 $f0, 0xF($at)\n" - "lw $t8, 0x13($at)\n" - "mthc1 $t8, $f0\n" - "aui $at, $a0, 0x1\n" - "lwc1 $f0, -0xF($at)\n" - "lw $t8, -0xB($at)\n" - "mthc1 $t8, $f0\n" - "aui $at, $a0, 0x1\n" - "ldc1 $f0, -0x8($at)\n" - "aui $at, $a0, 0x1\n" - "ldc1 $f0, 0x7FE8($at)\n" - "aui $at, $a0, 0xFFFF\n" - "ldc1 $f0, -0x7FF0($at)\n" - "aui $at, $a0, 0xFFFF\n" - "lwc1 $f0, -0x7FE9($at)\n" - "lw $t8, -0x7FE5($at)\n" - "mthc1 $t8, $f0\n" - "aui $at, $a0, 0x1\n" - "lwc1 $f0, 0x7FE9($at)\n" - "lw $t8, 0x7FED($at)\n" - "mthc1 $t8, $f0\n" - "aui $at, $a0, 0x1\n" - "ldc1 $f0, 0x7FF0($at)\n" - "aui $at, $a0, 0x1234\n" - "ldc1 $f0, 0x5678($at)\n"; - DriverStr(expected, "LoadDFromOffset"); -} - -TEST_F(AssemblerMIPS32r6Test, LoadQFromOffset) { - __ LoadQFromOffset(mips::F0, mips::A0, 0); - __ LoadQFromOffset(mips::F0, mips::A0, 1); - __ LoadQFromOffset(mips::F0, mips::A0, 2); - __ LoadQFromOffset(mips::F0, mips::A0, 4); - __ LoadQFromOffset(mips::F0, mips::A0, 8); - __ LoadQFromOffset(mips::F0, mips::A0, 511); - __ LoadQFromOffset(mips::F0, mips::A0, 512); - __ LoadQFromOffset(mips::F0, mips::A0, 513); - __ LoadQFromOffset(mips::F0, mips::A0, 514); - __ LoadQFromOffset(mips::F0, mips::A0, 516); - __ LoadQFromOffset(mips::F0, mips::A0, 1022); - __ LoadQFromOffset(mips::F0, mips::A0, 1024); - __ LoadQFromOffset(mips::F0, mips::A0, 1025); - __ LoadQFromOffset(mips::F0, mips::A0, 1026); - __ LoadQFromOffset(mips::F0, mips::A0, 1028); - __ LoadQFromOffset(mips::F0, mips::A0, 2044); - __ LoadQFromOffset(mips::F0, mips::A0, 2048); - __ LoadQFromOffset(mips::F0, mips::A0, 2049); - __ LoadQFromOffset(mips::F0, mips::A0, 2050); - __ LoadQFromOffset(mips::F0, mips::A0, 2052); - __ LoadQFromOffset(mips::F0, mips::A0, 4088); - __ LoadQFromOffset(mips::F0, mips::A0, 4096); - __ LoadQFromOffset(mips::F0, mips::A0, 4097); - __ LoadQFromOffset(mips::F0, mips::A0, 4098); - __ LoadQFromOffset(mips::F0, mips::A0, 4100); - __ LoadQFromOffset(mips::F0, mips::A0, 4104); - __ LoadQFromOffset(mips::F0, mips::A0, 0x7FFC); - __ LoadQFromOffset(mips::F0, mips::A0, 0x8000); - __ LoadQFromOffset(mips::F0, mips::A0, 0x10000); - __ LoadQFromOffset(mips::F0, mips::A0, 0x12345678); - __ LoadQFromOffset(mips::F0, mips::A0, 0x12350078); - __ LoadQFromOffset(mips::F0, mips::A0, -256); - __ LoadQFromOffset(mips::F0, mips::A0, -511); - __ LoadQFromOffset(mips::F0, mips::A0, -513); - __ LoadQFromOffset(mips::F0, mips::A0, -1022); - __ LoadQFromOffset(mips::F0, mips::A0, -1026); - __ LoadQFromOffset(mips::F0, mips::A0, -2044); - __ LoadQFromOffset(mips::F0, mips::A0, -2052); - __ LoadQFromOffset(mips::F0, mips::A0, -4096); - __ LoadQFromOffset(mips::F0, mips::A0, -4104); - __ LoadQFromOffset(mips::F0, mips::A0, -32768); - __ LoadQFromOffset(mips::F0, mips::A0, 0xABCDEF00); - __ LoadQFromOffset(mips::F0, mips::A0, 0x7FFFABCD); - - const char* expected = - "ld.d $w0, 0($a0)\n" - "ld.b $w0, 1($a0)\n" - "ld.h $w0, 2($a0)\n" - "ld.w $w0, 4($a0)\n" - "ld.d $w0, 8($a0)\n" - "ld.b $w0, 511($a0)\n" - "ld.d $w0, 512($a0)\n" - "addiu $at, $a0, 513\n" - "ld.b $w0, 0($at)\n" - "ld.h $w0, 514($a0)\n" - "ld.w $w0, 516($a0)\n" - "ld.h $w0, 1022($a0)\n" - "ld.d $w0, 1024($a0)\n" - "addiu $at, $a0, 1025\n" - "ld.b $w0, 0($at)\n" - "addiu $at, $a0, 1026\n" - "ld.h $w0, 0($at)\n" - "ld.w $w0, 1028($a0)\n" - "ld.w $w0, 2044($a0)\n" - "ld.d $w0, 2048($a0)\n" - "addiu $at, $a0, 2049\n" - "ld.b $w0, 0($at)\n" - "addiu $at, $a0, 2050\n" - "ld.h $w0, 0($at)\n" - "addiu $at, $a0, 2052\n" - "ld.w $w0, 0($at)\n" - "ld.d $w0, 4088($a0)\n" - "addiu $at, $a0, 4096\n" - "ld.d $w0, 0($at)\n" - "addiu $at, $a0, 4097\n" - "ld.b $w0, 0($at)\n" - "addiu $at, $a0, 4098\n" - "ld.h $w0, 0($at)\n" - "addiu $at, $a0, 4100\n" - "ld.w $w0, 0($at)\n" - "addiu $at, $a0, 4104\n" - "ld.d $w0, 0($at)\n" - "addiu $at, $a0, 0x7FFC\n" - "ld.w $w0, 0($at)\n" - "addiu $at, $a0, 0x7FF8\n" - "ld.d $w0, 8($at)\n" - "aui $at, $a0, 0x1\n" - "ld.d $w0, 0($at)\n" - "aui $at, $a0, 0x1234\n" - "addiu $at, $at, 0x6000\n" - "ld.d $w0, -2440($at) # 0xF678\n" - "aui $at, $a0, 0x1235\n" - "ld.d $w0, 0x78($at)\n" - "ld.d $w0, -256($a0)\n" - "ld.b $w0, -511($a0)\n" - "addiu $at, $a0, -513\n" - "ld.b $w0, 0($at)\n" - "ld.h $w0, -1022($a0)\n" - "addiu $at, $a0, -1026\n" - "ld.h $w0, 0($at)\n" - "ld.w $w0, -2044($a0)\n" - "addiu $at, $a0, -2052\n" - "ld.w $w0, 0($at)\n" - "ld.d $w0, -4096($a0)\n" - "addiu $at, $a0, -4104\n" - "ld.d $w0, 0($at)\n" - "addiu $at, $a0, -32768\n" - "ld.d $w0, 0($at)\n" - "aui $at, $a0, 0xABCE\n" - "addiu $at, $at, -8192 # 0xE000\n" - "ld.d $w0, 0xF00($at)\n" - "aui $at, $a0, 0x8000\n" - "addiu $at, $at, -21504 # 0xAC00\n" - "ld.b $w0, -51($at) # 0xFFCD\n"; - DriverStr(expected, "LoadQFromOffset"); -} - -TEST_F(AssemblerMIPS32r6Test, StoreDToOffset) { - __ 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" - "sdc1 $f0, 0x7FF8($a0)\n" - "mfhc1 $t8, $f0\n" - "swc1 $f0, 0x7FFB($a0)\n" - "sw $t8, 0x7FFF($a0)\n" - "addiu $at, $a0, 0x7FF8\n" - "mfhc1 $t8, $f0\n" - "swc1 $f0, 4($at)\n" - "sw $t8, 8($at)\n" - "addiu $at, $a0, 0x7FF8\n" - "mfhc1 $t8, $f0\n" - "swc1 $f0, 7($at)\n" - "sw $t8, 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" - "mfhc1 $t8, $f0\n" - "swc1 $f0, -9($at)\n" - "sw $t8, -5($at)\n" - "addiu $at, $a0, 0x7FF8\n" - "sdc1 $f0, 8($at)\n" - "addiu $at, $a0, 0x7FF8\n" - "sdc1 $f0, 0x7FF8($at)\n" - "aui $at, $a0, 0xFFFF\n" - "sdc1 $f0, -0x7FE8($at)\n" - "aui $at, $a0, 0xFFFF\n" - "sdc1 $f0, 0x8($at)\n" - "aui $at, $a0, 0xFFFF\n" - "mfhc1 $t8, $f0\n" - "swc1 $f0, 0xF($at)\n" - "sw $t8, 0x13($at)\n" - "aui $at, $a0, 0x1\n" - "mfhc1 $t8, $f0\n" - "swc1 $f0, -0xF($at)\n" - "sw $t8, -0xB($at)\n" - "aui $at, $a0, 0x1\n" - "sdc1 $f0, -0x8($at)\n" - "aui $at, $a0, 0x1\n" - "sdc1 $f0, 0x7FE8($at)\n" - "aui $at, $a0, 0xFFFF\n" - "sdc1 $f0, -0x7FF0($at)\n" - "aui $at, $a0, 0xFFFF\n" - "mfhc1 $t8, $f0\n" - "swc1 $f0, -0x7FE9($at)\n" - "sw $t8, -0x7FE5($at)\n" - "aui $at, $a0, 0x1\n" - "mfhc1 $t8, $f0\n" - "swc1 $f0, 0x7FE9($at)\n" - "sw $t8, 0x7FED($at)\n" - "aui $at, $a0, 0x1\n" - "sdc1 $f0, 0x7FF0($at)\n" - "aui $at, $a0, 0x1234\n" - "sdc1 $f0, 0x5678($at)\n"; - DriverStr(expected, "StoreDToOffset"); -} - -TEST_F(AssemblerMIPS32r6Test, StoreQToOffset) { - __ StoreQToOffset(mips::F0, mips::A0, 0); - __ StoreQToOffset(mips::F0, mips::A0, 1); - __ StoreQToOffset(mips::F0, mips::A0, 2); - __ StoreQToOffset(mips::F0, mips::A0, 4); - __ StoreQToOffset(mips::F0, mips::A0, 8); - __ StoreQToOffset(mips::F0, mips::A0, 511); - __ StoreQToOffset(mips::F0, mips::A0, 512); - __ StoreQToOffset(mips::F0, mips::A0, 513); - __ StoreQToOffset(mips::F0, mips::A0, 514); - __ StoreQToOffset(mips::F0, mips::A0, 516); - __ StoreQToOffset(mips::F0, mips::A0, 1022); - __ StoreQToOffset(mips::F0, mips::A0, 1024); - __ StoreQToOffset(mips::F0, mips::A0, 1025); - __ StoreQToOffset(mips::F0, mips::A0, 1026); - __ StoreQToOffset(mips::F0, mips::A0, 1028); - __ StoreQToOffset(mips::F0, mips::A0, 2044); - __ StoreQToOffset(mips::F0, mips::A0, 2048); - __ StoreQToOffset(mips::F0, mips::A0, 2049); - __ StoreQToOffset(mips::F0, mips::A0, 2050); - __ StoreQToOffset(mips::F0, mips::A0, 2052); - __ StoreQToOffset(mips::F0, mips::A0, 4088); - __ StoreQToOffset(mips::F0, mips::A0, 4096); - __ StoreQToOffset(mips::F0, mips::A0, 4097); - __ StoreQToOffset(mips::F0, mips::A0, 4098); - __ StoreQToOffset(mips::F0, mips::A0, 4100); - __ StoreQToOffset(mips::F0, mips::A0, 4104); - __ StoreQToOffset(mips::F0, mips::A0, 0x7FFC); - __ StoreQToOffset(mips::F0, mips::A0, 0x8000); - __ StoreQToOffset(mips::F0, mips::A0, 0x10000); - __ StoreQToOffset(mips::F0, mips::A0, 0x12345678); - __ StoreQToOffset(mips::F0, mips::A0, 0x12350078); - __ StoreQToOffset(mips::F0, mips::A0, -256); - __ StoreQToOffset(mips::F0, mips::A0, -511); - __ StoreQToOffset(mips::F0, mips::A0, -513); - __ StoreQToOffset(mips::F0, mips::A0, -1022); - __ StoreQToOffset(mips::F0, mips::A0, -1026); - __ StoreQToOffset(mips::F0, mips::A0, -2044); - __ StoreQToOffset(mips::F0, mips::A0, -2052); - __ StoreQToOffset(mips::F0, mips::A0, -4096); - __ StoreQToOffset(mips::F0, mips::A0, -4104); - __ StoreQToOffset(mips::F0, mips::A0, -32768); - __ StoreQToOffset(mips::F0, mips::A0, 0xABCDEF00); - __ StoreQToOffset(mips::F0, mips::A0, 0x7FFFABCD); - - const char* expected = - "st.d $w0, 0($a0)\n" - "st.b $w0, 1($a0)\n" - "st.h $w0, 2($a0)\n" - "st.w $w0, 4($a0)\n" - "st.d $w0, 8($a0)\n" - "st.b $w0, 511($a0)\n" - "st.d $w0, 512($a0)\n" - "addiu $at, $a0, 513\n" - "st.b $w0, 0($at)\n" - "st.h $w0, 514($a0)\n" - "st.w $w0, 516($a0)\n" - "st.h $w0, 1022($a0)\n" - "st.d $w0, 1024($a0)\n" - "addiu $at, $a0, 1025\n" - "st.b $w0, 0($at)\n" - "addiu $at, $a0, 1026\n" - "st.h $w0, 0($at)\n" - "st.w $w0, 1028($a0)\n" - "st.w $w0, 2044($a0)\n" - "st.d $w0, 2048($a0)\n" - "addiu $at, $a0, 2049\n" - "st.b $w0, 0($at)\n" - "addiu $at, $a0, 2050\n" - "st.h $w0, 0($at)\n" - "addiu $at, $a0, 2052\n" - "st.w $w0, 0($at)\n" - "st.d $w0, 4088($a0)\n" - "addiu $at, $a0, 4096\n" - "st.d $w0, 0($at)\n" - "addiu $at, $a0, 4097\n" - "st.b $w0, 0($at)\n" - "addiu $at, $a0, 4098\n" - "st.h $w0, 0($at)\n" - "addiu $at, $a0, 4100\n" - "st.w $w0, 0($at)\n" - "addiu $at, $a0, 4104\n" - "st.d $w0, 0($at)\n" - "addiu $at, $a0, 0x7FFC\n" - "st.w $w0, 0($at)\n" - "addiu $at, $a0, 0x7FF8\n" - "st.d $w0, 8($at)\n" - "aui $at, $a0, 0x1\n" - "st.d $w0, 0($at)\n" - "aui $at, $a0, 0x1234\n" - "addiu $at, $at, 0x6000\n" - "st.d $w0, -2440($at) # 0xF678\n" - "aui $at, $a0, 0x1235\n" - "st.d $w0, 0x78($at)\n" - "st.d $w0, -256($a0)\n" - "st.b $w0, -511($a0)\n" - "addiu $at, $a0, -513\n" - "st.b $w0, 0($at)\n" - "st.h $w0, -1022($a0)\n" - "addiu $at, $a0, -1026\n" - "st.h $w0, 0($at)\n" - "st.w $w0, -2044($a0)\n" - "addiu $at, $a0, -2052\n" - "st.w $w0, 0($at)\n" - "st.d $w0, -4096($a0)\n" - "addiu $at, $a0, -4104\n" - "st.d $w0, 0($at)\n" - "addiu $at, $a0, -32768\n" - "st.d $w0, 0($at)\n" - "aui $at, $a0, 0xABCE\n" - "addiu $at, $at, -8192 # 0xE000\n" - "st.d $w0, 0xF00($at)\n" - "aui $at, $a0, 0x8000\n" - "addiu $at, $at, -21504 # 0xAC00\n" - "st.b $w0, -51($at) # 0xFFCD\n"; - DriverStr(expected, "StoreQToOffset"); -} - -////////////// -// BRANCHES // -////////////// - -TEST_F(AssemblerMIPS32r6Test, Bc) { - BranchHelper(&mips::MipsAssembler::Bc, "Bc", /* has_slot= */ false); -} - -TEST_F(AssemblerMIPS32r6Test, Balc) { - BranchHelper(&mips::MipsAssembler::Balc, "Balc", /* has_slot= */ false); -} - -TEST_F(AssemblerMIPS32r6Test, Beqc) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Beqc, "Beqc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bnec) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bnec, "Bnec"); -} - -TEST_F(AssemblerMIPS32r6Test, Beqzc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Beqzc, "Beqzc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bnezc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bnezc, "Bnezc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bltzc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bltzc, "Bltzc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bgezc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgezc, "Bgezc"); -} - -TEST_F(AssemblerMIPS32r6Test, Blezc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Blezc, "Blezc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bgtzc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgtzc, "Bgtzc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bltc) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltc, "Bltc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bgec) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgec, "Bgec"); -} - -TEST_F(AssemblerMIPS32r6Test, Bltuc) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltuc, "Bltuc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bgeuc) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeuc, "Bgeuc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bc1eqz) { - BranchFpuCondHelper(&mips::MipsAssembler::Bc1eqz, "Bc1eqz"); -} - -TEST_F(AssemblerMIPS32r6Test, Bc1nez) { - BranchFpuCondHelper(&mips::MipsAssembler::Bc1nez, "Bc1nez"); -} - -TEST_F(AssemblerMIPS32r6Test, B) { - BranchHelper(&mips::MipsAssembler::B, "Bc", /* has_slot= */ false); -} - -TEST_F(AssemblerMIPS32r6Test, Bal) { - BranchHelper(&mips::MipsAssembler::Bal, "Balc", /* has_slot= */ false); -} - -TEST_F(AssemblerMIPS32r6Test, Beq) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Beq, "Beqc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bne) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bne, "Bnec"); -} - -TEST_F(AssemblerMIPS32r6Test, Beqz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Beqz, "Beqzc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bnez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bnez, "Bnezc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bltz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bltz, "Bltzc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bgez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgez, "Bgezc"); -} - -TEST_F(AssemblerMIPS32r6Test, Blez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Blez, "Blezc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bgtz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgtz, "Bgtzc"); -} - -TEST_F(AssemblerMIPS32r6Test, Blt) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Blt, "Bltc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bge) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bge, "Bgec"); -} - -TEST_F(AssemblerMIPS32r6Test, Bltu) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltu, "Bltuc"); -} - -TEST_F(AssemblerMIPS32r6Test, Bgeu) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeu, "Bgeuc"); -} - -TEST_F(AssemblerMIPS32r6Test, BareBc) { - BranchHelper(&mips::MipsAssembler::Bc, "Bc", /* has_slot= */ false, /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBalc) { - BranchHelper(&mips::MipsAssembler::Balc, "Balc", /* has_slot= */ false, /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBeqc) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Beqc, "Beqc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBnec) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bnec, "Bnec", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBeqzc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Beqzc, "Beqzc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBnezc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bnezc, "Bnezc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBltzc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bltzc, "Bltzc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBgezc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgezc, "Bgezc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBlezc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Blezc, "Blezc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBgtzc) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgtzc, "Bgtzc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBltc) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltc, "Bltc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBgec) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgec, "Bgec", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBltuc) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltuc, "Bltuc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBgeuc) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeuc, "Bgeuc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBc1eqz) { - BranchFpuCondHelper(&mips::MipsAssembler::Bc1eqz, "Bc1eqz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBc1nez) { - BranchFpuCondHelper(&mips::MipsAssembler::Bc1nez, "Bc1nez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareB) { - BranchHelper(&mips::MipsAssembler::B, "B", /* has_slot= */ true, /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBal) { - BranchHelper(&mips::MipsAssembler::Bal, "Bal", /* has_slot= */ true, /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBeq) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Beq, "Beq", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBne) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bne, "Bne", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBeqz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Beqz, "Beqz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBnez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bnez, "Bnez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBltz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bltz, "Bltz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBgez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgez, "Bgez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBlez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Blez, "Blez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBgtz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgtz, "Bgtz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBlt) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Blt, "Blt", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBge) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bge, "Bge", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBltu) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltu, "Bltu", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, BareBgeu) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeu, "Bgeu", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS32r6Test, LongBeqc) { - mips::MipsLabel label; - __ Beqc(mips::A0, mips::A1, &label); - constexpr uint32_t kAdduCount1 = (1u << 15) + 1; - for (uint32_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr uint32_t kAdduCount2 = (1u << 15) + 1; - for (uint32_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Beqc(mips::A2, mips::A3, &label); - - uint32_t offset_forward = 2 + kAdduCount1; // 2: account for auipc and jic. - offset_forward <<= 2; - offset_forward += (offset_forward & 0x8000) << 1; // Account for sign extension in jic. - - uint32_t offset_back = -(kAdduCount2 + 1); // 1: account for bnec. - offset_back <<= 2; - offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic. - - std::ostringstream oss; - oss << - ".set noreorder\n" - "bnec $a0, $a1, 1f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_forward) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_forward) << "\n" - "1:\n" << - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") << - "2:\n" << - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") << - "bnec $a2, $a3, 3f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n" - "3:\n"; - std::string expected = oss.str(); - DriverStr(expected, "LongBeqc"); -} - -TEST_F(AssemblerMIPS32r6Test, LongBeqzc) { - constexpr uint32_t kNopCount1 = (1u << 20) + 1; - constexpr uint32_t kNopCount2 = (1u << 20) + 1; - constexpr uint32_t kRequiredCapacity = (kNopCount1 + kNopCount2 + 6u) * 4u; - ASSERT_LT(__ GetBuffer()->Capacity(), kRequiredCapacity); - __ GetBuffer()->ExtendCapacity(kRequiredCapacity); - mips::MipsLabel label; - __ Beqzc(mips::A0, &label); - for (uint32_t i = 0; i != kNopCount1; ++i) { - __ Nop(); - } - __ Bind(&label); - for (uint32_t i = 0; i != kNopCount2; ++i) { - __ Nop(); - } - __ Beqzc(mips::A2, &label); - - uint32_t offset_forward = 2 + kNopCount1; // 2: account for auipc and jic. - offset_forward <<= 2; - offset_forward += (offset_forward & 0x8000) << 1; // Account for sign extension in jic. - - uint32_t offset_back = -(kNopCount2 + 1); // 1: account for bnezc. - offset_back <<= 2; - offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic. - - // Note, we're using the ".fill" directive to tell the assembler to generate many NOPs - // instead of generating them ourselves in the source code. This saves test time. - std::ostringstream oss; - oss << - ".set noreorder\n" - "bnezc $a0, 1f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_forward) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_forward) << "\n" - "1:\n" << - ".fill 0x" << std::hex << kNopCount1 << " , 4, 0\n" - "2:\n" << - ".fill 0x" << std::hex << kNopCount2 << " , 4, 0\n" - "bnezc $a2, 3f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n" - "3:\n"; - std::string expected = oss.str(); - DriverStr(expected, "LongBeqzc"); -} - -TEST_F(AssemblerMIPS32r6Test, LongBc) { - constexpr uint32_t kNopCount1 = (1u << 25) + 1; - constexpr uint32_t kNopCount2 = (1u << 25) + 1; - constexpr uint32_t kRequiredCapacity = (kNopCount1 + kNopCount2 + 6u) * 4u; - ASSERT_LT(__ GetBuffer()->Capacity(), kRequiredCapacity); - __ GetBuffer()->ExtendCapacity(kRequiredCapacity); - mips::MipsLabel label1, label2; - __ Bc(&label1); - for (uint32_t i = 0; i != kNopCount1; ++i) { - __ Nop(); - } - __ Bind(&label1); - __ Bc(&label2); - for (uint32_t i = 0; i != kNopCount2; ++i) { - __ Nop(); - } - __ Bind(&label2); - __ Bc(&label1); - - uint32_t offset_forward1 = 2 + kNopCount1; // 2: account for auipc and jic. - offset_forward1 <<= 2; - offset_forward1 += (offset_forward1 & 0x8000) << 1; // Account for sign extension in jic. - - uint32_t offset_forward2 = 2 + kNopCount2; // 2: account for auipc and jic. - offset_forward2 <<= 2; - offset_forward2 += (offset_forward2 & 0x8000) << 1; // Account for sign extension in jic. - - uint32_t offset_back = -(2 + kNopCount2); // 2: account for auipc and jic. - offset_back <<= 2; - offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic. - - // Note, we're using the ".fill" directive to tell the assembler to generate many NOPs - // instead of generating them ourselves in the source code. This saves a few minutes - // of test time. - std::ostringstream oss; - oss << - ".set noreorder\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_forward1) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_forward1) << "\n" - ".fill 0x" << std::hex << kNopCount1 << " , 4, 0\n" - "1:\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_forward2) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_forward2) << "\n" - ".fill 0x" << std::hex << kNopCount2 << " , 4, 0\n" - "2:\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n"; - std::string expected = oss.str(); - DriverStr(expected, "LongBc"); -} - -TEST_F(AssemblerMIPS32r6Test, ImpossibleReordering) { - mips::MipsLabel label; - __ SetReorder(true); - __ Bind(&label); - - __ CmpLtD(mips::F0, mips::F2, mips::F4); - __ Bc1nez(mips::F0, &label); // F0 dependency. - - __ MulD(mips::F10, mips::F2, mips::F4); - __ Bc1eqz(mips::F10, &label); // F10 dependency. - - std::string expected = - ".set noreorder\n" - "1:\n" - - "cmp.lt.d $f0, $f2, $f4\n" - "bc1nez $f0, 1b\n" - "nop\n" - - "mul.d $f10, $f2, $f4\n" - "bc1eqz $f10, 1b\n" - "nop\n"; - DriverStr(expected, "ImpossibleReordering"); -} - -TEST_F(AssemblerMIPS32r6Test, Reordering) { - mips::MipsLabel label; - __ SetReorder(true); - __ Bind(&label); - - __ CmpLtD(mips::F0, mips::F2, mips::F4); - __ Bc1nez(mips::F2, &label); - - __ MulD(mips::F0, mips::F2, mips::F4); - __ Bc1eqz(mips::F4, &label); - - std::string expected = - ".set noreorder\n" - "1:\n" - - "bc1nez $f2, 1b\n" - "cmp.lt.d $f0, $f2, $f4\n" - - "bc1eqz $f4, 1b\n" - "mul.d $f0, $f2, $f4\n"; - DriverStr(expected, "Reordering"); -} - -TEST_F(AssemblerMIPS32r6Test, SetReorder) { - mips::MipsLabel label1, label2, label3, label4; - - __ SetReorder(true); - __ Bind(&label1); - __ Addu(mips::T0, mips::T1, mips::T2); - __ Bc1nez(mips::F0, &label1); - - __ SetReorder(false); - __ Bind(&label2); - __ Addu(mips::T0, mips::T1, mips::T2); - __ Bc1nez(mips::F0, &label2); - - __ SetReorder(true); - __ Bind(&label3); - __ Addu(mips::T0, mips::T1, mips::T2); - __ Bc1eqz(mips::F0, &label3); - - __ SetReorder(false); - __ Bind(&label4); - __ Addu(mips::T0, mips::T1, mips::T2); - __ Bc1eqz(mips::F0, &label4); - - std::string expected = - ".set noreorder\n" - "1:\n" - "bc1nez $f0, 1b\n" - "addu $t0, $t1, $t2\n" - - "2:\n" - "addu $t0, $t1, $t2\n" - "bc1nez $f0, 2b\n" - "nop\n" - - "3:\n" - "bc1eqz $f0, 3b\n" - "addu $t0, $t1, $t2\n" - - "4:\n" - "addu $t0, $t1, $t2\n" - "bc1eqz $f0, 4b\n" - "nop\n"; - DriverStr(expected, "SetReorder"); -} - -TEST_F(AssemblerMIPS32r6Test, ReorderPatchedInstruction) { - __ SetReorder(true); - mips::MipsLabel label1, label2; - mips::MipsLabel patcher_label1, patcher_label2, patcher_label3, patcher_label4, patcher_label5; - __ Lw(mips::V0, mips::A0, 0x5678, &patcher_label1); - __ Bc1eqz(mips::F0, &label1); - constexpr uint32_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label1); - __ Sw(mips::V0, mips::A0, 0x5678, &patcher_label2); - __ Bc1nez(mips::F2, &label2); - constexpr uint32_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label2); - __ Addiu(mips::V0, mips::A0, 0x5678, &patcher_label3); - __ Bc1eqz(mips::F4, &label1); - __ Lw(mips::V0, mips::A0, 0x5678, &patcher_label4); - __ Jalr(mips::T9); - __ Sw(mips::V0, mips::A0, 0x5678, &patcher_label5); - __ Bltc(mips::V0, mips::V1, &label2); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" - "bc1eqz $f0, 1f\n" - "lw $v0, 0x5678($a0)\n" + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" - "bc1nez $f2, 2f\n" - "sw $v0, 0x5678($a0)\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "2:\n" - "bc1eqz $f4, 1b\n" - "addiu $v0, $a0, 0x5678\n" - "jalr $t9\n" - "lw $v0, 0x5678($a0)\n" - "sw $v0, 0x5678($a0)\n" - "bltc $v0, $v1, 2b\n" - "nop\n" - "addu $zero, $zero, $zero\n"; - DriverStr(expected, "ReorderPatchedInstruction"); - EXPECT_EQ(__ GetLabelLocation(&patcher_label1), 1 * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label2), (kAdduCount1 + 3) * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label3), (kAdduCount1 + kAdduCount2 + 5) * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label4), (kAdduCount1 + kAdduCount2 + 7) * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label5), (kAdduCount1 + kAdduCount2 + 8) * 4u); -} - -TEST_F(AssemblerMIPS32r6Test, LongBranchReorder) { - mips::MipsLabel label, patcher_label1, patcher_label2; - __ SetReorder(true); - __ Addiu(mips::T0, mips::T1, 0x5678, &patcher_label1); - __ Bc1nez(mips::F0, &label); - constexpr uint32_t kAdduCount1 = (1u << 15) + 1; - for (uint32_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr uint32_t kAdduCount2 = (1u << 15) + 1; - for (uint32_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Addiu(mips::T0, mips::T1, 0x5678, &patcher_label2); - __ Bc1eqz(mips::F0, &label); - - uint32_t offset_forward = 2 + kAdduCount1; // 2: account for auipc and jic. - offset_forward <<= 2; - offset_forward += (offset_forward & 0x8000) << 1; // Account for sign extension in jic. - - uint32_t offset_back = -(kAdduCount2 + 2); // 2: account for subu and bc1nez. - offset_back <<= 2; - offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic. - - std::ostringstream oss; - oss << - ".set noreorder\n" - "addiu $t0, $t1, 0x5678\n" - "bc1eqz $f0, 1f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_forward) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_forward) << "\n" - "1:\n" << - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") << - "2:\n" << - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") << - "addiu $t0, $t1, 0x5678\n" - "bc1nez $f0, 3f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n" - "3:\n"; - std::string expected = oss.str(); - DriverStr(expected, "LongBranchReorder"); - EXPECT_EQ(__ GetLabelLocation(&patcher_label1), 0 * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label2), (kAdduCount1 + kAdduCount2 + 4) * 4u); -} - -/////////////////////// -// Loading Constants // -/////////////////////// - -TEST_F(AssemblerMIPS32r6Test, LoadFarthestNearLabelAddress) { - mips::MipsLabel label; - __ LoadLabelAddress(mips::V0, mips::ZERO, &label); - constexpr size_t kAdduCount = 0x3FFDE; - for (size_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - - std::string expected = - "lapc $v0, 1f\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "1:\n"; - DriverStr(expected, "LoadFarthestNearLabelAddress"); -} - -TEST_F(AssemblerMIPS32r6Test, LoadNearestFarLabelAddress) { - mips::MipsLabel label; - __ LoadLabelAddress(mips::V0, mips::ZERO, &label); - constexpr size_t kAdduCount = 0x3FFDF; - for (size_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - - std::string expected = - "1:\n" - "auipc $at, %hi(2f - 1b)\n" - "addiu $v0, $at, %lo(2f - 1b)\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n"; - DriverStr(expected, "LoadNearestFarLabelAddress"); -} - -TEST_F(AssemblerMIPS32r6Test, LoadFarthestNearLiteral) { - mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ LoadLiteral(mips::V0, mips::ZERO, literal); - constexpr size_t kAdduCount = 0x3FFDE; - for (size_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - - std::string expected = - "lwpc $v0, 1f\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "1:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadFarthestNearLiteral"); -} - -TEST_F(AssemblerMIPS32r6Test, LoadNearestFarLiteral) { - mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ LoadLiteral(mips::V0, mips::ZERO, literal); - constexpr size_t kAdduCount = 0x3FFDF; - for (size_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - - std::string expected = - "1:\n" - "auipc $at, %hi(2f - 1b)\n" - "lw $v0, %lo(2f - 1b)($at)\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadNearestFarLiteral"); -} - -// MSA instructions. - -TEST_F(AssemblerMIPS32r6Test, AndV) { - DriverStr(RepeatVVV(&mips::MipsAssembler::AndV, "and.v ${reg1}, ${reg2}, ${reg3}"), "and.v"); -} - -TEST_F(AssemblerMIPS32r6Test, OrV) { - DriverStr(RepeatVVV(&mips::MipsAssembler::OrV, "or.v ${reg1}, ${reg2}, ${reg3}"), "or.v"); -} - -TEST_F(AssemblerMIPS32r6Test, NorV) { - DriverStr(RepeatVVV(&mips::MipsAssembler::NorV, "nor.v ${reg1}, ${reg2}, ${reg3}"), "nor.v"); -} - -TEST_F(AssemblerMIPS32r6Test, XorV) { - DriverStr(RepeatVVV(&mips::MipsAssembler::XorV, "xor.v ${reg1}, ${reg2}, ${reg3}"), "xor.v"); -} - -TEST_F(AssemblerMIPS32r6Test, AddvB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::AddvB, "addv.b ${reg1}, ${reg2}, ${reg3}"), "addv.b"); -} - -TEST_F(AssemblerMIPS32r6Test, AddvH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::AddvH, "addv.h ${reg1}, ${reg2}, ${reg3}"), "addv.h"); -} - -TEST_F(AssemblerMIPS32r6Test, AddvW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::AddvW, "addv.w ${reg1}, ${reg2}, ${reg3}"), "addv.w"); -} - -TEST_F(AssemblerMIPS32r6Test, AddvD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::AddvD, "addv.d ${reg1}, ${reg2}, ${reg3}"), "addv.d"); -} - -TEST_F(AssemblerMIPS32r6Test, SubvB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SubvB, "subv.b ${reg1}, ${reg2}, ${reg3}"), "subv.b"); -} - -TEST_F(AssemblerMIPS32r6Test, SubvH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SubvH, "subv.h ${reg1}, ${reg2}, ${reg3}"), "subv.h"); -} - -TEST_F(AssemblerMIPS32r6Test, SubvW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SubvW, "subv.w ${reg1}, ${reg2}, ${reg3}"), "subv.w"); -} - -TEST_F(AssemblerMIPS32r6Test, SubvD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SubvD, "subv.d ${reg1}, ${reg2}, ${reg3}"), "subv.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Asub_sB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Asub_sB, "asub_s.b ${reg1}, ${reg2}, ${reg3}"), - "asub_s.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Asub_sH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Asub_sH, "asub_s.h ${reg1}, ${reg2}, ${reg3}"), - "asub_s.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Asub_sW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Asub_sW, "asub_s.w ${reg1}, ${reg2}, ${reg3}"), - "asub_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Asub_sD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Asub_sD, "asub_s.d ${reg1}, ${reg2}, ${reg3}"), - "asub_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Asub_uB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Asub_uB, "asub_u.b ${reg1}, ${reg2}, ${reg3}"), - "asub_u.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Asub_uH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Asub_uH, "asub_u.h ${reg1}, ${reg2}, ${reg3}"), - "asub_u.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Asub_uW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Asub_uW, "asub_u.w ${reg1}, ${reg2}, ${reg3}"), - "asub_u.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Asub_uD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Asub_uD, "asub_u.d ${reg1}, ${reg2}, ${reg3}"), - "asub_u.d"); -} - -TEST_F(AssemblerMIPS32r6Test, MulvB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MulvB, "mulv.b ${reg1}, ${reg2}, ${reg3}"), "mulv.b"); -} - -TEST_F(AssemblerMIPS32r6Test, MulvH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MulvH, "mulv.h ${reg1}, ${reg2}, ${reg3}"), "mulv.h"); -} - -TEST_F(AssemblerMIPS32r6Test, MulvW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MulvW, "mulv.w ${reg1}, ${reg2}, ${reg3}"), "mulv.w"); -} - -TEST_F(AssemblerMIPS32r6Test, MulvD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MulvD, "mulv.d ${reg1}, ${reg2}, ${reg3}"), "mulv.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Div_sB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Div_sB, "div_s.b ${reg1}, ${reg2}, ${reg3}"), - "div_s.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Div_sH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Div_sH, "div_s.h ${reg1}, ${reg2}, ${reg3}"), - "div_s.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Div_sW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Div_sW, "div_s.w ${reg1}, ${reg2}, ${reg3}"), - "div_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Div_sD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Div_sD, "div_s.d ${reg1}, ${reg2}, ${reg3}"), - "div_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Div_uB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Div_uB, "div_u.b ${reg1}, ${reg2}, ${reg3}"), - "div_u.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Div_uH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Div_uH, "div_u.h ${reg1}, ${reg2}, ${reg3}"), - "div_u.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Div_uW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Div_uW, "div_u.w ${reg1}, ${reg2}, ${reg3}"), - "div_u.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Div_uD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Div_uD, "div_u.d ${reg1}, ${reg2}, ${reg3}"), - "div_u.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Mod_sB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Mod_sB, "mod_s.b ${reg1}, ${reg2}, ${reg3}"), - "mod_s.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Mod_sH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Mod_sH, "mod_s.h ${reg1}, ${reg2}, ${reg3}"), - "mod_s.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Mod_sW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Mod_sW, "mod_s.w ${reg1}, ${reg2}, ${reg3}"), - "mod_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Mod_sD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Mod_sD, "mod_s.d ${reg1}, ${reg2}, ${reg3}"), - "mod_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Mod_uB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Mod_uB, "mod_u.b ${reg1}, ${reg2}, ${reg3}"), - "mod_u.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Mod_uH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Mod_uH, "mod_u.h ${reg1}, ${reg2}, ${reg3}"), - "mod_u.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Mod_uW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Mod_uW, "mod_u.w ${reg1}, ${reg2}, ${reg3}"), - "mod_u.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Mod_uD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Mod_uD, "mod_u.d ${reg1}, ${reg2}, ${reg3}"), - "mod_u.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Add_aB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Add_aB, "add_a.b ${reg1}, ${reg2}, ${reg3}"), - "add_a.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Add_aH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Add_aH, "add_a.h ${reg1}, ${reg2}, ${reg3}"), - "add_a.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Add_aW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Add_aW, "add_a.w ${reg1}, ${reg2}, ${reg3}"), - "add_a.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Add_aD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Add_aD, "add_a.d ${reg1}, ${reg2}, ${reg3}"), - "add_a.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Ave_sB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Ave_sB, "ave_s.b ${reg1}, ${reg2}, ${reg3}"), - "ave_s.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Ave_sH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Ave_sH, "ave_s.h ${reg1}, ${reg2}, ${reg3}"), - "ave_s.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Ave_sW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Ave_sW, "ave_s.w ${reg1}, ${reg2}, ${reg3}"), - "ave_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Ave_sD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Ave_sD, "ave_s.d ${reg1}, ${reg2}, ${reg3}"), - "ave_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Ave_uB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Ave_uB, "ave_u.b ${reg1}, ${reg2}, ${reg3}"), - "ave_u.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Ave_uH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Ave_uH, "ave_u.h ${reg1}, ${reg2}, ${reg3}"), - "ave_u.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Ave_uW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Ave_uW, "ave_u.w ${reg1}, ${reg2}, ${reg3}"), - "ave_u.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Ave_uD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Ave_uD, "ave_u.d ${reg1}, ${reg2}, ${reg3}"), - "ave_u.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Aver_sB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Aver_sB, "aver_s.b ${reg1}, ${reg2}, ${reg3}"), - "aver_s.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Aver_sH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Aver_sH, "aver_s.h ${reg1}, ${reg2}, ${reg3}"), - "aver_s.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Aver_sW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Aver_sW, "aver_s.w ${reg1}, ${reg2}, ${reg3}"), - "aver_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Aver_sD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Aver_sD, "aver_s.d ${reg1}, ${reg2}, ${reg3}"), - "aver_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Aver_uB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Aver_uB, "aver_u.b ${reg1}, ${reg2}, ${reg3}"), - "aver_u.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Aver_uH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Aver_uH, "aver_u.h ${reg1}, ${reg2}, ${reg3}"), - "aver_u.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Aver_uW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Aver_uW, "aver_u.w ${reg1}, ${reg2}, ${reg3}"), - "aver_u.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Aver_uD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Aver_uD, "aver_u.d ${reg1}, ${reg2}, ${reg3}"), - "aver_u.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Max_sB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Max_sB, "max_s.b ${reg1}, ${reg2}, ${reg3}"), - "max_s.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Max_sH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Max_sH, "max_s.h ${reg1}, ${reg2}, ${reg3}"), - "max_s.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Max_sW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Max_sW, "max_s.w ${reg1}, ${reg2}, ${reg3}"), - "max_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Max_sD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Max_sD, "max_s.d ${reg1}, ${reg2}, ${reg3}"), - "max_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Max_uB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Max_uB, "max_u.b ${reg1}, ${reg2}, ${reg3}"), - "max_u.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Max_uH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Max_uH, "max_u.h ${reg1}, ${reg2}, ${reg3}"), - "max_u.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Max_uW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Max_uW, "max_u.w ${reg1}, ${reg2}, ${reg3}"), - "max_u.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Max_uD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Max_uD, "max_u.d ${reg1}, ${reg2}, ${reg3}"), - "max_u.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Min_sB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Min_sB, "min_s.b ${reg1}, ${reg2}, ${reg3}"), - "min_s.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Min_sH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Min_sH, "min_s.h ${reg1}, ${reg2}, ${reg3}"), - "min_s.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Min_sW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Min_sW, "min_s.w ${reg1}, ${reg2}, ${reg3}"), - "min_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Min_sD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Min_sD, "min_s.d ${reg1}, ${reg2}, ${reg3}"), - "min_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Min_uB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Min_uB, "min_u.b ${reg1}, ${reg2}, ${reg3}"), - "min_u.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Min_uH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Min_uH, "min_u.h ${reg1}, ${reg2}, ${reg3}"), - "min_u.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Min_uW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Min_uW, "min_u.w ${reg1}, ${reg2}, ${reg3}"), - "min_u.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Min_uD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Min_uD, "min_u.d ${reg1}, ${reg2}, ${reg3}"), - "min_u.d"); -} - -TEST_F(AssemblerMIPS32r6Test, FaddW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FaddW, "fadd.w ${reg1}, ${reg2}, ${reg3}"), "fadd.w"); -} - -TEST_F(AssemblerMIPS32r6Test, FaddD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FaddD, "fadd.d ${reg1}, ${reg2}, ${reg3}"), "fadd.d"); -} - -TEST_F(AssemblerMIPS32r6Test, FsubW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FsubW, "fsub.w ${reg1}, ${reg2}, ${reg3}"), "fsub.w"); -} - -TEST_F(AssemblerMIPS32r6Test, FsubD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FsubD, "fsub.d ${reg1}, ${reg2}, ${reg3}"), "fsub.d"); -} - -TEST_F(AssemblerMIPS32r6Test, FmulW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FmulW, "fmul.w ${reg1}, ${reg2}, ${reg3}"), "fmul.w"); -} - -TEST_F(AssemblerMIPS32r6Test, FmulD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FmulD, "fmul.d ${reg1}, ${reg2}, ${reg3}"), "fmul.d"); -} - -TEST_F(AssemblerMIPS32r6Test, FdivW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FdivW, "fdiv.w ${reg1}, ${reg2}, ${reg3}"), "fdiv.w"); -} - -TEST_F(AssemblerMIPS32r6Test, FdivD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FdivD, "fdiv.d ${reg1}, ${reg2}, ${reg3}"), "fdiv.d"); -} - -TEST_F(AssemblerMIPS32r6Test, FmaxW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FmaxW, "fmax.w ${reg1}, ${reg2}, ${reg3}"), "fmax.w"); -} - -TEST_F(AssemblerMIPS32r6Test, FmaxD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FmaxD, "fmax.d ${reg1}, ${reg2}, ${reg3}"), "fmax.d"); -} - -TEST_F(AssemblerMIPS32r6Test, FminW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FminW, "fmin.w ${reg1}, ${reg2}, ${reg3}"), "fmin.w"); -} - -TEST_F(AssemblerMIPS32r6Test, FminD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FminD, "fmin.d ${reg1}, ${reg2}, ${reg3}"), "fmin.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Ffint_sW) { - DriverStr(RepeatVV(&mips::MipsAssembler::Ffint_sW, "ffint_s.w ${reg1}, ${reg2}"), "ffint_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Ffint_sD) { - DriverStr(RepeatVV(&mips::MipsAssembler::Ffint_sD, "ffint_s.d ${reg1}, ${reg2}"), "ffint_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Ftint_sW) { - DriverStr(RepeatVV(&mips::MipsAssembler::Ftint_sW, "ftint_s.w ${reg1}, ${reg2}"), "ftint_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Ftint_sD) { - DriverStr(RepeatVV(&mips::MipsAssembler::Ftint_sD, "ftint_s.d ${reg1}, ${reg2}"), "ftint_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, SllB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SllB, "sll.b ${reg1}, ${reg2}, ${reg3}"), "sll.b"); -} - -TEST_F(AssemblerMIPS32r6Test, SllH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SllH, "sll.h ${reg1}, ${reg2}, ${reg3}"), "sll.h"); -} - -TEST_F(AssemblerMIPS32r6Test, SllW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SllW, "sll.w ${reg1}, ${reg2}, ${reg3}"), "sll.w"); -} - -TEST_F(AssemblerMIPS32r6Test, SllD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SllD, "sll.d ${reg1}, ${reg2}, ${reg3}"), "sll.d"); -} - -TEST_F(AssemblerMIPS32r6Test, SraB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SraB, "sra.b ${reg1}, ${reg2}, ${reg3}"), "sra.b"); -} - -TEST_F(AssemblerMIPS32r6Test, SraH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SraH, "sra.h ${reg1}, ${reg2}, ${reg3}"), "sra.h"); -} - -TEST_F(AssemblerMIPS32r6Test, SraW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SraW, "sra.w ${reg1}, ${reg2}, ${reg3}"), "sra.w"); -} - -TEST_F(AssemblerMIPS32r6Test, SraD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SraD, "sra.d ${reg1}, ${reg2}, ${reg3}"), "sra.d"); -} - -TEST_F(AssemblerMIPS32r6Test, SrlB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SrlB, "srl.b ${reg1}, ${reg2}, ${reg3}"), "srl.b"); -} - -TEST_F(AssemblerMIPS32r6Test, SrlH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SrlH, "srl.h ${reg1}, ${reg2}, ${reg3}"), "srl.h"); -} - -TEST_F(AssemblerMIPS32r6Test, SrlW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SrlW, "srl.w ${reg1}, ${reg2}, ${reg3}"), "srl.w"); -} - -TEST_F(AssemblerMIPS32r6Test, SrlD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::SrlD, "srl.d ${reg1}, ${reg2}, ${reg3}"), "srl.d"); -} - -TEST_F(AssemblerMIPS32r6Test, SlliB) { - DriverStr(RepeatVVIb(&mips::MipsAssembler::SlliB, 3, "slli.b ${reg1}, ${reg2}, {imm}"), "slli.b"); -} - -TEST_F(AssemblerMIPS32r6Test, SlliH) { - DriverStr(RepeatVVIb(&mips::MipsAssembler::SlliH, 4, "slli.h ${reg1}, ${reg2}, {imm}"), "slli.h"); -} - -TEST_F(AssemblerMIPS32r6Test, SlliW) { - DriverStr(RepeatVVIb(&mips::MipsAssembler::SlliW, 5, "slli.w ${reg1}, ${reg2}, {imm}"), "slli.w"); -} - -TEST_F(AssemblerMIPS32r6Test, SlliD) { - DriverStr(RepeatVVIb(&mips::MipsAssembler::SlliD, 6, "slli.d ${reg1}, ${reg2}, {imm}"), "slli.d"); -} - -TEST_F(AssemblerMIPS32r6Test, MoveV) { - DriverStr(RepeatVV(&mips::MipsAssembler::MoveV, "move.v ${reg1}, ${reg2}"), "move.v"); -} - -TEST_F(AssemblerMIPS32r6Test, SplatiB) { - DriverStr(RepeatVVIb(&mips::MipsAssembler::SplatiB, 4, "splati.b ${reg1}, ${reg2}[{imm}]"), - "splati.b"); -} - -TEST_F(AssemblerMIPS32r6Test, SplatiH) { - DriverStr(RepeatVVIb(&mips::MipsAssembler::SplatiH, 3, "splati.h ${reg1}, ${reg2}[{imm}]"), - "splati.h"); -} - -TEST_F(AssemblerMIPS32r6Test, SplatiW) { - DriverStr(RepeatVVIb(&mips::MipsAssembler::SplatiW, 2, "splati.w ${reg1}, ${reg2}[{imm}]"), - "splati.w"); -} - -TEST_F(AssemblerMIPS32r6Test, SplatiD) { - DriverStr(RepeatVVIb(&mips::MipsAssembler::SplatiD, 1, "splati.d ${reg1}, ${reg2}[{imm}]"), - "splati.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Copy_sB) { - DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_sB, 4, "copy_s.b ${reg1}, ${reg2}[{imm}]"), - "copy_s.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Copy_sH) { - DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_sH, 3, "copy_s.h ${reg1}, ${reg2}[{imm}]"), - "copy_s.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Copy_sW) { - DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_sW, 2, "copy_s.w ${reg1}, ${reg2}[{imm}]"), - "copy_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Copy_uB) { - DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_uB, 4, "copy_u.b ${reg1}, ${reg2}[{imm}]"), - "copy_u.b"); -} - -TEST_F(AssemblerMIPS32r6Test, Copy_uH) { - DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_uH, 3, "copy_u.h ${reg1}, ${reg2}[{imm}]"), - "copy_u.h"); -} - -TEST_F(AssemblerMIPS32r6Test, InsertB) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::InsertB, 4, "insert.b ${reg1}[{imm}], ${reg2}"), - "insert.b"); -} - -TEST_F(AssemblerMIPS32r6Test, InsertH) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::InsertH, 3, "insert.h ${reg1}[{imm}], ${reg2}"), - "insert.h"); -} - -TEST_F(AssemblerMIPS32r6Test, InsertW) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::InsertW, 2, "insert.w ${reg1}[{imm}], ${reg2}"), - "insert.w"); -} - -TEST_F(AssemblerMIPS32r6Test, FillB) { - DriverStr(RepeatVR(&mips::MipsAssembler::FillB, "fill.b ${reg1}, ${reg2}"), "fill.b"); -} - -TEST_F(AssemblerMIPS32r6Test, FillH) { - DriverStr(RepeatVR(&mips::MipsAssembler::FillH, "fill.h ${reg1}, ${reg2}"), "fill.h"); -} - -TEST_F(AssemblerMIPS32r6Test, FillW) { - DriverStr(RepeatVR(&mips::MipsAssembler::FillW, "fill.w ${reg1}, ${reg2}"), "fill.w"); -} - -TEST_F(AssemblerMIPS32r6Test, PcntB) { - DriverStr(RepeatVV(&mips::MipsAssembler::PcntB, "pcnt.b ${reg1}, ${reg2}"), "pcnt.b"); -} - -TEST_F(AssemblerMIPS32r6Test, PcntH) { - DriverStr(RepeatVV(&mips::MipsAssembler::PcntH, "pcnt.h ${reg1}, ${reg2}"), "pcnt.h"); -} - -TEST_F(AssemblerMIPS32r6Test, PcntW) { - DriverStr(RepeatVV(&mips::MipsAssembler::PcntW, "pcnt.w ${reg1}, ${reg2}"), "pcnt.w"); -} - -TEST_F(AssemblerMIPS32r6Test, PcntD) { - DriverStr(RepeatVV(&mips::MipsAssembler::PcntD, "pcnt.d ${reg1}, ${reg2}"), "pcnt.d"); -} - -TEST_F(AssemblerMIPS32r6Test, LdiB) { - DriverStr(RepeatVIb(&mips::MipsAssembler::LdiB, -8, "ldi.b ${reg}, {imm}"), "ldi.b"); -} - -TEST_F(AssemblerMIPS32r6Test, LdiH) { - DriverStr(RepeatVIb(&mips::MipsAssembler::LdiH, -10, "ldi.h ${reg}, {imm}"), "ldi.h"); -} - -TEST_F(AssemblerMIPS32r6Test, LdiW) { - DriverStr(RepeatVIb(&mips::MipsAssembler::LdiW, -10, "ldi.w ${reg}, {imm}"), "ldi.w"); -} - -TEST_F(AssemblerMIPS32r6Test, LdiD) { - DriverStr(RepeatVIb(&mips::MipsAssembler::LdiD, -10, "ldi.d ${reg}, {imm}"), "ldi.d"); -} - -TEST_F(AssemblerMIPS32r6Test, LdB) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::LdB, -10, "ld.b ${reg1}, {imm}(${reg2})"), "ld.b"); -} - -TEST_F(AssemblerMIPS32r6Test, LdH) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::LdH, -10, "ld.h ${reg1}, {imm}(${reg2})", 0, 2), - "ld.h"); -} - -TEST_F(AssemblerMIPS32r6Test, LdW) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::LdW, -10, "ld.w ${reg1}, {imm}(${reg2})", 0, 4), - "ld.w"); -} - -TEST_F(AssemblerMIPS32r6Test, LdD) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::LdD, -10, "ld.d ${reg1}, {imm}(${reg2})", 0, 8), - "ld.d"); -} - -TEST_F(AssemblerMIPS32r6Test, StB) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::StB, -10, "st.b ${reg1}, {imm}(${reg2})"), "st.b"); -} - -TEST_F(AssemblerMIPS32r6Test, StH) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::StH, -10, "st.h ${reg1}, {imm}(${reg2})", 0, 2), - "st.h"); -} - -TEST_F(AssemblerMIPS32r6Test, StW) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::StW, -10, "st.w ${reg1}, {imm}(${reg2})", 0, 4), - "st.w"); -} - -TEST_F(AssemblerMIPS32r6Test, StD) { - DriverStr(RepeatVRIb(&mips::MipsAssembler::StD, -10, "st.d ${reg1}, {imm}(${reg2})", 0, 8), - "st.d"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvlB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvlB, "ilvl.b ${reg1}, ${reg2}, ${reg3}"), "ilvl.b"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvlH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvlH, "ilvl.h ${reg1}, ${reg2}, ${reg3}"), "ilvl.h"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvlW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvlW, "ilvl.w ${reg1}, ${reg2}, ${reg3}"), "ilvl.w"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvlD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvlD, "ilvl.d ${reg1}, ${reg2}, ${reg3}"), "ilvl.d"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvrB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvrB, "ilvr.b ${reg1}, ${reg2}, ${reg3}"), "ilvr.b"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvrH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvrH, "ilvr.h ${reg1}, ${reg2}, ${reg3}"), "ilvr.h"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvrW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvrW, "ilvr.w ${reg1}, ${reg2}, ${reg3}"), "ilvr.w"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvrD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvrD, "ilvr.d ${reg1}, ${reg2}, ${reg3}"), "ilvr.d"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvevB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvevB, "ilvev.b ${reg1}, ${reg2}, ${reg3}"), - "ilvev.b"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvevH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvevH, "ilvev.h ${reg1}, ${reg2}, ${reg3}"), - "ilvev.h"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvevW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvevW, "ilvev.w ${reg1}, ${reg2}, ${reg3}"), - "ilvev.w"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvevD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvevD, "ilvev.d ${reg1}, ${reg2}, ${reg3}"), - "ilvev.d"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvodB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvodB, "ilvod.b ${reg1}, ${reg2}, ${reg3}"), - "ilvod.b"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvodH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvodH, "ilvod.h ${reg1}, ${reg2}, ${reg3}"), - "ilvod.h"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvodW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvodW, "ilvod.w ${reg1}, ${reg2}, ${reg3}"), - "ilvod.w"); -} - -TEST_F(AssemblerMIPS32r6Test, IlvodD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::IlvodD, "ilvod.d ${reg1}, ${reg2}, ${reg3}"), - "ilvod.d"); -} - -TEST_F(AssemblerMIPS32r6Test, MaddvB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MaddvB, "maddv.b ${reg1}, ${reg2}, ${reg3}"), - "maddv.b"); -} - -TEST_F(AssemblerMIPS32r6Test, MaddvH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MaddvH, "maddv.h ${reg1}, ${reg2}, ${reg3}"), - "maddv.h"); -} - -TEST_F(AssemblerMIPS32r6Test, MaddvW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MaddvW, "maddv.w ${reg1}, ${reg2}, ${reg3}"), - "maddv.w"); -} - -TEST_F(AssemblerMIPS32r6Test, MaddvD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MaddvD, "maddv.d ${reg1}, ${reg2}, ${reg3}"), - "maddv.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Hadd_sH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_sH, "hadd_s.h ${reg1}, ${reg2}, ${reg3}"), - "hadd_s.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Hadd_sW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_sW, "hadd_s.w ${reg1}, ${reg2}, ${reg3}"), - "hadd_s.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Hadd_sD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_sD, "hadd_s.d ${reg1}, ${reg2}, ${reg3}"), - "hadd_s.d"); -} - -TEST_F(AssemblerMIPS32r6Test, Hadd_uH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_uH, "hadd_u.h ${reg1}, ${reg2}, ${reg3}"), - "hadd_u.h"); -} - -TEST_F(AssemblerMIPS32r6Test, Hadd_uW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_uW, "hadd_u.w ${reg1}, ${reg2}, ${reg3}"), - "hadd_u.w"); -} - -TEST_F(AssemblerMIPS32r6Test, Hadd_uD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_uD, "hadd_u.d ${reg1}, ${reg2}, ${reg3}"), - "hadd_u.d"); -} - -TEST_F(AssemblerMIPS32r6Test, MsubvB) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MsubvB, "msubv.b ${reg1}, ${reg2}, ${reg3}"), - "msubv.b"); -} - -TEST_F(AssemblerMIPS32r6Test, MsubvH) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MsubvH, "msubv.h ${reg1}, ${reg2}, ${reg3}"), - "msubv.h"); -} - -TEST_F(AssemblerMIPS32r6Test, MsubvW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MsubvW, "msubv.w ${reg1}, ${reg2}, ${reg3}"), - "msubv.w"); -} - -TEST_F(AssemblerMIPS32r6Test, MsubvD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::MsubvD, "msubv.d ${reg1}, ${reg2}, ${reg3}"), - "msubv.d"); -} - -TEST_F(AssemblerMIPS32r6Test, FmaddW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FmaddW, "fmadd.w ${reg1}, ${reg2}, ${reg3}"), - "fmadd.w"); -} - -TEST_F(AssemblerMIPS32r6Test, FmaddD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FmaddD, "fmadd.d ${reg1}, ${reg2}, ${reg3}"), - "fmadd.d"); -} - -TEST_F(AssemblerMIPS32r6Test, FmsubW) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FmsubW, "fmsub.w ${reg1}, ${reg2}, ${reg3}"), - "fmsub.w"); -} - -TEST_F(AssemblerMIPS32r6Test, FmsubD) { - DriverStr(RepeatVVV(&mips::MipsAssembler::FmsubD, "fmsub.d ${reg1}, ${reg2}, ${reg3}"), - "fmsub.d"); -} - -#undef __ - -} // namespace art diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc deleted file mode 100644 index c0894d309e..0000000000 --- a/compiler/utils/mips/assembler_mips_test.cc +++ /dev/null @@ -1,3046 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "assembler_mips.h" - -#include <map> - -#include "base/stl_util.h" -#include "utils/assembler_test.h" - -#define __ GetAssembler()-> - -namespace art { - -struct MIPSCpuRegisterCompare { - bool operator()(const mips::Register& a, const mips::Register& b) const { - return a < b; - } -}; - -class AssemblerMIPSTest : public AssemblerTest<mips::MipsAssembler, - mips::MipsLabel, - mips::Register, - mips::FRegister, - uint32_t> { - public: - using Base = AssemblerTest<mips::MipsAssembler, - mips::MipsLabel, - mips::Register, - mips::FRegister, - uint32_t>; - - // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<> - // and reimplement it without the verification against `assembly_string`. b/73903608 - void DriverStr(const std::string& assembly_string ATTRIBUTE_UNUSED, - const std::string& test_name ATTRIBUTE_UNUSED) { - GetAssembler()->FinalizeCode(); - std::vector<uint8_t> data(GetAssembler()->CodeSize()); - MemoryRegion code(data.data(), data.size()); - GetAssembler()->FinalizeInstructions(code); - } - - protected: - // Get the typically used name for this architecture, e.g., aarch64, x86-64, ... - std::string GetArchitectureString() override { - return "mips"; - } - - std::string GetAssemblerParameters() override { - return " --no-warn -32 -march=mips32r2"; - } - - std::string GetDisassembleParameters() override { - return " -D -bbinary -mmips:isa32r2"; - } - - void SetUpHelpers() override { - if (registers_.size() == 0) { - registers_.push_back(new mips::Register(mips::ZERO)); - registers_.push_back(new mips::Register(mips::AT)); - registers_.push_back(new mips::Register(mips::V0)); - registers_.push_back(new mips::Register(mips::V1)); - registers_.push_back(new mips::Register(mips::A0)); - registers_.push_back(new mips::Register(mips::A1)); - registers_.push_back(new mips::Register(mips::A2)); - registers_.push_back(new mips::Register(mips::A3)); - registers_.push_back(new mips::Register(mips::T0)); - registers_.push_back(new mips::Register(mips::T1)); - registers_.push_back(new mips::Register(mips::T2)); - registers_.push_back(new mips::Register(mips::T3)); - registers_.push_back(new mips::Register(mips::T4)); - registers_.push_back(new mips::Register(mips::T5)); - registers_.push_back(new mips::Register(mips::T6)); - registers_.push_back(new mips::Register(mips::T7)); - registers_.push_back(new mips::Register(mips::S0)); - registers_.push_back(new mips::Register(mips::S1)); - registers_.push_back(new mips::Register(mips::S2)); - registers_.push_back(new mips::Register(mips::S3)); - registers_.push_back(new mips::Register(mips::S4)); - registers_.push_back(new mips::Register(mips::S5)); - registers_.push_back(new mips::Register(mips::S6)); - registers_.push_back(new mips::Register(mips::S7)); - registers_.push_back(new mips::Register(mips::T8)); - registers_.push_back(new mips::Register(mips::T9)); - registers_.push_back(new mips::Register(mips::K0)); - registers_.push_back(new mips::Register(mips::K1)); - registers_.push_back(new mips::Register(mips::GP)); - registers_.push_back(new mips::Register(mips::SP)); - registers_.push_back(new mips::Register(mips::FP)); - registers_.push_back(new mips::Register(mips::RA)); - - secondary_register_names_.emplace(mips::Register(mips::ZERO), "zero"); - secondary_register_names_.emplace(mips::Register(mips::AT), "at"); - secondary_register_names_.emplace(mips::Register(mips::V0), "v0"); - secondary_register_names_.emplace(mips::Register(mips::V1), "v1"); - secondary_register_names_.emplace(mips::Register(mips::A0), "a0"); - secondary_register_names_.emplace(mips::Register(mips::A1), "a1"); - secondary_register_names_.emplace(mips::Register(mips::A2), "a2"); - secondary_register_names_.emplace(mips::Register(mips::A3), "a3"); - secondary_register_names_.emplace(mips::Register(mips::T0), "t0"); - secondary_register_names_.emplace(mips::Register(mips::T1), "t1"); - secondary_register_names_.emplace(mips::Register(mips::T2), "t2"); - secondary_register_names_.emplace(mips::Register(mips::T3), "t3"); - secondary_register_names_.emplace(mips::Register(mips::T4), "t4"); - secondary_register_names_.emplace(mips::Register(mips::T5), "t5"); - secondary_register_names_.emplace(mips::Register(mips::T6), "t6"); - secondary_register_names_.emplace(mips::Register(mips::T7), "t7"); - secondary_register_names_.emplace(mips::Register(mips::S0), "s0"); - secondary_register_names_.emplace(mips::Register(mips::S1), "s1"); - secondary_register_names_.emplace(mips::Register(mips::S2), "s2"); - secondary_register_names_.emplace(mips::Register(mips::S3), "s3"); - secondary_register_names_.emplace(mips::Register(mips::S4), "s4"); - secondary_register_names_.emplace(mips::Register(mips::S5), "s5"); - secondary_register_names_.emplace(mips::Register(mips::S6), "s6"); - secondary_register_names_.emplace(mips::Register(mips::S7), "s7"); - secondary_register_names_.emplace(mips::Register(mips::T8), "t8"); - secondary_register_names_.emplace(mips::Register(mips::T9), "t9"); - secondary_register_names_.emplace(mips::Register(mips::K0), "k0"); - secondary_register_names_.emplace(mips::Register(mips::K1), "k1"); - secondary_register_names_.emplace(mips::Register(mips::GP), "gp"); - secondary_register_names_.emplace(mips::Register(mips::SP), "sp"); - secondary_register_names_.emplace(mips::Register(mips::FP), "fp"); - secondary_register_names_.emplace(mips::Register(mips::RA), "ra"); - - fp_registers_.push_back(new mips::FRegister(mips::F0)); - fp_registers_.push_back(new mips::FRegister(mips::F1)); - fp_registers_.push_back(new mips::FRegister(mips::F2)); - fp_registers_.push_back(new mips::FRegister(mips::F3)); - fp_registers_.push_back(new mips::FRegister(mips::F4)); - fp_registers_.push_back(new mips::FRegister(mips::F5)); - fp_registers_.push_back(new mips::FRegister(mips::F6)); - fp_registers_.push_back(new mips::FRegister(mips::F7)); - fp_registers_.push_back(new mips::FRegister(mips::F8)); - fp_registers_.push_back(new mips::FRegister(mips::F9)); - fp_registers_.push_back(new mips::FRegister(mips::F10)); - fp_registers_.push_back(new mips::FRegister(mips::F11)); - fp_registers_.push_back(new mips::FRegister(mips::F12)); - fp_registers_.push_back(new mips::FRegister(mips::F13)); - fp_registers_.push_back(new mips::FRegister(mips::F14)); - fp_registers_.push_back(new mips::FRegister(mips::F15)); - fp_registers_.push_back(new mips::FRegister(mips::F16)); - fp_registers_.push_back(new mips::FRegister(mips::F17)); - fp_registers_.push_back(new mips::FRegister(mips::F18)); - fp_registers_.push_back(new mips::FRegister(mips::F19)); - fp_registers_.push_back(new mips::FRegister(mips::F20)); - fp_registers_.push_back(new mips::FRegister(mips::F21)); - fp_registers_.push_back(new mips::FRegister(mips::F22)); - fp_registers_.push_back(new mips::FRegister(mips::F23)); - fp_registers_.push_back(new mips::FRegister(mips::F24)); - fp_registers_.push_back(new mips::FRegister(mips::F25)); - fp_registers_.push_back(new mips::FRegister(mips::F26)); - fp_registers_.push_back(new mips::FRegister(mips::F27)); - fp_registers_.push_back(new mips::FRegister(mips::F28)); - fp_registers_.push_back(new mips::FRegister(mips::F29)); - fp_registers_.push_back(new mips::FRegister(mips::F30)); - fp_registers_.push_back(new mips::FRegister(mips::F31)); - } - } - - void TearDown() override { - AssemblerTest::TearDown(); - STLDeleteElements(®isters_); - STLDeleteElements(&fp_registers_); - } - - std::vector<mips::MipsLabel> GetAddresses() override { - UNIMPLEMENTED(FATAL) << "Feature not implemented yet"; - UNREACHABLE(); - } - - std::vector<mips::Register*> GetRegisters() override { - return registers_; - } - - std::vector<mips::FRegister*> GetFPRegisters() override { - return fp_registers_; - } - - uint32_t CreateImmediate(int64_t imm_value) override { - return imm_value; - } - - std::string GetSecondaryRegisterName(const mips::Register& reg) override { - CHECK(secondary_register_names_.find(reg) != secondary_register_names_.end()); - return secondary_register_names_[reg]; - } - - std::string RepeatInsn(size_t count, const std::string& insn) { - std::string result; - for (; count != 0u; --count) { - result += insn; - } - return result; - } - - void BranchHelper(void (mips::MipsAssembler::*f)(mips::MipsLabel*, - bool), - const std::string& instr_name, - bool is_bare = false) { - __ SetReorder(false); - mips::MipsLabel label1, label2; - (Base::GetAssembler()->*f)(&label1, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label1); - (Base::GetAssembler()->*f)(&label2, is_bare); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label2); - (Base::GetAssembler()->*f)(&label1, is_bare); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - instr_name + " 2f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "2:\n" + - instr_name + " 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - void BranchCondOneRegHelper(void (mips::MipsAssembler::*f)(mips::Register, - mips::MipsLabel*, - bool), - const std::string& instr_name, - bool is_bare = false) { - __ SetReorder(false); - mips::MipsLabel label; - (Base::GetAssembler()->*f)(mips::A0, &label, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - (Base::GetAssembler()->*f)(mips::A1, &label, is_bare); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " $a0, 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - instr_name + " $a1, 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - void BranchCondTwoRegsHelper(void (mips::MipsAssembler::*f)(mips::Register, - mips::Register, - mips::MipsLabel*, - bool), - const std::string& instr_name, - bool is_bare = false) { - __ SetReorder(false); - mips::MipsLabel label; - (Base::GetAssembler()->*f)(mips::A0, mips::A1, &label, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - (Base::GetAssembler()->*f)(mips::A2, mips::A3, &label, is_bare); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " $a0, $a1, 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - instr_name + " $a2, $a3, 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - void BranchFpuCondCodeHelper(void (mips::MipsAssembler::*f)(int, - mips::MipsLabel*, - bool), - const std::string& instr_name, - bool is_bare = false) { - __ SetReorder(false); - mips::MipsLabel label; - (Base::GetAssembler()->*f)(0, &label, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - (Base::GetAssembler()->*f)(7, &label, is_bare); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " $fcc0, 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - instr_name + " $fcc7, 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - private: - std::vector<mips::Register*> registers_; - std::map<mips::Register, std::string, MIPSCpuRegisterCompare> secondary_register_names_; - - std::vector<mips::FRegister*> fp_registers_; -}; - - -TEST_F(AssemblerMIPSTest, Toolchain) { - EXPECT_TRUE(CheckTools()); -} - -TEST_F(AssemblerMIPSTest, Addu) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Addu, "addu ${reg1}, ${reg2}, ${reg3}"), "Addu"); -} - -TEST_F(AssemblerMIPSTest, Addiu) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Addiu, -16, "addiu ${reg1}, ${reg2}, {imm}"), "Addiu"); -} - -TEST_F(AssemblerMIPSTest, Subu) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Subu, "subu ${reg1}, ${reg2}, ${reg3}"), "Subu"); -} - -TEST_F(AssemblerMIPSTest, MultR2) { - DriverStr(RepeatRR(&mips::MipsAssembler::MultR2, "mult ${reg1}, ${reg2}"), "MultR2"); -} - -TEST_F(AssemblerMIPSTest, MultuR2) { - DriverStr(RepeatRR(&mips::MipsAssembler::MultuR2, "multu ${reg1}, ${reg2}"), "MultuR2"); -} - -TEST_F(AssemblerMIPSTest, DivR2Basic) { - DriverStr(RepeatRR(&mips::MipsAssembler::DivR2, "div $zero, ${reg1}, ${reg2}"), "DivR2Basic"); -} - -TEST_F(AssemblerMIPSTest, DivuR2Basic) { - DriverStr(RepeatRR(&mips::MipsAssembler::DivuR2, "divu $zero, ${reg1}, ${reg2}"), "DivuR2Basic"); -} - -TEST_F(AssemblerMIPSTest, MulR2) { - DriverStr(RepeatRRR(&mips::MipsAssembler::MulR2, "mul ${reg1}, ${reg2}, ${reg3}"), "MulR2"); -} - -TEST_F(AssemblerMIPSTest, DivR2) { - DriverStr(RepeatRRR(&mips::MipsAssembler::DivR2, "div $zero, ${reg2}, ${reg3}\nmflo ${reg1}"), - "DivR2"); -} - -TEST_F(AssemblerMIPSTest, ModR2) { - DriverStr(RepeatRRR(&mips::MipsAssembler::ModR2, "div $zero, ${reg2}, ${reg3}\nmfhi ${reg1}"), - "ModR2"); -} - -TEST_F(AssemblerMIPSTest, DivuR2) { - DriverStr(RepeatRRR(&mips::MipsAssembler::DivuR2, "divu $zero, ${reg2}, ${reg3}\nmflo ${reg1}"), - "DivuR2"); -} - -TEST_F(AssemblerMIPSTest, ModuR2) { - DriverStr(RepeatRRR(&mips::MipsAssembler::ModuR2, "divu $zero, ${reg2}, ${reg3}\nmfhi ${reg1}"), - "ModuR2"); -} - -TEST_F(AssemblerMIPSTest, And) { - DriverStr(RepeatRRR(&mips::MipsAssembler::And, "and ${reg1}, ${reg2}, ${reg3}"), "And"); -} - -TEST_F(AssemblerMIPSTest, Andi) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Andi, 16, "andi ${reg1}, ${reg2}, {imm}"), "Andi"); -} - -TEST_F(AssemblerMIPSTest, Or) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Or, "or ${reg1}, ${reg2}, ${reg3}"), "Or"); -} - -TEST_F(AssemblerMIPSTest, Ori) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Ori, 16, "ori ${reg1}, ${reg2}, {imm}"), "Ori"); -} - -TEST_F(AssemblerMIPSTest, Xor) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Xor, "xor ${reg1}, ${reg2}, ${reg3}"), "Xor"); -} - -TEST_F(AssemblerMIPSTest, Xori) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Xori, 16, "xori ${reg1}, ${reg2}, {imm}"), "Xori"); -} - -TEST_F(AssemblerMIPSTest, Nor) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Nor, "nor ${reg1}, ${reg2}, ${reg3}"), "Nor"); -} - -////////// -// MISC // -////////// - -TEST_F(AssemblerMIPSTest, Movz) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Movz, "movz ${reg1}, ${reg2}, ${reg3}"), "Movz"); -} - -TEST_F(AssemblerMIPSTest, Movn) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Movn, "movn ${reg1}, ${reg2}, ${reg3}"), "Movn"); -} - -TEST_F(AssemblerMIPSTest, Seb) { - DriverStr(RepeatRR(&mips::MipsAssembler::Seb, "seb ${reg1}, ${reg2}"), "Seb"); -} - -TEST_F(AssemblerMIPSTest, Seh) { - DriverStr(RepeatRR(&mips::MipsAssembler::Seh, "seh ${reg1}, ${reg2}"), "Seh"); -} - -TEST_F(AssemblerMIPSTest, Sll) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Sll, 5, "sll ${reg1}, ${reg2}, {imm}"), "Sll"); -} - -TEST_F(AssemblerMIPSTest, Srl) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Srl, 5, "srl ${reg1}, ${reg2}, {imm}"), "Srl"); -} - -TEST_F(AssemblerMIPSTest, Sra) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Sra, 5, "sra ${reg1}, ${reg2}, {imm}"), "Sra"); -} - -TEST_F(AssemblerMIPSTest, Sllv) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Sllv, "sllv ${reg1}, ${reg2}, ${reg3}"), "Sllv"); -} - -TEST_F(AssemblerMIPSTest, Srlv) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Srlv, "srlv ${reg1}, ${reg2}, ${reg3}"), "Srlv"); -} - -TEST_F(AssemblerMIPSTest, Rotrv) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Rotrv, "rotrv ${reg1}, ${reg2}, ${reg3}"), "rotrv"); -} - -TEST_F(AssemblerMIPSTest, Srav) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Srav, "srav ${reg1}, ${reg2}, ${reg3}"), "Srav"); -} - -TEST_F(AssemblerMIPSTest, Ins) { - std::vector<mips::Register*> regs = GetRegisters(); - WarnOnCombinations(regs.size() * regs.size() * 33 * 16); - std::string expected; - for (mips::Register* reg1 : regs) { - for (mips::Register* reg2 : regs) { - for (int32_t pos = 0; pos < 32; pos++) { - for (int32_t size = 1; pos + size <= 32; size++) { - __ Ins(*reg1, *reg2, pos, size); - std::ostringstream instr; - instr << "ins $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n"; - expected += instr.str(); - } - } - } - } - DriverStr(expected, "Ins"); -} - -TEST_F(AssemblerMIPSTest, Ext) { - std::vector<mips::Register*> regs = GetRegisters(); - WarnOnCombinations(regs.size() * regs.size() * 33 * 16); - std::string expected; - for (mips::Register* reg1 : regs) { - for (mips::Register* reg2 : regs) { - for (int32_t pos = 0; pos < 32; pos++) { - for (int32_t size = 1; pos + size <= 32; size++) { - __ Ext(*reg1, *reg2, pos, size); - std::ostringstream instr; - instr << "ext $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n"; - expected += instr.str(); - } - } - } - } - DriverStr(expected, "Ext"); -} - -TEST_F(AssemblerMIPSTest, ClzR2) { - DriverStr(RepeatRR(&mips::MipsAssembler::ClzR2, "clz ${reg1}, ${reg2}"), "clzR2"); -} - -TEST_F(AssemblerMIPSTest, CloR2) { - DriverStr(RepeatRR(&mips::MipsAssembler::CloR2, "clo ${reg1}, ${reg2}"), "cloR2"); -} - -TEST_F(AssemblerMIPSTest, Lb) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Lb, -16, "lb ${reg1}, {imm}(${reg2})"), "Lb"); -} - -TEST_F(AssemblerMIPSTest, Lh) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Lh, -16, "lh ${reg1}, {imm}(${reg2})"), "Lh"); -} - -TEST_F(AssemblerMIPSTest, Lwl) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Lwl, -16, "lwl ${reg1}, {imm}(${reg2})"), "Lwl"); -} - -TEST_F(AssemblerMIPSTest, Lw) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Lw, -16, "lw ${reg1}, {imm}(${reg2})"), "Lw"); -} - -TEST_F(AssemblerMIPSTest, Lwr) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Lwr, -16, "lwr ${reg1}, {imm}(${reg2})"), "Lwr"); -} - -TEST_F(AssemblerMIPSTest, Lbu) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Lbu, -16, "lbu ${reg1}, {imm}(${reg2})"), "Lbu"); -} - -TEST_F(AssemblerMIPSTest, Lhu) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Lhu, -16, "lhu ${reg1}, {imm}(${reg2})"), "Lhu"); -} - -TEST_F(AssemblerMIPSTest, Lui) { - DriverStr(RepeatRIb(&mips::MipsAssembler::Lui, 16, "lui ${reg}, {imm}"), "Lui"); -} - -TEST_F(AssemblerMIPSTest, Mfhi) { - DriverStr(RepeatR(&mips::MipsAssembler::Mfhi, "mfhi ${reg}"), "Mfhi"); -} - -TEST_F(AssemblerMIPSTest, Mflo) { - DriverStr(RepeatR(&mips::MipsAssembler::Mflo, "mflo ${reg}"), "Mflo"); -} - -TEST_F(AssemblerMIPSTest, Sb) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Sb, -16, "sb ${reg1}, {imm}(${reg2})"), "Sb"); -} - -TEST_F(AssemblerMIPSTest, Sh) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Sh, -16, "sh ${reg1}, {imm}(${reg2})"), "Sh"); -} - -TEST_F(AssemblerMIPSTest, Swl) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Swl, -16, "swl ${reg1}, {imm}(${reg2})"), "Swl"); -} - -TEST_F(AssemblerMIPSTest, Sw) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Sw, -16, "sw ${reg1}, {imm}(${reg2})"), "Sw"); -} - -TEST_F(AssemblerMIPSTest, Swr) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Swr, -16, "swr ${reg1}, {imm}(${reg2})"), "Swr"); -} - -TEST_F(AssemblerMIPSTest, LlR2) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::LlR2, -16, "ll ${reg1}, {imm}(${reg2})"), "LlR2"); -} - -TEST_F(AssemblerMIPSTest, ScR2) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::ScR2, -16, "sc ${reg1}, {imm}(${reg2})"), "ScR2"); -} - -TEST_F(AssemblerMIPSTest, Slt) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Slt, "slt ${reg1}, ${reg2}, ${reg3}"), "Slt"); -} - -TEST_F(AssemblerMIPSTest, Sltu) { - DriverStr(RepeatRRR(&mips::MipsAssembler::Sltu, "sltu ${reg1}, ${reg2}, ${reg3}"), "Sltu"); -} - -TEST_F(AssemblerMIPSTest, Slti) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Slti, -16, "slti ${reg1}, ${reg2}, {imm}"), "Slti"); -} - -TEST_F(AssemblerMIPSTest, Sltiu) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Sltiu, -16, "sltiu ${reg1}, ${reg2}, {imm}"), "Sltiu"); -} - -TEST_F(AssemblerMIPSTest, AddS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::AddS, "add.s ${reg1}, ${reg2}, ${reg3}"), "AddS"); -} - -TEST_F(AssemblerMIPSTest, AddD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::AddD, "add.d ${reg1}, ${reg2}, ${reg3}"), "AddD"); -} - -TEST_F(AssemblerMIPSTest, SubS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::SubS, "sub.s ${reg1}, ${reg2}, ${reg3}"), "SubS"); -} - -TEST_F(AssemblerMIPSTest, SubD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::SubD, "sub.d ${reg1}, ${reg2}, ${reg3}"), "SubD"); -} - -TEST_F(AssemblerMIPSTest, MulS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::MulS, "mul.s ${reg1}, ${reg2}, ${reg3}"), "MulS"); -} - -TEST_F(AssemblerMIPSTest, MulD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::MulD, "mul.d ${reg1}, ${reg2}, ${reg3}"), "MulD"); -} - -TEST_F(AssemblerMIPSTest, DivS) { - DriverStr(RepeatFFF(&mips::MipsAssembler::DivS, "div.s ${reg1}, ${reg2}, ${reg3}"), "DivS"); -} - -TEST_F(AssemblerMIPSTest, DivD) { - DriverStr(RepeatFFF(&mips::MipsAssembler::DivD, "div.d ${reg1}, ${reg2}, ${reg3}"), "DivD"); -} - -TEST_F(AssemblerMIPSTest, MovS) { - DriverStr(RepeatFF(&mips::MipsAssembler::MovS, "mov.s ${reg1}, ${reg2}"), "MovS"); -} - -TEST_F(AssemblerMIPSTest, MovD) { - DriverStr(RepeatFF(&mips::MipsAssembler::MovD, "mov.d ${reg1}, ${reg2}"), "MovD"); -} - -TEST_F(AssemblerMIPSTest, NegS) { - DriverStr(RepeatFF(&mips::MipsAssembler::NegS, "neg.s ${reg1}, ${reg2}"), "NegS"); -} - -TEST_F(AssemblerMIPSTest, NegD) { - DriverStr(RepeatFF(&mips::MipsAssembler::NegD, "neg.d ${reg1}, ${reg2}"), "NegD"); -} - -TEST_F(AssemblerMIPSTest, FloorWS) { - DriverStr(RepeatFF(&mips::MipsAssembler::FloorWS, "floor.w.s ${reg1}, ${reg2}"), "floor.w.s"); -} - -TEST_F(AssemblerMIPSTest, FloorWD) { - DriverStr(RepeatFF(&mips::MipsAssembler::FloorWD, "floor.w.d ${reg1}, ${reg2}"), "floor.w.d"); -} - -TEST_F(AssemblerMIPSTest, CunS) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CunS, 3, "c.un.s $fcc{imm}, ${reg1}, ${reg2}"), - "CunS"); -} - -TEST_F(AssemblerMIPSTest, CeqS) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CeqS, 3, "c.eq.s $fcc{imm}, ${reg1}, ${reg2}"), - "CeqS"); -} - -TEST_F(AssemblerMIPSTest, CueqS) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CueqS, 3, "c.ueq.s $fcc{imm}, ${reg1}, ${reg2}"), - "CueqS"); -} - -TEST_F(AssemblerMIPSTest, ColtS) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::ColtS, 3, "c.olt.s $fcc{imm}, ${reg1}, ${reg2}"), - "ColtS"); -} - -TEST_F(AssemblerMIPSTest, CultS) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CultS, 3, "c.ult.s $fcc{imm}, ${reg1}, ${reg2}"), - "CultS"); -} - -TEST_F(AssemblerMIPSTest, ColeS) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::ColeS, 3, "c.ole.s $fcc{imm}, ${reg1}, ${reg2}"), - "ColeS"); -} - -TEST_F(AssemblerMIPSTest, CuleS) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CuleS, 3, "c.ule.s $fcc{imm}, ${reg1}, ${reg2}"), - "CuleS"); -} - -TEST_F(AssemblerMIPSTest, CunD) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CunD, 3, "c.un.d $fcc{imm}, ${reg1}, ${reg2}"), - "CunD"); -} - -TEST_F(AssemblerMIPSTest, CeqD) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CeqD, 3, "c.eq.d $fcc{imm}, ${reg1}, ${reg2}"), - "CeqD"); -} - -TEST_F(AssemblerMIPSTest, CueqD) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CueqD, 3, "c.ueq.d $fcc{imm}, ${reg1}, ${reg2}"), - "CueqD"); -} - -TEST_F(AssemblerMIPSTest, ColtD) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::ColtD, 3, "c.olt.d $fcc{imm}, ${reg1}, ${reg2}"), - "ColtD"); -} - -TEST_F(AssemblerMIPSTest, CultD) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CultD, 3, "c.ult.d $fcc{imm}, ${reg1}, ${reg2}"), - "CultD"); -} - -TEST_F(AssemblerMIPSTest, ColeD) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::ColeD, 3, "c.ole.d $fcc{imm}, ${reg1}, ${reg2}"), - "ColeD"); -} - -TEST_F(AssemblerMIPSTest, CuleD) { - DriverStr(RepeatIbFF(&mips::MipsAssembler::CuleD, 3, "c.ule.d $fcc{imm}, ${reg1}, ${reg2}"), - "CuleD"); -} - -TEST_F(AssemblerMIPSTest, Movf) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Movf, 3, "movf ${reg1}, ${reg2}, $fcc{imm}"), "Movf"); -} - -TEST_F(AssemblerMIPSTest, Movt) { - DriverStr(RepeatRRIb(&mips::MipsAssembler::Movt, 3, "movt ${reg1}, ${reg2}, $fcc{imm}"), "Movt"); -} - -TEST_F(AssemblerMIPSTest, MovfS) { - DriverStr(RepeatFFIb(&mips::MipsAssembler::MovfS, 3, "movf.s ${reg1}, ${reg2}, $fcc{imm}"), - "MovfS"); -} - -TEST_F(AssemblerMIPSTest, MovfD) { - DriverStr(RepeatFFIb(&mips::MipsAssembler::MovfD, 3, "movf.d ${reg1}, ${reg2}, $fcc{imm}"), - "MovfD"); -} - -TEST_F(AssemblerMIPSTest, MovtS) { - DriverStr(RepeatFFIb(&mips::MipsAssembler::MovtS, 3, "movt.s ${reg1}, ${reg2}, $fcc{imm}"), - "MovtS"); -} - -TEST_F(AssemblerMIPSTest, MovtD) { - DriverStr(RepeatFFIb(&mips::MipsAssembler::MovtD, 3, "movt.d ${reg1}, ${reg2}, $fcc{imm}"), - "MovtD"); -} - -TEST_F(AssemblerMIPSTest, MovzS) { - DriverStr(RepeatFFR(&mips::MipsAssembler::MovzS, "movz.s ${reg1}, ${reg2}, ${reg3}"), "MovzS"); -} - -TEST_F(AssemblerMIPSTest, MovzD) { - DriverStr(RepeatFFR(&mips::MipsAssembler::MovzD, "movz.d ${reg1}, ${reg2}, ${reg3}"), "MovzD"); -} - -TEST_F(AssemblerMIPSTest, MovnS) { - DriverStr(RepeatFFR(&mips::MipsAssembler::MovnS, "movn.s ${reg1}, ${reg2}, ${reg3}"), "MovnS"); -} - -TEST_F(AssemblerMIPSTest, MovnD) { - DriverStr(RepeatFFR(&mips::MipsAssembler::MovnD, "movn.d ${reg1}, ${reg2}, ${reg3}"), "MovnD"); -} - -TEST_F(AssemblerMIPSTest, CvtSW) { - DriverStr(RepeatFF(&mips::MipsAssembler::Cvtsw, "cvt.s.w ${reg1}, ${reg2}"), "CvtSW"); -} - -TEST_F(AssemblerMIPSTest, CvtDW) { - DriverStr(RepeatFF(&mips::MipsAssembler::Cvtdw, "cvt.d.w ${reg1}, ${reg2}"), "CvtDW"); -} - -TEST_F(AssemblerMIPSTest, CvtSL) { - DriverStr(RepeatFF(&mips::MipsAssembler::Cvtsl, "cvt.s.l ${reg1}, ${reg2}"), "CvtSL"); -} - -TEST_F(AssemblerMIPSTest, CvtDL) { - DriverStr(RepeatFF(&mips::MipsAssembler::Cvtdl, "cvt.d.l ${reg1}, ${reg2}"), "CvtDL"); -} - -TEST_F(AssemblerMIPSTest, CvtSD) { - DriverStr(RepeatFF(&mips::MipsAssembler::Cvtsd, "cvt.s.d ${reg1}, ${reg2}"), "CvtSD"); -} - -TEST_F(AssemblerMIPSTest, CvtDS) { - DriverStr(RepeatFF(&mips::MipsAssembler::Cvtds, "cvt.d.s ${reg1}, ${reg2}"), "CvtDS"); -} - -TEST_F(AssemblerMIPSTest, TruncWS) { - DriverStr(RepeatFF(&mips::MipsAssembler::TruncWS, "trunc.w.s ${reg1}, ${reg2}"), "TruncWS"); -} - -TEST_F(AssemblerMIPSTest, TruncWD) { - DriverStr(RepeatFF(&mips::MipsAssembler::TruncWD, "trunc.w.d ${reg1}, ${reg2}"), "TruncWD"); -} - -TEST_F(AssemblerMIPSTest, TruncLS) { - DriverStr(RepeatFF(&mips::MipsAssembler::TruncLS, "trunc.l.s ${reg1}, ${reg2}"), "TruncLS"); -} - -TEST_F(AssemblerMIPSTest, TruncLD) { - DriverStr(RepeatFF(&mips::MipsAssembler::TruncLD, "trunc.l.d ${reg1}, ${reg2}"), "TruncLD"); -} - -TEST_F(AssemblerMIPSTest, Mfc1) { - DriverStr(RepeatRF(&mips::MipsAssembler::Mfc1, "mfc1 ${reg1}, ${reg2}"), "Mfc1"); -} - -TEST_F(AssemblerMIPSTest, Mtc1) { - DriverStr(RepeatRF(&mips::MipsAssembler::Mtc1, "mtc1 ${reg1}, ${reg2}"), "Mtc1"); -} - -TEST_F(AssemblerMIPSTest, Mfhc1) { - DriverStr(RepeatRF(&mips::MipsAssembler::Mfhc1, "mfhc1 ${reg1}, ${reg2}"), "Mfhc1"); -} - -TEST_F(AssemblerMIPSTest, Mthc1) { - DriverStr(RepeatRF(&mips::MipsAssembler::Mthc1, "mthc1 ${reg1}, ${reg2}"), "Mthc1"); -} - -TEST_F(AssemblerMIPSTest, Lwc1) { - DriverStr(RepeatFRIb(&mips::MipsAssembler::Lwc1, -16, "lwc1 ${reg1}, {imm}(${reg2})"), "Lwc1"); -} - -TEST_F(AssemblerMIPSTest, Ldc1) { - DriverStr(RepeatFRIb(&mips::MipsAssembler::Ldc1, -16, "ldc1 ${reg1}, {imm}(${reg2})"), "Ldc1"); -} - -TEST_F(AssemblerMIPSTest, Swc1) { - DriverStr(RepeatFRIb(&mips::MipsAssembler::Swc1, -16, "swc1 ${reg1}, {imm}(${reg2})"), "Swc1"); -} - -TEST_F(AssemblerMIPSTest, Sdc1) { - DriverStr(RepeatFRIb(&mips::MipsAssembler::Sdc1, -16, "sdc1 ${reg1}, {imm}(${reg2})"), "Sdc1"); -} - -TEST_F(AssemblerMIPSTest, Move) { - DriverStr(RepeatRR(&mips::MipsAssembler::Move, "or ${reg1}, ${reg2}, $zero"), "Move"); -} - -TEST_F(AssemblerMIPSTest, Clear) { - DriverStr(RepeatR(&mips::MipsAssembler::Clear, "or ${reg}, $zero, $zero"), "Clear"); -} - -TEST_F(AssemblerMIPSTest, Not) { - DriverStr(RepeatRR(&mips::MipsAssembler::Not, "nor ${reg1}, ${reg2}, $zero"), "Not"); -} - -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 = - "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 $a1, $a2, $at\n" - "lui $at, 1\n" - "ori $at, $at, 1\n" - "addu $a1, $a2, $at\n" - "lui $at, 0x1234\n" - "ori $at, $at, 0x5678\n" - "addu $a1, $a2, $at\n"; - DriverStr(expected, "Addiu32"); -} - -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" - "lb $a3, 0($at)\n" - "lui $at, 0xFFFE\n" - "ori $at, $at, 0x8010\n" - "addu $at, $at, $a1\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, $at, 0x5678\n" - "addu $at, $at, $a1\n" - "lb $a3, 0($at)\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" - "lbu $a3, 0($at)\n" - "lui $at, 0xFFFE\n" - "ori $at, $at, 0x8010\n" - "addu $at, $at, $a1\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, $at, 0x5678\n" - "addu $at, $at, $a1\n" - "lbu $a3, 0($at)\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" - "lh $a3, 0($at)\n" - "lui $at, 0xFFFE\n" - "ori $at, $at, 0x8010\n" - "addu $at, $at, $a1\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, $at, 0x5678\n" - "addu $at, $at, $a1\n" - "lh $a3, 0($at)\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, 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, 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, $at, 0x5678\n" - "addu $at, $at, $a2\n" - "lw $a0, 0($at)\n" - "lw $a1, 4($at)\n"; - DriverStr(expected, "LoadFromOffset"); -} - -TEST_F(AssemblerMIPSTest, LoadSFromOffset) { - __ 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 $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 $f2, 0($at)\n" - "lui $at, 0xFFFE\n" - "ori $at, $at, 0x8010\n" - "addu $at, $at, $a0\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, $at, 0x5678\n" - "addu $at, $at, $a0\n" - "lwc1 $f2, 0($at)\n"; - DriverStr(expected, "LoadSFromOffset"); -} - -TEST_F(AssemblerMIPSTest, LoadDFromOffset) { - __ 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" - "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, 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, $at, 0x5678\n" - "addu $at, $at, $a0\n" - "ldc1 $f0, 0($at)\n"; - DriverStr(expected, "LoadDFromOffset"); -} - -TEST_F(AssemblerMIPSTest, StoreToOffset) { - __ 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::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::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, -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 $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 $a3, 0($at)\n" - "lui $at, 0xFFFE\n" - "ori $at, $at, 0x8010\n" - "addu $at, $at, $a1\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, $at, 0x5678\n" - "addu $at, $at, $a1\n" - "sb $a3, 0($at)\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 $a3, 0($at)\n" - "lui $at, 0xFFFE\n" - "ori $at, $at, 0x8010\n" - "addu $at, $at, $a1\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, $at, 0x5678\n" - "addu $at, $at, $a1\n" - "sh $a3, 0($at)\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 $a3, 0($at)\n" - "lui $at, 0xFFFE\n" - "ori $at, $at, 0x8010\n" - "addu $at, $at, $a1\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, $at, 0x5678\n" - "addu $at, $at, $a1\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, 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, 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, $at, 0x5678\n" - "addu $at, $at, $a2\n" - "sw $a0, 0($at)\n" - "sw $a1, 4($at)\n"; - DriverStr(expected, "StoreToOffset"); -} - -TEST_F(AssemblerMIPSTest, StoreSToOffset) { - __ 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 $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 $f2, 0($at)\n" - "lui $at, 0xFFFE\n" - "ori $at, $at, 0x8010\n" - "addu $at, $at, $a0\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, $at, 0x5678\n" - "addu $at, $at, $a0\n" - "swc1 $f2, 0($at)\n"; - DriverStr(expected, "StoreSToOffset"); -} - -TEST_F(AssemblerMIPSTest, StoreDToOffset) { - __ 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" - "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, 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, $at, 0x5678\n" - "addu $at, $at, $a0\n" - "sdc1 $f0, 0($at)\n"; - 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"); -} - -////////////// -// BRANCHES // -////////////// - -TEST_F(AssemblerMIPSTest, B) { - BranchHelper(&mips::MipsAssembler::B, "B"); -} - -TEST_F(AssemblerMIPSTest, Bal) { - BranchHelper(&mips::MipsAssembler::Bal, "Bal"); -} - -TEST_F(AssemblerMIPSTest, Beq) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Beq, "Beq"); -} - -TEST_F(AssemblerMIPSTest, Bne) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bne, "Bne"); -} - -TEST_F(AssemblerMIPSTest, Beqz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Beqz, "Beqz"); -} - -TEST_F(AssemblerMIPSTest, Bnez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bnez, "Bnez"); -} - -TEST_F(AssemblerMIPSTest, Bltz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bltz, "Bltz"); -} - -TEST_F(AssemblerMIPSTest, Bgez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgez, "Bgez"); -} - -TEST_F(AssemblerMIPSTest, Blez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Blez, "Blez"); -} - -TEST_F(AssemblerMIPSTest, Bgtz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgtz, "Bgtz"); -} - -TEST_F(AssemblerMIPSTest, Blt) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Blt, "Blt"); -} - -TEST_F(AssemblerMIPSTest, Bge) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bge, "Bge"); -} - -TEST_F(AssemblerMIPSTest, Bltu) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltu, "Bltu"); -} - -TEST_F(AssemblerMIPSTest, Bgeu) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeu, "Bgeu"); -} - -TEST_F(AssemblerMIPSTest, Bc1f) { - BranchFpuCondCodeHelper(&mips::MipsAssembler::Bc1f, "Bc1f"); -} - -TEST_F(AssemblerMIPSTest, Bc1t) { - BranchFpuCondCodeHelper(&mips::MipsAssembler::Bc1t, "Bc1t"); -} - -TEST_F(AssemblerMIPSTest, BareB) { - BranchHelper(&mips::MipsAssembler::B, "B", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBal) { - BranchHelper(&mips::MipsAssembler::Bal, "Bal", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBeq) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Beq, "Beq", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBne) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bne, "Bne", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBeqz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Beqz, "Beqz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBnez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bnez, "Bnez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBltz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bltz, "Bltz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBgez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgez, "Bgez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBlez) { - BranchCondOneRegHelper(&mips::MipsAssembler::Blez, "Blez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBgtz) { - BranchCondOneRegHelper(&mips::MipsAssembler::Bgtz, "Bgtz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBlt) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Blt, "Blt", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBge) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bge, "Bge", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBltu) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltu, "Bltu", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBgeu) { - BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeu, "Bgeu", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBc1f) { - BranchFpuCondCodeHelper(&mips::MipsAssembler::Bc1f, "Bc1f", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, BareBc1t) { - BranchFpuCondCodeHelper(&mips::MipsAssembler::Bc1t, "Bc1t", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPSTest, ImpossibleReordering) { - mips::MipsLabel label1, label2; - __ SetReorder(true); - - __ B(&label1); // No preceding or target instruction for the delay slot. - - __ Addu(mips::T0, mips::T1, mips::T2); - __ Bind(&label1); - __ B(&label1); // The preceding label prevents moving Addu into the delay slot. - __ B(&label1); // No preceding or target instruction for the delay slot. - - __ Addu(mips::T0, mips::T1, mips::T2); - __ Beqz(mips::T0, &label1); // T0 dependency. - - __ Or(mips::T1, mips::T2, mips::T3); - __ Bne(mips::T2, mips::T1, &label1); // T1 dependency. - - __ And(mips::T0, mips::T1, mips::T2); - __ Blt(mips::T1, mips::T0, &label1); // T0 dependency. - - __ Xor(mips::AT, mips::T0, mips::T1); - __ Bge(mips::T1, mips::T0, &label1); // AT dependency. - - __ Subu(mips::T0, mips::T1, mips::AT); - __ Bltu(mips::T1, mips::T0, &label1); // AT dependency. - - __ ColtS(1, mips::F2, mips::F4); - __ Bc1t(1, &label1); // cc1 dependency. - - __ Move(mips::T0, mips::RA); - __ Bal(&label1); // RA dependency. - - __ Lw(mips::RA, mips::T0, 0); - __ Bal(&label1); // RA dependency. - - __ LlR2(mips::T9, mips::T0, 0); - __ Jalr(mips::T9); // T9 dependency. - - __ Sw(mips::RA, mips::T0, 0); - __ Jalr(mips::T9); // RA dependency. - - __ Lw(mips::T1, mips::T0, 0); - __ Jalr(mips::T1, mips::T9); // T1 dependency. - - __ ScR2(mips::T9, mips::T0, 0); - __ Jr(mips::T9); // T9 dependency. - - __ Bind(&label2); - - __ Bnez(mips::T0, &label2); // No preceding instruction for the delay slot. - - __ Bgeu(mips::T1, mips::T0, &label2); // No preceding instruction for the delay slot. - - __ Bc1f(2, &label2); // No preceding instruction for the delay slot. - - __ Bal(&label2); // No preceding instruction for the delay slot. - - __ Jalr(mips::T9); // No preceding instruction for the delay slot. - - __ Addu(mips::T0, mips::T1, mips::T2); - __ CodePosition(); // Drops the delay slot candidate (the last instruction). - __ Beq(mips::T1, mips::T2, &label2); // No preceding or target instruction for the delay slot. - - std::string expected = - ".set noreorder\n" - "b 1f\n" - "nop\n" - - "addu $t0, $t1, $t2\n" - "1:\n" - "b 1b\n" - "nop\n" - "b 1b\n" - "nop\n" - - "addu $t0, $t1, $t2\n" - "beqz $t0, 1b\n" - "nop\n" - - "or $t1, $t2, $t3\n" - "bne $t2, $t1, 1b\n" - "nop\n" - - "and $t0, $t1, $t2\n" - "slt $at, $t1, $t0\n" - "bnez $at, 1b\n" - "nop\n" - - "xor $at, $t0, $t1\n" - "slt $at, $t1, $t0\n" - "beqz $at, 1b\n" - "nop\n" - - "subu $t0, $t1, $at\n" - "sltu $at, $t1, $t0\n" - "bnez $at, 1b\n" - "nop\n" - - "c.olt.s $fcc1, $f2, $f4\n" - "bc1t $fcc1, 1b\n" - "nop\n" - - "or $t0, $ra, $zero\n" - "bal 1b\n" - "nop\n" - - "lw $ra, 0($t0)\n" - "bal 1b\n" - "nop\n" - - "ll $t9, 0($t0)\n" - "jalr $t9\n" - "nop\n" - - "sw $ra, 0($t0)\n" - "jalr $t9\n" - "nop\n" - - "lw $t1, 0($t0)\n" - "jalr $t1, $t9\n" - "nop\n" - - "sc $t9, 0($t0)\n" - "jalr $zero, $t9\n" - "nop\n" - - "2:\n" - - "bnez $t0, 2b\n" - "nop\n" - - "sltu $at, $t1, $t0\n" - "beqz $at, 2b\n" - "nop\n" - - "bc1f $fcc2, 2b\n" - "nop\n" - - "bal 2b\n" - "nop\n" - - "jalr $t9\n" - "nop\n" - - "addu $t0, $t1, $t2\n" - "beq $t1, $t2, 2b\n" - "nop\n"; - DriverStr(expected, "ImpossibleReordering"); -} - -TEST_F(AssemblerMIPSTest, Reordering) { - mips::MipsLabel label1, label2; - __ SetReorder(true); - - __ Bind(&label1); - __ Bind(&label2); - - __ Addu(mips::T0, mips::T1, mips::T2); - __ Beqz(mips::T1, &label1); - - __ Or(mips::T1, mips::T2, mips::T3); - __ Bne(mips::T2, mips::T3, &label1); - - __ And(mips::T0, mips::T1, mips::T2); - __ Blt(mips::T1, mips::T2, &label1); - - __ Xor(mips::T2, mips::T0, mips::T1); - __ Bge(mips::T1, mips::T0, &label1); - - __ Subu(mips::T2, mips::T1, mips::T0); - __ Bltu(mips::T1, mips::T0, &label1); - - __ ColtS(0, mips::F2, mips::F4); - __ Bc1t(1, &label1); - - __ Move(mips::T0, mips::T1); - __ Bal(&label1); - - __ LlR2(mips::T1, mips::T0, 0); - __ Jalr(mips::T9); - - __ ScR2(mips::T1, mips::T0, 0); - __ Jr(mips::T9); - - std::string expected = - ".set noreorder\n" - "1:\n" - - "beqz $t1, 1b\n" - "addu $t0, $t1, $t2\n" - - "bne $t2, $t3, 1b\n" - "or $t1, $t2, $t3\n" - - "slt $at, $t1, $t2\n" - "bnez $at, 1b\n" - "and $t0, $t1, $t2\n" - - "slt $at, $t1, $t0\n" - "beqz $at, 1b\n" - "xor $t2, $t0, $t1\n" - - "sltu $at, $t1, $t0\n" - "bnez $at, 1b\n" - "subu $t2, $t1, $t0\n" - - "bc1t $fcc1, 1b\n" - "c.olt.s $fcc0, $f2, $f4\n" - - "bal 1b\n" - "or $t0, $t1, $zero\n" - - "jalr $t9\n" - "ll $t1, 0($t0)\n" - - "jalr $zero, $t9\n" - "sc $t1, 0($t0)\n"; - DriverStr(expected, "Reordering"); -} - -TEST_F(AssemblerMIPSTest, AbsorbTargetInstruction) { - mips::MipsLabel label1, label2, label3, label4, label5, label6; - mips::MipsLabel label7, label8, label9, label10, label11, label12, label13; - __ SetReorder(true); - - __ B(&label1); - __ Bind(&label1); - __ Addu(mips::T0, mips::T1, mips::T2); - - __ Bind(&label2); - __ Xor(mips::T0, mips::T1, mips::T2); - __ Addu(mips::T0, mips::T1, mips::T2); - __ Bind(&label3); // Prevents reordering ADDU above with B below. - __ B(&label2); - - __ B(&label4); - __ Bind(&label4); - __ Addu(mips::T0, mips::T1, mips::T2); - __ CodePosition(); // Prevents absorbing ADDU above. - - __ B(&label5); - __ Bind(&label5); - __ Addu(mips::T0, mips::T1, mips::T2); - __ Bind(&label6); - __ CodePosition(); // Even across Bind(), CodePosition() prevents absorbing the ADDU above. - - __ Nop(); - __ B(&label7); - __ Bind(&label7); - __ Lw(mips::V0, mips::A0, 0x5678); // Possibly patchable instruction, not absorbed. - - __ Nop(); - __ B(&label8); - __ Bind(&label8); - __ Sw(mips::V0, mips::A0, 0x5678); // Possibly patchable instruction, not absorbed. - - __ Nop(); - __ B(&label9); - __ Bind(&label9); - __ Addiu(mips::V0, mips::A0, 0x5678); // Possibly patchable instruction, not absorbed. - - __ Nop(); - __ B(&label10); - __ Bind(&label10); - __ Lw(mips::V0, mips::A0, 0x5680); // Immediate isn't 0x5678, absorbed. - - __ Nop(); - __ B(&label11); - __ Bind(&label11); - __ Sw(mips::V0, mips::A0, 0x5680); // Immediate isn't 0x5678, absorbed. - - __ Nop(); - __ B(&label12); - __ Bind(&label12); - __ Addiu(mips::V0, mips::A0, 0x5680); // Immediate isn't 0x5678, absorbed. - - __ Nop(); - __ B(&label13); - __ Bind(&label13); - __ Andi(mips::V0, mips::A0, 0x5678); // Not one of patchable instructions, absorbed. - - std::string expected = - ".set noreorder\n" - "b 1f\n" - "addu $t0, $t1, $t2\n" - "addu $t0, $t1, $t2\n" - "1:\n" - - "xor $t0, $t1, $t2\n" - "2:\n" - "addu $t0, $t1, $t2\n" - "b 2b\n" - "xor $t0, $t1, $t2\n" - - "b 4f\n" - "nop\n" - "4:\n" - "addu $t0, $t1, $t2\n" - - "b 5f\n" - "nop\n" - "5:\n" - "addu $t0, $t1, $t2\n" - - "nop\n" - "b 7f\n" - "nop\n" - "7:\n" - "lw $v0, 0x5678($a0)\n" - - "nop\n" - "b 8f\n" - "nop\n" - "8:\n" - "sw $v0, 0x5678($a0)\n" - - "nop\n" - "b 9f\n" - "nop\n" - "9:\n" - "addiu $v0, $a0, 0x5678\n" - - "nop\n" - "b 10f\n" - "lw $v0, 0x5680($a0)\n" - "lw $v0, 0x5680($a0)\n" - "10:\n" - - "nop\n" - "b 11f\n" - "sw $v0, 0x5680($a0)\n" - "sw $v0, 0x5680($a0)\n" - "11:\n" - - "nop\n" - "b 12f\n" - "addiu $v0, $a0, 0x5680\n" - "addiu $v0, $a0, 0x5680\n" - "12:\n" - - "nop\n" - "b 13f\n" - "andi $v0, $a0, 0x5678\n" - "andi $v0, $a0, 0x5678\n" - "13:\n"; - DriverStr(expected, "AbsorbTargetInstruction"); -} - -TEST_F(AssemblerMIPSTest, SetReorder) { - mips::MipsLabel label1, label2, label3, label4, label5, label6; - - __ SetReorder(true); - __ Bind(&label1); - __ Addu(mips::T0, mips::T1, mips::T2); - __ B(&label1); - __ B(&label5); - __ B(&label6); - - __ SetReorder(false); - __ Bind(&label2); - __ Addu(mips::T0, mips::T1, mips::T2); - __ B(&label2); - __ B(&label5); - __ B(&label6); - - __ SetReorder(true); - __ Bind(&label3); - __ Addu(mips::T0, mips::T1, mips::T2); - __ B(&label3); - __ B(&label5); - __ B(&label6); - - __ SetReorder(false); - __ Bind(&label4); - __ Addu(mips::T0, mips::T1, mips::T2); - __ B(&label4); - __ B(&label5); - __ B(&label6); - - __ SetReorder(true); - __ Bind(&label5); - __ Subu(mips::T0, mips::T1, mips::T2); - - __ SetReorder(false); - __ Bind(&label6); - __ Xor(mips::T0, mips::T1, mips::T2); - - std::string expected = - ".set noreorder\n" - "1:\n" - "b 1b\n" - "addu $t0, $t1, $t2\n" - "b 55f\n" - "subu $t0, $t1, $t2\n" - "b 6f\n" - "nop\n" - - "2:\n" - "addu $t0, $t1, $t2\n" - "b 2b\n" - "nop\n" - "b 5f\n" - "nop\n" - "b 6f\n" - "nop\n" - - "3:\n" - "b 3b\n" - "addu $t0, $t1, $t2\n" - "b 55f\n" - "subu $t0, $t1, $t2\n" - "b 6f\n" - "nop\n" - - "4:\n" - "addu $t0, $t1, $t2\n" - "b 4b\n" - "nop\n" - "b 5f\n" - "nop\n" - "b 6f\n" - "nop\n" - - "5:\n" - "subu $t0, $t1, $t2\n" - "55:\n" - "6:\n" - "xor $t0, $t1, $t2\n"; - DriverStr(expected, "SetReorder"); -} - -TEST_F(AssemblerMIPSTest, ReorderPatchedInstruction) { - __ SetReorder(true); - mips::MipsLabel label1, label2; - mips::MipsLabel patcher_label1, patcher_label2, patcher_label3, patcher_label4, patcher_label5; - __ Lw(mips::V0, mips::A0, 0x5678, &patcher_label1); - __ Beq(mips::A0, mips::A1, &label1); - constexpr uint32_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label1); - __ Sw(mips::V0, mips::A0, 0x5678, &patcher_label2); - __ Bltz(mips::V1, &label2); - constexpr uint32_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label2); - __ Addiu(mips::V0, mips::A0, 0x5678, &patcher_label3); - __ B(&label1); - __ Lw(mips::V0, mips::A0, 0x5678, &patcher_label4); - __ Jalr(mips::T9); - __ Sw(mips::V0, mips::A0, 0x5678, &patcher_label5); - __ Blt(mips::V0, mips::V1, &label2); - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - - std::string expected = - ".set noreorder\n" - "beq $a0, $a1, 1f\n" - "lw $v0, 0x5678($a0)\n" + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" - "bltz $v1, 2f\n" - "sw $v0, 0x5678($a0)\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "2:\n" - "b 1b\n" - "addiu $v0, $a0, 0x5678\n" - "jalr $t9\n" - "lw $v0, 0x5678($a0)\n" - "slt $at, $v0, $v1\n" - "bnez $at, 2b\n" - "sw $v0, 0x5678($a0)\n" - "addu $zero, $zero, $zero\n"; - DriverStr(expected, "ReorderPatchedInstruction"); - EXPECT_EQ(__ GetLabelLocation(&patcher_label1), 1 * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label2), (kAdduCount1 + 3) * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label3), (kAdduCount1 + kAdduCount2 + 5) * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label4), (kAdduCount1 + kAdduCount2 + 7) * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label5), (kAdduCount1 + kAdduCount2 + 10) * 4u); -} - -TEST_F(AssemblerMIPSTest, LongBranchReorder) { - mips::MipsLabel label, patcher_label1, patcher_label2; - __ SetReorder(true); - __ Addiu(mips::T0, mips::T1, 0x5678, &patcher_label1); - __ B(&label); - constexpr uint32_t kAdduCount1 = (1u << 15) + 1; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr uint32_t kAdduCount2 = (1u << 15) + 1; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Addiu(mips::T0, mips::T1, 0x5678, &patcher_label2); - __ B(&label); - - // Account for 5 extra instructions: ori, addu, lw, jalr, addiu. - uint32_t offset_forward = (kAdduCount1 + 5) * sizeof(uint32_t); - // Account for 5 extra instructions: subu, addiu, sw, nal, lui. - uint32_t offset_back = static_cast<uint32_t>(-(kAdduCount1 + 5) * sizeof(uint32_t)); - - std::ostringstream oss; - oss << - ".set noreorder\n" - "addiu $t0, $t1, 0x5678\n" - "addiu $sp, $sp, -16\n" - "sw $ra, 0($sp)\n" - "bltzal $zero, .+4\n" - "lui $at, 0x" << std::hex << High16Bits(offset_forward) << "\n" - "ori $at, $at, 0x" << std::hex << Low16Bits(offset_forward) << "\n" - "addu $at, $at, $ra\n" - "lw $ra, 0($sp)\n" - "jalr $zero, $at\n" - "addiu $sp, $sp, 16\n" << - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") << - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") << - "addiu $t0, $t1, 0x5678\n" - "addiu $sp, $sp, -16\n" - "sw $ra, 0($sp)\n" - "bltzal $zero, .+4\n" - "lui $at, 0x" << std::hex << High16Bits(offset_back) << "\n" - "ori $at, $at, 0x" << std::hex << Low16Bits(offset_back) << "\n" - "addu $at, $at, $ra\n" - "lw $ra, 0($sp)\n" - "jalr $zero, $at\n" - "addiu $sp, $sp, 16\n"; - std::string expected = oss.str(); - DriverStr(expected, "LongBranchReorder"); - EXPECT_EQ(__ GetLabelLocation(&patcher_label1), 0 * 4u); - EXPECT_EQ(__ GetLabelLocation(&patcher_label2), (kAdduCount1 + kAdduCount2 + 10) * 4u); -} - -/////////////////////// -// Loading Constants // -/////////////////////// - -TEST_F(AssemblerMIPSTest, LoadConst32) { - // IsUint<16>(value) - __ LoadConst32(mips::V0, 0); - __ LoadConst32(mips::V0, 65535); - // IsInt<16>(value) - __ LoadConst32(mips::V0, -1); - __ LoadConst32(mips::V0, -32768); - // Everything else - __ LoadConst32(mips::V0, 65536); - __ LoadConst32(mips::V0, 65537); - __ LoadConst32(mips::V0, 2147483647); - __ LoadConst32(mips::V0, -32769); - __ LoadConst32(mips::V0, -65536); - __ LoadConst32(mips::V0, -65537); - __ LoadConst32(mips::V0, -2147483647); - __ LoadConst32(mips::V0, -2147483648); - - const char* expected = - // IsUint<16>(value) - "ori $v0, $zero, 0\n" // __ LoadConst32(mips::V0, 0); - "ori $v0, $zero, 65535\n" // __ LoadConst32(mips::V0, 65535); - // IsInt<16>(value) - "addiu $v0, $zero, -1\n" // __ LoadConst32(mips::V0, -1); - "addiu $v0, $zero, -32768\n" // __ LoadConst32(mips::V0, -32768); - // Everything else - "lui $v0, 1\n" // __ LoadConst32(mips::V0, 65536); - "lui $v0, 1\n" // __ LoadConst32(mips::V0, 65537); - "ori $v0, 1\n" // " - "lui $v0, 32767\n" // __ LoadConst32(mips::V0, 2147483647); - "ori $v0, 65535\n" // " - "lui $v0, 65535\n" // __ LoadConst32(mips::V0, -32769); - "ori $v0, 32767\n" // " - "lui $v0, 65535\n" // __ LoadConst32(mips::V0, -65536); - "lui $v0, 65534\n" // __ LoadConst32(mips::V0, -65537); - "ori $v0, 65535\n" // " - "lui $v0, 32768\n" // __ LoadConst32(mips::V0, -2147483647); - "ori $v0, 1\n" // " - "lui $v0, 32768\n"; // __ LoadConst32(mips::V0, -2147483648); - DriverStr(expected, "LoadConst32"); -} - -TEST_F(AssemblerMIPSTest, LoadFarthestNearLabelAddress) { - mips::MipsLabel label; - __ BindPcRelBaseLabel(); - __ LoadLabelAddress(mips::V0, mips::V1, &label); - constexpr size_t kAddiuCount = 0x1FDE; - for (size_t i = 0; i != kAddiuCount; ++i) { - __ Addiu(mips::A0, mips::A1, 0); - } - __ Bind(&label); - - std::string expected = - "1:\n" - "addiu $v0, $v1, %lo(2f - 1b)\n" + - RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") + - "2:\n"; - DriverStr(expected, "LoadFarthestNearLabelAddress"); -} - -TEST_F(AssemblerMIPSTest, LoadNearestFarLabelAddress) { - mips::MipsLabel label; - __ BindPcRelBaseLabel(); - __ LoadLabelAddress(mips::V0, mips::V1, &label); - constexpr size_t kAdduCount = 0x1FDF; - for (size_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - - std::string expected = - "1:\n" - "lui $at, %hi(2f - 1b)\n" - "ori $at, $at, %lo(2f - 1b)\n" - "addu $v0, $at, $v1\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n"; - DriverStr(expected, "LoadNearestFarLabelAddress"); -} - -TEST_F(AssemblerMIPSTest, LoadFarthestNearLabelAddressUsingNal) { - mips::MipsLabel label; - __ LoadLabelAddress(mips::V0, mips::ZERO, &label); - constexpr size_t kAddiuCount = 0x1FDE; - for (size_t i = 0; i != kAddiuCount; ++i) { - __ Addiu(mips::A0, mips::A1, 0); - } - __ Bind(&label); - - std::string expected = - ".set noreorder\n" - "bltzal $zero, .+4\n" - "addiu $v0, $ra, %lo(2f - 1f)\n" - "1:\n" + - RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") + - "2:\n"; - DriverStr(expected, "LoadFarthestNearLabelAddressUsingNal"); -} - -TEST_F(AssemblerMIPSTest, LoadNearestFarLabelAddressUsingNal) { - mips::MipsLabel label; - __ LoadLabelAddress(mips::V0, mips::ZERO, &label); - constexpr size_t kAdduCount = 0x1FDF; - for (size_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - - std::string expected = - ".set noreorder\n" - "bltzal $zero, .+4\n" - "lui $at, %hi(2f - 1f)\n" - "1:\n" - "ori $at, $at, %lo(2f - 1b)\n" - "addu $v0, $at, $ra\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n"; - DriverStr(expected, "LoadNearestFarLabelAddressUsingNal"); -} - -TEST_F(AssemblerMIPSTest, LoadFarthestNearLiteral) { - mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ BindPcRelBaseLabel(); - __ LoadLiteral(mips::V0, mips::V1, literal); - constexpr size_t kAddiuCount = 0x1FDE; - for (size_t i = 0; i != kAddiuCount; ++i) { - __ Addiu(mips::A0, mips::A1, 0); - } - - std::string expected = - "1:\n" - "lw $v0, %lo(2f - 1b)($v1)\n" + - RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") + - "2:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadFarthestNearLiteral"); -} - -TEST_F(AssemblerMIPSTest, LoadNearestFarLiteral) { - mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ BindPcRelBaseLabel(); - __ LoadLiteral(mips::V0, mips::V1, literal); - constexpr size_t kAdduCount = 0x1FDF; - for (size_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - - std::string expected = - "1:\n" - "lui $at, %hi(2f - 1b)\n" - "addu $at, $at, $v1\n" - "lw $v0, %lo(2f - 1b)($at)\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadNearestFarLiteral"); -} - -TEST_F(AssemblerMIPSTest, LoadFarthestNearLiteralUsingNal) { - mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ LoadLiteral(mips::V0, mips::ZERO, literal); - constexpr size_t kAddiuCount = 0x1FDE; - for (size_t i = 0; i != kAddiuCount; ++i) { - __ Addiu(mips::A0, mips::A1, 0); - } - - std::string expected = - ".set noreorder\n" - "bltzal $zero, .+4\n" - "lw $v0, %lo(2f - 1f)($ra)\n" - "1:\n" + - RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") + - "2:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadFarthestNearLiteralUsingNal"); -} - -TEST_F(AssemblerMIPSTest, LoadNearestFarLiteralUsingNal) { - mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ LoadLiteral(mips::V0, mips::ZERO, literal); - constexpr size_t kAdduCount = 0x1FDF; - for (size_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - - std::string expected = - ".set noreorder\n" - "bltzal $zero, .+4\n" - "lui $at, %hi(2f - 1f)\n" - "1:\n" - "addu $at, $at, $ra\n" - "lw $v0, %lo(2f - 1b)($at)\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadNearestFarLiteralUsingNal"); -} - -#undef __ - -} // namespace art diff --git a/compiler/utils/mips/constants_mips.h b/compiler/utils/mips/constants_mips.h deleted file mode 100644 index 07d8b7de0e..0000000000 --- a/compiler/utils/mips/constants_mips.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_UTILS_MIPS_CONSTANTS_MIPS_H_ -#define ART_COMPILER_UTILS_MIPS_CONSTANTS_MIPS_H_ - -#include <iosfwd> - -#include <android-base/logging.h> - -#include "arch/mips/registers_mips.h" -#include "base/globals.h" -#include "base/macros.h" - -namespace art { -namespace mips { - -// Values for double-precision floating point registers. -enum DRegister { - D0 = 0, - D1 = 1, - D2 = 2, - D3 = 3, - D4 = 4, - D5 = 5, - D6 = 6, - D7 = 7, - D8 = 8, - D9 = 9, - D10 = 10, - D11 = 11, - D12 = 12, - D13 = 13, - D14 = 14, - D15 = 15, - kNumberOfDRegisters = 16, - kNumberOfOverlappingDRegisters = 16, - kNoDRegister = -1, -}; -std::ostream& operator<<(std::ostream& os, const DRegister& rhs); - -// Constants used for the decoding or encoding of the individual fields of instructions. -enum InstructionFields { - kOpcodeShift = 26, - kOpcodeBits = 6, - kRsShift = 21, - kRsBits = 5, - kRtShift = 16, - kRtBits = 5, - kRdShift = 11, - kRdBits = 5, - kShamtShift = 6, - kShamtBits = 5, - kFunctShift = 0, - kFunctBits = 6, - - kFmtShift = 21, - kFmtBits = 5, - kFtShift = 16, - kFtBits = 5, - kFsShift = 11, - kFsBits = 5, - kFdShift = 6, - kFdBits = 5, - - kMsaOperationShift = 23, - kMsaELMOperationShift = 22, - kMsa2ROperationShift = 18, - kMsa2RFOperationShift = 17, - kDfShift = 21, - kDfMShift = 16, - kDf2RShift = 16, - kDfNShift = 16, - kWtShift = 16, - kWtBits = 5, - kWsShift = 11, - kWsBits = 5, - kWdShift = 6, - kWdBits = 5, - kS10Shift = 16, - kI10Shift = 11, - kS10MinorShift = 2, - - kBranchOffsetMask = 0x0000ffff, - kJumpOffsetMask = 0x03ffffff, - - kMsaMajorOpcode = 0x1e, - kMsaDfMByteMask = 0x70, - kMsaDfMHalfwordMask = 0x60, - kMsaDfMWordMask = 0x40, - kMsaDfMDoublewordMask = 0x00, - kMsaDfNByteMask = 0x00, - kMsaDfNHalfwordMask = 0x20, - kMsaDfNWordMask = 0x30, - kMsaDfNDoublewordMask = 0x38, - kMsaS10Mask = 0x3ff, -}; - -enum ScaleFactor { - TIMES_1 = 0, - TIMES_2 = 1, - TIMES_4 = 2, - TIMES_8 = 3 -}; - -class Instr { - public: - static const uint32_t kBreakPointInstruction = 0x0000000D; - - bool IsBreakPoint() { - return ((*reinterpret_cast<const uint32_t*>(this)) & 0xFC0000CF) == kBreakPointInstruction; - } - - // Instructions are read out of a code stream. The only way to get a - // reference to an instruction is to convert a pointer. There is no way - // to allocate or create instances of class Instr. - // Use the At(pc) function to create references to Instr. - static Instr* At(uintptr_t pc) { return reinterpret_cast<Instr*>(pc); } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); -}; - -} // namespace mips -} // namespace art - -#endif // ART_COMPILER_UTILS_MIPS_CONSTANTS_MIPS_H_ diff --git a/compiler/utils/mips/managed_register_mips.cc b/compiler/utils/mips/managed_register_mips.cc deleted file mode 100644 index 9b3ed79d2f..0000000000 --- a/compiler/utils/mips/managed_register_mips.cc +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "managed_register_mips.h" - -#include "base/globals.h" - -namespace art { -namespace mips { - -bool MipsManagedRegister::Overlaps(const MipsManagedRegister& other) const { - if (IsNoRegister() || other.IsNoRegister()) return false; - CHECK(IsValidManagedRegister()); - CHECK(other.IsValidManagedRegister()); - if (Equals(other)) return true; - if (IsRegisterPair()) { - Register low = AsRegisterPairLow(); - Register high = AsRegisterPairHigh(); - return MipsManagedRegister::FromCoreRegister(low).Overlaps(other) || - MipsManagedRegister::FromCoreRegister(high).Overlaps(other); - } - if (IsOverlappingDRegister()) { - if (other.IsDRegister()) return Equals(other); - if (other.IsFRegister()) { - FRegister low = AsOverlappingDRegisterLow(); - FRegister high = AsOverlappingDRegisterHigh(); - FRegister other_freg = other.AsFRegister(); - return (low == other_freg) || (high == other_freg); - } - return false; - } - if (other.IsRegisterPair() || other.IsOverlappingDRegister()) { - return other.Overlaps(*this); - } - return false; -} - - -int MipsManagedRegister::AllocIdLow() const { - CHECK(IsOverlappingDRegister() || IsRegisterPair()); - const int r = RegId() - (kNumberOfCoreRegIds + kNumberOfFRegIds); - int low; - if (r < kNumberOfOverlappingDRegIds) { - CHECK(IsOverlappingDRegister()); - low = (r * 2) + kNumberOfCoreRegIds; // Return an FRegister. - } else { - CHECK(IsRegisterPair()); - low = (r - kNumberOfDRegIds) * 2 + 2; // Return a Register. - if (low >= 24) { - // we got a pair higher than S6_S7, must be the dalvik special case - low = 5; - } - } - return low; -} - - -int MipsManagedRegister::AllocIdHigh() const { - return AllocIdLow() + 1; -} - - -void MipsManagedRegister::Print(std::ostream& os) const { - if (!IsValidManagedRegister()) { - os << "No Register"; - } else if (IsCoreRegister()) { - os << "Core: " << static_cast<int>(AsCoreRegister()); - } else if (IsRegisterPair()) { - os << "Pair: " << AsRegisterPairLow() << ", " << AsRegisterPairHigh(); - } else if (IsFRegister()) { - os << "FRegister: " << static_cast<int>(AsFRegister()); - } else if (IsDRegister()) { - os << "DRegister: " << static_cast<int>(AsDRegister()); - } else { - os << "??: " << RegId(); - } -} - -std::ostream& operator<<(std::ostream& os, const MipsManagedRegister& reg) { - reg.Print(os); - return os; -} - -std::ostream& operator<<(std::ostream& os, const RegisterPair& reg) { - os << MipsManagedRegister::FromRegisterPair(reg); - return os; -} - -} // namespace mips -} // namespace art diff --git a/compiler/utils/mips/managed_register_mips.h b/compiler/utils/mips/managed_register_mips.h deleted file mode 100644 index 18d5821e61..0000000000 --- a/compiler/utils/mips/managed_register_mips.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ -#define ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ - -#include "constants_mips.h" -#include "utils/managed_register.h" - -namespace art { -namespace mips { - -// Values for register pairs. -enum RegisterPair { - V0_V1 = 0, - A0_A1 = 1, - A2_A3 = 2, - T0_T1 = 3, - T2_T3 = 4, - T4_T5 = 5, - T6_T7 = 6, - S0_S1 = 7, - S2_S3 = 8, - S4_S5 = 9, - S6_S7 = 10, - A1_A2 = 11, // Dalvik style passing - kNumberOfRegisterPairs = 12, - kNoRegisterPair = -1, -}; - -std::ostream& operator<<(std::ostream& os, const RegisterPair& reg); - -const int kNumberOfCoreRegIds = kNumberOfCoreRegisters; -const int kNumberOfCoreAllocIds = kNumberOfCoreRegisters; - -const int kNumberOfFRegIds = kNumberOfFRegisters; -const int kNumberOfFAllocIds = kNumberOfFRegisters; - -const int kNumberOfDRegIds = kNumberOfDRegisters; -const int kNumberOfOverlappingDRegIds = kNumberOfOverlappingDRegisters; -const int kNumberOfDAllocIds = kNumberOfDRegisters; - -const int kNumberOfPairRegIds = kNumberOfRegisterPairs; - -const int kNumberOfRegIds = kNumberOfCoreRegIds + kNumberOfFRegIds + - kNumberOfDRegIds + kNumberOfPairRegIds; -const int kNumberOfAllocIds = - kNumberOfCoreAllocIds + kNumberOfFAllocIds + kNumberOfDAllocIds; - -// Register ids map: -// [0..R[ core registers (enum Register) -// [R..F[ single precision FP registers (enum FRegister) -// [F..D[ double precision FP registers (enum DRegister) -// [D..P[ core register pairs (enum RegisterPair) -// where -// R = kNumberOfCoreRegIds -// F = R + kNumberOfFRegIds -// D = F + kNumberOfDRegIds -// P = D + kNumberOfRegisterPairs - -// Allocation ids map: -// [0..R[ core registers (enum Register) -// [R..F[ single precision FP registers (enum FRegister) -// where -// R = kNumberOfCoreRegIds -// F = R + kNumberOfFRegIds - - -// An instance of class 'ManagedRegister' represents a single core register (enum -// Register), a single precision FP register (enum FRegister), a double precision -// FP register (enum DRegister), or a pair of core registers (enum RegisterPair). -// 'ManagedRegister::NoRegister()' provides an invalid register. -// There is a one-to-one mapping between ManagedRegister and register id. -class MipsManagedRegister : public ManagedRegister { - public: - constexpr Register AsCoreRegister() const { - CHECK(IsCoreRegister()); - return static_cast<Register>(id_); - } - - constexpr FRegister AsFRegister() const { - CHECK(IsFRegister()); - return static_cast<FRegister>(id_ - kNumberOfCoreRegIds); - } - - constexpr DRegister AsDRegister() const { - CHECK(IsDRegister()); - return static_cast<DRegister>(id_ - kNumberOfCoreRegIds - kNumberOfFRegIds); - } - - constexpr FRegister AsOverlappingDRegisterLow() const { - CHECK(IsOverlappingDRegister()); - DRegister d_reg = AsDRegister(); - return static_cast<FRegister>(d_reg * 2); - } - - constexpr FRegister AsOverlappingDRegisterHigh() const { - CHECK(IsOverlappingDRegister()); - DRegister d_reg = AsDRegister(); - return static_cast<FRegister>(d_reg * 2 + 1); - } - - constexpr Register AsRegisterPairLow() const { - CHECK(IsRegisterPair()); - // Appropriate mapping of register ids allows to use AllocIdLow(). - return FromRegId(AllocIdLow()).AsCoreRegister(); - } - - constexpr Register AsRegisterPairHigh() const { - CHECK(IsRegisterPair()); - // Appropriate mapping of register ids allows to use AllocIdHigh(). - return FromRegId(AllocIdHigh()).AsCoreRegister(); - } - - constexpr bool IsCoreRegister() const { - CHECK(IsValidManagedRegister()); - return (0 <= id_) && (id_ < kNumberOfCoreRegIds); - } - - constexpr bool IsFRegister() const { - CHECK(IsValidManagedRegister()); - const int test = id_ - kNumberOfCoreRegIds; - return (0 <= test) && (test < kNumberOfFRegIds); - } - - constexpr bool IsDRegister() const { - CHECK(IsValidManagedRegister()); - const int test = id_ - (kNumberOfCoreRegIds + kNumberOfFRegIds); - return (0 <= test) && (test < kNumberOfDRegIds); - } - - // Returns true if this DRegister overlaps FRegisters. - constexpr bool IsOverlappingDRegister() const { - CHECK(IsValidManagedRegister()); - const int test = id_ - (kNumberOfCoreRegIds + kNumberOfFRegIds); - return (0 <= test) && (test < kNumberOfOverlappingDRegIds); - } - - constexpr bool IsRegisterPair() const { - CHECK(IsValidManagedRegister()); - const int test = - id_ - (kNumberOfCoreRegIds + kNumberOfFRegIds + kNumberOfDRegIds); - return (0 <= test) && (test < kNumberOfPairRegIds); - } - - void Print(std::ostream& os) const; - - // Returns true if the two managed-registers ('this' and 'other') overlap. - // Either managed-register may be the NoRegister. If both are the NoRegister - // then false is returned. - bool Overlaps(const MipsManagedRegister& other) const; - - static constexpr MipsManagedRegister FromCoreRegister(Register r) { - CHECK_NE(r, kNoRegister); - return FromRegId(r); - } - - static constexpr MipsManagedRegister FromFRegister(FRegister r) { - CHECK_NE(r, kNoFRegister); - return FromRegId(r + kNumberOfCoreRegIds); - } - - static constexpr MipsManagedRegister FromDRegister(DRegister r) { - CHECK_NE(r, kNoDRegister); - return FromRegId(r + kNumberOfCoreRegIds + kNumberOfFRegIds); - } - - static constexpr MipsManagedRegister FromRegisterPair(RegisterPair r) { - CHECK_NE(r, kNoRegisterPair); - return FromRegId(r + (kNumberOfCoreRegIds + kNumberOfFRegIds + kNumberOfDRegIds)); - } - - private: - constexpr bool IsValidManagedRegister() const { - return (0 <= id_) && (id_ < kNumberOfRegIds); - } - - constexpr int RegId() const { - CHECK(!IsNoRegister()); - return id_; - } - - int AllocId() const { - CHECK(IsValidManagedRegister() && !IsOverlappingDRegister() && !IsRegisterPair()); - CHECK_LT(id_, kNumberOfAllocIds); - return id_; - } - - int AllocIdLow() const; - int AllocIdHigh() const; - - friend class ManagedRegister; - - explicit constexpr MipsManagedRegister(int reg_id) : ManagedRegister(reg_id) {} - - static constexpr MipsManagedRegister FromRegId(int reg_id) { - MipsManagedRegister reg(reg_id); - CHECK(reg.IsValidManagedRegister()); - return reg; - } -}; - -std::ostream& operator<<(std::ostream& os, const MipsManagedRegister& reg); - -} // namespace mips - -constexpr inline mips::MipsManagedRegister ManagedRegister::AsMips() const { - mips::MipsManagedRegister reg(id_); - CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister()); - return reg; -} - -} // namespace art - -#endif // ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc deleted file mode 100644 index 70313ca093..0000000000 --- a/compiler/utils/mips64/assembler_mips64.cc +++ /dev/null @@ -1,4101 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "assembler_mips64.h" - -#include "base/bit_utils.h" -#include "base/casts.h" -#include "base/memory_region.h" -#include "entrypoints/quick/quick_entrypoints.h" -#include "entrypoints/quick/quick_entrypoints_enum.h" -#include "thread.h" - -namespace art { -namespace mips64 { - -static_assert(static_cast<size_t>(kMips64PointerSize) == kMips64DoublewordSize, - "Unexpected Mips64 pointer size."); -static_assert(kMips64PointerSize == PointerSize::k64, "Unexpected Mips64 pointer size."); - - -void Mips64Assembler::FinalizeCode() { - for (auto& exception_block : exception_blocks_) { - EmitExceptionPoll(&exception_block); - } - ReserveJumpTableSpace(); - EmitLiterals(); - PromoteBranches(); -} - -void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) { - EmitBranches(); - EmitJumpTables(); - Assembler::FinalizeInstructions(region); - PatchCFI(); -} - -void Mips64Assembler::PatchCFI() { - if (cfi().NumberOfDelayedAdvancePCs() == 0u) { - return; - } - - using DelayedAdvancePC = DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC; - const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC(); - const std::vector<uint8_t>& old_stream = data.first; - const std::vector<DelayedAdvancePC>& advances = data.second; - - // Refill our data buffer with patched opcodes. - cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16); - size_t stream_pos = 0; - for (const DelayedAdvancePC& advance : advances) { - DCHECK_GE(advance.stream_pos, stream_pos); - // Copy old data up to the point where advance was issued. - cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos); - stream_pos = advance.stream_pos; - // Insert the advance command with its final offset. - size_t final_pc = GetAdjustedPosition(advance.pc); - cfi().AdvancePC(final_pc); - } - // Copy the final segment if any. - cfi().AppendRawData(old_stream, stream_pos, old_stream.size()); -} - -void Mips64Assembler::EmitBranches() { - CHECK(!overwriting_); - // Switch from appending instructions at the end of the buffer to overwriting - // existing instructions (branch placeholders) in the buffer. - overwriting_ = true; - for (auto& branch : branches_) { - EmitBranch(&branch); - } - overwriting_ = false; -} - -void Mips64Assembler::Emit(uint32_t value) { - if (overwriting_) { - // Branches to labels are emitted into their placeholders here. - buffer_.Store<uint32_t>(overwrite_location_, value); - overwrite_location_ += sizeof(uint32_t); - } else { - // Other instructions are simply appended at the end here. - AssemblerBuffer::EnsureCapacity ensured(&buffer_); - buffer_.Emit<uint32_t>(value); - } -} - -void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd, - int shamt, int funct) { - CHECK_NE(rs, kNoGpuRegister); - CHECK_NE(rt, kNoGpuRegister); - CHECK_NE(rd, kNoGpuRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - static_cast<uint32_t>(rs) << kRsShift | - static_cast<uint32_t>(rt) << kRtShift | - static_cast<uint32_t>(rd) << kRdShift | - shamt << kShamtShift | - funct; - Emit(encoding); -} - -void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd, - int shamt, int funct) { - CHECK_NE(rs, kNoGpuRegister); - CHECK_NE(rd, kNoGpuRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - static_cast<uint32_t>(rs) << kRsShift | - static_cast<uint32_t>(ZERO) << kRtShift | - static_cast<uint32_t>(rd) << kRdShift | - shamt << kShamtShift | - funct; - Emit(encoding); -} - -void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd, - int shamt, int funct) { - CHECK_NE(rt, kNoGpuRegister); - CHECK_NE(rd, kNoGpuRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - static_cast<uint32_t>(ZERO) << kRsShift | - static_cast<uint32_t>(rt) << kRtShift | - static_cast<uint32_t>(rd) << kRdShift | - shamt << kShamtShift | - funct; - Emit(encoding); -} - -void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) { - CHECK_NE(rs, kNoGpuRegister); - CHECK_NE(rt, kNoGpuRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - static_cast<uint32_t>(rs) << kRsShift | - static_cast<uint32_t>(rt) << kRtShift | - imm; - Emit(encoding); -} - -void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) { - CHECK_NE(rs, kNoGpuRegister); - CHECK(IsUint<21>(imm21)) << imm21; - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - static_cast<uint32_t>(rs) << kRsShift | - imm21; - Emit(encoding); -} - -void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) { - CHECK(IsUint<26>(imm26)) << imm26; - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26; - Emit(encoding); -} - -void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd, - int funct) { - CHECK_NE(ft, kNoFpuRegister); - CHECK_NE(fs, kNoFpuRegister); - CHECK_NE(fd, kNoFpuRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - fmt << kFmtShift | - static_cast<uint32_t>(ft) << kFtShift | - static_cast<uint32_t>(fs) << kFsShift | - static_cast<uint32_t>(fd) << kFdShift | - funct; - Emit(encoding); -} - -void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) { - CHECK_NE(ft, kNoFpuRegister); - uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | - fmt << kFmtShift | - static_cast<uint32_t>(ft) << kFtShift | - imm; - Emit(encoding); -} - -void Mips64Assembler::EmitMsa3R(int operation, - int df, - VectorRegister wt, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(wt, kNoVectorRegister); - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsaOperationShift | - df << kDfShift | - static_cast<uint32_t>(wt) << kWtShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); -} - -void Mips64Assembler::EmitMsaBIT(int operation, - int df_m, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsaOperationShift | - df_m << kDfMShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); -} - -void Mips64Assembler::EmitMsaELM(int operation, - int df_n, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsaELMOperationShift | - df_n << kDfNShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); -} - -void Mips64Assembler::EmitMsaMI10(int s10, - GpuRegister rs, - VectorRegister wd, - int minor_opcode, - int df) { - CHECK_NE(rs, kNoGpuRegister); - CHECK_NE(wd, kNoVectorRegister); - CHECK(IsUint<10>(s10)) << s10; - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - s10 << kS10Shift | - static_cast<uint32_t>(rs) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode << kS10MinorShift | - df; - Emit(encoding); -} - -void Mips64Assembler::EmitMsaI10(int operation, - int df, - int i10, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(wd, kNoVectorRegister); - CHECK(IsUint<10>(i10)) << i10; - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsaOperationShift | - df << kDfShift | - i10 << kI10Shift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); -} - -void Mips64Assembler::EmitMsa2R(int operation, - int df, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsa2ROperationShift | - df << kDf2RShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); -} - -void Mips64Assembler::EmitMsa2RF(int operation, - int df, - VectorRegister ws, - VectorRegister wd, - int minor_opcode) { - CHECK_NE(ws, kNoVectorRegister); - CHECK_NE(wd, kNoVectorRegister); - uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | - operation << kMsa2RFOperationShift | - df << kDf2RShift | - static_cast<uint32_t>(ws) << kWsShift | - static_cast<uint32_t>(wd) << kWdShift | - minor_opcode; - Emit(encoding); -} - -void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x21); -} - -void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x9, rs, rt, imm16); -} - -void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x2d); -} - -void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x19, rs, rt, imm16); -} - -void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x23); -} - -void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x2f); -} - -void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 2, 0x18); -} - -void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 3, 0x18); -} - -void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 2, 0x1a); -} - -void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 3, 0x1a); -} - -void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 2, 0x1b); -} - -void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 3, 0x1b); -} - -void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 2, 0x1c); -} - -void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 3, 0x1c); -} - -void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 2, 0x1e); -} - -void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 3, 0x1e); -} - -void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 2, 0x1f); -} - -void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 3, 0x1f); -} - -void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x24); -} - -void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0xc, rs, rt, imm16); -} - -void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x25); -} - -void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0xd, rs, rt, imm16); -} - -void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x26); -} - -void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0xe, rs, rt, imm16); -} - -void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x27); -} - -void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) { - EmitRtd(0x1f, rt, rd, 0x0, 0x20); -} - -void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) { - EmitRtd(0x1f, rt, rd, 0x0, 0x24); -} - -void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) { - EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20); -} - -void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) { - EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20); -} - -void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) { - EmitRtd(0x1f, rt, rd, 0x2, 0x24); -} - -void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) { - EmitRtd(0x1f, rt, rd, 0x5, 0x24); -} - -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<GpuRegister>(size - 1), pos, 0x3); -} - -void Mips64Assembler::Ins(GpuRegister rd, GpuRegister rt, int pos, int size) { - CHECK(IsUint<5>(pos)) << pos; - CHECK(IsUint<5>(size - 1)) << size; - CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size; - EmitR(0x1f, rt, rd, static_cast<GpuRegister>(pos + size - 1), pos, 0x04); -} - -void Mips64Assembler::Dinsm(GpuRegister rt, GpuRegister rs, int pos, int size) { - CHECK(IsUint<5>(pos)) << pos; - CHECK(2 <= size && size <= 64) << size; - CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size; - EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos, 0x5); -} - -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<GpuRegister>(pos + size - 33), pos - 32, 0x6); -} - -void Mips64Assembler::Dins(GpuRegister rt, GpuRegister rs, int pos, int size) { - CHECK(IsUint<5>(pos)) << pos; - CHECK(IsUint<5>(size - 1)) << size; - CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size; - EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 1), pos, 0x7); -} - -void Mips64Assembler::DblIns(GpuRegister rt, GpuRegister rs, int pos, int size) { - if (pos >= 32) { - Dinsu(rt, rs, pos, size); - } else if ((static_cast<int64_t>(pos) + size - 1) >= 32) { - Dinsm(rt, rs, pos, size); - } else { - Dins(rt, rs, pos, size); - } -} - -void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) { - CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne; - int sa = saPlusOne - 1; - EmitR(0x0, rs, rt, rd, sa, 0x05); -} - -void Mips64Assembler::Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) { - CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne; - int sa = saPlusOne - 1; - EmitR(0x0, rs, rt, rd, sa, 0x15); -} - -void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) { - EmitRtd(0x1f, rt, rd, 2, 0x20); -} - -void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) { - CHECK(IsInt<9>(imm9)); - EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26); -} - -void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) { - CHECK(IsInt<9>(imm9)); - EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27); -} - -void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) { - CHECK(IsInt<9>(imm9)); - EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36); -} - -void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) { - CHECK(IsInt<9>(imm9)); - EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37); -} - -void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00); -} - -void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02); -} - -void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02); -} - -void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03); -} - -void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { - EmitR(0, rs, rt, rd, 0, 0x04); -} - -void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { - EmitR(0, rs, rt, rd, 1, 0x06); -} - -void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { - EmitR(0, rs, rt, rd, 0, 0x06); -} - -void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) { - EmitR(0, rs, rt, rd, 0, 0x07); -} - -void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38); -} - -void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a); -} - -void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a); -} - -void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b); -} - -void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c); -} - -void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e); -} - -void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e); -} - -void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) { - EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f); -} - -void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { - EmitR(0, rs, rt, rd, 0, 0x14); -} - -void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { - EmitR(0, rs, rt, rd, 0, 0x16); -} - -void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { - EmitR(0, rs, rt, rd, 1, 0x16); -} - -void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) { - EmitR(0, rs, rt, rd, 0, 0x17); -} - -void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x20, rs, rt, imm16); -} - -void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x21, rs, rt, imm16); -} - -void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x23, rs, rt, imm16); -} - -void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x37, rs, rt, imm16); -} - -void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x24, rs, rt, imm16); -} - -void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x25, rs, rt, imm16); -} - -void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x27, rs, rt, imm16); -} - -void Mips64Assembler::Lwpc(GpuRegister rs, uint32_t imm19) { - CHECK(IsUint<19>(imm19)) << imm19; - EmitI21(0x3B, rs, (0x01 << 19) | imm19); -} - -void Mips64Assembler::Lwupc(GpuRegister rs, uint32_t imm19) { - CHECK(IsUint<19>(imm19)) << imm19; - EmitI21(0x3B, rs, (0x02 << 19) | imm19); -} - -void Mips64Assembler::Ldpc(GpuRegister rs, uint32_t imm18) { - CHECK(IsUint<18>(imm18)) << imm18; - EmitI21(0x3B, rs, (0x06 << 18) | imm18); -} - -void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) { - EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16); -} - -void Mips64Assembler::Aui(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0xf, rs, rt, imm16); -} - -void Mips64Assembler::Daui(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - CHECK_NE(rs, ZERO); - EmitI(0x1d, rs, rt, imm16); -} - -void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) { - EmitI(1, rs, static_cast<GpuRegister>(6), imm16); -} - -void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) { - EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16); -} - -void Mips64Assembler::Sync(uint32_t stype) { - EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), - static_cast<GpuRegister>(0), stype & 0x1f, 0xf); -} - -void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x28, rs, rt, imm16); -} - -void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x29, rs, rt, imm16); -} - -void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x2b, rs, rt, imm16); -} - -void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0x3f, rs, rt, imm16); -} - -void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x2a); -} - -void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x2b); -} - -void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0xa, rs, rt, imm16); -} - -void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { - EmitI(0xb, rs, rt, imm16); -} - -void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x35); -} - -void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) { - EmitR(0, rs, rt, rd, 0, 0x37); -} - -void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) { - EmitRsd(0, rs, rd, 0x01, 0x10); -} - -void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) { - EmitRsd(0, rs, rd, 0x01, 0x11); -} - -void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) { - EmitRsd(0, rs, rd, 0x01, 0x12); -} - -void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) { - EmitRsd(0, rs, rd, 0x01, 0x13); -} - -void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) { - EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09); -} - -void Mips64Assembler::Jalr(GpuRegister rs) { - Jalr(RA, rs); -} - -void Mips64Assembler::Jr(GpuRegister rs) { - Jalr(ZERO, rs); -} - -void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) { - EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16); -} - -void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) { - CHECK(IsUint<19>(imm19)) << imm19; - EmitI21(0x3B, rs, imm19); -} - -void Mips64Assembler::Bc(uint32_t imm26) { - EmitI26(0x32, imm26); -} - -void Mips64Assembler::Balc(uint32_t imm26) { - EmitI26(0x3A, imm26); -} - -void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) { - EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16); -} - -void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) { - EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16); -} - -void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) { - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - EmitI(0x17, rs, rt, imm16); -} - -void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) { - CHECK_NE(rt, ZERO); - EmitI(0x17, rt, rt, imm16); -} - -void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) { - CHECK_NE(rt, ZERO); - EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16); -} - -void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) { - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - EmitI(0x16, rs, rt, imm16); -} - -void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) { - CHECK_NE(rt, ZERO); - EmitI(0x16, rt, rt, imm16); -} - -void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) { - CHECK_NE(rt, ZERO); - EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16); -} - -void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) { - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - EmitI(0x7, rs, rt, imm16); -} - -void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) { - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - EmitI(0x6, rs, rt, imm16); -} - -void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) { - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16); -} - -void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) { - CHECK_NE(rs, ZERO); - CHECK_NE(rt, ZERO); - CHECK_NE(rs, rt); - EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16); -} - -void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) { - CHECK_NE(rs, ZERO); - EmitI21(0x36, rs, imm21); -} - -void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) { - CHECK_NE(rs, ZERO); - EmitI21(0x3E, rs, imm21); -} - -void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) { - EmitFI(0x11, 0x9, ft, imm16); -} - -void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) { - EmitFI(0x11, 0xD, ft, imm16); -} - -void Mips64Assembler::Beq(GpuRegister rs, GpuRegister rt, uint16_t imm16) { - EmitI(0x4, rs, rt, imm16); -} - -void Mips64Assembler::Bne(GpuRegister rs, GpuRegister rt, uint16_t imm16) { - EmitI(0x5, rs, rt, imm16); -} - -void Mips64Assembler::Beqz(GpuRegister rt, uint16_t imm16) { - Beq(rt, ZERO, imm16); -} - -void Mips64Assembler::Bnez(GpuRegister rt, uint16_t imm16) { - Bne(rt, ZERO, imm16); -} - -void Mips64Assembler::Bltz(GpuRegister rt, uint16_t imm16) { - EmitI(0x1, rt, static_cast<GpuRegister>(0), imm16); -} - -void Mips64Assembler::Bgez(GpuRegister rt, uint16_t imm16) { - EmitI(0x1, rt, static_cast<GpuRegister>(0x1), imm16); -} - -void Mips64Assembler::Blez(GpuRegister rt, uint16_t imm16) { - EmitI(0x6, rt, static_cast<GpuRegister>(0), imm16); -} - -void Mips64Assembler::Bgtz(GpuRegister rt, uint16_t imm16) { - EmitI(0x7, rt, static_cast<GpuRegister>(0), imm16); -} - -void Mips64Assembler::EmitBcondR6(BranchCondition cond, - GpuRegister rs, - GpuRegister rt, - uint32_t imm16_21) { - switch (cond) { - case kCondLT: - Bltc(rs, rt, imm16_21); - break; - case kCondGE: - Bgec(rs, rt, imm16_21); - break; - case kCondLE: - Bgec(rt, rs, imm16_21); - break; - case kCondGT: - Bltc(rt, rs, imm16_21); - break; - case kCondLTZ: - CHECK_EQ(rt, ZERO); - Bltzc(rs, imm16_21); - break; - case kCondGEZ: - CHECK_EQ(rt, ZERO); - Bgezc(rs, imm16_21); - break; - case kCondLEZ: - CHECK_EQ(rt, ZERO); - Blezc(rs, imm16_21); - break; - case kCondGTZ: - CHECK_EQ(rt, ZERO); - Bgtzc(rs, imm16_21); - break; - case kCondEQ: - Beqc(rs, rt, imm16_21); - break; - case kCondNE: - Bnec(rs, rt, imm16_21); - break; - case kCondEQZ: - CHECK_EQ(rt, ZERO); - Beqzc(rs, imm16_21); - break; - case kCondNEZ: - CHECK_EQ(rt, ZERO); - Bnezc(rs, imm16_21); - break; - case kCondLTU: - Bltuc(rs, rt, imm16_21); - break; - case kCondGEU: - Bgeuc(rs, rt, imm16_21); - break; - case kCondF: - CHECK_EQ(rt, ZERO); - Bc1eqz(static_cast<FpuRegister>(rs), imm16_21); - break; - case kCondT: - CHECK_EQ(rt, ZERO); - Bc1nez(static_cast<FpuRegister>(rs), imm16_21); - break; - case kUncond: - LOG(FATAL) << "Unexpected branch condition " << cond; - UNREACHABLE(); - } -} - -void Mips64Assembler::EmitBcondR2(BranchCondition cond, - GpuRegister rs, - GpuRegister rt, - uint16_t imm16) { - switch (cond) { - case kCondLTZ: - CHECK_EQ(rt, ZERO); - Bltz(rs, imm16); - break; - case kCondGEZ: - CHECK_EQ(rt, ZERO); - Bgez(rs, imm16); - break; - case kCondLEZ: - CHECK_EQ(rt, ZERO); - Blez(rs, imm16); - break; - case kCondGTZ: - CHECK_EQ(rt, ZERO); - Bgtz(rs, imm16); - break; - case kCondEQ: - Beq(rs, rt, imm16); - break; - case kCondNE: - Bne(rs, rt, imm16); - break; - case kCondEQZ: - CHECK_EQ(rt, ZERO); - Beqz(rs, imm16); - break; - case kCondNEZ: - CHECK_EQ(rt, ZERO); - Bnez(rs, imm16); - break; - case kCondF: - case kCondT: - case kCondLT: - case kCondGE: - case kCondLE: - case kCondGT: - case kCondLTU: - case kCondGEU: - case kUncond: - LOG(FATAL) << "Unexpected branch condition " << cond; - UNREACHABLE(); - } -} - -void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x10, ft, fs, fd, 0x0); -} - -void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x10, ft, fs, fd, 0x1); -} - -void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x10, ft, fs, fd, 0x2); -} - -void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x10, ft, fs, fd, 0x3); -} - -void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x11, ft, fs, fd, 0x0); -} - -void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x11, ft, fs, fd, 0x1); -} - -void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x11, ft, fs, fd, 0x2); -} - -void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x11, ft, fs, fd, 0x3); -} - -void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4); -} - -void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4); -} - -void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5); -} - -void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5); -} - -void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6); -} - -void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6); -} - -void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7); -} - -void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7); -} - -void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8); -} - -void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8); -} - -void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc); -} - -void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc); -} - -void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9); -} - -void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9); -} - -void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd); -} - -void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd); -} - -void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa); -} - -void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa); -} - -void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe); -} - -void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe); -} - -void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb); -} - -void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb); -} - -void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf); -} - -void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf); -} - -void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x10, ft, fs, fd, 0x10); -} - -void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x11, ft, fs, fd, 0x10); -} - -void Mips64Assembler::SeleqzS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x10, ft, fs, fd, 0x14); -} - -void Mips64Assembler::SeleqzD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x11, ft, fs, fd, 0x14); -} - -void Mips64Assembler::SelnezS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x10, ft, fs, fd, 0x17); -} - -void Mips64Assembler::SelnezD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x11, ft, fs, fd, 0x17); -} - -void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a); -} - -void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a); -} - -void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b); -} - -void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b); -} - -void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x10, ft, fs, fd, 0x1c); -} - -void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x11, ft, fs, fd, 0x1c); -} - -void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x10, ft, fs, fd, 0x1e); -} - -void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x11, ft, fs, fd, 0x1e); -} - -void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x01); -} - -void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x02); -} - -void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x03); -} - -void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x04); -} - -void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x05); -} - -void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x06); -} - -void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x07); -} - -void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x11); -} - -void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x12); -} - -void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x14, ft, fs, fd, 0x13); -} - -void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x01); -} - -void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x02); -} - -void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x03); -} - -void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x04); -} - -void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x05); -} - -void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x06); -} - -void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x07); -} - -void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x11); -} - -void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x12); -} - -void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { - EmitFR(0x11, 0x15, ft, fs, fd, 0x13); -} - -void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20); -} - -void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21); -} - -void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20); -} - -void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21); -} - -void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20); -} - -void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) { - EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21); -} - -void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) { - EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); -} - -void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) { - EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); -} - -void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) { - EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); -} - -void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) { - EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); -} - -void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) { - EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); -} - -void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) { - EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); -} - -void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) { - EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16); -} - -void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) { - EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16); -} - -void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) { - EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16); -} - -void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) { - EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16); -} - -void Mips64Assembler::Break() { - EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), - static_cast<GpuRegister>(0), 0, 0xD); -} - -void Mips64Assembler::Nop() { - EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), - static_cast<GpuRegister>(0), 0, 0x0); -} - -void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) { - Or(rd, rs, ZERO); -} - -void Mips64Assembler::Clear(GpuRegister rd) { - Move(rd, ZERO); -} - -void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) { - Nor(rd, rs, ZERO); -} - -void Mips64Assembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e); -} - -void Mips64Assembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e); -} - -void Mips64Assembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e); -} - -void Mips64Assembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e); -} - -void Mips64Assembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe); -} - -void Mips64Assembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe); -} - -void Mips64Assembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe); -} - -void Mips64Assembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe); -} - -void Mips64Assembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe); -} - -void Mips64Assembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe); -} - -void Mips64Assembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe); -} - -void Mips64Assembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Asub_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x11); -} - -void Mips64Assembler::Asub_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x11); -} - -void Mips64Assembler::Asub_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x11); -} - -void Mips64Assembler::Asub_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x11); -} - -void Mips64Assembler::Asub_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x11); -} - -void Mips64Assembler::Asub_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x11); -} - -void Mips64Assembler::Asub_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x11); -} - -void Mips64Assembler::Asub_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x11); -} - -void Mips64Assembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12); -} - -void Mips64Assembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10); -} - -void Mips64Assembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe); -} - -void Mips64Assembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe); -} - -void Mips64Assembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::Ffint_sW(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e); -} - -void Mips64Assembler::Ffint_sD(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e); -} - -void Mips64Assembler::Ftint_sW(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e); -} - -void Mips64Assembler::Ftint_sD(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e); -} - -void Mips64Assembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd); -} - -void Mips64Assembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(shamt3)) << shamt3; - EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9); -} - -void Mips64Assembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(shamt4)) << shamt4; - EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9); -} - -void Mips64Assembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) { - CHECK(HasMsa()); - CHECK(IsUint<5>(shamt5)) << shamt5; - EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9); -} - -void Mips64Assembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) { - CHECK(HasMsa()); - CHECK(IsUint<6>(shamt6)) << shamt6; - EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9); -} - -void Mips64Assembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(shamt3)) << shamt3; - EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9); -} - -void Mips64Assembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(shamt4)) << shamt4; - EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9); -} - -void Mips64Assembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) { - CHECK(HasMsa()); - CHECK(IsUint<5>(shamt5)) << shamt5; - EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9); -} - -void Mips64Assembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) { - CHECK(HasMsa()); - CHECK(IsUint<6>(shamt6)) << shamt6; - EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9); -} - -void Mips64Assembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(shamt3)) << shamt3; - EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9); -} - -void Mips64Assembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(shamt4)) << shamt4; - EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9); -} - -void Mips64Assembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) { - CHECK(HasMsa()); - CHECK(IsUint<5>(shamt5)) << shamt5; - EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9); -} - -void Mips64Assembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) { - CHECK(HasMsa()); - CHECK(IsUint<6>(shamt6)) << shamt6; - EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9); -} - -void Mips64Assembler::MoveV(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19); -} - -void Mips64Assembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(n4)) << n4; - EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19); -} - -void Mips64Assembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(n3)) << n3; - EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19); -} - -void Mips64Assembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) { - CHECK(HasMsa()); - CHECK(IsUint<2>(n2)) << n2; - EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19); -} - -void Mips64Assembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) { - CHECK(HasMsa()); - CHECK(IsUint<1>(n1)) << n1; - EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19); -} - -void Mips64Assembler::Copy_sB(GpuRegister rd, VectorRegister ws, int n4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(n4)) << n4; - EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19); -} - -void Mips64Assembler::Copy_sH(GpuRegister rd, VectorRegister ws, int n3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(n3)) << n3; - EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19); -} - -void Mips64Assembler::Copy_sW(GpuRegister rd, VectorRegister ws, int n2) { - CHECK(HasMsa()); - CHECK(IsUint<2>(n2)) << n2; - EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19); -} - -void Mips64Assembler::Copy_sD(GpuRegister rd, VectorRegister ws, int n1) { - CHECK(HasMsa()); - CHECK(IsUint<1>(n1)) << n1; - EmitMsaELM(0x2, n1 | kMsaDfNDoublewordMask, ws, static_cast<VectorRegister>(rd), 0x19); -} - -void Mips64Assembler::Copy_uB(GpuRegister rd, VectorRegister ws, int n4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(n4)) << n4; - EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19); -} - -void Mips64Assembler::Copy_uH(GpuRegister rd, VectorRegister ws, int n3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(n3)) << n3; - EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19); -} - -void Mips64Assembler::Copy_uW(GpuRegister rd, VectorRegister ws, int n2) { - CHECK(HasMsa()); - CHECK(IsUint<2>(n2)) << n2; - EmitMsaELM(0x3, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19); -} - -void Mips64Assembler::InsertB(VectorRegister wd, GpuRegister rs, int n4) { - CHECK(HasMsa()); - CHECK(IsUint<4>(n4)) << n4; - EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19); -} - -void Mips64Assembler::InsertH(VectorRegister wd, GpuRegister rs, int n3) { - CHECK(HasMsa()); - CHECK(IsUint<3>(n3)) << n3; - EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19); -} - -void Mips64Assembler::InsertW(VectorRegister wd, GpuRegister rs, int n2) { - CHECK(HasMsa()); - CHECK(IsUint<2>(n2)) << n2; - EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19); -} - -void Mips64Assembler::InsertD(VectorRegister wd, GpuRegister rs, int n1) { - CHECK(HasMsa()); - CHECK(IsUint<1>(n1)) << n1; - EmitMsaELM(0x4, n1 | kMsaDfNDoublewordMask, static_cast<VectorRegister>(rs), wd, 0x19); -} - -void Mips64Assembler::FillB(VectorRegister wd, GpuRegister rs) { - CHECK(HasMsa()); - EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e); -} - -void Mips64Assembler::FillH(VectorRegister wd, GpuRegister rs) { - CHECK(HasMsa()); - EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e); -} - -void Mips64Assembler::FillW(VectorRegister wd, GpuRegister rs) { - CHECK(HasMsa()); - EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e); -} - -void Mips64Assembler::FillD(VectorRegister wd, GpuRegister rs) { - CHECK(HasMsa()); - EmitMsa2R(0xc0, 0x3, static_cast<VectorRegister>(rs), wd, 0x1e); -} - -void Mips64Assembler::LdiB(VectorRegister wd, int imm8) { - CHECK(HasMsa()); - CHECK(IsInt<8>(imm8)) << imm8; - EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7); -} - -void Mips64Assembler::LdiH(VectorRegister wd, int imm10) { - CHECK(HasMsa()); - CHECK(IsInt<10>(imm10)) << imm10; - EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7); -} - -void Mips64Assembler::LdiW(VectorRegister wd, int imm10) { - CHECK(HasMsa()); - CHECK(IsInt<10>(imm10)) << imm10; - EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7); -} - -void Mips64Assembler::LdiD(VectorRegister wd, int imm10) { - CHECK(HasMsa()); - CHECK(IsInt<10>(imm10)) << imm10; - EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7); -} - -void Mips64Assembler::LdB(VectorRegister wd, GpuRegister rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<10>(offset)) << offset; - EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0); -} - -void Mips64Assembler::LdH(VectorRegister wd, GpuRegister rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<11>(offset)) << offset; - CHECK_ALIGNED(offset, kMips64HalfwordSize); - EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1); -} - -void Mips64Assembler::LdW(VectorRegister wd, GpuRegister rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<12>(offset)) << offset; - CHECK_ALIGNED(offset, kMips64WordSize); - EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2); -} - -void Mips64Assembler::LdD(VectorRegister wd, GpuRegister rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<13>(offset)) << offset; - CHECK_ALIGNED(offset, kMips64DoublewordSize); - EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3); -} - -void Mips64Assembler::StB(VectorRegister wd, GpuRegister rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<10>(offset)) << offset; - EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0); -} - -void Mips64Assembler::StH(VectorRegister wd, GpuRegister rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<11>(offset)) << offset; - CHECK_ALIGNED(offset, kMips64HalfwordSize); - EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1); -} - -void Mips64Assembler::StW(VectorRegister wd, GpuRegister rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<12>(offset)) << offset; - CHECK_ALIGNED(offset, kMips64WordSize); - EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2); -} - -void Mips64Assembler::StD(VectorRegister wd, GpuRegister rs, int offset) { - CHECK(HasMsa()); - CHECK(IsInt<13>(offset)) << offset; - CHECK_ALIGNED(offset, kMips64DoublewordSize); - EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3); -} - -void Mips64Assembler::IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14); -} - -void Mips64Assembler::IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14); -} - -void Mips64Assembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12); -} - -void Mips64Assembler::MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12); -} - -void Mips64Assembler::FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b); -} - -void Mips64Assembler::Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15); -} - -void Mips64Assembler::Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15); -} - -void Mips64Assembler::Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15); -} - -void Mips64Assembler::Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15); -} - -void Mips64Assembler::Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15); -} - -void Mips64Assembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { - CHECK(HasMsa()); - EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15); -} - -void Mips64Assembler::PcntB(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - EmitMsa2R(0xc1, 0x0, ws, wd, 0x1e); -} - -void Mips64Assembler::PcntH(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - EmitMsa2R(0xc1, 0x1, ws, wd, 0x1e); -} - -void Mips64Assembler::PcntW(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - EmitMsa2R(0xc1, 0x2, ws, wd, 0x1e); -} - -void Mips64Assembler::PcntD(VectorRegister wd, VectorRegister ws) { - CHECK(HasMsa()); - EmitMsa2R(0xc1, 0x3, ws, wd, 0x1e); -} - -void Mips64Assembler::ReplicateFPToVectorRegister(VectorRegister dst, - FpuRegister src, - bool is_double) { - // Float or double in FPU register Fx can be considered as 0th element in vector register Wx. - if (is_double) { - SplatiD(dst, static_cast<VectorRegister>(src), 0); - } else { - SplatiW(dst, static_cast<VectorRegister>(src), 0); - } -} - -void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) { - TemplateLoadConst32(this, rd, value); -} - -// This function is only used for testing purposes. -void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) { -} - -void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) { - TemplateLoadConst64(this, rd, value); -} - -void Mips64Assembler::Addiu32(GpuRegister rt, GpuRegister rs, int32_t value) { - if (IsInt<16>(value)) { - Addiu(rt, rs, value); - } else { - int16_t high = High16Bits(value); - int16_t low = Low16Bits(value); - high += (low < 0) ? 1 : 0; // Account for sign extension in addiu. - Aui(rt, rs, high); - if (low != 0) { - Addiu(rt, rt, low); - } - } -} - -// TODO: don't use rtmp, use daui, dahi, dati. -void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) { - CHECK_NE(rs, rtmp); - if (IsInt<16>(value)) { - Daddiu(rt, rs, value); - } else { - LoadConst64(rtmp, value); - Daddu(rt, rs, rtmp); - } -} - -void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size, - Mips64Assembler::Branch::Type short_type, - Mips64Assembler::Branch::Type long_type) { - type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type; -} - -void Mips64Assembler::Branch::InitializeType(Type initial_type, bool is_r6) { - OffsetBits offset_size_needed = GetOffsetSizeNeeded(location_, target_); - if (is_r6) { - // R6 - switch (initial_type) { - case kLabel: - case kLiteral: - case kLiteralUnsigned: - case kLiteralLong: - CHECK(!IsResolved()); - type_ = initial_type; - break; - case kCall: - InitShortOrLong(offset_size_needed, kCall, kLongCall); - break; - case kCondBranch: - switch (condition_) { - case kUncond: - InitShortOrLong(offset_size_needed, kUncondBranch, kLongUncondBranch); - break; - case kCondEQZ: - case kCondNEZ: - // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions. - type_ = (offset_size_needed <= kOffset23) ? kCondBranch : kLongCondBranch; - break; - default: - InitShortOrLong(offset_size_needed, kCondBranch, kLongCondBranch); - break; - } - break; - case kBareCall: - type_ = kBareCall; - CHECK_LE(offset_size_needed, GetOffsetSize()); - break; - case kBareCondBranch: - type_ = (condition_ == kUncond) ? kBareUncondBranch : kBareCondBranch; - CHECK_LE(offset_size_needed, GetOffsetSize()); - break; - default: - LOG(FATAL) << "Unexpected branch type " << initial_type; - UNREACHABLE(); - } - } else { - // R2 - CHECK_EQ(initial_type, kBareCondBranch); - switch (condition_) { - case kCondLTZ: - case kCondGEZ: - case kCondLEZ: - case kCondGTZ: - case kCondEQ: - case kCondNE: - case kCondEQZ: - case kCondNEZ: - break; - default: - LOG(FATAL) << "Unexpected R2 branch condition " << condition_; - UNREACHABLE(); - } - type_ = kR2BareCondBranch; - CHECK_LE(offset_size_needed, GetOffsetSize()); - } - old_type_ = type_; -} - -bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) { - switch (condition) { - case kCondLT: - case kCondGT: - case kCondNE: - case kCondLTU: - return lhs == rhs; - default: - return false; - } -} - -bool Mips64Assembler::Branch::IsUncond(BranchCondition condition, - GpuRegister lhs, - GpuRegister rhs) { - switch (condition) { - case kUncond: - return true; - case kCondGE: - case kCondLE: - case kCondEQ: - case kCondGEU: - return lhs == rhs; - default: - return false; - } -} - -Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, bool is_call, bool is_bare) - : old_location_(location), - location_(location), - target_(target), - lhs_reg_(ZERO), - rhs_reg_(ZERO), - condition_(kUncond) { - InitializeType( - (is_call ? (is_bare ? kBareCall : kCall) : (is_bare ? kBareCondBranch : kCondBranch)), - /* is_r6= */ true); -} - -Mips64Assembler::Branch::Branch(bool is_r6, - uint32_t location, - uint32_t target, - Mips64Assembler::BranchCondition condition, - GpuRegister lhs_reg, - GpuRegister rhs_reg, - bool is_bare) - : old_location_(location), - location_(location), - target_(target), - lhs_reg_(lhs_reg), - rhs_reg_(rhs_reg), - condition_(condition) { - CHECK_NE(condition, kUncond); - switch (condition) { - case kCondEQ: - case kCondNE: - case kCondLT: - case kCondGE: - case kCondLE: - case kCondGT: - case kCondLTU: - case kCondGEU: - CHECK_NE(lhs_reg, ZERO); - CHECK_NE(rhs_reg, ZERO); - break; - case kCondLTZ: - case kCondGEZ: - case kCondLEZ: - case kCondGTZ: - case kCondEQZ: - case kCondNEZ: - CHECK_NE(lhs_reg, ZERO); - CHECK_EQ(rhs_reg, ZERO); - break; - case kCondF: - case kCondT: - CHECK_EQ(rhs_reg, ZERO); - break; - case kUncond: - UNREACHABLE(); - } - CHECK(!IsNop(condition, lhs_reg, rhs_reg)); - if (IsUncond(condition, lhs_reg, rhs_reg)) { - // Branch condition is always true, make the branch unconditional. - condition_ = kUncond; - } - InitializeType((is_bare ? kBareCondBranch : kCondBranch), is_r6); -} - -Mips64Assembler::Branch::Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type) - : old_location_(location), - location_(location), - target_(kUnresolved), - lhs_reg_(dest_reg), - rhs_reg_(ZERO), - condition_(kUncond) { - CHECK_NE(dest_reg, ZERO); - InitializeType(label_or_literal_type, /* is_r6= */ true); -} - -Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition( - Mips64Assembler::BranchCondition cond) { - switch (cond) { - case kCondLT: - return kCondGE; - case kCondGE: - return kCondLT; - case kCondLE: - return kCondGT; - case kCondGT: - return kCondLE; - case kCondLTZ: - return kCondGEZ; - case kCondGEZ: - return kCondLTZ; - case kCondLEZ: - return kCondGTZ; - case kCondGTZ: - return kCondLEZ; - case kCondEQ: - return kCondNE; - case kCondNE: - return kCondEQ; - case kCondEQZ: - return kCondNEZ; - case kCondNEZ: - return kCondEQZ; - case kCondLTU: - return kCondGEU; - case kCondGEU: - return kCondLTU; - case kCondF: - return kCondT; - case kCondT: - return kCondF; - case kUncond: - LOG(FATAL) << "Unexpected branch condition " << cond; - } - UNREACHABLE(); -} - -Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const { - return type_; -} - -Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const { - return condition_; -} - -GpuRegister Mips64Assembler::Branch::GetLeftRegister() const { - return lhs_reg_; -} - -GpuRegister Mips64Assembler::Branch::GetRightRegister() const { - return rhs_reg_; -} - -uint32_t Mips64Assembler::Branch::GetTarget() const { - return target_; -} - -uint32_t Mips64Assembler::Branch::GetLocation() const { - return location_; -} - -uint32_t Mips64Assembler::Branch::GetOldLocation() const { - return old_location_; -} - -uint32_t Mips64Assembler::Branch::GetLength() const { - return branch_info_[type_].length; -} - -uint32_t Mips64Assembler::Branch::GetOldLength() const { - return branch_info_[old_type_].length; -} - -uint32_t Mips64Assembler::Branch::GetSize() const { - return GetLength() * sizeof(uint32_t); -} - -uint32_t Mips64Assembler::Branch::GetOldSize() const { - return GetOldLength() * sizeof(uint32_t); -} - -uint32_t Mips64Assembler::Branch::GetEndLocation() const { - return GetLocation() + GetSize(); -} - -uint32_t Mips64Assembler::Branch::GetOldEndLocation() const { - return GetOldLocation() + GetOldSize(); -} - -bool Mips64Assembler::Branch::IsBare() const { - switch (type_) { - // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. - case kBareUncondBranch: - case kBareCondBranch: - case kBareCall: - // R2 short branches (can't be promoted to long), delay slots filled manually. - case kR2BareCondBranch: - return true; - default: - return false; - } -} - -bool Mips64Assembler::Branch::IsLong() const { - switch (type_) { - // R6 short branches (can be promoted to long). - case kUncondBranch: - case kCondBranch: - case kCall: - // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. - case kBareUncondBranch: - case kBareCondBranch: - case kBareCall: - // R2 short branches (can't be promoted to long), delay slots filled manually. - case kR2BareCondBranch: - // Near label. - case kLabel: - // Near literals. - case kLiteral: - case kLiteralUnsigned: - case kLiteralLong: - return false; - // Long branches. - case kLongUncondBranch: - case kLongCondBranch: - case kLongCall: - // Far label. - case kFarLabel: - // Far literals. - case kFarLiteral: - case kFarLiteralUnsigned: - case kFarLiteralLong: - return true; - } - UNREACHABLE(); -} - -bool Mips64Assembler::Branch::IsResolved() const { - return target_ != kUnresolved; -} - -Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const { - bool r6_cond_branch = (type_ == kCondBranch || type_ == kBareCondBranch); - OffsetBits offset_size = - (r6_cond_branch && (condition_ == kCondEQZ || condition_ == kCondNEZ)) - ? kOffset23 - : branch_info_[type_].offset_size; - return offset_size; -} - -Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location, - uint32_t target) { - // For unresolved targets assume the shortest encoding - // (later it will be made longer if needed). - if (target == kUnresolved) - return kOffset16; - int64_t distance = static_cast<int64_t>(target) - location; - // To simplify calculations in composite branches consisting of multiple instructions - // bump up the distance by a value larger than the max byte size of a composite branch. - distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize; - if (IsInt<kOffset16>(distance)) - return kOffset16; - else if (IsInt<kOffset18>(distance)) - return kOffset18; - else if (IsInt<kOffset21>(distance)) - return kOffset21; - else if (IsInt<kOffset23>(distance)) - return kOffset23; - else if (IsInt<kOffset28>(distance)) - return kOffset28; - return kOffset32; -} - -void Mips64Assembler::Branch::Resolve(uint32_t target) { - target_ = target; -} - -void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) { - if (location_ > expand_location) { - location_ += delta; - } - if (!IsResolved()) { - return; // Don't know the target yet. - } - if (target_ > expand_location) { - target_ += delta; - } -} - -void Mips64Assembler::Branch::PromoteToLong() { - CHECK(!IsBare()); // Bare branches do not promote. - switch (type_) { - // R6 short branches (can be promoted to long). - case kUncondBranch: - type_ = kLongUncondBranch; - break; - case kCondBranch: - type_ = kLongCondBranch; - break; - case kCall: - type_ = kLongCall; - break; - // Near label. - case kLabel: - type_ = kFarLabel; - break; - // Near literals. - case kLiteral: - type_ = kFarLiteral; - break; - case kLiteralUnsigned: - type_ = kFarLiteralUnsigned; - break; - case kLiteralLong: - type_ = kFarLiteralLong; - break; - default: - // Note: 'type_' is already long. - break; - } - CHECK(IsLong()); -} - -uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) { - // If the branch is still unresolved or already long, nothing to do. - if (IsLong() || !IsResolved()) { - return 0; - } - // Promote the short branch to long if the offset size is too small - // to hold the distance between location_ and target_. - if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) { - PromoteToLong(); - uint32_t old_size = GetOldSize(); - uint32_t new_size = GetSize(); - CHECK_GT(new_size, old_size); - return new_size - old_size; - } - // The following logic is for debugging/testing purposes. - // Promote some short branches to long when it's not really required. - if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max() && !IsBare())) { - int64_t distance = static_cast<int64_t>(target_) - location_; - distance = (distance >= 0) ? distance : -distance; - if (distance >= max_short_distance) { - PromoteToLong(); - uint32_t old_size = GetOldSize(); - uint32_t new_size = GetSize(); - CHECK_GT(new_size, old_size); - return new_size - old_size; - } - } - return 0; -} - -uint32_t Mips64Assembler::Branch::GetOffsetLocation() const { - return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t); -} - -uint32_t Mips64Assembler::Branch::GetOffset() const { - CHECK(IsResolved()); - uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize()); - // Calculate the byte distance between instructions and also account for - // different PC-relative origins. - uint32_t offset_location = GetOffsetLocation(); - if (type_ == kLiteralLong) { - // Special case for the ldpc instruction, whose address (PC) is rounded down to - // a multiple of 8 before adding the offset. - // Note, branch promotion has already taken care of aligning `target_` to an - // address that's a multiple of 8. - offset_location = RoundDown(offset_location, sizeof(uint64_t)); - } - uint32_t offset = target_ - offset_location - branch_info_[type_].pc_org * sizeof(uint32_t); - // Prepare the offset for encoding into the instruction(s). - offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift; - return offset; -} - -Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) { - CHECK_LT(branch_id, branches_.size()); - return &branches_[branch_id]; -} - -const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const { - CHECK_LT(branch_id, branches_.size()); - return &branches_[branch_id]; -} - -void Mips64Assembler::Bind(Mips64Label* label) { - CHECK(!label->IsBound()); - uint32_t bound_pc = buffer_.Size(); - - // Walk the list of branches referring to and preceding this label. - // Store the previously unknown target addresses in them. - while (label->IsLinked()) { - uint32_t branch_id = label->Position(); - Branch* branch = GetBranch(branch_id); - branch->Resolve(bound_pc); - - uint32_t branch_location = branch->GetLocation(); - // Extract the location of the previous branch in the list (walking the list backwards; - // the previous branch ID was stored in the space reserved for this branch). - uint32_t prev = buffer_.Load<uint32_t>(branch_location); - - // On to the previous branch in the list... - label->position_ = prev; - } - - // Now make the label object contain its own location (relative to the end of the preceding - // branch, if any; it will be used by the branches referring to and following this label). - label->prev_branch_id_plus_one_ = branches_.size(); - if (label->prev_branch_id_plus_one_) { - uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; - const Branch* branch = GetBranch(branch_id); - bound_pc -= branch->GetEndLocation(); - } - label->BindTo(bound_pc); -} - -uint32_t Mips64Assembler::GetLabelLocation(const Mips64Label* label) const { - CHECK(label->IsBound()); - uint32_t target = label->Position(); - if (label->prev_branch_id_plus_one_) { - // Get label location based on the branch preceding it. - uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; - const Branch* branch = GetBranch(branch_id); - target += branch->GetEndLocation(); - } - return target; -} - -uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) { - // We can reconstruct the adjustment by going through all the branches from the beginning - // up to the old_position. Since we expect AdjustedPosition() to be called in a loop - // with increasing old_position, we can use the data from last AdjustedPosition() to - // continue where we left off and the whole loop should be O(m+n) where m is the number - // of positions to adjust and n is the number of branches. - if (old_position < last_old_position_) { - last_position_adjustment_ = 0; - last_old_position_ = 0; - last_branch_id_ = 0; - } - while (last_branch_id_ != branches_.size()) { - const Branch* branch = GetBranch(last_branch_id_); - if (branch->GetLocation() >= old_position + last_position_adjustment_) { - break; - } - last_position_adjustment_ += branch->GetSize() - branch->GetOldSize(); - ++last_branch_id_; - } - last_old_position_ = old_position; - return old_position + last_position_adjustment_; -} - -void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) { - uint32_t length = branches_.back().GetLength(); - if (!label->IsBound()) { - // Branch forward (to a following label), distance is unknown. - // The first branch forward will contain 0, serving as the terminator of - // the list of forward-reaching branches. - Emit(label->position_); - length--; - // Now make the label object point to this branch - // (this forms a linked list of branches preceding this label). - uint32_t branch_id = branches_.size() - 1; - label->LinkTo(branch_id); - } - // Reserve space for the branch. - for (; length != 0u; --length) { - Nop(); - } -} - -void Mips64Assembler::Buncond(Mips64Label* label, bool is_bare) { - uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; - branches_.emplace_back(buffer_.Size(), target, /* is_call= */ false, is_bare); - FinalizeLabeledBranch(label); -} - -void Mips64Assembler::Bcond(Mips64Label* label, - bool is_r6, - bool is_bare, - BranchCondition condition, - GpuRegister lhs, - GpuRegister rhs) { - // If lhs = rhs, this can be a NOP. - if (Branch::IsNop(condition, lhs, rhs)) { - return; - } - uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; - branches_.emplace_back(is_r6, buffer_.Size(), target, condition, lhs, rhs, is_bare); - FinalizeLabeledBranch(label); -} - -void Mips64Assembler::Call(Mips64Label* label, bool is_bare) { - uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; - branches_.emplace_back(buffer_.Size(), target, /* is_call= */ true, is_bare); - FinalizeLabeledBranch(label); -} - -void Mips64Assembler::LoadLabelAddress(GpuRegister dest_reg, Mips64Label* label) { - // Label address loads are treated as pseudo branches since they require very similar handling. - DCHECK(!label->IsBound()); - branches_.emplace_back(buffer_.Size(), dest_reg, Branch::kLabel); - FinalizeLabeledBranch(label); -} - -Literal* Mips64Assembler::NewLiteral(size_t size, const uint8_t* data) { - // We don't support byte and half-word literals. - if (size == 4u) { - literals_.emplace_back(size, data); - return &literals_.back(); - } else { - DCHECK_EQ(size, 8u); - long_literals_.emplace_back(size, data); - return &long_literals_.back(); - } -} - -void Mips64Assembler::LoadLiteral(GpuRegister dest_reg, - LoadOperandType load_type, - Literal* literal) { - // Literal loads are treated as pseudo branches since they require very similar handling. - Branch::Type literal_type; - switch (load_type) { - case kLoadWord: - DCHECK_EQ(literal->GetSize(), 4u); - literal_type = Branch::kLiteral; - break; - case kLoadUnsignedWord: - DCHECK_EQ(literal->GetSize(), 4u); - literal_type = Branch::kLiteralUnsigned; - break; - case kLoadDoubleword: - DCHECK_EQ(literal->GetSize(), 8u); - literal_type = Branch::kLiteralLong; - break; - default: - LOG(FATAL) << "Unexpected literal load type " << load_type; - UNREACHABLE(); - } - Mips64Label* label = literal->GetLabel(); - DCHECK(!label->IsBound()); - branches_.emplace_back(buffer_.Size(), dest_reg, literal_type); - FinalizeLabeledBranch(label); -} - -JumpTable* Mips64Assembler::CreateJumpTable(std::vector<Mips64Label*>&& labels) { - jump_tables_.emplace_back(std::move(labels)); - JumpTable* table = &jump_tables_.back(); - DCHECK(!table->GetLabel()->IsBound()); - return table; -} - -void Mips64Assembler::ReserveJumpTableSpace() { - if (!jump_tables_.empty()) { - for (JumpTable& table : jump_tables_) { - Mips64Label* label = table.GetLabel(); - Bind(label); - - // Bulk ensure capacity, as this may be large. - size_t orig_size = buffer_.Size(); - size_t required_capacity = orig_size + table.GetSize(); - if (required_capacity > buffer_.Capacity()) { - buffer_.ExtendCapacity(required_capacity); - } -#ifndef NDEBUG - buffer_.has_ensured_capacity_ = true; -#endif - - // Fill the space with dummy data as the data is not final - // until the branches have been promoted. And we shouldn't - // be moving uninitialized data during branch promotion. - for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) { - buffer_.Emit<uint32_t>(0x1abe1234u); - } - -#ifndef NDEBUG - buffer_.has_ensured_capacity_ = false; -#endif - } - } -} - -void Mips64Assembler::EmitJumpTables() { - if (!jump_tables_.empty()) { - CHECK(!overwriting_); - // Switch from appending instructions at the end of the buffer to overwriting - // existing instructions (here, jump tables) in the buffer. - overwriting_ = true; - - for (JumpTable& table : jump_tables_) { - Mips64Label* table_label = table.GetLabel(); - uint32_t start = GetLabelLocation(table_label); - overwrite_location_ = start; - - for (Mips64Label* target : table.GetData()) { - CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u); - // The table will contain target addresses relative to the table start. - uint32_t offset = GetLabelLocation(target) - start; - Emit(offset); - } - } - - overwriting_ = false; - } -} - -void Mips64Assembler::EmitLiterals() { - if (!literals_.empty()) { - for (Literal& literal : literals_) { - Mips64Label* label = literal.GetLabel(); - Bind(label); - AssemblerBuffer::EnsureCapacity ensured(&buffer_); - DCHECK_EQ(literal.GetSize(), 4u); - for (size_t i = 0, size = literal.GetSize(); i != size; ++i) { - buffer_.Emit<uint8_t>(literal.GetData()[i]); - } - } - } - if (!long_literals_.empty()) { - // Reserve 4 bytes for potential alignment. If after the branch promotion the 64-bit - // literals don't end up 8-byte-aligned, they will be moved down 4 bytes. - Emit(0); // NOP. - for (Literal& literal : long_literals_) { - Mips64Label* label = literal.GetLabel(); - Bind(label); - AssemblerBuffer::EnsureCapacity ensured(&buffer_); - DCHECK_EQ(literal.GetSize(), 8u); - for (size_t i = 0, size = literal.GetSize(); i != size; ++i) { - buffer_.Emit<uint8_t>(literal.GetData()[i]); - } - } - } -} - -void Mips64Assembler::PromoteBranches() { - // Promote short branches to long as necessary. - bool changed; - do { - changed = false; - for (auto& branch : branches_) { - CHECK(branch.IsResolved()); - uint32_t delta = branch.PromoteIfNeeded(); - // If this branch has been promoted and needs to expand in size, - // relocate all branches by the expansion size. - if (delta) { - changed = true; - uint32_t expand_location = branch.GetLocation(); - for (auto& branch2 : branches_) { - branch2.Relocate(expand_location, delta); - } - } - } - } while (changed); - - // Account for branch expansion by resizing the code buffer - // and moving the code in it to its final location. - size_t branch_count = branches_.size(); - if (branch_count > 0) { - // Resize. - Branch& last_branch = branches_[branch_count - 1]; - uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation(); - uint32_t old_size = buffer_.Size(); - buffer_.Resize(old_size + size_delta); - // Move the code residing between branch placeholders. - uint32_t end = old_size; - for (size_t i = branch_count; i > 0; ) { - Branch& branch = branches_[--i]; - uint32_t size = end - branch.GetOldEndLocation(); - buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size); - end = branch.GetOldLocation(); - } - } - - // Align 64-bit literals by moving them down by 4 bytes if needed. - // This will reduce the PC-relative distance, which should be safe for both near and far literals. - if (!long_literals_.empty()) { - uint32_t first_literal_location = GetLabelLocation(long_literals_.front().GetLabel()); - size_t lit_size = long_literals_.size() * sizeof(uint64_t); - size_t buf_size = buffer_.Size(); - // 64-bit literals must be at the very end of the buffer. - CHECK_EQ(first_literal_location + lit_size, buf_size); - if (!IsAligned<sizeof(uint64_t)>(first_literal_location)) { - buffer_.Move(first_literal_location - sizeof(uint32_t), first_literal_location, lit_size); - // The 4 reserved bytes proved useless, reduce the buffer size. - buffer_.Resize(buf_size - sizeof(uint32_t)); - // Reduce target addresses in literal and address loads by 4 bytes in order for correct - // offsets from PC to be generated. - for (auto& branch : branches_) { - uint32_t target = branch.GetTarget(); - if (target >= first_literal_location) { - branch.Resolve(target - sizeof(uint32_t)); - } - } - // If after this we ever call GetLabelLocation() to get the location of a 64-bit literal, - // we need to adjust the location of the literal's label as well. - for (Literal& literal : long_literals_) { - // Bound label's position is negative, hence incrementing it instead of decrementing. - literal.GetLabel()->position_ += sizeof(uint32_t); - } - } - } -} - -// Note: make sure branch_info_[] and EmitBranch() are kept synchronized. -const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = { - // R6 short branches (can be promoted to long). - { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch - { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch - // Exception: kOffset23 for beqzc/bnezc - { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kCall - // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. - { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kBareUncondBranch - { 1, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kBareCondBranch - // Exception: kOffset23 for beqzc/bnezc - { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kBareCall - // R2 short branches (can't be promoted to long), delay slots filled manually. - { 1, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kR2BareCondBranch - // Near label. - { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLabel - // Near literals. - { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteral - { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLiteralUnsigned - { 1, 0, 0, Mips64Assembler::Branch::kOffset21, 3 }, // kLiteralLong - // Long branches. - { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch - { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch - { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall - // Far label. - { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLabel - // Far literals. - { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteral - { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralUnsigned - { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kFarLiteralLong -}; - -// Note: make sure branch_info_[] and EmitBranch() are kept synchronized. -void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) { - CHECK(overwriting_); - overwrite_location_ = branch->GetLocation(); - uint32_t offset = branch->GetOffset(); - BranchCondition condition = branch->GetCondition(); - GpuRegister lhs = branch->GetLeftRegister(); - GpuRegister rhs = branch->GetRightRegister(); - switch (branch->GetType()) { - // Short branches. - case Branch::kUncondBranch: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Bc(offset); - break; - case Branch::kCondBranch: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - EmitBcondR6(condition, lhs, rhs, offset); - Nop(); // TODO: improve by filling the forbidden/delay slot. - break; - case Branch::kCall: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Balc(offset); - break; - case Branch::kBareUncondBranch: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Bc(offset); - break; - case Branch::kBareCondBranch: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - EmitBcondR6(condition, lhs, rhs, offset); - break; - case Branch::kBareCall: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Balc(offset); - break; - case Branch::kR2BareCondBranch: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - EmitBcondR2(condition, lhs, rhs, offset); - break; - - // Near label. - case Branch::kLabel: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Addiupc(lhs, offset); - break; - // Near literals. - case Branch::kLiteral: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Lwpc(lhs, offset); - break; - case Branch::kLiteralUnsigned: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Lwupc(lhs, offset); - break; - case Branch::kLiteralLong: - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Ldpc(lhs, offset); - break; - - // Long branches. - case Branch::kLongUncondBranch: - offset += (offset & 0x8000) << 1; // Account for sign extension in jic. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Jic(AT, Low16Bits(offset)); - break; - case Branch::kLongCondBranch: - EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2); - offset += (offset & 0x8000) << 1; // Account for sign extension in jic. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Jic(AT, Low16Bits(offset)); - break; - case Branch::kLongCall: - offset += (offset & 0x8000) << 1; // Account for sign extension in jialc. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Jialc(AT, Low16Bits(offset)); - break; - - // Far label. - case Branch::kFarLabel: - offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Daddiu(lhs, AT, Low16Bits(offset)); - break; - // Far literals. - case Branch::kFarLiteral: - offset += (offset & 0x8000) << 1; // Account for sign extension in lw. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Lw(lhs, AT, Low16Bits(offset)); - break; - case Branch::kFarLiteralUnsigned: - offset += (offset & 0x8000) << 1; // Account for sign extension in lwu. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Lwu(lhs, AT, Low16Bits(offset)); - break; - case Branch::kFarLiteralLong: - offset += (offset & 0x8000) << 1; // Account for sign extension in ld. - CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - Auipc(AT, High16Bits(offset)); - Ld(lhs, AT, Low16Bits(offset)); - break; - } - CHECK_EQ(overwrite_location_, branch->GetEndLocation()); - CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize)); -} - -void Mips64Assembler::Bc(Mips64Label* label, bool is_bare) { - Buncond(label, is_bare); -} - -void Mips64Assembler::Balc(Mips64Label* label, bool is_bare) { - Call(label, is_bare); -} - -void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondLT, rs, rt); -} - -void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondLTZ, rt); -} - -void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondGTZ, rt); -} - -void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondGE, rs, rt); -} - -void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondGEZ, rt); -} - -void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondLEZ, rt); -} - -void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondLTU, rs, rt); -} - -void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondGEU, rs, rt); -} - -void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondEQ, rs, rt); -} - -void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondNE, rs, rt); -} - -void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondEQZ, rs); -} - -void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondNEZ, rs); -} - -void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondF, static_cast<GpuRegister>(ft), ZERO); -} - -void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label, bool is_bare) { - Bcond(label, /* is_r6= */ true, is_bare, kCondT, static_cast<GpuRegister>(ft), ZERO); -} - -void Mips64Assembler::Bltz(GpuRegister rt, Mips64Label* label, bool is_bare) { - CHECK(is_bare); - Bcond(label, /* is_r6= */ false, is_bare, kCondLTZ, rt); -} - -void Mips64Assembler::Bgtz(GpuRegister rt, Mips64Label* label, bool is_bare) { - CHECK(is_bare); - Bcond(label, /* is_r6= */ false, is_bare, kCondGTZ, rt); -} - -void Mips64Assembler::Bgez(GpuRegister rt, Mips64Label* label, bool is_bare) { - CHECK(is_bare); - Bcond(label, /* is_r6= */ false, is_bare, kCondGEZ, rt); -} - -void Mips64Assembler::Blez(GpuRegister rt, Mips64Label* label, bool is_bare) { - CHECK(is_bare); - Bcond(label, /* is_r6= */ false, is_bare, kCondLEZ, rt); -} - -void Mips64Assembler::Beq(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) { - CHECK(is_bare); - Bcond(label, /* is_r6= */ false, is_bare, kCondEQ, rs, rt); -} - -void Mips64Assembler::Bne(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) { - CHECK(is_bare); - Bcond(label, /* is_r6= */ false, is_bare, kCondNE, rs, rt); -} - -void Mips64Assembler::Beqz(GpuRegister rs, Mips64Label* label, bool is_bare) { - CHECK(is_bare); - Bcond(label, /* is_r6= */ false, is_bare, kCondEQZ, rs); -} - -void Mips64Assembler::Bnez(GpuRegister rs, Mips64Label* label, bool is_bare) { - CHECK(is_bare); - Bcond(label, /* is_r6= */ false, is_bare, kCondNEZ, rs); -} - -void Mips64Assembler::AdjustBaseAndOffset(GpuRegister& base, - int32_t& offset, - bool is_doubleword) { - // 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<kMips64DoublewordSize>(offset); - bool two_accesses = is_doubleword && !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 + kMips64WordSize)))) { - // 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 & (kMips64DoublewordSize - 1); - - // First, see if `offset` can be represented as a sum of two 16-bit signed - // offsets. This can save an instruction. - // 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) { - Daddiu(AT, base, kMinOffsetForSimpleAdjustment); - offset -= kMinOffsetForSimpleAdjustment; - } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) { - Daddiu(AT, base, -kMinOffsetForSimpleAdjustment); - offset += kMinOffsetForSimpleAdjustment; - } else { - // In more complex cases take advantage of the daui instruction, e.g.: - // daui AT, base, offset_high - // [dahi AT, 1] // When `offset` is close to +2GB. - // lw reg_lo, offset_low(AT) - // [lw reg_hi, (offset_low+4)(AT)] // If misaligned 64-bit load. - // or when offset_low+4 overflows int16_t: - // daui AT, base, offset_high - // daddiu AT, AT, 8 - // lw reg_lo, (offset_low-8)(AT) - // lw reg_hi, (offset_low-4)(AT) - int16_t offset_low = Low16Bits(offset); - int32_t offset_low32 = offset_low; - int16_t offset_high = High16Bits(offset); - bool increment_hi16 = offset_low < 0; - bool overflow_hi16 = false; - - if (increment_hi16) { - offset_high++; - overflow_hi16 = (offset_high == -32768); - } - Daui(AT, base, offset_high); - - if (overflow_hi16) { - Dahi(AT, 1); - } - - if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low32 + kMips64WordSize))) { - // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4. - Daddiu(AT, AT, kMips64DoublewordSize); - offset_low32 -= kMips64DoublewordSize; - } - - offset = offset_low32; - } - base = AT; - - CHECK(IsInt<16>(offset)); - if (two_accesses) { - CHECK(IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize))); - } - CHECK_EQ(misalignment, offset & (kMips64DoublewordSize - 1)); -} - -void Mips64Assembler::AdjustBaseOffsetAndElementSizeShift(GpuRegister& base, - int32_t& offset, - int& element_size_shift) { - // This method is used to adjust the base register, offset and element_size_shift - // for a vector load/store when the offset doesn't fit into allowed number of bits. - // MSA ld.df and st.df instructions take signed offsets as arguments, but maximum - // offset is dependant on the size of the data format df (10-bit offsets for ld.b, - // 11-bit for ld.h, 12-bit for ld.w and 13-bit for ld.d). - // If element_size_shift is non-negative at entry, it won't be changed, but offset - // will be checked for appropriate alignment. If negative at entry, it will be - // adjusted based on offset for maximum fit. - // It's assumed that `base` is a multiple of 8. - - CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`. - - if (element_size_shift >= 0) { - CHECK_LE(element_size_shift, TIMES_8); - CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift); - } else if (IsAligned<kMips64DoublewordSize>(offset)) { - element_size_shift = TIMES_8; - } else if (IsAligned<kMips64WordSize>(offset)) { - element_size_shift = TIMES_4; - } else if (IsAligned<kMips64HalfwordSize>(offset)) { - element_size_shift = TIMES_2; - } else { - element_size_shift = TIMES_1; - } - - const int low_len = 10 + element_size_shift; // How many low bits of `offset` ld.df/st.df - // will take. - int16_t low = offset & ((1 << low_len) - 1); // Isolate these bits. - low -= (low & (1 << (low_len - 1))) << 1; // Sign-extend these bits. - if (low == offset) { - return; // `offset` fits into ld.df/st.df. - } - - // First, see if `offset` can be represented as a sum of two signed offsets. - // This can save an instruction. - - // Max int16_t that's a multiple of element size. - const int32_t kMaxDeltaForSimpleAdjustment = 0x8000 - (1 << element_size_shift); - // Max ld.df/st.df offset that's a multiple of element size. - const int32_t kMaxLoadStoreOffset = 0x1ff << element_size_shift; - const int32_t kMaxOffsetForSimpleAdjustment = kMaxDeltaForSimpleAdjustment + kMaxLoadStoreOffset; - - if (IsInt<16>(offset)) { - Daddiu(AT, base, offset); - offset = 0; - } else if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) { - Daddiu(AT, base, kMaxDeltaForSimpleAdjustment); - offset -= kMaxDeltaForSimpleAdjustment; - } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) { - Daddiu(AT, base, -kMaxDeltaForSimpleAdjustment); - offset += kMaxDeltaForSimpleAdjustment; - } else { - // Let's treat `offset` as 64-bit to simplify handling of sign - // extensions in the instructions that supply its smaller signed parts. - // - // 16-bit or smaller parts of `offset`: - // |63 top 48|47 hi 32|31 upper 16|15 mid 13-10|12-9 low 0| - // - // Instructions that supply each part as a signed integer addend: - // |dati |dahi |daui |daddiu |ld.df/st.df | - // - // `top` is always 0, so dati isn't used. - // `hi` is 1 when `offset` is close to +2GB and 0 otherwise. - uint64_t tmp = static_cast<uint64_t>(offset) - low; // Exclude `low` from the rest of `offset` - // (accounts for sign of `low`). - tmp += (tmp & (UINT64_C(1) << 15)) << 1; // Account for sign extension in daddiu. - tmp += (tmp & (UINT64_C(1) << 31)) << 1; // Account for sign extension in daui. - int16_t mid = Low16Bits(tmp); - int16_t upper = High16Bits(tmp); - int16_t hi = Low16Bits(High32Bits(tmp)); - Daui(AT, base, upper); - if (hi != 0) { - CHECK_EQ(hi, 1); - Dahi(AT, hi); - } - if (mid != 0) { - Daddiu(AT, AT, mid); - } - offset = low; - } - base = AT; - CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift); - CHECK(IsInt<10>(offset >> element_size_shift)); -} - -void Mips64Assembler::LoadFromOffset(LoadOperandType type, - GpuRegister reg, - GpuRegister base, - int32_t offset) { - LoadFromOffset<>(type, reg, base, offset); -} - -void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, - FpuRegister reg, - GpuRegister base, - int32_t offset) { - LoadFpuFromOffset<>(type, reg, base, offset); -} - -void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset, - size_t size) { - Mips64ManagedRegister dst = m_dst.AsMips64(); - if (dst.IsNoRegister()) { - CHECK_EQ(0u, size) << dst; - } else if (dst.IsGpuRegister()) { - if (size == 4) { - LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset); - } else if (size == 8) { - CHECK_EQ(8u, size) << dst; - LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset); - } else { - UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8"; - } - } else if (dst.IsFpuRegister()) { - if (size == 4) { - CHECK_EQ(4u, size) << dst; - LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset); - } else if (size == 8) { - CHECK_EQ(8u, size) << dst; - LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset); - } else { - UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8"; - } - } -} - -void Mips64Assembler::StoreToOffset(StoreOperandType type, - GpuRegister reg, - GpuRegister base, - int32_t offset) { - StoreToOffset<>(type, reg, base, offset); -} - -void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, - FpuRegister reg, - GpuRegister base, - int32_t offset) { - StoreFpuToOffset<>(type, reg, base, offset); -} - -static dwarf::Reg DWARFReg(GpuRegister reg) { - return dwarf::Reg::Mips64Core(static_cast<int>(reg)); -} - -constexpr size_t kFramePointerSize = 8; - -void Mips64Assembler::BuildFrame(size_t frame_size, - ManagedRegister method_reg, - ArrayRef<const ManagedRegister> callee_save_regs, - const ManagedRegisterEntrySpills& entry_spills) { - CHECK_ALIGNED(frame_size, kStackAlignment); - DCHECK(!overwriting_); - - // Increase frame to required size. - IncreaseFrameSize(frame_size); - - // Push callee saves and return address - int stack_offset = frame_size - kFramePointerSize; - StoreToOffset(kStoreDoubleword, RA, SP, stack_offset); - cfi_.RelOffset(DWARFReg(RA), stack_offset); - for (int i = callee_save_regs.size() - 1; i >= 0; --i) { - stack_offset -= kFramePointerSize; - GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister(); - StoreToOffset(kStoreDoubleword, reg, SP, stack_offset); - cfi_.RelOffset(DWARFReg(reg), stack_offset); - } - - // Write out Method*. - StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0); - - // Write out entry spills. - int32_t offset = frame_size + kFramePointerSize; - for (const ManagedRegisterSpill& spill : entry_spills) { - Mips64ManagedRegister reg = spill.AsMips64(); - int32_t size = spill.getSize(); - if (reg.IsNoRegister()) { - // only increment stack offset. - offset += size; - } else if (reg.IsFpuRegister()) { - StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword, - reg.AsFpuRegister(), SP, offset); - offset += size; - } else if (reg.IsGpuRegister()) { - StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword, - reg.AsGpuRegister(), SP, offset); - offset += size; - } - } -} - -void Mips64Assembler::RemoveFrame(size_t frame_size, - ArrayRef<const ManagedRegister> callee_save_regs, - bool may_suspend ATTRIBUTE_UNUSED) { - CHECK_ALIGNED(frame_size, kStackAlignment); - DCHECK(!overwriting_); - cfi_.RememberState(); - - // Pop callee saves and return address - int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; - for (size_t i = 0; i < callee_save_regs.size(); ++i) { - GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister(); - LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset); - cfi_.Restore(DWARFReg(reg)); - stack_offset += kFramePointerSize; - } - LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset); - cfi_.Restore(DWARFReg(RA)); - - // Decrease frame to required size. - DecreaseFrameSize(frame_size); - - // Then jump to the return address. - Jr(RA); - Nop(); - - // The CFI should be restored for any code that follows the exit block. - cfi_.RestoreState(); - cfi_.DefCFAOffset(frame_size); -} - -void Mips64Assembler::IncreaseFrameSize(size_t adjust) { - CHECK_ALIGNED(adjust, kFramePointerSize); - DCHECK(!overwriting_); - Daddiu64(SP, SP, static_cast<int32_t>(-adjust)); - cfi_.AdjustCFAOffset(adjust); -} - -void Mips64Assembler::DecreaseFrameSize(size_t adjust) { - CHECK_ALIGNED(adjust, kFramePointerSize); - DCHECK(!overwriting_); - Daddiu64(SP, SP, static_cast<int32_t>(adjust)); - cfi_.AdjustCFAOffset(-adjust); -} - -void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { - Mips64ManagedRegister src = msrc.AsMips64(); - if (src.IsNoRegister()) { - CHECK_EQ(0u, size); - } else if (src.IsGpuRegister()) { - CHECK(size == 4 || size == 8) << size; - if (size == 8) { - StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value()); - } else if (size == 4) { - StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value()); - } else { - UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8"; - } - } else if (src.IsFpuRegister()) { - CHECK(size == 4 || size == 8) << size; - if (size == 8) { - StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value()); - } else if (size == 4) { - StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value()); - } else { - UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8"; - } - } -} - -void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { - Mips64ManagedRegister src = msrc.AsMips64(); - CHECK(src.IsGpuRegister()); - StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value()); -} - -void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { - Mips64ManagedRegister src = msrc.AsMips64(); - CHECK(src.IsGpuRegister()); - StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value()); -} - -void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, - ManagedRegister mscratch) { - Mips64ManagedRegister scratch = mscratch.AsMips64(); - CHECK(scratch.IsGpuRegister()) << scratch; - LoadConst32(scratch.AsGpuRegister(), imm); - StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value()); -} - -void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs, - FrameOffset fr_offs, - ManagedRegister mscratch) { - Mips64ManagedRegister scratch = mscratch.AsMips64(); - CHECK(scratch.IsGpuRegister()) << scratch; - Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value()); -} - -void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) { - StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value()); -} - -void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc, - FrameOffset in_off, ManagedRegister mscratch) { - Mips64ManagedRegister src = msrc.AsMips64(); - Mips64ManagedRegister scratch = mscratch.AsMips64(); - StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value()); - LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8); -} - -void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { - return EmitLoad(mdest, SP, src.Int32Value(), size); -} - -void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) { - return EmitLoad(mdest, S1, src.Int32Value(), size); -} - -void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) { - Mips64ManagedRegister dest = mdest.AsMips64(); - CHECK(dest.IsGpuRegister()); - LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value()); -} - -void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, - bool unpoison_reference) { - Mips64ManagedRegister dest = mdest.AsMips64(); - CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister()); - LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), - base.AsMips64().AsGpuRegister(), offs.Int32Value()); - if (unpoison_reference) { - MaybeUnpoisonHeapReference(dest.AsGpuRegister()); - } -} - -void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, - Offset offs) { - Mips64ManagedRegister dest = mdest.AsMips64(); - CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister()); - LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), - base.AsMips64().AsGpuRegister(), offs.Int32Value()); -} - -void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) { - Mips64ManagedRegister dest = mdest.AsMips64(); - CHECK(dest.IsGpuRegister()); - LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value()); -} - -void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED, - size_t size ATTRIBUTE_UNUSED) { - UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64"; -} - -void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED, - size_t size ATTRIBUTE_UNUSED) { - UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64"; -} - -void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) { - Mips64ManagedRegister dest = mdest.AsMips64(); - Mips64ManagedRegister src = msrc.AsMips64(); - if (!dest.Equals(src)) { - if (dest.IsGpuRegister()) { - CHECK(src.IsGpuRegister()) << src; - Move(dest.AsGpuRegister(), src.AsGpuRegister()); - } else if (dest.IsFpuRegister()) { - CHECK(src.IsFpuRegister()) << src; - if (size == 4) { - MovS(dest.AsFpuRegister(), src.AsFpuRegister()); - } else if (size == 8) { - MovD(dest.AsFpuRegister(), src.AsFpuRegister()); - } else { - UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; - } - } - } -} - -void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src, - ManagedRegister mscratch) { - Mips64ManagedRegister scratch = mscratch.AsMips64(); - CHECK(scratch.IsGpuRegister()) << scratch; - LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value()); - StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value()); -} - -void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs, - ThreadOffset64 thr_offs, - ManagedRegister mscratch) { - Mips64ManagedRegister scratch = mscratch.AsMips64(); - CHECK(scratch.IsGpuRegister()) << scratch; - LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value()); -} - -void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs, - FrameOffset fr_offs, - ManagedRegister mscratch) { - Mips64ManagedRegister scratch = mscratch.AsMips64(); - CHECK(scratch.IsGpuRegister()) << scratch; - LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), - SP, fr_offs.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), - S1, thr_offs.Int32Value()); -} - -void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src, - ManagedRegister mscratch, size_t size) { - Mips64ManagedRegister scratch = mscratch.AsMips64(); - CHECK(scratch.IsGpuRegister()) << scratch; - CHECK(size == 4 || size == 8) << size; - if (size == 4) { - LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value()); - } else if (size == 8) { - LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value()); - } else { - UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; - } -} - -void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, - ManagedRegister mscratch, size_t size) { - GpuRegister scratch = mscratch.AsMips64().AsGpuRegister(); - CHECK(size == 4 || size == 8) << size; - if (size == 4) { - LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(), - src_offset.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value()); - } else if (size == 8) { - LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(), - src_offset.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value()); - } else { - UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; - } -} - -void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, - ManagedRegister mscratch, size_t size) { - GpuRegister scratch = mscratch.AsMips64().AsGpuRegister(); - CHECK(size == 4 || size == 8) << size; - if (size == 4) { - LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(), - dest_offset.Int32Value()); - } else if (size == 8) { - LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(), - dest_offset.Int32Value()); - } else { - UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; - } -} - -void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, - FrameOffset src_base ATTRIBUTE_UNUSED, - Offset src_offset ATTRIBUTE_UNUSED, - ManagedRegister mscratch ATTRIBUTE_UNUSED, - size_t size ATTRIBUTE_UNUSED) { - UNIMPLEMENTED(FATAL) << "No MIPS64 implementation"; -} - -void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset, - ManagedRegister src, Offset src_offset, - ManagedRegister mscratch, size_t size) { - GpuRegister scratch = mscratch.AsMips64().AsGpuRegister(); - CHECK(size == 4 || size == 8) << size; - if (size == 4) { - LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value()); - } else if (size == 8) { - LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(), - src_offset.Int32Value()); - StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), - dest_offset.Int32Value()); - } else { - UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; - } -} - -void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, - Offset dest_offset ATTRIBUTE_UNUSED, - FrameOffset src ATTRIBUTE_UNUSED, - Offset src_offset ATTRIBUTE_UNUSED, - ManagedRegister mscratch ATTRIBUTE_UNUSED, - size_t size ATTRIBUTE_UNUSED) { - UNIMPLEMENTED(FATAL) << "No MIPS64 implementation"; -} - -void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) { - // TODO: sync? - UNIMPLEMENTED(FATAL) << "No MIPS64 implementation"; -} - -void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg, - FrameOffset handle_scope_offset, - ManagedRegister min_reg, - bool null_allowed) { - Mips64ManagedRegister out_reg = mout_reg.AsMips64(); - Mips64ManagedRegister in_reg = min_reg.AsMips64(); - CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg; - CHECK(out_reg.IsGpuRegister()) << out_reg; - if (null_allowed) { - Mips64Label null_arg; - // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is - // the address in the handle scope holding the reference. - // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset) - if (in_reg.IsNoRegister()) { - LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(), - SP, handle_scope_offset.Int32Value()); - in_reg = out_reg; - } - if (!out_reg.Equals(in_reg)) { - LoadConst32(out_reg.AsGpuRegister(), 0); - } - Beqzc(in_reg.AsGpuRegister(), &null_arg); - Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value()); - Bind(&null_arg); - } else { - Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value()); - } -} - -void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off, - FrameOffset handle_scope_offset, - ManagedRegister mscratch, - bool null_allowed) { - Mips64ManagedRegister scratch = mscratch.AsMips64(); - CHECK(scratch.IsGpuRegister()) << scratch; - if (null_allowed) { - Mips64Label null_arg; - LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP, - handle_scope_offset.Int32Value()); - // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is - // the address in the handle scope holding the reference. - // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset) - Beqzc(scratch.AsGpuRegister(), &null_arg); - Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value()); - Bind(&null_arg); - } else { - Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value()); - } - StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value()); -} - -// Given a handle scope entry, load the associated reference. -void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, - ManagedRegister min_reg) { - Mips64ManagedRegister out_reg = mout_reg.AsMips64(); - Mips64ManagedRegister in_reg = min_reg.AsMips64(); - CHECK(out_reg.IsGpuRegister()) << out_reg; - CHECK(in_reg.IsGpuRegister()) << in_reg; - Mips64Label null_arg; - if (!out_reg.Equals(in_reg)) { - LoadConst32(out_reg.AsGpuRegister(), 0); - } - Beqzc(in_reg.AsGpuRegister(), &null_arg); - LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(), - in_reg.AsGpuRegister(), 0); - Bind(&null_arg); -} - -void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED, - bool could_be_null ATTRIBUTE_UNUSED) { - // TODO: not validating references -} - -void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED, - bool could_be_null ATTRIBUTE_UNUSED) { - // TODO: not validating references -} - -void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) { - Mips64ManagedRegister base = mbase.AsMips64(); - Mips64ManagedRegister scratch = mscratch.AsMips64(); - CHECK(base.IsGpuRegister()) << base; - CHECK(scratch.IsGpuRegister()) << scratch; - LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), - base.AsGpuRegister(), offset.Int32Value()); - Jalr(scratch.AsGpuRegister()); - Nop(); - // TODO: place reference map on call -} - -void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { - Mips64ManagedRegister scratch = mscratch.AsMips64(); - CHECK(scratch.IsGpuRegister()) << scratch; - // Call *(*(SP + base) + offset) - LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), - SP, base.Int32Value()); - LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), - scratch.AsGpuRegister(), offset.Int32Value()); - Jalr(scratch.AsGpuRegister()); - Nop(); - // TODO: place reference map on call -} - -void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED, - ManagedRegister mscratch ATTRIBUTE_UNUSED) { - UNIMPLEMENTED(FATAL) << "No MIPS64 implementation"; -} - -void Mips64Assembler::GetCurrentThread(ManagedRegister tr) { - Move(tr.AsMips64().AsGpuRegister(), S1); -} - -void Mips64Assembler::GetCurrentThread(FrameOffset offset, - ManagedRegister mscratch ATTRIBUTE_UNUSED) { - StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value()); -} - -void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) { - Mips64ManagedRegister scratch = mscratch.AsMips64(); - exception_blocks_.emplace_back(scratch, stack_adjust); - LoadFromOffset(kLoadDoubleword, - scratch.AsGpuRegister(), - S1, - Thread::ExceptionOffset<kMips64PointerSize>().Int32Value()); - Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry()); -} - -void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) { - Bind(exception->Entry()); - if (exception->stack_adjust_ != 0) { // Fix up the frame. - DecreaseFrameSize(exception->stack_adjust_); - } - // Pass exception object as argument. - // Don't care about preserving A0 as this call won't return. - CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>(); - Move(A0, exception->scratch_.AsGpuRegister()); - // Set up call to Thread::Current()->pDeliverException - LoadFromOffset(kLoadDoubleword, - T9, - S1, - QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, pDeliverException).Int32Value()); - Jr(T9); - Nop(); - - // Call never returns - Break(); -} - -} // namespace mips64 -} // namespace art diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h deleted file mode 100644 index b331cee33d..0000000000 --- a/compiler/utils/mips64/assembler_mips64.h +++ /dev/null @@ -1,1736 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_ -#define ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_ - -#include <deque> -#include <utility> -#include <vector> - -#include "arch/mips64/instruction_set_features_mips64.h" -#include "base/arena_containers.h" -#include "base/enums.h" -#include "base/globals.h" -#include "base/macros.h" -#include "base/stl_util_identity.h" -#include "constants_mips64.h" -#include "heap_poisoning.h" -#include "managed_register_mips64.h" -#include "offsets.h" -#include "utils/assembler.h" -#include "utils/jni_macro_assembler.h" -#include "utils/label.h" - -namespace art { -namespace mips64 { - -enum LoadConst64Path { - kLoadConst64PathZero = 0x0, - kLoadConst64PathOri = 0x1, - kLoadConst64PathDaddiu = 0x2, - kLoadConst64PathLui = 0x4, - kLoadConst64PathLuiOri = 0x8, - kLoadConst64PathOriDahi = 0x10, - kLoadConst64PathOriDati = 0x20, - kLoadConst64PathLuiDahi = 0x40, - kLoadConst64PathLuiDati = 0x80, - kLoadConst64PathDaddiuDsrlX = 0x100, - kLoadConst64PathOriDsllX = 0x200, - kLoadConst64PathDaddiuDsllX = 0x400, - kLoadConst64PathLuiOriDsllX = 0x800, - kLoadConst64PathOriDsllXOri = 0x1000, - kLoadConst64PathDaddiuDsllXOri = 0x2000, - kLoadConst64PathDaddiuDahi = 0x4000, - kLoadConst64PathDaddiuDati = 0x8000, - kLoadConst64PathDinsu1 = 0x10000, - kLoadConst64PathDinsu2 = 0x20000, - kLoadConst64PathCatchAll = 0x40000, - kLoadConst64PathAllPaths = 0x7ffff, -}; - -template <typename Asm> -void TemplateLoadConst32(Asm* a, GpuRegister rd, int32_t value) { - if (IsUint<16>(value)) { - // Use OR with (unsigned) immediate to encode 16b unsigned int. - a->Ori(rd, ZERO, value); - } else if (IsInt<16>(value)) { - // Use ADD with (signed) immediate to encode 16b signed int. - a->Addiu(rd, ZERO, value); - } else { - // Set 16 most significant bits of value. The "lui" instruction - // also clears the 16 least significant bits to zero. - a->Lui(rd, value >> 16); - if (value & 0xFFFF) { - // If the 16 least significant bits are non-zero, set them - // here. - a->Ori(rd, rd, value); - } - } -} - -static inline int InstrCountForLoadReplicatedConst32(int64_t value) { - int32_t x = Low32Bits(value); - int32_t y = High32Bits(value); - - if (x == y) { - return (IsUint<16>(x) || IsInt<16>(x) || ((x & 0xFFFF) == 0)) ? 2 : 3; - } - - return INT_MAX; -} - -template <typename Asm, typename Rtype, typename Vtype> -void TemplateLoadConst64(Asm* a, Rtype rd, Vtype value) { - int bit31 = (value & UINT64_C(0x80000000)) != 0; - int rep32_count = InstrCountForLoadReplicatedConst32(value); - - // Loads with 1 instruction. - if (IsUint<16>(value)) { - // 64-bit value can be loaded as an unsigned 16-bit number. - a->RecordLoadConst64Path(kLoadConst64PathOri); - a->Ori(rd, ZERO, value); - } else if (IsInt<16>(value)) { - // 64-bit value can be loaded as an signed 16-bit number. - a->RecordLoadConst64Path(kLoadConst64PathDaddiu); - a->Daddiu(rd, ZERO, value); - } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) { - // 64-bit value can be loaded as an signed 32-bit number which has all - // of its 16 least significant bits set to zero. - a->RecordLoadConst64Path(kLoadConst64PathLui); - a->Lui(rd, value >> 16); - } else if (IsInt<32>(value)) { - // Loads with 2 instructions. - // 64-bit value can be loaded as an signed 32-bit number which has some - // or all of its 16 least significant bits set to one. - a->RecordLoadConst64Path(kLoadConst64PathLuiOri); - a->Lui(rd, value >> 16); - a->Ori(rd, rd, value); - } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) { - // 64-bit value which consists of an unsigned 16-bit value in its - // least significant 32-bits, and a signed 16-bit value in its - // most significant 32-bits. - a->RecordLoadConst64Path(kLoadConst64PathOriDahi); - a->Ori(rd, ZERO, value); - a->Dahi(rd, value >> 32); - } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) { - // 64-bit value which consists of an unsigned 16-bit value in its - // least significant 48-bits, and a signed 16-bit value in its - // most significant 16-bits. - a->RecordLoadConst64Path(kLoadConst64PathOriDati); - a->Ori(rd, ZERO, value); - a->Dati(rd, value >> 48); - } else if ((value & 0xFFFF) == 0 && - (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) { - // 16 LSBs (Least Significant Bits) all set to zero. - // 48 MSBs (Most Significant Bits) hold a signed 32-bit value. - a->RecordLoadConst64Path(kLoadConst64PathLuiDahi); - a->Lui(rd, value >> 16); - a->Dahi(rd, (value >> 32) + bit31); - } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) { - // 16 LSBs all set to zero. - // 48 MSBs hold a signed value which can't be represented by signed - // 32-bit number, and the middle 16 bits are all zero, or all one. - a->RecordLoadConst64Path(kLoadConst64PathLuiDati); - a->Lui(rd, value >> 16); - a->Dati(rd, (value >> 48) + bit31); - } else if (IsInt<16>(static_cast<int32_t>(value)) && - (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) { - // 32 LSBs contain an unsigned 16-bit number. - // 32 MSBs contain a signed 16-bit number. - a->RecordLoadConst64Path(kLoadConst64PathDaddiuDahi); - a->Daddiu(rd, ZERO, value); - a->Dahi(rd, (value >> 32) + bit31); - } else if (IsInt<16>(static_cast<int32_t>(value)) && - ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) { - // 48 LSBs contain an unsigned 16-bit number. - // 16 MSBs contain a signed 16-bit number. - a->RecordLoadConst64Path(kLoadConst64PathDaddiuDati); - a->Daddiu(rd, ZERO, value); - a->Dati(rd, (value >> 48) + bit31); - } else if (IsPowerOfTwo(value + UINT64_C(1))) { - // 64-bit values which have their "n" MSBs set to one, and their - // "64-n" LSBs set to zero. "n" must meet the restrictions 0 < n < 64. - int shift_cnt = 64 - CTZ(value + UINT64_C(1)); - a->RecordLoadConst64Path(kLoadConst64PathDaddiuDsrlX); - a->Daddiu(rd, ZERO, -1); - if (shift_cnt < 32) { - a->Dsrl(rd, rd, shift_cnt); - } else { - a->Dsrl32(rd, rd, shift_cnt & 31); - } - } else { - int shift_cnt = CTZ(value); - int64_t tmp = value >> shift_cnt; - a->RecordLoadConst64Path(kLoadConst64PathOriDsllX); - if (IsUint<16>(tmp)) { - // Value can be computed by loading a 16-bit unsigned value, and - // then shifting left. - a->Ori(rd, ZERO, tmp); - if (shift_cnt < 32) { - a->Dsll(rd, rd, shift_cnt); - } else { - a->Dsll32(rd, rd, shift_cnt & 31); - } - } else if (IsInt<16>(tmp)) { - // Value can be computed by loading a 16-bit signed value, and - // then shifting left. - a->RecordLoadConst64Path(kLoadConst64PathDaddiuDsllX); - a->Daddiu(rd, ZERO, tmp); - if (shift_cnt < 32) { - a->Dsll(rd, rd, shift_cnt); - } else { - a->Dsll32(rd, rd, shift_cnt & 31); - } - } else if (rep32_count < 3) { - // Value being loaded has 32 LSBs equal to the 32 MSBs, and the - // value loaded into the 32 LSBs can be loaded with a single - // MIPS instruction. - a->LoadConst32(rd, value); - a->Dinsu(rd, rd, 32, 32); - a->RecordLoadConst64Path(kLoadConst64PathDinsu1); - } else if (IsInt<32>(tmp)) { - // Loads with 3 instructions. - // Value can be computed by loading a 32-bit signed value, and - // then shifting left. - a->RecordLoadConst64Path(kLoadConst64PathLuiOriDsllX); - a->Lui(rd, tmp >> 16); - a->Ori(rd, rd, tmp); - if (shift_cnt < 32) { - a->Dsll(rd, rd, shift_cnt); - } else { - a->Dsll32(rd, rd, shift_cnt & 31); - } - } else { - shift_cnt = 16 + CTZ(value >> 16); - tmp = value >> shift_cnt; - if (IsUint<16>(tmp)) { - // Value can be computed by loading a 16-bit unsigned value, - // shifting left, and "or"ing in another 16-bit unsigned value. - a->RecordLoadConst64Path(kLoadConst64PathOriDsllXOri); - a->Ori(rd, ZERO, tmp); - if (shift_cnt < 32) { - a->Dsll(rd, rd, shift_cnt); - } else { - a->Dsll32(rd, rd, shift_cnt & 31); - } - a->Ori(rd, rd, value); - } else if (IsInt<16>(tmp)) { - // Value can be computed by loading a 16-bit signed value, - // shifting left, and "or"ing in a 16-bit unsigned value. - a->RecordLoadConst64Path(kLoadConst64PathDaddiuDsllXOri); - a->Daddiu(rd, ZERO, tmp); - if (shift_cnt < 32) { - a->Dsll(rd, rd, shift_cnt); - } else { - a->Dsll32(rd, rd, shift_cnt & 31); - } - a->Ori(rd, rd, value); - } else if (rep32_count < 4) { - // Value being loaded has 32 LSBs equal to the 32 MSBs, and the - // value in the 32 LSBs requires 2 MIPS instructions to load. - a->LoadConst32(rd, value); - a->Dinsu(rd, rd, 32, 32); - a->RecordLoadConst64Path(kLoadConst64PathDinsu2); - } else { - // Loads with 3-4 instructions. - // Catch-all case to get any other 64-bit values which aren't - // handled by special cases above. - uint64_t tmp2 = value; - a->RecordLoadConst64Path(kLoadConst64PathCatchAll); - a->LoadConst32(rd, value); - if (bit31) { - tmp2 += UINT64_C(0x100000000); - } - if (((tmp2 >> 32) & 0xFFFF) != 0) { - a->Dahi(rd, tmp2 >> 32); - } - if (tmp2 & UINT64_C(0x800000000000)) { - tmp2 += UINT64_C(0x1000000000000); - } - if ((tmp2 >> 48) != 0) { - a->Dati(rd, tmp2 >> 48); - } - } - } - } -} - -static constexpr size_t kMips64HalfwordSize = 2; -static constexpr size_t kMips64WordSize = 4; -static constexpr size_t kMips64DoublewordSize = 8; - -enum LoadOperandType { - kLoadSignedByte, - kLoadUnsignedByte, - kLoadSignedHalfword, - kLoadUnsignedHalfword, - kLoadWord, - kLoadUnsignedWord, - kLoadDoubleword, - kLoadQuadword -}; - -enum StoreOperandType { - kStoreByte, - kStoreHalfword, - kStoreWord, - kStoreDoubleword, - kStoreQuadword -}; - -// Used to test the values returned by ClassS/ClassD. -enum FPClassMaskType { - kSignalingNaN = 0x001, - kQuietNaN = 0x002, - kNegativeInfinity = 0x004, - kNegativeNormal = 0x008, - kNegativeSubnormal = 0x010, - kNegativeZero = 0x020, - kPositiveInfinity = 0x040, - kPositiveNormal = 0x080, - kPositiveSubnormal = 0x100, - kPositiveZero = 0x200, -}; - -class Mips64Label : public Label { - public: - Mips64Label() : prev_branch_id_plus_one_(0) {} - - Mips64Label(Mips64Label&& src) - : Label(std::move(src)), prev_branch_id_plus_one_(src.prev_branch_id_plus_one_) {} - - private: - uint32_t prev_branch_id_plus_one_; // To get distance from preceding branch, if any. - - friend class Mips64Assembler; - DISALLOW_COPY_AND_ASSIGN(Mips64Label); -}; - -// Assembler literal is a value embedded in code, retrieved using a PC-relative load. -class Literal { - public: - static constexpr size_t kMaxSize = 8; - - Literal(uint32_t size, const uint8_t* data) - : label_(), size_(size) { - DCHECK_LE(size, Literal::kMaxSize); - memcpy(data_, data, size); - } - - template <typename T> - T GetValue() const { - DCHECK_EQ(size_, sizeof(T)); - T value; - memcpy(&value, data_, sizeof(T)); - return value; - } - - uint32_t GetSize() const { - return size_; - } - - const uint8_t* GetData() const { - return data_; - } - - Mips64Label* GetLabel() { - return &label_; - } - - const Mips64Label* GetLabel() const { - return &label_; - } - - private: - Mips64Label label_; - const uint32_t size_; - uint8_t data_[kMaxSize]; - - DISALLOW_COPY_AND_ASSIGN(Literal); -}; - -// Jump table: table of labels emitted after the code and before the literals. Similar to literals. -class JumpTable { - public: - explicit JumpTable(std::vector<Mips64Label*>&& labels) - : label_(), labels_(std::move(labels)) { - } - - size_t GetSize() const { - return labels_.size() * sizeof(uint32_t); - } - - const std::vector<Mips64Label*>& GetData() const { - return labels_; - } - - Mips64Label* GetLabel() { - return &label_; - } - - const Mips64Label* GetLabel() const { - return &label_; - } - - private: - Mips64Label label_; - std::vector<Mips64Label*> labels_; - - DISALLOW_COPY_AND_ASSIGN(JumpTable); -}; - -// Slowpath entered when Thread::Current()->_exception is non-null. -class Mips64ExceptionSlowPath { - public: - explicit Mips64ExceptionSlowPath(Mips64ManagedRegister scratch, size_t stack_adjust) - : scratch_(scratch), stack_adjust_(stack_adjust) {} - - Mips64ExceptionSlowPath(Mips64ExceptionSlowPath&& src) - : scratch_(src.scratch_), - stack_adjust_(src.stack_adjust_), - exception_entry_(std::move(src.exception_entry_)) {} - - private: - Mips64Label* Entry() { return &exception_entry_; } - const Mips64ManagedRegister scratch_; - const size_t stack_adjust_; - Mips64Label exception_entry_; - - friend class Mips64Assembler; - DISALLOW_COPY_AND_ASSIGN(Mips64ExceptionSlowPath); -}; - -class Mips64Assembler final : public Assembler, public JNIMacroAssembler<PointerSize::k64> { - public: - using JNIBase = JNIMacroAssembler<PointerSize::k64>; - - explicit Mips64Assembler(ArenaAllocator* allocator, - const Mips64InstructionSetFeatures* instruction_set_features = nullptr) - : Assembler(allocator), - overwriting_(false), - overwrite_location_(0), - literals_(allocator->Adapter(kArenaAllocAssembler)), - long_literals_(allocator->Adapter(kArenaAllocAssembler)), - jump_tables_(allocator->Adapter(kArenaAllocAssembler)), - last_position_adjustment_(0), - last_old_position_(0), - last_branch_id_(0), - has_msa_(instruction_set_features != nullptr ? instruction_set_features->HasMsa() : false) { - cfi().DelayEmittingAdvancePCs(); - } - - virtual ~Mips64Assembler() { - for (auto& branch : branches_) { - CHECK(branch.IsResolved()); - } - } - - size_t CodeSize() const override { return Assembler::CodeSize(); } - DebugFrameOpCodeWriterForAssembler& cfi() override { return Assembler::cfi(); } - - // Emit Machine Instructions. - void Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64 - void Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16); // MIPS64 - void Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64 - - void MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64 - void Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64 - void Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64 - void Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64 - void Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64 - void Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64 - - void And(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Or(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt); - - void Bitswap(GpuRegister rd, GpuRegister rt); - void Dbitswap(GpuRegister rd, GpuRegister rt); // MIPS64 - void Seb(GpuRegister rd, GpuRegister rt); - void Seh(GpuRegister rd, GpuRegister rt); - void Dsbh(GpuRegister rd, GpuRegister rt); // MIPS64 - void Dshd(GpuRegister rd, GpuRegister rt); // MIPS64 - void Dext(GpuRegister rs, GpuRegister rt, int pos, int size); // MIPS64 - void Ins(GpuRegister rt, GpuRegister rs, int pos, int size); - void Dins(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64 - void Dinsm(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64 - void Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64 - void DblIns(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64 - void Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne); - void Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne); // 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); // MIPS64 - void Ll(GpuRegister rt, GpuRegister base, int16_t imm9 = 0); - void Lld(GpuRegister rt, GpuRegister base, int16_t imm9 = 0); // MIPS64 - - void Sll(GpuRegister rd, GpuRegister rt, int shamt); - void Srl(GpuRegister rd, GpuRegister rt, int shamt); - void Rotr(GpuRegister rd, GpuRegister rt, int shamt); - void Sra(GpuRegister rd, GpuRegister rt, int shamt); - void Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs); - void Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs); - void Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs); - void Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs); - void Dsll(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64 - void Dsrl(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64 - void Drotr(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64 - void Dsra(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64 - void Dsll32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64 - void Dsrl32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64 - void Drotr32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64 - void Dsra32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64 - void Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64 - void Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64 - void Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64 - void Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64 - - void Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16); // MIPS64 - void Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16); // MIPS64 - void Lwpc(GpuRegister rs, uint32_t imm19); - void Lwupc(GpuRegister rs, uint32_t imm19); // MIPS64 - void Ldpc(GpuRegister rs, uint32_t imm18); // MIPS64 - void Lui(GpuRegister rt, uint16_t imm16); - void Aui(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Daui(GpuRegister rt, GpuRegister rs, uint16_t imm16); // MIPS64 - void Dahi(GpuRegister rs, uint16_t imm16); // MIPS64 - void Dati(GpuRegister rs, uint16_t imm16); // MIPS64 - void Sync(uint32_t stype); - - void Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16); // MIPS64 - - void Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16); - void Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt); - void Clz(GpuRegister rd, GpuRegister rs); - void Clo(GpuRegister rd, GpuRegister rs); - void Dclz(GpuRegister rd, GpuRegister rs); // MIPS64 - void Dclo(GpuRegister rd, GpuRegister rs); // MIPS64 - - void Jalr(GpuRegister rd, GpuRegister rs); - void Jalr(GpuRegister rs); - void Jr(GpuRegister rs); - void Auipc(GpuRegister rs, uint16_t imm16); - void Addiupc(GpuRegister rs, uint32_t imm19); - void Bc(uint32_t imm26); - void Balc(uint32_t imm26); - void Jic(GpuRegister rt, uint16_t imm16); - void Jialc(GpuRegister rt, uint16_t imm16); - void Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16); - void Bltzc(GpuRegister rt, uint16_t imm16); - void Bgtzc(GpuRegister rt, uint16_t imm16); - void Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16); - void Bgezc(GpuRegister rt, uint16_t imm16); - void Blezc(GpuRegister rt, uint16_t imm16); - void Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16); - void Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16); - void Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16); - void Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16); - void Beqzc(GpuRegister rs, uint32_t imm21); - void Bnezc(GpuRegister rs, uint32_t imm21); - void Bc1eqz(FpuRegister ft, uint16_t imm16); - void Bc1nez(FpuRegister ft, uint16_t imm16); - void Beq(GpuRegister rs, GpuRegister rt, uint16_t imm16); // R2 - void Bne(GpuRegister rs, GpuRegister rt, uint16_t imm16); // R2 - void Beqz(GpuRegister rt, uint16_t imm16); // R2 - void Bnez(GpuRegister rt, uint16_t imm16); // R2 - void Bltz(GpuRegister rt, uint16_t imm16); // R2 - void Bgez(GpuRegister rt, uint16_t imm16); // R2 - void Blez(GpuRegister rt, uint16_t imm16); // R2 - void Bgtz(GpuRegister rt, uint16_t imm16); // R2 - - void AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void SqrtS(FpuRegister fd, FpuRegister fs); - void SqrtD(FpuRegister fd, FpuRegister fs); - void AbsS(FpuRegister fd, FpuRegister fs); - void AbsD(FpuRegister fd, FpuRegister fs); - void MovS(FpuRegister fd, FpuRegister fs); - void MovD(FpuRegister fd, FpuRegister fs); - void NegS(FpuRegister fd, FpuRegister fs); - void NegD(FpuRegister fd, FpuRegister fs); - void RoundLS(FpuRegister fd, FpuRegister fs); - void RoundLD(FpuRegister fd, FpuRegister fs); - void RoundWS(FpuRegister fd, FpuRegister fs); - void RoundWD(FpuRegister fd, FpuRegister fs); - void TruncLS(FpuRegister fd, FpuRegister fs); - void TruncLD(FpuRegister fd, FpuRegister fs); - void TruncWS(FpuRegister fd, FpuRegister fs); - void TruncWD(FpuRegister fd, FpuRegister fs); - void CeilLS(FpuRegister fd, FpuRegister fs); - void CeilLD(FpuRegister fd, FpuRegister fs); - void CeilWS(FpuRegister fd, FpuRegister fs); - void CeilWD(FpuRegister fd, FpuRegister fs); - void FloorLS(FpuRegister fd, FpuRegister fs); - void FloorLD(FpuRegister fd, FpuRegister fs); - void FloorWS(FpuRegister fd, FpuRegister fs); - void FloorWD(FpuRegister fd, FpuRegister fs); - void SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void SeleqzS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void SeleqzD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void SelnezS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void SelnezD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void RintS(FpuRegister fd, FpuRegister fs); - void RintD(FpuRegister fd, FpuRegister fs); - void ClassS(FpuRegister fd, FpuRegister fs); - void ClassD(FpuRegister fd, FpuRegister fs); - void MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - void CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft); - - void Cvtsw(FpuRegister fd, FpuRegister fs); - void Cvtdw(FpuRegister fd, FpuRegister fs); - void Cvtsd(FpuRegister fd, FpuRegister fs); - void Cvtds(FpuRegister fd, FpuRegister fs); - void Cvtsl(FpuRegister fd, FpuRegister fs); - 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); - void Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16); - void Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16); - void Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16); - - void Break(); - void Nop(); - void Move(GpuRegister rd, GpuRegister rs); - void Clear(GpuRegister rd); - void Not(GpuRegister rd, GpuRegister rs); - - // MSA instructions. - void AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Asub_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void Ffint_sW(VectorRegister wd, VectorRegister ws); - void Ffint_sD(VectorRegister wd, VectorRegister ws); - void Ftint_sW(VectorRegister wd, VectorRegister ws); - void Ftint_sD(VectorRegister wd, VectorRegister ws); - - void SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - // Immediate shift instructions, where shamtN denotes shift amount (must be between 0 and 2^N-1). - void SlliB(VectorRegister wd, VectorRegister ws, int shamt3); - void SlliH(VectorRegister wd, VectorRegister ws, int shamt4); - void SlliW(VectorRegister wd, VectorRegister ws, int shamt5); - void SlliD(VectorRegister wd, VectorRegister ws, int shamt6); - void SraiB(VectorRegister wd, VectorRegister ws, int shamt3); - void SraiH(VectorRegister wd, VectorRegister ws, int shamt4); - void SraiW(VectorRegister wd, VectorRegister ws, int shamt5); - void SraiD(VectorRegister wd, VectorRegister ws, int shamt6); - void SrliB(VectorRegister wd, VectorRegister ws, int shamt3); - void SrliH(VectorRegister wd, VectorRegister ws, int shamt4); - void SrliW(VectorRegister wd, VectorRegister ws, int shamt5); - void SrliD(VectorRegister wd, VectorRegister ws, int shamt6); - - void MoveV(VectorRegister wd, VectorRegister ws); - void SplatiB(VectorRegister wd, VectorRegister ws, int n4); - void SplatiH(VectorRegister wd, VectorRegister ws, int n3); - void SplatiW(VectorRegister wd, VectorRegister ws, int n2); - void SplatiD(VectorRegister wd, VectorRegister ws, int n1); - void Copy_sB(GpuRegister rd, VectorRegister ws, int n4); - void Copy_sH(GpuRegister rd, VectorRegister ws, int n3); - void Copy_sW(GpuRegister rd, VectorRegister ws, int n2); - void Copy_sD(GpuRegister rd, VectorRegister ws, int n1); - void Copy_uB(GpuRegister rd, VectorRegister ws, int n4); - void Copy_uH(GpuRegister rd, VectorRegister ws, int n3); - void Copy_uW(GpuRegister rd, VectorRegister ws, int n2); - void InsertB(VectorRegister wd, GpuRegister rs, int n4); - void InsertH(VectorRegister wd, GpuRegister rs, int n3); - void InsertW(VectorRegister wd, GpuRegister rs, int n2); - void InsertD(VectorRegister wd, GpuRegister rs, int n1); - void FillB(VectorRegister wd, GpuRegister rs); - void FillH(VectorRegister wd, GpuRegister rs); - void FillW(VectorRegister wd, GpuRegister rs); - void FillD(VectorRegister wd, GpuRegister rs); - - void LdiB(VectorRegister wd, int imm8); - void LdiH(VectorRegister wd, int imm10); - void LdiW(VectorRegister wd, int imm10); - void LdiD(VectorRegister wd, int imm10); - void LdB(VectorRegister wd, GpuRegister rs, int offset); - void LdH(VectorRegister wd, GpuRegister rs, int offset); - void LdW(VectorRegister wd, GpuRegister rs, int offset); - void LdD(VectorRegister wd, GpuRegister rs, int offset); - void StB(VectorRegister wd, GpuRegister rs, int offset); - void StH(VectorRegister wd, GpuRegister rs, int offset); - void StW(VectorRegister wd, GpuRegister rs, int offset); - void StD(VectorRegister wd, GpuRegister rs, int offset); - - void IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); - void Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); - - void PcntB(VectorRegister wd, VectorRegister ws); - void PcntH(VectorRegister wd, VectorRegister ws); - void PcntW(VectorRegister wd, VectorRegister ws); - void PcntD(VectorRegister wd, VectorRegister ws); - - // Helper for replicating floating point value in all destination elements. - void ReplicateFPToVectorRegister(VectorRegister dst, FpuRegister src, bool is_double); - - // Higher level composite instructions. - int InstrCountForLoadReplicatedConst32(int64_t); - void LoadConst32(GpuRegister rd, int32_t value); - void LoadConst64(GpuRegister rd, int64_t value); // MIPS64 - - // This function is only used for testing purposes. - void RecordLoadConst64Path(int value); - - void Addiu32(GpuRegister rt, GpuRegister rs, int32_t value); - void Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp = AT); // MIPS64 - - // - // Heap poisoning. - // - - // Poison a heap reference contained in `src` and store it in `dst`. - void PoisonHeapReference(GpuRegister dst, GpuRegister src) { - // dst = -src. - // Negate the 32-bit ref. - Dsubu(dst, ZERO, src); - // And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64. - Dext(dst, dst, 0, 32); - } - // Poison a heap reference contained in `reg`. - void PoisonHeapReference(GpuRegister reg) { - // reg = -reg. - PoisonHeapReference(reg, reg); - } - // Unpoison a heap reference contained in `reg`. - void UnpoisonHeapReference(GpuRegister reg) { - // reg = -reg. - // Negate the 32-bit ref. - Dsubu(reg, ZERO, reg); - // And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64. - Dext(reg, reg, 0, 32); - } - // Poison a heap reference contained in `reg` if heap poisoning is enabled. - void MaybePoisonHeapReference(GpuRegister reg) { - if (kPoisonHeapReferences) { - PoisonHeapReference(reg); - } - } - // Unpoison a heap reference contained in `reg` if heap poisoning is enabled. - void MaybeUnpoisonHeapReference(GpuRegister reg) { - if (kPoisonHeapReferences) { - UnpoisonHeapReference(reg); - } - } - - void Bind(Label* label) override { - Bind(down_cast<Mips64Label*>(label)); - } - void Jump(Label* label ATTRIBUTE_UNUSED) override { - UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS64"; - } - - void Bind(Mips64Label* label); - - // Don't warn about a different virtual Bind/Jump in the base class. - using JNIBase::Bind; - using JNIBase::Jump; - - // Create a new label that can be used with Jump/Bind calls. - std::unique_ptr<JNIMacroLabel> CreateLabel() override { - LOG(FATAL) << "Not implemented on MIPS64"; - UNREACHABLE(); - } - // Emit an unconditional jump to the label. - void Jump(JNIMacroLabel* label ATTRIBUTE_UNUSED) override { - LOG(FATAL) << "Not implemented on MIPS64"; - UNREACHABLE(); - } - // Emit a conditional jump to the label by applying a unary condition test to the register. - void Jump(JNIMacroLabel* label ATTRIBUTE_UNUSED, - JNIMacroUnaryCondition cond ATTRIBUTE_UNUSED, - ManagedRegister test ATTRIBUTE_UNUSED) override { - LOG(FATAL) << "Not implemented on MIPS64"; - UNREACHABLE(); - } - - // Code at this offset will serve as the target for the Jump call. - void Bind(JNIMacroLabel* label ATTRIBUTE_UNUSED) override { - LOG(FATAL) << "Not implemented on MIPS64"; - UNREACHABLE(); - } - - // Create a new literal with a given value. - // NOTE: Force the template parameter to be explicitly specified. - template <typename T> - Literal* NewLiteral(typename Identity<T>::type value) { - static_assert(std::is_integral<T>::value, "T must be an integral type."); - return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value)); - } - - // Load label address using PC-relative loads. To be used with data labels in the literal / - // jump table area only and not with regular code labels. - void LoadLabelAddress(GpuRegister dest_reg, Mips64Label* label); - - // Create a new literal with the given data. - Literal* NewLiteral(size_t size, const uint8_t* data); - - // Load literal using PC-relative loads. - void LoadLiteral(GpuRegister dest_reg, LoadOperandType load_type, Literal* literal); - - // Create a jump table for the given labels that will be emitted when finalizing. - // When the table is emitted, offsets will be relative to the location of the table. - // The table location is determined by the location of its label (the label precedes - // the table data) and should be loaded using LoadLabelAddress(). - JumpTable* CreateJumpTable(std::vector<Mips64Label*>&& labels); - - // When `is_bare` is false, the branches will promote to long (if the range - // of the individual branch instruction is insufficient) and the delay/ - // forbidden slots will be taken care of. - // Use `is_bare = false` when the branch target may be out of reach of the - // individual branch instruction. IOW, this is for general purpose use. - // - // When `is_bare` is true, just the branch instructions will be generated - // leaving delay/forbidden slot filling up to the caller and the branches - // won't promote to long if the range is insufficient (you'll get a - // compilation error when the range is exceeded). - // Use `is_bare = true` when the branch target is known to be within reach - // of the individual branch instruction. This is intended for small local - // optimizations around delay/forbidden slots. - // Also prefer using `is_bare = true` if the code near the branch is to be - // patched or analyzed at run time (e.g. introspection) to - // - show the intent and - // - fail during compilation rather than during patching/execution if the - // bare branch range is insufficent but the code size and layout are - // expected to remain unchanged - // - // R6 compact branches without delay/forbidden slots. - void Bc(Mips64Label* label, bool is_bare = false); - void Balc(Mips64Label* label, bool is_bare = false); - // R6 compact branches with forbidden slots. - void Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Bltzc(GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Bgtzc(GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Bgezc(GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Blezc(GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); - void Beqzc(GpuRegister rs, Mips64Label* label, bool is_bare = false); - void Bnezc(GpuRegister rs, Mips64Label* label, bool is_bare = false); - // R6 branches with delay slots. - void Bc1eqz(FpuRegister ft, Mips64Label* label, bool is_bare = false); - void Bc1nez(FpuRegister ft, Mips64Label* label, bool is_bare = false); - // R2 branches with delay slots that are also available on R6. - // The `is_bare` parameter exists and is checked in these branches only to - // prevent programming mistakes. These branches never promote to long, not - // even if `is_bare` is false. - void Bltz(GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2 - void Bgtz(GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2 - void Bgez(GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2 - void Blez(GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2 - void Beq(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2 - void Bne(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2 - void Beqz(GpuRegister rs, Mips64Label* label, bool is_bare = false); // R2 - void Bnez(GpuRegister rs, Mips64Label* label, bool is_bare = false); // R2 - - void EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset, size_t size); - void AdjustBaseAndOffset(GpuRegister& base, int32_t& offset, bool is_doubleword); - // If element_size_shift is negative at entry, its value will be calculated based on the offset. - void AdjustBaseOffsetAndElementSizeShift(GpuRegister& base, - int32_t& offset, - int& element_size_shift); - - private: - // This will be used as an argument for loads/stores - // when there is no need for implicit null checks. - struct NoImplicitNullChecker { - void operator()() const {} - }; - - public: - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void StoreConstToOffset(StoreOperandType type, - int64_t value, - GpuRegister base, - int32_t offset, - GpuRegister 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= */ (type == kStoreDoubleword)); - GpuRegister 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 (type == kStoreDoubleword && IsAligned<kMips64DoublewordSize>(offset)) { - if (value == 0) { - reg = ZERO; - } else { - reg = temp; - LoadConst64(reg, value); - } - Sd(reg, base, offset); - null_checker(); - } else { - uint32_t low = Low32Bits(value); - uint32_t high = High32Bits(value); - if (low == 0) { - reg = ZERO; - } else { - reg = temp; - LoadConst32(reg, low); - } - 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: - // not aligned to kMips64DoublewordSize - CHECK_ALIGNED(offset, kMips64WordSize); - Sw(reg, base, offset); - null_checker(); - if (high == 0) { - reg = ZERO; - } else { - reg = temp; - if (high != low) { - LoadConst32(reg, high); - } - } - Sw(reg, base, offset + kMips64WordSize); - break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - if (type != kStoreDoubleword) { - null_checker(); - } - } - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void LoadFromOffset(LoadOperandType type, - GpuRegister reg, - GpuRegister base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - AdjustBaseAndOffset(base, offset, /* is_doubleword= */ (type == kLoadDoubleword)); - - switch (type) { - case kLoadSignedByte: - Lb(reg, base, offset); - break; - case kLoadUnsignedByte: - Lbu(reg, base, offset); - break; - case kLoadSignedHalfword: - Lh(reg, base, offset); - break; - case kLoadUnsignedHalfword: - 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: - if (!IsAligned<kMips64DoublewordSize>(offset)) { - CHECK_ALIGNED(offset, kMips64WordSize); - Lwu(reg, base, offset); - null_checker(); - Lwu(TMP2, base, offset + kMips64WordSize); - Dinsu(reg, TMP2, 32, 32); - } else { - Ld(reg, base, offset); - null_checker(); - } - break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - if (type != kLoadDoubleword) { - null_checker(); - } - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void LoadFpuFromOffset(LoadOperandType type, - FpuRegister reg, - GpuRegister base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - int element_size_shift = -1; - if (type != kLoadQuadword) { - AdjustBaseAndOffset(base, offset, /* is_doubleword= */ (type == kLoadDoubleword)); - } else { - AdjustBaseOffsetAndElementSizeShift(base, offset, element_size_shift); - } - - switch (type) { - case kLoadWord: - CHECK_ALIGNED(offset, kMips64WordSize); - Lwc1(reg, base, offset); - null_checker(); - break; - case kLoadDoubleword: - if (!IsAligned<kMips64DoublewordSize>(offset)) { - CHECK_ALIGNED(offset, kMips64WordSize); - Lwc1(reg, base, offset); - null_checker(); - Lw(TMP2, base, offset + kMips64WordSize); - Mthc1(TMP2, reg); - } else { - Ldc1(reg, base, offset); - null_checker(); - } - break; - case kLoadQuadword: - switch (element_size_shift) { - case TIMES_1: LdB(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_2: LdH(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_4: LdW(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_8: LdD(static_cast<VectorRegister>(reg), base, offset); break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - null_checker(); - break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void StoreToOffset(StoreOperandType type, - GpuRegister reg, - GpuRegister base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - // 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); - break; - case kStoreHalfword: - Sh(reg, base, offset); - break; - case kStoreWord: - CHECK_ALIGNED(offset, kMips64WordSize); - Sw(reg, base, offset); - break; - case kStoreDoubleword: - if (!IsAligned<kMips64DoublewordSize>(offset)) { - CHECK_ALIGNED(offset, kMips64WordSize); - Sw(reg, base, offset); - null_checker(); - Dsrl32(TMP2, reg, 0); - Sw(TMP2, base, offset + kMips64WordSize); - } else { - Sd(reg, base, offset); - null_checker(); - } - break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - if (type != kStoreDoubleword) { - null_checker(); - } - } - - template <typename ImplicitNullChecker = NoImplicitNullChecker> - void StoreFpuToOffset(StoreOperandType type, - FpuRegister reg, - GpuRegister base, - int32_t offset, - ImplicitNullChecker null_checker = NoImplicitNullChecker()) { - int element_size_shift = -1; - if (type != kStoreQuadword) { - AdjustBaseAndOffset(base, offset, /* is_doubleword= */ (type == kStoreDoubleword)); - } else { - AdjustBaseOffsetAndElementSizeShift(base, offset, element_size_shift); - } - - switch (type) { - case kStoreWord: - CHECK_ALIGNED(offset, kMips64WordSize); - Swc1(reg, base, offset); - null_checker(); - break; - case kStoreDoubleword: - if (!IsAligned<kMips64DoublewordSize>(offset)) { - CHECK_ALIGNED(offset, kMips64WordSize); - Mfhc1(TMP2, reg); - Swc1(reg, base, offset); - null_checker(); - Sw(TMP2, base, offset + kMips64WordSize); - } else { - Sdc1(reg, base, offset); - null_checker(); - } - break; - case kStoreQuadword: - switch (element_size_shift) { - case TIMES_1: StB(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_2: StH(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_4: StW(static_cast<VectorRegister>(reg), base, offset); break; - case TIMES_8: StD(static_cast<VectorRegister>(reg), base, offset); break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - null_checker(); - break; - default: - LOG(FATAL) << "UNREACHABLE"; - } - } - - void LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base, int32_t offset); - void LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base, int32_t offset); - void StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base, int32_t offset); - void StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base, int32_t offset); - - // Emit data (e.g. encoded instruction or immediate) to the instruction stream. - void Emit(uint32_t value); - - // - // Overridden common assembler high-level functionality. - // - - // Emit code that will create an activation on the stack. - void BuildFrame(size_t frame_size, - ManagedRegister method_reg, - ArrayRef<const ManagedRegister> callee_save_regs, - const ManagedRegisterEntrySpills& entry_spills) override; - - // Emit code that will remove an activation from the stack. - void RemoveFrame(size_t frame_size, - ArrayRef<const ManagedRegister> callee_save_regs, - bool may_suspend) override; - - void IncreaseFrameSize(size_t adjust) override; - void DecreaseFrameSize(size_t adjust) override; - - // Store routines. - void Store(FrameOffset offs, ManagedRegister msrc, size_t size) override; - void StoreRef(FrameOffset dest, ManagedRegister msrc) override; - void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) override; - - void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) override; - - void StoreStackOffsetToThread(ThreadOffset64 thr_offs, - FrameOffset fr_offs, - ManagedRegister mscratch) override; - - void StoreStackPointerToThread(ThreadOffset64 thr_offs) override; - - void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off, - ManagedRegister mscratch) override; - - // Load routines. - void Load(ManagedRegister mdest, FrameOffset src, size_t size) override; - - void LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) override; - - void LoadRef(ManagedRegister dest, FrameOffset src) override; - - void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, - bool unpoison_reference) override; - - void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) override; - - void LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) override; - - // Copying routines. - void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) override; - - void CopyRawPtrFromThread(FrameOffset fr_offs, - ThreadOffset64 thr_offs, - ManagedRegister mscratch) override; - - void CopyRawPtrToThread(ThreadOffset64 thr_offs, - FrameOffset fr_offs, - ManagedRegister mscratch) override; - - void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) override; - - void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) override; - - void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister mscratch, - size_t size) override; - - void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, - ManagedRegister mscratch, size_t size) override; - - void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister mscratch, - size_t size) override; - - void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset, - ManagedRegister mscratch, size_t size) override; - - void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset, - ManagedRegister mscratch, size_t size) override; - - void MemoryBarrier(ManagedRegister) override; - - // Sign extension. - void SignExtend(ManagedRegister mreg, size_t size) override; - - // Zero extension. - void ZeroExtend(ManagedRegister mreg, size_t size) override; - - // Exploit fast access in managed code to Thread::Current(). - void GetCurrentThread(ManagedRegister tr) override; - void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) override; - - // Set up out_reg to hold a Object** into the handle scope, or to be null if the - // value is null and null_allowed. in_reg holds a possibly stale reference - // that can be used to avoid loading the handle scope entry to see if the value is - // null. - void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset, - ManagedRegister in_reg, bool null_allowed) override; - - // Set up out_off to hold a Object** into the handle scope, or to be null if the - // value is null and null_allowed. - void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, ManagedRegister - mscratch, bool null_allowed) override; - - // src holds a handle scope entry (Object**) load this into dst. - void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) override; - - // Heap::VerifyObject on src. In some cases (such as a reference to this) we - // know that src may not be null. - void VerifyObject(ManagedRegister src, bool could_be_null) override; - void VerifyObject(FrameOffset src, bool could_be_null) override; - - // 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 CallFromThread(ThreadOffset64 offset, ManagedRegister mscratch) override; - - // Generate code to check if Thread::Current()->exception_ is non-null - // and branch to a ExceptionSlowPath if it is. - void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) override; - - // Emit slow paths queued during assembly and promote short branches to long if needed. - void FinalizeCode() override; - - // Emit branches and finalize all instructions. - void FinalizeInstructions(const MemoryRegion& region) override; - - // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS64, - // must be used instead of Mips64Label::GetPosition()). - uint32_t GetLabelLocation(const Mips64Label* label) const; - - // Get the final position of a label after local fixup based on the old position - // recorded before FinalizeCode(). - uint32_t GetAdjustedPosition(uint32_t old_position); - - // Note that PC-relative literal loads are handled as pseudo branches because they need very - // similar relocation and may similarly expand in size to accomodate for larger offsets relative - // to PC. - enum BranchCondition { - kCondLT, - kCondGE, - kCondLE, - kCondGT, - kCondLTZ, - kCondGEZ, - kCondLEZ, - kCondGTZ, - kCondEQ, - kCondNE, - kCondEQZ, - kCondNEZ, - kCondLTU, - kCondGEU, - kCondF, // Floating-point predicate false. - kCondT, // Floating-point predicate true. - kUncond, - }; - friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs); - - private: - class Branch { - public: - enum Type { - // R6 short branches (can be promoted to long). - kUncondBranch, - kCondBranch, - kCall, - // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. - kBareUncondBranch, - kBareCondBranch, - kBareCall, - // R2 short branches (can't be promoted to long), delay slots filled manually. - kR2BareCondBranch, - // Near label. - kLabel, - // Near literals. - kLiteral, - kLiteralUnsigned, - kLiteralLong, - // Long branches. - kLongUncondBranch, - kLongCondBranch, - kLongCall, - // Far label. - kFarLabel, - // Far literals. - kFarLiteral, - kFarLiteralUnsigned, - kFarLiteralLong, - }; - - // Bit sizes of offsets defined as enums to minimize chance of typos. - enum OffsetBits { - kOffset16 = 16, - kOffset18 = 18, - kOffset21 = 21, - kOffset23 = 23, - kOffset28 = 28, - kOffset32 = 32, - }; - - static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_ - static constexpr int32_t kMaxBranchLength = 32; - static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t); - - struct BranchInfo { - // Branch length as a number of 4-byte-long instructions. - uint32_t length; - // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's - // PC-relative offset (or its most significant 16-bit half, which goes first). - uint32_t instr_offset; - // Different MIPS instructions with PC-relative offsets apply said offsets to slightly - // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte - // instructions) from the instruction containing the offset. - uint32_t pc_org; - // How large (in bits) a PC-relative offset can be for a given type of branch (kCondBranch - // and kBareCondBranch are an exception: use kOffset23 for beqzc/bnezc). - OffsetBits offset_size; - // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift - // count. - int offset_shift; - }; - static const BranchInfo branch_info_[/* Type */]; - - // Unconditional branch or call. - Branch(uint32_t location, uint32_t target, bool is_call, bool is_bare); - // Conditional branch. - Branch(bool is_r6, - uint32_t location, - uint32_t target, - BranchCondition condition, - GpuRegister lhs_reg, - GpuRegister rhs_reg, - bool is_bare); - // Label address (in literal area) or literal. - Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type); - - // Some conditional branches with lhs = rhs are effectively NOPs, while some - // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs. - // So, we need a way to identify such branches in order to emit no instructions for them - // or change them to unconditional. - static bool IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs); - static bool IsUncond(BranchCondition condition, GpuRegister lhs, GpuRegister rhs); - - static BranchCondition OppositeCondition(BranchCondition cond); - - Type GetType() const; - BranchCondition GetCondition() const; - GpuRegister GetLeftRegister() const; - GpuRegister GetRightRegister() const; - uint32_t GetTarget() const; - uint32_t GetLocation() const; - uint32_t GetOldLocation() const; - uint32_t GetLength() const; - uint32_t GetOldLength() const; - uint32_t GetSize() const; - uint32_t GetOldSize() const; - uint32_t GetEndLocation() const; - uint32_t GetOldEndLocation() const; - bool IsBare() const; - bool IsLong() const; - bool IsResolved() const; - - // Returns the bit size of the signed offset that the branch instruction can handle. - OffsetBits GetOffsetSize() const; - - // Calculates the distance between two byte locations in the assembler buffer and - // returns the number of bits needed to represent the distance as a signed integer. - // - // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc), - // and 26 (bc) bits, which are additionally shifted left 2 positions at run time. - // - // Composite branches (made of several instructions) with longer reach have 32-bit - // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first). - // The composite branches cover the range of PC + ~+/-2GB. The range is not end-to-end, - // however. Consider the following implementation of a long unconditional branch, for - // example: - // - // auipc at, offset_31_16 // at = pc + sign_extend(offset_31_16) << 16 - // jic at, offset_15_0 // pc = at + sign_extend(offset_15_0) - // - // Both of the above instructions take 16-bit signed offsets as immediate operands. - // When bit 15 of offset_15_0 is 1, it effectively causes subtraction of 0x10000 - // due to sign extension. This must be compensated for by incrementing offset_31_16 - // by 1. offset_31_16 can only be incremented by 1 if it's not 0x7FFF. If it is - // 0x7FFF, adding 1 will overflow the positive offset into the negative range. - // Therefore, the long branch range is something like from PC - 0x80000000 to - // PC + 0x7FFF7FFF, IOW, shorter by 32KB on one side. - // - // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special - // case with the addiu instruction and a 16 bit offset. - static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target); - - // Resolve a branch when the target is known. - void Resolve(uint32_t target); - - // Relocate a branch by a given delta if needed due to expansion of this or another - // branch at a given location by this delta (just changes location_ and target_). - void Relocate(uint32_t expand_location, uint32_t delta); - - // If the branch is short, changes its type to long. - void PromoteToLong(); - - // If necessary, updates the type by promoting a short branch to a long branch - // based on the branch location and target. Returns the amount (in bytes) by - // which the branch size has increased. - // max_short_distance caps the maximum distance between location_ and target_ - // that is allowed for short branches. This is for debugging/testing purposes. - // max_short_distance = 0 forces all short branches to become long. - // Use the implicit default argument when not debugging/testing. - uint32_t PromoteIfNeeded(uint32_t max_short_distance = std::numeric_limits<uint32_t>::max()); - - // Returns the location of the instruction(s) containing the offset. - uint32_t GetOffsetLocation() const; - - // Calculates and returns the offset ready for encoding in the branch instruction(s). - uint32_t GetOffset() const; - - private: - // Completes branch construction by determining and recording its type. - void InitializeType(Type initial_type, bool is_r6); - // Helper for the above. - void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type); - - uint32_t old_location_; // Offset into assembler buffer in bytes. - uint32_t location_; // Offset into assembler buffer in bytes. - uint32_t target_; // Offset into assembler buffer in bytes. - - GpuRegister lhs_reg_; // Left-hand side register in conditional branches or - // destination register in literals. - GpuRegister rhs_reg_; // Right-hand side register in conditional branches. - BranchCondition condition_; // Condition for conditional branches. - - Type type_; // Current type of the branch. - Type old_type_; // Initial type of the branch. - }; - friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs); - friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs); - - void EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd, int shamt, int funct); - void EmitRsd(int opcode, GpuRegister rs, GpuRegister rd, int shamt, int funct); - void EmitRtd(int opcode, GpuRegister rt, GpuRegister rd, int shamt, int funct); - void EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm); - void EmitI21(int opcode, GpuRegister rs, uint32_t imm21); - void EmitI26(int opcode, uint32_t imm26); - void EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd, int funct); - void EmitFI(int opcode, int fmt, FpuRegister rt, uint16_t imm); - void EmitBcondR6(BranchCondition cond, GpuRegister rs, GpuRegister rt, uint32_t imm16_21); - void EmitBcondR2(BranchCondition cond, GpuRegister rs, GpuRegister rt, uint16_t imm16); - void EmitMsa3R(int operation, - int df, - VectorRegister wt, - VectorRegister ws, - VectorRegister wd, - int minor_opcode); - void EmitMsaBIT(int operation, int df_m, VectorRegister ws, VectorRegister wd, int minor_opcode); - void EmitMsaELM(int operation, int df_n, VectorRegister ws, VectorRegister wd, int minor_opcode); - void EmitMsaMI10(int s10, GpuRegister rs, VectorRegister wd, int minor_opcode, int df); - void EmitMsaI10(int operation, int df, int i10, VectorRegister wd, int minor_opcode); - void EmitMsa2R(int operation, int df, VectorRegister ws, VectorRegister wd, int minor_opcode); - void EmitMsa2RF(int operation, int df, VectorRegister ws, VectorRegister wd, int minor_opcode); - - void Buncond(Mips64Label* label, bool is_bare); - void Bcond(Mips64Label* label, - bool is_r6, - bool is_bare, - BranchCondition condition, - GpuRegister lhs, - GpuRegister rhs = ZERO); - void Call(Mips64Label* label, bool is_bare); - void FinalizeLabeledBranch(Mips64Label* label); - - Branch* GetBranch(uint32_t branch_id); - const Branch* GetBranch(uint32_t branch_id) const; - - void EmitLiterals(); - void ReserveJumpTableSpace(); - void EmitJumpTables(); - void PromoteBranches(); - void EmitBranch(Branch* branch); - void EmitBranches(); - void PatchCFI(); - - // Emits exception block. - void EmitExceptionPoll(Mips64ExceptionSlowPath* exception); - - bool HasMsa() const { - return has_msa_; - } - - // List of exception blocks to generate at the end of the code cache. - std::vector<Mips64ExceptionSlowPath> exception_blocks_; - - std::vector<Branch> branches_; - - // Whether appending instructions at the end of the buffer or overwriting the existing ones. - bool overwriting_; - // The current overwrite location. - uint32_t overwrite_location_; - - // Use std::deque<> for literal labels to allow insertions at the end - // without invalidating pointers and references to existing elements. - ArenaDeque<Literal> literals_; - ArenaDeque<Literal> long_literals_; // 64-bit literals separated for alignment reasons. - - // Jump table list. - ArenaDeque<JumpTable> jump_tables_; - - // Data for AdjustedPosition(), see the description there. - uint32_t last_position_adjustment_; - uint32_t last_old_position_; - uint32_t last_branch_id_; - - const bool has_msa_; - - DISALLOW_COPY_AND_ASSIGN(Mips64Assembler); -}; - -} // namespace mips64 -} // namespace art - -#endif // ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_ diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc deleted file mode 100644 index 499e8f4e15..0000000000 --- a/compiler/utils/mips64/assembler_mips64_test.cc +++ /dev/null @@ -1,3784 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "assembler_mips64.h" - -#include <inttypes.h> -#include <map> -#include <random> - -#include "base/bit_utils.h" -#include "base/stl_util.h" -#include "utils/assembler_test.h" - -#define __ GetAssembler()-> - -namespace art { - -struct MIPS64CpuRegisterCompare { - bool operator()(const mips64::GpuRegister& a, const mips64::GpuRegister& b) const { - return a < b; - } -}; - -class AssemblerMIPS64Test : public AssemblerTest<mips64::Mips64Assembler, - mips64::Mips64Label, - mips64::GpuRegister, - mips64::FpuRegister, - uint32_t, - mips64::VectorRegister> { - public: - using Base = AssemblerTest<mips64::Mips64Assembler, - mips64::Mips64Label, - mips64::GpuRegister, - mips64::FpuRegister, - uint32_t, - mips64::VectorRegister>; - - // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<> - // and reimplement it without the verification against `assembly_string`. b/73903608 - void DriverStr(const std::string& assembly_string ATTRIBUTE_UNUSED, - const std::string& test_name ATTRIBUTE_UNUSED) { - GetAssembler()->FinalizeCode(); - std::vector<uint8_t> data(GetAssembler()->CodeSize()); - MemoryRegion code(data.data(), data.size()); - GetAssembler()->FinalizeInstructions(code); - } - - AssemblerMIPS64Test() - : instruction_set_features_(Mips64InstructionSetFeatures::FromVariant("default", nullptr)) {} - - protected: - // Get the typically used name for this architecture, e.g., aarch64, x86-64, ... - std::string GetArchitectureString() override { - return "mips64"; - } - - std::string GetAssemblerCmdName() override { - // We assemble and link for MIPS64R6. See GetAssemblerParameters() for details. - return "gcc"; - } - - std::string GetAssemblerParameters() override { - // We assemble and link for MIPS64R6. The reason is that object files produced for MIPS64R6 - // (and MIPS32R6) with the GNU assembler don't have correct final offsets in PC-relative - // branches in the .text section and so they require a relocation pass (there's a relocation - // section, .rela.text, that has the needed info to fix up the branches). - return " -march=mips64r6 -mmsa -Wa,--no-warn -Wl,-Ttext=0 -Wl,-e0 -nostdlib"; - } - - void Pad(std::vector<uint8_t>& data) override { - // The GNU linker unconditionally pads the code segment with NOPs to a size that is a multiple - // of 16 and there doesn't appear to be a way to suppress this padding. Our assembler doesn't - // pad, so, in order for two assembler outputs to match, we need to match the padding as well. - // NOP is encoded as four zero bytes on MIPS. - size_t pad_size = RoundUp(data.size(), 16u) - data.size(); - data.insert(data.end(), pad_size, 0); - } - - std::string GetDisassembleParameters() override { - return " -D -bbinary -mmips:isa64r6"; - } - - mips64::Mips64Assembler* CreateAssembler(ArenaAllocator* allocator) override { - return new (allocator) mips64::Mips64Assembler(allocator, instruction_set_features_.get()); - } - - void SetUpHelpers() override { - if (registers_.size() == 0) { - registers_.push_back(new mips64::GpuRegister(mips64::ZERO)); - registers_.push_back(new mips64::GpuRegister(mips64::AT)); - registers_.push_back(new mips64::GpuRegister(mips64::V0)); - registers_.push_back(new mips64::GpuRegister(mips64::V1)); - registers_.push_back(new mips64::GpuRegister(mips64::A0)); - registers_.push_back(new mips64::GpuRegister(mips64::A1)); - registers_.push_back(new mips64::GpuRegister(mips64::A2)); - registers_.push_back(new mips64::GpuRegister(mips64::A3)); - registers_.push_back(new mips64::GpuRegister(mips64::A4)); - registers_.push_back(new mips64::GpuRegister(mips64::A5)); - registers_.push_back(new mips64::GpuRegister(mips64::A6)); - registers_.push_back(new mips64::GpuRegister(mips64::A7)); - registers_.push_back(new mips64::GpuRegister(mips64::T0)); - registers_.push_back(new mips64::GpuRegister(mips64::T1)); - registers_.push_back(new mips64::GpuRegister(mips64::T2)); - registers_.push_back(new mips64::GpuRegister(mips64::T3)); - registers_.push_back(new mips64::GpuRegister(mips64::S0)); - registers_.push_back(new mips64::GpuRegister(mips64::S1)); - registers_.push_back(new mips64::GpuRegister(mips64::S2)); - registers_.push_back(new mips64::GpuRegister(mips64::S3)); - registers_.push_back(new mips64::GpuRegister(mips64::S4)); - registers_.push_back(new mips64::GpuRegister(mips64::S5)); - registers_.push_back(new mips64::GpuRegister(mips64::S6)); - registers_.push_back(new mips64::GpuRegister(mips64::S7)); - registers_.push_back(new mips64::GpuRegister(mips64::T8)); - registers_.push_back(new mips64::GpuRegister(mips64::T9)); - registers_.push_back(new mips64::GpuRegister(mips64::K0)); - registers_.push_back(new mips64::GpuRegister(mips64::K1)); - registers_.push_back(new mips64::GpuRegister(mips64::GP)); - registers_.push_back(new mips64::GpuRegister(mips64::SP)); - registers_.push_back(new mips64::GpuRegister(mips64::S8)); - registers_.push_back(new mips64::GpuRegister(mips64::RA)); - - secondary_register_names_.emplace(mips64::GpuRegister(mips64::ZERO), "zero"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::AT), "at"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::V0), "v0"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::V1), "v1"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::A0), "a0"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::A1), "a1"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::A2), "a2"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::A3), "a3"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::A4), "a4"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::A5), "a5"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::A6), "a6"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::A7), "a7"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::T0), "t0"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::T1), "t1"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::T2), "t2"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::T3), "t3"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::S0), "s0"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::S1), "s1"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::S2), "s2"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::S3), "s3"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::S4), "s4"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::S5), "s5"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::S6), "s6"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::S7), "s7"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::T8), "t8"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::T9), "t9"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::K0), "k0"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::K1), "k1"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::GP), "gp"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::SP), "sp"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::S8), "s8"); - secondary_register_names_.emplace(mips64::GpuRegister(mips64::RA), "ra"); - - fp_registers_.push_back(new mips64::FpuRegister(mips64::F0)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F1)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F2)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F3)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F4)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F5)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F6)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F7)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F8)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F9)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F10)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F11)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F12)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F13)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F14)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F15)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F16)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F17)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F18)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F19)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F20)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F21)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F22)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F23)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F24)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F25)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F26)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F27)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F28)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F29)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F30)); - fp_registers_.push_back(new mips64::FpuRegister(mips64::F31)); - - vec_registers_.push_back(new mips64::VectorRegister(mips64::W0)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W1)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W2)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W3)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W4)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W5)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W6)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W7)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W8)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W9)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W10)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W11)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W12)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W13)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W14)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W15)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W16)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W17)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W18)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W19)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W20)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W21)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W22)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W23)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W24)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W25)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W26)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W27)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W28)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W29)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W30)); - vec_registers_.push_back(new mips64::VectorRegister(mips64::W31)); - } - } - - void TearDown() override { - AssemblerTest::TearDown(); - STLDeleteElements(®isters_); - STLDeleteElements(&fp_registers_); - STLDeleteElements(&vec_registers_); - } - - std::vector<mips64::Mips64Label> GetAddresses() override { - UNIMPLEMENTED(FATAL) << "Feature not implemented yet"; - UNREACHABLE(); - } - - std::vector<mips64::GpuRegister*> GetRegisters() override { - return registers_; - } - - std::vector<mips64::FpuRegister*> GetFPRegisters() override { - return fp_registers_; - } - - std::vector<mips64::VectorRegister*> GetVectorRegisters() override { - return vec_registers_; - } - - uint32_t CreateImmediate(int64_t imm_value) override { - return imm_value; - } - - std::string GetSecondaryRegisterName(const mips64::GpuRegister& reg) override { - CHECK(secondary_register_names_.find(reg) != secondary_register_names_.end()); - return secondary_register_names_[reg]; - } - - std::string RepeatInsn(size_t count, const std::string& insn) { - std::string result; - for (; count != 0u; --count) { - result += insn; - } - return result; - } - - void BranchHelper(void (mips64::Mips64Assembler::*f)(mips64::Mips64Label*, - bool), - const std::string& instr_name, - bool is_bare = false) { - mips64::Mips64Label label1, label2; - (Base::GetAssembler()->*f)(&label1, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - __ Bind(&label1); - (Base::GetAssembler()->*f)(&label2, is_bare); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - __ Bind(&label2); - (Base::GetAssembler()->*f)(&label1, is_bare); - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " 1f\n" + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - instr_name + " 2f\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "2:\n" + - instr_name + " 1b\n" + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - void BranchCondOneRegHelper(void (mips64::Mips64Assembler::*f)(mips64::GpuRegister, - mips64::Mips64Label*, - bool), - const std::string& instr_name, - bool is_bare = false) { - mips64::Mips64Label label; - (Base::GetAssembler()->*f)(mips64::A0, &label, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - (Base::GetAssembler()->*f)(mips64::A1, &label, is_bare); - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " $a0, 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - instr_name + " $a1, 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - void BranchCondTwoRegsHelper(void (mips64::Mips64Assembler::*f)(mips64::GpuRegister, - mips64::GpuRegister, - mips64::Mips64Label*, - bool), - const std::string& instr_name, - bool is_bare = false) { - mips64::Mips64Label label; - (Base::GetAssembler()->*f)(mips64::A0, mips64::A1, &label, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - (Base::GetAssembler()->*f)(mips64::A2, mips64::A3, &label, is_bare); - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " $a0, $a1, 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - instr_name + " $a2, $a3, 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - void BranchFpuCondHelper(void (mips64::Mips64Assembler::*f)(mips64::FpuRegister, - mips64::Mips64Label*, - bool), - const std::string& instr_name, - bool is_bare = false) { - mips64::Mips64Label label; - (Base::GetAssembler()->*f)(mips64::F0, &label, is_bare); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - (Base::GetAssembler()->*f)(mips64::F31, &label, is_bare); - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - - std::string expected = - ".set noreorder\n" + - instr_name + " $f0, 1f\n" + - (is_bare ? "" : "nop\n") + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - instr_name + " $f31, 1b\n" + - (is_bare ? "" : "nop\n") + - "addu $zero, $zero, $zero\n"; - DriverStr(expected, instr_name); - } - - private: - std::vector<mips64::GpuRegister*> registers_; - std::map<mips64::GpuRegister, std::string, MIPS64CpuRegisterCompare> secondary_register_names_; - - std::vector<mips64::FpuRegister*> fp_registers_; - std::vector<mips64::VectorRegister*> vec_registers_; - - std::unique_ptr<const Mips64InstructionSetFeatures> instruction_set_features_; -}; - -TEST_F(AssemblerMIPS64Test, Toolchain) { - EXPECT_TRUE(CheckTools()); -} - -/////////////////// -// FP Operations // -/////////////////// - -TEST_F(AssemblerMIPS64Test, AddS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::AddS, "add.s ${reg1}, ${reg2}, ${reg3}"), "add.s"); -} - -TEST_F(AssemblerMIPS64Test, AddD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::AddD, "add.d ${reg1}, ${reg2}, ${reg3}"), "add.d"); -} - -TEST_F(AssemblerMIPS64Test, SubS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::SubS, "sub.s ${reg1}, ${reg2}, ${reg3}"), "sub.s"); -} - -TEST_F(AssemblerMIPS64Test, SubD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::SubD, "sub.d ${reg1}, ${reg2}, ${reg3}"), "sub.d"); -} - -TEST_F(AssemblerMIPS64Test, MulS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::MulS, "mul.s ${reg1}, ${reg2}, ${reg3}"), "mul.s"); -} - -TEST_F(AssemblerMIPS64Test, MulD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::MulD, "mul.d ${reg1}, ${reg2}, ${reg3}"), "mul.d"); -} - -TEST_F(AssemblerMIPS64Test, DivS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::DivS, "div.s ${reg1}, ${reg2}, ${reg3}"), "div.s"); -} - -TEST_F(AssemblerMIPS64Test, DivD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::DivD, "div.d ${reg1}, ${reg2}, ${reg3}"), "div.d"); -} - -TEST_F(AssemblerMIPS64Test, SqrtS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::SqrtS, "sqrt.s ${reg1}, ${reg2}"), "sqrt.s"); -} - -TEST_F(AssemblerMIPS64Test, SqrtD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::SqrtD, "sqrt.d ${reg1}, ${reg2}"), "sqrt.d"); -} - -TEST_F(AssemblerMIPS64Test, AbsS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::AbsS, "abs.s ${reg1}, ${reg2}"), "abs.s"); -} - -TEST_F(AssemblerMIPS64Test, AbsD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::AbsD, "abs.d ${reg1}, ${reg2}"), "abs.d"); -} - -TEST_F(AssemblerMIPS64Test, MovS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::MovS, "mov.s ${reg1}, ${reg2}"), "mov.s"); -} - -TEST_F(AssemblerMIPS64Test, MovD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::MovD, "mov.d ${reg1}, ${reg2}"), "mov.d"); -} - -TEST_F(AssemblerMIPS64Test, NegS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::NegS, "neg.s ${reg1}, ${reg2}"), "neg.s"); -} - -TEST_F(AssemblerMIPS64Test, NegD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::NegD, "neg.d ${reg1}, ${reg2}"), "neg.d"); -} - -TEST_F(AssemblerMIPS64Test, RoundLS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::RoundLS, "round.l.s ${reg1}, ${reg2}"), "round.l.s"); -} - -TEST_F(AssemblerMIPS64Test, RoundLD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::RoundLD, "round.l.d ${reg1}, ${reg2}"), "round.l.d"); -} - -TEST_F(AssemblerMIPS64Test, RoundWS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::RoundWS, "round.w.s ${reg1}, ${reg2}"), "round.w.s"); -} - -TEST_F(AssemblerMIPS64Test, RoundWD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::RoundWD, "round.w.d ${reg1}, ${reg2}"), "round.w.d"); -} - -TEST_F(AssemblerMIPS64Test, CeilLS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::CeilLS, "ceil.l.s ${reg1}, ${reg2}"), "ceil.l.s"); -} - -TEST_F(AssemblerMIPS64Test, CeilLD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::CeilLD, "ceil.l.d ${reg1}, ${reg2}"), "ceil.l.d"); -} - -TEST_F(AssemblerMIPS64Test, CeilWS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::CeilWS, "ceil.w.s ${reg1}, ${reg2}"), "ceil.w.s"); -} - -TEST_F(AssemblerMIPS64Test, CeilWD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::CeilWD, "ceil.w.d ${reg1}, ${reg2}"), "ceil.w.d"); -} - -TEST_F(AssemblerMIPS64Test, FloorLS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::FloorLS, "floor.l.s ${reg1}, ${reg2}"), "floor.l.s"); -} - -TEST_F(AssemblerMIPS64Test, FloorLD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::FloorLD, "floor.l.d ${reg1}, ${reg2}"), "floor.l.d"); -} - -TEST_F(AssemblerMIPS64Test, FloorWS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::FloorWS, "floor.w.s ${reg1}, ${reg2}"), "floor.w.s"); -} - -TEST_F(AssemblerMIPS64Test, FloorWD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::FloorWD, "floor.w.d ${reg1}, ${reg2}"), "floor.w.d"); -} - -TEST_F(AssemblerMIPS64Test, SelS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::SelS, "sel.s ${reg1}, ${reg2}, ${reg3}"), "sel.s"); -} - -TEST_F(AssemblerMIPS64Test, SelD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::SelD, "sel.d ${reg1}, ${reg2}, ${reg3}"), "sel.d"); -} - -TEST_F(AssemblerMIPS64Test, SeleqzS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::SeleqzS, "seleqz.s ${reg1}, ${reg2}, ${reg3}"), - "seleqz.s"); -} - -TEST_F(AssemblerMIPS64Test, SeleqzD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::SeleqzD, "seleqz.d ${reg1}, ${reg2}, ${reg3}"), - "seleqz.d"); -} - -TEST_F(AssemblerMIPS64Test, SelnezS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::SelnezS, "selnez.s ${reg1}, ${reg2}, ${reg3}"), - "selnez.s"); -} - -TEST_F(AssemblerMIPS64Test, SelnezD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::SelnezD, "selnez.d ${reg1}, ${reg2}, ${reg3}"), - "selnez.d"); -} - -TEST_F(AssemblerMIPS64Test, RintS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::RintS, "rint.s ${reg1}, ${reg2}"), "rint.s"); -} - -TEST_F(AssemblerMIPS64Test, RintD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::RintD, "rint.d ${reg1}, ${reg2}"), "rint.d"); -} - -TEST_F(AssemblerMIPS64Test, ClassS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::ClassS, "class.s ${reg1}, ${reg2}"), "class.s"); -} - -TEST_F(AssemblerMIPS64Test, ClassD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::ClassD, "class.d ${reg1}, ${reg2}"), "class.d"); -} - -TEST_F(AssemblerMIPS64Test, MinS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::MinS, "min.s ${reg1}, ${reg2}, ${reg3}"), "min.s"); -} - -TEST_F(AssemblerMIPS64Test, MinD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::MinD, "min.d ${reg1}, ${reg2}, ${reg3}"), "min.d"); -} - -TEST_F(AssemblerMIPS64Test, MaxS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::MaxS, "max.s ${reg1}, ${reg2}, ${reg3}"), "max.s"); -} - -TEST_F(AssemblerMIPS64Test, MaxD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::MaxD, "max.d ${reg1}, ${reg2}, ${reg3}"), "max.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpUnS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUnS, "cmp.un.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.un.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpEqS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpEqS, "cmp.eq.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.eq.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpUeqS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUeqS, "cmp.ueq.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.ueq.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpLtS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpLtS, "cmp.lt.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.lt.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpUltS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUltS, "cmp.ult.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.ult.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpLeS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpLeS, "cmp.le.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.le.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpUleS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUleS, "cmp.ule.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.ule.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpOrS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpOrS, "cmp.or.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.or.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpUneS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUneS, "cmp.une.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.une.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpNeS) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpNeS, "cmp.ne.s ${reg1}, ${reg2}, ${reg3}"), - "cmp.ne.s"); -} - -TEST_F(AssemblerMIPS64Test, CmpUnD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUnD, "cmp.un.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.un.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpEqD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpEqD, "cmp.eq.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.eq.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpUeqD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUeqD, "cmp.ueq.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.ueq.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpLtD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpLtD, "cmp.lt.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.lt.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpUltD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUltD, "cmp.ult.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.ult.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpLeD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpLeD, "cmp.le.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.le.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpUleD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUleD, "cmp.ule.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.ule.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpOrD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpOrD, "cmp.or.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.or.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpUneD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpUneD, "cmp.une.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.une.d"); -} - -TEST_F(AssemblerMIPS64Test, CmpNeD) { - DriverStr(RepeatFFF(&mips64::Mips64Assembler::CmpNeD, "cmp.ne.d ${reg1}, ${reg2}, ${reg3}"), - "cmp.ne.d"); -} - -TEST_F(AssemblerMIPS64Test, CvtDL) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::Cvtdl, "cvt.d.l ${reg1}, ${reg2}"), "cvt.d.l"); -} - -TEST_F(AssemblerMIPS64Test, CvtDS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::Cvtds, "cvt.d.s ${reg1}, ${reg2}"), "cvt.d.s"); -} - -TEST_F(AssemblerMIPS64Test, CvtDW) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::Cvtdw, "cvt.d.w ${reg1}, ${reg2}"), "cvt.d.w"); -} - -TEST_F(AssemblerMIPS64Test, CvtSL) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::Cvtsl, "cvt.s.l ${reg1}, ${reg2}"), "cvt.s.l"); -} - -TEST_F(AssemblerMIPS64Test, CvtSD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::Cvtsd, "cvt.s.d ${reg1}, ${reg2}"), "cvt.s.d"); -} - -TEST_F(AssemblerMIPS64Test, CvtSW) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::Cvtsw, "cvt.s.w ${reg1}, ${reg2}"), "cvt.s.w"); -} - -TEST_F(AssemblerMIPS64Test, TruncWS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::TruncWS, "trunc.w.s ${reg1}, ${reg2}"), "trunc.w.s"); -} - -TEST_F(AssemblerMIPS64Test, TruncWD) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::TruncWD, "trunc.w.d ${reg1}, ${reg2}"), "trunc.w.d"); -} - -TEST_F(AssemblerMIPS64Test, TruncLS) { - DriverStr(RepeatFF(&mips64::Mips64Assembler::TruncLS, "trunc.l.s ${reg1}, ${reg2}"), "trunc.l.s"); -} - -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"); -} - -TEST_F(AssemblerMIPS64Test, Lwc1) { - DriverStr(RepeatFRIb(&mips64::Mips64Assembler::Lwc1, -16, "lwc1 ${reg1}, {imm}(${reg2})"), - "lwc1"); -} - -TEST_F(AssemblerMIPS64Test, Ldc1) { - DriverStr(RepeatFRIb(&mips64::Mips64Assembler::Ldc1, -16, "ldc1 ${reg1}, {imm}(${reg2})"), - "ldc1"); -} - -TEST_F(AssemblerMIPS64Test, Swc1) { - DriverStr(RepeatFRIb(&mips64::Mips64Assembler::Swc1, -16, "swc1 ${reg1}, {imm}(${reg2})"), - "swc1"); -} - -TEST_F(AssemblerMIPS64Test, Sdc1) { - DriverStr(RepeatFRIb(&mips64::Mips64Assembler::Sdc1, -16, "sdc1 ${reg1}, {imm}(${reg2})"), - "sdc1"); -} - -////////////// -// BRANCHES // -////////////// - -TEST_F(AssemblerMIPS64Test, Jalr) { - DriverStr(".set noreorder\n" + - RepeatRRNoDupes(&mips64::Mips64Assembler::Jalr, "jalr ${reg1}, ${reg2}"), "jalr"); -} - -TEST_F(AssemblerMIPS64Test, Bc) { - BranchHelper(&mips64::Mips64Assembler::Bc, "Bc"); -} - -TEST_F(AssemblerMIPS64Test, Balc) { - BranchHelper(&mips64::Mips64Assembler::Balc, "Balc"); -} - -TEST_F(AssemblerMIPS64Test, Beqzc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Beqzc, "Beqzc"); -} - -TEST_F(AssemblerMIPS64Test, Bnezc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bnezc, "Bnezc"); -} - -TEST_F(AssemblerMIPS64Test, Bltzc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bltzc, "Bltzc"); -} - -TEST_F(AssemblerMIPS64Test, Bgezc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgezc, "Bgezc"); -} - -TEST_F(AssemblerMIPS64Test, Blezc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Blezc, "Blezc"); -} - -TEST_F(AssemblerMIPS64Test, Bgtzc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgtzc, "Bgtzc"); -} - -TEST_F(AssemblerMIPS64Test, Beqc) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Beqc, "Beqc"); -} - -TEST_F(AssemblerMIPS64Test, Bnec) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bnec, "Bnec"); -} - -TEST_F(AssemblerMIPS64Test, Bltc) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bltc, "Bltc"); -} - -TEST_F(AssemblerMIPS64Test, Bgec) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bgec, "Bgec"); -} - -TEST_F(AssemblerMIPS64Test, Bltuc) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bltuc, "Bltuc"); -} - -TEST_F(AssemblerMIPS64Test, Bgeuc) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bgeuc, "Bgeuc"); -} - -TEST_F(AssemblerMIPS64Test, Bc1eqz) { - BranchFpuCondHelper(&mips64::Mips64Assembler::Bc1eqz, "Bc1eqz"); -} - -TEST_F(AssemblerMIPS64Test, Bc1nez) { - BranchFpuCondHelper(&mips64::Mips64Assembler::Bc1nez, "Bc1nez"); -} - -TEST_F(AssemblerMIPS64Test, BareBc) { - BranchHelper(&mips64::Mips64Assembler::Bc, "Bc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBalc) { - BranchHelper(&mips64::Mips64Assembler::Balc, "Balc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBeqzc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Beqzc, "Beqzc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBnezc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bnezc, "Bnezc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBltzc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bltzc, "Bltzc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBgezc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgezc, "Bgezc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBlezc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Blezc, "Blezc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBgtzc) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgtzc, "Bgtzc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBeqc) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Beqc, "Beqc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBnec) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bnec, "Bnec", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBltc) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bltc, "Bltc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBgec) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bgec, "Bgec", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBltuc) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bltuc, "Bltuc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBgeuc) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bgeuc, "Bgeuc", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBc1eqz) { - BranchFpuCondHelper(&mips64::Mips64Assembler::Bc1eqz, "Bc1eqz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBc1nez) { - BranchFpuCondHelper(&mips64::Mips64Assembler::Bc1nez, "Bc1nez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBeqz) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Beqz, "Beqz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBnez) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bnez, "Bnez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBltz) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bltz, "Bltz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBgez) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgez, "Bgez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBlez) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Blez, "Blez", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBgtz) { - BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgtz, "Bgtz", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBeq) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Beq, "Beq", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, BareBne) { - BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bne, "Bne", /* is_bare= */ true); -} - -TEST_F(AssemblerMIPS64Test, LongBeqc) { - mips64::Mips64Label label; - __ Beqc(mips64::A0, mips64::A1, &label); - constexpr uint32_t kAdduCount1 = (1u << 15) + 1; - for (uint32_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - __ Bind(&label); - constexpr uint32_t kAdduCount2 = (1u << 15) + 1; - for (uint32_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - __ Beqc(mips64::A2, mips64::A3, &label); - - uint32_t offset_forward = 2 + kAdduCount1; // 2: account for auipc and jic. - offset_forward <<= 2; - offset_forward += (offset_forward & 0x8000) << 1; // Account for sign extension in jic. - - uint32_t offset_back = -(kAdduCount2 + 1); // 1: account for bnec. - offset_back <<= 2; - offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic. - - std::ostringstream oss; - oss << - ".set noreorder\n" - "bnec $a0, $a1, 1f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_forward) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_forward) << "\n" - "1:\n" << - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") << - "2:\n" << - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") << - "bnec $a2, $a3, 3f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n" - "3:\n"; - std::string expected = oss.str(); - DriverStr(expected, "LongBeqc"); -} - -TEST_F(AssemblerMIPS64Test, LongBeqzc) { - constexpr uint32_t kNopCount1 = (1u << 20) + 1; - constexpr uint32_t kNopCount2 = (1u << 20) + 1; - constexpr uint32_t kRequiredCapacity = (kNopCount1 + kNopCount2 + 6u) * 4u; - ASSERT_LT(__ GetBuffer()->Capacity(), kRequiredCapacity); - __ GetBuffer()->ExtendCapacity(kRequiredCapacity); - mips64::Mips64Label label; - __ Beqzc(mips64::A0, &label); - for (uint32_t i = 0; i != kNopCount1; ++i) { - __ Nop(); - } - __ Bind(&label); - for (uint32_t i = 0; i != kNopCount2; ++i) { - __ Nop(); - } - __ Beqzc(mips64::A2, &label); - - uint32_t offset_forward = 2 + kNopCount1; // 2: account for auipc and jic. - offset_forward <<= 2; - offset_forward += (offset_forward & 0x8000) << 1; // Account for sign extension in jic. - - uint32_t offset_back = -(kNopCount2 + 1); // 1: account for bnezc. - offset_back <<= 2; - offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic. - - // Note, we're using the ".fill" directive to tell the assembler to generate many NOPs - // instead of generating them ourselves in the source code. This saves test time. - std::ostringstream oss; - oss << - ".set noreorder\n" - "bnezc $a0, 1f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_forward) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_forward) << "\n" - "1:\n" << - ".fill 0x" << std::hex << kNopCount1 << " , 4, 0\n" - "2:\n" << - ".fill 0x" << std::hex << kNopCount2 << " , 4, 0\n" - "bnezc $a2, 3f\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n" - "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n" - "3:\n"; - std::string expected = oss.str(); - DriverStr(expected, "LongBeqzc"); -} - -TEST_F(AssemblerMIPS64Test, LongBalc) { - constexpr uint32_t kNopCount1 = (1u << 25) + 1; - constexpr uint32_t kNopCount2 = (1u << 25) + 1; - constexpr uint32_t kRequiredCapacity = (kNopCount1 + kNopCount2 + 6u) * 4u; - ASSERT_LT(__ GetBuffer()->Capacity(), kRequiredCapacity); - __ GetBuffer()->ExtendCapacity(kRequiredCapacity); - mips64::Mips64Label label1, label2; - __ Balc(&label1); - for (uint32_t i = 0; i != kNopCount1; ++i) { - __ Nop(); - } - __ Bind(&label1); - __ Balc(&label2); - for (uint32_t i = 0; i != kNopCount2; ++i) { - __ Nop(); - } - __ Bind(&label2); - __ Balc(&label1); - - uint32_t offset_forward1 = 2 + kNopCount1; // 2: account for auipc and jialc. - offset_forward1 <<= 2; - offset_forward1 += (offset_forward1 & 0x8000) << 1; // Account for sign extension in jialc. - - uint32_t offset_forward2 = 2 + kNopCount2; // 2: account for auipc and jialc. - offset_forward2 <<= 2; - offset_forward2 += (offset_forward2 & 0x8000) << 1; // Account for sign extension in jialc. - - uint32_t offset_back = -(2 + kNopCount2); // 2: account for auipc and jialc. - offset_back <<= 2; - offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jialc. - - // Note, we're using the ".fill" directive to tell the assembler to generate many NOPs - // instead of generating them ourselves in the source code. This saves a few minutes - // of test time. - std::ostringstream oss; - oss << - ".set noreorder\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_forward1) << "\n" - "jialc $at, 0x" << std::hex << Low16Bits(offset_forward1) << "\n" - ".fill 0x" << std::hex << kNopCount1 << " , 4, 0\n" - "1:\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_forward2) << "\n" - "jialc $at, 0x" << std::hex << Low16Bits(offset_forward2) << "\n" - ".fill 0x" << std::hex << kNopCount2 << " , 4, 0\n" - "2:\n" - "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n" - "jialc $at, 0x" << std::hex << Low16Bits(offset_back) << "\n"; - std::string expected = oss.str(); - DriverStr(expected, "LongBalc"); -} - -////////// -// MISC // -////////// - -TEST_F(AssemblerMIPS64Test, Lwpc) { - // Lwpc() takes an unsigned 19-bit immediate, while the GNU assembler needs a signed offset, - // hence the sign extension from bit 18 with `imm - ((imm & 0x40000) << 1)`. - // The GNU assembler also wants the offset to be a multiple of 4, which it will shift right - // by 2 positions when encoding, hence `<< 2` to compensate for that shift. - // We capture the value of the immediate with `.set imm, {imm}` because the value is needed - // twice for the sign extension, but `{imm}` is substituted only once. - const char* code = ".set imm, {imm}\nlw ${reg}, ((imm - ((imm & 0x40000) << 1)) << 2)($pc)"; - DriverStr(RepeatRIb(&mips64::Mips64Assembler::Lwpc, 19, code), "Lwpc"); -} - -TEST_F(AssemblerMIPS64Test, Lwupc) { - // The comment for the Lwpc test applies here as well. - const char* code = ".set imm, {imm}\nlwu ${reg}, ((imm - ((imm & 0x40000) << 1)) << 2)($pc)"; - DriverStr(RepeatRIb(&mips64::Mips64Assembler::Lwupc, 19, code), "Lwupc"); -} - -TEST_F(AssemblerMIPS64Test, Ldpc) { - // The comment for the Lwpc test applies here as well. - const char* code = ".set imm, {imm}\nld ${reg}, ((imm - ((imm & 0x20000) << 1)) << 3)($pc)"; - DriverStr(RepeatRIb(&mips64::Mips64Assembler::Ldpc, 18, code), "Ldpc"); -} - -TEST_F(AssemblerMIPS64Test, Auipc) { - DriverStr(RepeatRIb(&mips64::Mips64Assembler::Auipc, 16, "auipc ${reg}, {imm}"), "Auipc"); -} - -TEST_F(AssemblerMIPS64Test, Addiupc) { - // The comment from the Lwpc() test applies to this Addiupc() test as well. - const char* code = ".set imm, {imm}\naddiupc ${reg}, (imm - ((imm & 0x40000) << 1)) << 2"; - DriverStr(RepeatRIb(&mips64::Mips64Assembler::Addiupc, 19, code), "Addiupc"); -} - -TEST_F(AssemblerMIPS64Test, Addu) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Addu, "addu ${reg1}, ${reg2}, ${reg3}"), "addu"); -} - -TEST_F(AssemblerMIPS64Test, Addiu) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Addiu, -16, "addiu ${reg1}, ${reg2}, {imm}"), - "addiu"); -} - -TEST_F(AssemblerMIPS64Test, Daddu) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Daddu, "daddu ${reg1}, ${reg2}, ${reg3}"), "daddu"); -} - -TEST_F(AssemblerMIPS64Test, Daddiu) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Daddiu, -16, "daddiu ${reg1}, ${reg2}, {imm}"), - "daddiu"); -} - -TEST_F(AssemblerMIPS64Test, Subu) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Subu, "subu ${reg1}, ${reg2}, ${reg3}"), "subu"); -} - -TEST_F(AssemblerMIPS64Test, Dsubu) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Dsubu, "dsubu ${reg1}, ${reg2}, ${reg3}"), "dsubu"); -} - -TEST_F(AssemblerMIPS64Test, MulR6) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::MulR6, "mul ${reg1}, ${reg2}, ${reg3}"), "mulR6"); -} - -TEST_F(AssemblerMIPS64Test, DivR6) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::DivR6, "div ${reg1}, ${reg2}, ${reg3}"), "divR6"); -} - -TEST_F(AssemblerMIPS64Test, ModR6) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::ModR6, "mod ${reg1}, ${reg2}, ${reg3}"), "modR6"); -} - -TEST_F(AssemblerMIPS64Test, DivuR6) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::DivuR6, "divu ${reg1}, ${reg2}, ${reg3}"), - "divuR6"); -} - -TEST_F(AssemblerMIPS64Test, ModuR6) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::ModuR6, "modu ${reg1}, ${reg2}, ${reg3}"), - "moduR6"); -} - -TEST_F(AssemblerMIPS64Test, Dmul) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Dmul, "dmul ${reg1}, ${reg2}, ${reg3}"), "dmul"); -} - -TEST_F(AssemblerMIPS64Test, Ddiv) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Ddiv, "ddiv ${reg1}, ${reg2}, ${reg3}"), "ddiv"); -} - -TEST_F(AssemblerMIPS64Test, Dmod) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Dmod, "dmod ${reg1}, ${reg2}, ${reg3}"), "dmod"); -} - -TEST_F(AssemblerMIPS64Test, Ddivu) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Ddivu, "ddivu ${reg1}, ${reg2}, ${reg3}"), "ddivu"); -} - -TEST_F(AssemblerMIPS64Test, Dmodu) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Dmodu, "dmodu ${reg1}, ${reg2}, ${reg3}"), "dmodu"); -} - -TEST_F(AssemblerMIPS64Test, And) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::And, "and ${reg1}, ${reg2}, ${reg3}"), "and"); -} - -TEST_F(AssemblerMIPS64Test, Andi) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Andi, 16, "andi ${reg1}, ${reg2}, {imm}"), "andi"); -} - -TEST_F(AssemblerMIPS64Test, Or) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Or, "or ${reg1}, ${reg2}, ${reg3}"), "or"); -} - -TEST_F(AssemblerMIPS64Test, Ori) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Ori, 16, "ori ${reg1}, ${reg2}, {imm}"), "ori"); -} - -TEST_F(AssemblerMIPS64Test, Xor) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Xor, "xor ${reg1}, ${reg2}, ${reg3}"), "xor"); -} - -TEST_F(AssemblerMIPS64Test, Xori) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Xori, 16, "xori ${reg1}, ${reg2}, {imm}"), "xori"); -} - -TEST_F(AssemblerMIPS64Test, Nor) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Nor, "nor ${reg1}, ${reg2}, ${reg3}"), "nor"); -} - -TEST_F(AssemblerMIPS64Test, Lb) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Lb, -16, "lb ${reg1}, {imm}(${reg2})"), "lb"); -} - -TEST_F(AssemblerMIPS64Test, Lh) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Lh, -16, "lh ${reg1}, {imm}(${reg2})"), "lh"); -} - -TEST_F(AssemblerMIPS64Test, Lw) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Lw, -16, "lw ${reg1}, {imm}(${reg2})"), "lw"); -} - -TEST_F(AssemblerMIPS64Test, Ld) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Ld, -16, "ld ${reg1}, {imm}(${reg2})"), "ld"); -} - -TEST_F(AssemblerMIPS64Test, Lbu) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Lbu, -16, "lbu ${reg1}, {imm}(${reg2})"), "lbu"); -} - -TEST_F(AssemblerMIPS64Test, Lhu) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Lhu, -16, "lhu ${reg1}, {imm}(${reg2})"), "lhu"); -} - -TEST_F(AssemblerMIPS64Test, Lwu) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Lwu, -16, "lwu ${reg1}, {imm}(${reg2})"), "lwu"); -} - -TEST_F(AssemblerMIPS64Test, Lui) { - DriverStr(RepeatRIb(&mips64::Mips64Assembler::Lui, 16, "lui ${reg}, {imm}"), "lui"); -} - -TEST_F(AssemblerMIPS64Test, Daui) { - std::vector<mips64::GpuRegister*> reg1_registers = GetRegisters(); - std::vector<mips64::GpuRegister*> reg2_registers = GetRegisters(); - reg2_registers.erase(reg2_registers.begin()); // reg2 can't be ZERO, remove it. - std::vector<int64_t> imms = CreateImmediateValuesBits(/* imm_bits= */ 16, /* as_uint= */ true); - WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size()); - std::ostringstream expected; - for (mips64::GpuRegister* reg1 : reg1_registers) { - for (mips64::GpuRegister* reg2 : reg2_registers) { - for (int64_t imm : imms) { - __ Daui(*reg1, *reg2, imm); - expected << "daui $" << *reg1 << ", $" << *reg2 << ", " << imm << "\n"; - } - } - } - DriverStr(expected.str(), "daui"); -} - -TEST_F(AssemblerMIPS64Test, Dahi) { - DriverStr(RepeatRIb(&mips64::Mips64Assembler::Dahi, 16, "dahi ${reg}, ${reg}, {imm}"), "dahi"); -} - -TEST_F(AssemblerMIPS64Test, Dati) { - DriverStr(RepeatRIb(&mips64::Mips64Assembler::Dati, 16, "dati ${reg}, ${reg}, {imm}"), "dati"); -} - -TEST_F(AssemblerMIPS64Test, Sb) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Sb, -16, "sb ${reg1}, {imm}(${reg2})"), "sb"); -} - -TEST_F(AssemblerMIPS64Test, Sh) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Sh, -16, "sh ${reg1}, {imm}(${reg2})"), "sh"); -} - -TEST_F(AssemblerMIPS64Test, Sw) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Sw, -16, "sw ${reg1}, {imm}(${reg2})"), "sw"); -} - -TEST_F(AssemblerMIPS64Test, Sd) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Sd, -16, "sd ${reg1}, {imm}(${reg2})"), "sd"); -} - -TEST_F(AssemblerMIPS64Test, Slt) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Slt, "slt ${reg1}, ${reg2}, ${reg3}"), "slt"); -} - -TEST_F(AssemblerMIPS64Test, Sltu) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Sltu, "sltu ${reg1}, ${reg2}, ${reg3}"), "sltu"); -} - -TEST_F(AssemblerMIPS64Test, Slti) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Slti, -16, "slti ${reg1}, ${reg2}, {imm}"), - "slti"); -} - -TEST_F(AssemblerMIPS64Test, Sltiu) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Sltiu, -16, "sltiu ${reg1}, ${reg2}, {imm}"), - "sltiu"); -} - -TEST_F(AssemblerMIPS64Test, Move) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Move, "or ${reg1}, ${reg2}, $zero"), "move"); -} - -TEST_F(AssemblerMIPS64Test, Clear) { - DriverStr(RepeatR(&mips64::Mips64Assembler::Clear, "or ${reg}, $zero, $zero"), "clear"); -} - -TEST_F(AssemblerMIPS64Test, Not) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Not, "nor ${reg1}, ${reg2}, $zero"), "not"); -} - -TEST_F(AssemblerMIPS64Test, Bitswap) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Bitswap, "bitswap ${reg1}, ${reg2}"), "bitswap"); -} - -TEST_F(AssemblerMIPS64Test, Dbitswap) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Dbitswap, "dbitswap ${reg1}, ${reg2}"), "dbitswap"); -} - -TEST_F(AssemblerMIPS64Test, Seb) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Seb, "seb ${reg1}, ${reg2}"), "seb"); -} - -TEST_F(AssemblerMIPS64Test, Seh) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Seh, "seh ${reg1}, ${reg2}"), "seh"); -} - -TEST_F(AssemblerMIPS64Test, Dsbh) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Dsbh, "dsbh ${reg1}, ${reg2}"), "dsbh"); -} - -TEST_F(AssemblerMIPS64Test, Dshd) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Dshd, "dshd ${reg1}, ${reg2}"), "dshd"); -} - -TEST_F(AssemblerMIPS64Test, Dext) { - std::vector<mips64::GpuRegister*> reg1_registers = GetRegisters(); - std::vector<mips64::GpuRegister*> 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, Ins) { - std::vector<mips64::GpuRegister*> regs = GetRegisters(); - WarnOnCombinations(regs.size() * regs.size() * 33 * 16); - std::string expected; - for (mips64::GpuRegister* reg1 : regs) { - for (mips64::GpuRegister* reg2 : regs) { - for (int32_t pos = 0; pos < 32; pos++) { - for (int32_t size = 1; pos + size <= 32; size++) { - __ Ins(*reg1, *reg2, pos, size); - std::ostringstream instr; - instr << "ins $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n"; - expected += instr.str(); - } - } - } - } - DriverStr(expected, "Ins"); -} - -TEST_F(AssemblerMIPS64Test, DblIns) { - std::vector<mips64::GpuRegister*> reg1_registers = GetRegisters(); - std::vector<mips64::GpuRegister*> reg2_registers = GetRegisters(); - WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 65 * 32); - std::ostringstream expected; - for (mips64::GpuRegister* reg1 : reg1_registers) { - for (mips64::GpuRegister* reg2 : reg2_registers) { - for (int32_t pos = 0; pos < 64; pos++) { - for (int32_t size = 1; pos + size <= 64; size++) { - __ DblIns(*reg1, *reg2, pos, size); - expected << "dins $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n"; - } - } - } - } - - DriverStr(expected.str(), "DblIns"); -} - -TEST_F(AssemblerMIPS64Test, Lsa) { - DriverStr(RepeatRRRIb(&mips64::Mips64Assembler::Lsa, - 2, - "lsa ${reg1}, ${reg2}, ${reg3}, {imm}", - 1), - "lsa"); -} - -TEST_F(AssemblerMIPS64Test, Dlsa) { - DriverStr(RepeatRRRIb(&mips64::Mips64Assembler::Dlsa, - 2, - "dlsa ${reg1}, ${reg2}, ${reg3}, {imm}", - 1), - "dlsa"); -} - -TEST_F(AssemblerMIPS64Test, Wsbh) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Wsbh, "wsbh ${reg1}, ${reg2}"), "wsbh"); -} - -TEST_F(AssemblerMIPS64Test, Sll) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Sll, 5, "sll ${reg1}, ${reg2}, {imm}"), "sll"); -} - -TEST_F(AssemblerMIPS64Test, Srl) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Srl, 5, "srl ${reg1}, ${reg2}, {imm}"), "srl"); -} - -TEST_F(AssemblerMIPS64Test, Rotr) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Rotr, 5, "rotr ${reg1}, ${reg2}, {imm}"), "rotr"); -} - -TEST_F(AssemblerMIPS64Test, Sra) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Sra, 5, "sra ${reg1}, ${reg2}, {imm}"), "sra"); -} - -TEST_F(AssemblerMIPS64Test, Sllv) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Sllv, "sllv ${reg1}, ${reg2}, ${reg3}"), "sllv"); -} - -TEST_F(AssemblerMIPS64Test, Srlv) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Srlv, "srlv ${reg1}, ${reg2}, ${reg3}"), "srlv"); -} - -TEST_F(AssemblerMIPS64Test, Rotrv) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Rotrv, "rotrv ${reg1}, ${reg2}, ${reg3}"), "rotrv"); -} - -TEST_F(AssemblerMIPS64Test, Srav) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Srav, "srav ${reg1}, ${reg2}, ${reg3}"), "srav"); -} - -TEST_F(AssemblerMIPS64Test, Dsll) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Dsll, 5, "dsll ${reg1}, ${reg2}, {imm}"), "dsll"); -} - -TEST_F(AssemblerMIPS64Test, Dsrl) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Dsrl, 5, "dsrl ${reg1}, ${reg2}, {imm}"), "dsrl"); -} - -TEST_F(AssemblerMIPS64Test, Drotr) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Drotr, 5, "drotr ${reg1}, ${reg2}, {imm}"), - "drotr"); -} - -TEST_F(AssemblerMIPS64Test, Dsra) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Dsra, 5, "dsra ${reg1}, ${reg2}, {imm}"), "dsra"); -} - -TEST_F(AssemblerMIPS64Test, Dsll32) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Dsll32, 5, "dsll32 ${reg1}, ${reg2}, {imm}"), - "dsll32"); -} - -TEST_F(AssemblerMIPS64Test, Dsrl32) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Dsrl32, 5, "dsrl32 ${reg1}, ${reg2}, {imm}"), - "dsrl32"); -} - -TEST_F(AssemblerMIPS64Test, Drotr32) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Drotr32, 5, "drotr32 ${reg1}, ${reg2}, {imm}"), - "drotr32"); -} - -TEST_F(AssemblerMIPS64Test, Dsra32) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Dsra32, 5, "dsra32 ${reg1}, ${reg2}, {imm}"), - "dsra32"); -} - -TEST_F(AssemblerMIPS64Test, Dsllv) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Dsllv, "dsllv ${reg1}, ${reg2}, ${reg3}"), "dsllv"); -} - -TEST_F(AssemblerMIPS64Test, Dsrlv) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Dsrlv, "dsrlv ${reg1}, ${reg2}, ${reg3}"), "dsrlv"); -} - -TEST_F(AssemblerMIPS64Test, Dsrav) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Dsrav, "dsrav ${reg1}, ${reg2}, ${reg3}"), "dsrav"); -} - -TEST_F(AssemblerMIPS64Test, Sc) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Sc, -9, "sc ${reg1}, {imm}(${reg2})"), "sc"); -} - -TEST_F(AssemblerMIPS64Test, Scd) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Scd, -9, "scd ${reg1}, {imm}(${reg2})"), "scd"); -} - -TEST_F(AssemblerMIPS64Test, Ll) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Ll, -9, "ll ${reg1}, {imm}(${reg2})"), "ll"); -} - -TEST_F(AssemblerMIPS64Test, Lld) { - DriverStr(RepeatRRIb(&mips64::Mips64Assembler::Lld, -9, "lld ${reg1}, {imm}(${reg2})"), "lld"); -} - -TEST_F(AssemblerMIPS64Test, Seleqz) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Seleqz, "seleqz ${reg1}, ${reg2}, ${reg3}"), - "seleqz"); -} - -TEST_F(AssemblerMIPS64Test, Selnez) { - DriverStr(RepeatRRR(&mips64::Mips64Assembler::Selnez, "selnez ${reg1}, ${reg2}, ${reg3}"), - "selnez"); -} - -TEST_F(AssemblerMIPS64Test, Clz) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Clz, "clz ${reg1}, ${reg2}"), "clz"); -} - -TEST_F(AssemblerMIPS64Test, Clo) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Clo, "clo ${reg1}, ${reg2}"), "clo"); -} - -TEST_F(AssemblerMIPS64Test, Dclz) { - DriverStr(RepeatRR(&mips64::Mips64Assembler::Dclz, "dclz ${reg1}, ${reg2}"), "dclz"); -} - -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::kLoadSignedByte, mips64::A0, mips64::A1, 0x7FFFFFFE); - __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x7FFFFFFF); - __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x80000000); - __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x80000001); - - __ 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::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x7FFFFFFE); - __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x7FFFFFFF); - __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x80000000); - __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x80000001); - - __ 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::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x7FFFFFFC); - __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x7FFFFFFE); - __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x80000000); - __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x80000002); - - __ 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::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x7FFFFFFC); - __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x7FFFFFFE); - __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x80000000); - __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x80000002); - - __ 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::kLoadWord, mips64::A0, mips64::A1, 0x7FFFFFF8); - __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x7FFFFFFC); - __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x80000000); - __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x80000004); - - __ 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::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x7FFFFFF8); - __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x7FFFFFFC); - __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x80000000); - __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x80000004); - - __ 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, 0x27FFC); - __ 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); - __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x7FFFFFF8); - __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x7FFFFFFC); - __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x80000000); - __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x80000004); - - 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" - "daddiu $at, $a1, 0x7FF8\n" - "lb $a0, 8($at)\n" - "daddiu $at, $a1, 32760\n" - "lb $a0, 9($at)\n" - "daui $at, $a1, 1\n" - "lb $a0, 0($at)\n" - "daui $at, $a1, 0x1234\n" - "lb $a0, 0x5678($at)\n" - "lb $a0, -256($a1)\n" - "lb $a0, -32768($a1)\n" - "daui $at, $a1, 0xABCE\n" - "lb $a0, -4352($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lb $a0, -2($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lb $a0, -1($at)\n" - "daui $at, $a1, 32768\n" - "lb $a0, 0($at)\n" - "daui $at, $a1, 32768\n" - "lb $a0, 1($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" - "daddiu $at, $a1, 0x7FF8\n" - "lbu $a0, 8($at)\n" - "daddiu $at, $a1, 32760\n" - "lbu $a0, 9($at)\n" - "daui $at, $a1, 1\n" - "lbu $a0, 0($at)\n" - "daui $at, $a1, 0x1234\n" - "lbu $a0, 0x5678($at)\n" - "lbu $a0, -256($a1)\n" - "lbu $a0, -32768($a1)\n" - "daui $at, $a1, 0xABCE\n" - "lbu $a0, -4352($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lbu $a0, -2($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lbu $a0, -1($at)\n" - "daui $at, $a1, 32768\n" - "lbu $a0, 0($at)\n" - "daui $at, $a1, 32768\n" - "lbu $a0, 1($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" - "daddiu $at, $a1, 0x7FF8\n" - "lh $a0, 8($at)\n" - "daddiu $at, $a1, 32760\n" - "lh $a0, 10($at)\n" - "daui $at, $a1, 1\n" - "lh $a0, 0($at)\n" - "daui $at, $a1, 0x1234\n" - "lh $a0, 0x5678($at)\n" - "lh $a0, -256($a1)\n" - "lh $a0, -32768($a1)\n" - "daui $at, $a1, 0xABCE\n" - "lh $a0, -4352($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lh $a0, -4($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lh $a0, -2($at)\n" - "daui $at, $a1, 32768\n" - "lh $a0, 0($at)\n" - "daui $at, $a1, 32768\n" - "lh $a0, 2($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" - "daddiu $at, $a1, 0x7FF8\n" - "lhu $a0, 8($at)\n" - "daddiu $at, $a1, 32760\n" - "lhu $a0, 10($at)\n" - "daui $at, $a1, 1\n" - "lhu $a0, 0($at)\n" - "daui $at, $a1, 0x1234\n" - "lhu $a0, 0x5678($at)\n" - "lhu $a0, -256($a1)\n" - "lhu $a0, -32768($a1)\n" - "daui $at, $a1, 0xABCE\n" - "lhu $a0, -4352($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lhu $a0, -4($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lhu $a0, -2($at)\n" - "daui $at, $a1, 32768\n" - "lhu $a0, 0($at)\n" - "daui $at, $a1, 32768\n" - "lhu $a0, 2($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" - "daddiu $at, $a1, 0x7FF8\n" - "lw $a0, 8($at)\n" - "daddiu $at, $a1, 32760\n" - "lw $a0, 12($at)\n" - "daui $at, $a1, 1\n" - "lw $a0, 0($at)\n" - "daui $at, $a1, 0x1234\n" - "lw $a0, 0x5678($at)\n" - "lw $a0, -256($a1)\n" - "lw $a0, -32768($a1)\n" - "daui $at, $a1, 0xABCE\n" - "lw $a0, -4352($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lw $a0, -8($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lw $a0, -4($at)\n" - "daui $at, $a1, 32768\n" - "lw $a0, 0($at)\n" - "daui $at, $a1, 32768\n" - "lw $a0, 4($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" - "daddiu $at, $a1, 0x7FF8\n" - "lwu $a0, 8($at)\n" - "daddiu $at, $a1, 32760\n" - "lwu $a0, 12($at)\n" - "daui $at, $a1, 1\n" - "lwu $a0, 0($at)\n" - "daui $at, $a1, 0x1234\n" - "lwu $a0, 0x5678($at)\n" - "lwu $a0, -256($a1)\n" - "lwu $a0, -32768($a1)\n" - "daui $at, $a1, 0xABCE\n" - "lwu $a0, -4352($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lwu $a0, -8($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lwu $a0, -4($at)\n" - "daui $at, $a1, 32768\n" - "lwu $a0, 0($at)\n" - "daui $at, $a1, 32768\n" - "lwu $a0, 4($at)\n" - - "ld $a0, 0($a0)\n" - "ld $a0, 0($a1)\n" - "lwu $a0, 4($a1)\n" - "lwu $t3, 8($a1)\n" - "dinsu $a0, $t3, 32, 32\n" - "ld $a0, 256($a1)\n" - "ld $a0, 1000($a1)\n" - "daddiu $at, $a1, 32760\n" - "lwu $a0, 4($at)\n" - "lwu $t3, 8($at)\n" - "dinsu $a0, $t3, 32, 32\n" - "daddiu $at, $a1, 32760\n" - "ld $a0, 8($at)\n" - "daddiu $at, $a1, 32760\n" - "lwu $a0, 12($at)\n" - "lwu $t3, 16($at)\n" - "dinsu $a0, $t3, 32, 32\n" - "daui $at, $a1, 1\n" - "ld $a0, 0($at)\n" - "daui $at, $a1, 2\n" - "daddiu $at, $at, 8\n" - "lwu $a0, 0x7ff4($at)\n" - "lwu $t3, 0x7ff8($at)\n" - "dinsu $a0, $t3, 32, 32\n" - "daui $at, $a1, 0x1234\n" - "ld $a0, 0x5678($at)\n" - "ld $a0, -256($a1)\n" - "ld $a0, -32768($a1)\n" - "daui $at, $a1, 0xABCE\n" - "ld $a0, -4352($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "ld $a0, -8($at)\n" - "daui $at, $a1, 32768\n" - "dahi $at, $at, 1\n" - "lwu $a0, -4($at)\n" - "lwu $t3, 0($at)\n" - "dinsu $a0, $t3, 32, 32\n" - "daui $at, $a1, 32768\n" - "ld $a0, 0($at)\n" - "daui $at, $a1, 32768\n" - "lwu $a0, 4($at)\n" - "lwu $t3, 8($at)\n" - "dinsu $a0, $t3, 32, 32\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); - - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 0); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 1); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 2); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 4); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 8); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 511); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 512); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 513); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 514); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 516); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 1022); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 1024); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 1025); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 1026); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 1028); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 2044); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 2048); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 2049); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 2050); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 2052); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 4088); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 4096); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 4097); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 4098); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 4100); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 4104); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 0x7FFC); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 0x8000); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 0x10000); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 0x12345678); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 0x12350078); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -256); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -511); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -513); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -1022); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -1026); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -2044); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -2052); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -4096); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -4104); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, -32768); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 0xABCDEF00); - __ LoadFpuFromOffset(mips64::kLoadQuadword, mips64::F0, mips64::A0, 0x7FFFABCD); - - const char* expected = - "lwc1 $f0, 0($a0)\n" - "lwc1 $f0, 4($a0)\n" - "lwc1 $f0, 256($a0)\n" - "lwc1 $f0, 0x7FFC($a0)\n" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "lwc1 $f0, 8($at)\n" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "lwc1 $f0, 12($at)\n" - "daui $at, $a0, 1\n" - "lwc1 $f0, 0($at)\n" - "daui $at, $a0, 4660 # 0x1234\n" - "lwc1 $f0, 22136($at) # 0x5678\n" - "lwc1 $f0, -256($a0)\n" - "lwc1 $f0, -32768($a0)\n" - "daui $at, $a0, 0xABCE\n" - "lwc1 $f0, -0x1100($at) # 0xEF00\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" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "lwc1 $f0, 4($at)\n" - "lw $t3, 8($at)\n" - "mthc1 $t3, $f0\n" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "ldc1 $f0, 8($at)\n" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "lwc1 $f0, 12($at)\n" - "lw $t3, 16($at)\n" - "mthc1 $t3, $f0\n" - "daui $at, $a0, 1\n" - "ldc1 $f0, 0($at)\n" - "daui $at, $a0, 4660 # 0x1234\n" - "ldc1 $f0, 22136($at) # 0x5678\n" - "ldc1 $f0, -256($a0)\n" - "ldc1 $f0, -32768($a0)\n" - "daui $at, $a0, 0xABCE\n" - "ldc1 $f0, -0x1100($at) # 0xEF00\n" - - "ld.d $w0, 0($a0)\n" - "ld.b $w0, 1($a0)\n" - "ld.h $w0, 2($a0)\n" - "ld.w $w0, 4($a0)\n" - "ld.d $w0, 8($a0)\n" - "ld.b $w0, 511($a0)\n" - "ld.d $w0, 512($a0)\n" - "daddiu $at, $a0, 513\n" - "ld.b $w0, 0($at)\n" - "ld.h $w0, 514($a0)\n" - "ld.w $w0, 516($a0)\n" - "ld.h $w0, 1022($a0)\n" - "ld.d $w0, 1024($a0)\n" - "daddiu $at, $a0, 1025\n" - "ld.b $w0, 0($at)\n" - "daddiu $at, $a0, 1026\n" - "ld.h $w0, 0($at)\n" - "ld.w $w0, 1028($a0)\n" - "ld.w $w0, 2044($a0)\n" - "ld.d $w0, 2048($a0)\n" - "daddiu $at, $a0, 2049\n" - "ld.b $w0, 0($at)\n" - "daddiu $at, $a0, 2050\n" - "ld.h $w0, 0($at)\n" - "daddiu $at, $a0, 2052\n" - "ld.w $w0, 0($at)\n" - "ld.d $w0, 4088($a0)\n" - "daddiu $at, $a0, 4096\n" - "ld.d $w0, 0($at)\n" - "daddiu $at, $a0, 4097\n" - "ld.b $w0, 0($at)\n" - "daddiu $at, $a0, 4098\n" - "ld.h $w0, 0($at)\n" - "daddiu $at, $a0, 4100\n" - "ld.w $w0, 0($at)\n" - "daddiu $at, $a0, 4104\n" - "ld.d $w0, 0($at)\n" - "daddiu $at, $a0, 0x7FFC\n" - "ld.w $w0, 0($at)\n" - "daddiu $at, $a0, 0x7FF8\n" - "ld.d $w0, 8($at)\n" - "daui $at, $a0, 0x1\n" - "ld.d $w0, 0($at)\n" - "daui $at, $a0, 0x1234\n" - "daddiu $at, $at, 0x6000\n" - "ld.d $w0, -2440($at) # 0xF678\n" - "daui $at, $a0, 0x1235\n" - "ld.d $w0, 0x78($at)\n" - "ld.d $w0, -256($a0)\n" - "ld.b $w0, -511($a0)\n" - "daddiu $at, $a0, -513\n" - "ld.b $w0, 0($at)\n" - "ld.h $w0, -1022($a0)\n" - "daddiu $at, $a0, -1026\n" - "ld.h $w0, 0($at)\n" - "ld.w $w0, -2044($a0)\n" - "daddiu $at, $a0, -2052\n" - "ld.w $w0, 0($at)\n" - "ld.d $w0, -4096($a0)\n" - "daddiu $at, $a0, -4104\n" - "ld.d $w0, 0($at)\n" - "daddiu $at, $a0, -32768\n" - "ld.d $w0, 0($at)\n" - "daui $at, $a0, 0xABCE\n" - "daddiu $at, $at, -8192 # 0xE000\n" - "ld.d $w0, 0xF00($at)\n" - "daui $at, $a0, 0x8000\n" - "dahi $at, $at, 1\n" - "daddiu $at, $at, -21504 # 0xAC00\n" - "ld.b $w0, -51($at) # 0xFFCD\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); - __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x7FFFFFF8); - __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x7FFFFFFC); - __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x80000000); - __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x80000004); - - 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" - "daddiu $at, $a1, 0x7FF8\n" - "sb $a0, 8($at)\n" - "daddiu $at, $a1, 0x7FF8\n" - "sb $a0, 9($at)\n" - "daui $at, $a1, 1\n" - "sb $a0, 0($at)\n" - "daui $at, $a1, 4660 # 0x1234\n" - "sb $a0, 22136($at) # 0x5678\n" - "sb $a0, -256($a1)\n" - "sb $a0, -32768($a1)\n" - "daui $at, $a1, 43982 # 0xABCE\n" - "sb $a0, -4352($at) # 0xEF00\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" - "daddiu $at, $a1, 0x7FF8\n" - "sh $a0, 8($at)\n" - "daddiu $at, $a1, 0x7FF8\n" - "sh $a0, 10($at)\n" - "daui $at, $a1, 1\n" - "sh $a0, 0($at)\n" - "daui $at, $a1, 4660 # 0x1234\n" - "sh $a0, 22136($at) # 0x5678\n" - "sh $a0, -256($a1)\n" - "sh $a0, -32768($a1)\n" - "daui $at, $a1, 43982 # 0xABCE\n" - "sh $a0, -4352($at) # 0xEF00\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" - "daddiu $at, $a1, 0x7FF8\n" - "sw $a0, 8($at)\n" - "daddiu $at, $a1, 0x7FF8\n" - "sw $a0, 12($at)\n" - "daui $at, $a1, 1\n" - "sw $a0, 0($at)\n" - "daui $at, $a1, 4660 # 0x1234\n" - "sw $a0, 22136($at) # 0x5678\n" - "sw $a0, -256($a1)\n" - "sw $a0, -32768($a1)\n" - "daui $at, $a1, 43982 # 0xABCE\n" - "sw $a0, -4352($at) # 0xEF00\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" - "daddiu $at, $a1, 0x7FF8\n" - "sw $a0, 4($at)\n" - "dsrl32 $t3, $a0, 0\n" - "sw $t3, 8($at)\n" - "daddiu $at, $a1, 32760 # 0x7FF8\n" - "sd $a0, 8($at)\n" - "daddiu $at, $a1, 32760 # 0x7FF8\n" - "sw $a0, 12($at)\n" - "dsrl32 $t3, $a0, 0\n" - "sw $t3, 16($at)\n" - "daui $at, $a1, 1\n" - "sd $a0, 0($at)\n" - "daui $at, $a1, 4660 # 0x1234\n" - "sd $a0, 22136($at) # 0x5678\n" - "sd $a0, -256($a1)\n" - "sd $a0, -32768($a1)\n" - "daui $at, $a1, 0xABCE\n" - "sd $a0, -0x1100($at)\n" - "daui $at, $a1, 0x8000\n" - "dahi $at, $at, 1\n" - "sd $a0, -8($at)\n" - "daui $at, $a1, 0x8000\n" - "dahi $at, $at, 1\n" - "sw $a0, -4($at) # 0xFFFC\n" - "dsrl32 $t3, $a0, 0\n" - "sw $t3, 0($at) # 0x0\n" - "daui $at, $a1, 0x8000\n" - "sd $a0, 0($at) # 0x0\n" - "daui $at, $a1, 0x8000\n" - "sw $a0, 4($at) # 0x4\n" - "dsrl32 $t3, $a0, 0\n" - "sw $t3, 8($at) # 0x8\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); - - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 0); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 1); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 2); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 4); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 8); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 511); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 512); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 513); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 514); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 516); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 1022); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 1024); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 1025); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 1026); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 1028); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 2044); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 2048); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 2049); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 2050); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 2052); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 4088); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 4096); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 4097); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 4098); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 4100); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 4104); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 0x7FFC); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 0x8000); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 0x10000); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 0x12345678); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 0x12350078); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -256); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -511); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -513); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -1022); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -1026); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -2044); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -2052); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -4096); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -4104); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, -32768); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 0xABCDEF00); - __ StoreFpuToOffset(mips64::kStoreQuadword, mips64::F0, mips64::A0, 0x7FFFABCD); - - const char* expected = - "swc1 $f0, 0($a0)\n" - "swc1 $f0, 4($a0)\n" - "swc1 $f0, 256($a0)\n" - "swc1 $f0, 0x7FFC($a0)\n" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "swc1 $f0, 8($at)\n" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "swc1 $f0, 12($at)\n" - "daui $at, $a0, 1\n" - "swc1 $f0, 0($at)\n" - "daui $at, $a0, 4660 # 0x1234\n" - "swc1 $f0, 22136($at) # 0x5678\n" - "swc1 $f0, -256($a0)\n" - "swc1 $f0, -32768($a0)\n" - "daui $at, $a0, 0xABCE\n" - "swc1 $f0, -0x1100($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" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "mfhc1 $t3, $f0\n" - "swc1 $f0, 4($at)\n" - "sw $t3, 8($at)\n" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "sdc1 $f0, 8($at)\n" - "daddiu $at, $a0, 32760 # 0x7FF8\n" - "mfhc1 $t3, $f0\n" - "swc1 $f0, 12($at)\n" - "sw $t3, 16($at)\n" - "daui $at, $a0, 1\n" - "sdc1 $f0, 0($at)\n" - "daui $at, $a0, 4660 # 0x1234\n" - "sdc1 $f0, 22136($at) # 0x5678\n" - "sdc1 $f0, -256($a0)\n" - "sdc1 $f0, -32768($a0)\n" - "daui $at, $a0, 0xABCE\n" - "sdc1 $f0, -0x1100($at)\n" - - "st.d $w0, 0($a0)\n" - "st.b $w0, 1($a0)\n" - "st.h $w0, 2($a0)\n" - "st.w $w0, 4($a0)\n" - "st.d $w0, 8($a0)\n" - "st.b $w0, 511($a0)\n" - "st.d $w0, 512($a0)\n" - "daddiu $at, $a0, 513\n" - "st.b $w0, 0($at)\n" - "st.h $w0, 514($a0)\n" - "st.w $w0, 516($a0)\n" - "st.h $w0, 1022($a0)\n" - "st.d $w0, 1024($a0)\n" - "daddiu $at, $a0, 1025\n" - "st.b $w0, 0($at)\n" - "daddiu $at, $a0, 1026\n" - "st.h $w0, 0($at)\n" - "st.w $w0, 1028($a0)\n" - "st.w $w0, 2044($a0)\n" - "st.d $w0, 2048($a0)\n" - "daddiu $at, $a0, 2049\n" - "st.b $w0, 0($at)\n" - "daddiu $at, $a0, 2050\n" - "st.h $w0, 0($at)\n" - "daddiu $at, $a0, 2052\n" - "st.w $w0, 0($at)\n" - "st.d $w0, 4088($a0)\n" - "daddiu $at, $a0, 4096\n" - "st.d $w0, 0($at)\n" - "daddiu $at, $a0, 4097\n" - "st.b $w0, 0($at)\n" - "daddiu $at, $a0, 4098\n" - "st.h $w0, 0($at)\n" - "daddiu $at, $a0, 4100\n" - "st.w $w0, 0($at)\n" - "daddiu $at, $a0, 4104\n" - "st.d $w0, 0($at)\n" - "daddiu $at, $a0, 0x7FFC\n" - "st.w $w0, 0($at)\n" - "daddiu $at, $a0, 0x7FF8\n" - "st.d $w0, 8($at)\n" - "daui $at, $a0, 0x1\n" - "st.d $w0, 0($at)\n" - "daui $at, $a0, 0x1234\n" - "daddiu $at, $at, 0x6000\n" - "st.d $w0, -2440($at) # 0xF678\n" - "daui $at, $a0, 0x1235\n" - "st.d $w0, 0x78($at)\n" - "st.d $w0, -256($a0)\n" - "st.b $w0, -511($a0)\n" - "daddiu $at, $a0, -513\n" - "st.b $w0, 0($at)\n" - "st.h $w0, -1022($a0)\n" - "daddiu $at, $a0, -1026\n" - "st.h $w0, 0($at)\n" - "st.w $w0, -2044($a0)\n" - "daddiu $at, $a0, -2052\n" - "st.w $w0, 0($at)\n" - "st.d $w0, -4096($a0)\n" - "daddiu $at, $a0, -4104\n" - "st.d $w0, 0($at)\n" - "daddiu $at, $a0, -32768\n" - "st.d $w0, 0($at)\n" - "daui $at, $a0, 0xABCE\n" - "daddiu $at, $at, -8192 # 0xE000\n" - "st.d $w0, 0xF00($at)\n" - "daui $at, $a0, 0x8000\n" - "dahi $at, $at, 1\n" - "daddiu $at, $at, -21504 # 0xAC00\n" - "st.b $w0, -51($at) # 0xFFCD\n"; - DriverStr(expected, "StoreFpuToOffset"); -} - -TEST_F(AssemblerMIPS64Test, StoreConstToOffset) { - __ StoreConstToOffset(mips64::kStoreByte, 0xFF, mips64::A1, +0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreHalfword, 0xFFFF, mips64::A1, +0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreWord, 0x12345678, mips64::A1, +0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreDoubleword, 0x123456789ABCDEF0, mips64::A1, +0, mips64::T8); - - __ StoreConstToOffset(mips64::kStoreByte, 0, mips64::A1, +0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreHalfword, 0, mips64::A1, +0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreWord, 0, mips64::A1, +0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreDoubleword, 0, mips64::A1, +0, mips64::T8); - - __ StoreConstToOffset(mips64::kStoreDoubleword, 0x1234567812345678, mips64::A1, +0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreDoubleword, 0x1234567800000000, mips64::A1, +0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreDoubleword, 0x0000000012345678, mips64::A1, +0, mips64::T8); - - __ StoreConstToOffset(mips64::kStoreWord, 0, mips64::T8, +0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreWord, 0x12345678, mips64::T8, +0, mips64::T8); - - __ StoreConstToOffset(mips64::kStoreWord, 0, mips64::A1, -0xFFF0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreWord, 0x12345678, mips64::A1, +0xFFF0, mips64::T8); - - __ StoreConstToOffset(mips64::kStoreWord, 0, mips64::T8, -0xFFF0, mips64::T8); - __ StoreConstToOffset(mips64::kStoreWord, 0x12345678, mips64::T8, +0xFFF0, mips64::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" - "dahi $t8, $t8, 0x5679\n" - "dati $t8, $t8, 0x1234\n" - "sd $t8, 0($a1)\n" - "sb $zero, 0($a1)\n" - "sh $zero, 0($a1)\n" - "sw $zero, 0($a1)\n" - "sd $zero, 0($a1)\n" - "lui $t8, 0x1234\n" - "ori $t8, $t8,0x5678\n" - "dins $t8, $t8, 0x20, 0x20\n" - "sd $t8, 0($a1)\n" - "lui $t8, 0x246\n" - "ori $t8, $t8, 0x8acf\n" - "dsll32 $t8, $t8, 0x3\n" - "sd $t8, 0($a1)\n" - "lui $t8, 0x1234\n" - "ori $t8, $t8, 0x5678\n" - "sd $t8, 0($a1)\n" - "sw $zero, 0($t8)\n" - "lui $at,0x1234\n" - "ori $at, $at, 0x5678\n" - "sw $at, 0($t8)\n" - "daddiu $at, $a1, -32760 # 0x8008\n" - "sw $zero, -32760($at) # 0x8008\n" - "daddiu $at, $a1, 32760 # 0x7FF8\n" - "lui $t8, 4660 # 0x1234\n" - "ori $t8, $t8, 22136 # 0x5678\n" - "sw $t8, 32760($at) # 0x7FF8\n" - "daddiu $at, $t8, -32760 # 0x8008\n" - "sw $zero, -32760($at) # 0x8008\n" - "daddiu $at, $t8, 32760 # 0x7FF8\n" - "lui $t8, 4660 # 0x1234\n" - "ori $t8, $t8, 22136 # 0x5678\n" - "sw $t8, 32760($at) # 0x7FF8\n"; - DriverStr(expected, "StoreConstToOffset"); -} -////////////////////////////// -// Loading/adding Constants // -////////////////////////////// - -TEST_F(AssemblerMIPS64Test, LoadConst32) { - // IsUint<16>(value) - __ LoadConst32(mips64::V0, 0); - __ LoadConst32(mips64::V0, 65535); - // IsInt<16>(value) - __ LoadConst32(mips64::V0, -1); - __ LoadConst32(mips64::V0, -32768); - // Everything else - __ LoadConst32(mips64::V0, 65536); - __ LoadConst32(mips64::V0, 65537); - __ LoadConst32(mips64::V0, 2147483647); - __ LoadConst32(mips64::V0, -32769); - __ LoadConst32(mips64::V0, -65536); - __ LoadConst32(mips64::V0, -65537); - __ LoadConst32(mips64::V0, -2147483647); - __ LoadConst32(mips64::V0, -2147483648); - - const char* expected = - // IsUint<16>(value) - "ori $v0, $zero, 0\n" // __ LoadConst32(mips64::V0, 0); - "ori $v0, $zero, 65535\n" // __ LoadConst32(mips64::V0, 65535); - // IsInt<16>(value) - "addiu $v0, $zero, -1\n" // __ LoadConst32(mips64::V0, -1); - "addiu $v0, $zero, -32768\n" // __ LoadConst32(mips64::V0, -32768); - // Everything else - "lui $v0, 1\n" // __ LoadConst32(mips64::V0, 65536); - "lui $v0, 1\n" // __ LoadConst32(mips64::V0, 65537); - "ori $v0, 1\n" // " - "lui $v0, 32767\n" // __ LoadConst32(mips64::V0, 2147483647); - "ori $v0, 65535\n" // " - "lui $v0, 65535\n" // __ LoadConst32(mips64::V0, -32769); - "ori $v0, 32767\n" // " - "lui $v0, 65535\n" // __ LoadConst32(mips64::V0, -65536); - "lui $v0, 65534\n" // __ LoadConst32(mips64::V0, -65537); - "ori $v0, 65535\n" // " - "lui $v0, 32768\n" // __ LoadConst32(mips64::V0, -2147483647); - "ori $v0, 1\n" // " - "lui $v0, 32768\n"; // __ LoadConst32(mips64::V0, -2147483648); - DriverStr(expected, "LoadConst32"); -} - -TEST_F(AssemblerMIPS64Test, Addiu32) { - __ Addiu32(mips64::A1, mips64::A2, -0x8000); - __ Addiu32(mips64::A1, mips64::A2, +0); - __ Addiu32(mips64::A1, mips64::A2, +0x7FFF); - __ Addiu32(mips64::A1, mips64::A2, -0x8001); - __ Addiu32(mips64::A1, mips64::A2, +0x8000); - __ Addiu32(mips64::A1, mips64::A2, -0x10000); - __ Addiu32(mips64::A1, mips64::A2, +0x10000); - __ Addiu32(mips64::A1, mips64::A2, +0x12345678); - - const char* expected = - "addiu $a1, $a2, -0x8000\n" - "addiu $a1, $a2, 0\n" - "addiu $a1, $a2, 0x7FFF\n" - "aui $a1, $a2, 0xFFFF\n" - "addiu $a1, $a1, 0x7FFF\n" - "aui $a1, $a2, 1\n" - "addiu $a1, $a1, -0x8000\n" - "aui $a1, $a2, 0xFFFF\n" - "aui $a1, $a2, 1\n" - "aui $a1, $a2, 0x1234\n" - "addiu $a1, $a1, 0x5678\n"; - DriverStr(expected, "Addiu32"); -} - -static uint64_t SignExtend16To64(uint16_t n) { - return static_cast<int16_t>(n); -} - -// The art::mips64::Mips64Assembler::LoadConst64() method uses a template -// to minimize the number of instructions needed to load a 64-bit constant -// value into a register. The template calls various methods which emit -// MIPS machine instructions. This struct (class) uses the same template -// but overrides the definitions of the methods which emit MIPS instructions -// to use methods which simulate the operation of the corresponding MIPS -// instructions. After invoking LoadConst64() the target register should -// contain the same 64-bit value as was input to LoadConst64(). If the -// simulated register doesn't contain the correct value then there is probably -// an error in the template function. -struct LoadConst64Tester { - LoadConst64Tester() { - // Initialize all of the registers for simulation to zero. - for (int r = 0; r < 32; r++) { - regs_[r] = 0; - } - // Clear all of the path flags. - loadconst64_paths_ = art::mips64::kLoadConst64PathZero; - } - void Addiu(mips64::GpuRegister rd, mips64::GpuRegister rs, uint16_t c) { - regs_[rd] = static_cast<int32_t>(regs_[rs] + SignExtend16To64(c)); - } - void Daddiu(mips64::GpuRegister rd, mips64::GpuRegister rs, uint16_t c) { - regs_[rd] = regs_[rs] + SignExtend16To64(c); - } - void Dahi(mips64::GpuRegister rd, uint16_t c) { - regs_[rd] += SignExtend16To64(c) << 32; - } - void Dati(mips64::GpuRegister rd, uint16_t c) { - regs_[rd] += SignExtend16To64(c) << 48; - } - void Dinsu(mips64::GpuRegister rt, mips64::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; - uint64_t src_mask = (UINT64_C(1) << size) - 1; - uint64_t dsk_mask = ~(src_mask << pos); - - regs_[rt] = (regs_[rt] & dsk_mask) | ((regs_[rs] & src_mask) << pos); - } - void Dsll(mips64::GpuRegister rd, mips64::GpuRegister rt, int shamt) { - regs_[rd] = regs_[rt] << (shamt & 0x1f); - } - void Dsll32(mips64::GpuRegister rd, mips64::GpuRegister rt, int shamt) { - regs_[rd] = regs_[rt] << (32 + (shamt & 0x1f)); - } - void Dsrl(mips64::GpuRegister rd, mips64::GpuRegister rt, int shamt) { - regs_[rd] = regs_[rt] >> (shamt & 0x1f); - } - void Dsrl32(mips64::GpuRegister rd, mips64::GpuRegister rt, int shamt) { - regs_[rd] = regs_[rt] >> (32 + (shamt & 0x1f)); - } - void Lui(mips64::GpuRegister rd, uint16_t c) { - regs_[rd] = SignExtend16To64(c) << 16; - } - void Ori(mips64::GpuRegister rd, mips64::GpuRegister rs, uint16_t c) { - regs_[rd] = regs_[rs] | c; - } - void LoadConst32(mips64::GpuRegister rd, int32_t c) { - CHECK_NE(rd, 0); - mips64::TemplateLoadConst32<LoadConst64Tester>(this, rd, c); - CHECK_EQ(regs_[rd], static_cast<uint64_t>(c)); - } - void LoadConst64(mips64::GpuRegister rd, int64_t c) { - CHECK_NE(rd, 0); - mips64::TemplateLoadConst64<LoadConst64Tester>(this, rd, c); - CHECK_EQ(regs_[rd], static_cast<uint64_t>(c)); - } - uint64_t regs_[32]; - - // Getter function for loadconst64_paths_. - int GetPathsCovered() { - return loadconst64_paths_; - } - - void RecordLoadConst64Path(int value) { - loadconst64_paths_ |= value; - } - - private: - // This variable holds a bitmask to tell us which paths were taken - // through the template function which loads 64-bit values. - int loadconst64_paths_; -}; - -TEST_F(AssemblerMIPS64Test, LoadConst64) { - const uint16_t imms[] = { - 0, 1, 2, 3, 4, 0x33, 0x66, 0x55, 0x99, 0xaa, 0xcc, 0xff, 0x5500, 0x5555, - 0x7ffc, 0x7ffd, 0x7ffe, 0x7fff, 0x8000, 0x8001, 0x8002, 0x8003, 0x8004, - 0xaaaa, 0xfffc, 0xfffd, 0xfffe, 0xffff - }; - unsigned d0, d1, d2, d3; - LoadConst64Tester tester; - - union { - int64_t v64; - uint16_t v16[4]; - } u; - - for (d3 = 0; d3 < sizeof imms / sizeof imms[0]; d3++) { - u.v16[3] = imms[d3]; - - for (d2 = 0; d2 < sizeof imms / sizeof imms[0]; d2++) { - u.v16[2] = imms[d2]; - - for (d1 = 0; d1 < sizeof imms / sizeof imms[0]; d1++) { - u.v16[1] = imms[d1]; - - for (d0 = 0; d0 < sizeof imms / sizeof imms[0]; d0++) { - u.v16[0] = imms[d0]; - - tester.LoadConst64(mips64::V0, u.v64); - } - } - } - } - - // Verify that we tested all paths through the "load 64-bit value" - // function template. - EXPECT_EQ(tester.GetPathsCovered(), art::mips64::kLoadConst64PathAllPaths); -} - -TEST_F(AssemblerMIPS64Test, LoadFarthestNearLabelAddress) { - mips64::Mips64Label label; - __ LoadLabelAddress(mips64::V0, &label); - constexpr uint32_t kAdduCount = 0x3FFDE; - for (uint32_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - __ Bind(&label); - - std::string expected = - "lapc $v0, 1f\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "1:\n"; - DriverStr(expected, "LoadFarthestNearLabelAddress"); - EXPECT_EQ(__ GetLabelLocation(&label), (1 + kAdduCount) * 4); -} - -TEST_F(AssemblerMIPS64Test, LoadNearestFarLabelAddress) { - mips64::Mips64Label label; - __ LoadLabelAddress(mips64::V0, &label); - constexpr uint32_t kAdduCount = 0x3FFDF; - for (uint32_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - __ Bind(&label); - - std::string expected = - "1:\n" - "auipc $at, %hi(2f - 1b)\n" - "daddiu $v0, $at, %lo(2f - 1b)\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n"; - DriverStr(expected, "LoadNearestFarLabelAddress"); - EXPECT_EQ(__ GetLabelLocation(&label), (2 + kAdduCount) * 4); -} - -TEST_F(AssemblerMIPS64Test, LoadFarthestNearLiteral) { - mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ LoadLiteral(mips64::V0, mips64::kLoadWord, literal); - constexpr uint32_t kAdduCount = 0x3FFDE; - for (uint32_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - - std::string expected = - "lwpc $v0, 1f\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "1:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadFarthestNearLiteral"); - EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (1 + kAdduCount) * 4); -} - -TEST_F(AssemblerMIPS64Test, LoadNearestFarLiteral) { - mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ LoadLiteral(mips64::V0, mips64::kLoadWord, literal); - constexpr uint32_t kAdduCount = 0x3FFDF; - for (uint32_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - - std::string expected = - "1:\n" - "auipc $at, %hi(2f - 1b)\n" - "lw $v0, %lo(2f - 1b)($at)\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadNearestFarLiteral"); - EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (2 + kAdduCount) * 4); -} - -TEST_F(AssemblerMIPS64Test, LoadFarthestNearLiteralUnsigned) { - mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ LoadLiteral(mips64::V0, mips64::kLoadUnsignedWord, literal); - constexpr uint32_t kAdduCount = 0x3FFDE; - for (uint32_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - - std::string expected = - "lwupc $v0, 1f\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "1:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadFarthestNearLiteralUnsigned"); - EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (1 + kAdduCount) * 4); -} - -TEST_F(AssemblerMIPS64Test, LoadNearestFarLiteralUnsigned) { - mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678); - __ LoadLiteral(mips64::V0, mips64::kLoadUnsignedWord, literal); - constexpr uint32_t kAdduCount = 0x3FFDF; - for (uint32_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - - std::string expected = - "1:\n" - "auipc $at, %hi(2f - 1b)\n" - "lwu $v0, %lo(2f - 1b)($at)\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n" - ".word 0x12345678\n"; - DriverStr(expected, "LoadNearestFarLiteralUnsigned"); - EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (2 + kAdduCount) * 4); -} - -TEST_F(AssemblerMIPS64Test, LoadFarthestNearLiteralLong) { - mips64::Literal* literal = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF)); - __ LoadLiteral(mips64::V0, mips64::kLoadDoubleword, literal); - constexpr uint32_t kAdduCount = 0x3FFDD; - for (uint32_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - - std::string expected = - "ldpc $v0, 1f\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "1:\n" - ".dword 0x0123456789ABCDEF\n"; - DriverStr(expected, "LoadFarthestNearLiteralLong"); - EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (1 + kAdduCount) * 4); -} - -TEST_F(AssemblerMIPS64Test, LoadNearestFarLiteralLong) { - mips64::Literal* literal = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF)); - __ LoadLiteral(mips64::V0, mips64::kLoadDoubleword, literal); - constexpr uint32_t kAdduCount = 0x3FFDE; - for (uint32_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - - std::string expected = - "1:\n" - "auipc $at, %hi(2f - 1b)\n" - "ld $v0, %lo(2f - 1b)($at)\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "2:\n" - ".dword 0x0123456789ABCDEF\n"; - DriverStr(expected, "LoadNearestFarLiteralLong"); - EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (2 + kAdduCount) * 4); -} - -TEST_F(AssemblerMIPS64Test, LongLiteralAlignmentNop) { - mips64::Literal* literal1 = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF)); - mips64::Literal* literal2 = __ NewLiteral<uint64_t>(UINT64_C(0x5555555555555555)); - mips64::Literal* literal3 = __ NewLiteral<uint64_t>(UINT64_C(0xAAAAAAAAAAAAAAAA)); - __ LoadLiteral(mips64::A1, mips64::kLoadDoubleword, literal1); - __ LoadLiteral(mips64::A2, mips64::kLoadDoubleword, literal2); - __ LoadLiteral(mips64::A3, mips64::kLoadDoubleword, literal3); - __ LoadLabelAddress(mips64::V0, literal1->GetLabel()); - __ LoadLabelAddress(mips64::V1, literal2->GetLabel()); - // A nop will be inserted here before the 64-bit literals. - - std::string expected = - "ldpc $a1, 1f\n" - // The GNU assembler incorrectly requires the ldpc instruction to be located - // at an address that's a multiple of 8. TODO: Remove this workaround if/when - // the assembler is fixed. - // "ldpc $a2, 2f\n" - ".word 0xECD80004\n" - "ldpc $a3, 3f\n" - "lapc $v0, 1f\n" - "lapc $v1, 2f\n" - "nop\n" - "1:\n" - ".dword 0x0123456789ABCDEF\n" - "2:\n" - ".dword 0x5555555555555555\n" - "3:\n" - ".dword 0xAAAAAAAAAAAAAAAA\n"; - DriverStr(expected, "LongLiteralAlignmentNop"); - EXPECT_EQ(__ GetLabelLocation(literal1->GetLabel()), 6 * 4u); - EXPECT_EQ(__ GetLabelLocation(literal2->GetLabel()), 8 * 4u); - EXPECT_EQ(__ GetLabelLocation(literal3->GetLabel()), 10 * 4u); -} - -TEST_F(AssemblerMIPS64Test, LongLiteralAlignmentNoNop) { - mips64::Literal* literal1 = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF)); - mips64::Literal* literal2 = __ NewLiteral<uint64_t>(UINT64_C(0x5555555555555555)); - __ LoadLiteral(mips64::A1, mips64::kLoadDoubleword, literal1); - __ LoadLiteral(mips64::A2, mips64::kLoadDoubleword, literal2); - __ LoadLabelAddress(mips64::V0, literal1->GetLabel()); - __ LoadLabelAddress(mips64::V1, literal2->GetLabel()); - - std::string expected = - "ldpc $a1, 1f\n" - // The GNU assembler incorrectly requires the ldpc instruction to be located - // at an address that's a multiple of 8. TODO: Remove this workaround if/when - // the assembler is fixed. - // "ldpc $a2, 2f\n" - ".word 0xECD80003\n" - "lapc $v0, 1f\n" - "lapc $v1, 2f\n" - "1:\n" - ".dword 0x0123456789ABCDEF\n" - "2:\n" - ".dword 0x5555555555555555\n"; - DriverStr(expected, "LongLiteralAlignmentNoNop"); - EXPECT_EQ(__ GetLabelLocation(literal1->GetLabel()), 4 * 4u); - EXPECT_EQ(__ GetLabelLocation(literal2->GetLabel()), 6 * 4u); -} - -TEST_F(AssemblerMIPS64Test, FarLongLiteralAlignmentNop) { - mips64::Literal* literal = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF)); - __ LoadLiteral(mips64::V0, mips64::kLoadDoubleword, literal); - __ LoadLabelAddress(mips64::V1, literal->GetLabel()); - constexpr uint32_t kAdduCount = 0x3FFDF; - for (uint32_t i = 0; i != kAdduCount; ++i) { - __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO); - } - // A nop will be inserted here before the 64-bit literal. - - std::string expected = - "1:\n" - "auipc $at, %hi(3f - 1b)\n" - "ld $v0, %lo(3f - 1b)($at)\n" - "2:\n" - "auipc $at, %hi(3f - 2b)\n" - "daddiu $v1, $at, %lo(3f - 2b)\n" + - RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") + - "nop\n" - "3:\n" - ".dword 0x0123456789ABCDEF\n"; - DriverStr(expected, "FarLongLiteralAlignmentNop"); - EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (5 + kAdduCount) * 4); -} - -// MSA instructions. - -TEST_F(AssemblerMIPS64Test, AndV) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::AndV, "and.v ${reg1}, ${reg2}, ${reg3}"), "and.v"); -} - -TEST_F(AssemblerMIPS64Test, OrV) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::OrV, "or.v ${reg1}, ${reg2}, ${reg3}"), "or.v"); -} - -TEST_F(AssemblerMIPS64Test, NorV) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::NorV, "nor.v ${reg1}, ${reg2}, ${reg3}"), "nor.v"); -} - -TEST_F(AssemblerMIPS64Test, XorV) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::XorV, "xor.v ${reg1}, ${reg2}, ${reg3}"), "xor.v"); -} - -TEST_F(AssemblerMIPS64Test, AddvB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::AddvB, "addv.b ${reg1}, ${reg2}, ${reg3}"), - "addv.b"); -} - -TEST_F(AssemblerMIPS64Test, AddvH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::AddvH, "addv.h ${reg1}, ${reg2}, ${reg3}"), - "addv.h"); -} - -TEST_F(AssemblerMIPS64Test, AddvW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::AddvW, "addv.w ${reg1}, ${reg2}, ${reg3}"), - "addv.w"); -} - -TEST_F(AssemblerMIPS64Test, AddvD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::AddvD, "addv.d ${reg1}, ${reg2}, ${reg3}"), - "addv.d"); -} - -TEST_F(AssemblerMIPS64Test, SubvB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SubvB, "subv.b ${reg1}, ${reg2}, ${reg3}"), - "subv.b"); -} - -TEST_F(AssemblerMIPS64Test, SubvH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SubvH, "subv.h ${reg1}, ${reg2}, ${reg3}"), - "subv.h"); -} - -TEST_F(AssemblerMIPS64Test, SubvW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SubvW, "subv.w ${reg1}, ${reg2}, ${reg3}"), - "subv.w"); -} - -TEST_F(AssemblerMIPS64Test, SubvD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SubvD, "subv.d ${reg1}, ${reg2}, ${reg3}"), - "subv.d"); -} - -TEST_F(AssemblerMIPS64Test, Asub_sB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Asub_sB, "asub_s.b ${reg1}, ${reg2}, ${reg3}"), - "asub_s.b"); -} - -TEST_F(AssemblerMIPS64Test, Asub_sH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Asub_sH, "asub_s.h ${reg1}, ${reg2}, ${reg3}"), - "asub_s.h"); -} - -TEST_F(AssemblerMIPS64Test, Asub_sW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Asub_sW, "asub_s.w ${reg1}, ${reg2}, ${reg3}"), - "asub_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Asub_sD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Asub_sD, "asub_s.d ${reg1}, ${reg2}, ${reg3}"), - "asub_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Asub_uB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Asub_uB, "asub_u.b ${reg1}, ${reg2}, ${reg3}"), - "asub_u.b"); -} - -TEST_F(AssemblerMIPS64Test, Asub_uH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Asub_uH, "asub_u.h ${reg1}, ${reg2}, ${reg3}"), - "asub_u.h"); -} - -TEST_F(AssemblerMIPS64Test, Asub_uW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Asub_uW, "asub_u.w ${reg1}, ${reg2}, ${reg3}"), - "asub_u.w"); -} - -TEST_F(AssemblerMIPS64Test, Asub_uD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Asub_uD, "asub_u.d ${reg1}, ${reg2}, ${reg3}"), - "asub_u.d"); -} - -TEST_F(AssemblerMIPS64Test, MulvB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MulvB, "mulv.b ${reg1}, ${reg2}, ${reg3}"), - "mulv.b"); -} - -TEST_F(AssemblerMIPS64Test, MulvH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MulvH, "mulv.h ${reg1}, ${reg2}, ${reg3}"), - "mulv.h"); -} - -TEST_F(AssemblerMIPS64Test, MulvW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MulvW, "mulv.w ${reg1}, ${reg2}, ${reg3}"), - "mulv.w"); -} - -TEST_F(AssemblerMIPS64Test, MulvD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MulvD, "mulv.d ${reg1}, ${reg2}, ${reg3}"), - "mulv.d"); -} - -TEST_F(AssemblerMIPS64Test, Div_sB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_sB, "div_s.b ${reg1}, ${reg2}, ${reg3}"), - "div_s.b"); -} - -TEST_F(AssemblerMIPS64Test, Div_sH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_sH, "div_s.h ${reg1}, ${reg2}, ${reg3}"), - "div_s.h"); -} - -TEST_F(AssemblerMIPS64Test, Div_sW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_sW, "div_s.w ${reg1}, ${reg2}, ${reg3}"), - "div_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Div_sD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_sD, "div_s.d ${reg1}, ${reg2}, ${reg3}"), - "div_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Div_uB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_uB, "div_u.b ${reg1}, ${reg2}, ${reg3}"), - "div_u.b"); -} - -TEST_F(AssemblerMIPS64Test, Div_uH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_uH, "div_u.h ${reg1}, ${reg2}, ${reg3}"), - "div_u.h"); -} - -TEST_F(AssemblerMIPS64Test, Div_uW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_uW, "div_u.w ${reg1}, ${reg2}, ${reg3}"), - "div_u.w"); -} - -TEST_F(AssemblerMIPS64Test, Div_uD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_uD, "div_u.d ${reg1}, ${reg2}, ${reg3}"), - "div_u.d"); -} - -TEST_F(AssemblerMIPS64Test, Mod_sB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_sB, "mod_s.b ${reg1}, ${reg2}, ${reg3}"), - "mod_s.b"); -} - -TEST_F(AssemblerMIPS64Test, Mod_sH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_sH, "mod_s.h ${reg1}, ${reg2}, ${reg3}"), - "mod_s.h"); -} - -TEST_F(AssemblerMIPS64Test, Mod_sW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_sW, "mod_s.w ${reg1}, ${reg2}, ${reg3}"), - "mod_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Mod_sD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_sD, "mod_s.d ${reg1}, ${reg2}, ${reg3}"), - "mod_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Mod_uB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_uB, "mod_u.b ${reg1}, ${reg2}, ${reg3}"), - "mod_u.b"); -} - -TEST_F(AssemblerMIPS64Test, Mod_uH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_uH, "mod_u.h ${reg1}, ${reg2}, ${reg3}"), - "mod_u.h"); -} - -TEST_F(AssemblerMIPS64Test, Mod_uW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_uW, "mod_u.w ${reg1}, ${reg2}, ${reg3}"), - "mod_u.w"); -} - -TEST_F(AssemblerMIPS64Test, Mod_uD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_uD, "mod_u.d ${reg1}, ${reg2}, ${reg3}"), - "mod_u.d"); -} - -TEST_F(AssemblerMIPS64Test, Add_aB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Add_aB, "add_a.b ${reg1}, ${reg2}, ${reg3}"), - "add_a.b"); -} - -TEST_F(AssemblerMIPS64Test, Add_aH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Add_aH, "add_a.h ${reg1}, ${reg2}, ${reg3}"), - "add_a.h"); -} - -TEST_F(AssemblerMIPS64Test, Add_aW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Add_aW, "add_a.w ${reg1}, ${reg2}, ${reg3}"), - "add_a.w"); -} - -TEST_F(AssemblerMIPS64Test, Add_aD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Add_aD, "add_a.d ${reg1}, ${reg2}, ${reg3}"), - "add_a.d"); -} - -TEST_F(AssemblerMIPS64Test, Ave_sB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Ave_sB, "ave_s.b ${reg1}, ${reg2}, ${reg3}"), - "ave_s.b"); -} - -TEST_F(AssemblerMIPS64Test, Ave_sH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Ave_sH, "ave_s.h ${reg1}, ${reg2}, ${reg3}"), - "ave_s.h"); -} - -TEST_F(AssemblerMIPS64Test, Ave_sW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Ave_sW, "ave_s.w ${reg1}, ${reg2}, ${reg3}"), - "ave_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Ave_sD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Ave_sD, "ave_s.d ${reg1}, ${reg2}, ${reg3}"), - "ave_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Ave_uB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Ave_uB, "ave_u.b ${reg1}, ${reg2}, ${reg3}"), - "ave_u.b"); -} - -TEST_F(AssemblerMIPS64Test, Ave_uH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Ave_uH, "ave_u.h ${reg1}, ${reg2}, ${reg3}"), - "ave_u.h"); -} - -TEST_F(AssemblerMIPS64Test, Ave_uW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Ave_uW, "ave_u.w ${reg1}, ${reg2}, ${reg3}"), - "ave_u.w"); -} - -TEST_F(AssemblerMIPS64Test, Ave_uD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Ave_uD, "ave_u.d ${reg1}, ${reg2}, ${reg3}"), - "ave_u.d"); -} - -TEST_F(AssemblerMIPS64Test, Aver_sB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Aver_sB, "aver_s.b ${reg1}, ${reg2}, ${reg3}"), - "aver_s.b"); -} - -TEST_F(AssemblerMIPS64Test, Aver_sH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Aver_sH, "aver_s.h ${reg1}, ${reg2}, ${reg3}"), - "aver_s.h"); -} - -TEST_F(AssemblerMIPS64Test, Aver_sW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Aver_sW, "aver_s.w ${reg1}, ${reg2}, ${reg3}"), - "aver_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Aver_sD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Aver_sD, "aver_s.d ${reg1}, ${reg2}, ${reg3}"), - "aver_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Aver_uB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Aver_uB, "aver_u.b ${reg1}, ${reg2}, ${reg3}"), - "aver_u.b"); -} - -TEST_F(AssemblerMIPS64Test, Aver_uH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Aver_uH, "aver_u.h ${reg1}, ${reg2}, ${reg3}"), - "aver_u.h"); -} - -TEST_F(AssemblerMIPS64Test, Aver_uW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Aver_uW, "aver_u.w ${reg1}, ${reg2}, ${reg3}"), - "aver_u.w"); -} - -TEST_F(AssemblerMIPS64Test, Aver_uD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Aver_uD, "aver_u.d ${reg1}, ${reg2}, ${reg3}"), - "aver_u.d"); -} - -TEST_F(AssemblerMIPS64Test, Max_sB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_sB, "max_s.b ${reg1}, ${reg2}, ${reg3}"), - "max_s.b"); -} - -TEST_F(AssemblerMIPS64Test, Max_sH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_sH, "max_s.h ${reg1}, ${reg2}, ${reg3}"), - "max_s.h"); -} - -TEST_F(AssemblerMIPS64Test, Max_sW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_sW, "max_s.w ${reg1}, ${reg2}, ${reg3}"), - "max_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Max_sD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_sD, "max_s.d ${reg1}, ${reg2}, ${reg3}"), - "max_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Max_uB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_uB, "max_u.b ${reg1}, ${reg2}, ${reg3}"), - "max_u.b"); -} - -TEST_F(AssemblerMIPS64Test, Max_uH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_uH, "max_u.h ${reg1}, ${reg2}, ${reg3}"), - "max_u.h"); -} - -TEST_F(AssemblerMIPS64Test, Max_uW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_uW, "max_u.w ${reg1}, ${reg2}, ${reg3}"), - "max_u.w"); -} - -TEST_F(AssemblerMIPS64Test, Max_uD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_uD, "max_u.d ${reg1}, ${reg2}, ${reg3}"), - "max_u.d"); -} - -TEST_F(AssemblerMIPS64Test, Min_sB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_sB, "min_s.b ${reg1}, ${reg2}, ${reg3}"), - "min_s.b"); -} - -TEST_F(AssemblerMIPS64Test, Min_sH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_sH, "min_s.h ${reg1}, ${reg2}, ${reg3}"), - "min_s.h"); -} - -TEST_F(AssemblerMIPS64Test, Min_sW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_sW, "min_s.w ${reg1}, ${reg2}, ${reg3}"), - "min_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Min_sD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_sD, "min_s.d ${reg1}, ${reg2}, ${reg3}"), - "min_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Min_uB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_uB, "min_u.b ${reg1}, ${reg2}, ${reg3}"), - "min_u.b"); -} - -TEST_F(AssemblerMIPS64Test, Min_uH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_uH, "min_u.h ${reg1}, ${reg2}, ${reg3}"), - "min_u.h"); -} - -TEST_F(AssemblerMIPS64Test, Min_uW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_uW, "min_u.w ${reg1}, ${reg2}, ${reg3}"), - "min_u.w"); -} - -TEST_F(AssemblerMIPS64Test, Min_uD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_uD, "min_u.d ${reg1}, ${reg2}, ${reg3}"), - "min_u.d"); -} - -TEST_F(AssemblerMIPS64Test, FaddW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FaddW, "fadd.w ${reg1}, ${reg2}, ${reg3}"), - "fadd.w"); -} - -TEST_F(AssemblerMIPS64Test, FaddD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FaddD, "fadd.d ${reg1}, ${reg2}, ${reg3}"), - "fadd.d"); -} - -TEST_F(AssemblerMIPS64Test, FsubW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FsubW, "fsub.w ${reg1}, ${reg2}, ${reg3}"), - "fsub.w"); -} - -TEST_F(AssemblerMIPS64Test, FsubD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FsubD, "fsub.d ${reg1}, ${reg2}, ${reg3}"), - "fsub.d"); -} - -TEST_F(AssemblerMIPS64Test, FmulW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmulW, "fmul.w ${reg1}, ${reg2}, ${reg3}"), - "fmul.w"); -} - -TEST_F(AssemblerMIPS64Test, FmulD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmulD, "fmul.d ${reg1}, ${reg2}, ${reg3}"), - "fmul.d"); -} - -TEST_F(AssemblerMIPS64Test, FdivW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FdivW, "fdiv.w ${reg1}, ${reg2}, ${reg3}"), - "fdiv.w"); -} - -TEST_F(AssemblerMIPS64Test, FdivD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FdivD, "fdiv.d ${reg1}, ${reg2}, ${reg3}"), - "fdiv.d"); -} - -TEST_F(AssemblerMIPS64Test, FmaxW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmaxW, "fmax.w ${reg1}, ${reg2}, ${reg3}"), - "fmax.w"); -} - -TEST_F(AssemblerMIPS64Test, FmaxD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmaxD, "fmax.d ${reg1}, ${reg2}, ${reg3}"), - "fmax.d"); -} - -TEST_F(AssemblerMIPS64Test, FminW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FminW, "fmin.w ${reg1}, ${reg2}, ${reg3}"), - "fmin.w"); -} - -TEST_F(AssemblerMIPS64Test, FminD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FminD, "fmin.d ${reg1}, ${reg2}, ${reg3}"), - "fmin.d"); -} - -TEST_F(AssemblerMIPS64Test, Ffint_sW) { - DriverStr(RepeatVV(&mips64::Mips64Assembler::Ffint_sW, "ffint_s.w ${reg1}, ${reg2}"), - "ffint_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Ffint_sD) { - DriverStr(RepeatVV(&mips64::Mips64Assembler::Ffint_sD, "ffint_s.d ${reg1}, ${reg2}"), - "ffint_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Ftint_sW) { - DriverStr(RepeatVV(&mips64::Mips64Assembler::Ftint_sW, "ftint_s.w ${reg1}, ${reg2}"), - "ftint_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Ftint_sD) { - DriverStr(RepeatVV(&mips64::Mips64Assembler::Ftint_sD, "ftint_s.d ${reg1}, ${reg2}"), - "ftint_s.d"); -} - -TEST_F(AssemblerMIPS64Test, SllB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SllB, "sll.b ${reg1}, ${reg2}, ${reg3}"), "sll.b"); -} - -TEST_F(AssemblerMIPS64Test, SllH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SllH, "sll.h ${reg1}, ${reg2}, ${reg3}"), "sll.h"); -} - -TEST_F(AssemblerMIPS64Test, SllW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SllW, "sll.w ${reg1}, ${reg2}, ${reg3}"), "sll.w"); -} - -TEST_F(AssemblerMIPS64Test, SllD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SllD, "sll.d ${reg1}, ${reg2}, ${reg3}"), "sll.d"); -} - -TEST_F(AssemblerMIPS64Test, SraB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SraB, "sra.b ${reg1}, ${reg2}, ${reg3}"), "sra.b"); -} - -TEST_F(AssemblerMIPS64Test, SraH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SraH, "sra.h ${reg1}, ${reg2}, ${reg3}"), "sra.h"); -} - -TEST_F(AssemblerMIPS64Test, SraW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SraW, "sra.w ${reg1}, ${reg2}, ${reg3}"), "sra.w"); -} - -TEST_F(AssemblerMIPS64Test, SraD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SraD, "sra.d ${reg1}, ${reg2}, ${reg3}"), "sra.d"); -} - -TEST_F(AssemblerMIPS64Test, SrlB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SrlB, "srl.b ${reg1}, ${reg2}, ${reg3}"), "srl.b"); -} - -TEST_F(AssemblerMIPS64Test, SrlH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SrlH, "srl.h ${reg1}, ${reg2}, ${reg3}"), "srl.h"); -} - -TEST_F(AssemblerMIPS64Test, SrlW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SrlW, "srl.w ${reg1}, ${reg2}, ${reg3}"), "srl.w"); -} - -TEST_F(AssemblerMIPS64Test, SrlD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::SrlD, "srl.d ${reg1}, ${reg2}, ${reg3}"), "srl.d"); -} - -TEST_F(AssemblerMIPS64Test, SlliB) { - DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SlliB, 3, "slli.b ${reg1}, ${reg2}, {imm}"), - "slli.b"); -} - -TEST_F(AssemblerMIPS64Test, SlliH) { - DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SlliH, 4, "slli.h ${reg1}, ${reg2}, {imm}"), - "slli.h"); -} - -TEST_F(AssemblerMIPS64Test, SlliW) { - DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SlliW, 5, "slli.w ${reg1}, ${reg2}, {imm}"), - "slli.w"); -} - -TEST_F(AssemblerMIPS64Test, SlliD) { - DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SlliD, 6, "slli.d ${reg1}, ${reg2}, {imm}"), - "slli.d"); -} - -TEST_F(AssemblerMIPS64Test, MoveV) { - DriverStr(RepeatVV(&mips64::Mips64Assembler::MoveV, "move.v ${reg1}, ${reg2}"), "move.v"); -} - -TEST_F(AssemblerMIPS64Test, SplatiB) { - DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SplatiB, 4, "splati.b ${reg1}, ${reg2}[{imm}]"), - "splati.b"); -} - -TEST_F(AssemblerMIPS64Test, SplatiH) { - DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SplatiH, 3, "splati.h ${reg1}, ${reg2}[{imm}]"), - "splati.h"); -} - -TEST_F(AssemblerMIPS64Test, SplatiW) { - DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SplatiW, 2, "splati.w ${reg1}, ${reg2}[{imm}]"), - "splati.w"); -} - -TEST_F(AssemblerMIPS64Test, SplatiD) { - DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SplatiD, 1, "splati.d ${reg1}, ${reg2}[{imm}]"), - "splati.d"); -} - -TEST_F(AssemblerMIPS64Test, Copy_sB) { - DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_sB, 4, "copy_s.b ${reg1}, ${reg2}[{imm}]"), - "copy_s.b"); -} - -TEST_F(AssemblerMIPS64Test, Copy_sH) { - DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_sH, 3, "copy_s.h ${reg1}, ${reg2}[{imm}]"), - "copy_s.h"); -} - -TEST_F(AssemblerMIPS64Test, Copy_sW) { - DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_sW, 2, "copy_s.w ${reg1}, ${reg2}[{imm}]"), - "copy_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Copy_sD) { - DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_sD, 1, "copy_s.d ${reg1}, ${reg2}[{imm}]"), - "copy_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Copy_uB) { - DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_uB, 4, "copy_u.b ${reg1}, ${reg2}[{imm}]"), - "copy_u.b"); -} - -TEST_F(AssemblerMIPS64Test, Copy_uH) { - DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_uH, 3, "copy_u.h ${reg1}, ${reg2}[{imm}]"), - "copy_u.h"); -} - -TEST_F(AssemblerMIPS64Test, Copy_uW) { - DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_uW, 2, "copy_u.w ${reg1}, ${reg2}[{imm}]"), - "copy_u.w"); -} - -TEST_F(AssemblerMIPS64Test, InsertB) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::InsertB, 4, "insert.b ${reg1}[{imm}], ${reg2}"), - "insert.b"); -} - -TEST_F(AssemblerMIPS64Test, InsertH) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::InsertH, 3, "insert.h ${reg1}[{imm}], ${reg2}"), - "insert.h"); -} - -TEST_F(AssemblerMIPS64Test, InsertW) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::InsertW, 2, "insert.w ${reg1}[{imm}], ${reg2}"), - "insert.w"); -} - -TEST_F(AssemblerMIPS64Test, InsertD) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::InsertD, 1, "insert.d ${reg1}[{imm}], ${reg2}"), - "insert.d"); -} - -TEST_F(AssemblerMIPS64Test, FillB) { - DriverStr(RepeatVR(&mips64::Mips64Assembler::FillB, "fill.b ${reg1}, ${reg2}"), "fill.b"); -} - -TEST_F(AssemblerMIPS64Test, FillH) { - DriverStr(RepeatVR(&mips64::Mips64Assembler::FillH, "fill.h ${reg1}, ${reg2}"), "fill.h"); -} - -TEST_F(AssemblerMIPS64Test, FillW) { - DriverStr(RepeatVR(&mips64::Mips64Assembler::FillW, "fill.w ${reg1}, ${reg2}"), "fill.w"); -} - -TEST_F(AssemblerMIPS64Test, FillD) { - DriverStr(RepeatVR(&mips64::Mips64Assembler::FillD, "fill.d ${reg1}, ${reg2}"), "fill.d"); -} - -TEST_F(AssemblerMIPS64Test, PcntB) { - DriverStr(RepeatVV(&mips64::Mips64Assembler::PcntB, "pcnt.b ${reg1}, ${reg2}"), "pcnt.b"); -} - -TEST_F(AssemblerMIPS64Test, PcntH) { - DriverStr(RepeatVV(&mips64::Mips64Assembler::PcntH, "pcnt.h ${reg1}, ${reg2}"), "pcnt.h"); -} - -TEST_F(AssemblerMIPS64Test, PcntW) { - DriverStr(RepeatVV(&mips64::Mips64Assembler::PcntW, "pcnt.w ${reg1}, ${reg2}"), "pcnt.w"); -} - -TEST_F(AssemblerMIPS64Test, PcntD) { - DriverStr(RepeatVV(&mips64::Mips64Assembler::PcntD, "pcnt.d ${reg1}, ${reg2}"), "pcnt.d"); -} - -TEST_F(AssemblerMIPS64Test, LdiB) { - DriverStr(RepeatVIb(&mips64::Mips64Assembler::LdiB, -8, "ldi.b ${reg}, {imm}"), "ldi.b"); -} - -TEST_F(AssemblerMIPS64Test, LdiH) { - DriverStr(RepeatVIb(&mips64::Mips64Assembler::LdiH, -10, "ldi.h ${reg}, {imm}"), "ldi.h"); -} - -TEST_F(AssemblerMIPS64Test, LdiW) { - DriverStr(RepeatVIb(&mips64::Mips64Assembler::LdiW, -10, "ldi.w ${reg}, {imm}"), "ldi.w"); -} - -TEST_F(AssemblerMIPS64Test, LdiD) { - DriverStr(RepeatVIb(&mips64::Mips64Assembler::LdiD, -10, "ldi.d ${reg}, {imm}"), "ldi.d"); -} - -TEST_F(AssemblerMIPS64Test, LdB) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::LdB, -10, "ld.b ${reg1}, {imm}(${reg2})"), "ld.b"); -} - -TEST_F(AssemblerMIPS64Test, LdH) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::LdH, -10, "ld.h ${reg1}, {imm}(${reg2})", 0, 2), - "ld.h"); -} - -TEST_F(AssemblerMIPS64Test, LdW) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::LdW, -10, "ld.w ${reg1}, {imm}(${reg2})", 0, 4), - "ld.w"); -} - -TEST_F(AssemblerMIPS64Test, LdD) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::LdD, -10, "ld.d ${reg1}, {imm}(${reg2})", 0, 8), - "ld.d"); -} - -TEST_F(AssemblerMIPS64Test, StB) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::StB, -10, "st.b ${reg1}, {imm}(${reg2})"), "st.b"); -} - -TEST_F(AssemblerMIPS64Test, StH) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::StH, -10, "st.h ${reg1}, {imm}(${reg2})", 0, 2), - "st.h"); -} - -TEST_F(AssemblerMIPS64Test, StW) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::StW, -10, "st.w ${reg1}, {imm}(${reg2})", 0, 4), - "st.w"); -} - -TEST_F(AssemblerMIPS64Test, StD) { - DriverStr(RepeatVRIb(&mips64::Mips64Assembler::StD, -10, "st.d ${reg1}, {imm}(${reg2})", 0, 8), - "st.d"); -} - -TEST_F(AssemblerMIPS64Test, IlvlB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvlB, "ilvl.b ${reg1}, ${reg2}, ${reg3}"), - "ilvl.b"); -} - -TEST_F(AssemblerMIPS64Test, IlvlH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvlH, "ilvl.h ${reg1}, ${reg2}, ${reg3}"), - "ilvl.h"); -} - -TEST_F(AssemblerMIPS64Test, IlvlW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvlW, "ilvl.w ${reg1}, ${reg2}, ${reg3}"), - "ilvl.w"); -} - -TEST_F(AssemblerMIPS64Test, IlvlD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvlD, "ilvl.d ${reg1}, ${reg2}, ${reg3}"), - "ilvl.d"); -} - -TEST_F(AssemblerMIPS64Test, IlvrB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvrB, "ilvr.b ${reg1}, ${reg2}, ${reg3}"), - "ilvr.b"); -} - -TEST_F(AssemblerMIPS64Test, IlvrH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvrH, "ilvr.h ${reg1}, ${reg2}, ${reg3}"), - "ilvr.h"); -} - -TEST_F(AssemblerMIPS64Test, IlvrW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvrW, "ilvr.w ${reg1}, ${reg2}, ${reg3}"), - "ilvr.w"); -} - -TEST_F(AssemblerMIPS64Test, IlvrD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvrD, "ilvr.d ${reg1}, ${reg2}, ${reg3}"), - "ilvr.d"); -} - -TEST_F(AssemblerMIPS64Test, IlvevB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvevB, "ilvev.b ${reg1}, ${reg2}, ${reg3}"), - "ilvev.b"); -} - -TEST_F(AssemblerMIPS64Test, IlvevH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvevH, "ilvev.h ${reg1}, ${reg2}, ${reg3}"), - "ilvev.h"); -} - -TEST_F(AssemblerMIPS64Test, IlvevW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvevW, "ilvev.w ${reg1}, ${reg2}, ${reg3}"), - "ilvev.w"); -} - -TEST_F(AssemblerMIPS64Test, IlvevD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvevD, "ilvev.d ${reg1}, ${reg2}, ${reg3}"), - "ilvev.d"); -} - -TEST_F(AssemblerMIPS64Test, IlvodB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvodB, "ilvod.b ${reg1}, ${reg2}, ${reg3}"), - "ilvod.b"); -} - -TEST_F(AssemblerMIPS64Test, IlvodH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvodH, "ilvod.h ${reg1}, ${reg2}, ${reg3}"), - "ilvod.h"); -} - -TEST_F(AssemblerMIPS64Test, IlvodW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvodW, "ilvod.w ${reg1}, ${reg2}, ${reg3}"), - "ilvod.w"); -} - -TEST_F(AssemblerMIPS64Test, IlvodD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvodD, "ilvod.d ${reg1}, ${reg2}, ${reg3}"), - "ilvod.d"); -} - -TEST_F(AssemblerMIPS64Test, MaddvB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MaddvB, "maddv.b ${reg1}, ${reg2}, ${reg3}"), - "maddv.b"); -} - -TEST_F(AssemblerMIPS64Test, MaddvH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MaddvH, "maddv.h ${reg1}, ${reg2}, ${reg3}"), - "maddv.h"); -} - -TEST_F(AssemblerMIPS64Test, MaddvW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MaddvW, "maddv.w ${reg1}, ${reg2}, ${reg3}"), - "maddv.w"); -} - -TEST_F(AssemblerMIPS64Test, MaddvD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MaddvD, "maddv.d ${reg1}, ${reg2}, ${reg3}"), - "maddv.d"); -} - -TEST_F(AssemblerMIPS64Test, Hadd_sH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_sH, "hadd_s.h ${reg1}, ${reg2}, ${reg3}"), - "hadd_s.h"); -} - -TEST_F(AssemblerMIPS64Test, Hadd_sW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_sW, "hadd_s.w ${reg1}, ${reg2}, ${reg3}"), - "hadd_s.w"); -} - -TEST_F(AssemblerMIPS64Test, Hadd_sD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_sD, "hadd_s.d ${reg1}, ${reg2}, ${reg3}"), - "hadd_s.d"); -} - -TEST_F(AssemblerMIPS64Test, Hadd_uH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_uH, "hadd_u.h ${reg1}, ${reg2}, ${reg3}"), - "hadd_u.h"); -} - -TEST_F(AssemblerMIPS64Test, Hadd_uW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_uW, "hadd_u.w ${reg1}, ${reg2}, ${reg3}"), - "hadd_u.w"); -} - -TEST_F(AssemblerMIPS64Test, Hadd_uD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_uD, "hadd_u.d ${reg1}, ${reg2}, ${reg3}"), - "hadd_u.d"); -} - -TEST_F(AssemblerMIPS64Test, MsubvB) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MsubvB, "msubv.b ${reg1}, ${reg2}, ${reg3}"), - "msubv.b"); -} - -TEST_F(AssemblerMIPS64Test, MsubvH) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MsubvH, "msubv.h ${reg1}, ${reg2}, ${reg3}"), - "msubv.h"); -} - -TEST_F(AssemblerMIPS64Test, MsubvW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MsubvW, "msubv.w ${reg1}, ${reg2}, ${reg3}"), - "msubv.w"); -} - -TEST_F(AssemblerMIPS64Test, MsubvD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::MsubvD, "msubv.d ${reg1}, ${reg2}, ${reg3}"), - "msubv.d"); -} - -TEST_F(AssemblerMIPS64Test, FmaddW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmaddW, "fmadd.w ${reg1}, ${reg2}, ${reg3}"), - "fmadd.w"); -} - -TEST_F(AssemblerMIPS64Test, FmaddD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmaddD, "fmadd.d ${reg1}, ${reg2}, ${reg3}"), - "fmadd.d"); -} - -TEST_F(AssemblerMIPS64Test, FmsubW) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmsubW, "fmsub.w ${reg1}, ${reg2}, ${reg3}"), - "fmsub.w"); -} - -TEST_F(AssemblerMIPS64Test, FmsubD) { - DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmsubD, "fmsub.d ${reg1}, ${reg2}, ${reg3}"), - "fmsub.d"); -} - -#undef __ - -} // namespace art diff --git a/compiler/utils/mips64/constants_mips64.h b/compiler/utils/mips64/constants_mips64.h deleted file mode 100644 index 41eb77c9ae..0000000000 --- a/compiler/utils/mips64/constants_mips64.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_UTILS_MIPS64_CONSTANTS_MIPS64_H_ -#define ART_COMPILER_UTILS_MIPS64_CONSTANTS_MIPS64_H_ - -#include <iosfwd> - -#include <android-base/logging.h> - -#include "arch/mips64/registers_mips64.h" -#include "base/globals.h" -#include "base/macros.h" - -namespace art { -namespace mips64 { - -// Constants used for the decoding or encoding of the individual fields of instructions. -enum InstructionFields { - kOpcodeShift = 26, - kOpcodeBits = 6, - kRsShift = 21, - kRsBits = 5, - kRtShift = 16, - kRtBits = 5, - kRdShift = 11, - kRdBits = 5, - kShamtShift = 6, - kShamtBits = 5, - kFunctShift = 0, - kFunctBits = 6, - - kFmtShift = 21, - kFmtBits = 5, - kFtShift = 16, - kFtBits = 5, - kFsShift = 11, - kFsBits = 5, - kFdShift = 6, - kFdBits = 5, - - kMsaOperationShift = 23, - kMsaELMOperationShift = 22, - kMsa2ROperationShift = 18, - kMsa2RFOperationShift = 17, - kDfShift = 21, - kDfMShift = 16, - kDf2RShift = 16, - kDfNShift = 16, - kWtShift = 16, - kWtBits = 5, - kWsShift = 11, - kWsBits = 5, - kWdShift = 6, - kWdBits = 5, - kS10Shift = 16, - kI10Shift = 11, - kS10MinorShift = 2, - - kBranchOffsetMask = 0x0000ffff, - kJumpOffsetMask = 0x03ffffff, - kMsaMajorOpcode = 0x1e, - kMsaDfMByteMask = 0x70, - kMsaDfMHalfwordMask = 0x60, - kMsaDfMWordMask = 0x40, - kMsaDfMDoublewordMask = 0x00, - kMsaDfNByteMask = 0x00, - kMsaDfNHalfwordMask = 0x20, - kMsaDfNWordMask = 0x30, - kMsaDfNDoublewordMask = 0x38, - kMsaS10Mask = 0x3ff, -}; - -enum ScaleFactor { - TIMES_1 = 0, - TIMES_2 = 1, - TIMES_4 = 2, - TIMES_8 = 3 -}; - -class Instr { - public: - static const uint32_t kBreakPointInstruction = 0x0000000D; - - bool IsBreakPoint() { - return ((*reinterpret_cast<const uint32_t*>(this)) & 0xFC00003F) == kBreakPointInstruction; - } - - // Instructions are read out of a code stream. The only way to get a - // reference to an instruction is to convert a pointer. There is no way - // to allocate or create instances of class Instr. - // Use the At(pc) function to create references to Instr. - static Instr* At(uintptr_t pc) { return reinterpret_cast<Instr*>(pc); } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); -}; - -} // namespace mips64 -} // namespace art - -#endif // ART_COMPILER_UTILS_MIPS64_CONSTANTS_MIPS64_H_ diff --git a/compiler/utils/mips64/managed_register_mips64.cc b/compiler/utils/mips64/managed_register_mips64.cc deleted file mode 100644 index 01cb6ddfe2..0000000000 --- a/compiler/utils/mips64/managed_register_mips64.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "managed_register_mips64.h" - -#include "base/globals.h" - -namespace art { -namespace mips64 { - -bool Mips64ManagedRegister::Overlaps(const Mips64ManagedRegister& other) const { - if (IsNoRegister() || other.IsNoRegister()) return false; - CHECK(IsValidManagedRegister()); - CHECK(other.IsValidManagedRegister()); - if (Equals(other)) return true; - if (IsFpuRegister() && other.IsVectorRegister()) { - return (AsFpuRegister() == other.AsOverlappingFpuRegister()); - } else if (IsVectorRegister() && other.IsFpuRegister()) { - return (AsVectorRegister() == other.AsOverlappingVectorRegister()); - } - return false; -} - -void Mips64ManagedRegister::Print(std::ostream& os) const { - if (!IsValidManagedRegister()) { - os << "No Register"; - } else if (IsGpuRegister()) { - os << "GPU: " << static_cast<int>(AsGpuRegister()); - } else if (IsFpuRegister()) { - os << "FpuRegister: " << static_cast<int>(AsFpuRegister()); - } else if (IsVectorRegister()) { - os << "VectorRegister: " << static_cast<int>(AsVectorRegister()); - } else { - os << "??: " << RegId(); - } -} - -std::ostream& operator<<(std::ostream& os, const Mips64ManagedRegister& reg) { - reg.Print(os); - return os; -} - -} // namespace mips64 -} // namespace art diff --git a/compiler/utils/mips64/managed_register_mips64.h b/compiler/utils/mips64/managed_register_mips64.h deleted file mode 100644 index 94166d32b7..0000000000 --- a/compiler/utils/mips64/managed_register_mips64.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_ -#define ART_COMPILER_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_ - -#include "constants_mips64.h" -#include "utils/managed_register.h" - -namespace art { -namespace mips64 { - -const int kNumberOfGpuRegIds = kNumberOfGpuRegisters; -const int kNumberOfGpuAllocIds = kNumberOfGpuRegisters; - -const int kNumberOfFpuRegIds = kNumberOfFpuRegisters; -const int kNumberOfFpuAllocIds = kNumberOfFpuRegisters; - -const int kNumberOfVecRegIds = kNumberOfVectorRegisters; -const int kNumberOfVecAllocIds = kNumberOfVectorRegisters; - -const int kNumberOfRegIds = kNumberOfGpuRegIds + kNumberOfFpuRegIds + kNumberOfVecRegIds; -const int kNumberOfAllocIds = kNumberOfGpuAllocIds + kNumberOfFpuAllocIds + kNumberOfVecAllocIds; - -// Register ids map: -// [0..R[ core registers (enum GpuRegister) -// [R..F[ floating-point registers (enum FpuRegister) -// [F..W[ MSA vector registers (enum VectorRegister) -// where -// R = kNumberOfGpuRegIds -// F = R + kNumberOfFpuRegIds -// W = F + kNumberOfVecRegIds - -// An instance of class 'ManagedRegister' represents a single Mips64 register. -// A register can be one of the following: -// * core register (enum GpuRegister) -// * floating-point register (enum FpuRegister) -// * MSA vector register (enum VectorRegister) -// -// 'ManagedRegister::NoRegister()' provides an invalid register. -// There is a one-to-one mapping between ManagedRegister and register id. -class Mips64ManagedRegister : public ManagedRegister { - public: - constexpr GpuRegister AsGpuRegister() const { - CHECK(IsGpuRegister()); - return static_cast<GpuRegister>(id_); - } - - constexpr FpuRegister AsFpuRegister() const { - CHECK(IsFpuRegister()); - return static_cast<FpuRegister>(id_ - kNumberOfGpuRegIds); - } - - constexpr VectorRegister AsVectorRegister() const { - CHECK(IsVectorRegister()); - return static_cast<VectorRegister>(id_ - (kNumberOfGpuRegIds + kNumberOfFpuRegisters)); - } - - constexpr FpuRegister AsOverlappingFpuRegister() const { - CHECK(IsValidManagedRegister()); - return static_cast<FpuRegister>(AsVectorRegister()); - } - - constexpr VectorRegister AsOverlappingVectorRegister() const { - CHECK(IsValidManagedRegister()); - return static_cast<VectorRegister>(AsFpuRegister()); - } - - constexpr bool IsGpuRegister() const { - CHECK(IsValidManagedRegister()); - return (0 <= id_) && (id_ < kNumberOfGpuRegIds); - } - - constexpr bool IsFpuRegister() const { - CHECK(IsValidManagedRegister()); - const int test = id_ - kNumberOfGpuRegIds; - return (0 <= test) && (test < kNumberOfFpuRegIds); - } - - constexpr bool IsVectorRegister() const { - CHECK(IsValidManagedRegister()); - const int test = id_ - (kNumberOfGpuRegIds + kNumberOfFpuRegIds); - return (0 <= test) && (test < kNumberOfVecRegIds); - } - - void Print(std::ostream& os) const; - - // Returns true if the two managed-registers ('this' and 'other') overlap. - // Either managed-register may be the NoRegister. If both are the NoRegister - // then false is returned. - bool Overlaps(const Mips64ManagedRegister& other) const; - - static constexpr Mips64ManagedRegister FromGpuRegister(GpuRegister r) { - CHECK_NE(r, kNoGpuRegister); - return FromRegId(r); - } - - static constexpr Mips64ManagedRegister FromFpuRegister(FpuRegister r) { - CHECK_NE(r, kNoFpuRegister); - return FromRegId(r + kNumberOfGpuRegIds); - } - - static constexpr Mips64ManagedRegister FromVectorRegister(VectorRegister r) { - CHECK_NE(r, kNoVectorRegister); - return FromRegId(r + kNumberOfGpuRegIds + kNumberOfFpuRegIds); - } - - private: - constexpr bool IsValidManagedRegister() const { - return (0 <= id_) && (id_ < kNumberOfRegIds); - } - - constexpr int RegId() const { - CHECK(!IsNoRegister()); - return id_; - } - - int AllocId() const { - CHECK(IsValidManagedRegister()); - CHECK_LT(id_, kNumberOfAllocIds); - return id_; - } - - int AllocIdLow() const; - int AllocIdHigh() const; - - friend class ManagedRegister; - - explicit constexpr Mips64ManagedRegister(int reg_id) : ManagedRegister(reg_id) {} - - static constexpr Mips64ManagedRegister FromRegId(int reg_id) { - Mips64ManagedRegister reg(reg_id); - CHECK(reg.IsValidManagedRegister()); - return reg; - } -}; - -std::ostream& operator<<(std::ostream& os, const Mips64ManagedRegister& reg); - -} // namespace mips64 - -constexpr inline mips64::Mips64ManagedRegister ManagedRegister::AsMips64() const { - mips64::Mips64ManagedRegister reg(id_); - CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister()); - return reg; -} - -} // namespace art - -#endif // ART_COMPILER_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_ diff --git a/compiler/utils/mips64/managed_register_mips64_test.cc b/compiler/utils/mips64/managed_register_mips64_test.cc deleted file mode 100644 index bbfeeee20f..0000000000 --- a/compiler/utils/mips64/managed_register_mips64_test.cc +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "managed_register_mips64.h" - -#include "base/globals.h" -#include "gtest/gtest.h" - -namespace art { -namespace mips64 { - -TEST(Mips64ManagedRegister, NoRegister) { - Mips64ManagedRegister reg = ManagedRegister::NoRegister().AsMips64(); - EXPECT_TRUE(reg.IsNoRegister()); - EXPECT_FALSE(reg.Overlaps(reg)); -} - -TEST(Mips64ManagedRegister, GpuRegister) { - Mips64ManagedRegister reg = Mips64ManagedRegister::FromGpuRegister(ZERO); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(ZERO, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(AT); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(AT, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(V0); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(V0, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(A0); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(A0, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(A7); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(A7, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(T0); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(T0, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(T3); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(T3, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(S0); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(S0, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(GP); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(GP, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(SP); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(SP, reg.AsGpuRegister()); - - reg = Mips64ManagedRegister::FromGpuRegister(RA); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_TRUE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_EQ(RA, reg.AsGpuRegister()); -} - -TEST(Mips64ManagedRegister, FpuRegister) { - Mips64ManagedRegister reg = Mips64ManagedRegister::FromFpuRegister(F0); - Mips64ManagedRegister vreg = Mips64ManagedRegister::FromVectorRegister(W0); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_FALSE(reg.IsGpuRegister()); - EXPECT_TRUE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_TRUE(reg.Overlaps(vreg)); - EXPECT_EQ(F0, reg.AsFpuRegister()); - EXPECT_EQ(W0, reg.AsOverlappingVectorRegister()); - EXPECT_TRUE(reg.Equals(Mips64ManagedRegister::FromFpuRegister(F0))); - - reg = Mips64ManagedRegister::FromFpuRegister(F1); - vreg = Mips64ManagedRegister::FromVectorRegister(W1); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_FALSE(reg.IsGpuRegister()); - EXPECT_TRUE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_TRUE(reg.Overlaps(vreg)); - EXPECT_EQ(F1, reg.AsFpuRegister()); - EXPECT_EQ(W1, reg.AsOverlappingVectorRegister()); - EXPECT_TRUE(reg.Equals(Mips64ManagedRegister::FromFpuRegister(F1))); - - reg = Mips64ManagedRegister::FromFpuRegister(F20); - vreg = Mips64ManagedRegister::FromVectorRegister(W20); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_FALSE(reg.IsGpuRegister()); - EXPECT_TRUE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_TRUE(reg.Overlaps(vreg)); - EXPECT_EQ(F20, reg.AsFpuRegister()); - EXPECT_EQ(W20, reg.AsOverlappingVectorRegister()); - EXPECT_TRUE(reg.Equals(Mips64ManagedRegister::FromFpuRegister(F20))); - - reg = Mips64ManagedRegister::FromFpuRegister(F31); - vreg = Mips64ManagedRegister::FromVectorRegister(W31); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_FALSE(reg.IsGpuRegister()); - EXPECT_TRUE(reg.IsFpuRegister()); - EXPECT_FALSE(reg.IsVectorRegister()); - EXPECT_TRUE(reg.Overlaps(vreg)); - EXPECT_EQ(F31, reg.AsFpuRegister()); - EXPECT_EQ(W31, reg.AsOverlappingVectorRegister()); - EXPECT_TRUE(reg.Equals(Mips64ManagedRegister::FromFpuRegister(F31))); -} - -TEST(Mips64ManagedRegister, VectorRegister) { - Mips64ManagedRegister reg = Mips64ManagedRegister::FromVectorRegister(W0); - Mips64ManagedRegister freg = Mips64ManagedRegister::FromFpuRegister(F0); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_FALSE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_TRUE(reg.IsVectorRegister()); - EXPECT_TRUE(reg.Overlaps(freg)); - EXPECT_EQ(W0, reg.AsVectorRegister()); - EXPECT_EQ(F0, reg.AsOverlappingFpuRegister()); - EXPECT_TRUE(reg.Equals(Mips64ManagedRegister::FromVectorRegister(W0))); - - reg = Mips64ManagedRegister::FromVectorRegister(W2); - freg = Mips64ManagedRegister::FromFpuRegister(F2); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_FALSE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_TRUE(reg.IsVectorRegister()); - EXPECT_TRUE(reg.Overlaps(freg)); - EXPECT_EQ(W2, reg.AsVectorRegister()); - EXPECT_EQ(F2, reg.AsOverlappingFpuRegister()); - EXPECT_TRUE(reg.Equals(Mips64ManagedRegister::FromVectorRegister(W2))); - - reg = Mips64ManagedRegister::FromVectorRegister(W13); - freg = Mips64ManagedRegister::FromFpuRegister(F13); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_FALSE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_TRUE(reg.IsVectorRegister()); - EXPECT_TRUE(reg.Overlaps(freg)); - EXPECT_EQ(W13, reg.AsVectorRegister()); - EXPECT_EQ(F13, reg.AsOverlappingFpuRegister()); - EXPECT_TRUE(reg.Equals(Mips64ManagedRegister::FromVectorRegister(W13))); - - reg = Mips64ManagedRegister::FromVectorRegister(W29); - freg = Mips64ManagedRegister::FromFpuRegister(F29); - EXPECT_FALSE(reg.IsNoRegister()); - EXPECT_FALSE(reg.IsGpuRegister()); - EXPECT_FALSE(reg.IsFpuRegister()); - EXPECT_TRUE(reg.IsVectorRegister()); - EXPECT_TRUE(reg.Overlaps(freg)); - EXPECT_EQ(W29, reg.AsVectorRegister()); - EXPECT_EQ(F29, reg.AsOverlappingFpuRegister()); - EXPECT_TRUE(reg.Equals(Mips64ManagedRegister::FromVectorRegister(W29))); -} - -TEST(Mips64ManagedRegister, Equals) { - ManagedRegister no_reg = ManagedRegister::NoRegister(); - EXPECT_TRUE(no_reg.Equals(Mips64ManagedRegister::NoRegister())); - EXPECT_FALSE(no_reg.Equals(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(no_reg.Equals(Mips64ManagedRegister::FromGpuRegister(A1))); - EXPECT_FALSE(no_reg.Equals(Mips64ManagedRegister::FromGpuRegister(S2))); - EXPECT_FALSE(no_reg.Equals(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(no_reg.Equals(Mips64ManagedRegister::FromVectorRegister(W0))); - - Mips64ManagedRegister reg_ZERO = Mips64ManagedRegister::FromGpuRegister(ZERO); - EXPECT_FALSE(reg_ZERO.Equals(Mips64ManagedRegister::NoRegister())); - EXPECT_TRUE(reg_ZERO.Equals(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg_ZERO.Equals(Mips64ManagedRegister::FromGpuRegister(A1))); - EXPECT_FALSE(reg_ZERO.Equals(Mips64ManagedRegister::FromGpuRegister(S2))); - EXPECT_FALSE(reg_ZERO.Equals(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg_ZERO.Equals(Mips64ManagedRegister::FromVectorRegister(W0))); - - Mips64ManagedRegister reg_A1 = Mips64ManagedRegister::FromGpuRegister(A1); - EXPECT_FALSE(reg_A1.Equals(Mips64ManagedRegister::NoRegister())); - EXPECT_FALSE(reg_A1.Equals(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg_A1.Equals(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_TRUE(reg_A1.Equals(Mips64ManagedRegister::FromGpuRegister(A1))); - EXPECT_FALSE(reg_A1.Equals(Mips64ManagedRegister::FromGpuRegister(S2))); - EXPECT_FALSE(reg_A1.Equals(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg_A1.Equals(Mips64ManagedRegister::FromVectorRegister(W0))); - - Mips64ManagedRegister reg_S2 = Mips64ManagedRegister::FromGpuRegister(S2); - EXPECT_FALSE(reg_S2.Equals(Mips64ManagedRegister::NoRegister())); - EXPECT_FALSE(reg_S2.Equals(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg_S2.Equals(Mips64ManagedRegister::FromGpuRegister(A1))); - EXPECT_FALSE(reg_S2.Equals(Mips64ManagedRegister::FromGpuRegister(S1))); - EXPECT_TRUE(reg_S2.Equals(Mips64ManagedRegister::FromGpuRegister(S2))); - EXPECT_FALSE(reg_S2.Equals(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg_S2.Equals(Mips64ManagedRegister::FromVectorRegister(W0))); - - Mips64ManagedRegister reg_F0 = Mips64ManagedRegister::FromFpuRegister(F0); - EXPECT_FALSE(reg_F0.Equals(Mips64ManagedRegister::NoRegister())); - EXPECT_FALSE(reg_F0.Equals(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg_F0.Equals(Mips64ManagedRegister::FromGpuRegister(A1))); - EXPECT_FALSE(reg_F0.Equals(Mips64ManagedRegister::FromGpuRegister(S2))); - EXPECT_TRUE(reg_F0.Equals(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg_F0.Equals(Mips64ManagedRegister::FromFpuRegister(F1))); - EXPECT_FALSE(reg_F0.Equals(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg_F0.Equals(Mips64ManagedRegister::FromVectorRegister(W0))); - - Mips64ManagedRegister reg_F31 = Mips64ManagedRegister::FromFpuRegister(F31); - EXPECT_FALSE(reg_F31.Equals(Mips64ManagedRegister::NoRegister())); - EXPECT_FALSE(reg_F31.Equals(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg_F31.Equals(Mips64ManagedRegister::FromGpuRegister(A1))); - EXPECT_FALSE(reg_F31.Equals(Mips64ManagedRegister::FromGpuRegister(S2))); - EXPECT_FALSE(reg_F31.Equals(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg_F31.Equals(Mips64ManagedRegister::FromFpuRegister(F1))); - EXPECT_TRUE(reg_F31.Equals(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg_F31.Equals(Mips64ManagedRegister::FromVectorRegister(W0))); - - Mips64ManagedRegister reg_W0 = Mips64ManagedRegister::FromVectorRegister(W0); - EXPECT_FALSE(reg_W0.Equals(Mips64ManagedRegister::NoRegister())); - EXPECT_FALSE(reg_W0.Equals(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg_W0.Equals(Mips64ManagedRegister::FromGpuRegister(A1))); - EXPECT_FALSE(reg_W0.Equals(Mips64ManagedRegister::FromGpuRegister(S1))); - EXPECT_FALSE(reg_W0.Equals(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_TRUE(reg_W0.Equals(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg_W0.Equals(Mips64ManagedRegister::FromVectorRegister(W1))); - EXPECT_FALSE(reg_W0.Equals(Mips64ManagedRegister::FromVectorRegister(W31))); - - Mips64ManagedRegister reg_W31 = Mips64ManagedRegister::FromVectorRegister(W31); - EXPECT_FALSE(reg_W31.Equals(Mips64ManagedRegister::NoRegister())); - EXPECT_FALSE(reg_W31.Equals(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg_W31.Equals(Mips64ManagedRegister::FromGpuRegister(A1))); - EXPECT_FALSE(reg_W31.Equals(Mips64ManagedRegister::FromGpuRegister(S1))); - EXPECT_FALSE(reg_W31.Equals(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg_W31.Equals(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg_W31.Equals(Mips64ManagedRegister::FromVectorRegister(W1))); - EXPECT_TRUE(reg_W31.Equals(Mips64ManagedRegister::FromVectorRegister(W31))); -} - -TEST(Mips64ManagedRegister, Overlaps) { - Mips64ManagedRegister reg = Mips64ManagedRegister::FromFpuRegister(F0); - Mips64ManagedRegister reg_o = Mips64ManagedRegister::FromVectorRegister(W0); - EXPECT_TRUE(reg.Overlaps(reg_o)); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_EQ(F0, reg_o.AsOverlappingFpuRegister()); - EXPECT_EQ(W0, reg.AsOverlappingVectorRegister()); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromFpuRegister(F4); - reg_o = Mips64ManagedRegister::FromVectorRegister(W4); - EXPECT_TRUE(reg.Overlaps(reg_o)); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_EQ(F4, reg_o.AsOverlappingFpuRegister()); - EXPECT_EQ(W4, reg.AsOverlappingVectorRegister()); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromFpuRegister(F16); - reg_o = Mips64ManagedRegister::FromVectorRegister(W16); - EXPECT_TRUE(reg.Overlaps(reg_o)); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_EQ(F16, reg_o.AsOverlappingFpuRegister()); - EXPECT_EQ(W16, reg.AsOverlappingVectorRegister()); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromFpuRegister(F31); - reg_o = Mips64ManagedRegister::FromVectorRegister(W31); - EXPECT_TRUE(reg.Overlaps(reg_o)); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_EQ(F31, reg_o.AsOverlappingFpuRegister()); - EXPECT_EQ(W31, reg.AsOverlappingVectorRegister()); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromVectorRegister(W0); - reg_o = Mips64ManagedRegister::FromFpuRegister(F0); - EXPECT_TRUE(reg.Overlaps(reg_o)); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_EQ(W0, reg_o.AsOverlappingVectorRegister()); - EXPECT_EQ(F0, reg.AsOverlappingFpuRegister()); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromVectorRegister(W4); - reg_o = Mips64ManagedRegister::FromFpuRegister(F4); - EXPECT_TRUE(reg.Overlaps(reg_o)); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_EQ(W4, reg_o.AsOverlappingVectorRegister()); - EXPECT_EQ(F4, reg.AsOverlappingFpuRegister()); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromVectorRegister(W16); - reg_o = Mips64ManagedRegister::FromFpuRegister(F16); - EXPECT_TRUE(reg.Overlaps(reg_o)); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_EQ(W16, reg_o.AsOverlappingVectorRegister()); - EXPECT_EQ(F16, reg.AsOverlappingFpuRegister()); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromVectorRegister(W31); - reg_o = Mips64ManagedRegister::FromFpuRegister(F31); - EXPECT_TRUE(reg.Overlaps(reg_o)); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_EQ(W31, reg_o.AsOverlappingVectorRegister()); - EXPECT_EQ(F31, reg.AsOverlappingFpuRegister()); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromGpuRegister(ZERO); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromGpuRegister(A0); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromGpuRegister(S0); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); - - reg = Mips64ManagedRegister::FromGpuRegister(RA); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(ZERO))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(A0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(S0))); - EXPECT_TRUE(reg.Overlaps(Mips64ManagedRegister::FromGpuRegister(RA))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromFpuRegister(F31))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W0))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W4))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W16))); - EXPECT_FALSE(reg.Overlaps(Mips64ManagedRegister::FromVectorRegister(W31))); -} - -} // namespace mips64 -} // namespace art diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 4b073bde0b..55f7691514 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -59,96 +59,11 @@ std::ostream& operator<<(std::ostream& os, const Address& addr) { } } -uint8_t X86Assembler::EmitVexByteZero(bool is_two_byte) { - uint8_t vex_zero = 0xC0; - if (!is_two_byte) { - vex_zero |= 0xC4; - } else { - vex_zero |= 0xC5; - } - return vex_zero; -} - -uint8_t X86Assembler::EmitVexByte1(bool r, bool x, bool b, int mmmmm ) { - // VEX Byte 1 - uint8_t vex_prefix = 0; - if (!r) { - vex_prefix |= 0x80; // VEX.R - } - if (!x) { - vex_prefix |= 0x40; // VEX.X - } - if (!b) { - vex_prefix |= 0x20; // VEX.B - } - - // VEX.mmmmm - switch (mmmmm) { - case 1: - // implied 0F leading opcode byte - vex_prefix |= 0x01; - break; - case 2: - // implied leading 0F 38 opcode byte - vex_prefix |= 0x02; - break; - case 3: - // implied leading OF 3A opcode byte - vex_prefix |= 0x03; - break; - default: - LOG(FATAL) << "unknown opcode bytes"; - } - return vex_prefix; -} - -uint8_t X86Assembler::EmitVexByte2(bool w, int l, X86ManagedRegister operand, int pp) { - uint8_t vex_prefix = 0; - // VEX Byte 2 - if (w) { - vex_prefix |= 0x80; - } - // VEX.vvvv - if (operand.IsXmmRegister()) { - XmmRegister vvvv = operand.AsXmmRegister(); - int inverted_reg = 15-static_cast<int>(vvvv); - uint8_t reg = static_cast<uint8_t>(inverted_reg); - vex_prefix |= ((reg & 0x0F) << 3); - } else if (operand.IsCpuRegister()) { - Register vvvv = operand.AsCpuRegister(); - int inverted_reg = 15 - static_cast<int>(vvvv); - uint8_t reg = static_cast<uint8_t>(inverted_reg); - vex_prefix |= ((reg & 0x0F) << 3); - } - - // VEX.L - if (l == 256) { - vex_prefix |= 0x04; +bool X86Assembler::CpuHasAVXorAVX2FeatureFlag() { + if (has_AVX_ || has_AVX2_) { + return true; } - - // VEX.pp - switch (pp) { - case 0: - // SIMD Pefix - None - vex_prefix |= 0x00; - break; - case 1: - // SIMD Prefix - 66 - vex_prefix |= 0x01; - break; - case 2: - // SIMD Prefix - F3 - vex_prefix |= 0x02; - break; - case 3: - // SIMD Prefix - F2 - vex_prefix |= 0x03; - break; - default: - LOG(FATAL) << "unknown SIMD Prefix"; - } - - return vex_prefix; + return false; } void X86Assembler::call(Register reg) { @@ -273,15 +188,11 @@ void X86Assembler::movntl(const Address& dst, Register src) { void X86Assembler::blsi(Register dst, Register src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - uint8_t byte_zero = EmitVexByteZero(/*is_two_byte=*/ false); - uint8_t byte_one = EmitVexByte1(/*r=*/ false, - /*x=*/ false, - /*b=*/ false, - /*mmmmm=*/ 2); - uint8_t byte_two = EmitVexByte2(/*w=*/ false, - /*l=*/ 128, - X86ManagedRegister::FromCpuRegister(dst), - /*pp=*/ 0); + uint8_t byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ false); + uint8_t byte_one = EmitVexPrefixByteOne(false, false, false, SET_VEX_M_0F_38); + uint8_t byte_two = EmitVexPrefixByteTwo(false, + X86ManagedRegister::FromCpuRegister(dst), + SET_VEX_L_128, SET_VEX_PP_NONE); EmitUint8(byte_zero); EmitUint8(byte_one); EmitUint8(byte_two); @@ -291,15 +202,11 @@ void X86Assembler::blsi(Register dst, Register src) { void X86Assembler::blsmsk(Register dst, Register src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - uint8_t byte_zero = EmitVexByteZero(/*is_two_byte=*/ false); - uint8_t byte_one = EmitVexByte1(/*r=*/ false, - /*x=*/ false, - /*b=*/ false, - /*mmmmm=*/ 2); - uint8_t byte_two = EmitVexByte2(/*w=*/ false, - /*l=*/ 128, - X86ManagedRegister::FromCpuRegister(dst), - /*pp=*/ 0); + uint8_t byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ false); + uint8_t byte_one = EmitVexPrefixByteOne(false, false, false, SET_VEX_M_0F_38); + uint8_t byte_two = EmitVexPrefixByteTwo(false, + X86ManagedRegister::FromCpuRegister(dst), + SET_VEX_L_128, SET_VEX_PP_NONE); EmitUint8(byte_zero); EmitUint8(byte_one); EmitUint8(byte_two); @@ -309,15 +216,11 @@ void X86Assembler::blsmsk(Register dst, Register src) { void X86Assembler::blsr(Register dst, Register src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - uint8_t byte_zero = EmitVexByteZero(/*is_two_byte=*/ false); - uint8_t byte_one = EmitVexByte1(/*r=*/ false, - /*x=*/ false, - /*b=*/ false, - /*mmmmm=*/ 2); - uint8_t byte_two = EmitVexByte2(/*w=*/ false, - /*l=*/ 128, - X86ManagedRegister::FromCpuRegister(dst), - /*pp=*/ 0); + uint8_t byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ false); + uint8_t byte_one = EmitVexPrefixByteOne(false, false, false, SET_VEX_M_0F_38); + uint8_t byte_two = EmitVexPrefixByteTwo(false, + X86ManagedRegister::FromCpuRegister(dst), + SET_VEX_L_128, SET_VEX_PP_NONE); EmitUint8(byte_zero); EmitUint8(byte_one); EmitUint8(byte_two); @@ -516,44 +419,165 @@ void X86Assembler::setb(Condition condition, Register dst) { void X86Assembler::movaps(XmmRegister dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovaps(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x0F); EmitUint8(0x28); EmitXmmRegisterOperand(dst, src); } +/**VEX.128.0F.WIG 28 /r VMOVAPS xmm1, xmm2*/ +void X86Assembler::vmovaps(XmmRegister dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix*/ + uint8_t byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.*/ + uint8_t byte_one = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(byte_zero); + EmitUint8(byte_one); + /**Instruction Opcode*/ + EmitUint8(0x28); + /**Instruction Operands*/ + EmitXmmRegisterOperand(dst, src); +} void X86Assembler::movaps(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovaps(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x0F); EmitUint8(0x28); EmitOperand(dst, src); } +/**VEX.128.0F.WIG 28 /r VMOVAPS xmm1, m128*/ +void X86Assembler::vmovaps(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix*/ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.*/ + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + /**Instruction Opcode*/ + EmitUint8(0x28); + /**Instruction Operands*/ + EmitOperand(dst, src); +} void X86Assembler::movups(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovups(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x0F); EmitUint8(0x10); EmitOperand(dst, src); } +/**VEX.128.0F.WIG 10 /r VMOVUPS xmm1, m128*/ +void X86Assembler::vmovups(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix*/ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.*/ + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + /*Instruction Opcode*/ + EmitUint8(0x10); + /*Instruction Operands*/ + EmitOperand(dst, src); +} void X86Assembler::movaps(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovaps(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x0F); EmitUint8(0x29); EmitOperand(src, dst); } +/**VEX.128.0F.WIG 29 /r VMOVAPS m128, xmm1*/ +void X86Assembler::vmovaps(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix*/ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.*/ + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + /**Instruction Opcode*/ + EmitUint8(0x29); + /**Instruction Operands*/ + EmitOperand(src, dst); +} void X86Assembler::movups(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovups(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x0F); EmitUint8(0x11); EmitOperand(src, dst); } +/**VEX.128.0F.WIG 11 /r VMOVUPS m128, xmm1*/ +void X86Assembler::vmovups(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix*/ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.*/ + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x11); + // Instruction Operands + EmitOperand(src, dst); +} + void X86Assembler::movss(XmmRegister dst, const Address& src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -679,6 +703,20 @@ void X86Assembler::addps(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vaddps(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(add_left), + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0x58); + EmitXmmRegisterOperand(dst, add_right); +} void X86Assembler::subps(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -687,6 +725,18 @@ void X86Assembler::subps(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vsubps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t byte_zero = 0x00, byte_one = 0x00; + byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(src1); + byte_one = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + EmitUint8(byte_zero); + EmitUint8(byte_one); + EmitUint8(0x5C); + EmitXmmRegisterOperand(dst, src2); +} void X86Assembler::mulps(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -695,6 +745,20 @@ void X86Assembler::mulps(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vmulps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0x59); + EmitXmmRegisterOperand(dst, src2); +} void X86Assembler::divps(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -704,7 +768,27 @@ void X86Assembler::divps(XmmRegister dst, XmmRegister src) { } +void X86Assembler::vdivps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0x5E); + EmitXmmRegisterOperand(dst, src2); +} + + void X86Assembler::movapd(XmmRegister dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovapd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitUint8(0x0F); @@ -712,8 +796,32 @@ void X86Assembler::movapd(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +/**VEX.128.66.0F.WIG 28 /r VMOVAPD xmm1, xmm2*/ +void X86Assembler::vmovapd(XmmRegister dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix*/ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.*/ + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg , + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x28); + // Instruction Operands + EmitXmmRegisterOperand(dst, src); +} void X86Assembler::movapd(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovapd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitUint8(0x0F); @@ -721,8 +829,32 @@ void X86Assembler::movapd(XmmRegister dst, const Address& src) { EmitOperand(dst, src); } +/**VEX.128.66.0F.WIG 28 /r VMOVAPD xmm1, m128*/ +void X86Assembler::vmovapd(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix*/ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.*/ + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x28); + // Instruction Operands + EmitOperand(dst, src); +} void X86Assembler::movupd(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovupd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitUint8(0x0F); @@ -730,8 +862,33 @@ void X86Assembler::movupd(XmmRegister dst, const Address& src) { EmitOperand(dst, src); } +/**VEX.128.66.0F.WIG 10 /r VMOVUPD xmm1, m128*/ +void X86Assembler::vmovupd(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix*/ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.*/ + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x10); + // Instruction Operands + EmitOperand(dst, src); +} + void X86Assembler::movapd(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovapd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitUint8(0x0F); @@ -739,8 +896,32 @@ void X86Assembler::movapd(const Address& dst, XmmRegister src) { EmitOperand(src, dst); } +/**VEX.128.66.0F.WIG 29 /r VMOVAPD m128, xmm1 */ +void X86Assembler::vmovapd(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix */ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.*/ + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x29); + // Instruction Operands + EmitOperand(src, dst); +} void X86Assembler::movupd(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovupd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitUint8(0x0F); @@ -748,6 +929,26 @@ void X86Assembler::movupd(const Address& dst, XmmRegister src) { EmitOperand(src, dst); } +/**VEX.128.66.0F.WIG 11 /r VMOVUPD m128, xmm1 */ +void X86Assembler::vmovupd(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix */ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + /**a REX prefix is necessary only if an instruction references one of the + extended registers or uses a 64-bit operand.**/ + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x11); + // Instruction Operands + EmitOperand(src, dst); +} void X86Assembler::flds(const Address& src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -896,6 +1097,21 @@ void X86Assembler::addpd(XmmRegister dst, XmmRegister src) { } +void X86Assembler::vaddpd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(add_left), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0x58); + EmitXmmRegisterOperand(dst, add_right); +} + + void X86Assembler::subpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -905,6 +1121,20 @@ void X86Assembler::subpd(XmmRegister dst, XmmRegister src) { } +void X86Assembler::vsubpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form*/ true); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0x5C); + EmitXmmRegisterOperand(dst, src2); +} + void X86Assembler::mulpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -913,6 +1143,20 @@ void X86Assembler::mulpd(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vmulpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0x59); + EmitXmmRegisterOperand(dst, src2); +} void X86Assembler::divpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -922,8 +1166,26 @@ void X86Assembler::divpd(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vdivpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0x5E); + EmitXmmRegisterOperand(dst, src2); +} void X86Assembler::movdqa(XmmRegister dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqa(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitUint8(0x0F); @@ -931,8 +1193,30 @@ void X86Assembler::movdqa(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +/**VEX.128.66.0F.WIG 6F /r VMOVDQA xmm1, xmm2 */ +void X86Assembler::vmovdqa(XmmRegister dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix */ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x6F); + // Instruction Operands + EmitXmmRegisterOperand(dst, src); +} void X86Assembler::movdqa(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqa(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitUint8(0x0F); @@ -940,8 +1224,30 @@ void X86Assembler::movdqa(XmmRegister dst, const Address& src) { EmitOperand(dst, src); } +/**VEX.128.66.0F.WIG 6F /r VMOVDQA xmm1, m128 */ +void X86Assembler::vmovdqa(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix */ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x6F); + // Instruction Operands + EmitOperand(dst, src); +} void X86Assembler::movdqu(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqu(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF3); EmitUint8(0x0F); @@ -949,8 +1255,30 @@ void X86Assembler::movdqu(XmmRegister dst, const Address& src) { EmitOperand(dst, src); } +/**VEX.128.F3.0F.WIG 6F /r VMOVDQU xmm1, m128 */ +void X86Assembler::vmovdqu(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix */ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_F3); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x6F); + // Instruction Operands + EmitOperand(dst, src); +} void X86Assembler::movdqa(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqa(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitUint8(0x0F); @@ -958,8 +1286,31 @@ void X86Assembler::movdqa(const Address& dst, XmmRegister src) { EmitOperand(src, dst); } +/**VEX.128.66.0F.WIG 7F /r VMOVDQA m128, xmm1 */ +void X86Assembler::vmovdqa(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + /**Instruction VEX Prefix */ + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x7F); + // Instruction Operands + EmitOperand(src, dst); +} + void X86Assembler::movdqu(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqu(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF3); EmitUint8(0x0F); @@ -967,6 +1318,24 @@ void X86Assembler::movdqu(const Address& dst, XmmRegister src) { EmitOperand(src, dst); } +/**VEX.128.F3.0F.WIG 7F /r VMOVDQU m128, xmm1 */ +void X86Assembler::vmovdqu(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + // Instruction VEX Prefix + uint8_t ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86(); + uint8_t ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_F3); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x7F); + // Instruction Operands + EmitOperand(src, dst); +} void X86Assembler::paddb(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -976,6 +1345,18 @@ void X86Assembler::paddb(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vpaddb(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteOne = 0x00, ByteZero = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(add_left); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xFC); + EmitXmmRegisterOperand(dst, add_right); +} void X86Assembler::psubb(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -985,6 +1366,18 @@ void X86Assembler::psubb(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vpsubb(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(add_left); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xF8); + EmitXmmRegisterOperand(dst, add_right); +} void X86Assembler::paddw(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -994,6 +1387,18 @@ void X86Assembler::paddw(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vpaddw(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(add_left); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xFD); + EmitXmmRegisterOperand(dst, add_right); +} void X86Assembler::psubw(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1003,6 +1408,18 @@ void X86Assembler::psubw(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vpsubw(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(add_left); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xF9); + EmitXmmRegisterOperand(dst, add_right); +} void X86Assembler::pmullw(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1021,6 +1438,18 @@ void X86Assembler::paddd(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vpaddd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(add_left); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xFE); + EmitXmmRegisterOperand(dst, add_right); +} void X86Assembler::psubd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1031,6 +1460,20 @@ void X86Assembler::psubd(XmmRegister dst, XmmRegister src) { } +void X86Assembler::vpsubd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(add_left); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xFA); + EmitXmmRegisterOperand(dst, add_right); +} + + void X86Assembler::pmulld(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1040,6 +1483,40 @@ void X86Assembler::pmulld(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vpmulld(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ false); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + /*X=*/ false, + /*B=*/ false, + SET_VEX_M_0F_38); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(ByteTwo); + EmitUint8(0x40); + EmitRegisterOperand(dst, src2); +} + +void X86Assembler::vpmullw(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xD5); + EmitRegisterOperand(dst, src2); +} void X86Assembler::paddq(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1049,6 +1526,19 @@ void X86Assembler::paddq(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vpaddq(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(add_left); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xD4); + EmitXmmRegisterOperand(dst, add_right); +} + void X86Assembler::psubq(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1058,6 +1548,18 @@ void X86Assembler::psubq(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::vpsubq(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(add_left); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xFB); + EmitXmmRegisterOperand(dst, add_right); +} void X86Assembler::paddusb(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1370,6 +1872,68 @@ void X86Assembler::pxor(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +/* VEX.128.66.0F.WIG EF /r VPXOR xmm1, xmm2, xmm3/m128 */ +void X86Assembler::vpxor(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0xEF); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} + +/* VEX.128.0F.WIG 57 /r VXORPS xmm1,xmm2, xmm3/m128 */ +void X86Assembler::vxorps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x57); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} + +/* VEX.128.66.0F.WIG 57 /r VXORPD xmm1,xmm2, xmm3/m128 */ +void X86Assembler::vxorpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x57); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} void X86Assembler::andpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1413,26 +1977,67 @@ void X86Assembler::pand(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } -void X86Assembler::andn(Register dst, Register src1, Register src2) { +/* VEX.128.66.0F.WIG DB /r VPAND xmm1, xmm2, xmm3/m128 */ +void X86Assembler::vpand(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); AssemblerBuffer::EnsureCapacity ensured(&buffer_); - uint8_t byte_zero = EmitVexByteZero(/*is_two_byte=*/ false); - uint8_t byte_one = EmitVexByte1(/*r=*/ false, - /*x=*/ false, - /*b=*/ false, - /*mmmmm=*/ 2); - uint8_t byte_two = EmitVexByte2(/*w=*/ false, - /*l=*/ 128, - X86ManagedRegister::FromCpuRegister(src1), - /*pp=*/ 0); - EmitUint8(byte_zero); - EmitUint8(byte_one); - EmitUint8(byte_two); - // Opcode field - EmitUint8(0xF2); - EmitRegisterOperand(dst, src2); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0xDB); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} + +/* VEX.128.0F 54 /r VANDPS xmm1,xmm2, xmm3/m128 */ +void X86Assembler::vandps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x54); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} + +/* VEX.128.66.0F 54 /r VANDPD xmm1, xmm2, xmm3/m128 */ +void X86Assembler::vandpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x54); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); } - void X86Assembler::andnpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1458,6 +2063,68 @@ void X86Assembler::pandn(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +/* VEX.128.66.0F.WIG DF /r VPANDN xmm1, xmm2, xmm3/m128 */ +void X86Assembler::vpandn(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0xDF); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} + +/* VEX.128.0F 55 /r VANDNPS xmm1, xmm2, xmm3/m128 */ +void X86Assembler::vandnps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x55); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} + +/* VEX.128.66.0F 55 /r VANDNPD xmm1, xmm2, xmm3/m128 */ +void X86Assembler::vandnpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x55); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} void X86Assembler::orpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1475,6 +2142,24 @@ void X86Assembler::orps(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +void X86Assembler::andn(Register dst, Register src1, Register src2) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ false); + uint8_t byte_one = EmitVexPrefixByteOne(/*R=*/ false, + /*X=*/ false, + /*B=*/ false, + SET_VEX_M_0F_38); + uint8_t byte_two = EmitVexPrefixByteTwo(/*W=*/ false, + X86ManagedRegister::FromCpuRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(byte_zero); + EmitUint8(byte_one); + EmitUint8(byte_two); + // Opcode field + EmitUint8(0xF2); + EmitRegisterOperand(dst, src2); +} void X86Assembler::por(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1484,6 +2169,68 @@ void X86Assembler::por(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst, src); } +/* VEX.128.66.0F.WIG EB /r VPOR xmm1, xmm2, xmm3/m128 */ +void X86Assembler::vpor(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0xEB); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} + +/* VEX.128.0F 56 /r VORPS xmm1,xmm2, xmm3/m128 */ +void X86Assembler::vorps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_NONE); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x56); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} + +/* VEX.128.66.0F 56 /r VORPD xmm1,xmm2, xmm3/m128 */ +void X86Assembler::vorpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + /* Instruction VEX Prefix */ + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ true); + /* REX prefix is necessary only if an instruction references one of extended + registers or uses a 64-bit operand. */ + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, + X86ManagedRegister::FromXmmRegister(src1), + SET_VEX_L_128, + SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + // Instruction Opcode + EmitUint8(0x56); + // Instruction Operands + EmitXmmRegisterOperand(dst, src2); +} void X86Assembler::pavgb(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1521,6 +2268,20 @@ void X86Assembler::pmaddwd(XmmRegister dst, XmmRegister src) { } +void X86Assembler::vpmaddwd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00; + ByteZero = EmitVexPrefixByteZero(/* is_twobyte_form=*/ true); + X86ManagedRegister vvvv_reg = X86ManagedRegister::FromXmmRegister(src1); + ByteOne = EmitVexPrefixByteOne(/*R=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(0xF5); + EmitXmmRegisterOperand(dst, src2); +} + + void X86Assembler::phaddw(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -3143,5 +3904,139 @@ size_t ConstantArea::AddFloat(float v) { return AddInt32(bit_cast<int32_t, float>(v)); } +uint8_t X86Assembler::EmitVexPrefixByteZero(bool is_twobyte_form) { + /**Vex Byte 0, + Bits [7:0] must contain the value 11000101b (0xC5) for 2-byte Vex + Bits [7:0] must contain the value 11000100b (0xC4) for 3-byte Vex */ + uint8_t vex_prefix = 0xC0; + if (is_twobyte_form) { + // 2-Byte Vex + vex_prefix |= TWO_BYTE_VEX; + } else { + // 3-Byte Vex + vex_prefix |= THREE_BYTE_VEX; + } + return vex_prefix; +} + +uint8_t X86Assembler::EmitVexPrefixByteOne(bool R, + bool X, + bool B, + int SET_VEX_M) { + /**Vex Byte 1, */ + uint8_t vex_prefix = VEX_INIT; + /** Bit[7] This bit needs to be set to '1' + otherwise the instruction is LES or LDS */ + if (!R) { + // R . + vex_prefix |= SET_VEX_R; + } + /** Bit[6] This bit needs to be set to '1' + otherwise the instruction is LES or LDS */ + if (!X) { + // X . + vex_prefix |= SET_VEX_X; + } + /** Bit[5] This bit needs to be set to '1' */ + if (!B) { + // B . + vex_prefix |= SET_VEX_B; + } + /** Bits[4:0], */ + vex_prefix |= SET_VEX_M; + return vex_prefix; +} + +uint8_t X86Assembler::EmitVexPrefixByteOne(bool R, + X86ManagedRegister operand, + int SET_VEX_L, + int SET_VEX_PP) { + /**Vex Byte 1, */ + uint8_t vex_prefix = VEX_INIT; + /** Bit[7] This bit needs to be set to '1' + otherwise the instruction is LES or LDS */ + if (!R) { + // R . + vex_prefix |= SET_VEX_R; + } + /**Bits[6:3] - 'vvvv' the source or dest register specifier */ + if (operand.IsNoRegister()) { + vex_prefix |= 0x78; + } else if (operand.IsXmmRegister()) { + XmmRegister vvvv = operand.AsXmmRegister(); + int inverted_reg = 15 - static_cast<int>(vvvv); + uint8_t reg = static_cast<uint8_t>(inverted_reg); + vex_prefix |= ((reg & 0x0F) << 3); + } else if (operand.IsCpuRegister()) { + Register vvvv = operand.AsCpuRegister(); + int inverted_reg = 15 - static_cast<int>(vvvv); + uint8_t reg = static_cast<uint8_t>(inverted_reg); + vex_prefix |= ((reg & 0x0F) << 3); + } + /** Bit[2] - "L" If VEX.L = 1 indicates 256-bit vector operation , + VEX.L = 0 indicates 128 bit vector operation */ + vex_prefix |= SET_VEX_L; + /** Bits[1:0] - "pp" */ + vex_prefix |= SET_VEX_PP; + return vex_prefix; +} + +uint8_t X86Assembler::EmitVexPrefixByteTwo(bool W, + X86ManagedRegister operand, + int SET_VEX_L, + int SET_VEX_PP) { + /** Vex Byte 2, */ + uint8_t vex_prefix = VEX_INIT; + /** Bit[7] This bits needs to be set to '1' with default value. + When using C4H form of VEX prefix, W value is ignored */ + if (W) { + vex_prefix |= SET_VEX_W; + } + /** Bits[6:3] - 'vvvv' the source or dest register specifier */ + if (operand.IsXmmRegister()) { + XmmRegister vvvv = operand.AsXmmRegister(); + int inverted_reg = 15 - static_cast<int>(vvvv); + uint8_t reg = static_cast<uint8_t>(inverted_reg); + vex_prefix |= ((reg & 0x0F) << 3); + } else if (operand.IsCpuRegister()) { + Register vvvv = operand.AsCpuRegister(); + int inverted_reg = 15 - static_cast<int>(vvvv); + uint8_t reg = static_cast<uint8_t>(inverted_reg); + vex_prefix |= ((reg & 0x0F) << 3); + } + /** Bit[2] - "L" If VEX.L = 1 indicates 256-bit vector operation , + VEX.L = 0 indicates 128 bit vector operation */ + vex_prefix |= SET_VEX_L; + // Bits[1:0] - "pp" + vex_prefix |= SET_VEX_PP; + return vex_prefix; +} + +uint8_t X86Assembler::EmitVexPrefixByteTwo(bool W, + int SET_VEX_L, + int SET_VEX_PP) { + /**Vex Byte 2, */ + uint8_t vex_prefix = VEX_INIT; + + /** Bit[7] This bits needs to be set to '1' with default value. + When using C4H form of VEX prefix, W value is ignored */ + if (W) { + vex_prefix |= SET_VEX_W; + } + /** Bits[6:3] - 'vvvv' the source or dest register specifier, + if unused set 1111 */ + vex_prefix |= (0x0F << 3); + + /** Bit[2] - "L" If VEX.L = 1 indicates 256-bit vector operation , + VEX.L = 0 indicates 128 bit vector operation */ + vex_prefix |= SET_VEX_L; + + /** Bits[1:0] - "pp" */ + if (SET_VEX_PP != SET_VEX_PP_NONE) { + vex_prefix |= SET_VEX_PP; + } + return vex_prefix; +} + } // namespace x86 } // namespace art diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index 275e5c1234..27fde26c80 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -19,6 +19,7 @@ #include <vector> +#include "arch/x86/instruction_set_features_x86.h" #include "base/arena_containers.h" #include "base/array_ref.h" #include "base/bit_utils.h" @@ -308,8 +309,12 @@ class ConstantArea { class X86Assembler final : public Assembler { public: - explicit X86Assembler(ArenaAllocator* allocator) - : Assembler(allocator), constant_area_(allocator) {} + explicit X86Assembler(ArenaAllocator* allocator, + const X86InstructionSetFeatures* instruction_set_features = nullptr) + : Assembler(allocator), + constant_area_(allocator), + has_AVX_(instruction_set_features != nullptr ? instruction_set_features->HasAVX() : false), + has_AVX2_(instruction_set_features != nullptr ? instruction_set_features->HasAVX2() :false) {} virtual ~X86Assembler() {} /* @@ -385,6 +390,12 @@ class X86Assembler final : public Assembler { void movaps(const Address& dst, XmmRegister src); // store aligned void movups(const Address& dst, XmmRegister src); // store unaligned + void vmovaps(XmmRegister dst, XmmRegister src); // move + void vmovaps(XmmRegister dst, const Address& src); // load aligned + void vmovups(XmmRegister dst, const Address& src); // load unaligned + void vmovaps(const Address& dst, XmmRegister src); // store aligned + void vmovups(const Address& dst, XmmRegister src); // store unaligned + void movss(XmmRegister dst, const Address& src); void movss(const Address& dst, XmmRegister src); void movss(XmmRegister dst, XmmRegister src); @@ -406,12 +417,28 @@ class X86Assembler final : public Assembler { void mulps(XmmRegister dst, XmmRegister src); void divps(XmmRegister dst, XmmRegister src); + void vmulps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vmulpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vdivps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vdivpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); + + void vaddps(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vsubps(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vsubpd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vaddpd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void movapd(XmmRegister dst, XmmRegister src); // move void movapd(XmmRegister dst, const Address& src); // load aligned void movupd(XmmRegister dst, const Address& src); // load unaligned void movapd(const Address& dst, XmmRegister src); // store aligned void movupd(const Address& dst, XmmRegister src); // store unaligned + void vmovapd(XmmRegister dst, XmmRegister src); // move + void vmovapd(XmmRegister dst, const Address& src); // load aligned + void vmovupd(XmmRegister dst, const Address& src); // load unaligned + void vmovapd(const Address& dst, XmmRegister src); // store aligned + void vmovupd(const Address& dst, XmmRegister src); // store unaligned + void movsd(XmmRegister dst, const Address& src); void movsd(const Address& dst, XmmRegister src); void movsd(XmmRegister dst, XmmRegister src); @@ -439,20 +466,41 @@ class X86Assembler final : public Assembler { void movdqa(const Address& dst, XmmRegister src); // store aligned void movdqu(const Address& dst, XmmRegister src); // store unaligned + void vmovdqa(XmmRegister dst, XmmRegister src); // move + void vmovdqa(XmmRegister dst, const Address& src); // load aligned + void vmovdqu(XmmRegister dst, const Address& src); // load unaligned + void vmovdqa(const Address& dst, XmmRegister src); // store aligned + void vmovdqu(const Address& dst, XmmRegister src); // store unaligned + void paddb(XmmRegister dst, XmmRegister src); // no addr variant (for now) void psubb(XmmRegister dst, XmmRegister src); + void vpaddb(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vpaddw(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void paddw(XmmRegister dst, XmmRegister src); void psubw(XmmRegister dst, XmmRegister src); void pmullw(XmmRegister dst, XmmRegister src); + void vpmullw(XmmRegister dst, XmmRegister src1, XmmRegister src2); + + void vpsubb(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vpsubw(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vpsubd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void paddd(XmmRegister dst, XmmRegister src); void psubd(XmmRegister dst, XmmRegister src); void pmulld(XmmRegister dst, XmmRegister src); + void vpmulld(XmmRegister dst, XmmRegister src1, XmmRegister src2); + + void vpaddd(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void paddq(XmmRegister dst, XmmRegister src); void psubq(XmmRegister dst, XmmRegister src); + void vpaddq(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vpsubq(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void paddusb(XmmRegister dst, XmmRegister src); void paddsb(XmmRegister dst, XmmRegister src); void paddusw(XmmRegister dst, XmmRegister src); @@ -497,26 +545,39 @@ class X86Assembler final : public Assembler { void xorps(XmmRegister dst, const Address& src); void xorps(XmmRegister dst, XmmRegister src); void pxor(XmmRegister dst, XmmRegister src); // no addr variant (for now) + void vpxor(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vxorps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vxorpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void andpd(XmmRegister dst, XmmRegister src); void andpd(XmmRegister dst, const Address& src); void andps(XmmRegister dst, XmmRegister src); void andps(XmmRegister dst, const Address& src); void pand(XmmRegister dst, XmmRegister src); // no addr variant (for now) + void vpand(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vandps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vandpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void andn(Register dst, Register src1, Register src2); // no addr variant (for now) void andnpd(XmmRegister dst, XmmRegister src); // no addr variant (for now) void andnps(XmmRegister dst, XmmRegister src); void pandn(XmmRegister dst, XmmRegister src); + void vpandn(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vandnps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vandnpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void orpd(XmmRegister dst, XmmRegister src); // no addr variant (for now) void orps(XmmRegister dst, XmmRegister src); void por(XmmRegister dst, XmmRegister src); + void vpor(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vorps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vorpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void pavgb(XmmRegister dst, XmmRegister src); // no addr variant (for now) void pavgw(XmmRegister dst, XmmRegister src); void psadbw(XmmRegister dst, XmmRegister src); void pmaddwd(XmmRegister dst, XmmRegister src); + void vpmaddwd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void phaddw(XmmRegister dst, XmmRegister src); void phaddd(XmmRegister dst, XmmRegister src); void haddps(XmmRegister dst, XmmRegister src); @@ -823,6 +884,8 @@ class X86Assembler final : public Assembler { // Return the current size of the constant area. size_t ConstantAreaSize() const { return constant_area_.GetSize(); } + bool CpuHasAVXorAVX2FeatureFlag(); + private: inline void EmitUint8(uint8_t value); inline void EmitInt32(int32_t value); @@ -842,12 +905,22 @@ class X86Assembler final : public Assembler { void EmitGenericShift(int rm, const Operand& operand, const Immediate& imm); void EmitGenericShift(int rm, const Operand& operand, Register shifter); - // Emit a 3 byte VEX Prefix - uint8_t EmitVexByteZero(bool is_two_byte); - uint8_t EmitVexByte1(bool r, bool x, bool b, int mmmmm); - uint8_t EmitVexByte2(bool w , int l , X86ManagedRegister operand, int pp); - + uint8_t EmitVexPrefixByteZero(bool is_twobyte_form); + uint8_t EmitVexPrefixByteOne(bool R, bool X, bool B, int SET_VEX_M); + uint8_t EmitVexPrefixByteOne(bool R, + X86ManagedRegister operand, + int SET_VEX_L, + int SET_VEX_PP); + uint8_t EmitVexPrefixByteTwo(bool W, + X86ManagedRegister operand, + int SET_VEX_L, + int SET_VEX_PP); + uint8_t EmitVexPrefixByteTwo(bool W, + int SET_VEX_L, + int SET_VEX_PP); ConstantArea constant_area_; + bool has_AVX_; // x86 256bit SIMD AVX. + bool has_AVX2_; // x86 256bit SIMD AVX 2.0. DISALLOW_COPY_AND_ASSIGN(X86Assembler); }; diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc index 1d8bfe7fa7..9253730797 100644 --- a/compiler/utils/x86/assembler_x86_test.cc +++ b/compiler/utils/x86/assembler_x86_test.cc @@ -148,6 +148,18 @@ class AssemblerX86Test : public AssemblerTest<x86::X86Assembler, std::vector<x86::XmmRegister*> fp_registers_; }; +class AssemblerX86AVXTest : public AssemblerX86Test { + public: + AssemblerX86AVXTest() + : instruction_set_features_(X86InstructionSetFeatures::FromVariant("kabylake", nullptr)) {} + protected: + x86::X86Assembler* CreateAssembler(ArenaAllocator* allocator) override { + return new (allocator) x86::X86Assembler(allocator, instruction_set_features_.get()); + } + private: + std::unique_ptr<const X86InstructionSetFeatures> instruction_set_features_; +}; + // // Test some repeat drivers used in the tests. // @@ -485,134 +497,326 @@ TEST_F(AssemblerX86Test, Movaps) { DriverStr(RepeatFF(&x86::X86Assembler::movaps, "movaps %{reg2}, %{reg1}"), "movaps"); } +TEST_F(AssemblerX86AVXTest, VMovaps) { + DriverStr(RepeatFF(&x86::X86Assembler::vmovaps, "vmovaps %{reg2}, %{reg1}"), "vmovaps"); +} + +TEST_F(AssemblerX86AVXTest, Movaps) { + DriverStr(RepeatFF(&x86::X86Assembler::movaps, "vmovaps %{reg2}, %{reg1}"), "avx_movaps"); +} + TEST_F(AssemblerX86Test, MovapsLoad) { DriverStr(RepeatFA(&x86::X86Assembler::movaps, "movaps {mem}, %{reg}"), "movaps_load"); } +TEST_F(AssemblerX86AVXTest, VMovapsLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::vmovaps, "vmovaps {mem}, %{reg}"), "vmovaps_load"); +} + +TEST_F(AssemblerX86AVXTest, MovapsLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::movaps, "vmovaps {mem}, %{reg}"), "avx_movaps_load"); +} + TEST_F(AssemblerX86Test, MovapsStore) { DriverStr(RepeatAF(&x86::X86Assembler::movaps, "movaps %{reg}, {mem}"), "movaps_store"); } +TEST_F(AssemblerX86AVXTest, VMovapsStore) { + DriverStr(RepeatAF(&x86::X86Assembler::vmovaps, "vmovaps %{reg}, {mem}"), "vmovaps_store"); +} + +TEST_F(AssemblerX86AVXTest, MovapsStore) { + DriverStr(RepeatAF(&x86::X86Assembler::movaps, "vmovaps %{reg}, {mem}"), "avx_movaps_store"); +} + TEST_F(AssemblerX86Test, MovupsLoad) { DriverStr(RepeatFA(&x86::X86Assembler::movups, "movups {mem}, %{reg}"), "movups_load"); } +TEST_F(AssemblerX86AVXTest, VMovupsLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::vmovups, "vmovups {mem}, %{reg}"), "vmovups_load"); +} + +TEST_F(AssemblerX86AVXTest, MovupsLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::movups, "vmovups {mem}, %{reg}"), "avx_movups_load"); +} + TEST_F(AssemblerX86Test, MovupsStore) { DriverStr(RepeatAF(&x86::X86Assembler::movups, "movups %{reg}, {mem}"), "movups_store"); } +TEST_F(AssemblerX86AVXTest, VMovupsStore) { + DriverStr(RepeatAF(&x86::X86Assembler::vmovups, "vmovups %{reg}, {mem}"), "vmovups_store"); +} + +TEST_F(AssemblerX86AVXTest, MovupsStore) { + DriverStr(RepeatAF(&x86::X86Assembler::movups, "vmovups %{reg}, {mem}"), "avx_movups_store"); +} + TEST_F(AssemblerX86Test, Movapd) { DriverStr(RepeatFF(&x86::X86Assembler::movapd, "movapd %{reg2}, %{reg1}"), "movapd"); } +TEST_F(AssemblerX86AVXTest, VMovapd) { + DriverStr(RepeatFF(&x86::X86Assembler::vmovapd, "vmovapd %{reg2}, %{reg1}"), "vmovapd"); +} + +TEST_F(AssemblerX86AVXTest, Movapd) { + DriverStr(RepeatFF(&x86::X86Assembler::movapd, "vmovapd %{reg2}, %{reg1}"), "avx_movapd"); +} + TEST_F(AssemblerX86Test, MovapdLoad) { DriverStr(RepeatFA(&x86::X86Assembler::movapd, "movapd {mem}, %{reg}"), "movapd_load"); } +TEST_F(AssemblerX86AVXTest, VMovapdLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::vmovapd, "vmovapd {mem}, %{reg}"), "vmovapd_load"); +} + +TEST_F(AssemblerX86AVXTest, MovapdLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::movapd, "vmovapd {mem}, %{reg}"), "avx_movapd_load"); +} + TEST_F(AssemblerX86Test, MovapdStore) { DriverStr(RepeatAF(&x86::X86Assembler::movapd, "movapd %{reg}, {mem}"), "movapd_store"); } +TEST_F(AssemblerX86AVXTest, VMovapdStore) { + DriverStr(RepeatAF(&x86::X86Assembler::vmovapd, "vmovapd %{reg}, {mem}"), "vmovapd_store"); +} + +TEST_F(AssemblerX86AVXTest, MovapdStore) { + DriverStr(RepeatAF(&x86::X86Assembler::movapd, "vmovapd %{reg}, {mem}"), "avx_movapd_store"); +} + TEST_F(AssemblerX86Test, MovupdLoad) { DriverStr(RepeatFA(&x86::X86Assembler::movupd, "movupd {mem}, %{reg}"), "movupd_load"); } +TEST_F(AssemblerX86AVXTest, VMovupdLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::vmovupd, "vmovupd {mem}, %{reg}"), "vmovupd_load"); +} + +TEST_F(AssemblerX86AVXTest, MovupdLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::movupd, "vmovupd {mem}, %{reg}"), "avx_movupd_load"); +} + TEST_F(AssemblerX86Test, MovupdStore) { DriverStr(RepeatAF(&x86::X86Assembler::movupd, "movupd %{reg}, {mem}"), "movupd_store"); } +TEST_F(AssemblerX86AVXTest, VMovupdStore) { + DriverStr(RepeatAF(&x86::X86Assembler::vmovupd, "vmovupd %{reg}, {mem}"), "vmovupd_store"); +} + +TEST_F(AssemblerX86AVXTest, MovupdStore) { + DriverStr(RepeatAF(&x86::X86Assembler::movupd, "vmovupd %{reg}, {mem}"), "avx_movupd_store"); +} + TEST_F(AssemblerX86Test, Movdqa) { DriverStr(RepeatFF(&x86::X86Assembler::movdqa, "movdqa %{reg2}, %{reg1}"), "movdqa"); } +TEST_F(AssemblerX86AVXTest, VMovdqa) { + DriverStr(RepeatFF(&x86::X86Assembler::vmovdqa, "vmovdqa %{reg2}, %{reg1}"), "vmovdqa"); +} + +TEST_F(AssemblerX86AVXTest, Movdqa) { + DriverStr(RepeatFF(&x86::X86Assembler::movdqa, "vmovdqa %{reg2}, %{reg1}"), "avx_movdqa"); +} + TEST_F(AssemblerX86Test, MovdqaLoad) { DriverStr(RepeatFA(&x86::X86Assembler::movdqa, "movdqa {mem}, %{reg}"), "movdqa_load"); } +TEST_F(AssemblerX86AVXTest, VMovdqaLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::vmovdqa, "vmovdqa {mem}, %{reg}"), "vmovdqa_load"); +} + +TEST_F(AssemblerX86AVXTest, MovdqaLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::movdqa, "vmovdqa {mem}, %{reg}"), "avx_movdqa_load"); +} + TEST_F(AssemblerX86Test, MovdqaStore) { DriverStr(RepeatAF(&x86::X86Assembler::movdqa, "movdqa %{reg}, {mem}"), "movdqa_store"); } +TEST_F(AssemblerX86AVXTest, VMovdqaStore) { + DriverStr(RepeatAF(&x86::X86Assembler::vmovdqa, "vmovdqa %{reg}, {mem}"), "vmovdqa_store"); +} + +TEST_F(AssemblerX86AVXTest, MovdqaStore) { + DriverStr(RepeatAF(&x86::X86Assembler::movdqa, "vmovdqa %{reg}, {mem}"), "avx_movdqa_store"); +} + TEST_F(AssemblerX86Test, MovdquLoad) { DriverStr(RepeatFA(&x86::X86Assembler::movdqu, "movdqu {mem}, %{reg}"), "movdqu_load"); } +TEST_F(AssemblerX86AVXTest, VMovdquLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::vmovdqu, "vmovdqu {mem}, %{reg}"), "vmovdqu_load"); +} + +TEST_F(AssemblerX86AVXTest, MovdquLoad) { + DriverStr(RepeatFA(&x86::X86Assembler::movdqu, "vmovdqu {mem}, %{reg}"), "avx_movdqu_load"); +} + TEST_F(AssemblerX86Test, MovdquStore) { DriverStr(RepeatAF(&x86::X86Assembler::movdqu, "movdqu %{reg}, {mem}"), "movdqu_store"); } +TEST_F(AssemblerX86AVXTest, VMovdquStore) { + DriverStr(RepeatAF(&x86::X86Assembler::vmovdqu, "vmovdqu %{reg}, {mem}"), "vmovdqu_store"); +} + +TEST_F(AssemblerX86AVXTest, MovdquStore) { + DriverStr(RepeatAF(&x86::X86Assembler::movdqu, "vmovdqu %{reg}, {mem}"), "avx_movdqu_store"); +} + TEST_F(AssemblerX86Test, AddPS) { DriverStr(RepeatFF(&x86::X86Assembler::addps, "addps %{reg2}, %{reg1}"), "addps"); } +TEST_F(AssemblerX86AVXTest, VAddPS) { + DriverStr(RepeatFFF(&x86::X86Assembler::vaddps, "vaddps %{reg3}, %{reg2}, %{reg1}"), "vaddps"); +} + TEST_F(AssemblerX86Test, AddPD) { DriverStr(RepeatFF(&x86::X86Assembler::addpd, "addpd %{reg2}, %{reg1}"), "addpd"); } +TEST_F(AssemblerX86AVXTest, VAddpd) { + DriverStr(RepeatFFF(&x86::X86Assembler::vaddpd, "vaddpd %{reg3}, %{reg2}, %{reg1}"), "vaddpd"); +} + TEST_F(AssemblerX86Test, SubPS) { DriverStr(RepeatFF(&x86::X86Assembler::subps, "subps %{reg2}, %{reg1}"), "subps"); } +TEST_F(AssemblerX86AVXTest, VSubPS) { + DriverStr(RepeatFFF(&x86::X86Assembler::vsubps, "vsubps %{reg3},%{reg2}, %{reg1}"), "vsubps"); +} + TEST_F(AssemblerX86Test, SubPD) { DriverStr(RepeatFF(&x86::X86Assembler::subpd, "subpd %{reg2}, %{reg1}"), "subpd"); } +TEST_F(AssemblerX86AVXTest, VSubPD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vsubpd, "vsubpd %{reg3}, %{reg2}, %{reg1}"), "vsubpd"); +} + TEST_F(AssemblerX86Test, MulPS) { DriverStr(RepeatFF(&x86::X86Assembler::mulps, "mulps %{reg2}, %{reg1}"), "mulps"); } +TEST_F(AssemblerX86AVXTest, VMulPS) { + DriverStr(RepeatFFF(&x86::X86Assembler::vmulps, "vmulps %{reg3}, %{reg2}, %{reg1}"), "vmulps"); +} + TEST_F(AssemblerX86Test, MulPD) { DriverStr(RepeatFF(&x86::X86Assembler::mulpd, "mulpd %{reg2}, %{reg1}"), "mulpd"); } +TEST_F(AssemblerX86AVXTest, VMulPD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vmulpd, "vmulpd %{reg3}, %{reg2}, %{reg1}"), "vmulpd"); +} + TEST_F(AssemblerX86Test, DivPS) { DriverStr(RepeatFF(&x86::X86Assembler::divps, "divps %{reg2}, %{reg1}"), "divps"); } +TEST_F(AssemblerX86AVXTest, VDivPS) { + DriverStr(RepeatFFF(&x86::X86Assembler::vdivps, "vdivps %{reg3}, %{reg2}, %{reg1}"), "vdivps"); +} + TEST_F(AssemblerX86Test, DivPD) { DriverStr(RepeatFF(&x86::X86Assembler::divpd, "divpd %{reg2}, %{reg1}"), "divpd"); } +TEST_F(AssemblerX86AVXTest, VDivPD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vdivpd, "vdivpd %{reg3}, %{reg2}, %{reg1}"), "vdivpd"); +} + TEST_F(AssemblerX86Test, PAddB) { DriverStr(RepeatFF(&x86::X86Assembler::paddb, "paddb %{reg2}, %{reg1}"), "paddb"); } +TEST_F(AssemblerX86AVXTest, VPaddB) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpaddb, "vpaddb %{reg3}, %{reg2}, %{reg1}"), "vpaddb"); +} + TEST_F(AssemblerX86Test, PSubB) { DriverStr(RepeatFF(&x86::X86Assembler::psubb, "psubb %{reg2}, %{reg1}"), "psubb"); } +TEST_F(AssemblerX86AVXTest, VPsubB) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpsubb, "vpsubb %{reg3},%{reg2}, %{reg1}"), "vpsubb"); +} + TEST_F(AssemblerX86Test, PAddW) { DriverStr(RepeatFF(&x86::X86Assembler::paddw, "paddw %{reg2}, %{reg1}"), "paddw"); } +TEST_F(AssemblerX86AVXTest, VPaddW) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpaddw, "vpaddw %{reg3}, %{reg2}, %{reg1}"), "vpaddw"); +} + TEST_F(AssemblerX86Test, PSubW) { DriverStr(RepeatFF(&x86::X86Assembler::psubw, "psubw %{reg2}, %{reg1}"), "psubw"); } +TEST_F(AssemblerX86AVXTest, VPsubW) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpsubw, "vpsubw %{reg3}, %{reg2}, %{reg1}"), "vpsubw"); +} + TEST_F(AssemblerX86Test, PMullW) { DriverStr(RepeatFF(&x86::X86Assembler::pmullw, "pmullw %{reg2}, %{reg1}"), "pmullw"); } +TEST_F(AssemblerX86AVXTest, VPMullW) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpmullw, "vpmullw %{reg3}, %{reg2}, %{reg1}"), "vpmullw"); +} + TEST_F(AssemblerX86Test, PAddD) { DriverStr(RepeatFF(&x86::X86Assembler::paddd, "paddd %{reg2}, %{reg1}"), "paddd"); } +TEST_F(AssemblerX86AVXTest, VPaddD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpaddd, "vpaddd %{reg3}, %{reg2}, %{reg1}"), "vpaddd"); +} + TEST_F(AssemblerX86Test, PSubD) { DriverStr(RepeatFF(&x86::X86Assembler::psubd, "psubd %{reg2}, %{reg1}"), "psubd"); } +TEST_F(AssemblerX86AVXTest, VPsubD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpsubd, "vpsubd %{reg3}, %{reg2}, %{reg1}"), "vpsubd"); +} + TEST_F(AssemblerX86Test, PMullD) { DriverStr(RepeatFF(&x86::X86Assembler::pmulld, "pmulld %{reg2}, %{reg1}"), "pmulld"); } +TEST_F(AssemblerX86AVXTest, VPMullD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpmulld, "vpmulld %{reg3}, %{reg2}, %{reg1}"), "vpmulld"); +} + TEST_F(AssemblerX86Test, PAddQ) { DriverStr(RepeatFF(&x86::X86Assembler::paddq, "paddq %{reg2}, %{reg1}"), "paddq"); } +TEST_F(AssemblerX86AVXTest, VPaddQ) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpaddq, "vpaddq %{reg3}, %{reg2}, %{reg1}"), "vpaddq"); +} + TEST_F(AssemblerX86Test, PSubQ) { DriverStr(RepeatFF(&x86::X86Assembler::psubq, "psubq %{reg2}, %{reg1}"), "psubq"); } +TEST_F(AssemblerX86AVXTest, VPsubQ) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpsubq, "vpsubq %{reg3}, %{reg2}, %{reg1}"), "vpsubq"); +} + TEST_F(AssemblerX86Test, PAddUSB) { DriverStr(RepeatFF(&x86::X86Assembler::paddusb, "paddusb %{reg2}, %{reg1}"), "paddusb"); } @@ -657,6 +861,18 @@ TEST_F(AssemblerX86Test, PXor) { DriverStr(RepeatFF(&x86::X86Assembler::pxor, "pxor %{reg2}, %{reg1}"), "pxor"); } +TEST_F(AssemblerX86AVXTest, VPXor) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpxor, "vpxor %{reg3}, %{reg2}, %{reg1}"), "vpxor"); +} + +TEST_F(AssemblerX86AVXTest, VXorPS) { + DriverStr(RepeatFFF(&x86::X86Assembler::vxorps, "vxorps %{reg3}, %{reg2}, %{reg1}"), "vxorps"); +} + +TEST_F(AssemblerX86AVXTest, VXorPD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vxorpd, "vxorpd %{reg3}, %{reg2}, %{reg1}"), "vxorpd"); +} + TEST_F(AssemblerX86Test, AndPD) { DriverStr(RepeatFF(&x86::X86Assembler::andpd, "andpd %{reg2}, %{reg1}"), "andpd"); } @@ -669,6 +885,18 @@ TEST_F(AssemblerX86Test, PAnd) { DriverStr(RepeatFF(&x86::X86Assembler::pand, "pand %{reg2}, %{reg1}"), "pand"); } +TEST_F(AssemblerX86AVXTest, VPAnd) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpand, "vpand %{reg3}, %{reg2}, %{reg1}"), "vpand"); +} + +TEST_F(AssemblerX86AVXTest, VAndPS) { + DriverStr(RepeatFFF(&x86::X86Assembler::vandps, "vandps %{reg3}, %{reg2}, %{reg1}"), "vandps"); +} + +TEST_F(AssemblerX86AVXTest, VAndPD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vandpd, "vandpd %{reg3}, %{reg2}, %{reg1}"), "vandpd"); +} + TEST_F(AssemblerX86Test, Andn) { DriverStr(RepeatRRR(&x86::X86Assembler::andn, "andn %{reg3}, %{reg2}, %{reg1}"), "andn"); } @@ -685,6 +913,18 @@ TEST_F(AssemblerX86Test, PAndn) { DriverStr(RepeatFF(&x86::X86Assembler::pandn, "pandn %{reg2}, %{reg1}"), "pandn"); } +TEST_F(AssemblerX86AVXTest, VPAndn) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpandn, "vpandn %{reg3}, %{reg2}, %{reg1}"), "vpandn"); +} + +TEST_F(AssemblerX86AVXTest, VAndnPS) { + DriverStr(RepeatFFF(&x86::X86Assembler::vandnps, "vandnps %{reg3}, %{reg2}, %{reg1}"), "vandnps"); +} + +TEST_F(AssemblerX86AVXTest, VAndnPD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vandnpd, "vandnpd %{reg3}, %{reg2}, %{reg1}"), "vandnpd"); +} + TEST_F(AssemblerX86Test, OrPD) { DriverStr(RepeatFF(&x86::X86Assembler::orpd, "orpd %{reg2}, %{reg1}"), "orpd"); } @@ -697,6 +937,18 @@ TEST_F(AssemblerX86Test, POr) { DriverStr(RepeatFF(&x86::X86Assembler::por, "por %{reg2}, %{reg1}"), "por"); } +TEST_F(AssemblerX86AVXTest, VPor) { + DriverStr(RepeatFFF(&x86::X86Assembler::vpor, "vpor %{reg3}, %{reg2}, %{reg1}"), "vpor"); +} + +TEST_F(AssemblerX86AVXTest, VorPS) { + DriverStr(RepeatFFF(&x86::X86Assembler::vorps, "vorps %{reg3}, %{reg2}, %{reg1}"), "vorps"); +} + +TEST_F(AssemblerX86AVXTest, VorPD) { + DriverStr(RepeatFFF(&x86::X86Assembler::vorpd, "vorpd %{reg3}, %{reg2}, %{reg1}"), "vorpd"); +} + TEST_F(AssemblerX86Test, PAvgB) { DriverStr(RepeatFF(&x86::X86Assembler::pavgb, "pavgb %{reg2}, %{reg1}"), "pavgb"); } @@ -713,6 +965,11 @@ TEST_F(AssemblerX86Test, PMAddWD) { DriverStr(RepeatFF(&x86::X86Assembler::pmaddwd, "pmaddwd %{reg2}, %{reg1}"), "pmaddwd"); } +TEST_F(AssemblerX86AVXTest, VPMAddWD) { + DriverStr( + RepeatFFF(&x86::X86Assembler::vpmaddwd, "vpmaddwd %{reg3}, %{reg2}, %{reg1}"), "vpmaddwd"); +} + TEST_F(AssemblerX86Test, PHAddW) { DriverStr(RepeatFF(&x86::X86Assembler::phaddw, "phaddw %{reg2}, %{reg1}"), "phaddw"); } diff --git a/compiler/utils/x86/jni_macro_assembler_x86.cc b/compiler/utils/x86/jni_macro_assembler_x86.cc index 540d72b28d..f4ea004894 100644 --- a/compiler/utils/x86/jni_macro_assembler_x86.cc +++ b/compiler/utils/x86/jni_macro_assembler_x86.cc @@ -39,6 +39,9 @@ static dwarf::Reg DWARFReg(Register reg) { constexpr size_t kFramePointerSize = 4; +static constexpr size_t kNativeStackAlignment = 16; +static_assert(kNativeStackAlignment == kStackAlignment); + #define __ asm_. void X86JNIMacroAssembler::BuildFrame(size_t frame_size, @@ -47,7 +50,15 @@ void X86JNIMacroAssembler::BuildFrame(size_t frame_size, const ManagedRegisterEntrySpills& entry_spills) { DCHECK_EQ(CodeSize(), 0U); // Nothing emitted yet. cfi().SetCurrentCFAOffset(4); // Return address on stack. - CHECK_ALIGNED(frame_size, kStackAlignment); + if (frame_size == kFramePointerSize) { + // For @CriticalNative tail call. + CHECK(method_reg.IsNoRegister()); + CHECK(spill_regs.empty()); + } else if (method_reg.IsNoRegister()) { + CHECK_ALIGNED(frame_size, kNativeStackAlignment); + } else { + CHECK_ALIGNED(frame_size, kStackAlignment); + } int gpr_count = 0; for (int i = spill_regs.size() - 1; i >= 0; --i) { Register spill = spill_regs[i].AsX86().AsCpuRegister(); @@ -59,12 +70,16 @@ void X86JNIMacroAssembler::BuildFrame(size_t frame_size, // return address then method on stack. int32_t adjust = frame_size - gpr_count * kFramePointerSize - - kFramePointerSize /*method*/ - - kFramePointerSize /*return address*/; - __ addl(ESP, Immediate(-adjust)); - cfi().AdjustCFAOffset(adjust); - __ pushl(method_reg.AsX86().AsCpuRegister()); - cfi().AdjustCFAOffset(kFramePointerSize); + kFramePointerSize /*return address*/ - + (method_reg.IsRegister() ? kFramePointerSize /*method*/ : 0u); + if (adjust != 0) { + __ addl(ESP, Immediate(-adjust)); + cfi().AdjustCFAOffset(adjust); + } + if (method_reg.IsRegister()) { + __ pushl(method_reg.AsX86().AsCpuRegister()); + cfi().AdjustCFAOffset(kFramePointerSize); + } DCHECK_EQ(static_cast<size_t>(cfi().GetCurrentCFAOffset()), frame_size); for (const ManagedRegisterSpill& spill : entry_spills) { @@ -86,12 +101,14 @@ void X86JNIMacroAssembler::BuildFrame(size_t frame_size, void X86JNIMacroAssembler::RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> spill_regs, bool may_suspend ATTRIBUTE_UNUSED) { - CHECK_ALIGNED(frame_size, kStackAlignment); + CHECK_ALIGNED(frame_size, kNativeStackAlignment); cfi().RememberState(); // -kFramePointerSize for ArtMethod*. int adjust = frame_size - spill_regs.size() * kFramePointerSize - kFramePointerSize; - __ addl(ESP, Immediate(adjust)); - cfi().AdjustCFAOffset(-adjust); + if (adjust != 0) { + __ addl(ESP, Immediate(adjust)); + cfi().AdjustCFAOffset(-adjust); + } for (size_t i = 0; i < spill_regs.size(); ++i) { Register spill = spill_regs[i].AsX86().AsCpuRegister(); __ popl(spill); @@ -105,15 +122,19 @@ void X86JNIMacroAssembler::RemoveFrame(size_t frame_size, } void X86JNIMacroAssembler::IncreaseFrameSize(size_t adjust) { - CHECK_ALIGNED(adjust, kStackAlignment); - __ addl(ESP, Immediate(-adjust)); - cfi().AdjustCFAOffset(adjust); + if (adjust != 0u) { + CHECK_ALIGNED(adjust, kNativeStackAlignment); + __ addl(ESP, Immediate(-adjust)); + cfi().AdjustCFAOffset(adjust); + } } static void DecreaseFrameSizeImpl(X86Assembler* assembler, size_t adjust) { - CHECK_ALIGNED(adjust, kStackAlignment); - assembler->addl(ESP, Immediate(adjust)); - assembler->cfi().AdjustCFAOffset(-adjust); + if (adjust != 0u) { + CHECK_ALIGNED(adjust, kNativeStackAlignment); + assembler->addl(ESP, Immediate(adjust)); + assembler->cfi().AdjustCFAOffset(-adjust); + } } void X86JNIMacroAssembler::DecreaseFrameSize(size_t adjust) { @@ -301,7 +322,7 @@ void X86JNIMacroAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, siz __ movl(dest.AsCpuRegister(), src.AsCpuRegister()); } else if (src.IsX87Register() && dest.IsXmmRegister()) { // Pass via stack and pop X87 register - __ subl(ESP, Immediate(16)); + IncreaseFrameSize(16); if (size == 4) { CHECK_EQ(src.AsX87Register(), ST0); __ fstps(Address(ESP, 0)); @@ -311,7 +332,7 @@ void X86JNIMacroAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, siz __ fstpl(Address(ESP, 0)); __ movsd(dest.AsXmmRegister(), Address(ESP, 0)); } - __ addl(ESP, Immediate(16)); + DecreaseFrameSize(16); } else { // TODO: x87, SSE UNIMPLEMENTED(FATAL) << ": Move " << dest << ", " << src; @@ -487,6 +508,12 @@ void X86JNIMacroAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_nul // TODO: not validating references } +void X86JNIMacroAssembler::Jump(ManagedRegister mbase, Offset offset, ManagedRegister) { + X86ManagedRegister base = mbase.AsX86(); + CHECK(base.IsCpuRegister()); + __ jmp(Address(base.AsCpuRegister(), offset.Int32Value())); +} + void X86JNIMacroAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister) { X86ManagedRegister base = mbase.AsX86(); CHECK(base.IsCpuRegister()); diff --git a/compiler/utils/x86/jni_macro_assembler_x86.h b/compiler/utils/x86/jni_macro_assembler_x86.h index a701080b4f..7bf2f98ddc 100644 --- a/compiler/utils/x86/jni_macro_assembler_x86.h +++ b/compiler/utils/x86/jni_macro_assembler_x86.h @@ -146,6 +146,9 @@ class X86JNIMacroAssembler final : public JNIMacroAssemblerFwd<X86Assembler, Poi void VerifyObject(ManagedRegister src, bool could_be_null) override; void VerifyObject(FrameOffset src, bool could_be_null) override; + // Jump to address held at [base+offset] (used for tail calls). + void Jump(ManagedRegister base, Offset offset, ManagedRegister scratch) override; + // Call to address held at [base+offset] void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) override; void Call(FrameOffset base, Offset offset, ManagedRegister scratch) override; diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index c118bc6fbe..2c5dd9e949 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -64,98 +64,13 @@ std::ostream& operator<<(std::ostream& os, const Address& addr) { } } -uint8_t X86_64Assembler::EmitVexByteZero(bool is_two_byte) { - uint8_t vex_zero = 0xC0; - if (!is_two_byte) { - vex_zero |= 0xC4; - } else { - vex_zero |= 0xC5; +bool X86_64Assembler::CpuHasAVXorAVX2FeatureFlag() { + if (has_AVX_ || has_AVX2_) { + return true; } - return vex_zero; + return false; } -uint8_t X86_64Assembler::EmitVexByte1(bool r, bool x, bool b, int mmmmm) { - // VEX Byte 1 - uint8_t vex_prefix = 0; - if (!r) { - vex_prefix |= 0x80; // VEX.R - } - if (!x) { - vex_prefix |= 0x40; // VEX.X - } - if (!b) { - vex_prefix |= 0x20; // VEX.B - } - - // VEX.mmmmm - switch (mmmmm) { - case 1: - // implied 0F leading opcode byte - vex_prefix |= 0x01; - break; - case 2: - // implied leading 0F 38 opcode byte - vex_prefix |= 0x02; - break; - case 3: - // implied leading OF 3A opcode byte - vex_prefix |= 0x03; - break; - default: - LOG(FATAL) << "unknown opcode bytes"; - } - - return vex_prefix; -} - -uint8_t X86_64Assembler::EmitVexByte2(bool w, int l, X86_64ManagedRegister operand, int pp) { - // VEX Byte 2 - uint8_t vex_prefix = 0; - if (w) { - vex_prefix |= 0x80; - } - // VEX.vvvv - if (operand.IsXmmRegister()) { - XmmRegister vvvv = operand.AsXmmRegister(); - int inverted_reg = 15-static_cast<int>(vvvv.AsFloatRegister()); - uint8_t reg = static_cast<uint8_t>(inverted_reg); - vex_prefix |= ((reg & 0x0F) << 3); - } else if (operand.IsCpuRegister()) { - CpuRegister vvvv = operand.AsCpuRegister(); - int inverted_reg = 15 - static_cast<int>(vvvv.AsRegister()); - uint8_t reg = static_cast<uint8_t>(inverted_reg); - vex_prefix |= ((reg & 0x0F) << 3); - } - - // VEX.L - if (l == 256) { - vex_prefix |= 0x04; - } - - // VEX.pp - switch (pp) { - case 0: - // SIMD Pefix - None - vex_prefix |= 0x00; - break; - case 1: - // SIMD Prefix - 66 - vex_prefix |= 0x01; - break; - case 2: - // SIMD Prefix - F3 - vex_prefix |= 0x02; - break; - case 3: - // SIMD Prefix - F2 - vex_prefix |= 0x03; - break; - default: - LOG(FATAL) << "unknown SIMD Prefix"; - } - - return vex_prefix; -} void X86_64Assembler::call(CpuRegister reg) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -499,6 +414,10 @@ void X86_64Assembler::leal(CpuRegister dst, const Address& src) { void X86_64Assembler::movaps(XmmRegister dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovaps(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst, src); EmitUint8(0x0F); @@ -507,7 +426,60 @@ void X86_64Assembler::movaps(XmmRegister dst, XmmRegister src) { } +/**VEX.128.0F.WIG 28 /r VMOVAPS xmm1, xmm2 */ +void X86_64Assembler::vmovaps(XmmRegister dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + uint8_t byte_zero, byte_one, byte_two; + bool is_twobyte_form = true; + bool load = dst.NeedsRex(); + bool store = !load; + + if (src.NeedsRex()&& dst.NeedsRex()) { + is_twobyte_form = false; + } + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + // Instruction VEX Prefix + byte_zero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + if (is_twobyte_form) { + bool rex_bit = (load) ? dst.NeedsRex() : src.NeedsRex(); + byte_one = EmitVexPrefixByteOne(rex_bit, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } else { + byte_one = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src.NeedsRex(), + SET_VEX_M_0F); + byte_two = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } + EmitUint8(byte_zero); + EmitUint8(byte_one); + if (!is_twobyte_form) { + EmitUint8(byte_two); + } + // Instruction Opcode + if (is_twobyte_form && store) { + EmitUint8(0x29); + } else { + EmitUint8(0x28); + } + // Instruction Operands + if (is_twobyte_form && store) { + EmitXmmRegisterOperand(src.LowBits(), dst); + } else { + EmitXmmRegisterOperand(dst.LowBits(), src); + } +} + void X86_64Assembler::movaps(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovaps(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst, src); EmitUint8(0x0F); @@ -515,8 +487,51 @@ void X86_64Assembler::movaps(XmmRegister dst, const Address& src) { EmitOperand(dst.LowBits(), src); } +/**VEX.128.0F.WIG 28 /r VMOVAPS xmm1, m128 */ +void X86_64Assembler::vmovaps(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = false; + // Instruction VEX Prefix + uint8_t rex = src.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_b && !Rex_x) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x28); + // Instruction Operands + EmitOperand(dst.LowBits(), src); +} void X86_64Assembler::movups(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovups(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst, src); EmitUint8(0x0F); @@ -524,8 +539,52 @@ void X86_64Assembler::movups(XmmRegister dst, const Address& src) { EmitOperand(dst.LowBits(), src); } +/** VEX.128.0F.WIG 10 /r VMOVUPS xmm1, m128 */ +void X86_64Assembler::vmovups(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = false; + // Instruction VEX Prefix + uint8_t rex = src.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_x && !Rex_b) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x10); + // Instruction Operands + EmitOperand(dst.LowBits(), src); +} + void X86_64Assembler::movaps(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovaps(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(src, dst); EmitUint8(0x0F); @@ -533,8 +592,52 @@ void X86_64Assembler::movaps(const Address& dst, XmmRegister src) { EmitOperand(src.LowBits(), dst); } +/** VEX.128.0F.WIG 29 /r VMOVAPS m128, xmm1 */ +void X86_64Assembler::vmovaps(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = false; + + // Instruction VEX Prefix + uint8_t rex = dst.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_b && !Rex_x) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x29); + // Instruction Operands + EmitOperand(src.LowBits(), dst); +} void X86_64Assembler::movups(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovups(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(src, dst); EmitUint8(0x0F); @@ -542,6 +645,47 @@ void X86_64Assembler::movups(const Address& dst, XmmRegister src) { EmitOperand(src.LowBits(), dst); } +/** VEX.128.0F.WIG 11 /r VMOVUPS m128, xmm1 */ +void X86_64Assembler::vmovups(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = false; + + // Instruction VEX Prefix + uint8_t rex = dst.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_b && !Rex_x) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x11); + // Instruction Operands + EmitOperand(src.LowBits(), dst); +} + void X86_64Assembler::movss(XmmRegister dst, const Address& src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -615,7 +759,6 @@ void X86_64Assembler::movd(CpuRegister dst, XmmRegister src, bool is64bit) { EmitOperand(src.LowBits(), Operand(dst)); } - void X86_64Assembler::addss(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF3); @@ -625,7 +768,6 @@ void X86_64Assembler::addss(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } - void X86_64Assembler::addss(XmmRegister dst, const Address& src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF3); @@ -713,6 +855,60 @@ void X86_64Assembler::subps(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vaddps(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!add_right.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x58); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} + +void X86_64Assembler::vsubps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t byte_zero = 0x00, byte_one = 0x00, byte_two = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + byte_zero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + if (is_twobyte_form) { + byte_one = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } else { + byte_one = EmitVexPrefixByteOne(dst.NeedsRex(), /*X=*/ false, src2.NeedsRex(), SET_VEX_M_0F); + byte_two = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } + EmitUint8(byte_zero); + EmitUint8(byte_one); + if (!is_twobyte_form) { + EmitUint8(byte_two); + } + EmitUint8(0x5C); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + void X86_64Assembler::mulps(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -722,6 +918,34 @@ void X86_64Assembler::mulps(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vmulps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x59); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} void X86_64Assembler::divps(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -731,6 +955,34 @@ void X86_64Assembler::divps(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vdivps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x5E); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} void X86_64Assembler::flds(const Address& src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -754,6 +1006,10 @@ void X86_64Assembler::fstps(const Address& dst) { void X86_64Assembler::movapd(XmmRegister dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovapd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitOptionalRex32(dst, src); @@ -762,8 +1018,59 @@ void X86_64Assembler::movapd(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +/** VEX.128.66.0F.WIG 28 /r VMOVAPD xmm1, xmm2 */ +void X86_64Assembler::vmovapd(XmmRegister dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = true; + + if (src.NeedsRex() && dst.NeedsRex()) { + is_twobyte_form = false; + } + // Instruction VEX Prefix + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + bool load = dst.NeedsRex(); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + bool rex_bit = load ? dst.NeedsRex() : src.NeedsRex(); + ByteOne = EmitVexPrefixByteOne(rex_bit, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + if (is_twobyte_form && !load) { + EmitUint8(0x29); + } else { + EmitUint8(0x28); + } + // Instruction Operands + if (is_twobyte_form && !load) { + EmitXmmRegisterOperand(src.LowBits(), dst); + } else { + EmitXmmRegisterOperand(dst.LowBits(), src); + } +} void X86_64Assembler::movapd(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovapd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitOptionalRex32(dst, src); @@ -772,8 +1079,52 @@ void X86_64Assembler::movapd(XmmRegister dst, const Address& src) { EmitOperand(dst.LowBits(), src); } +/** VEX.128.66.0F.WIG 28 /r VMOVAPD xmm1, m128 */ +void X86_64Assembler::vmovapd(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = false; + + // Instruction VEX Prefix + uint8_t rex = src.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_b && !Rex_x) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x28); + // Instruction Operands + EmitOperand(dst.LowBits(), src); +} void X86_64Assembler::movupd(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovupd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitOptionalRex32(dst, src); @@ -782,8 +1133,51 @@ void X86_64Assembler::movupd(XmmRegister dst, const Address& src) { EmitOperand(dst.LowBits(), src); } +/** VEX.128.66.0F.WIG 10 /r VMOVUPD xmm1, m128 */ +void X86_64Assembler::vmovupd(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero, ByteOne, ByteTwo; + + // Instruction VEX Prefix + uint8_t rex = src.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_b && !Rex_x) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) + EmitUint8(ByteTwo); + // Instruction Opcode + EmitUint8(0x10); + // Instruction Operands + EmitOperand(dst.LowBits(), src); +} void X86_64Assembler::movapd(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovapd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitOptionalRex32(src, dst); @@ -792,8 +1186,51 @@ void X86_64Assembler::movapd(const Address& dst, XmmRegister src) { EmitOperand(src.LowBits(), dst); } +/** VEX.128.66.0F.WIG 29 /r VMOVAPD m128, xmm1 */ +void X86_64Assembler::vmovapd(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero, ByteOne, ByteTwo; + // Instruction VEX Prefix + uint8_t rex = dst.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_x && !Rex_b) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x29); + // Instruction Operands + EmitOperand(src.LowBits(), dst); +} void X86_64Assembler::movupd(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovupd(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitOptionalRex32(src, dst); @@ -802,6 +1239,47 @@ void X86_64Assembler::movupd(const Address& dst, XmmRegister src) { EmitOperand(src.LowBits(), dst); } +/** VEX.128.66.0F.WIG 11 /r VMOVUPD m128, xmm1 */ +void X86_64Assembler::vmovupd(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero, ByteOne, ByteTwo; + + // Instruction VEX Prefix + uint8_t rex = dst.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_x && !Rex_b) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x11); + // Instruction Operands + EmitOperand(src.LowBits(), dst); +} + void X86_64Assembler::movsd(XmmRegister dst, const Address& src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -923,6 +1401,35 @@ void X86_64Assembler::addpd(XmmRegister dst, XmmRegister src) { } +void X86_64Assembler::vaddpd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!add_right.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x58); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} + + void X86_64Assembler::subpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -933,6 +1440,35 @@ void X86_64Assembler::subpd(XmmRegister dst, XmmRegister src) { } +void X86_64Assembler::vsubpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x5C); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + + void X86_64Assembler::mulpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -942,6 +1478,34 @@ void X86_64Assembler::mulpd(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vmulpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x59); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} void X86_64Assembler::divpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -953,7 +1517,41 @@ void X86_64Assembler::divpd(XmmRegister dst, XmmRegister src) { } +void X86_64Assembler::vdivpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x5E); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + + void X86_64Assembler::movdqa(XmmRegister dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqa(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitOptionalRex32(dst, src); @@ -962,8 +1560,59 @@ void X86_64Assembler::movdqa(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +/** VEX.128.66.0F.WIG 6F /r VMOVDQA xmm1, xmm2 */ +void X86_64Assembler::vmovdqa(XmmRegister dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = true; + + // Instruction VEX Prefix + if (src.NeedsRex() && dst.NeedsRex()) { + is_twobyte_form = false; + } + bool load = dst.NeedsRex(); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + bool rex_bit = load ? dst.NeedsRex() : src.NeedsRex(); + ByteOne = EmitVexPrefixByteOne(rex_bit, + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + if (is_twobyte_form && !load) { + EmitUint8(0x7F); + } else { + EmitUint8(0x6F); + } + // Instruction Operands + if (is_twobyte_form && !load) { + EmitXmmRegisterOperand(src.LowBits(), dst); + } else { + EmitXmmRegisterOperand(dst.LowBits(), src); + } +} void X86_64Assembler::movdqa(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqa(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitOptionalRex32(dst, src); @@ -972,8 +1621,52 @@ void X86_64Assembler::movdqa(XmmRegister dst, const Address& src) { EmitOperand(dst.LowBits(), src); } +/** VEX.128.66.0F.WIG 6F /r VMOVDQA xmm1, m128 */ +void X86_64Assembler::vmovdqa(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = false; + + // Instruction VEX Prefix + uint8_t rex = src.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_x && !Rex_b) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x6F); + // Instruction Operands + EmitOperand(dst.LowBits(), src); +} void X86_64Assembler::movdqu(XmmRegister dst, const Address& src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqu(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF3); EmitOptionalRex32(dst, src); @@ -982,8 +1675,53 @@ void X86_64Assembler::movdqu(XmmRegister dst, const Address& src) { EmitOperand(dst.LowBits(), src); } +/** VEX.128.F3.0F.WIG 6F /r VMOVDQU xmm1, m128 +Load Unaligned */ +void X86_64Assembler::vmovdqu(XmmRegister dst, const Address& src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = false; + + // Instruction VEX Prefix + uint8_t rex = src.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_x && !Rex_b) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_F3); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_F3); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x6F); + // Instruction Operands + EmitOperand(dst.LowBits(), src); +} void X86_64Assembler::movdqa(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqa(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); EmitOptionalRex32(src, dst); @@ -992,8 +1730,51 @@ void X86_64Assembler::movdqa(const Address& dst, XmmRegister src) { EmitOperand(src.LowBits(), dst); } +/** VEX.128.66.0F.WIG 7F /r VMOVDQA m128, xmm1 */ +void X86_64Assembler::vmovdqa(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero, ByteOne, ByteTwo; + // Instruction VEX Prefix + uint8_t rex = dst.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_x && !Rex_b) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x7F); + // Instruction Operands + EmitOperand(src.LowBits(), dst); +} void X86_64Assembler::movdqu(const Address& dst, XmmRegister src) { + if (CpuHasAVXorAVX2FeatureFlag()) { + vmovdqu(dst, src); + return; + } AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF3); EmitOptionalRex32(src, dst); @@ -1002,6 +1783,46 @@ void X86_64Assembler::movdqu(const Address& dst, XmmRegister src) { EmitOperand(src.LowBits(), dst); } +/** VEX.128.F3.0F.WIG 7F /r VMOVDQU m128, xmm1 */ +void X86_64Assembler::vmovdqu(const Address& dst, XmmRegister src) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero, ByteOne, ByteTwo; + bool is_twobyte_form = false; + + // Instruction VEX Prefix + uint8_t rex = dst.rex(); + bool Rex_x = rex & GET_REX_X; + bool Rex_b = rex & GET_REX_B; + if (!Rex_b && !Rex_x) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + X86_64ManagedRegister vvvv_reg = ManagedRegister::NoRegister().AsX86_64(); + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + vvvv_reg, + SET_VEX_L_128, + SET_VEX_PP_F3); + } else { + ByteOne = EmitVexPrefixByteOne(src.NeedsRex(), + Rex_x, + Rex_b, + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, + SET_VEX_L_128, + SET_VEX_PP_F3); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + // Instruction Opcode + EmitUint8(0x7F); + // Instruction Operands + EmitOperand(src.LowBits(), dst); +} void X86_64Assembler::paddb(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1013,6 +1834,36 @@ void X86_64Assembler::paddb(XmmRegister dst, XmmRegister src) { } +void X86_64Assembler::vpaddb(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteOne = 0x00, ByteZero = 0x00, ByteTwo = 0x00; + bool is_twobyte_form = true; + if (add_right.NeedsRex()) { + is_twobyte_form = false; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xFC); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} + + void X86_64Assembler::psubb(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1023,6 +1874,36 @@ void X86_64Assembler::psubb(XmmRegister dst, XmmRegister src) { } +void X86_64Assembler::vpsubb(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!add_right.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xF8); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} + + void X86_64Assembler::paddw(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1032,6 +1913,35 @@ void X86_64Assembler::paddw(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vpaddw(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!add_right.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xFD); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} + void X86_64Assembler::psubw(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1042,6 +1952,35 @@ void X86_64Assembler::psubw(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vpsubw(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!add_right.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xF9); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} + void X86_64Assembler::pmullw(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1052,6 +1991,34 @@ void X86_64Assembler::pmullw(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vpmullw(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xD5); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} void X86_64Assembler::paddd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1062,6 +2029,34 @@ void X86_64Assembler::paddd(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vpaddd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!add_right.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xFE); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} void X86_64Assembler::psubd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1083,6 +2078,24 @@ void X86_64Assembler::pmulld(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vpmulld(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + ByteZero = EmitVexPrefixByteZero(/*is_twobyte_form*/ false); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F_38); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + EmitUint8(ByteZero); + EmitUint8(ByteOne); + EmitUint8(ByteTwo); + EmitUint8(0x40); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} void X86_64Assembler::paddq(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1094,6 +2107,36 @@ void X86_64Assembler::paddq(XmmRegister dst, XmmRegister src) { } +void X86_64Assembler::vpaddq(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!add_right.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xD4); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} + + void X86_64Assembler::psubq(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1103,6 +2146,35 @@ void X86_64Assembler::psubq(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vpsubq(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!add_right.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xFB); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} + void X86_64Assembler::paddusb(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1164,6 +2236,36 @@ void X86_64Assembler::psubsb(XmmRegister dst, XmmRegister src) { } +void X86_64Assembler::vpsubd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!add_right.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(add_left.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + add_right.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xFA); + EmitXmmRegisterOperand(dst.LowBits(), add_right); +} + + void X86_64Assembler::psubusw(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1530,7 +2632,6 @@ void X86_64Assembler::xorps(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } - void X86_64Assembler::pxor(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1540,6 +2641,95 @@ void X86_64Assembler::pxor(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +/* VEX.128.66.0F.WIG EF /r VPXOR xmm1, xmm2, xmm3/m128 */ +void X86_64Assembler::vpxor(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xEF); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + +/* VEX.128.0F.WIG 57 /r VXORPS xmm1,xmm2, xmm3/m128 */ +void X86_64Assembler::vxorps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x57); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + +/* VEX.128.66.0F.WIG 57 /r VXORPD xmm1,xmm2, xmm3/m128 */ +void X86_64Assembler::vxorpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x57); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} void X86_64Assembler::andpd(XmmRegister dst, const Address& src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -1576,17 +2766,107 @@ void X86_64Assembler::pand(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +/* VEX.128.66.0F.WIG DB /r VPAND xmm1, xmm2, xmm3/m128 */ +void X86_64Assembler::vpand(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xDB); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + +/* VEX.128.0F 54 /r VANDPS xmm1,xmm2, xmm3/m128 */ +void X86_64Assembler::vandps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x54); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + +/* VEX.128.66.0F 54 /r VANDPD xmm1, xmm2, xmm3/m128 */ +void X86_64Assembler::vandpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x54); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + void X86_64Assembler::andn(CpuRegister dst, CpuRegister src1, CpuRegister src2) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - uint8_t byte_zero = EmitVexByteZero(/*is_two_byte=*/ false); - uint8_t byte_one = EmitVexByte1(dst.NeedsRex(), - /*x=*/ false, - src2.NeedsRex(), - /*mmmmm=*/ 2); - uint8_t byte_two = EmitVexByte2(/*w=*/ true, - /*l=*/ 128, - X86_64ManagedRegister::FromCpuRegister(src1.AsRegister()), - /*pp=*/ 0); + uint8_t byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ false); + uint8_t byte_one = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F_38); + uint8_t byte_two = EmitVexPrefixByteTwo(/*W=*/ true, + X86_64ManagedRegister::FromCpuRegister(src1.AsRegister()), + SET_VEX_L_128, + SET_VEX_PP_NONE); EmitUint8(byte_zero); EmitUint8(byte_one); EmitUint8(byte_two); @@ -1621,6 +2901,96 @@ void X86_64Assembler::pandn(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +/* VEX.128.66.0F.WIG DF /r VPANDN xmm1, xmm2, xmm3/m128 */ +void X86_64Assembler::vpandn(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xDF); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + +/* VEX.128.0F 55 /r VANDNPS xmm1, xmm2, xmm3/m128 */ +void X86_64Assembler::vandnps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x55); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + +/* VEX.128.66.0F 55 /r VANDNPD xmm1, xmm2, xmm3/m128 */ +void X86_64Assembler::vandnpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x55); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + void X86_64Assembler::orpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1647,6 +3017,96 @@ void X86_64Assembler::por(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +/* VEX.128.66.0F.WIG EB /r VPOR xmm1, xmm2, xmm3/m128 */ +void X86_64Assembler::vpor(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xEB); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + +/* VEX.128.0F 56 /r VORPS xmm1,xmm2, xmm3/m128 */ +void X86_64Assembler::vorps(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_NONE); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x56); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + +/* VEX.128.66.0F 56 /r VORPD xmm1,xmm2, xmm3/m128 */ +void X86_64Assembler::vorpd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0x56); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + void X86_64Assembler::pavgb(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1683,6 +3143,35 @@ void X86_64Assembler::pmaddwd(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::vpmaddwd(XmmRegister dst, XmmRegister src1, XmmRegister src2) { + DCHECK(CpuHasAVXorAVX2FeatureFlag()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + bool is_twobyte_form = false; + uint8_t ByteZero = 0x00, ByteOne = 0x00, ByteTwo = 0x00; + if (!src2.NeedsRex()) { + is_twobyte_form = true; + } + ByteZero = EmitVexPrefixByteZero(is_twobyte_form); + X86_64ManagedRegister vvvv_reg = + X86_64ManagedRegister::FromXmmRegister(src1.AsFloatRegister()); + if (is_twobyte_form) { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } else { + ByteOne = EmitVexPrefixByteOne(dst.NeedsRex(), + /*X=*/ false, + src2.NeedsRex(), + SET_VEX_M_0F); + ByteTwo = EmitVexPrefixByteTwo(/*W=*/ false, vvvv_reg, SET_VEX_L_128, SET_VEX_PP_66); + } + EmitUint8(ByteZero); + EmitUint8(ByteOne); + if (!is_twobyte_form) { + EmitUint8(ByteTwo); + } + EmitUint8(0xF5); + EmitXmmRegisterOperand(dst.LowBits(), src2); +} + void X86_64Assembler::phaddw(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -3374,15 +4863,15 @@ void X86_64Assembler::setcc(Condition condition, CpuRegister dst) { void X86_64Assembler::blsi(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - uint8_t byte_zero = EmitVexByteZero(/*is_two_byte=*/ false); - uint8_t byte_one = EmitVexByte1(/*r=*/ false, - /*x=*/ false, - src.NeedsRex(), - /*mmmmm=*/ 2); - uint8_t byte_two = EmitVexByte2(/*w=*/ true, - /*l=*/ 128, - X86_64ManagedRegister::FromCpuRegister(dst.AsRegister()), - /*pp=*/ 0); + uint8_t byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ false); + uint8_t byte_one = EmitVexPrefixByteOne(/*R=*/ false, + /*X=*/ false, + src.NeedsRex(), + SET_VEX_M_0F_38); + uint8_t byte_two = EmitVexPrefixByteTwo(/*W=*/true, + X86_64ManagedRegister::FromCpuRegister(dst.AsRegister()), + SET_VEX_L_128, + SET_VEX_PP_NONE); EmitUint8(byte_zero); EmitUint8(byte_one); EmitUint8(byte_two); @@ -3392,15 +4881,15 @@ void X86_64Assembler::blsi(CpuRegister dst, CpuRegister src) { void X86_64Assembler::blsmsk(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - uint8_t byte_zero = EmitVexByteZero(/*is_two_byte=*/ false); - uint8_t byte_one = EmitVexByte1(/*r=*/ false, - /*x=*/ false, - src.NeedsRex(), - /*mmmmm=*/ 2); - uint8_t byte_two = EmitVexByte2(/*w=*/ true, - /*l=*/ 128, - X86_64ManagedRegister::FromCpuRegister(dst.AsRegister()), - /*pp=*/ 0); + uint8_t byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/ false); + uint8_t byte_one = EmitVexPrefixByteOne(/*R=*/ false, + /*X=*/ false, + src.NeedsRex(), + SET_VEX_M_0F_38); + uint8_t byte_two = EmitVexPrefixByteTwo(/*W=*/ true, + X86_64ManagedRegister::FromCpuRegister(dst.AsRegister()), + SET_VEX_L_128, + SET_VEX_PP_NONE); EmitUint8(byte_zero); EmitUint8(byte_one); EmitUint8(byte_two); @@ -3410,15 +4899,15 @@ void X86_64Assembler::blsmsk(CpuRegister dst, CpuRegister src) { void X86_64Assembler::blsr(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - uint8_t byte_zero = EmitVexByteZero(/*is_two_byte=*/ false); - uint8_t byte_one = EmitVexByte1(/*r=*/ false, - /*x=*/ false, - src.NeedsRex(), - /*mmmmm=*/ 2); - uint8_t byte_two = EmitVexByte2(/*w=*/ true, - /*l=*/ 128, - X86_64ManagedRegister::FromCpuRegister(dst.AsRegister()), - /*pp=*/ 0); + uint8_t byte_zero = EmitVexPrefixByteZero(/*is_twobyte_form=*/false); + uint8_t byte_one = EmitVexPrefixByteOne(/*R=*/ false, + /*X=*/ false, + src.NeedsRex(), + SET_VEX_M_0F_38); + uint8_t byte_two = EmitVexPrefixByteTwo(/*W=*/ true, + X86_64ManagedRegister::FromCpuRegister(dst.AsRegister()), + SET_VEX_L_128, + SET_VEX_PP_NONE); EmitUint8(byte_zero); EmitUint8(byte_one); EmitUint8(byte_two); @@ -3937,5 +5426,133 @@ size_t ConstantArea::AddFloat(float v) { return AddInt32(bit_cast<int32_t, float>(v)); } +uint8_t X86_64Assembler::EmitVexPrefixByteZero(bool is_twobyte_form) { + // Vex Byte 0, + // Bits [7:0] must contain the value 11000101b (0xC5) for 2-byte Vex + // Bits [7:0] must contain the value 11000100b (0xC4) for 3-byte Vex + uint8_t vex_prefix = 0xC0; + if (is_twobyte_form) { + vex_prefix |= TWO_BYTE_VEX; // 2-Byte Vex + } else { + vex_prefix |= THREE_BYTE_VEX; // 3-Byte Vex + } + return vex_prefix; +} + +uint8_t X86_64Assembler::EmitVexPrefixByteOne(bool R, bool X, bool B, int SET_VEX_M) { + // Vex Byte 1, + uint8_t vex_prefix = VEX_INIT; + /** Bit[7] This bit needs to be set to '1' + otherwise the instruction is LES or LDS */ + if (!R) { + // R . + vex_prefix |= SET_VEX_R; + } + /** Bit[6] This bit needs to be set to '1' + otherwise the instruction is LES or LDS */ + if (!X) { + // X . + vex_prefix |= SET_VEX_X; + } + /** Bit[5] This bit needs to be set to '1' */ + if (!B) { + // B . + vex_prefix |= SET_VEX_B; + } + /** Bits[4:0], Based on the instruction documentaion */ + vex_prefix |= SET_VEX_M; + return vex_prefix; +} + +uint8_t X86_64Assembler::EmitVexPrefixByteOne(bool R, + X86_64ManagedRegister operand, + int SET_VEX_L, + int SET_VEX_PP) { + // Vex Byte 1, + uint8_t vex_prefix = VEX_INIT; + /** Bit[7] This bit needs to be set to '1' + otherwise the instruction is LES or LDS */ + if (!R) { + // R . + vex_prefix |= SET_VEX_R; + } + /**Bits[6:3] - 'vvvv' the source or dest register specifier */ + if (operand.IsNoRegister()) { + vex_prefix |= 0x78; + } else if (operand.IsXmmRegister()) { + XmmRegister vvvv = operand.AsXmmRegister(); + int inverted_reg = 15 - static_cast<int>(vvvv.AsFloatRegister()); + uint8_t reg = static_cast<uint8_t>(inverted_reg); + vex_prefix |= ((reg & 0x0F) << 3); + } else if (operand.IsCpuRegister()) { + CpuRegister vvvv = operand.AsCpuRegister(); + int inverted_reg = 15 - static_cast<int>(vvvv.AsRegister()); + uint8_t reg = static_cast<uint8_t>(inverted_reg); + vex_prefix |= ((reg & 0x0F) << 3); + } + /** Bit[2] - "L" If VEX.L = 1 indicates 256-bit vector operation, + VEX.L = 0 indicates 128 bit vector operation */ + vex_prefix |= SET_VEX_L; + // Bits[1:0] - "pp" + vex_prefix |= SET_VEX_PP; + return vex_prefix; +} + +uint8_t X86_64Assembler::EmitVexPrefixByteTwo(bool W, + X86_64ManagedRegister operand, + int SET_VEX_L, + int SET_VEX_PP) { + // Vex Byte 2, + uint8_t vex_prefix = VEX_INIT; + + /** Bit[7] This bits needs to be set to '1' with default value. + When using C4H form of VEX prefix, REX.W value is ignored */ + if (W) { + vex_prefix |= SET_VEX_W; + } + // Bits[6:3] - 'vvvv' the source or dest register specifier + if (operand.IsXmmRegister()) { + XmmRegister vvvv = operand.AsXmmRegister(); + int inverted_reg = 15 - static_cast<int>(vvvv.AsFloatRegister()); + uint8_t reg = static_cast<uint8_t>(inverted_reg); + vex_prefix |= ((reg & 0x0F) << 3); + } else if (operand.IsCpuRegister()) { + CpuRegister vvvv = operand.AsCpuRegister(); + int inverted_reg = 15 - static_cast<int>(vvvv.AsRegister()); + uint8_t reg = static_cast<uint8_t>(inverted_reg); + vex_prefix |= ((reg & 0x0F) << 3); + } + /** Bit[2] - "L" If VEX.L = 1 indicates 256-bit vector operation, + VEX.L = 0 indicates 128 bit vector operation */ + vex_prefix |= SET_VEX_L; + // Bits[1:0] - "pp" + vex_prefix |= SET_VEX_PP; + return vex_prefix; +} + +uint8_t X86_64Assembler::EmitVexPrefixByteTwo(bool W, + int SET_VEX_L, + int SET_VEX_PP) { + // Vex Byte 2, + uint8_t vex_prefix = VEX_INIT; + + /** Bit[7] This bits needs to be set to '1' with default value. + When using C4H form of VEX prefix, REX.W value is ignored */ + if (W) { + vex_prefix |= SET_VEX_W; + } + /** Bits[6:3] - 'vvvv' the source or dest register specifier */ + vex_prefix |= (0x0F << 3); + /** Bit[2] - "L" If VEX.L = 1 indicates 256-bit vector operation, + VEX.L = 0 indicates 128 bit vector operation */ + vex_prefix |= SET_VEX_L; + + // Bits[1:0] - "pp" + if (SET_VEX_PP != SET_VEX_PP_NONE) { + vex_prefix |= SET_VEX_PP; + } + return vex_prefix; +} + } // namespace x86_64 } // namespace art diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index ff13ea3293..70072d9224 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -19,6 +19,7 @@ #include <vector> +#include "arch/x86_64/instruction_set_features_x86_64.h" #include "base/arena_containers.h" #include "base/array_ref.h" #include "base/bit_utils.h" @@ -353,8 +354,12 @@ class NearLabel : private Label { class X86_64Assembler final : public Assembler { public: - explicit X86_64Assembler(ArenaAllocator* allocator) - : Assembler(allocator), constant_area_(allocator) {} + explicit X86_64Assembler(ArenaAllocator* allocator, + const X86_64InstructionSetFeatures* instruction_set_features = nullptr) + : Assembler(allocator), + constant_area_(allocator), + has_AVX_(instruction_set_features != nullptr ? instruction_set_features->HasAVX(): false), + has_AVX2_(instruction_set_features != nullptr ? instruction_set_features->HasAVX2() : false) {} virtual ~X86_64Assembler() {} /* @@ -415,6 +420,12 @@ class X86_64Assembler final : public Assembler { void movaps(const Address& dst, XmmRegister src); // store aligned void movups(const Address& dst, XmmRegister src); // store unaligned + void vmovaps(XmmRegister dst, XmmRegister src); // move + void vmovaps(XmmRegister dst, const Address& src); // load aligned + void vmovaps(const Address& dst, XmmRegister src); // store aligned + void vmovups(XmmRegister dst, const Address& src); // load unaligned + void vmovups(const Address& dst, XmmRegister src); // store unaligned + void movss(XmmRegister dst, const Address& src); void movss(const Address& dst, XmmRegister src); void movss(XmmRegister dst, XmmRegister src); @@ -441,12 +452,28 @@ class X86_64Assembler final : public Assembler { void mulps(XmmRegister dst, XmmRegister src); void divps(XmmRegister dst, XmmRegister src); + void vmulps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vmulpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vdivps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vdivpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); + + void vaddps(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vsubps(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vsubpd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vaddpd(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void movapd(XmmRegister dst, XmmRegister src); // move void movapd(XmmRegister dst, const Address& src); // load aligned void movupd(XmmRegister dst, const Address& src); // load unaligned void movapd(const Address& dst, XmmRegister src); // store aligned void movupd(const Address& dst, XmmRegister src); // store unaligned + void vmovapd(XmmRegister dst, XmmRegister src); // move + void vmovapd(XmmRegister dst, const Address& src); // load aligned + void vmovapd(const Address& dst, XmmRegister src); // store aligned + void vmovupd(XmmRegister dst, const Address& src); // load unaligned + void vmovupd(const Address& dst, XmmRegister src); // store unaligned + void movsd(XmmRegister dst, const Address& src); void movsd(const Address& dst, XmmRegister src); void movsd(XmmRegister dst, XmmRegister src); @@ -471,20 +498,40 @@ class X86_64Assembler final : public Assembler { void movdqa(const Address& dst, XmmRegister src); // store aligned void movdqu(const Address& dst, XmmRegister src); // store unaligned + void vmovdqa(XmmRegister dst, XmmRegister src); // move + void vmovdqa(XmmRegister dst, const Address& src); // load aligned + void vmovdqa(const Address& dst, XmmRegister src); // store aligned + void vmovdqu(XmmRegister dst, const Address& src); // load unaligned + void vmovdqu(const Address& dst, XmmRegister src); // store unaligned + void paddb(XmmRegister dst, XmmRegister src); // no addr variant (for now) void psubb(XmmRegister dst, XmmRegister src); + void vpaddb(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vpaddw(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void paddw(XmmRegister dst, XmmRegister src); void psubw(XmmRegister dst, XmmRegister src); void pmullw(XmmRegister dst, XmmRegister src); + void vpmullw(XmmRegister dst, XmmRegister src1, XmmRegister src2); + + void vpsubb(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vpsubw(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vpsubd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void paddd(XmmRegister dst, XmmRegister src); void psubd(XmmRegister dst, XmmRegister src); void pmulld(XmmRegister dst, XmmRegister src); + void vpmulld(XmmRegister dst, XmmRegister src1, XmmRegister src2); + + void vpaddd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void paddq(XmmRegister dst, XmmRegister src); void psubq(XmmRegister dst, XmmRegister src); + void vpaddq(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void vpsubq(XmmRegister dst, XmmRegister add_left, XmmRegister add_right); + void paddusb(XmmRegister dst, XmmRegister src); void paddsb(XmmRegister dst, XmmRegister src); void paddusw(XmmRegister dst, XmmRegister src); @@ -537,25 +584,38 @@ class X86_64Assembler final : public Assembler { void xorps(XmmRegister dst, const Address& src); void xorps(XmmRegister dst, XmmRegister src); void pxor(XmmRegister dst, XmmRegister src); // no addr variant (for now) + void vpxor(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vxorps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vxorpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void andpd(XmmRegister dst, const Address& src); void andpd(XmmRegister dst, XmmRegister src); void andps(XmmRegister dst, XmmRegister src); // no addr variant (for now) void pand(XmmRegister dst, XmmRegister src); + void vpand(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vandps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vandpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void andn(CpuRegister dst, CpuRegister src1, CpuRegister src2); void andnpd(XmmRegister dst, XmmRegister src); // no addr variant (for now) void andnps(XmmRegister dst, XmmRegister src); void pandn(XmmRegister dst, XmmRegister src); + void vpandn(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vandnps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vandnpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void orpd(XmmRegister dst, XmmRegister src); // no addr variant (for now) void orps(XmmRegister dst, XmmRegister src); void por(XmmRegister dst, XmmRegister src); + void vpor(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vorps(XmmRegister dst, XmmRegister src1, XmmRegister src2); + void vorpd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void pavgb(XmmRegister dst, XmmRegister src); // no addr variant (for now) void pavgw(XmmRegister dst, XmmRegister src); void psadbw(XmmRegister dst, XmmRegister src); void pmaddwd(XmmRegister dst, XmmRegister src); + void vpmaddwd(XmmRegister dst, XmmRegister src1, XmmRegister src2); void phaddw(XmmRegister dst, XmmRegister src); void phaddd(XmmRegister dst, XmmRegister src); void haddps(XmmRegister dst, XmmRegister src); @@ -909,6 +969,8 @@ class X86_64Assembler final : public Assembler { } } + bool CpuHasAVXorAVX2FeatureFlag(); + private: void EmitUint8(uint8_t value); void EmitInt32(int32_t value); @@ -956,12 +1018,22 @@ class X86_64Assembler final : public Assembler { void EmitOptionalByteRegNormalizingRex32(CpuRegister dst, CpuRegister src); void EmitOptionalByteRegNormalizingRex32(CpuRegister dst, const Operand& operand); - // Emit a 3 byte VEX Prefix - uint8_t EmitVexByteZero(bool is_two_byte); - uint8_t EmitVexByte1(bool r, bool x, bool b, int mmmmm); - uint8_t EmitVexByte2(bool w , int l , X86_64ManagedRegister operand, int pp); - + uint8_t EmitVexPrefixByteZero(bool is_twobyte_form); + uint8_t EmitVexPrefixByteOne(bool R, bool X, bool B, int SET_VEX_M); + uint8_t EmitVexPrefixByteOne(bool R, + X86_64ManagedRegister operand, + int SET_VEX_L, + int SET_VEX_PP); + uint8_t EmitVexPrefixByteTwo(bool W, + X86_64ManagedRegister operand, + int SET_VEX_L, + int SET_VEX_PP); + uint8_t EmitVexPrefixByteTwo(bool W, + int SET_VEX_L, + int SET_VEX_PP); ConstantArea constant_area_; + bool has_AVX_; // x86 256bit SIMD AVX. + bool has_AVX2_; // x86 256bit SIMD AVX 2.0. DISALLOW_COPY_AND_ASSIGN(X86_64Assembler); }; diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc index 461f028d9a..993cf95aed 100644 --- a/compiler/utils/x86_64/assembler_x86_64_test.cc +++ b/compiler/utils/x86_64/assembler_x86_64_test.cc @@ -339,6 +339,18 @@ class AssemblerX86_64Test : public AssemblerTest<x86_64::X86_64Assembler, std::vector<x86_64::XmmRegister*> fp_registers_; }; +class AssemblerX86_64AVXTest : public AssemblerX86_64Test { + public: + AssemblerX86_64AVXTest() + : instruction_set_features_(X86_64InstructionSetFeatures::FromVariant("kabylake", nullptr)) {} + protected: + x86_64::X86_64Assembler* CreateAssembler(ArenaAllocator* allocator) override { + return new (allocator) x86_64::X86_64Assembler(allocator, instruction_set_features_.get()); + } + private: + std::unique_ptr<const X86_64InstructionSetFeatures> instruction_set_features_; +}; + // // Test some repeat drivers used in the tests. // @@ -1107,22 +1119,62 @@ TEST_F(AssemblerX86_64Test, Movaps) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::movaps, "movaps %{reg2}, %{reg1}"), "movaps"); } +TEST_F(AssemblerX86_64AVXTest, VMovaps) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::vmovaps, "vmovaps %{reg2}, %{reg1}"), "vmovaps"); +} + +TEST_F(AssemblerX86_64AVXTest, Movaps) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::movaps, "vmovaps %{reg2}, %{reg1}"), "avx_movaps"); +} + TEST_F(AssemblerX86_64Test, MovapsStore) { DriverStr(RepeatAF(&x86_64::X86_64Assembler::movaps, "movaps %{reg}, {mem}"), "movaps_s"); } +TEST_F(AssemblerX86_64AVXTest, VMovapsStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::vmovaps, "vmovaps %{reg}, {mem}"), "vmovaps_s"); +} + +TEST_F(AssemblerX86_64AVXTest, MovapsStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::movaps, "vmovaps %{reg}, {mem}"), "avx_movaps_s"); +} + TEST_F(AssemblerX86_64Test, MovapsLoad) { DriverStr(RepeatFA(&x86_64::X86_64Assembler::movaps, "movaps {mem}, %{reg}"), "movaps_l"); } +TEST_F(AssemblerX86_64AVXTest, VMovapsLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::vmovaps, "vmovaps {mem}, %{reg}"), "vmovaps_l"); +} + +TEST_F(AssemblerX86_64AVXTest, MovapsLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::movaps, "vmovaps {mem}, %{reg}"), "avx_movaps_l"); +} + TEST_F(AssemblerX86_64Test, MovupsStore) { DriverStr(RepeatAF(&x86_64::X86_64Assembler::movups, "movups %{reg}, {mem}"), "movups_s"); } +TEST_F(AssemblerX86_64AVXTest, VMovupsStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::vmovups, "vmovups %{reg}, {mem}"), "vmovups_s"); +} + +TEST_F(AssemblerX86_64AVXTest, MovupsStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::movups, "vmovups %{reg}, {mem}"), "avx_movups_s"); +} + TEST_F(AssemblerX86_64Test, MovupsLoad) { DriverStr(RepeatFA(&x86_64::X86_64Assembler::movups, "movups {mem}, %{reg}"), "movups_l"); } +TEST_F(AssemblerX86_64AVXTest, VMovupsLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::vmovups, "vmovups {mem}, %{reg}"), "vmovups_l"); +} + +TEST_F(AssemblerX86_64AVXTest, MovupsLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::movups, "vmovups {mem}, %{reg}"), "avx_movups_l"); +} + TEST_F(AssemblerX86_64Test, Movss) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::movss, "movss %{reg2}, %{reg1}"), "movss"); } @@ -1131,22 +1183,62 @@ TEST_F(AssemblerX86_64Test, Movapd) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::movapd, "movapd %{reg2}, %{reg1}"), "movapd"); } +TEST_F(AssemblerX86_64AVXTest, VMovapd) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::vmovapd, "vmovapd %{reg2}, %{reg1}"), "vmovapd"); +} + +TEST_F(AssemblerX86_64AVXTest, Movapd) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::movapd, "vmovapd %{reg2}, %{reg1}"), "avx_movapd"); +} + TEST_F(AssemblerX86_64Test, MovapdStore) { DriverStr(RepeatAF(&x86_64::X86_64Assembler::movapd, "movapd %{reg}, {mem}"), "movapd_s"); } +TEST_F(AssemblerX86_64AVXTest, VMovapdStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::vmovapd, "vmovapd %{reg}, {mem}"), "vmovapd_s"); +} + +TEST_F(AssemblerX86_64AVXTest, MovapdStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::movapd, "vmovapd %{reg}, {mem}"), "avx_movapd_s"); +} + TEST_F(AssemblerX86_64Test, MovapdLoad) { DriverStr(RepeatFA(&x86_64::X86_64Assembler::movapd, "movapd {mem}, %{reg}"), "movapd_l"); } +TEST_F(AssemblerX86_64AVXTest, VMovapdLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::vmovapd, "vmovapd {mem}, %{reg}"), "vmovapd_l"); +} + +TEST_F(AssemblerX86_64AVXTest, MovapdLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::movapd, "vmovapd {mem}, %{reg}"), "avx_movapd_l"); +} + TEST_F(AssemblerX86_64Test, MovupdStore) { DriverStr(RepeatAF(&x86_64::X86_64Assembler::movupd, "movupd %{reg}, {mem}"), "movupd_s"); } +TEST_F(AssemblerX86_64AVXTest, VMovupdStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::vmovupd, "vmovupd %{reg}, {mem}"), "vmovupd_s"); +} + +TEST_F(AssemblerX86_64AVXTest, MovupdStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::movupd, "vmovupd %{reg}, {mem}"), "avx_movupd_s"); +} + TEST_F(AssemblerX86_64Test, MovupdLoad) { DriverStr(RepeatFA(&x86_64::X86_64Assembler::movupd, "movupd {mem}, %{reg}"), "movupd_l"); } +TEST_F(AssemblerX86_64AVXTest, VMovupdLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::vmovupd, "vmovupd {mem}, %{reg}"), "vmovupd_l"); +} + +TEST_F(AssemblerX86_64AVXTest, MovupdLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::movupd, "vmovupd {mem}, %{reg}"), "avx_movupd_l"); +} + TEST_F(AssemblerX86_64Test, Movsd) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::movsd, "movsd %{reg2}, %{reg1}"), "movsd"); } @@ -1155,22 +1247,62 @@ TEST_F(AssemblerX86_64Test, Movdqa) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::movdqa, "movdqa %{reg2}, %{reg1}"), "movdqa"); } +TEST_F(AssemblerX86_64AVXTest, VMovdqa) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::vmovdqa, "vmovdqa %{reg2}, %{reg1}"), "vmovdqa"); +} + +TEST_F(AssemblerX86_64AVXTest, Movdqa) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::movdqa, "vmovdqa %{reg2}, %{reg1}"), "avx_movdqa"); +} + TEST_F(AssemblerX86_64Test, MovdqaStore) { DriverStr(RepeatAF(&x86_64::X86_64Assembler::movdqa, "movdqa %{reg}, {mem}"), "movdqa_s"); } +TEST_F(AssemblerX86_64AVXTest, VMovdqaStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::vmovdqa, "vmovdqa %{reg}, {mem}"), "vmovdqa_s"); +} + +TEST_F(AssemblerX86_64AVXTest, MovdqaStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::movdqa, "vmovdqa %{reg}, {mem}"), "avx_movdqa_s"); +} + TEST_F(AssemblerX86_64Test, MovdqaLoad) { DriverStr(RepeatFA(&x86_64::X86_64Assembler::movdqa, "movdqa {mem}, %{reg}"), "movdqa_l"); } +TEST_F(AssemblerX86_64AVXTest, VMovdqaLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::vmovdqa, "vmovdqa {mem}, %{reg}"), "vmovdqa_l"); +} + +TEST_F(AssemblerX86_64AVXTest, MovdqaLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::movdqa, "vmovdqa {mem}, %{reg}"), "avx_movdqa_l"); +} + TEST_F(AssemblerX86_64Test, MovdquStore) { DriverStr(RepeatAF(&x86_64::X86_64Assembler::movdqu, "movdqu %{reg}, {mem}"), "movdqu_s"); } +TEST_F(AssemblerX86_64AVXTest, VMovdquStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::vmovdqu, "vmovdqu %{reg}, {mem}"), "vmovdqu_s"); +} + +TEST_F(AssemblerX86_64AVXTest, MovdquStore) { + DriverStr(RepeatAF(&x86_64::X86_64Assembler::movdqu, "vmovdqu %{reg}, {mem}"), "avx_movdqu_s"); +} + TEST_F(AssemblerX86_64Test, MovdquLoad) { DriverStr(RepeatFA(&x86_64::X86_64Assembler::movdqu, "movdqu {mem}, %{reg}"), "movdqu_l"); } +TEST_F(AssemblerX86_64AVXTest, VMovdquLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::vmovdqu, "vmovdqu {mem}, %{reg}"), "vmovdqu_l"); +} + +TEST_F(AssemblerX86_64AVXTest, MovdquLoad) { + DriverStr(RepeatFA(&x86_64::X86_64Assembler::movdqu, "vmovdqu {mem}, %{reg}"), "avx_movdqu_l"); +} + TEST_F(AssemblerX86_64Test, Movd1) { DriverStr(RepeatFR(&x86_64::X86_64Assembler::movd, "movd %{reg2}, %{reg1}"), "movd.1"); } @@ -1191,10 +1323,20 @@ TEST_F(AssemblerX86_64Test, Addps) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::addps, "addps %{reg2}, %{reg1}"), "addps"); } +TEST_F(AssemblerX86_64AVXTest, VAddps) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vaddps, "vaddps %{reg3}, %{reg2}, %{reg1}"), "vaddps"); +} + TEST_F(AssemblerX86_64Test, Addpd) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::addpd, "addpd %{reg2}, %{reg1}"), "addpd"); } +TEST_F(AssemblerX86_64AVXTest, VAddpd) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vaddpd, "vaddpd %{reg3}, %{reg2}, %{reg1}"), "vaddpd"); +} + TEST_F(AssemblerX86_64Test, Subss) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::subss, "subss %{reg2}, %{reg1}"), "subss"); } @@ -1207,10 +1349,20 @@ TEST_F(AssemblerX86_64Test, Subps) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::subps, "subps %{reg2}, %{reg1}"), "subps"); } +TEST_F(AssemblerX86_64AVXTest, VSubps) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vsubps, "vsubps %{reg3},%{reg2}, %{reg1}"), "vsubps"); +} + TEST_F(AssemblerX86_64Test, Subpd) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::subpd, "subpd %{reg2}, %{reg1}"), "subpd"); } +TEST_F(AssemblerX86_64AVXTest, VSubpd) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vsubpd, "vsubpd %{reg3}, %{reg2}, %{reg1}"), "vsubpd"); +} + TEST_F(AssemblerX86_64Test, Mulss) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::mulss, "mulss %{reg2}, %{reg1}"), "mulss"); } @@ -1223,10 +1375,20 @@ TEST_F(AssemblerX86_64Test, Mulps) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::mulps, "mulps %{reg2}, %{reg1}"), "mulps"); } +TEST_F(AssemblerX86_64AVXTest, VMulps) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vmulps, "vmulps %{reg3}, %{reg2}, %{reg1}"), "vmulps"); +} + TEST_F(AssemblerX86_64Test, Mulpd) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::mulpd, "mulpd %{reg2}, %{reg1}"), "mulpd"); } +TEST_F(AssemblerX86_64AVXTest, VMulpd) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vmulpd, "vmulpd %{reg3}, %{reg2}, %{reg1}"), "vmulpd"); +} + TEST_F(AssemblerX86_64Test, Divss) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::divss, "divss %{reg2}, %{reg1}"), "divss"); } @@ -1239,22 +1401,52 @@ TEST_F(AssemblerX86_64Test, Divps) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::divps, "divps %{reg2}, %{reg1}"), "divps"); } +TEST_F(AssemblerX86_64AVXTest, VDivps) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vdivps, "vdivps %{reg3}, %{reg2}, %{reg1}"), "vdivps"); +} + TEST_F(AssemblerX86_64Test, Divpd) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::divpd, "divpd %{reg2}, %{reg1}"), "divpd"); } +TEST_F(AssemblerX86_64AVXTest, VDivpd) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vdivpd, "vdivpd %{reg3}, %{reg2}, %{reg1}"), "vdivpd"); +} + TEST_F(AssemblerX86_64Test, Paddb) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::paddb, "paddb %{reg2}, %{reg1}"), "paddb"); } +TEST_F(AssemblerX86_64AVXTest, VPaddb) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpaddb, "vpaddb %{reg3}, %{reg2}, %{reg1}"), "vpaddb"); +} + TEST_F(AssemblerX86_64Test, Psubb) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::psubb, "psubb %{reg2}, %{reg1}"), "psubb"); } +TEST_F(AssemblerX86_64AVXTest, VPsubb) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpsubb, "vpsubb %{reg3},%{reg2}, %{reg1}"), "vpsubb"); +} + TEST_F(AssemblerX86_64Test, Paddw) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::paddw, "paddw %{reg2}, %{reg1}"), "paddw"); } +TEST_F(AssemblerX86_64AVXTest, VPsubw) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpsubw, "vpsubw %{reg3}, %{reg2}, %{reg1}"), "vpsubw"); +} + +TEST_F(AssemblerX86_64AVXTest, VPaddw) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpaddw, "vpaddw %{reg3}, %{reg2}, %{reg1}"), "vpaddw"); +} + TEST_F(AssemblerX86_64Test, Psubw) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::psubw, "psubw %{reg2}, %{reg1}"), "psubw"); } @@ -1263,26 +1455,56 @@ TEST_F(AssemblerX86_64Test, Pmullw) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::pmullw, "pmullw %{reg2}, %{reg1}"), "pmullw"); } +TEST_F(AssemblerX86_64AVXTest, VPmullw) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpmullw, "vpmullw %{reg3}, %{reg2}, %{reg1}"), "vpmullw"); +} + TEST_F(AssemblerX86_64Test, Paddd) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::paddd, "paddd %{reg2}, %{reg1}"), "paddd"); } +TEST_F(AssemblerX86_64AVXTest, VPaddd) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpaddd, "vpaddd %{reg3}, %{reg2}, %{reg1}"), "vpaddd"); +} + TEST_F(AssemblerX86_64Test, Psubd) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::psubd, "psubd %{reg2}, %{reg1}"), "psubd"); } +TEST_F(AssemblerX86_64AVXTest, VPsubd) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpsubd, "vpsubd %{reg3}, %{reg2}, %{reg1}"), "vpsubd"); +} + TEST_F(AssemblerX86_64Test, Pmulld) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::pmulld, "pmulld %{reg2}, %{reg1}"), "pmulld"); } +TEST_F(AssemblerX86_64AVXTest, VPmulld) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpmulld, "vpmulld %{reg3}, %{reg2}, %{reg1}"), "vpmulld"); +} + TEST_F(AssemblerX86_64Test, Paddq) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::paddq, "paddq %{reg2}, %{reg1}"), "paddq"); } +TEST_F(AssemblerX86_64AVXTest, VPaddq) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpaddq, "vpaddq %{reg3}, %{reg2}, %{reg1}"), "vpaddq"); +} + TEST_F(AssemblerX86_64Test, Psubq) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::psubq, "psubq %{reg2}, %{reg1}"), "psubq"); } +TEST_F(AssemblerX86_64AVXTest, VPsubq) { + DriverStr( + RepeatFFF(&x86_64::X86_64Assembler::vpsubq, "vpsubq %{reg3}, %{reg2}, %{reg1}"), "vpsubq"); +} + TEST_F(AssemblerX86_64Test, Paddusb) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::paddusb, "paddusb %{reg2}, %{reg1}"), "paddusb"); } @@ -1403,6 +1625,21 @@ TEST_F(AssemblerX86_64Test, Pxor) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::pxor, "pxor %{reg2}, %{reg1}"), "pxor"); } +TEST_F(AssemblerX86_64AVXTest, VPXor) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vpxor, + "vpxor %{reg3}, %{reg2}, %{reg1}"), "vpxor"); +} + +TEST_F(AssemblerX86_64AVXTest, VXorps) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vxorps, + "vxorps %{reg3}, %{reg2}, %{reg1}"), "vxorps"); +} + +TEST_F(AssemblerX86_64AVXTest, VXorpd) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vxorpd, + "vxorpd %{reg3}, %{reg2}, %{reg1}"), "vxorpd"); +} + TEST_F(AssemblerX86_64Test, Andps) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::andps, "andps %{reg2}, %{reg1}"), "andps"); } @@ -1414,6 +1651,22 @@ TEST_F(AssemblerX86_64Test, Andpd) { TEST_F(AssemblerX86_64Test, Pand) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::pand, "pand %{reg2}, %{reg1}"), "pand"); } + +TEST_F(AssemblerX86_64AVXTest, VPAnd) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vpand, + "vpand %{reg3}, %{reg2}, %{reg1}"), "vpand"); +} + +TEST_F(AssemblerX86_64AVXTest, VAndps) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vandps, + "vandps %{reg3}, %{reg2}, %{reg1}"), "vandps"); +} + +TEST_F(AssemblerX86_64AVXTest, VAndpd) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vandpd, + "vandpd %{reg3}, %{reg2}, %{reg1}"), "vandpd"); +} + TEST_F(AssemblerX86_64Test, Andn) { DriverStr(RepeatRRR(&x86_64::X86_64Assembler::andn, "andn %{reg3}, %{reg2}, %{reg1}"), "andn"); } @@ -1429,6 +1682,21 @@ TEST_F(AssemblerX86_64Test, Pandn) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::pandn, "pandn %{reg2}, %{reg1}"), "pandn"); } +TEST_F(AssemblerX86_64AVXTest, VPAndn) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vpandn, + "vpandn %{reg3}, %{reg2}, %{reg1}"), "vpandn"); +} + +TEST_F(AssemblerX86_64AVXTest, VAndnps) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vandnps, + "vandnps %{reg3}, %{reg2}, %{reg1}"), "vandnps"); +} + +TEST_F(AssemblerX86_64AVXTest, VAndnpd) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vandnpd, + "vandnpd %{reg3}, %{reg2}, %{reg1}"), "vandnpd"); +} + TEST_F(AssemblerX86_64Test, Orps) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::orps, "orps %{reg2}, %{reg1}"), "orps"); } @@ -1441,6 +1709,21 @@ TEST_F(AssemblerX86_64Test, Por) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::por, "por %{reg2}, %{reg1}"), "por"); } +TEST_F(AssemblerX86_64AVXTest, VPor) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vpor, + "vpor %{reg3}, %{reg2}, %{reg1}"), "vpor"); +} + +TEST_F(AssemblerX86_64AVXTest, Vorps) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vorps, + "vorps %{reg3}, %{reg2}, %{reg1}"), "vorps"); +} + +TEST_F(AssemblerX86_64AVXTest, Vorpd) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vorpd, + "vorpd %{reg3}, %{reg2}, %{reg1}"), "vorpd"); +} + TEST_F(AssemblerX86_64Test, Pavgb) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::pavgb, "pavgb %{reg2}, %{reg1}"), "pavgb"); } @@ -1457,6 +1740,11 @@ TEST_F(AssemblerX86_64Test, Pmaddwd) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::pmaddwd, "pmaddwd %{reg2}, %{reg1}"), "pmadwd"); } +TEST_F(AssemblerX86_64AVXTest, VPmaddwd) { + DriverStr(RepeatFFF(&x86_64::X86_64Assembler::vpmaddwd, + "vpmaddwd %{reg3}, %{reg2}, %{reg1}"), "vpmaddwd"); +} + TEST_F(AssemblerX86_64Test, Phaddw) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::phaddw, "phaddw %{reg2}, %{reg1}"), "phaddw"); } @@ -2122,7 +2410,7 @@ std::string increaseframe_test_fn( // Construct assembly text counterpart. std::ostringstream str; - str << "addq $0, %rsp\n"; + // Increase by 0 is a NO-OP and ignored by the assembler. str << "addq $-" << kStackAlignment << ", %rsp\n"; str << "addq $-" << 10 * kStackAlignment << ", %rsp\n"; @@ -2142,7 +2430,7 @@ std::string decreaseframe_test_fn( // Construct assembly text counterpart. std::ostringstream str; - str << "addq $0, %rsp\n"; + // Decrease by 0 is a NO-OP and ignored by the assembler. str << "addq $" << kStackAlignment << ", %rsp\n"; str << "addq $" << 10 * kStackAlignment << ", %rsp\n"; diff --git a/compiler/utils/x86_64/constants_x86_64.h b/compiler/utils/x86_64/constants_x86_64.h index b02e246842..5335398de9 100644 --- a/compiler/utils/x86_64/constants_x86_64.h +++ b/compiler/utils/x86_64/constants_x86_64.h @@ -59,6 +59,9 @@ class XmmRegister { constexpr bool NeedsRex() const { return reg_ > 7; } + bool operator==(XmmRegister& other) { + return reg_ == other.reg_; + } private: const FloatRegister reg_; }; diff --git a/compiler/utils/x86_64/jni_macro_assembler_x86_64.cc b/compiler/utils/x86_64/jni_macro_assembler_x86_64.cc index 5924a8bd08..ffe90206a0 100644 --- a/compiler/utils/x86_64/jni_macro_assembler_x86_64.cc +++ b/compiler/utils/x86_64/jni_macro_assembler_x86_64.cc @@ -33,6 +33,9 @@ static dwarf::Reg DWARFReg(FloatRegister reg) { constexpr size_t kFramePointerSize = 8; +static constexpr size_t kNativeStackAlignment = 16; +static_assert(kNativeStackAlignment == kStackAlignment); + #define __ asm_. void X86_64JNIMacroAssembler::BuildFrame(size_t frame_size, @@ -41,8 +44,13 @@ void X86_64JNIMacroAssembler::BuildFrame(size_t frame_size, const ManagedRegisterEntrySpills& entry_spills) { DCHECK_EQ(CodeSize(), 0U); // Nothing emitted yet. cfi().SetCurrentCFAOffset(8); // Return address on stack. - CHECK_ALIGNED(frame_size, kStackAlignment); - int gpr_count = 0; + // Note: @CriticalNative tail call is not used (would have frame_size == kFramePointerSize). + if (method_reg.IsNoRegister()) { + CHECK_ALIGNED(frame_size, kNativeStackAlignment); + } else { + CHECK_ALIGNED(frame_size, kStackAlignment); + } + size_t gpr_count = 0u; for (int i = spill_regs.size() - 1; i >= 0; --i) { x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64(); if (spill.IsCpuRegister()) { @@ -56,8 +64,10 @@ void X86_64JNIMacroAssembler::BuildFrame(size_t frame_size, int64_t rest_of_frame = static_cast<int64_t>(frame_size) - (gpr_count * kFramePointerSize) - kFramePointerSize /*return address*/; - __ subq(CpuRegister(RSP), Immediate(rest_of_frame)); - cfi().AdjustCFAOffset(rest_of_frame); + if (rest_of_frame != 0) { + __ subq(CpuRegister(RSP), Immediate(rest_of_frame)); + cfi().AdjustCFAOffset(rest_of_frame); + } // spill xmms int64_t offset = rest_of_frame; @@ -73,7 +83,9 @@ void X86_64JNIMacroAssembler::BuildFrame(size_t frame_size, static_assert(static_cast<size_t>(kX86_64PointerSize) == kFramePointerSize, "Unexpected frame pointer size."); - __ movq(Address(CpuRegister(RSP), 0), method_reg.AsX86_64().AsCpuRegister()); + if (method_reg.IsRegister()) { + __ movq(Address(CpuRegister(RSP), 0), method_reg.AsX86_64().AsCpuRegister()); + } for (const ManagedRegisterSpill& spill : entry_spills) { if (spill.AsX86_64().IsCpuRegister()) { @@ -101,26 +113,29 @@ void X86_64JNIMacroAssembler::BuildFrame(size_t frame_size, void X86_64JNIMacroAssembler::RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> spill_regs, bool may_suspend ATTRIBUTE_UNUSED) { - CHECK_ALIGNED(frame_size, kStackAlignment); + CHECK_ALIGNED(frame_size, kNativeStackAlignment); cfi().RememberState(); int gpr_count = 0; // unspill xmms int64_t offset = static_cast<int64_t>(frame_size) - (spill_regs.size() * kFramePointerSize) - - 2 * kFramePointerSize; + - kFramePointerSize; for (size_t i = 0; i < spill_regs.size(); ++i) { x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64(); if (spill.IsXmmRegister()) { - offset += sizeof(double); __ movsd(spill.AsXmmRegister(), Address(CpuRegister(RSP), offset)); cfi().Restore(DWARFReg(spill.AsXmmRegister().AsFloatRegister())); + offset += sizeof(double); } else { gpr_count++; } } - int adjust = static_cast<int>(frame_size) - (gpr_count * kFramePointerSize) - kFramePointerSize; - __ addq(CpuRegister(RSP), Immediate(adjust)); - cfi().AdjustCFAOffset(-adjust); + DCHECK_EQ(static_cast<size_t>(offset), + frame_size - (gpr_count * kFramePointerSize) - kFramePointerSize); + if (offset != 0) { + __ addq(CpuRegister(RSP), Immediate(offset)); + cfi().AdjustCFAOffset(-offset); + } for (size_t i = 0; i < spill_regs.size(); ++i) { x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64(); if (spill.IsCpuRegister()) { @@ -136,15 +151,19 @@ void X86_64JNIMacroAssembler::RemoveFrame(size_t frame_size, } void X86_64JNIMacroAssembler::IncreaseFrameSize(size_t adjust) { - CHECK_ALIGNED(adjust, kStackAlignment); - __ addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(adjust))); - cfi().AdjustCFAOffset(adjust); + if (adjust != 0u) { + CHECK_ALIGNED(adjust, kNativeStackAlignment); + __ addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(adjust))); + cfi().AdjustCFAOffset(adjust); + } } static void DecreaseFrameSizeImpl(size_t adjust, X86_64Assembler* assembler) { - CHECK_ALIGNED(adjust, kStackAlignment); - assembler->addq(CpuRegister(RSP), Immediate(adjust)); - assembler->cfi().AdjustCFAOffset(-adjust); + if (adjust != 0u) { + CHECK_ALIGNED(adjust, kNativeStackAlignment); + assembler->addq(CpuRegister(RSP), Immediate(adjust)); + assembler->cfi().AdjustCFAOffset(-adjust); + } } void X86_64JNIMacroAssembler::DecreaseFrameSize(size_t adjust) { @@ -544,6 +563,12 @@ void X86_64JNIMacroAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_ // TODO: not validating references } +void X86_64JNIMacroAssembler::Jump(ManagedRegister mbase, Offset offset, ManagedRegister) { + X86_64ManagedRegister base = mbase.AsX86_64(); + CHECK(base.IsCpuRegister()); + __ jmp(Address(base.AsCpuRegister(), offset.Int32Value())); +} + void X86_64JNIMacroAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister) { X86_64ManagedRegister base = mbase.AsX86_64(); CHECK(base.IsCpuRegister()); diff --git a/compiler/utils/x86_64/jni_macro_assembler_x86_64.h b/compiler/utils/x86_64/jni_macro_assembler_x86_64.h index 4c2fd8fc73..d3f1fce9bb 100644 --- a/compiler/utils/x86_64/jni_macro_assembler_x86_64.h +++ b/compiler/utils/x86_64/jni_macro_assembler_x86_64.h @@ -172,6 +172,9 @@ class X86_64JNIMacroAssembler final : public JNIMacroAssemblerFwd<X86_64Assemble void VerifyObject(ManagedRegister src, bool could_be_null) override; void VerifyObject(FrameOffset src, bool could_be_null) override; + // Jump to address held at [base+offset] (used for tail calls). + void Jump(ManagedRegister base, Offset offset, ManagedRegister scratch) override; + // Call to address held at [base+offset] void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) override; void Call(FrameOffset base, Offset offset, ManagedRegister scratch) override; |