diff options
author | 2020-02-12 10:52:22 +0000 | |
---|---|---|
committer | 2020-02-13 15:07:15 +0000 | |
commit | 2c8123c1480dcd42e31963697264fca7ad6fa154 (patch) | |
tree | 9599252703d41b43ac973c38032385b303bcb9c8 | |
parent | c3f2fe95ef4f3a51039e497b02b978e7d85ee3fa (diff) |
Remove MIPS support from JNI/trampoline compiler.
Also remove MIPS assembler/disassembler support.
Test: aosp_taimen-userdebug boots.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 147346243
Change-Id: Id736074b97cd04987a7902741828b119508df1c0
36 files changed, 3 insertions, 26336 deletions
diff --git a/build/Android.bp b/build/Android.bp index d1026cad2f..946e5a60e9 100644 --- a/build/Android.bp +++ b/build/Android.bp @@ -198,12 +198,6 @@ art_global_defaults { arm64: { cflags: ["-DART_ENABLE_CODEGEN_arm64"], }, - mips: { - cflags: ["-DART_ENABLE_CODEGEN_mips"], - }, - mips64: { - cflags: ["-DART_ENABLE_CODEGEN_mips64"], - }, x86: { cflags: ["-DART_ENABLE_CODEGEN_x86"], }, diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py index fca1f15137..71c58838cf 100755 --- a/build/apex/art_apex_test.py +++ b/build/apex/art_apex_test.py @@ -753,7 +753,6 @@ class TestingTargetChecker: self._checker.check_optional_art_test_executable('liveness_test') self._checker.check_optional_art_test_executable('managed_register_arm64_test') self._checker.check_optional_art_test_executable('managed_register_arm_test') - self._checker.check_optional_art_test_executable('managed_register_mips64_test') self._checker.check_optional_art_test_executable('managed_register_x86_64_test') self._checker.check_optional_art_test_executable('managed_register_x86_test') self._checker.check_optional_art_test_executable('register_allocator_test') diff --git a/compiler/Android.bp b/compiler/Android.bp index 2b95003769..c7a6ec2e2c 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -121,20 +121,6 @@ art_cc_defaults { "utils/arm64/managed_register_arm64.cc", ], }, - mips: { - srcs: [ - "jni/quick/mips/calling_convention_mips.cc", - "utils/mips/assembler_mips.cc", - "utils/mips/managed_register_mips.cc", - ], - }, - mips64: { - srcs: [ - "jni/quick/mips64/calling_convention_mips64.cc", - "utils/mips64/assembler_mips64.cc", - "utils/mips64/managed_register_mips64.cc", - ], - }, x86: { srcs: [ "jni/quick/x86/calling_convention_x86.cc", @@ -194,8 +180,6 @@ gensrcs { "optimizing/optimizing_compiler_stats.h", "utils/arm/constants_arm.h", - "utils/mips/assembler_mips.h", - "utils/mips64/assembler_mips64.h", ], output_extension: "operator_out.cc", } @@ -418,15 +402,6 @@ art_cc_test { "utils/arm64/managed_register_arm64_test.cc", ], }, - mips: { - srcs: [ - ], - }, - mips64: { - srcs: [ - "utils/mips64/managed_register_mips64_test.cc", - ], - }, x86: { srcs: [ "utils/x86/managed_register_x86_test.cc", @@ -486,18 +461,6 @@ art_cc_test { "utils/assembler_thumb_test.cc", ], }, - mips: { - srcs: [ - "utils/mips/assembler_mips_test.cc", - "utils/mips/assembler_mips32r5_test.cc", - "utils/mips/assembler_mips32r6_test.cc", - ], - }, - mips64: { - srcs: [ - "utils/mips64/assembler_mips64_test.cc", - ], - }, x86: { srcs: [ "utils/x86/assembler_x86_test.cc", diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc index 58f7e4f227..03b87ef09e 100644 --- a/compiler/compiled_method.cc +++ b/compiler/compiled_method.cc @@ -62,8 +62,6 @@ size_t CompiledCode::CodeDelta(InstructionSet instruction_set) { switch (instruction_set) { case InstructionSet::kArm: case InstructionSet::kArm64: - case InstructionSet::kMips: - case InstructionSet::kMips64: case InstructionSet::kX86: case InstructionSet::kX86_64: return 0; @@ -81,8 +79,6 @@ const void* CompiledCode::CodePointer(const void* code_pointer, InstructionSet i switch (instruction_set) { case InstructionSet::kArm: case InstructionSet::kArm64: - case InstructionSet::kMips: - case InstructionSet::kMips64: case InstructionSet::kX86: case InstructionSet::kX86_64: return code_pointer; diff --git a/compiler/jni/jni_cfi_test.cc b/compiler/jni/jni_cfi_test.cc index b19a2b8843..cec94c922b 100644 --- a/compiler/jni/jni_cfi_test.cc +++ b/compiler/jni/jni_cfi_test.cc @@ -142,14 +142,6 @@ TEST_ISA(kX86) TEST_ISA(kX86_64) #endif -#ifdef ART_ENABLE_CODEGEN_mips -TEST_ISA(kMips) -#endif - -#ifdef ART_ENABLE_CODEGEN_mips64 -TEST_ISA(kMips64) -#endif - #endif // ART_TARGET_ANDROID } // namespace art diff --git a/compiler/jni/jni_cfi_test_expected.inc b/compiler/jni/jni_cfi_test_expected.inc index d641fe4251..489ae00f3a 100644 --- a/compiler/jni/jni_cfi_test_expected.inc +++ b/compiler/jni/jni_cfi_test_expected.inc @@ -328,146 +328,3 @@ static constexpr uint8_t expected_cfi_kX86_64[] = { // 0x0000007f: .cfi_restore_state // 0x0000007f: .cfi_def_cfa_offset: 128 -static constexpr uint8_t expected_asm_kMips[] = { - 0xC0, 0xFF, 0xBD, 0x27, 0x3C, 0x00, 0xBF, 0xAF, 0x38, 0x00, 0xBE, 0xAF, - 0x34, 0x00, 0xB7, 0xAF, 0x30, 0x00, 0xB6, 0xAF, 0x2C, 0x00, 0xB5, 0xAF, - 0x28, 0x00, 0xB4, 0xAF, 0x24, 0x00, 0xB3, 0xAF, 0x20, 0x00, 0xB2, 0xAF, - 0x00, 0x00, 0xA4, 0xAF, 0x44, 0x00, 0xA5, 0xAF, 0x48, 0x00, 0xA8, 0xE7, - 0x4C, 0x00, 0xA6, 0xAF, 0x50, 0x00, 0xA7, 0xAF, 0xE0, 0xFF, 0xBD, 0x27, - 0x20, 0x00, 0xBD, 0x27, 0x20, 0x00, 0xB2, 0x8F, 0x24, 0x00, 0xB3, 0x8F, - 0x28, 0x00, 0xB4, 0x8F, 0x2C, 0x00, 0xB5, 0x8F, 0x30, 0x00, 0xB6, 0x8F, - 0x34, 0x00, 0xB7, 0x8F, 0x38, 0x00, 0xBE, 0x8F, 0x3C, 0x00, 0xBF, 0x8F, - 0x09, 0x00, 0xE0, 0x03, 0x40, 0x00, 0xBD, 0x27, -}; -static constexpr uint8_t expected_cfi_kMips[] = { - 0x44, 0x0E, 0x40, 0x44, 0x9F, 0x01, 0x44, 0x9E, 0x02, 0x44, 0x97, 0x03, - 0x44, 0x96, 0x04, 0x44, 0x95, 0x05, 0x44, 0x94, 0x06, 0x44, 0x93, 0x07, - 0x44, 0x92, 0x08, 0x58, 0x0E, 0x60, 0x44, 0x0E, 0x40, 0x0A, 0x44, 0xD2, - 0x44, 0xD3, 0x44, 0xD4, 0x44, 0xD5, 0x44, 0xD6, 0x44, 0xD7, 0x44, 0xDE, - 0x44, 0xDF, 0x48, 0x0E, 0x00, 0x0B, 0x0E, 0x40, -}; -// 0x00000000: addiu r29, r29, -64 -// 0x00000004: .cfi_def_cfa_offset: 64 -// 0x00000004: sw r31, +60(r29) -// 0x00000008: .cfi_offset: r31 at cfa-4 -// 0x00000008: sw r30, +56(r29) -// 0x0000000c: .cfi_offset: r30 at cfa-8 -// 0x0000000c: sw r23, +52(r29) -// 0x00000010: .cfi_offset: r23 at cfa-12 -// 0x00000010: sw r22, +48(r29) -// 0x00000014: .cfi_offset: r22 at cfa-16 -// 0x00000014: sw r21, +44(r29) -// 0x00000018: .cfi_offset: r21 at cfa-20 -// 0x00000018: sw r20, +40(r29) -// 0x0000001c: .cfi_offset: r20 at cfa-24 -// 0x0000001c: sw r19, +36(r29) -// 0x00000020: .cfi_offset: r19 at cfa-28 -// 0x00000020: sw r18, +32(r29) -// 0x00000024: .cfi_offset: r18 at cfa-32 -// 0x00000024: sw r4, +0(r29) -// 0x00000028: sw r5, +68(r29) -// 0x0000002c: swc1 f8, +72(r29) -// 0x00000030: sw r6, +76(r29) -// 0x00000034: sw r7, +80(r29) -// 0x00000038: addiu r29, r29, -32 -// 0x0000003c: .cfi_def_cfa_offset: 96 -// 0x0000003c: addiu r29, r29, 32 -// 0x00000040: .cfi_def_cfa_offset: 64 -// 0x00000040: .cfi_remember_state -// 0x00000040: lw r18, +32(r29) -// 0x00000044: .cfi_restore: r18 -// 0x00000044: lw r19, +36(r29) -// 0x00000048: .cfi_restore: r19 -// 0x00000048: lw r20, +40(r29) -// 0x0000004c: .cfi_restore: r20 -// 0x0000004c: lw r21, +44(r29) -// 0x00000050: .cfi_restore: r21 -// 0x00000050: lw r22, +48(r29) -// 0x00000054: .cfi_restore: r22 -// 0x00000054: lw r23, +52(r29) -// 0x00000058: .cfi_restore: r23 -// 0x00000058: lw r30, +56(r29) -// 0x0000005c: .cfi_restore: r30 -// 0x0000005c: lw r31, +60(r29) -// 0x00000060: .cfi_restore: r31 -// 0x00000060: jr r31 -// 0x00000064: addiu r29, r29, 64 -// 0x00000068: .cfi_def_cfa_offset: 0 -// 0x00000068: .cfi_restore_state -// 0x00000068: .cfi_def_cfa_offset: 64 - -static constexpr uint8_t expected_asm_kMips64[] = { - 0x90, 0xFF, 0xBD, 0x67, 0x68, 0x00, 0xBF, 0xFF, 0x60, 0x00, 0xBE, 0xFF, - 0x58, 0x00, 0xBC, 0xFF, 0x50, 0x00, 0xB7, 0xFF, 0x48, 0x00, 0xB6, 0xFF, - 0x40, 0x00, 0xB5, 0xFF, 0x38, 0x00, 0xB4, 0xFF, 0x30, 0x00, 0xB3, 0xFF, - 0x28, 0x00, 0xB2, 0xFF, 0x00, 0x00, 0xA4, 0xFF, 0x78, 0x00, 0xA5, 0xAF, - 0x7C, 0x00, 0xAE, 0xE7, 0x80, 0x00, 0xA7, 0xAF, 0x84, 0x00, 0xA8, 0xAF, - 0xE0, 0xFF, 0xBD, 0x67, 0x20, 0x00, 0xBD, 0x67, 0x28, 0x00, 0xB2, 0xDF, - 0x30, 0x00, 0xB3, 0xDF, 0x38, 0x00, 0xB4, 0xDF, 0x40, 0x00, 0xB5, 0xDF, - 0x48, 0x00, 0xB6, 0xDF, 0x50, 0x00, 0xB7, 0xDF, 0x58, 0x00, 0xBC, 0xDF, - 0x60, 0x00, 0xBE, 0xDF, 0x68, 0x00, 0xBF, 0xDF, 0x70, 0x00, 0xBD, 0x67, - 0x09, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x00, -}; -static constexpr uint8_t expected_cfi_kMips64[] = { - 0x44, 0x0E, 0x70, 0x44, 0x9F, 0x02, 0x44, 0x9E, 0x04, 0x44, 0x9C, 0x06, - 0x44, 0x97, 0x08, 0x44, 0x96, 0x0A, 0x44, 0x95, 0x0C, 0x44, 0x94, 0x0E, - 0x44, 0x93, 0x10, 0x44, 0x92, 0x12, 0x58, 0x0E, 0x90, 0x01, 0x44, 0x0E, - 0x70, 0x0A, 0x44, 0xD2, 0x44, 0xD3, 0x44, 0xD4, 0x44, 0xD5, 0x44, 0xD6, - 0x44, 0xD7, 0x44, 0xDC, 0x44, 0xDE, 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, - 0x0B, 0x0E, 0x70, -}; -// 0x00000000: daddiu r29, r29, -112 -// 0x00000004: .cfi_def_cfa_offset: 112 -// 0x00000004: sd r31, +104(r29) -// 0x00000008: .cfi_offset: r31 at cfa-8 -// 0x00000008: sd r30, +96(r29) -// 0x0000000c: .cfi_offset: r30 at cfa-16 -// 0x0000000c: sd r28, +88(r29) -// 0x00000010: .cfi_offset: r28 at cfa-24 -// 0x00000010: sd r23, +80(r29) -// 0x00000014: .cfi_offset: r23 at cfa-32 -// 0x00000014: sd r22, +72(r29) -// 0x00000018: .cfi_offset: r22 at cfa-40 -// 0x00000018: sd r21, +64(r29) -// 0x0000001c: .cfi_offset: r21 at cfa-48 -// 0x0000001c: sd r20, +56(r29) -// 0x00000020: .cfi_offset: r20 at cfa-56 -// 0x00000020: sd r19, +48(r29) -// 0x00000024: .cfi_offset: r19 at cfa-64 -// 0x00000024: sd r18, +40(r29) -// 0x00000028: .cfi_offset: r18 at cfa-72 -// 0x00000028: sd r4, +0(r29) -// 0x0000002c: sw r5, +120(r29) -// 0x00000030: swc1 f14, +124(r29) -// 0x00000034: sw r7, +128(r29) -// 0x00000038: sw r8, +132(r29) -// 0x0000003c: daddiu r29, r29, -32 -// 0x00000040: .cfi_def_cfa_offset: 144 -// 0x00000040: daddiu r29, r29, 32 -// 0x00000044: .cfi_def_cfa_offset: 112 -// 0x00000044: .cfi_remember_state -// 0x00000044: ld r18, +40(r29) -// 0x00000048: .cfi_restore: r18 -// 0x00000048: ld r19, +48(r29) -// 0x0000004c: .cfi_restore: r19 -// 0x0000004c: ld r20, +56(r29) -// 0x00000050: .cfi_restore: r20 -// 0x00000050: ld r21, +64(r29) -// 0x00000054: .cfi_restore: r21 -// 0x00000054: ld r22, +72(r29) -// 0x00000058: .cfi_restore: r22 -// 0x00000058: ld r23, +80(r29) -// 0x0000005c: .cfi_restore: r23 -// 0x0000005c: ld r28, +88(r29) -// 0x00000060: .cfi_restore: r28 -// 0x00000060: ld r30, +96(r29) -// 0x00000064: .cfi_restore: r30 -// 0x00000064: ld r31, +104(r29) -// 0x00000068: .cfi_restore: r31 -// 0x00000068: daddiu r29, r29, 112 -// 0x0000006c: .cfi_def_cfa_offset: 0 -// 0x0000006c: jr r31 -// 0x00000070: nop -// 0x00000074: .cfi_restore_state -// 0x00000074: .cfi_def_cfa_offset: 112 - diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index 0e8602e8e1..fb9704a69b 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -355,9 +355,6 @@ class JniCompilerTest : public CommonCompilerTest { void StackArgsIntsFirstImpl(); void StackArgsFloatsFirstImpl(); void StackArgsMixedImpl(); -#if defined(__mips__) && defined(__LP64__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - void StackArgsSignExtendedMips64Impl(); -#endif void NormalNativeImpl(); void FastNativeImpl(); @@ -2136,44 +2133,6 @@ void JniCompilerTest::StackArgsMixedImpl() { JNI_TEST_CRITICAL(StackArgsMixed) -#if defined(__mips__) && defined(__LP64__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -// Function will fetch the last argument passed from caller that is now on top of the stack and -// return it as a 8B long. That way we can test if the caller has properly sign-extended the -// value when placing it on the stack. -__attribute__((naked)) -jlong Java_MyClassNatives_getStackArgSignExtendedMips64( - JNIEnv*, jclass, // Arguments passed from caller - jint, jint, jint, jint, jint, jint, // through regs a0 to a7. - jint) { // The last argument will be passed on the stack. - __asm__( - ".set noreorder\n\t" // Just return and store 8 bytes from the top of the stack - "jr $ra\n\t" // in v0 (in branch delay slot). This should be the last - "ld $v0, 0($sp)\n\t"); // argument. It is a 32-bit int, but it should be sign - // extended and it occupies 64-bit location. -} - -void JniCompilerTest::StackArgsSignExtendedMips64Impl() { - uint64_t ret; - SetUpForTest(true, - "getStackArgSignExtendedMips64", - "(IIIIIII)J", - // Don't use wrapper because this is raw assembly function. - reinterpret_cast<void*>(&Java_MyClassNatives_getStackArgSignExtendedMips64)); - - // Mips64 ABI requires that arguments passed through stack be sign-extended 8B slots. - // First 8 arguments are passed through registers. - // Final argument's value is 7. When sign-extended, higher stack bits should be 0. - ret = env_->CallStaticLongMethod(jklass_, jmethod_, 1, 2, 3, 4, 5, 6, 7); - EXPECT_EQ(High32Bits(ret), static_cast<uint32_t>(0)); - - // Final argument's value is -8. When sign-extended, higher stack bits should be 0xffffffff. - ret = env_->CallStaticLongMethod(jklass_, jmethod_, 1, 2, 3, 4, 5, 6, -8); - EXPECT_EQ(High32Bits(ret), static_cast<uint32_t>(0xffffffff)); -} - -JNI_TEST(StackArgsSignExtendedMips64) -#endif - void Java_MyClassNatives_normalNative(JNIEnv*, jclass) { // Intentionally left empty. } diff --git a/compiler/jni/quick/calling_convention.cc b/compiler/jni/quick/calling_convention.cc index 15af248583..194375671e 100644 --- a/compiler/jni/quick/calling_convention.cc +++ b/compiler/jni/quick/calling_convention.cc @@ -28,14 +28,6 @@ #include "jni/quick/arm64/calling_convention_arm64.h" #endif -#ifdef ART_ENABLE_CODEGEN_mips -#include "jni/quick/mips/calling_convention_mips.h" -#endif - -#ifdef ART_ENABLE_CODEGEN_mips64 -#include "jni/quick/mips64/calling_convention_mips64.h" -#endif - #ifdef ART_ENABLE_CODEGEN_x86 #include "jni/quick/x86/calling_convention_x86.h" #endif @@ -68,18 +60,6 @@ std::unique_ptr<ManagedRuntimeCallingConvention> ManagedRuntimeCallingConvention new (allocator) arm64::Arm64ManagedRuntimeCallingConvention( is_static, is_synchronized, shorty)); #endif -#ifdef ART_ENABLE_CODEGEN_mips - case InstructionSet::kMips: - return std::unique_ptr<ManagedRuntimeCallingConvention>( - new (allocator) mips::MipsManagedRuntimeCallingConvention( - is_static, is_synchronized, shorty)); -#endif -#ifdef ART_ENABLE_CODEGEN_mips64 - case InstructionSet::kMips64: - return std::unique_ptr<ManagedRuntimeCallingConvention>( - new (allocator) mips64::Mips64ManagedRuntimeCallingConvention( - is_static, is_synchronized, shorty)); -#endif #ifdef ART_ENABLE_CODEGEN_x86 case InstructionSet::kX86: return std::unique_ptr<ManagedRuntimeCallingConvention>( @@ -170,18 +150,6 @@ std::unique_ptr<JniCallingConvention> JniCallingConvention::Create(ArenaAllocato new (allocator) arm64::Arm64JniCallingConvention( is_static, is_synchronized, is_critical_native, shorty)); #endif -#ifdef ART_ENABLE_CODEGEN_mips - case InstructionSet::kMips: - return std::unique_ptr<JniCallingConvention>( - new (allocator) mips::MipsJniCallingConvention( - is_static, is_synchronized, is_critical_native, shorty)); -#endif -#ifdef ART_ENABLE_CODEGEN_mips64 - case InstructionSet::kMips64: - return std::unique_ptr<JniCallingConvention>( - new (allocator) mips64::Mips64JniCallingConvention( - is_static, is_synchronized, is_critical_native, shorty)); -#endif #ifdef ART_ENABLE_CODEGEN_x86 case InstructionSet::kX86: return std::unique_ptr<JniCallingConvention>( diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index 363e6462ed..c2db73a938 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -43,8 +43,6 @@ #include "utils/assembler.h" #include "utils/jni_macro_assembler.h" #include "utils/managed_register.h" -#include "utils/mips/managed_register_mips.h" -#include "utils/mips64/managed_register_mips64.h" #include "utils/x86/managed_register_x86.h" #define __ jni_asm-> @@ -324,8 +322,7 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp // Skip this for @CriticalNative because we didn't build a HandleScope to begin with. // Note that we always have outgoing param space available for at least two params. if (kUseReadBarrier && is_static && !is_critical_native) { - const bool kReadBarrierFastPath = - (instruction_set != InstructionSet::kMips) && (instruction_set != InstructionSet::kMips64); + const bool kReadBarrierFastPath = true; // Always true after Mips codegen was removed. std::unique_ptr<JNIMacroLabel> skip_cold_path_label; if (kReadBarrierFastPath) { skip_cold_path_label = __ CreateLabel(); @@ -548,16 +545,6 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp if (LIKELY(!is_critical_native)) { // For normal JNI, store the return value on the stack because the call to // JniMethodEnd will clobber the return value. It will be restored in (13). - if ((instruction_set == InstructionSet::kMips || - instruction_set == InstructionSet::kMips64) && - main_jni_conv->GetReturnType() == Primitive::kPrimDouble && - return_save_location.Uint32Value() % 8 != 0) { - // Ensure doubles are 8-byte aligned for MIPS - return_save_location = FrameOffset(return_save_location.Uint32Value() - + static_cast<size_t>(kMipsPointerSize)); - // TODO: refactor this into the JniCallingConvention code - // as a return value alignment requirement. - } CHECK_LT(return_save_location.Uint32Value(), current_frame_size); __ Store(return_save_location, main_jni_conv->ReturnRegister(), diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc deleted file mode 100644 index cbb692e917..0000000000 --- a/compiler/jni/quick/mips/calling_convention_mips.cc +++ /dev/null @@ -1,471 +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 "calling_convention_mips.h" - -#include <android-base/logging.h> - -#include "arch/instruction_set.h" -#include "handle_scope-inl.h" -#include "utils/mips/managed_register_mips.h" - -namespace art { -namespace mips { - -// -// JNI calling convention constants. -// - -// Up to how many float-like (float, double) args can be enregistered in floating-point registers. -// The rest of the args must go in integer registers or on the stack. -constexpr size_t kMaxFloatOrDoubleRegisterArguments = 2u; -// Up to how many integer-like (pointers, objects, longs, int, short, bool, etc) args can be -// enregistered. The rest of the args must go on the stack. -constexpr size_t kMaxIntLikeRegisterArguments = 4u; - -static const Register kJniCoreArgumentRegisters[] = { A0, A1, A2, A3 }; -static const FRegister kJniFArgumentRegisters[] = { F12, F14 }; -static const DRegister kJniDArgumentRegisters[] = { D6, D7 }; - -// -// Managed calling convention constants. -// - -static const Register kManagedCoreArgumentRegisters[] = { A0, A1, A2, A3, T0, T1 }; -static const FRegister kManagedFArgumentRegisters[] = { F8, F10, F12, F14, F16, F18 }; -static const DRegister kManagedDArgumentRegisters[] = { D4, D5, D6, D7, D8, D9 }; - -static constexpr ManagedRegister kCalleeSaveRegisters[] = { - // Core registers. - MipsManagedRegister::FromCoreRegister(S2), - MipsManagedRegister::FromCoreRegister(S3), - MipsManagedRegister::FromCoreRegister(S4), - MipsManagedRegister::FromCoreRegister(S5), - MipsManagedRegister::FromCoreRegister(S6), - MipsManagedRegister::FromCoreRegister(S7), - MipsManagedRegister::FromCoreRegister(FP), - // No hard float callee saves. -}; - -static constexpr uint32_t CalculateCoreCalleeSpillMask() { - // RA is a special callee save which is not reported by CalleeSaveRegisters(). - uint32_t result = 1 << RA; - for (auto&& r : kCalleeSaveRegisters) { - if (r.AsMips().IsCoreRegister()) { - result |= (1 << r.AsMips().AsCoreRegister()); - } - } - return result; -} - -static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask(); -static constexpr uint32_t kFpCalleeSpillMask = 0u; - -// Calling convention -ManagedRegister MipsManagedRuntimeCallingConvention::InterproceduralScratchRegister() const { - return MipsManagedRegister::FromCoreRegister(T9); -} - -ManagedRegister MipsJniCallingConvention::InterproceduralScratchRegister() const { - return MipsManagedRegister::FromCoreRegister(T9); -} - -static ManagedRegister ReturnRegisterForShorty(const char* shorty) { - if (shorty[0] == 'F') { - return MipsManagedRegister::FromFRegister(F0); - } else if (shorty[0] == 'D') { - return MipsManagedRegister::FromDRegister(D0); - } else if (shorty[0] == 'J') { - return MipsManagedRegister::FromRegisterPair(V0_V1); - } else if (shorty[0] == 'V') { - return MipsManagedRegister::NoRegister(); - } else { - return MipsManagedRegister::FromCoreRegister(V0); - } -} - -ManagedRegister MipsManagedRuntimeCallingConvention::ReturnRegister() { - return ReturnRegisterForShorty(GetShorty()); -} - -ManagedRegister MipsJniCallingConvention::ReturnRegister() { - return ReturnRegisterForShorty(GetShorty()); -} - -ManagedRegister MipsJniCallingConvention::IntReturnRegister() { - return MipsManagedRegister::FromCoreRegister(V0); -} - -// Managed runtime calling convention - -ManagedRegister MipsManagedRuntimeCallingConvention::MethodRegister() { - return MipsManagedRegister::FromCoreRegister(A0); -} - -bool MipsManagedRuntimeCallingConvention::IsCurrentParamInRegister() { - return false; // Everything moved to stack on entry. -} - -bool MipsManagedRuntimeCallingConvention::IsCurrentParamOnStack() { - return true; -} - -ManagedRegister MipsManagedRuntimeCallingConvention::CurrentParamRegister() { - LOG(FATAL) << "Should not reach here"; - UNREACHABLE(); -} - -FrameOffset MipsManagedRuntimeCallingConvention::CurrentParamStackOffset() { - CHECK(IsCurrentParamOnStack()); - FrameOffset result = - FrameOffset(displacement_.Int32Value() + // displacement - kFramePointerSize + // Method* - (itr_slots_ * kFramePointerSize)); // offset into in args - return result; -} - -const ManagedRegisterEntrySpills& MipsManagedRuntimeCallingConvention::EntrySpills() { - // We spill the argument registers on MIPS to free them up for scratch use, we then assume - // all arguments are on the stack. - if ((entry_spills_.size() == 0) && (NumArgs() > 0)) { - uint32_t gpr_index = 1; // Skip A0, it is used for ArtMethod*. - uint32_t fpr_index = 0; - - for (ResetIterator(FrameOffset(0)); HasNext(); Next()) { - if (IsCurrentParamAFloatOrDouble()) { - if (IsCurrentParamADouble()) { - if (fpr_index < arraysize(kManagedDArgumentRegisters)) { - entry_spills_.push_back( - MipsManagedRegister::FromDRegister(kManagedDArgumentRegisters[fpr_index++])); - } else { - entry_spills_.push_back(ManagedRegister::NoRegister(), 8); - } - } else { - if (fpr_index < arraysize(kManagedFArgumentRegisters)) { - entry_spills_.push_back( - MipsManagedRegister::FromFRegister(kManagedFArgumentRegisters[fpr_index++])); - } else { - entry_spills_.push_back(ManagedRegister::NoRegister(), 4); - } - } - } else { - if (IsCurrentParamALong() && !IsCurrentParamAReference()) { - if (gpr_index == 1 || gpr_index == 3) { - // Don't use A1-A2(A3-T0) as a register pair, move to A2-A3(T0-T1) instead. - gpr_index++; - } - if (gpr_index < arraysize(kManagedCoreArgumentRegisters) - 1) { - entry_spills_.push_back( - MipsManagedRegister::FromCoreRegister(kManagedCoreArgumentRegisters[gpr_index++])); - } else if (gpr_index == arraysize(kManagedCoreArgumentRegisters) - 1) { - gpr_index++; - entry_spills_.push_back(ManagedRegister::NoRegister(), 4); - } else { - entry_spills_.push_back(ManagedRegister::NoRegister(), 4); - } - } - - if (gpr_index < arraysize(kManagedCoreArgumentRegisters)) { - entry_spills_.push_back( - MipsManagedRegister::FromCoreRegister(kManagedCoreArgumentRegisters[gpr_index++])); - } else { - entry_spills_.push_back(ManagedRegister::NoRegister(), 4); - } - } - } - } - return entry_spills_; -} - -// JNI calling convention - -MipsJniCallingConvention::MipsJniCallingConvention(bool is_static, - bool is_synchronized, - bool is_critical_native, - const char* shorty) - : JniCallingConvention(is_static, - is_synchronized, - is_critical_native, - shorty, - kMipsPointerSize) { - // SYSTEM V - Application Binary Interface (MIPS RISC Processor): - // Data Representation - Fundamental Types (3-4) specifies fundamental alignments for each type. - // "Each member is assigned to the lowest available offset with the appropriate alignment. This - // may require internal padding, depending on the previous member." - // - // All of our stack arguments are usually 4-byte aligned, however longs and doubles must be 8 - // bytes aligned. Add padding to maintain 8-byte alignment invariant. - // - // Compute padding to ensure longs and doubles are not split in o32. - size_t padding = 0; - size_t cur_arg, cur_reg; - if (LIKELY(HasExtraArgumentsForJni())) { - // Ignore the 'this' jobject or jclass for static methods and the JNIEnv. - // We start at the aligned register A2. - // - // Ignore the first 2 parameters because they are guaranteed to be aligned. - cur_arg = NumImplicitArgs(); // Skip the "this" argument. - cur_reg = 2; // Skip {A0=JNIEnv, A1=jobject} / {A0=JNIEnv, A1=jclass} parameters (start at A2). - } else { - // Check every parameter. - cur_arg = 0; - cur_reg = 0; - } - - // Shift across a logical register mapping that looks like: - // - // | A0 | A1 | A2 | A3 | SP+16 | SP+20 | SP+24 | ... | SP+n | SP+n+4 | - // - // or some of variants with floating-point registers (F12 and F14), for example - // - // | F12 | F14 | A3 | SP+16 | SP+20 | SP+24 | ... | SP+n | SP+n+4 | - // - // (where SP is the stack pointer at the start of called function). - // - // Any time there would normally be a long/double in an odd logical register, - // we have to push out the rest of the mappings by 4 bytes to maintain an 8-byte alignment. - // - // This works for both physical register pairs {A0, A1}, {A2, A3}, - // floating-point registers F12, F14 and for when the value is on the stack. - // - // For example: - // (a) long would normally go into A1, but we shift it into A2 - // | INT | (PAD) | LONG | - // | A0 | A1 | A2 | A3 | - // - // (b) long would normally go into A3, but we shift it into SP - // | INT | INT | INT | (PAD) | LONG | - // | A0 | A1 | A2 | A3 | SP+16 SP+20 | - // - // where INT is any <=4 byte arg, and LONG is any 8-byte arg. - for (; cur_arg < NumArgs(); cur_arg++) { - if (IsParamALongOrDouble(cur_arg)) { - if ((cur_reg & 1) != 0) { - padding += 4; - cur_reg++; // Additional bump to ensure alignment. - } - cur_reg += 2; // Bump the iterator twice for every long argument. - } else { - cur_reg++; // Bump the iterator for every argument. - } - } - if (cur_reg < kMaxIntLikeRegisterArguments) { - // As a special case when, as a result of shifting (or not) there are no arguments on the stack, - // we actually have 0 stack padding. - // - // For example with @CriticalNative and: - // (int, long) -> shifts the long but doesn't need to pad the stack - // - // shift - // \/ - // | INT | (PAD) | LONG | (EMPTY) ... - // | r0 | r1 | r2 | r3 | SP ... - // /\ - // no stack padding - padding_ = 0; - } else { - padding_ = padding; - } - - // Argument Passing (3-17): - // "When the first argument is integral, the remaining arguments are passed in the integer - // registers." - // - // "The rules that determine which arguments go into registers and which ones must be passed on - // the stack are most easily explained by considering the list of arguments as a structure, - // aligned according to normal structure rules. Mapping of this structure into the combination of - // stack and registers is as follows: up to two leading floating-point arguments can be passed in - // $f12 and $f14; everything else with a structure offset greater than or equal to 16 is passed on - // the stack. The remainder of the arguments are passed in $4..$7 based on their structure offset. - // Holes left in the structure for alignment are unused, whether in registers or in the stack." - // - // For example with @CriticalNative and: - // (a) first argument is not floating-point, so all go into integer registers - // | INT | FLOAT | DOUBLE | - // | A0 | A1 | A2 | A3 | - // (b) first argument is floating-point, but 2nd is integer - // | FLOAT | INT | DOUBLE | - // | F12 | A1 | A2 | A3 | - // (c) first two arguments are floating-point (float, double) - // | FLOAT | (PAD) | DOUBLE | INT | - // | F12 | | F14 | SP+16 | - // (d) first two arguments are floating-point (double, float) - // | DOUBLE | FLOAT | INT | - // | F12 | F14 | A3 | - // (e) first three arguments are floating-point, but just first two will go into fp registers - // | DOUBLE | FLOAT | FLOAT | - // | F12 | F14 | A3 | - // - // Find out if the first argument is a floating-point. In that case, floating-point registers will - // be used for up to two leading floating-point arguments. Otherwise, all arguments will be passed - // using integer registers. - use_fp_arg_registers_ = false; - if (is_critical_native) { - if (NumArgs() > 0) { - if (IsParamAFloatOrDouble(0)) { - use_fp_arg_registers_ = true; - } - } - } -} - -uint32_t MipsJniCallingConvention::CoreSpillMask() const { - return kCoreCalleeSpillMask; -} - -uint32_t MipsJniCallingConvention::FpSpillMask() const { - return kFpCalleeSpillMask; -} - -ManagedRegister MipsJniCallingConvention::ReturnScratchRegister() const { - return MipsManagedRegister::FromCoreRegister(AT); -} - -size_t MipsJniCallingConvention::FrameSize() const { - // ArtMethod*, RA and callee save area size, local reference segment state. - const size_t method_ptr_size = static_cast<size_t>(kMipsPointerSize); - const size_t ra_return_addr_size = kFramePointerSize; - const size_t callee_save_area_size = CalleeSaveRegisters().size() * kFramePointerSize; - - size_t frame_data_size = method_ptr_size + ra_return_addr_size + callee_save_area_size; - - if (LIKELY(HasLocalReferenceSegmentState())) { - // Local reference segment state. - frame_data_size += kFramePointerSize; - } - - // References plus 2 words for HandleScope header. - const size_t handle_scope_size = HandleScope::SizeOf(kMipsPointerSize, ReferenceCount()); - - size_t total_size = frame_data_size; - if (LIKELY(HasHandleScope())) { - // HandleScope is sometimes excluded. - total_size += handle_scope_size; // Handle scope size. - } - - // Plus return value spill area size. - total_size += SizeOfReturnValue(); - - return RoundUp(total_size, kStackAlignment); -} - -size_t MipsJniCallingConvention::OutArgSize() const { - // Argument Passing (3-17): - // "Despite the fact that some or all of the arguments to a function are passed in registers, - // always allocate space on the stack for all arguments. This stack space should be a structure - // large enough to contain all the arguments, aligned according to normal structure rules (after - // promotion and structure return pointer insertion). The locations within the stack frame used - // for arguments are called the home locations." - // - // Allocate 16 bytes for home locations + space needed for stack arguments. - - size_t static_args = HasSelfClass() ? 1 : 0; // Count jclass. - // Regular argument parameters and this. - size_t param_args = NumArgs() + NumLongOrDoubleArgs(); // Twice count 8-byte args. - // Count JNIEnv* less arguments in registers. - size_t internal_args = (HasJniEnv() ? 1 : 0); - size_t total_args = static_args + param_args + internal_args; - - size_t stack_args = - total_args - std::min(kMaxIntLikeRegisterArguments, static_cast<size_t>(total_args)); - - return RoundUp( - (kMaxIntLikeRegisterArguments + stack_args) * kFramePointerSize + padding_, - kStackAlignment); -} - -ArrayRef<const ManagedRegister> MipsJniCallingConvention::CalleeSaveRegisters() const { - return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters); -} - -// JniCallingConvention ABI follows o32 where longs and doubles must occur -// in even register numbers and stack slots. -void MipsJniCallingConvention::Next() { - JniCallingConvention::Next(); - - if (LIKELY(HasNext())) { // Avoid CHECK failure for IsCurrentParam - // Ensure slot is 8-byte aligned for longs/doubles (o32). - if (IsCurrentParamALongOrDouble() && ((itr_slots_ & 0x1u) != 0)) { - // itr_slots_ needs to be an even number, according to o32. - itr_slots_++; - } - } -} - -bool MipsJniCallingConvention::IsCurrentParamInRegister() { - // Argument Passing (3-17): - // "The rules that determine which arguments go into registers and which ones must be passed on - // the stack are most easily explained by considering the list of arguments as a structure, - // aligned according to normal structure rules. Mapping of this structure into the combination of - // stack and registers is as follows: up to two leading floating-point arguments can be passed in - // $f12 and $f14; everything else with a structure offset greater than or equal to 16 is passed on - // the stack. The remainder of the arguments are passed in $4..$7 based on their structure offset. - // Holes left in the structure for alignment are unused, whether in registers or in the stack." - // - // Even when floating-point registers are used, there can be up to 4 arguments passed in - // registers. - return itr_slots_ < kMaxIntLikeRegisterArguments; -} - -bool MipsJniCallingConvention::IsCurrentParamOnStack() { - return !IsCurrentParamInRegister(); -} - -ManagedRegister MipsJniCallingConvention::CurrentParamRegister() { - CHECK_LT(itr_slots_, kMaxIntLikeRegisterArguments); - // Up to two leading floating-point arguments can be passed in floating-point registers. - if (use_fp_arg_registers_ && (itr_args_ < kMaxFloatOrDoubleRegisterArguments)) { - if (IsCurrentParamAFloatOrDouble()) { - if (IsCurrentParamADouble()) { - return MipsManagedRegister::FromDRegister(kJniDArgumentRegisters[itr_args_]); - } else { - return MipsManagedRegister::FromFRegister(kJniFArgumentRegisters[itr_args_]); - } - } - } - // All other arguments (including other floating-point arguments) will be passed in integer - // registers. - if (IsCurrentParamALongOrDouble()) { - if (itr_slots_ == 0u) { - return MipsManagedRegister::FromRegisterPair(A0_A1); - } else { - CHECK_EQ(itr_slots_, 2u); - return MipsManagedRegister::FromRegisterPair(A2_A3); - } - } else { - return MipsManagedRegister::FromCoreRegister(kJniCoreArgumentRegisters[itr_slots_]); - } -} - -FrameOffset MipsJniCallingConvention::CurrentParamStackOffset() { - CHECK_GE(itr_slots_, kMaxIntLikeRegisterArguments); - size_t offset = displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize); - CHECK_LT(offset, OutArgSize()); - return FrameOffset(offset); -} - -ManagedRegister MipsJniCallingConvention::HiddenArgumentRegister() const { - UNIMPLEMENTED(FATAL); - UNREACHABLE(); -} - -bool MipsJniCallingConvention::UseTailCall() const { - UNIMPLEMENTED(FATAL); - UNREACHABLE(); -} - -} // namespace mips -} // namespace art diff --git a/compiler/jni/quick/mips/calling_convention_mips.h b/compiler/jni/quick/mips/calling_convention_mips.h deleted file mode 100644 index af27dc8841..0000000000 --- a/compiler/jni/quick/mips/calling_convention_mips.h +++ /dev/null @@ -1,101 +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_JNI_QUICK_MIPS_CALLING_CONVENTION_MIPS_H_ -#define ART_COMPILER_JNI_QUICK_MIPS_CALLING_CONVENTION_MIPS_H_ - -#include "base/enums.h" -#include "jni/quick/calling_convention.h" - -namespace art { -namespace mips { - -constexpr size_t kFramePointerSize = 4; -static_assert(kFramePointerSize == static_cast<size_t>(PointerSize::k32), - "Invalid frame pointer size"); - -class MipsManagedRuntimeCallingConvention final : public ManagedRuntimeCallingConvention { - public: - MipsManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty) - : ManagedRuntimeCallingConvention(is_static, - is_synchronized, - shorty, - PointerSize::k32) {} - ~MipsManagedRuntimeCallingConvention() override {} - // Calling convention - ManagedRegister ReturnRegister() override; - ManagedRegister InterproceduralScratchRegister() const override; - // Managed runtime calling convention - ManagedRegister MethodRegister() override; - bool IsCurrentParamInRegister() override; - bool IsCurrentParamOnStack() override; - ManagedRegister CurrentParamRegister() override; - FrameOffset CurrentParamStackOffset() override; - const ManagedRegisterEntrySpills& EntrySpills() override; - - private: - ManagedRegisterEntrySpills entry_spills_; - - DISALLOW_COPY_AND_ASSIGN(MipsManagedRuntimeCallingConvention); -}; - -class MipsJniCallingConvention final : public JniCallingConvention { - public: - MipsJniCallingConvention(bool is_static, - bool is_synchronized, - bool is_critical_native, - const char* shorty); - ~MipsJniCallingConvention() override {} - // Calling convention - ManagedRegister ReturnRegister() override; - ManagedRegister IntReturnRegister() override; - ManagedRegister InterproceduralScratchRegister() const override; - // JNI calling convention - void Next() override; // Override default behavior for o32. - size_t FrameSize() const override; - size_t OutArgSize() const override; - ArrayRef<const ManagedRegister> CalleeSaveRegisters() const override; - ManagedRegister ReturnScratchRegister() const override; - uint32_t CoreSpillMask() const override; - uint32_t FpSpillMask() const override; - bool IsCurrentParamInRegister() override; - bool IsCurrentParamOnStack() override; - ManagedRegister CurrentParamRegister() override; - FrameOffset CurrentParamStackOffset() override; - - // Mips does not need to extend small return types. - bool RequiresSmallResultTypeExtension() const override { - return false; - } - - // Hidden argument register, used to pass the method pointer for @CriticalNative call. - ManagedRegister HiddenArgumentRegister() const override; - - // Whether to use tail call (used only for @CriticalNative). - bool UseTailCall() const override; - - private: - // Padding to ensure longs and doubles are not split in o32. - size_t padding_; - bool use_fp_arg_registers_; - - DISALLOW_COPY_AND_ASSIGN(MipsJniCallingConvention); -}; - -} // namespace mips -} // namespace art - -#endif // ART_COMPILER_JNI_QUICK_MIPS_CALLING_CONVENTION_MIPS_H_ diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.cc b/compiler/jni/quick/mips64/calling_convention_mips64.cc deleted file mode 100644 index e65ad83197..0000000000 --- a/compiler/jni/quick/mips64/calling_convention_mips64.cc +++ /dev/null @@ -1,256 +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 "calling_convention_mips64.h" - -#include <android-base/logging.h> - -#include "arch/instruction_set.h" -#include "handle_scope-inl.h" -#include "utils/mips64/managed_register_mips64.h" - -namespace art { -namespace mips64 { - -// Up to kow many args can be enregistered. The rest of the args must go on the stack. -constexpr size_t kMaxRegisterArguments = 8u; - -static const GpuRegister kGpuArgumentRegisters[] = { - A0, A1, A2, A3, A4, A5, A6, A7 -}; - -static const FpuRegister kFpuArgumentRegisters[] = { - F12, F13, F14, F15, F16, F17, F18, F19 -}; - -static constexpr ManagedRegister kCalleeSaveRegisters[] = { - // Core registers. - Mips64ManagedRegister::FromGpuRegister(S2), - Mips64ManagedRegister::FromGpuRegister(S3), - Mips64ManagedRegister::FromGpuRegister(S4), - Mips64ManagedRegister::FromGpuRegister(S5), - Mips64ManagedRegister::FromGpuRegister(S6), - Mips64ManagedRegister::FromGpuRegister(S7), - Mips64ManagedRegister::FromGpuRegister(GP), - Mips64ManagedRegister::FromGpuRegister(S8), - // No hard float callee saves. -}; - -static constexpr uint32_t CalculateCoreCalleeSpillMask() { - // RA is a special callee save which is not reported by CalleeSaveRegisters(). - uint32_t result = 1 << RA; - for (auto&& r : kCalleeSaveRegisters) { - if (r.AsMips64().IsGpuRegister()) { - result |= (1 << r.AsMips64().AsGpuRegister()); - } - } - return result; -} - -static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask(); -static constexpr uint32_t kFpCalleeSpillMask = 0u; - -// Calling convention -ManagedRegister Mips64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() const { - return Mips64ManagedRegister::FromGpuRegister(T9); -} - -ManagedRegister Mips64JniCallingConvention::InterproceduralScratchRegister() const { - return Mips64ManagedRegister::FromGpuRegister(T9); -} - -static ManagedRegister ReturnRegisterForShorty(const char* shorty) { - if (shorty[0] == 'F' || shorty[0] == 'D') { - return Mips64ManagedRegister::FromFpuRegister(F0); - } else if (shorty[0] == 'V') { - return Mips64ManagedRegister::NoRegister(); - } else { - return Mips64ManagedRegister::FromGpuRegister(V0); - } -} - -ManagedRegister Mips64ManagedRuntimeCallingConvention::ReturnRegister() { - return ReturnRegisterForShorty(GetShorty()); -} - -ManagedRegister Mips64JniCallingConvention::ReturnRegister() { - return ReturnRegisterForShorty(GetShorty()); -} - -ManagedRegister Mips64JniCallingConvention::IntReturnRegister() { - return Mips64ManagedRegister::FromGpuRegister(V0); -} - -// Managed runtime calling convention - -ManagedRegister Mips64ManagedRuntimeCallingConvention::MethodRegister() { - return Mips64ManagedRegister::FromGpuRegister(A0); -} - -bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamInRegister() { - return false; // Everything moved to stack on entry. -} - -bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() { - return true; -} - -ManagedRegister Mips64ManagedRuntimeCallingConvention::CurrentParamRegister() { - LOG(FATAL) << "Should not reach here"; - UNREACHABLE(); -} - -FrameOffset Mips64ManagedRuntimeCallingConvention::CurrentParamStackOffset() { - CHECK(IsCurrentParamOnStack()); - FrameOffset result = - FrameOffset(displacement_.Int32Value() + // displacement - kFramePointerSize + // Method ref - (itr_slots_ * sizeof(uint32_t))); // offset into in args - return result; -} - -const ManagedRegisterEntrySpills& Mips64ManagedRuntimeCallingConvention::EntrySpills() { - // We spill the argument registers on MIPS64 to free them up for scratch use, - // we then assume all arguments are on the stack. - if ((entry_spills_.size() == 0) && (NumArgs() > 0)) { - int reg_index = 1; // we start from A1, A0 holds ArtMethod*. - - // We need to choose the correct register size since the managed - // stack uses 32bit stack slots. - ResetIterator(FrameOffset(0)); - while (HasNext()) { - if (reg_index < 8) { - if (IsCurrentParamAFloatOrDouble()) { // FP regs. - FpuRegister arg = kFpuArgumentRegisters[reg_index]; - Mips64ManagedRegister reg = Mips64ManagedRegister::FromFpuRegister(arg); - entry_spills_.push_back(reg, IsCurrentParamADouble() ? 8 : 4); - } else { // GP regs. - GpuRegister arg = kGpuArgumentRegisters[reg_index]; - Mips64ManagedRegister reg = Mips64ManagedRegister::FromGpuRegister(arg); - entry_spills_.push_back(reg, - (IsCurrentParamALong() && (!IsCurrentParamAReference())) ? 8 : 4); - } - // e.g. A1, A2, F3, A4, F5, F6, A7 - reg_index++; - } - - Next(); - } - } - return entry_spills_; -} - -// JNI calling convention - -Mips64JniCallingConvention::Mips64JniCallingConvention(bool is_static, - bool is_synchronized, - bool is_critical_native, - const char* shorty) - : JniCallingConvention(is_static, - is_synchronized, - is_critical_native, - shorty, - kMips64PointerSize) { -} - -uint32_t Mips64JniCallingConvention::CoreSpillMask() const { - return kCoreCalleeSpillMask; -} - -uint32_t Mips64JniCallingConvention::FpSpillMask() const { - return kFpCalleeSpillMask; -} - -ManagedRegister Mips64JniCallingConvention::ReturnScratchRegister() const { - return Mips64ManagedRegister::FromGpuRegister(AT); -} - -size_t Mips64JniCallingConvention::FrameSize() const { - // ArtMethod*, RA and callee save area size, local reference segment state. - size_t method_ptr_size = static_cast<size_t>(kFramePointerSize); - size_t ra_and_callee_save_area_size = (CalleeSaveRegisters().size() + 1) * kFramePointerSize; - - size_t frame_data_size = method_ptr_size + ra_and_callee_save_area_size; - if (LIKELY(HasLocalReferenceSegmentState())) { // Local ref. segment state. - // Local reference segment state is sometimes excluded. - frame_data_size += sizeof(uint32_t); - } - // References plus 2 words for HandleScope header. - size_t handle_scope_size = HandleScope::SizeOf(kMips64PointerSize, ReferenceCount()); - - size_t total_size = frame_data_size; - if (LIKELY(HasHandleScope())) { - // HandleScope is sometimes excluded. - total_size += handle_scope_size; // Handle scope size. - } - - // Plus return value spill area size. - total_size += SizeOfReturnValue(); - - return RoundUp(total_size, kStackAlignment); -} - -size_t Mips64JniCallingConvention::OutArgSize() const { - // all arguments including JNI args - size_t all_args = NumArgs() + NumberOfExtraArgumentsForJni(); - - // Nothing on the stack unless there are more than 8 arguments - size_t stack_args = (all_args > kMaxRegisterArguments) ? all_args - kMaxRegisterArguments : 0; - - return RoundUp(stack_args * kFramePointerSize, kStackAlignment); -} - -ArrayRef<const ManagedRegister> Mips64JniCallingConvention::CalleeSaveRegisters() const { - return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters); -} - -bool Mips64JniCallingConvention::IsCurrentParamInRegister() { - return itr_args_ < kMaxRegisterArguments; -} - -bool Mips64JniCallingConvention::IsCurrentParamOnStack() { - return !IsCurrentParamInRegister(); -} - -ManagedRegister Mips64JniCallingConvention::CurrentParamRegister() { - CHECK(IsCurrentParamInRegister()); - if (IsCurrentParamAFloatOrDouble()) { - return Mips64ManagedRegister::FromFpuRegister(kFpuArgumentRegisters[itr_args_]); - } else { - return Mips64ManagedRegister::FromGpuRegister(kGpuArgumentRegisters[itr_args_]); - } -} - -FrameOffset Mips64JniCallingConvention::CurrentParamStackOffset() { - CHECK(IsCurrentParamOnStack()); - size_t args_on_stack = itr_args_ - kMaxRegisterArguments; - size_t offset = displacement_.Int32Value() - OutArgSize() + (args_on_stack * kFramePointerSize); - CHECK_LT(offset, OutArgSize()); - return FrameOffset(offset); -} - -ManagedRegister Mips64JniCallingConvention::HiddenArgumentRegister() const { - UNIMPLEMENTED(FATAL); - UNREACHABLE(); -} - -bool Mips64JniCallingConvention::UseTailCall() const { - UNIMPLEMENTED(FATAL); - UNREACHABLE(); -} - -} // namespace mips64 -} // namespace art diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.h b/compiler/jni/quick/mips64/calling_convention_mips64.h deleted file mode 100644 index e9a42a4330..0000000000 --- a/compiler/jni/quick/mips64/calling_convention_mips64.h +++ /dev/null @@ -1,96 +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. - */ - -#ifndef ART_COMPILER_JNI_QUICK_MIPS64_CALLING_CONVENTION_MIPS64_H_ -#define ART_COMPILER_JNI_QUICK_MIPS64_CALLING_CONVENTION_MIPS64_H_ - -#include "base/enums.h" -#include "jni/quick/calling_convention.h" - -namespace art { -namespace mips64 { - -constexpr size_t kFramePointerSize = 8; -static_assert(kFramePointerSize == static_cast<size_t>(PointerSize::k64), - "Invalid frame pointer size"); - -class Mips64ManagedRuntimeCallingConvention final : public ManagedRuntimeCallingConvention { - public: - Mips64ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty) - : ManagedRuntimeCallingConvention(is_static, - is_synchronized, - shorty, - PointerSize::k64) {} - ~Mips64ManagedRuntimeCallingConvention() override {} - // Calling convention - ManagedRegister ReturnRegister() override; - ManagedRegister InterproceduralScratchRegister() const override; - // Managed runtime calling convention - ManagedRegister MethodRegister() override; - bool IsCurrentParamInRegister() override; - bool IsCurrentParamOnStack() override; - ManagedRegister CurrentParamRegister() override; - FrameOffset CurrentParamStackOffset() override; - const ManagedRegisterEntrySpills& EntrySpills() override; - - private: - ManagedRegisterEntrySpills entry_spills_; - - DISALLOW_COPY_AND_ASSIGN(Mips64ManagedRuntimeCallingConvention); -}; - -class Mips64JniCallingConvention final : public JniCallingConvention { - public: - Mips64JniCallingConvention(bool is_static, - bool is_synchronized, - bool is_critical_native, - const char* shorty); - ~Mips64JniCallingConvention() override {} - // Calling convention - ManagedRegister ReturnRegister() override; - ManagedRegister IntReturnRegister() override; - ManagedRegister InterproceduralScratchRegister() const override; - // JNI calling convention - size_t FrameSize() const override; - size_t OutArgSize() const override; - ArrayRef<const ManagedRegister> CalleeSaveRegisters() const override; - ManagedRegister ReturnScratchRegister() const override; - uint32_t CoreSpillMask() const override; - uint32_t FpSpillMask() const override; - bool IsCurrentParamInRegister() override; - bool IsCurrentParamOnStack() override; - ManagedRegister CurrentParamRegister() override; - FrameOffset CurrentParamStackOffset() override; - - // Mips64 does not need to extend small return types. - bool RequiresSmallResultTypeExtension() const override { - return false; - } - - // Hidden argument register, used to pass the method pointer for @CriticalNative call. - ManagedRegister HiddenArgumentRegister() const override; - - // Whether to use tail call (used only for @CriticalNative). - bool UseTailCall() const override; - - private: - DISALLOW_COPY_AND_ASSIGN(Mips64JniCallingConvention); -}; - -} // namespace mips64 -} // namespace art - -#endif // ART_COMPILER_JNI_QUICK_MIPS64_CALLING_CONVENTION_MIPS64_H_ 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/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/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 fb41153b90..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; diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc deleted file mode 100644 index 6b73695208..0000000000 --- a/compiler/utils/mips/assembler_mips.cc +++ /dev/null @@ -1,5271 +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::Jump(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()); - Jr(scratch.AsCoreRegister()); - NopIfNoReordering(); -} - -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 3a4e0ceba2..0000000000 --- a/compiler/utils/mips/assembler_mips.h +++ /dev/null @@ -1,1829 +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; - - // 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 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 a465a682d9..0000000000 --- a/compiler/utils/mips/assembler_mips32r6_test.cc +++ /dev/null @@ -1,2528 +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) { - // This test is disabled as `gcc` (used as MIPS32 assembler, see - // `AssemblerMIPS32r6Test.GetAssemblerCmdName`) is being removed from Android - // (see b/147336214 and b/147240075). - TEST_DISABLED(); - 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 07d3716b40..0000000000 --- a/compiler/utils/mips64/assembler_mips64.cc +++ /dev/null @@ -1,4112 +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::Jump(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()); - Jr(scratch.AsGpuRegister()); - Nop(); -} - -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 03eae916c5..0000000000 --- a/compiler/utils/mips64/assembler_mips64.h +++ /dev/null @@ -1,1739 +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; - - // 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 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 2f7b223e1f..0000000000 --- a/compiler/utils/mips64/assembler_mips64_test.cc +++ /dev/null @@ -1,3788 +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) { - // This test is disabled as `gcc` (used as MIPS64 assembler, see - // `AssemblerMIPS64Test.GetAssemblerCmdName`) is being removed from Android - // (see b/147336214 and b/147240075). - TEST_DISABLED(); - 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/disassembler/Android.bp b/disassembler/Android.bp index e841953c28..a59b3c775c 100644 --- a/disassembler/Android.bp +++ b/disassembler/Android.bp @@ -28,12 +28,6 @@ art_cc_defaults { arm64: { srcs: ["disassembler_arm64.cc"], }, - mips: { - srcs: ["disassembler_mips.cc"], - }, - mips64: { - srcs: ["disassembler_mips.cc"], - }, x86: { srcs: ["disassembler_x86.cc"], }, diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc index 0662334852..53461ce5ae 100644 --- a/disassembler/disassembler.cc +++ b/disassembler/disassembler.cc @@ -29,10 +29,6 @@ # include "disassembler_arm64.h" #endif -#if defined(ART_ENABLE_CODEGEN_mips) || defined(ART_ENABLE_CODEGEN_mips64) -# include "disassembler_mips.h" -#endif - #if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64) # include "disassembler_x86.h" #endif @@ -57,14 +53,6 @@ Disassembler* Disassembler::Create(InstructionSet instruction_set, DisassemblerO case InstructionSet::kArm64: return new arm64::DisassemblerArm64(options); #endif -#ifdef ART_ENABLE_CODEGEN_mips - case InstructionSet::kMips: - return new mips::DisassemblerMips(options, /* is_o32_abi= */ true); -#endif -#ifdef ART_ENABLE_CODEGEN_mips64 - case InstructionSet::kMips64: - return new mips::DisassemblerMips(options, /* is_o32_abi= */ false); -#endif #ifdef ART_ENABLE_CODEGEN_x86 case InstructionSet::kX86: return new x86::DisassemblerX86(options, /* supports_rex= */ false); diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc deleted file mode 100644 index eaf11be7f2..0000000000 --- a/disassembler/disassembler_mips.cc +++ /dev/null @@ -1,851 +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. - */ - -#include "disassembler_mips.h" - -#include <ostream> -#include <sstream> - -#include "android-base/logging.h" -#include "android-base/stringprintf.h" - -#include "base/bit_utils.h" - -using android::base::StringPrintf; - -namespace art { -namespace mips { - -struct MipsInstruction { - uint32_t mask; - uint32_t value; - const char* name; - const char* args_fmt; - - bool Matches(uint32_t instruction) const { - return (instruction & mask) == value; - } -}; - -static const char* gO32AbiRegNames[] = { - "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" -}; - -static const char* gN64AbiRegNames[] = { - "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" -}; - -static const uint32_t kOpcodeShift = 26; - -static const uint32_t kCop1 = (17 << kOpcodeShift); -static const uint32_t kMsa = (30 << kOpcodeShift); // MSA major opcode. - -static const uint32_t kITypeMask = (0x3f << kOpcodeShift); -static const uint32_t kJTypeMask = (0x3f << kOpcodeShift); -static const uint32_t kRTypeMask = ((0x3f << kOpcodeShift) | (0x3f)); -static const uint32_t kSpecial0Mask = (0x3f << kOpcodeShift); -static const uint32_t kSpecial2Mask = (0x3f << kOpcodeShift); -static const uint32_t kSpecial3Mask = (0x3f << kOpcodeShift); -static const uint32_t kFpMask = kRTypeMask; -static const uint32_t kMsaMask = kRTypeMask; -static const uint32_t kMsaSpecialMask = (0x3f << kOpcodeShift); - -static const MipsInstruction gMipsInstructions[] = { - // "sll r0, r0, 0" is the canonical "nop", used in delay slots. - { 0xffffffff, 0, "nop", "" }, - - // R-type instructions. - { kRTypeMask, 0, "sll", "DTA", }, - // 0, 1, movci - { kRTypeMask | (0x1f << 21), 2, "srl", "DTA", }, - { kRTypeMask, 3, "sra", "DTA", }, - { kRTypeMask | (0x1f << 6), 4, "sllv", "DTS", }, - { kRTypeMask | (0x1f << 6), 6, "srlv", "DTS", }, - { kRTypeMask | (0x1f << 6), (1 << 6) | 6, "rotrv", "DTS", }, - { kRTypeMask | (0x1f << 6), 7, "srav", "DTS", }, - { kRTypeMask, 8, "jr", "S", }, - { kRTypeMask | (0x1f << 11), 9 | (31 << 11), "jalr", "S", }, // rd = 31 is implicit. - { kRTypeMask | (0x1f << 11), 9, "jr", "S", }, // rd = 0 is implicit. - { kRTypeMask, 9, "jalr", "DS", }, // General case. - { kRTypeMask | (0x1f << 6), 10, "movz", "DST", }, - { kRTypeMask | (0x1f << 6), 11, "movn", "DST", }, - { kRTypeMask, 12, "syscall", "", }, // TODO: code - { kRTypeMask, 13, "break", "", }, // TODO: code - { kRTypeMask, 15, "sync", "", }, // TODO: type - { kRTypeMask, 16, "mfhi", "D", }, - { kRTypeMask, 17, "mthi", "S", }, - { kRTypeMask, 18, "mflo", "D", }, - { kRTypeMask, 19, "mtlo", "S", }, - { kRTypeMask | (0x1f << 6), 20, "dsllv", "DTS", }, - { kRTypeMask | (0x1f << 6), 22, "dsrlv", "DTS", }, - { kRTypeMask | (0x1f << 6), (1 << 6) | 22, "drotrv", "DTS", }, - { kRTypeMask | (0x1f << 6), 23, "dsrav", "DTS", }, - { kRTypeMask | (0x1f << 6), 24, "mult", "ST", }, - { kRTypeMask | (0x1f << 6), 25, "multu", "ST", }, - { kRTypeMask | (0x1f << 6), 26, "div", "ST", }, - { kRTypeMask | (0x1f << 6), 27, "divu", "ST", }, - { kRTypeMask | (0x1f << 6), 24 + (2 << 6), "mul", "DST", }, - { kRTypeMask | (0x1f << 6), 24 + (3 << 6), "muh", "DST", }, - { kRTypeMask | (0x1f << 6), 26 + (2 << 6), "div", "DST", }, - { kRTypeMask | (0x1f << 6), 26 + (3 << 6), "mod", "DST", }, - { kRTypeMask, 32, "add", "DST", }, - { kRTypeMask, 33, "addu", "DST", }, - { kRTypeMask, 34, "sub", "DST", }, - { kRTypeMask, 35, "subu", "DST", }, - { kRTypeMask, 36, "and", "DST", }, - { kRTypeMask | (0x1f << 16), 37 | (0 << 16), "move", "DS" }, - { kRTypeMask | (0x1f << 21), 37 | (0 << 21), "move", "DT" }, - { kRTypeMask, 37, "or", "DST", }, - { kRTypeMask, 38, "xor", "DST", }, - { kRTypeMask, 39, "nor", "DST", }, - { kRTypeMask, 42, "slt", "DST", }, - { kRTypeMask, 43, "sltu", "DST", }, - { kRTypeMask, 45, "daddu", "DST", }, - { kRTypeMask, 46, "dsub", "DST", }, - { kRTypeMask, 47, "dsubu", "DST", }, - // TODO: tge[u], tlt[u], teg, tne - { kRTypeMask | (0x1f << 21), 56, "dsll", "DTA", }, - { kRTypeMask | (0x1f << 21), 58, "dsrl", "DTA", }, - { kRTypeMask | (0x1f << 21), (1 << 21) | 58, "drotr", "DTA", }, - { kRTypeMask | (0x1f << 21), 59, "dsra", "DTA", }, - { kRTypeMask | (0x1f << 21), 60, "dsll32", "DTA", }, - { kRTypeMask | (0x1f << 21), 62, "dsrl32", "DTA", }, - { kRTypeMask | (0x1f << 21), (1 << 21) | 62, "drotr32", "DTA", }, - { kRTypeMask | (0x1f << 21), 63, "dsra32", "DTA", }, - - // SPECIAL0 - { kSpecial0Mask | 0x307ff, 1, "movf", "DSc" }, - { kSpecial0Mask | 0x307ff, 0x10001, "movt", "DSc" }, - { kSpecial0Mask | 0x7ff, (2 << 6) | 24, "mul", "DST" }, - { kSpecial0Mask | 0x7ff, (3 << 6) | 24, "muh", "DST" }, - { kSpecial0Mask | 0x7ff, (2 << 6) | 25, "mulu", "DST" }, - { kSpecial0Mask | 0x7ff, (3 << 6) | 25, "muhu", "DST" }, - { kSpecial0Mask | 0x7ff, (2 << 6) | 26, "div", "DST" }, - { kSpecial0Mask | 0x7ff, (3 << 6) | 26, "mod", "DST" }, - { kSpecial0Mask | 0x7ff, (2 << 6) | 27, "divu", "DST" }, - { kSpecial0Mask | 0x7ff, (3 << 6) | 27, "modu", "DST" }, - { kSpecial0Mask | 0x7ff, (2 << 6) | 28, "dmul", "DST" }, - { kSpecial0Mask | 0x7ff, (3 << 6) | 28, "dmuh", "DST" }, - { kSpecial0Mask | 0x7ff, (2 << 6) | 29, "dmulu", "DST" }, - { kSpecial0Mask | 0x7ff, (3 << 6) | 29, "dmuhu", "DST" }, - { kSpecial0Mask | 0x7ff, (2 << 6) | 30, "ddiv", "DST" }, - { kSpecial0Mask | 0x7ff, (3 << 6) | 30, "dmod", "DST" }, - { kSpecial0Mask | 0x7ff, (2 << 6) | 31, "ddivu", "DST" }, - { kSpecial0Mask | 0x7ff, (3 << 6) | 31, "dmodu", "DST" }, - { kSpecial0Mask | 0x7ff, (0 << 6) | 53, "seleqz", "DST" }, - { kSpecial0Mask | 0x7ff, (0 << 6) | 55, "selnez", "DST" }, - { kSpecial0Mask | (0x1f << 21) | 0x3f, (1 << 21) | 2, "rotr", "DTA", }, - { kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x10, "clz", "DS" }, - { kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x11, "clo", "DS" }, - { kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x12, "dclz", "DS" }, - { kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x13, "dclo", "DS" }, - { kSpecial0Mask | 0x73f, 0x05, "lsa", "DSTj" }, - { kSpecial0Mask | 0x73f, 0x15, "dlsa", "DSTj" }, - // TODO: sdbbp - - // SPECIAL2 - { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 2, "mul", "DST" }, - { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 32, "clz", "DS" }, - { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 33, "clo", "DS" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 0, "madd", "ST" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 1, "maddu", "ST" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 2, "mul", "DST" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 4, "msub", "ST" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 5, "msubu", "ST" }, - { kSpecial2Mask | 0x3f, (28 << kOpcodeShift) | 0x3f, "sdbbp", "" }, // TODO: code - - // SPECIAL3 - { kSpecial3Mask | 0x3f, (31 << kOpcodeShift), "ext", "TSAZ", }, - { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 3, "dext", "TSAZ", }, - { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 4, "ins", "TSAz", }, - { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 5, "dinsm", "TSAJ", }, - { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 6, "dinsu", "TSFz", }, - { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 7, "dins", "TSAz", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, - (31 << kOpcodeShift) | (16 << 6) | 32, - "seb", - "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, - (31 << kOpcodeShift) | (24 << 6) | 32, - "seh", - "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, - (31 << kOpcodeShift) | 32, - "bitswap", - "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, - (31 << kOpcodeShift) | 36, - "dbitswap", - "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, - (31 << kOpcodeShift) | (2 << 6) | 36, - "dsbh", - "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, - (31 << kOpcodeShift) | (5 << 6) | 36, - "dshd", - "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, - (31 << kOpcodeShift) | (2 << 6) | 32, - "wsbh", - "DT", }, - { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x26, "sc", "Tl", }, - { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x27, "scd", "Tl", }, - { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x36, "ll", "Tl", }, - { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x37, "lld", "Tl", }, - - // J-type instructions. - { kJTypeMask, 2 << kOpcodeShift, "j", "L" }, - { kJTypeMask, 3 << kOpcodeShift, "jal", "L" }, - - // I-type instructions. - { kITypeMask | (0x3ff << 16), 4 << kOpcodeShift, "b", "B" }, - { kITypeMask | (0x1f << 16), 4 << kOpcodeShift | (0 << 16), "beqz", "SB" }, - { kITypeMask | (0x1f << 21), 4 << kOpcodeShift | (0 << 21), "beqz", "TB" }, - { kITypeMask, 4 << kOpcodeShift, "beq", "STB" }, - { kITypeMask | (0x1f << 16), 5 << kOpcodeShift | (0 << 16), "bnez", "SB" }, - { kITypeMask | (0x1f << 21), 5 << kOpcodeShift | (0 << 21), "bnez", "TB" }, - { kITypeMask, 5 << kOpcodeShift, "bne", "STB" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (1 << 16), "bgez", "SB" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (0 << 16), "bltz", "SB" }, - { kITypeMask | (0x3ff << 16), 1 << kOpcodeShift | (16 << 16), "nal", "" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (16 << 16), "bltzal", "SB" }, - { kITypeMask | (0x3ff << 16), 1 << kOpcodeShift | (17 << 16), "bal", "B" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (17 << 16), "bgezal", "SB" }, - { kITypeMask | (0x1f << 16), 6 << kOpcodeShift | (0 << 16), "blez", "SB" }, - { kITypeMask, 6 << kOpcodeShift, "bgeuc", "STB" }, - { kITypeMask | (0x1f << 16), 7 << kOpcodeShift | (0 << 16), "bgtz", "SB" }, - { kITypeMask, 7 << kOpcodeShift, "bltuc", "STB" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (6 << 16), "dahi", "Si", }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (30 << 16), "dati", "Si", }, - - { kITypeMask, 8 << kOpcodeShift, "beqc", "STB" }, - - { kITypeMask | (0x1f << 21), 9 << kOpcodeShift | (0 << 21), "li", "Ti" }, - { kITypeMask, 9 << kOpcodeShift, "addiu", "TSi", }, - { kITypeMask, 10 << kOpcodeShift, "slti", "TSi", }, - { kITypeMask, 11 << kOpcodeShift, "sltiu", "TSi", }, - { kITypeMask, 12 << kOpcodeShift, "andi", "TSI", }, - { kITypeMask | (0x1f << 21), 13 << kOpcodeShift | (0 << 21), "li", "TI" }, - { kITypeMask, 13 << kOpcodeShift, "ori", "TSI", }, - { kITypeMask, 14 << kOpcodeShift, "xori", "TSI", }, - { kITypeMask | (0x1f << 21), 15 << kOpcodeShift, "lui", "Ti", }, - { kITypeMask, 15 << kOpcodeShift, "aui", "TSi", }, - - { kITypeMask | (0x3e3 << 16), (17 << kOpcodeShift) | (8 << 21), "bc1f", "cB" }, - { kITypeMask | (0x3e3 << 16), (17 << kOpcodeShift) | (8 << 21) | (1 << 16), "bc1t", "cB" }, - { kITypeMask | (0x1f << 21), (17 << kOpcodeShift) | (9 << 21), "bc1eqz", "tB" }, - { kITypeMask | (0x1f << 21), (17 << kOpcodeShift) | (13 << 21), "bc1nez", "tB" }, - - { kITypeMask | (0x1f << 21), 22 << kOpcodeShift, "blezc", "TB" }, - - // TODO: de-dup - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (1 << 21) | (1 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (2 << 21) | (2 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (3 << 21) | (3 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (4 << 21) | (4 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (5 << 21) | (5 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (6 << 21) | (6 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (7 << 21) | (7 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (8 << 21) | (8 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (9 << 21) | (9 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (10 << 21) | (10 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (11 << 21) | (11 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (12 << 21) | (12 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (13 << 21) | (13 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (14 << 21) | (14 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (15 << 21) | (15 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (16 << 21) | (16 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (17 << 21) | (17 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (18 << 21) | (18 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (19 << 21) | (19 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (20 << 21) | (20 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (21 << 21) | (21 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (22 << 21) | (22 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (23 << 21) | (23 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (24 << 21) | (24 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (25 << 21) | (25 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (26 << 21) | (26 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (27 << 21) | (27 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (28 << 21) | (28 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (29 << 21) | (29 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (30 << 21) | (30 << 16), "bgezc", "TB" }, - { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (31 << 21) | (31 << 16), "bgezc", "TB" }, - - { kITypeMask, 22 << kOpcodeShift, "bgec", "STB" }, - - { kITypeMask | (0x1f << 21), 23 << kOpcodeShift, "bgtzc", "TB" }, - - // TODO: de-dup - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (1 << 21) | (1 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (2 << 21) | (2 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (3 << 21) | (3 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (4 << 21) | (4 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (5 << 21) | (5 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (6 << 21) | (6 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (7 << 21) | (7 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (8 << 21) | (8 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (9 << 21) | (9 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (10 << 21) | (10 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (11 << 21) | (11 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (12 << 21) | (12 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (13 << 21) | (13 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (14 << 21) | (14 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (15 << 21) | (15 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (16 << 21) | (16 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (17 << 21) | (17 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (18 << 21) | (18 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (19 << 21) | (19 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (20 << 21) | (20 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (21 << 21) | (21 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (22 << 21) | (22 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (23 << 21) | (23 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (24 << 21) | (24 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (25 << 21) | (25 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (26 << 21) | (26 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (27 << 21) | (27 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (28 << 21) | (28 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (29 << 21) | (29 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (30 << 21) | (30 << 16), "bltzc", "TB" }, - { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (31 << 21) | (31 << 16), "bltzc", "TB" }, - - { kITypeMask, 23 << kOpcodeShift, "bltc", "STB" }, - - { kITypeMask, 24 << kOpcodeShift, "bnec", "STB" }, - - { kITypeMask | (0x1f << 21), 25 << kOpcodeShift | (0 << 21), "dli", "Ti" }, - { kITypeMask, 25 << kOpcodeShift, "daddiu", "TSi", }, - { kITypeMask, 29 << kOpcodeShift, "daui", "TSi", }, - - { kITypeMask, 32u << kOpcodeShift, "lb", "TO", }, - { kITypeMask, 33u << kOpcodeShift, "lh", "TO", }, - { kITypeMask, 34u << kOpcodeShift, "lwl", "TO", }, - { kITypeMask, 35u << kOpcodeShift, "lw", "TO", }, - { kITypeMask, 36u << kOpcodeShift, "lbu", "TO", }, - { kITypeMask, 37u << kOpcodeShift, "lhu", "TO", }, - { kITypeMask, 38u << kOpcodeShift, "lwr", "TO", }, - { kITypeMask, 39u << kOpcodeShift, "lwu", "TO", }, - { kITypeMask, 40u << kOpcodeShift, "sb", "TO", }, - { kITypeMask, 41u << kOpcodeShift, "sh", "TO", }, - { kITypeMask, 42u << kOpcodeShift, "swl", "TO", }, - { kITypeMask, 43u << kOpcodeShift, "sw", "TO", }, - { kITypeMask, 46u << kOpcodeShift, "swr", "TO", }, - { kITypeMask, 48u << kOpcodeShift, "ll", "TO", }, - { kITypeMask, 49u << kOpcodeShift, "lwc1", "tO", }, - { kJTypeMask, 50u << kOpcodeShift, "bc", "P" }, - { kITypeMask, 53u << kOpcodeShift, "ldc1", "tO", }, - { kITypeMask | (0x1f << 21), 54u << kOpcodeShift, "jic", "Ti" }, - { kITypeMask | (1 << 21), (54u << kOpcodeShift) | (1 << 21), "beqzc", "Sb" }, // TODO: de-dup? - { kITypeMask | (1 << 22), (54u << kOpcodeShift) | (1 << 22), "beqzc", "Sb" }, - { kITypeMask | (1 << 23), (54u << kOpcodeShift) | (1 << 23), "beqzc", "Sb" }, - { kITypeMask | (1 << 24), (54u << kOpcodeShift) | (1 << 24), "beqzc", "Sb" }, - { kITypeMask | (1 << 25), (54u << kOpcodeShift) | (1 << 25), "beqzc", "Sb" }, - { kITypeMask, 55u << kOpcodeShift, "ld", "TO", }, - { kITypeMask, 56u << kOpcodeShift, "sc", "TO", }, - { kITypeMask, 57u << kOpcodeShift, "swc1", "tO", }, - { kJTypeMask, 58u << kOpcodeShift, "balc", "P" }, - { kITypeMask | (0x1f << 16), (59u << kOpcodeShift) | (30 << 16), "auipc", "Si" }, - { kITypeMask | (0x3 << 19), (59u << kOpcodeShift) | (0 << 19), "addiupc", "Sp" }, - { kITypeMask | (0x3 << 19), (59u << kOpcodeShift) | (1 << 19), "lwpc", "So" }, - { kITypeMask | (0x3 << 19), (59u << kOpcodeShift) | (2 << 19), "lwupc", "So" }, - { kITypeMask | (0x7 << 18), (59u << kOpcodeShift) | (6 << 18), "ldpc", "S0" }, - { kITypeMask, 61u << kOpcodeShift, "sdc1", "tO", }, - { kITypeMask | (0x1f << 21), 62u << kOpcodeShift, "jialc", "Ti" }, - { kITypeMask | (1 << 21), (62u << kOpcodeShift) | (1 << 21), "bnezc", "Sb" }, // TODO: de-dup? - { kITypeMask | (1 << 22), (62u << kOpcodeShift) | (1 << 22), "bnezc", "Sb" }, - { kITypeMask | (1 << 23), (62u << kOpcodeShift) | (1 << 23), "bnezc", "Sb" }, - { kITypeMask | (1 << 24), (62u << kOpcodeShift) | (1 << 24), "bnezc", "Sb" }, - { kITypeMask | (1 << 25), (62u << kOpcodeShift) | (1 << 25), "bnezc", "Sb" }, - { kITypeMask, 63u << kOpcodeShift, "sd", "TO", }, - - // Floating point. - { kFpMask | (0x1f << 21), kCop1 | (0x00 << 21), "mfc1", "Td" }, - { kFpMask | (0x1f << 21), kCop1 | (0x01 << 21), "dmfc1", "Td" }, - { kFpMask | (0x1f << 21), kCop1 | (0x03 << 21), "mfhc1", "Td" }, - { kFpMask | (0x1f << 21), kCop1 | (0x04 << 21), "mtc1", "Td" }, - { kFpMask | (0x1f << 21), kCop1 | (0x05 << 21), "dmtc1", "Td" }, - { kFpMask | (0x1f << 21), kCop1 | (0x07 << 21), "mthc1", "Td" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 1, "cmp.un.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 2, "cmp.eq.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 3, "cmp.ueq.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 4, "cmp.lt.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 5, "cmp.ult.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 6, "cmp.le.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 7, "cmp.ule.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 17, "cmp.or.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 18, "cmp.une.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 19, "cmp.ne.s", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 1, "cmp.un.d", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 2, "cmp.eq.d", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 3, "cmp.ueq.d", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 4, "cmp.lt.d", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 5, "cmp.ult.d", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 6, "cmp.le.d", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 7, "cmp.ule.d", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 17, "cmp.or.d", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 18, "cmp.une.d", "adt" }, - { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 19, "cmp.ne.d", "adt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 0, "add", "fadt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 1, "sub", "fadt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 2, "mul", "fadt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 3, "div", "fadt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 4, "sqrt", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 5, "abs", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 6, "mov", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 7, "neg", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 8, "round.l", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 9, "trunc.l", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 10, "ceil.l", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 11, "floor.l", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 12, "round.w", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 13, "trunc.w", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 14, "ceil.w", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 15, "floor.w", "fad" }, - { kFpMask | (0x201 << 16), kCop1 | (0x200 << 16) | 17, "movf", "fadc" }, - { kFpMask | (0x201 << 16), kCop1 | (0x201 << 16) | 17, "movt", "fadc" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 18, "movz", "fadT" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 19, "movn", "fadT" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 20, "seleqz", "fadt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 23, "selnez", "fadt" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 26, "rint", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 27, "class", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 32, "cvt.s", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 33, "cvt.d", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 36, "cvt.w", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 37, "cvt.l", "fad" }, - { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 38, "cvt.ps", "fad" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 49, "c.un", "fCdt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 50, "c.eq", "fCdt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 51, "c.ueq", "fCdt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 52, "c.olt", "fCdt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 53, "c.ult", "fCdt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 54, "c.ole", "fCdt" }, - { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 55, "c.ule", "fCdt" }, - { kFpMask, kCop1 | 0x10, "sel", "fadt" }, - { kFpMask, kCop1 | 0x1e, "max", "fadt" }, - { kFpMask, kCop1 | 0x1c, "min", "fadt" }, - - // MSA instructions. - { kMsaMask | (0x1f << 21), kMsa | (0x0 << 21) | 0x1e, "and.v", "kmn" }, - { kMsaMask | (0x1f << 21), kMsa | (0x1 << 21) | 0x1e, "or.v", "kmn" }, - { kMsaMask | (0x1f << 21), kMsa | (0x2 << 21) | 0x1e, "nor.v", "kmn" }, - { kMsaMask | (0x1f << 21), kMsa | (0x3 << 21) | 0x1e, "xor.v", "kmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0xe, "addv", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x1 << 23) | 0xe, "subv", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x4 << 23) | 0x11, "asub_s", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x5 << 23) | 0x11, "asub_u", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0x12, "mulv", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x4 << 23) | 0x12, "div_s", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x5 << 23) | 0x12, "div_u", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x6 << 23) | 0x12, "mod_s", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x7 << 23) | 0x12, "mod_u", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0x10, "add_a", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x4 << 23) | 0x10, "ave_s", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x5 << 23) | 0x10, "ave_u", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x6 << 23) | 0x10, "aver_s", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x7 << 23) | 0x10, "aver_u", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x2 << 23) | 0xe, "max_s", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x3 << 23) | 0xe, "max_u", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x4 << 23) | 0xe, "min_s", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x5 << 23) | 0xe, "min_u", "Vkmn" }, - { kMsaMask | (0xf << 22), kMsa | (0x0 << 22) | 0x1b, "fadd", "Ukmn" }, - { kMsaMask | (0xf << 22), kMsa | (0x1 << 22) | 0x1b, "fsub", "Ukmn" }, - { kMsaMask | (0xf << 22), kMsa | (0x2 << 22) | 0x1b, "fmul", "Ukmn" }, - { kMsaMask | (0xf << 22), kMsa | (0x3 << 22) | 0x1b, "fdiv", "Ukmn" }, - { kMsaMask | (0xf << 22), kMsa | (0xe << 22) | 0x1b, "fmax", "Ukmn" }, - { kMsaMask | (0xf << 22), kMsa | (0xc << 22) | 0x1b, "fmin", "Ukmn" }, - { kMsaMask | (0x1ff << 17), kMsa | (0x19e << 17) | 0x1e, "ffint_s", "ukm" }, - { kMsaMask | (0x1ff << 17), kMsa | (0x19c << 17) | 0x1e, "ftint_s", "ukm" }, - { kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0xd, "sll", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x1 << 23) | 0xd, "sra", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x2 << 23) | 0xd, "srl", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0x9, "slli", "kmW" }, - { kMsaMask | (0x7 << 23), kMsa | (0x1 << 23) | 0x9, "srai", "kmW" }, - { kMsaMask | (0x7 << 23), kMsa | (0x2 << 23) | 0x9, "srli", "kmW" }, - { kMsaMask | (0x3ff << 16), kMsa | (0xbe << 16) | 0x19, "move.v", "km" }, - { kMsaMask | (0xf << 22), kMsa | (0x1 << 22) | 0x19, "splati", "kX" }, - { kMsaMask | (0xf << 22), kMsa | (0x2 << 22) | 0x19, "copy_s", "yX" }, - { kMsaMask | (0xf << 22), kMsa | (0x3 << 22) | 0x19, "copy_u", "yX" }, - { kMsaMask | (0xf << 22), kMsa | (0x4 << 22) | 0x19, "insert", "YD" }, - { kMsaMask | (0xff << 18), kMsa | (0xc0 << 18) | 0x1e, "fill", "vkD" }, - { kMsaMask | (0xff << 18), kMsa | (0xc1 << 18) | 0x1e, "pcnt", "vkm" }, - { kMsaMask | (0x7 << 23), kMsa | (0x6 << 23) | 0x7, "ldi", "kx" }, - { kMsaSpecialMask | (0xf << 2), kMsa | (0x8 << 2), "ld", "kw" }, - { kMsaSpecialMask | (0xf << 2), kMsa | (0x9 << 2), "st", "kw" }, - { kMsaMask | (0x7 << 23), kMsa | (0x4 << 23) | 0x14, "ilvl", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x5 << 23) | 0x14, "ilvr", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x6 << 23) | 0x14, "ilvev", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x7 << 23) | 0x14, "ilvod", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x1 << 23) | 0x12, "maddv", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x2 << 23) | 0x12, "msubv", "Vkmn" }, - { kMsaMask | (0xf << 22), kMsa | (0x4 << 22) | 0x1b, "fmadd", "Ukmn" }, - { kMsaMask | (0xf << 22), kMsa | (0x5 << 22) | 0x1b, "fmsub", "Ukmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x4 << 23) | 0x15, "hadd_s", "Vkmn" }, - { kMsaMask | (0x7 << 23), kMsa | (0x5 << 23) | 0x15, "hadd_u", "Vkmn" }, -}; - -static uint32_t ReadU32(const uint8_t* ptr) { - // We only support little-endian MIPS. - return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); -} - -const char* DisassemblerMips::RegName(uint32_t reg) { - if (is_o32_abi_) { - return gO32AbiRegNames[reg]; - } else { - return gN64AbiRegNames[reg]; - } -} - -size_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* instr_ptr) { - uint32_t instruction = ReadU32(instr_ptr); - - uint32_t rs = (instruction >> 21) & 0x1f; // I-type, R-type. - uint32_t rt = (instruction >> 16) & 0x1f; // I-type, R-type. - uint32_t rd = (instruction >> 11) & 0x1f; // R-type. - uint32_t sa = (instruction >> 6) & 0x1f; // R-type. - - std::string opcode; - std::ostringstream args; - - // TODO: remove this! - uint32_t op = (instruction >> 26) & 0x3f; - uint32_t function = (instruction & 0x3f); // R-type. - opcode = StringPrintf("op=%d fn=%d", op, function); - - for (size_t i = 0; i < arraysize(gMipsInstructions); ++i) { - if (gMipsInstructions[i].Matches(instruction)) { - opcode = gMipsInstructions[i].name; - for (const char* args_fmt = gMipsInstructions[i].args_fmt; *args_fmt; ++args_fmt) { - switch (*args_fmt) { - case 'A': // sa (shift amount or [d]ins/[d]ext position). - args << sa; - break; - case 'B': // Branch offset. - { - int32_t offset = static_cast<int16_t>(instruction & 0xffff); - offset <<= 2; - offset += 4; // Delay slot. - args << FormatInstructionPointer(instr_ptr + offset) - << StringPrintf(" ; %+d", offset); - } - break; - case 'b': // 21-bit branch offset. - { - int32_t offset = (instruction & 0x1fffff) - ((instruction & 0x100000) << 1); - offset <<= 2; - offset += 4; // Delay slot. - args << FormatInstructionPointer(instr_ptr + offset) - << StringPrintf(" ; %+d", offset); - } - break; - case 'C': // Floating-point condition code flag in c.<cond>.fmt. - args << "cc" << (sa >> 2); - break; - case 'c': // Floating-point condition code flag in bc1f/bc1t and movf/movt. - args << "cc" << (rt >> 2); - break; - case 'D': args << RegName(rd); break; - case 'd': args << 'f' << rd; break; - case 'a': args << 'f' << sa; break; - case 'F': args << (sa + 32); break; // dinsu position. - case 'f': // Floating point "fmt". - { - size_t fmt = (instruction >> 21) & 0x7; // TODO: other fmts? - switch (fmt) { - case 0: opcode += ".s"; break; - case 1: opcode += ".d"; break; - case 4: opcode += ".w"; break; - case 5: opcode += ".l"; break; - case 6: opcode += ".ps"; break; - default: opcode += ".?"; break; - } - continue; // No ", ". - } - case 'I': // Unsigned lower 16-bit immediate. - args << (instruction & 0xffff); - break; - case 'i': // Sign-extended lower 16-bit immediate. - args << static_cast<int16_t>(instruction & 0xffff); - break; - case 'J': // sz (dinsm size). - args << (rd - sa + 33); - break; - case 'j': // sa value for lsa/dlsa. - args << (sa + 1); - break; - case 'L': // Jump label. - { - // TODO: is this right? - uint32_t instr_index = (instruction & 0x1ffffff); - uint32_t target = (instr_index << 2); - target |= (reinterpret_cast<uintptr_t>(instr_ptr + 4) & 0xf0000000); - args << reinterpret_cast<void*>(target); - } - break; - case 'l': // 9-bit signed offset - { - int32_t offset = static_cast<int16_t>(instruction) >> 7; - args << StringPrintf("%+d(%s)", offset, RegName(rs)); - } - break; - case 'O': // +x(rs) - { - int32_t offset = static_cast<int16_t>(instruction & 0xffff); - args << StringPrintf("%+d(%s)", offset, RegName(rs)); - if (rs == 17) { - args << " ; "; - GetDisassemblerOptions()->thread_offset_name_function_(args, offset); - } - } - break; - case 'o': // 19-bit offset in lwpc and lwupc. - { - int32_t offset = (instruction & 0x7ffff) - ((instruction & 0x40000) << 1); - offset <<= 2; - args << FormatInstructionPointer(instr_ptr + offset); - args << StringPrintf(" ; %+d", offset); - } - break; - case '0': // 18-bit offset in ldpc. - { - int32_t offset = (instruction & 0x3ffff) - ((instruction & 0x20000) << 1); - offset <<= 3; - uintptr_t ptr = RoundDown(reinterpret_cast<uintptr_t>(instr_ptr), 8); - args << FormatInstructionPointer(reinterpret_cast<const uint8_t*>(ptr + offset)); - args << StringPrintf(" ; %+d", offset); - } - break; - case 'P': // 26-bit offset in bc and balc. - { - int32_t offset = (instruction & 0x3ffffff) - ((instruction & 0x2000000) << 1); - offset <<= 2; - offset += 4; - args << FormatInstructionPointer(instr_ptr + offset); - args << StringPrintf(" ; %+d", offset); - } - break; - case 'p': // 19-bit offset in addiupc. - { - int32_t offset = (instruction & 0x7ffff) - ((instruction & 0x40000) << 1); - args << offset << " ; move " << RegName(rs) << ", "; - args << FormatInstructionPointer(instr_ptr + (offset << 2)); - } - break; - case 'S': args << RegName(rs); break; - case 's': args << 'f' << rs; break; - case 'T': args << RegName(rt); break; - case 't': args << 'f' << rt; break; - case 'Z': args << (rd + 1); break; // sz ([d]ext size). - case 'z': args << (rd - sa + 1); break; // sz ([d]ins, dinsu size). - case 'k': args << 'w' << sa; break; - case 'm': args << 'w' << rd; break; - case 'n': args << 'w' << rt; break; - case 'U': // MSA 1-bit df (word/doubleword), position 21. - { - int32_t df = (instruction >> 21) & 0x1; - switch (df) { - case 0: opcode += ".w"; break; - case 1: opcode += ".d"; break; - } - continue; // No ", ". - } - case 'u': // MSA 1-bit df (word/doubleword), position 16. - { - int32_t df = (instruction >> 16) & 0x1; - switch (df) { - case 0: opcode += ".w"; break; - case 1: opcode += ".d"; break; - } - continue; // No ", ". - } - case 'V': // MSA 2-bit df, position 21. - { - int32_t df = (instruction >> 21) & 0x3; - switch (df) { - case 0: opcode += ".b"; break; - case 1: opcode += ".h"; break; - case 2: opcode += ".w"; break; - case 3: opcode += ".d"; break; - } - continue; // No ", ". - } - case 'v': // MSA 2-bit df, position 16. - { - int32_t df = (instruction >> 16) & 0x3; - switch (df) { - case 0: opcode += ".b"; break; - case 1: opcode += ".h"; break; - case 2: opcode += ".w"; break; - case 3: opcode += ".d"; break; - } - continue; // No ", ". - } - case 'W': // MSA df/m. - { - int32_t df_m = (instruction >> 16) & 0x7f; - if ((df_m & (0x1 << 6)) == 0) { - opcode += ".d"; - args << (df_m & 0x3f); - break; - } - if ((df_m & (0x1 << 5)) == 0) { - opcode += ".w"; - args << (df_m & 0x1f); - break; - } - if ((df_m & (0x1 << 4)) == 0) { - opcode += ".h"; - args << (df_m & 0xf); - break; - } - if ((df_m & (0x1 << 3)) == 0) { - opcode += ".b"; - args << (df_m & 0x7); - } - break; - } - case 'w': // MSA +x(rs). - { - int32_t df = instruction & 0x3; - int32_t s10 = (instruction >> 16) & 0x3ff; - s10 -= (s10 & 0x200) << 1; // Sign-extend s10. - switch (df) { - case 0: opcode += ".b"; break; - case 1: opcode += ".h"; break; - case 2: opcode += ".w"; break; - case 3: opcode += ".d"; break; - } - args << StringPrintf("%+d(%s)", s10 << df, RegName(rd)); - break; - } - case 'X': // MSA df/n - ws[x]. - { - int32_t df_n = (instruction >> 16) & 0x3f; - if ((df_n & (0x3 << 4)) == 0) { - opcode += ".b"; - args << 'w' << rd << '[' << (df_n & 0xf) << ']'; - break; - } - if ((df_n & (0x3 << 3)) == 0) { - opcode += ".h"; - args << 'w' << rd << '[' << (df_n & 0x7) << ']'; - break; - } - if ((df_n & (0x3 << 2)) == 0) { - opcode += ".w"; - args << 'w' << rd << '[' << (df_n & 0x3) << ']'; - break; - } - if ((df_n & (0x3 << 1)) == 0) { - opcode += ".d"; - args << 'w' << rd << '[' << (df_n & 0x1) << ']'; - } - break; - } - case 'x': // MSA i10. - { - int32_t df = (instruction >> 21) & 0x3; - int32_t i10 = (instruction >> 11) & 0x3ff; - i10 -= (i10 & 0x200) << 1; // Sign-extend i10. - switch (df) { - case 0: opcode += ".b"; break; - case 1: opcode += ".h"; break; - case 2: opcode += ".w"; break; - case 3: opcode += ".d"; break; - } - args << i10; - break; - } - case 'Y': // MSA df/n - wd[x]. - { - int32_t df_n = (instruction >> 16) & 0x3f; - if ((df_n & (0x3 << 4)) == 0) { - opcode += ".b"; - args << 'w' << sa << '[' << (df_n & 0xf) << ']'; - break; - } - if ((df_n & (0x3 << 3)) == 0) { - opcode += ".h"; - args << 'w' << sa << '[' << (df_n & 0x7) << ']'; - break; - } - if ((df_n & (0x3 << 2)) == 0) { - opcode += ".w"; - args << 'w' << sa << '[' << (df_n & 0x3) << ']'; - break; - } - if ((df_n & (0x3 << 1)) == 0) { - opcode += ".d"; - args << 'w' << sa << '[' << (df_n & 0x1) << ']'; - } - break; - } - case 'y': args << RegName(sa); break; - } - if (*(args_fmt + 1)) { - args << ", "; - } - } - break; - } - } - - // Special cases for sequences of: - // pc-relative +/- 2GB branch: - // auipc reg, imm - // jic reg, imm - // pc-relative +/- 2GB branch and link: - // auipc reg, imm - // jialc reg, imm - if (((op == 0x36 || op == 0x3E) && rs == 0 && rt != 0) && // ji[al]c - last_ptr_ && (intptr_t)instr_ptr - (intptr_t)last_ptr_ == 4 && - (last_instr_ & 0xFC1F0000) == 0xEC1E0000 && // auipc - ((last_instr_ >> 21) & 0x1F) == rt) { - uint32_t offset = (last_instr_ << 16) | (instruction & 0xFFFF); - offset -= (offset & 0x8000) << 1; - offset -= 4; - if (op == 0x36) { - args << " ; bc "; - } else { - args << " ; balc "; - } - args << FormatInstructionPointer(instr_ptr + (int32_t)offset); - args << StringPrintf(" ; %+d", (int32_t)offset); - } - - os << FormatInstructionPointer(instr_ptr) - << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str()) - << args.str() << '\n'; - last_ptr_ = instr_ptr; - last_instr_ = instruction; - return 4; -} - -void DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { - for (const uint8_t* cur = begin; cur < end; cur += 4) { - Dump(os, cur); - } -} - -} // namespace mips -} // namespace art diff --git a/disassembler/disassembler_mips.h b/disassembler/disassembler_mips.h deleted file mode 100644 index bc74b43ac9..0000000000 --- a/disassembler/disassembler_mips.h +++ /dev/null @@ -1,52 +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_DISASSEMBLER_DISASSEMBLER_MIPS_H_ -#define ART_DISASSEMBLER_DISASSEMBLER_MIPS_H_ - -#include <vector> - -#include "disassembler.h" - -namespace art { -namespace mips { - -class DisassemblerMips final : public Disassembler { - public: - explicit DisassemblerMips(DisassemblerOptions* options, bool is_o32_abi) - : Disassembler(options), - last_ptr_(nullptr), - last_instr_(0), - is_o32_abi_(is_o32_abi) {} - - const char* RegName(uint32_t reg); - size_t Dump(std::ostream& os, const uint8_t* begin) override; - void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) override; - - private: - // Address and encoding of the last disassembled instruction. - // Needed to produce more readable disassembly of certain 2-instruction sequences. - const uint8_t* last_ptr_; - uint32_t last_instr_; - const bool is_o32_abi_; - - DISALLOW_COPY_AND_ASSIGN(DisassemblerMips); -}; - -} // namespace mips -} // namespace art - -#endif // ART_DISASSEMBLER_DISASSEMBLER_MIPS_H_ |