diff options
Diffstat (limited to 'deps/v8/src/codegen/mips/constants-mips.h')
-rw-r--r-- | deps/v8/src/codegen/mips/constants-mips.h | 1901 |
1 files changed, 1901 insertions, 0 deletions
diff --git a/deps/v8/src/codegen/mips/constants-mips.h b/deps/v8/src/codegen/mips/constants-mips.h new file mode 100644 index 0000000000..d2b3f6b08f --- /dev/null +++ b/deps/v8/src/codegen/mips/constants-mips.h @@ -0,0 +1,1901 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CODEGEN_MIPS_CONSTANTS_MIPS_H_ +#define V8_CODEGEN_MIPS_CONSTANTS_MIPS_H_ +#include "src/codegen/cpu-features.h" +// UNIMPLEMENTED_ macro for MIPS. +#ifdef DEBUG +#define UNIMPLEMENTED_MIPS() \ + v8::internal::PrintF("%s, \tline %d: \tfunction %s not implemented. \n", \ + __FILE__, __LINE__, __func__) +#else +#define UNIMPLEMENTED_MIPS() +#endif + +#define UNSUPPORTED_MIPS() v8::internal::PrintF("Unsupported instruction.\n") + +enum ArchVariants { + kMips32r1 = v8::internal::MIPSr1, + kMips32r2 = v8::internal::MIPSr2, + kMips32r6 = v8::internal::MIPSr6, + kLoongson +}; + +#ifdef _MIPS_ARCH_MIPS32R2 +static const ArchVariants kArchVariant = kMips32r2; +#elif _MIPS_ARCH_MIPS32R6 +static const ArchVariants kArchVariant = kMips32r6; +#elif _MIPS_ARCH_LOONGSON +// The loongson flag refers to the LOONGSON architectures based on MIPS-III, +// which predates (and is a subset of) the mips32r2 and r1 architectures. +static const ArchVariants kArchVariant = kLoongson; +#elif _MIPS_ARCH_MIPS32RX +// This flags referred to compatibility mode that creates universal code that +// can run on any MIPS32 architecture revision. The dynamically generated code +// by v8 is specialized for the MIPS host detected in runtime probing. +static const ArchVariants kArchVariant = kMips32r1; +#else +static const ArchVariants kArchVariant = kMips32r1; +#endif + +enum Endianness { kLittle, kBig }; + +#if defined(V8_TARGET_LITTLE_ENDIAN) +static const Endianness kArchEndian = kLittle; +#elif defined(V8_TARGET_BIG_ENDIAN) +static const Endianness kArchEndian = kBig; +#else +#error Unknown endianness +#endif + +enum FpuMode { kFP32, kFP64, kFPXX }; + +#if defined(FPU_MODE_FP32) +static const FpuMode kFpuMode = kFP32; +#elif defined(FPU_MODE_FP64) +static const FpuMode kFpuMode = kFP64; +#elif defined(FPU_MODE_FPXX) +#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS32R6) +static const FpuMode kFpuMode = kFPXX; +#else +#error "FPXX is supported only on Mips32R2 and Mips32R6" +#endif +#else +static const FpuMode kFpuMode = kFP32; +#endif + +#if defined(__mips_hard_float) && __mips_hard_float != 0 +// Use floating-point coprocessor instructions. This flag is raised when +// -mhard-float is passed to the compiler. +const bool IsMipsSoftFloatABI = false; +#elif defined(__mips_soft_float) && __mips_soft_float != 0 +// This flag is raised when -msoft-float is passed to the compiler. +// Although FPU is a base requirement for v8, soft-float ABI is used +// on soft-float systems with FPU kernel emulation. +const bool IsMipsSoftFloatABI = true; +#else +const bool IsMipsSoftFloatABI = true; +#endif + +#if defined(V8_TARGET_LITTLE_ENDIAN) +const uint32_t kHoleNanUpper32Offset = 4; +const uint32_t kHoleNanLower32Offset = 0; +#elif defined(V8_TARGET_BIG_ENDIAN) +const uint32_t kHoleNanUpper32Offset = 0; +const uint32_t kHoleNanLower32Offset = 4; +#else +#error Unknown endianness +#endif + +#define IsFp64Mode() (kFpuMode == kFP64) +#define IsFp32Mode() (kFpuMode == kFP32) +#define IsFpxxMode() (kFpuMode == kFPXX) + +#ifndef _MIPS_ARCH_MIPS32RX +#define IsMipsArchVariant(check) (kArchVariant == check) +#else +#define IsMipsArchVariant(check) \ + (CpuFeatures::IsSupported(static_cast<CpuFeature>(check))) +#endif + +#if defined(V8_TARGET_LITTLE_ENDIAN) +const uint32_t kMipsLwrOffset = 0; +const uint32_t kMipsLwlOffset = 3; +const uint32_t kMipsSwrOffset = 0; +const uint32_t kMipsSwlOffset = 3; +#elif defined(V8_TARGET_BIG_ENDIAN) +const uint32_t kMipsLwrOffset = 3; +const uint32_t kMipsLwlOffset = 0; +const uint32_t kMipsSwrOffset = 3; +const uint32_t kMipsSwlOffset = 0; +#else +#error Unknown endianness +#endif + +#if defined(V8_TARGET_LITTLE_ENDIAN) +const uint32_t kLeastSignificantByteInInt32Offset = 0; +#elif defined(V8_TARGET_BIG_ENDIAN) +const uint32_t kLeastSignificantByteInInt32Offset = 3; +#else +#error Unknown endianness +#endif + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include <inttypes.h> + +// Defines constants and accessor classes to assemble, disassemble and +// simulate MIPS32 instructions. +// +// See: MIPS32 Architecture For Programmers +// Volume II: The MIPS32 Instruction Set +// Try www.cs.cornell.edu/courses/cs3410/2008fa/MIPS_Vol2.pdf. + +namespace v8 { +namespace internal { + +constexpr size_t kMaxPCRelativeCodeRangeInMB = 4096; + +// ----------------------------------------------------------------------------- +// Registers and FPURegisters. + +// Number of general purpose registers. +const int kNumRegisters = 32; +const int kInvalidRegister = -1; + +// Number of registers with HI, LO, and pc. +const int kNumSimuRegisters = 35; + +// In the simulator, the PC register is simulated as the 34th register. +const int kPCRegister = 34; + +// Number coprocessor registers. +const int kNumFPURegisters = 32; +const int kInvalidFPURegister = -1; + +// Number of MSA registers +const int kNumMSARegisters = 32; +const int kInvalidMSARegister = -1; + +const int kInvalidMSAControlRegister = -1; +const int kMSAIRRegister = 0; +const int kMSACSRRegister = 1; +const int kMSARegSize = 128; +const int kMSALanesByte = kMSARegSize / 8; +const int kMSALanesHalf = kMSARegSize / 16; +const int kMSALanesWord = kMSARegSize / 32; +const int kMSALanesDword = kMSARegSize / 64; + +// FPU (coprocessor 1) control registers. Currently only FCSR is implemented. +const int kFCSRRegister = 31; +const int kInvalidFPUControlRegister = -1; +const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1u << 31) - 1; +const int32_t kFPUInvalidResultNegative = static_cast<int32_t>(1u << 31); +const uint64_t kFPU64InvalidResult = + static_cast<uint64_t>(static_cast<uint64_t>(1) << 63) - 1; +const int64_t kFPU64InvalidResultNegative = + static_cast<int64_t>(static_cast<uint64_t>(1) << 63); + +// FCSR constants. +const uint32_t kFCSRInexactFlagBit = 2; +const uint32_t kFCSRUnderflowFlagBit = 3; +const uint32_t kFCSROverflowFlagBit = 4; +const uint32_t kFCSRDivideByZeroFlagBit = 5; +const uint32_t kFCSRInvalidOpFlagBit = 6; +const uint32_t kFCSRNaN2008FlagBit = 18; + +const uint32_t kFCSRInexactFlagMask = 1 << kFCSRInexactFlagBit; +const uint32_t kFCSRUnderflowFlagMask = 1 << kFCSRUnderflowFlagBit; +const uint32_t kFCSROverflowFlagMask = 1 << kFCSROverflowFlagBit; +const uint32_t kFCSRDivideByZeroFlagMask = 1 << kFCSRDivideByZeroFlagBit; +const uint32_t kFCSRInvalidOpFlagMask = 1 << kFCSRInvalidOpFlagBit; +const uint32_t kFCSRNaN2008FlagMask = 1 << kFCSRNaN2008FlagBit; + +const uint32_t kFCSRFlagMask = + kFCSRInexactFlagMask | kFCSRUnderflowFlagMask | kFCSROverflowFlagMask | + kFCSRDivideByZeroFlagMask | kFCSRInvalidOpFlagMask; + +const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask; + +// 'pref' instruction hints +const int32_t kPrefHintLoad = 0; +const int32_t kPrefHintStore = 1; +const int32_t kPrefHintLoadStreamed = 4; +const int32_t kPrefHintStoreStreamed = 5; +const int32_t kPrefHintLoadRetained = 6; +const int32_t kPrefHintStoreRetained = 7; +const int32_t kPrefHintWritebackInvalidate = 25; +const int32_t kPrefHintPrepareForStore = 30; + +// Actual value of root register is offset from the root array's start +// to take advantage of negative displacement values. +// TODO(sigurds): Choose best value. +constexpr int kRootRegisterBias = 256; + +// Helper functions for converting between register numbers and names. +class Registers { + public: + // Return the name of the register. + static const char* Name(int reg); + + // Lookup the register number for the name provided. + static int Number(const char* name); + + struct RegisterAlias { + int reg; + const char* name; + }; + + static const int32_t kMaxValue = 0x7fffffff; + static const int32_t kMinValue = 0x80000000; + + private: + static const char* names_[kNumSimuRegisters]; + static const RegisterAlias aliases_[]; +}; + +// Helper functions for converting between register numbers and names. +class FPURegisters { + public: + // Return the name of the register. + static const char* Name(int reg); + + // Lookup the register number for the name provided. + static int Number(const char* name); + + struct RegisterAlias { + int creg; + const char* name; + }; + + private: + static const char* names_[kNumFPURegisters]; + static const RegisterAlias aliases_[]; +}; + +// Helper functions for converting between register numbers and names. +class MSARegisters { + public: + // Return the name of the register. + static const char* Name(int reg); + + // Lookup the register number for the name provided. + static int Number(const char* name); + + struct RegisterAlias { + int creg; + const char* name; + }; + + private: + static const char* names_[kNumMSARegisters]; + static const RegisterAlias aliases_[]; +}; + +// ----------------------------------------------------------------------------- +// Instructions encoding constants. + +// On MIPS all instructions are 32 bits. +using Instr = int32_t; + +// Special Software Interrupt codes when used in the presence of the MIPS +// simulator. +enum SoftwareInterruptCodes { + // Transition to C code. + call_rt_redirected = 0xfffff +}; + +// On MIPS Simulator breakpoints can have different codes: +// - Breaks between 0 and kMaxWatchpointCode are treated as simple watchpoints, +// the simulator will run through them and print the registers. +// - Breaks between kMaxWatchpointCode and kMaxStopCode are treated as stop() +// instructions (see Assembler::stop()). +// - Breaks larger than kMaxStopCode are simple breaks, dropping you into the +// debugger. +const uint32_t kMaxWatchpointCode = 31; +const uint32_t kMaxStopCode = 127; +STATIC_ASSERT(kMaxWatchpointCode < kMaxStopCode); + +// ----- Fields offset and length. +const int kOpcodeShift = 26; +const int kOpcodeBits = 6; +const int kRsShift = 21; +const int kRsBits = 5; +const int kRtShift = 16; +const int kRtBits = 5; +const int kRdShift = 11; +const int kRdBits = 5; +const int kSaShift = 6; +const int kSaBits = 5; +const int kLsaSaBits = 2; +const int kFunctionShift = 0; +const int kFunctionBits = 6; +const int kLuiShift = 16; +const int kBp2Shift = 6; +const int kBp2Bits = 2; +const int kBaseShift = 21; +const int kBaseBits = 5; +const int kBit6Shift = 6; +const int kBit6Bits = 1; + +const int kImm9Shift = 7; +const int kImm9Bits = 9; +const int kImm16Shift = 0; +const int kImm16Bits = 16; +const int kImm18Shift = 0; +const int kImm18Bits = 18; +const int kImm19Shift = 0; +const int kImm19Bits = 19; +const int kImm21Shift = 0; +const int kImm21Bits = 21; +const int kImm26Shift = 0; +const int kImm26Bits = 26; +const int kImm28Shift = 0; +const int kImm28Bits = 28; +const int kImm32Shift = 0; +const int kImm32Bits = 32; +const int kMsaImm8Shift = 16; +const int kMsaImm8Bits = 8; +const int kMsaImm5Shift = 16; +const int kMsaImm5Bits = 5; +const int kMsaImm10Shift = 11; +const int kMsaImm10Bits = 10; +const int kMsaImmMI10Shift = 16; +const int kMsaImmMI10Bits = 10; + +// In branches and jumps immediate fields point to words, not bytes, +// and are therefore shifted by 2. +const int kImmFieldShift = 2; + +const int kFrBits = 5; +const int kFrShift = 21; +const int kFsShift = 11; +const int kFsBits = 5; +const int kFtShift = 16; +const int kFtBits = 5; +const int kFdShift = 6; +const int kFdBits = 5; +const int kFCccShift = 8; +const int kFCccBits = 3; +const int kFBccShift = 18; +const int kFBccBits = 3; +const int kFBtrueShift = 16; +const int kFBtrueBits = 1; +const int kWtBits = 5; +const int kWtShift = 16; +const int kWsBits = 5; +const int kWsShift = 11; +const int kWdBits = 5; +const int kWdShift = 6; + +// ----- Miscellaneous useful masks. +// Instruction bit masks. +const int kOpcodeMask = ((1 << kOpcodeBits) - 1) << kOpcodeShift; +const int kImm9Mask = ((1 << kImm9Bits) - 1) << kImm9Shift; +const int kImm16Mask = ((1 << kImm16Bits) - 1) << kImm16Shift; +const int kImm18Mask = ((1 << kImm18Bits) - 1) << kImm18Shift; +const int kImm19Mask = ((1 << kImm19Bits) - 1) << kImm19Shift; +const int kImm21Mask = ((1 << kImm21Bits) - 1) << kImm21Shift; +const int kImm26Mask = ((1 << kImm26Bits) - 1) << kImm26Shift; +const int kImm28Mask = ((1 << kImm28Bits) - 1) << kImm28Shift; +const int kImm5Mask = ((1 << 5) - 1); +const int kImm8Mask = ((1 << 8) - 1); +const int kImm10Mask = ((1 << 10) - 1); +const int kMsaI5I10Mask = ((7U << 23) | ((1 << 6) - 1)); +const int kMsaI8Mask = ((3U << 24) | ((1 << 6) - 1)); +const int kMsaI5Mask = ((7U << 23) | ((1 << 6) - 1)); +const int kMsaMI10Mask = (15U << 2); +const int kMsaBITMask = ((7U << 23) | ((1 << 6) - 1)); +const int kMsaELMMask = (15U << 22); +const int kMsaLongerELMMask = kMsaELMMask | (63U << 16); +const int kMsa3RMask = ((7U << 23) | ((1 << 6) - 1)); +const int kMsa3RFMask = ((15U << 22) | ((1 << 6) - 1)); +const int kMsaVECMask = (23U << 21); +const int kMsa2RMask = (7U << 18); +const int kMsa2RFMask = (15U << 17); +const int kRsFieldMask = ((1 << kRsBits) - 1) << kRsShift; +const int kRtFieldMask = ((1 << kRtBits) - 1) << kRtShift; +const int kRdFieldMask = ((1 << kRdBits) - 1) << kRdShift; +const int kSaFieldMask = ((1 << kSaBits) - 1) << kSaShift; +const int kFunctionFieldMask = ((1 << kFunctionBits) - 1) << kFunctionShift; +// Misc masks. +const int kHiMask = 0xffff << 16; +const int kLoMask = 0xffff; +const int kSignMask = 0x80000000; +const int kJumpAddrMask = (1 << (kImm26Bits + kImmFieldShift)) - 1; + +// ----- MIPS Opcodes and Function Fields. +// We use this presentation to stay close to the table representation in +// MIPS32 Architecture For Programmers, Volume II: The MIPS32 Instruction Set. +enum Opcode : uint32_t { + SPECIAL = 0U << kOpcodeShift, + REGIMM = 1U << kOpcodeShift, + + J = ((0U << 3) + 2) << kOpcodeShift, + JAL = ((0U << 3) + 3) << kOpcodeShift, + BEQ = ((0U << 3) + 4) << kOpcodeShift, + BNE = ((0U << 3) + 5) << kOpcodeShift, + BLEZ = ((0U << 3) + 6) << kOpcodeShift, + BGTZ = ((0U << 3) + 7) << kOpcodeShift, + + ADDI = ((1U << 3) + 0) << kOpcodeShift, + ADDIU = ((1U << 3) + 1) << kOpcodeShift, + SLTI = ((1U << 3) + 2) << kOpcodeShift, + SLTIU = ((1U << 3) + 3) << kOpcodeShift, + ANDI = ((1U << 3) + 4) << kOpcodeShift, + ORI = ((1U << 3) + 5) << kOpcodeShift, + XORI = ((1U << 3) + 6) << kOpcodeShift, + LUI = ((1U << 3) + 7) << kOpcodeShift, // LUI/AUI family. + + BEQC = ((2U << 3) + 0) << kOpcodeShift, + COP1 = ((2U << 3) + 1) << kOpcodeShift, // Coprocessor 1 class. + BEQL = ((2U << 3) + 4) << kOpcodeShift, + BNEL = ((2U << 3) + 5) << kOpcodeShift, + BLEZL = ((2U << 3) + 6) << kOpcodeShift, + BGTZL = ((2U << 3) + 7) << kOpcodeShift, + + DADDI = ((3U << 3) + 0) << kOpcodeShift, // This is also BNEC. + SPECIAL2 = ((3U << 3) + 4) << kOpcodeShift, + MSA = ((3U << 3) + 6) << kOpcodeShift, + SPECIAL3 = ((3U << 3) + 7) << kOpcodeShift, + + LB = ((4U << 3) + 0) << kOpcodeShift, + LH = ((4U << 3) + 1) << kOpcodeShift, + LWL = ((4U << 3) + 2) << kOpcodeShift, + LW = ((4U << 3) + 3) << kOpcodeShift, + LBU = ((4U << 3) + 4) << kOpcodeShift, + LHU = ((4U << 3) + 5) << kOpcodeShift, + LWR = ((4U << 3) + 6) << kOpcodeShift, + SB = ((5U << 3) + 0) << kOpcodeShift, + SH = ((5U << 3) + 1) << kOpcodeShift, + SWL = ((5U << 3) + 2) << kOpcodeShift, + SW = ((5U << 3) + 3) << kOpcodeShift, + SWR = ((5U << 3) + 6) << kOpcodeShift, + + LL = ((6U << 3) + 0) << kOpcodeShift, + LWC1 = ((6U << 3) + 1) << kOpcodeShift, + BC = ((6U << 3) + 2) << kOpcodeShift, + LDC1 = ((6U << 3) + 5) << kOpcodeShift, + POP66 = ((6U << 3) + 6) << kOpcodeShift, // beqzc, jic + + PREF = ((6U << 3) + 3) << kOpcodeShift, + + SC = ((7U << 3) + 0) << kOpcodeShift, + SWC1 = ((7U << 3) + 1) << kOpcodeShift, + BALC = ((7U << 3) + 2) << kOpcodeShift, + PCREL = ((7U << 3) + 3) << kOpcodeShift, + SDC1 = ((7U << 3) + 5) << kOpcodeShift, + POP76 = ((7U << 3) + 6) << kOpcodeShift, // bnezc, jialc + + COP1X = ((1U << 4) + 3) << kOpcodeShift, + + // New r6 instruction. + POP06 = BLEZ, // bgeuc/bleuc, blezalc, bgezalc + POP07 = BGTZ, // bltuc/bgtuc, bgtzalc, bltzalc + POP10 = ADDI, // beqzalc, bovc, beqc + POP26 = BLEZL, // bgezc, blezc, bgec/blec + POP27 = BGTZL, // bgtzc, bltzc, bltc/bgtc + POP30 = DADDI, // bnezalc, bnvc, bnec +}; + +enum SecondaryField : uint32_t { + // SPECIAL Encoding of Function Field. + SLL = ((0U << 3) + 0), + MOVCI = ((0U << 3) + 1), + SRL = ((0U << 3) + 2), + SRA = ((0U << 3) + 3), + SLLV = ((0U << 3) + 4), + LSA = ((0U << 3) + 5), + SRLV = ((0U << 3) + 6), + SRAV = ((0U << 3) + 7), + + JR = ((1U << 3) + 0), + JALR = ((1U << 3) + 1), + MOVZ = ((1U << 3) + 2), + MOVN = ((1U << 3) + 3), + BREAK = ((1U << 3) + 5), + SYNC = ((1U << 3) + 7), + + MFHI = ((2U << 3) + 0), + CLZ_R6 = ((2U << 3) + 0), + CLO_R6 = ((2U << 3) + 1), + MFLO = ((2U << 3) + 2), + + MULT = ((3U << 3) + 0), + MULTU = ((3U << 3) + 1), + DIV = ((3U << 3) + 2), + DIVU = ((3U << 3) + 3), + + ADD = ((4U << 3) + 0), + ADDU = ((4U << 3) + 1), + SUB = ((4U << 3) + 2), + SUBU = ((4U << 3) + 3), + AND = ((4U << 3) + 4), + OR = ((4U << 3) + 5), + XOR = ((4U << 3) + 6), + NOR = ((4U << 3) + 7), + + SLT = ((5U << 3) + 2), + SLTU = ((5U << 3) + 3), + + TGE = ((6U << 3) + 0), + TGEU = ((6U << 3) + 1), + TLT = ((6U << 3) + 2), + TLTU = ((6U << 3) + 3), + TEQ = ((6U << 3) + 4), + SELEQZ_S = ((6U << 3) + 5), + TNE = ((6U << 3) + 6), + SELNEZ_S = ((6U << 3) + 7), + + // Multiply integers in r6. + MUL_MUH = ((3U << 3) + 0), // MUL, MUH. + MUL_MUH_U = ((3U << 3) + 1), // MUL_U, MUH_U. + RINT = ((3U << 3) + 2), + + MUL_OP = ((0U << 3) + 2), + MUH_OP = ((0U << 3) + 3), + DIV_OP = ((0U << 3) + 2), + MOD_OP = ((0U << 3) + 3), + + DIV_MOD = ((3U << 3) + 2), + DIV_MOD_U = ((3U << 3) + 3), + + // SPECIAL2 Encoding of Function Field. + MUL = ((0U << 3) + 2), + CLZ = ((4U << 3) + 0), + CLO = ((4U << 3) + 1), + + // SPECIAL3 Encoding of Function Field. + EXT = ((0U << 3) + 0), + INS = ((0U << 3) + 4), + BSHFL = ((4U << 3) + 0), + SC_R6 = ((4U << 3) + 6), + LL_R6 = ((6U << 3) + 6), + + // SPECIAL3 Encoding of sa Field. + BITSWAP = ((0U << 3) + 0), + ALIGN = ((0U << 3) + 2), + WSBH = ((0U << 3) + 2), + SEB = ((2U << 3) + 0), + SEH = ((3U << 3) + 0), + + // REGIMM encoding of rt Field. + BLTZ = ((0U << 3) + 0) << 16, + BGEZ = ((0U << 3) + 1) << 16, + BLTZAL = ((2U << 3) + 0) << 16, + BGEZAL = ((2U << 3) + 1) << 16, + BGEZALL = ((2U << 3) + 3) << 16, + + // COP1 Encoding of rs Field. + MFC1 = ((0U << 3) + 0) << 21, + CFC1 = ((0U << 3) + 2) << 21, + MFHC1 = ((0U << 3) + 3) << 21, + MTC1 = ((0U << 3) + 4) << 21, + CTC1 = ((0U << 3) + 6) << 21, + MTHC1 = ((0U << 3) + 7) << 21, + BC1 = ((1U << 3) + 0) << 21, + S = ((2U << 3) + 0) << 21, + D = ((2U << 3) + 1) << 21, + W = ((2U << 3) + 4) << 21, + L = ((2U << 3) + 5) << 21, + PS = ((2U << 3) + 6) << 21, + // COP1 Encoding of Function Field When rs=S. + + ADD_S = ((0U << 3) + 0), + SUB_S = ((0U << 3) + 1), + MUL_S = ((0U << 3) + 2), + DIV_S = ((0U << 3) + 3), + ABS_S = ((0U << 3) + 5), + SQRT_S = ((0U << 3) + 4), + MOV_S = ((0U << 3) + 6), + NEG_S = ((0U << 3) + 7), + ROUND_L_S = ((1U << 3) + 0), + TRUNC_L_S = ((1U << 3) + 1), + CEIL_L_S = ((1U << 3) + 2), + FLOOR_L_S = ((1U << 3) + 3), + ROUND_W_S = ((1U << 3) + 4), + TRUNC_W_S = ((1U << 3) + 5), + CEIL_W_S = ((1U << 3) + 6), + FLOOR_W_S = ((1U << 3) + 7), + RECIP_S = ((2U << 3) + 5), + RSQRT_S = ((2U << 3) + 6), + MADDF_S = ((3U << 3) + 0), + MSUBF_S = ((3U << 3) + 1), + CLASS_S = ((3U << 3) + 3), + CVT_D_S = ((4U << 3) + 1), + CVT_W_S = ((4U << 3) + 4), + CVT_L_S = ((4U << 3) + 5), + CVT_PS_S = ((4U << 3) + 6), + + // COP1 Encoding of Function Field When rs=D. + ADD_D = ((0U << 3) + 0), + SUB_D = ((0U << 3) + 1), + MUL_D = ((0U << 3) + 2), + DIV_D = ((0U << 3) + 3), + SQRT_D = ((0U << 3) + 4), + ABS_D = ((0U << 3) + 5), + MOV_D = ((0U << 3) + 6), + NEG_D = ((0U << 3) + 7), + ROUND_L_D = ((1U << 3) + 0), + TRUNC_L_D = ((1U << 3) + 1), + CEIL_L_D = ((1U << 3) + 2), + FLOOR_L_D = ((1U << 3) + 3), + ROUND_W_D = ((1U << 3) + 4), + TRUNC_W_D = ((1U << 3) + 5), + CEIL_W_D = ((1U << 3) + 6), + FLOOR_W_D = ((1U << 3) + 7), + RECIP_D = ((2U << 3) + 5), + RSQRT_D = ((2U << 3) + 6), + MADDF_D = ((3U << 3) + 0), + MSUBF_D = ((3U << 3) + 1), + CLASS_D = ((3U << 3) + 3), + MIN = ((3U << 3) + 4), + MINA = ((3U << 3) + 5), + MAX = ((3U << 3) + 6), + MAXA = ((3U << 3) + 7), + CVT_S_D = ((4U << 3) + 0), + CVT_W_D = ((4U << 3) + 4), + CVT_L_D = ((4U << 3) + 5), + C_F_D = ((6U << 3) + 0), + C_UN_D = ((6U << 3) + 1), + C_EQ_D = ((6U << 3) + 2), + C_UEQ_D = ((6U << 3) + 3), + C_OLT_D = ((6U << 3) + 4), + C_ULT_D = ((6U << 3) + 5), + C_OLE_D = ((6U << 3) + 6), + C_ULE_D = ((6U << 3) + 7), + + // COP1 Encoding of Function Field When rs=W or L. + CVT_S_W = ((4U << 3) + 0), + CVT_D_W = ((4U << 3) + 1), + CVT_S_L = ((4U << 3) + 0), + CVT_D_L = ((4U << 3) + 1), + BC1EQZ = ((2U << 2) + 1) << 21, + BC1NEZ = ((3U << 2) + 1) << 21, + // COP1 CMP positive predicates Bit 5..4 = 00. + CMP_AF = ((0U << 3) + 0), + CMP_UN = ((0U << 3) + 1), + CMP_EQ = ((0U << 3) + 2), + CMP_UEQ = ((0U << 3) + 3), + CMP_LT = ((0U << 3) + 4), + CMP_ULT = ((0U << 3) + 5), + CMP_LE = ((0U << 3) + 6), + CMP_ULE = ((0U << 3) + 7), + CMP_SAF = ((1U << 3) + 0), + CMP_SUN = ((1U << 3) + 1), + CMP_SEQ = ((1U << 3) + 2), + CMP_SUEQ = ((1U << 3) + 3), + CMP_SSLT = ((1U << 3) + 4), + CMP_SSULT = ((1U << 3) + 5), + CMP_SLE = ((1U << 3) + 6), + CMP_SULE = ((1U << 3) + 7), + // COP1 CMP negative predicates Bit 5..4 = 01. + CMP_AT = ((2U << 3) + 0), // Reserved, not implemented. + CMP_OR = ((2U << 3) + 1), + CMP_UNE = ((2U << 3) + 2), + CMP_NE = ((2U << 3) + 3), + CMP_UGE = ((2U << 3) + 4), // Reserved, not implemented. + CMP_OGE = ((2U << 3) + 5), // Reserved, not implemented. + CMP_UGT = ((2U << 3) + 6), // Reserved, not implemented. + CMP_OGT = ((2U << 3) + 7), // Reserved, not implemented. + CMP_SAT = ((3U << 3) + 0), // Reserved, not implemented. + CMP_SOR = ((3U << 3) + 1), + CMP_SUNE = ((3U << 3) + 2), + CMP_SNE = ((3U << 3) + 3), + CMP_SUGE = ((3U << 3) + 4), // Reserved, not implemented. + CMP_SOGE = ((3U << 3) + 5), // Reserved, not implemented. + CMP_SUGT = ((3U << 3) + 6), // Reserved, not implemented. + CMP_SOGT = ((3U << 3) + 7), // Reserved, not implemented. + + SEL = ((2U << 3) + 0), + MOVZ_C = ((2U << 3) + 2), + MOVN_C = ((2U << 3) + 3), + SELEQZ_C = ((2U << 3) + 4), // COP1 on FPR registers. + MOVF = ((2U << 3) + 1), // Function field for MOVT.fmt and MOVF.fmt + SELNEZ_C = ((2U << 3) + 7), // COP1 on FPR registers. + // COP1 Encoding of Function Field When rs=PS. + + // COP1X Encoding of Function Field. + MADD_S = ((4U << 3) + 0), + MADD_D = ((4U << 3) + 1), + MSUB_S = ((5U << 3) + 0), + MSUB_D = ((5U << 3) + 1), + + // PCREL Encoding of rt Field. + ADDIUPC = ((0U << 2) + 0), + LWPC = ((0U << 2) + 1), + AUIPC = ((3U << 3) + 6), + ALUIPC = ((3U << 3) + 7), + + // POP66 Encoding of rs Field. + JIC = ((0U << 5) + 0), + + // POP76 Encoding of rs Field. + JIALC = ((0U << 5) + 0), + + // COP1 Encoding of rs Field for MSA Branch Instructions + BZ_V = (((1U << 3) + 3) << kRsShift), + BNZ_V = (((1U << 3) + 7) << kRsShift), + BZ_B = (((3U << 3) + 0) << kRsShift), + BZ_H = (((3U << 3) + 1) << kRsShift), + BZ_W = (((3U << 3) + 2) << kRsShift), + BZ_D = (((3U << 3) + 3) << kRsShift), + BNZ_B = (((3U << 3) + 4) << kRsShift), + BNZ_H = (((3U << 3) + 5) << kRsShift), + BNZ_W = (((3U << 3) + 6) << kRsShift), + BNZ_D = (((3U << 3) + 7) << kRsShift), + + // MSA: Operation Field for MI10 Instruction Formats + MSA_LD = (8U << 2), + MSA_ST = (9U << 2), + LD_B = ((8U << 2) + 0), + LD_H = ((8U << 2) + 1), + LD_W = ((8U << 2) + 2), + LD_D = ((8U << 2) + 3), + ST_B = ((9U << 2) + 0), + ST_H = ((9U << 2) + 1), + ST_W = ((9U << 2) + 2), + ST_D = ((9U << 2) + 3), + + // MSA: Operation Field for I5 Instruction Format + ADDVI = ((0U << 23) + 6), + SUBVI = ((1U << 23) + 6), + MAXI_S = ((2U << 23) + 6), + MAXI_U = ((3U << 23) + 6), + MINI_S = ((4U << 23) + 6), + MINI_U = ((5U << 23) + 6), + CEQI = ((0U << 23) + 7), + CLTI_S = ((2U << 23) + 7), + CLTI_U = ((3U << 23) + 7), + CLEI_S = ((4U << 23) + 7), + CLEI_U = ((5U << 23) + 7), + LDI = ((6U << 23) + 7), // I10 instruction format + I5_DF_b = (0U << 21), + I5_DF_h = (1U << 21), + I5_DF_w = (2U << 21), + I5_DF_d = (3U << 21), + + // MSA: Operation Field for I8 Instruction Format + ANDI_B = ((0U << 24) + 0), + ORI_B = ((1U << 24) + 0), + NORI_B = ((2U << 24) + 0), + XORI_B = ((3U << 24) + 0), + BMNZI_B = ((0U << 24) + 1), + BMZI_B = ((1U << 24) + 1), + BSELI_B = ((2U << 24) + 1), + SHF_B = ((0U << 24) + 2), + SHF_H = ((1U << 24) + 2), + SHF_W = ((2U << 24) + 2), + + MSA_VEC_2R_2RF_MINOR = ((3U << 3) + 6), + + // MSA: Operation Field for VEC Instruction Formats + AND_V = (((0U << 2) + 0) << 21), + OR_V = (((0U << 2) + 1) << 21), + NOR_V = (((0U << 2) + 2) << 21), + XOR_V = (((0U << 2) + 3) << 21), + BMNZ_V = (((1U << 2) + 0) << 21), + BMZ_V = (((1U << 2) + 1) << 21), + BSEL_V = (((1U << 2) + 2) << 21), + + // MSA: Operation Field for 2R Instruction Formats + MSA_2R_FORMAT = (((6U << 2) + 0) << 21), + FILL = (0U << 18), + PCNT = (1U << 18), + NLOC = (2U << 18), + NLZC = (3U << 18), + MSA_2R_DF_b = (0U << 16), + MSA_2R_DF_h = (1U << 16), + MSA_2R_DF_w = (2U << 16), + MSA_2R_DF_d = (3U << 16), + + // MSA: Operation Field for 2RF Instruction Formats + MSA_2RF_FORMAT = (((6U << 2) + 1) << 21), + FCLASS = (0U << 17), + FTRUNC_S = (1U << 17), + FTRUNC_U = (2U << 17), + FSQRT = (3U << 17), + FRSQRT = (4U << 17), + FRCP = (5U << 17), + FRINT = (6U << 17), + FLOG2 = (7U << 17), + FEXUPL = (8U << 17), + FEXUPR = (9U << 17), + FFQL = (10U << 17), + FFQR = (11U << 17), + FTINT_S = (12U << 17), + FTINT_U = (13U << 17), + FFINT_S = (14U << 17), + FFINT_U = (15U << 17), + MSA_2RF_DF_w = (0U << 16), + MSA_2RF_DF_d = (1U << 16), + + // MSA: Operation Field for 3R Instruction Format + SLL_MSA = ((0U << 23) + 13), + SRA_MSA = ((1U << 23) + 13), + SRL_MSA = ((2U << 23) + 13), + BCLR = ((3U << 23) + 13), + BSET = ((4U << 23) + 13), + BNEG = ((5U << 23) + 13), + BINSL = ((6U << 23) + 13), + BINSR = ((7U << 23) + 13), + ADDV = ((0U << 23) + 14), + SUBV = ((1U << 23) + 14), + MAX_S = ((2U << 23) + 14), + MAX_U = ((3U << 23) + 14), + MIN_S = ((4U << 23) + 14), + MIN_U = ((5U << 23) + 14), + MAX_A = ((6U << 23) + 14), + MIN_A = ((7U << 23) + 14), + CEQ = ((0U << 23) + 15), + CLT_S = ((2U << 23) + 15), + CLT_U = ((3U << 23) + 15), + CLE_S = ((4U << 23) + 15), + CLE_U = ((5U << 23) + 15), + ADD_A = ((0U << 23) + 16), + ADDS_A = ((1U << 23) + 16), + ADDS_S = ((2U << 23) + 16), + ADDS_U = ((3U << 23) + 16), + AVE_S = ((4U << 23) + 16), + AVE_U = ((5U << 23) + 16), + AVER_S = ((6U << 23) + 16), + AVER_U = ((7U << 23) + 16), + SUBS_S = ((0U << 23) + 17), + SUBS_U = ((1U << 23) + 17), + SUBSUS_U = ((2U << 23) + 17), + SUBSUU_S = ((3U << 23) + 17), + ASUB_S = ((4U << 23) + 17), + ASUB_U = ((5U << 23) + 17), + MULV = ((0U << 23) + 18), + MADDV = ((1U << 23) + 18), + MSUBV = ((2U << 23) + 18), + DIV_S_MSA = ((4U << 23) + 18), + DIV_U = ((5U << 23) + 18), + MOD_S = ((6U << 23) + 18), + MOD_U = ((7U << 23) + 18), + DOTP_S = ((0U << 23) + 19), + DOTP_U = ((1U << 23) + 19), + DPADD_S = ((2U << 23) + 19), + DPADD_U = ((3U << 23) + 19), + DPSUB_S = ((4U << 23) + 19), + DPSUB_U = ((5U << 23) + 19), + SLD = ((0U << 23) + 20), + SPLAT = ((1U << 23) + 20), + PCKEV = ((2U << 23) + 20), + PCKOD = ((3U << 23) + 20), + ILVL = ((4U << 23) + 20), + ILVR = ((5U << 23) + 20), + ILVEV = ((6U << 23) + 20), + ILVOD = ((7U << 23) + 20), + VSHF = ((0U << 23) + 21), + SRAR = ((1U << 23) + 21), + SRLR = ((2U << 23) + 21), + HADD_S = ((4U << 23) + 21), + HADD_U = ((5U << 23) + 21), + HSUB_S = ((6U << 23) + 21), + HSUB_U = ((7U << 23) + 21), + MSA_3R_DF_b = (0U << 21), + MSA_3R_DF_h = (1U << 21), + MSA_3R_DF_w = (2U << 21), + MSA_3R_DF_d = (3U << 21), + + // MSA: Operation Field for 3RF Instruction Format + FCAF = ((0U << 22) + 26), + FCUN = ((1U << 22) + 26), + FCEQ = ((2U << 22) + 26), + FCUEQ = ((3U << 22) + 26), + FCLT = ((4U << 22) + 26), + FCULT = ((5U << 22) + 26), + FCLE = ((6U << 22) + 26), + FCULE = ((7U << 22) + 26), + FSAF = ((8U << 22) + 26), + FSUN = ((9U << 22) + 26), + FSEQ = ((10U << 22) + 26), + FSUEQ = ((11U << 22) + 26), + FSLT = ((12U << 22) + 26), + FSULT = ((13U << 22) + 26), + FSLE = ((14U << 22) + 26), + FSULE = ((15U << 22) + 26), + FADD = ((0U << 22) + 27), + FSUB = ((1U << 22) + 27), + FMUL = ((2U << 22) + 27), + FDIV = ((3U << 22) + 27), + FMADD = ((4U << 22) + 27), + FMSUB = ((5U << 22) + 27), + FEXP2 = ((7U << 22) + 27), + FEXDO = ((8U << 22) + 27), + FTQ = ((10U << 22) + 27), + FMIN = ((12U << 22) + 27), + FMIN_A = ((13U << 22) + 27), + FMAX = ((14U << 22) + 27), + FMAX_A = ((15U << 22) + 27), + FCOR = ((1U << 22) + 28), + FCUNE = ((2U << 22) + 28), + FCNE = ((3U << 22) + 28), + MUL_Q = ((4U << 22) + 28), + MADD_Q = ((5U << 22) + 28), + MSUB_Q = ((6U << 22) + 28), + FSOR = ((9U << 22) + 28), + FSUNE = ((10U << 22) + 28), + FSNE = ((11U << 22) + 28), + MULR_Q = ((12U << 22) + 28), + MADDR_Q = ((13U << 22) + 28), + MSUBR_Q = ((14U << 22) + 28), + + // MSA: Operation Field for ELM Instruction Format + MSA_ELM_MINOR = ((3U << 3) + 1), + SLDI = (0U << 22), + CTCMSA = ((0U << 22) | (62U << 16)), + SPLATI = (1U << 22), + CFCMSA = ((1U << 22) | (62U << 16)), + COPY_S = (2U << 22), + MOVE_V = ((2U << 22) | (62U << 16)), + COPY_U = (3U << 22), + INSERT = (4U << 22), + INSVE = (5U << 22), + ELM_DF_B = ((0U << 4) << 16), + ELM_DF_H = ((4U << 3) << 16), + ELM_DF_W = ((12U << 2) << 16), + ELM_DF_D = ((28U << 1) << 16), + + // MSA: Operation Field for BIT Instruction Format + SLLI = ((0U << 23) + 9), + SRAI = ((1U << 23) + 9), + SRLI = ((2U << 23) + 9), + BCLRI = ((3U << 23) + 9), + BSETI = ((4U << 23) + 9), + BNEGI = ((5U << 23) + 9), + BINSLI = ((6U << 23) + 9), + BINSRI = ((7U << 23) + 9), + SAT_S = ((0U << 23) + 10), + SAT_U = ((1U << 23) + 10), + SRARI = ((2U << 23) + 10), + SRLRI = ((3U << 23) + 10), + BIT_DF_b = ((14U << 3) << 16), + BIT_DF_h = ((6U << 4) << 16), + BIT_DF_w = ((2U << 5) << 16), + BIT_DF_d = ((0U << 6) << 16), + + nullptrSF = 0U +}; + +enum MSAMinorOpcode : uint32_t { + kMsaMinorUndefined = 0, + kMsaMinorI8, + kMsaMinorI5, + kMsaMinorI10, + kMsaMinorBIT, + kMsaMinor3R, + kMsaMinor3RF, + kMsaMinorELM, + kMsaMinorVEC, + kMsaMinor2R, + kMsaMinor2RF, + kMsaMinorMI10 +}; + +// ----- Emulated conditions. +// On MIPS we use this enum to abstract from conditional branch instructions. +// The 'U' prefix is used to specify unsigned comparisons. +// Opposite conditions must be paired as odd/even numbers +// because 'NegateCondition' function flips LSB to negate condition. +enum Condition { + // Any value < 0 is considered no_condition. + kNoCondition = -1, + overflow = 0, + no_overflow = 1, + Uless = 2, + Ugreater_equal = 3, + Uless_equal = 4, + Ugreater = 5, + equal = 6, + not_equal = 7, // Unordered or Not Equal. + negative = 8, + positive = 9, + parity_even = 10, + parity_odd = 11, + less = 12, + greater_equal = 13, + less_equal = 14, + greater = 15, + ueq = 16, // Unordered or Equal. + ogl = 17, // Ordered and Not Equal. + cc_always = 18, + + // Aliases. + carry = Uless, + not_carry = Ugreater_equal, + zero = equal, + eq = equal, + not_zero = not_equal, + ne = not_equal, + nz = not_equal, + sign = negative, + not_sign = positive, + mi = negative, + pl = positive, + hi = Ugreater, + ls = Uless_equal, + ge = greater_equal, + lt = less, + gt = greater, + le = less_equal, + hs = Ugreater_equal, + lo = Uless, + al = cc_always, + ult = Uless, + uge = Ugreater_equal, + ule = Uless_equal, + ugt = Ugreater, + cc_default = kNoCondition +}; + +// Returns the equivalent of !cc. +// Negation of the default kNoCondition (-1) results in a non-default +// no_condition value (-2). As long as tests for no_condition check +// for condition < 0, this will work as expected. +inline Condition NegateCondition(Condition cc) { + DCHECK(cc != cc_always); + return static_cast<Condition>(cc ^ 1); +} + +inline Condition NegateFpuCondition(Condition cc) { + DCHECK(cc != cc_always); + switch (cc) { + case ult: + return ge; + case ugt: + return le; + case uge: + return lt; + case ule: + return gt; + case lt: + return uge; + case gt: + return ule; + case ge: + return ult; + case le: + return ugt; + case eq: + return ne; + case ne: + return eq; + case ueq: + return ogl; + case ogl: + return ueq; + default: + return cc; + } +} + +enum MSABranchCondition { + all_not_zero = 0, // Branch If All Elements Are Not Zero + one_elem_not_zero, // Branch If At Least One Element of Any Format Is Not + // Zero + one_elem_zero, // Branch If At Least One Element Is Zero + all_zero // Branch If All Elements of Any Format Are Zero +}; + +inline MSABranchCondition NegateMSABranchCondition(MSABranchCondition cond) { + switch (cond) { + case all_not_zero: + return one_elem_zero; + case one_elem_not_zero: + return all_zero; + case one_elem_zero: + return all_not_zero; + case all_zero: + return one_elem_not_zero; + default: + return cond; + } +} + +enum MSABranchDF { + MSA_BRANCH_B = 0, + MSA_BRANCH_H, + MSA_BRANCH_W, + MSA_BRANCH_D, + MSA_BRANCH_V +}; + +// ----- Coprocessor conditions. +enum FPUCondition { + kNoFPUCondition = -1, + + F = 0x00, // False. + UN = 0x01, // Unordered. + EQ = 0x02, // Equal. + UEQ = 0x03, // Unordered or Equal. + OLT = 0x04, // Ordered or Less Than, on Mips release < 6. + LT = 0x04, // Ordered or Less Than, on Mips release >= 6. + ULT = 0x05, // Unordered or Less Than. + OLE = 0x06, // Ordered or Less Than or Equal, on Mips release < 6. + LE = 0x06, // Ordered or Less Than or Equal, on Mips release >= 6. + ULE = 0x07, // Unordered or Less Than or Equal. + + // Following constants are available on Mips release >= 6 only. + ORD = 0x11, // Ordered, on Mips release >= 6. + UNE = 0x12, // Not equal, on Mips release >= 6. + NE = 0x13, // Ordered Greater Than or Less Than. on Mips >= 6 only. +}; + +// FPU rounding modes. +enum FPURoundingMode { + RN = 0 << 0, // Round to Nearest. + RZ = 1 << 0, // Round towards zero. + RP = 2 << 0, // Round towards Plus Infinity. + RM = 3 << 0, // Round towards Minus Infinity. + + // Aliases. + kRoundToNearest = RN, + kRoundToZero = RZ, + kRoundToPlusInf = RP, + kRoundToMinusInf = RM, + + mode_round = RN, + mode_ceil = RP, + mode_floor = RM, + mode_trunc = RZ +}; + +const uint32_t kFPURoundingModeMask = 3 << 0; + +enum CheckForInexactConversion { + kCheckForInexactConversion, + kDontCheckForInexactConversion +}; + +enum class MaxMinKind : int { kMin = 0, kMax = 1 }; + +// ----------------------------------------------------------------------------- +// Hints. + +// Branch hints are not used on the MIPS. They are defined so that they can +// appear in shared function signatures, but will be ignored in MIPS +// implementations. +enum Hint { no_hint = 0 }; + +inline Hint NegateHint(Hint hint) { return no_hint; } + +// ----------------------------------------------------------------------------- +// Specific instructions, constants, and masks. +// These constants are declared in assembler-mips.cc, as they use named +// registers and other constants. + +// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r) +// operations as post-increment of sp. +extern const Instr kPopInstruction; +// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp. +extern const Instr kPushInstruction; +// sw(r, MemOperand(sp, 0)) +extern const Instr kPushRegPattern; +// lw(r, MemOperand(sp, 0)) +extern const Instr kPopRegPattern; +extern const Instr kLwRegFpOffsetPattern; +extern const Instr kSwRegFpOffsetPattern; +extern const Instr kLwRegFpNegOffsetPattern; +extern const Instr kSwRegFpNegOffsetPattern; +// A mask for the Rt register for push, pop, lw, sw instructions. +extern const Instr kRtMask; +extern const Instr kLwSwInstrTypeMask; +extern const Instr kLwSwInstrArgumentMask; +extern const Instr kLwSwOffsetMask; + +// Break 0xfffff, reserved for redirected real time call. +const Instr rtCallRedirInstr = SPECIAL | BREAK | call_rt_redirected << 6; +// A nop instruction. (Encoding of sll 0 0 0). +const Instr nopInstr = 0; + +static constexpr uint64_t OpcodeToBitNumber(Opcode opcode) { + return 1ULL << (static_cast<uint32_t>(opcode) >> kOpcodeShift); +} + +constexpr uint8_t kInstrSize = 4; +constexpr uint8_t kInstrSizeLog2 = 2; + +class InstructionBase { + public: + enum { + // On MIPS PC cannot actually be directly accessed. We behave as if PC was + // always the value of the current instruction being executed. + kPCReadOffset = 0 + }; + + // Instruction type. + enum Type { kRegisterType, kImmediateType, kJumpType, kUnsupported = -1 }; + + // Get the raw instruction bits. + inline Instr InstructionBits() const { + return *reinterpret_cast<const Instr*>(this); + } + + // Set the raw instruction bits to value. + inline void SetInstructionBits(Instr value) { + *reinterpret_cast<Instr*>(this) = value; + } + + // Read one particular bit out of the instruction bits. + inline int Bit(int nr) const { return (InstructionBits() >> nr) & 1; } + + // Read a bit field out of the instruction bits. + inline int Bits(int hi, int lo) const { + return (InstructionBits() >> lo) & ((2U << (hi - lo)) - 1); + } + + static constexpr uint64_t kOpcodeImmediateTypeMask = + OpcodeToBitNumber(REGIMM) | OpcodeToBitNumber(BEQ) | + OpcodeToBitNumber(BNE) | OpcodeToBitNumber(BLEZ) | + OpcodeToBitNumber(BGTZ) | OpcodeToBitNumber(ADDI) | + OpcodeToBitNumber(DADDI) | OpcodeToBitNumber(ADDIU) | + OpcodeToBitNumber(SLTI) | OpcodeToBitNumber(SLTIU) | + OpcodeToBitNumber(ANDI) | OpcodeToBitNumber(ORI) | + OpcodeToBitNumber(XORI) | OpcodeToBitNumber(LUI) | + OpcodeToBitNumber(BEQL) | OpcodeToBitNumber(BNEL) | + OpcodeToBitNumber(BLEZL) | OpcodeToBitNumber(BGTZL) | + OpcodeToBitNumber(POP66) | OpcodeToBitNumber(POP76) | + OpcodeToBitNumber(LB) | OpcodeToBitNumber(LH) | OpcodeToBitNumber(LWL) | + OpcodeToBitNumber(LW) | OpcodeToBitNumber(LBU) | OpcodeToBitNumber(LHU) | + OpcodeToBitNumber(LWR) | OpcodeToBitNumber(SB) | OpcodeToBitNumber(SH) | + OpcodeToBitNumber(SWL) | OpcodeToBitNumber(SW) | OpcodeToBitNumber(SWR) | + OpcodeToBitNumber(LWC1) | OpcodeToBitNumber(LDC1) | + OpcodeToBitNumber(SWC1) | OpcodeToBitNumber(SDC1) | + OpcodeToBitNumber(PCREL) | OpcodeToBitNumber(BC) | + OpcodeToBitNumber(BALC); + +#define FunctionFieldToBitNumber(function) (1ULL << function) + + static const uint64_t kFunctionFieldRegisterTypeMask = + FunctionFieldToBitNumber(JR) | FunctionFieldToBitNumber(JALR) | + FunctionFieldToBitNumber(BREAK) | FunctionFieldToBitNumber(SLL) | + FunctionFieldToBitNumber(SRL) | FunctionFieldToBitNumber(SRA) | + FunctionFieldToBitNumber(SLLV) | FunctionFieldToBitNumber(SRLV) | + FunctionFieldToBitNumber(SRAV) | FunctionFieldToBitNumber(LSA) | + FunctionFieldToBitNumber(MFHI) | FunctionFieldToBitNumber(MFLO) | + FunctionFieldToBitNumber(MULT) | FunctionFieldToBitNumber(MULTU) | + FunctionFieldToBitNumber(DIV) | FunctionFieldToBitNumber(DIVU) | + FunctionFieldToBitNumber(ADD) | FunctionFieldToBitNumber(ADDU) | + FunctionFieldToBitNumber(SUB) | FunctionFieldToBitNumber(SUBU) | + FunctionFieldToBitNumber(AND) | FunctionFieldToBitNumber(OR) | + FunctionFieldToBitNumber(XOR) | FunctionFieldToBitNumber(NOR) | + FunctionFieldToBitNumber(SLT) | FunctionFieldToBitNumber(SLTU) | + FunctionFieldToBitNumber(TGE) | FunctionFieldToBitNumber(TGEU) | + FunctionFieldToBitNumber(TLT) | FunctionFieldToBitNumber(TLTU) | + FunctionFieldToBitNumber(TEQ) | FunctionFieldToBitNumber(TNE) | + FunctionFieldToBitNumber(MOVZ) | FunctionFieldToBitNumber(MOVN) | + FunctionFieldToBitNumber(MOVCI) | FunctionFieldToBitNumber(SELEQZ_S) | + FunctionFieldToBitNumber(SELNEZ_S) | FunctionFieldToBitNumber(SYNC); + + // Accessors for the different named fields used in the MIPS encoding. + inline Opcode OpcodeValue() const { + return static_cast<Opcode>( + Bits(kOpcodeShift + kOpcodeBits - 1, kOpcodeShift)); + } + + inline int FunctionFieldRaw() const { + return InstructionBits() & kFunctionFieldMask; + } + + // Return the fields at their original place in the instruction encoding. + inline Opcode OpcodeFieldRaw() const { + return static_cast<Opcode>(InstructionBits() & kOpcodeMask); + } + + // Safe to call within InstructionType(). + inline int RsFieldRawNoAssert() const { + return InstructionBits() & kRsFieldMask; + } + + inline int SaFieldRaw() const { return InstructionBits() & kSaFieldMask; } + + // Get the encoding type of the instruction. + inline Type InstructionType() const; + + inline MSAMinorOpcode MSAMinorOpcodeField() const { + int op = this->FunctionFieldRaw(); + switch (op) { + case 0: + case 1: + case 2: + return kMsaMinorI8; + case 6: + return kMsaMinorI5; + case 7: + return (((this->InstructionBits() & kMsaI5I10Mask) == LDI) + ? kMsaMinorI10 + : kMsaMinorI5); + case 9: + case 10: + return kMsaMinorBIT; + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + return kMsaMinor3R; + case 25: + return kMsaMinorELM; + case 26: + case 27: + case 28: + return kMsaMinor3RF; + case 30: + switch (this->RsFieldRawNoAssert()) { + case MSA_2R_FORMAT: + return kMsaMinor2R; + case MSA_2RF_FORMAT: + return kMsaMinor2RF; + default: + return kMsaMinorVEC; + } + break; + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + return kMsaMinorMI10; + default: + return kMsaMinorUndefined; + } + } + + protected: + InstructionBase() {} +}; + +template <class T> +class InstructionGetters : public T { + public: + inline int RsValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return InstructionBase::Bits(kRsShift + kRsBits - 1, kRsShift); + } + + inline int RtValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(kRtShift + kRtBits - 1, kRtShift); + } + + inline int RdValue() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kRegisterType); + return this->Bits(kRdShift + kRdBits - 1, kRdShift); + } + + inline int BaseValue() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kBaseShift + kBaseBits - 1, kBaseShift); + } + + inline int SaValue() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kRegisterType); + return this->Bits(kSaShift + kSaBits - 1, kSaShift); + } + + inline int LsaSaValue() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kRegisterType); + return this->Bits(kSaShift + kLsaSaBits - 1, kSaShift); + } + + inline int FunctionValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift); + } + + inline int FdValue() const { + return this->Bits(kFdShift + kFdBits - 1, kFdShift); + } + + inline int FsValue() const { + return this->Bits(kFsShift + kFsBits - 1, kFsShift); + } + + inline int FtValue() const { + return this->Bits(kFtShift + kFtBits - 1, kFtShift); + } + + inline int FrValue() const { + return this->Bits(kFrShift + kFrBits - 1, kFrShift); + } + + inline int WdValue() const { + return this->Bits(kWdShift + kWdBits - 1, kWdShift); + } + + inline int WsValue() const { + return this->Bits(kWsShift + kWsBits - 1, kWsShift); + } + + inline int WtValue() const { + return this->Bits(kWtShift + kWtBits - 1, kWtShift); + } + + inline int Bp2Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kRegisterType); + return this->Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift); + } + + // Float Compare condition code instruction bits. + inline int FCccValue() const { + return this->Bits(kFCccShift + kFCccBits - 1, kFCccShift); + } + + // Float Branch condition code instruction bits. + inline int FBccValue() const { + return this->Bits(kFBccShift + kFBccBits - 1, kFBccShift); + } + + // Float Branch true/false instruction bit. + inline int FBtrueValue() const { + return this->Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift); + } + + // Return the fields at their original place in the instruction encoding. + inline Opcode OpcodeFieldRaw() const { + return static_cast<Opcode>(this->InstructionBits() & kOpcodeMask); + } + + inline int RsFieldRaw() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->InstructionBits() & kRsFieldMask; + } + + inline int RtFieldRaw() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->InstructionBits() & kRtFieldMask; + } + + inline int RdFieldRaw() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kRegisterType); + return this->InstructionBits() & kRdFieldMask; + } + + inline int SaFieldRaw() const { + return this->InstructionBits() & kSaFieldMask; + } + + inline int FunctionFieldRaw() const { + return this->InstructionBits() & kFunctionFieldMask; + } + + // Get the secondary field according to the opcode. + inline int SecondaryValue() const { + Opcode op = this->OpcodeFieldRaw(); + switch (op) { + case SPECIAL: + case SPECIAL2: + return FunctionValue(); + case COP1: + return RsValue(); + case REGIMM: + return RtValue(); + default: + return nullptrSF; + } + } + + inline int32_t ImmValue(int bits) const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(bits - 1, 0); + } + + inline int32_t Imm9Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kImm9Shift + kImm9Bits - 1, kImm9Shift); + } + + inline int32_t Imm16Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift); + } + + inline int32_t Imm18Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift); + } + + inline int32_t Imm19Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift); + } + + inline int32_t Imm21Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift); + } + + inline int32_t Imm26Value() const { + DCHECK((this->InstructionType() == InstructionBase::kJumpType) || + (this->InstructionType() == InstructionBase::kImmediateType)); + return this->Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift); + } + + inline int32_t MsaImm8Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kMsaImm8Shift + kMsaImm8Bits - 1, kMsaImm8Shift); + } + + inline int32_t MsaImm5Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kMsaImm5Shift + kMsaImm5Bits - 1, kMsaImm5Shift); + } + + inline int32_t MsaImm10Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kMsaImm10Shift + kMsaImm10Bits - 1, kMsaImm10Shift); + } + + inline int32_t MsaImmMI10Value() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(kMsaImmMI10Shift + kMsaImmMI10Bits - 1, kMsaImmMI10Shift); + } + + inline int32_t MsaBitDf() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + int32_t df_m = this->Bits(22, 16); + if (((df_m >> 6) & 1U) == 0) { + return 3; + } else if (((df_m >> 5) & 3U) == 2) { + return 2; + } else if (((df_m >> 4) & 7U) == 6) { + return 1; + } else if (((df_m >> 3) & 15U) == 14) { + return 0; + } else { + return -1; + } + } + + inline int32_t MsaBitMValue() const { + DCHECK_EQ(this->InstructionType(), InstructionBase::kImmediateType); + return this->Bits(16 + this->MsaBitDf() + 3, 16); + } + + inline int32_t MsaElmDf() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + int32_t df_n = this->Bits(21, 16); + if (((df_n >> 4) & 3U) == 0) { + return 0; + } else if (((df_n >> 3) & 7U) == 4) { + return 1; + } else if (((df_n >> 2) & 15U) == 12) { + return 2; + } else if (((df_n >> 1) & 31U) == 28) { + return 3; + } else { + return -1; + } + } + + inline int32_t MsaElmNValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(16 + 4 - this->MsaElmDf(), 16); + } + + static bool IsForbiddenAfterBranchInstr(Instr instr); + + // Say if the instruction should not be used in a branch delay slot or + // immediately after a compact branch. + inline bool IsForbiddenAfterBranch() const { + return IsForbiddenAfterBranchInstr(this->InstructionBits()); + } + + inline bool IsForbiddenInBranchDelay() const { + return IsForbiddenAfterBranch(); + } + + // Say if the instruction 'links'. e.g. jal, bal. + bool IsLinkingInstruction() const; + // Say if the instruction is a break or a trap. + bool IsTrap() const; + + inline bool IsMSABranchInstr() const { + if (this->OpcodeFieldRaw() == COP1) { + switch (this->RsFieldRaw()) { + case BZ_V: + case BZ_B: + case BZ_H: + case BZ_W: + case BZ_D: + case BNZ_V: + case BNZ_B: + case BNZ_H: + case BNZ_W: + case BNZ_D: + return true; + default: + return false; + } + } + return false; + } + + inline bool IsMSAInstr() const { + if (this->IsMSABranchInstr() || (this->OpcodeFieldRaw() == MSA)) + return true; + return false; + } +}; + +class Instruction : public InstructionGetters<InstructionBase> { + public: + // Instructions are read of out 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 Instruction. + // Use the At(pc) function to create references to Instruction. + static Instruction* At(byte* pc) { + return reinterpret_cast<Instruction*>(pc); + } + + private: + // We need to prevent the creation of instances of class Instruction. + DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction); +}; + +// ----------------------------------------------------------------------------- +// MIPS assembly various constants. + +// C/C++ argument slots size. +const int kCArgSlotCount = 4; +const int kCArgsSlotsSize = kCArgSlotCount * kInstrSize; + +// JS argument slots size. +const int kJSArgsSlotsSize = 0 * kInstrSize; + +// Assembly builtins argument slots size. +const int kBArgsSlotsSize = 0 * kInstrSize; + +const int kBranchReturnOffset = 2 * kInstrSize; + +InstructionBase::Type InstructionBase::InstructionType() const { + switch (OpcodeFieldRaw()) { + case SPECIAL: + if (FunctionFieldToBitNumber(FunctionFieldRaw()) & + kFunctionFieldRegisterTypeMask) { + return kRegisterType; + } + return kUnsupported; + case SPECIAL2: + switch (FunctionFieldRaw()) { + case MUL: + case CLZ: + return kRegisterType; + default: + return kUnsupported; + } + break; + case SPECIAL3: + switch (FunctionFieldRaw()) { + case INS: + case EXT: + return kRegisterType; + case BSHFL: { + int sa = SaFieldRaw() >> kSaShift; + switch (sa) { + case BITSWAP: + case WSBH: + case SEB: + case SEH: + return kRegisterType; + } + sa >>= kBp2Bits; + switch (sa) { + case ALIGN: + return kRegisterType; + default: + return kUnsupported; + } + } + case LL_R6: + case SC_R6: { + DCHECK(IsMipsArchVariant(kMips32r6)); + return kImmediateType; + } + default: + return kUnsupported; + } + break; + case COP1: // Coprocessor instructions. + switch (RsFieldRawNoAssert()) { + case BC1: // Branch on coprocessor condition. + case BC1EQZ: + case BC1NEZ: + return kImmediateType; + // MSA Branch instructions + case BZ_V: + case BNZ_V: + case BZ_B: + case BZ_H: + case BZ_W: + case BZ_D: + case BNZ_B: + case BNZ_H: + case BNZ_W: + case BNZ_D: + return kImmediateType; + default: + return kRegisterType; + } + break; + case COP1X: + return kRegisterType; + + // 26 bits immediate type instructions. e.g.: j imm26. + case J: + case JAL: + return kJumpType; + + case MSA: + switch (MSAMinorOpcodeField()) { + case kMsaMinor3R: + case kMsaMinor3RF: + case kMsaMinorVEC: + case kMsaMinor2R: + case kMsaMinor2RF: + return kRegisterType; + case kMsaMinorELM: + switch (InstructionBits() & kMsaLongerELMMask) { + case CFCMSA: + case CTCMSA: + case MOVE_V: + return kRegisterType; + default: + return kImmediateType; + } + default: + return kImmediateType; + } + + default: + return kImmediateType; + } +} + +#undef OpcodeToBitNumber +#undef FunctionFieldToBitNumber + +// ----------------------------------------------------------------------------- +// Instructions. + +template <class P> +bool InstructionGetters<P>::IsLinkingInstruction() const { + uint32_t op = this->OpcodeFieldRaw(); + switch (op) { + case JAL: + return true; + case POP76: + if (this->RsFieldRawNoAssert() == JIALC) + return true; // JIALC + else + return false; // BNEZC + case REGIMM: + switch (this->RtFieldRaw()) { + case BGEZAL: + case BLTZAL: + return true; + default: + return false; + } + case SPECIAL: + switch (this->FunctionFieldRaw()) { + case JALR: + return true; + default: + return false; + } + default: + return false; + } +} + +template <class P> +bool InstructionGetters<P>::IsTrap() const { + if (this->OpcodeFieldRaw() != SPECIAL) { + return false; + } else { + switch (this->FunctionFieldRaw()) { + case BREAK: + case TGE: + case TGEU: + case TLT: + case TLTU: + case TEQ: + case TNE: + return true; + default: + return false; + } + } +} + +// static +template <class T> +bool InstructionGetters<T>::IsForbiddenAfterBranchInstr(Instr instr) { + Opcode opcode = static_cast<Opcode>(instr & kOpcodeMask); + switch (opcode) { + case J: + case JAL: + case BEQ: + case BNE: + case BLEZ: // POP06 bgeuc/bleuc, blezalc, bgezalc + case BGTZ: // POP07 bltuc/bgtuc, bgtzalc, bltzalc + case BEQL: + case BNEL: + case BLEZL: // POP26 bgezc, blezc, bgec/blec + case BGTZL: // POP27 bgtzc, bltzc, bltc/bgtc + case BC: + case BALC: + case POP10: // beqzalc, bovc, beqc + case POP30: // bnezalc, bnvc, bnec + case POP66: // beqzc, jic + case POP76: // bnezc, jialc + return true; + case REGIMM: + switch (instr & kRtFieldMask) { + case BLTZ: + case BGEZ: + case BLTZAL: + case BGEZAL: + return true; + default: + return false; + } + break; + case SPECIAL: + switch (instr & kFunctionFieldMask) { + case JR: + case JALR: + return true; + default: + return false; + } + break; + case COP1: + switch (instr & kRsFieldMask) { + case BC1: + case BC1EQZ: + case BC1NEZ: + case BZ_V: + case BZ_B: + case BZ_H: + case BZ_W: + case BZ_D: + case BNZ_V: + case BNZ_B: + case BNZ_H: + case BNZ_W: + case BNZ_D: + return true; + break; + default: + return false; + } + break; + default: + return false; + } +} +} // namespace internal +} // namespace v8 + +#endif // V8_CODEGEN_MIPS_CONSTANTS_MIPS_H_ |