| // Copyright 2021 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_LOONG64_CONSTANTS_LOONG64_H_ |
| #define V8_CODEGEN_LOONG64_CONSTANTS_LOONG64_H_ |
| |
| #include "src/base/logging.h" |
| #include "src/base/macros.h" |
| #include "src/common/globals.h" |
| |
| // Get the standard printf format macros for C99 stdint types. |
| #ifndef __STDC_FORMAT_MACROS |
| #define __STDC_FORMAT_MACROS |
| #endif |
| #include <inttypes.h> |
| |
| // Defines constants and accessor classes to assemble, disassemble and |
| // simulate LOONG64 instructions. |
| |
| namespace v8 { |
| namespace internal { |
| |
| constexpr size_t kMaxPCRelativeCodeRangeInMB = 128; |
| |
| // ----------------------------------------------------------------------------- |
| // Registers and FPURegisters. |
| |
| // Number of general purpose registers. |
| const int kNumRegisters = 32; |
| const int kInvalidRegister = -1; |
| |
| // Number of registers with pc. |
| const int kNumSimuRegisters = 33; |
| |
| // In the simulator, the PC register is simulated as the 33th register. |
| const int kPCRegister = 32; |
| |
| // Number of floating point registers. |
| const int kNumFPURegisters = 32; |
| const int kInvalidFPURegister = -1; |
| |
| // FPU control registers. |
| const int kFCSRRegister = 0; |
| 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 kFCSRInexactCauseBit = 24; |
| const uint32_t kFCSRUnderflowCauseBit = 25; |
| const uint32_t kFCSROverflowCauseBit = 26; |
| const uint32_t kFCSRDivideByZeroCauseBit = 27; |
| const uint32_t kFCSRInvalidOpCauseBit = 28; |
| |
| const uint32_t kFCSRInexactCauseMask = 1 << kFCSRInexactCauseBit; |
| const uint32_t kFCSRUnderflowCauseMask = 1 << kFCSRUnderflowCauseBit; |
| const uint32_t kFCSROverflowCauseMask = 1 << kFCSROverflowCauseBit; |
| const uint32_t kFCSRDivideByZeroCauseMask = 1 << kFCSRDivideByZeroCauseBit; |
| const uint32_t kFCSRInvalidOpCauseMask = 1 << kFCSRInvalidOpCauseBit; |
| |
| const uint32_t kFCSRCauseMask = |
| kFCSRInexactCauseMask | kFCSRUnderflowCauseMask | kFCSROverflowCauseMask | |
| kFCSRDivideByZeroCauseMask | kFCSRInvalidOpCauseMask; |
| |
| const uint32_t kFCSRExceptionCauseMask = kFCSRCauseMask ^ kFCSRInexactCauseMask; |
| |
| // 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 int64_t kMaxValue = 0x7fffffffffffffffl; |
| static const int64_t kMinValue = 0x8000000000000000l; |
| |
| 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_[]; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // Instructions encoding constants. |
| |
| // On LoongArch all instructions are 32 bits. |
| using Instr = int32_t; |
| |
| // Special Software Interrupt codes when used in the presence of the LOONG64 |
| // simulator. |
| enum SoftwareInterruptCodes { |
| // Transition to C code. |
| call_rt_redirected = 0x7fff |
| }; |
| |
| // On LOONG64 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 kRjShift = 5; |
| const int kRjBits = 5; |
| const int kRkShift = 10; |
| const int kRkBits = 5; |
| const int kRdShift = 0; |
| const int kRdBits = 5; |
| const int kSaShift = 15; |
| const int kSa2Bits = 2; |
| const int kSa3Bits = 3; |
| const int kCdShift = 0; |
| const int kCdBits = 3; |
| const int kCjShift = 5; |
| const int kCjBits = 3; |
| const int kCodeShift = 0; |
| const int kCodeBits = 15; |
| const int kCondShift = 15; |
| const int kCondBits = 5; |
| const int kUi5Shift = 10; |
| const int kUi5Bits = 5; |
| const int kUi6Shift = 10; |
| const int kUi6Bits = 6; |
| const int kUi12Shift = 10; |
| const int kUi12Bits = 12; |
| const int kSi12Shift = 10; |
| const int kSi12Bits = 12; |
| const int kSi14Shift = 10; |
| const int kSi14Bits = 14; |
| const int kSi16Shift = 10; |
| const int kSi16Bits = 16; |
| const int kSi20Shift = 5; |
| const int kSi20Bits = 20; |
| const int kMsbwShift = 16; |
| const int kMsbwBits = 5; |
| const int kLsbwShift = 10; |
| const int kLsbwBits = 5; |
| const int kMsbdShift = 16; |
| const int kMsbdBits = 6; |
| const int kLsbdShift = 10; |
| const int kLsbdBits = 6; |
| const int kFdShift = 0; |
| const int kFdBits = 5; |
| const int kFjShift = 5; |
| const int kFjBits = 5; |
| const int kFkShift = 10; |
| const int kFkBits = 5; |
| const int kFaShift = 15; |
| const int kFaBits = 5; |
| const int kCaShift = 15; |
| const int kCaBits = 3; |
| const int kHint15Shift = 0; |
| const int kHint15Bits = 15; |
| const int kHint5Shift = 0; |
| const int kHint5Bits = 5; |
| const int kOffsLowShift = 10; |
| const int kOffsLowBits = 16; |
| const int kOffs26HighShift = 0; |
| const int kOffs26HighBits = 10; |
| const int kOffs21HighShift = 0; |
| const int kOffs21HighBits = 5; |
| const int kImm12Shift = 0; |
| const int kImm12Bits = 12; |
| const int kImm16Shift = 0; |
| const int kImm16Bits = 16; |
| const int kImm26Shift = 0; |
| const int kImm26Bits = 26; |
| const int kImm28Shift = 0; |
| const int kImm28Bits = 28; |
| const int kImm32Shift = 0; |
| const int kImm32Bits = 32; |
| |
| // ----- Miscellaneous useful masks. |
| // Instruction bit masks. |
| const int kRjFieldMask = ((1 << kRjBits) - 1) << kRjShift; |
| const int kRkFieldMask = ((1 << kRkBits) - 1) << kRkShift; |
| const int kRdFieldMask = ((1 << kRdBits) - 1) << kRdShift; |
| const int kSa2FieldMask = ((1 << kSa2Bits) - 1) << kSaShift; |
| const int kSa3FieldMask = ((1 << kSa3Bits) - 1) << kSaShift; |
| // Misc masks. |
| const int kHiMaskOf32 = 0xffff << 16; // Only to be used with 32-bit values |
| const int kLoMaskOf32 = 0xffff; |
| const int kSignMaskOf32 = 0x80000000; // Only to be used with 32-bit values |
| const int64_t kTop16MaskOf64 = (int64_t)0xffff << 48; |
| const int64_t kHigher16MaskOf64 = (int64_t)0xffff << 32; |
| const int64_t kUpper16MaskOf64 = (int64_t)0xffff << 16; |
| |
| const int kImm12Mask = ((1 << kImm12Bits) - 1) << kImm12Shift; |
| const int kImm16Mask = ((1 << kImm16Bits) - 1) << kImm16Shift; |
| const int kImm26Mask = ((1 << kImm26Bits) - 1) << kImm26Shift; |
| const int kImm28Mask = ((1 << kImm28Bits) - 1) << kImm28Shift; |
| |
| // ----- LOONG64 Opcodes and Function Fields. |
| enum Opcode : uint32_t { |
| BEQZ = 0x10U << 26, |
| BNEZ = 0x11U << 26, |
| BCZ = 0x12U << 26, // BCEQZ & BCNEZ |
| JIRL = 0x13U << 26, |
| B = 0x14U << 26, |
| BL = 0x15U << 26, |
| BEQ = 0x16U << 26, |
| BNE = 0x17U << 26, |
| BLT = 0x18U << 26, |
| BGE = 0x19U << 26, |
| BLTU = 0x1aU << 26, |
| BGEU = 0x1bU << 26, |
| |
| ADDU16I_D = 0x4U << 26, |
| |
| LU12I_W = 0xaU << 25, |
| LU32I_D = 0xbU << 25, |
| PCADDI = 0xcU << 25, |
| PCALAU12I = 0xdU << 25, |
| PCADDU12I = 0xeU << 25, |
| PCADDU18I = 0xfU << 25, |
| |
| LL_W = 0x20U << 24, |
| SC_W = 0x21U << 24, |
| LL_D = 0x22U << 24, |
| SC_D = 0x23U << 24, |
| LDPTR_W = 0x24U << 24, |
| STPTR_W = 0x25U << 24, |
| LDPTR_D = 0x26U << 24, |
| STPTR_D = 0x27U << 24, |
| |
| BSTR_W = 0x1U << 22, // BSTRINS_W & BSTRPICK_W |
| BSTRINS_W = BSTR_W, |
| BSTRPICK_W = BSTR_W, |
| BSTRINS_D = 0x2U << 22, |
| BSTRPICK_D = 0x3U << 22, |
| |
| SLTI = 0x8U << 22, |
| SLTUI = 0x9U << 22, |
| ADDI_W = 0xaU << 22, |
| ADDI_D = 0xbU << 22, |
| LU52I_D = 0xcU << 22, |
| ANDI = 0xdU << 22, |
| ORI = 0xeU << 22, |
| XORI = 0xfU << 22, |
| |
| LD_B = 0xa0U << 22, |
| LD_H = 0xa1U << 22, |
| LD_W = 0xa2U << 22, |
| LD_D = 0xa3U << 22, |
| ST_B = 0xa4U << 22, |
| ST_H = 0xa5U << 22, |
| ST_W = 0xa6U << 22, |
| ST_D = 0xa7U << 22, |
| LD_BU = 0xa8U << 22, |
| LD_HU = 0xa9U << 22, |
| LD_WU = 0xaaU << 22, |
| FLD_S = 0xacU << 22, |
| FST_S = 0xadU << 22, |
| FLD_D = 0xaeU << 22, |
| FST_D = 0xafU << 22, |
| |
| FMADD_S = 0x81U << 20, |
| FMADD_D = 0x82U << 20, |
| FMSUB_S = 0x85U << 20, |
| FMSUB_D = 0x86U << 20, |
| FNMADD_S = 0x89U << 20, |
| FNMADD_D = 0x8aU << 20, |
| FNMSUB_S = 0x8dU << 20, |
| FNMSUB_D = 0x8eU << 20, |
| FCMP_COND_S = 0xc1U << 20, |
| FCMP_COND_D = 0xc2U << 20, |
| |
| BYTEPICK_D = 0x3U << 18, |
| BYTEPICK_W = 0x2U << 18, |
| |
| FSEL = 0x340U << 18, |
| |
| ALSL = 0x1U << 18, |
| ALSL_W = ALSL, |
| ALSL_WU = ALSL, |
| |
| ALSL_D = 0xbU << 18, |
| |
| SLLI_W = 0x40U << 16, |
| SRLI_W = 0x44U << 16, |
| SRAI_W = 0x48U << 16, |
| ROTRI_W = 0x4cU << 16, |
| |
| SLLI_D = 0x41U << 16, |
| SRLI_D = 0x45U << 16, |
| SRAI_D = 0x49U << 16, |
| ROTRI_D = 0x4dU << 16, |
| |
| SLLI = 0x10U << 18, |
| SRLI = 0x11U << 18, |
| SRAI = 0x12U << 18, |
| ROTRI = 0x13U << 18, |
| |
| ADD_W = 0x20U << 15, |
| ADD_D = 0x21U << 15, |
| SUB_W = 0x22U << 15, |
| SUB_D = 0x23U << 15, |
| SLT = 0x24U << 15, |
| SLTU = 0x25U << 15, |
| MASKEQZ = 0x26U << 15, |
| MASKNEZ = 0x27U << 15, |
| NOR = 0x28U << 15, |
| AND = 0x29U << 15, |
| OR = 0x2aU << 15, |
| XOR = 0x2bU << 15, |
| ORN = 0x2cU << 15, |
| ANDN = 0x2dU << 15, |
| SLL_W = 0x2eU << 15, |
| SRL_W = 0x2fU << 15, |
| SRA_W = 0x30U << 15, |
| SLL_D = 0x31U << 15, |
| SRL_D = 0x32U << 15, |
| SRA_D = 0x33U << 15, |
| ROTR_W = 0x36U << 15, |
| ROTR_D = 0x37U << 15, |
| MUL_W = 0x38U << 15, |
| MULH_W = 0x39U << 15, |
| MULH_WU = 0x3aU << 15, |
| MUL_D = 0x3bU << 15, |
| MULH_D = 0x3cU << 15, |
| MULH_DU = 0x3dU << 15, |
| MULW_D_W = 0x3eU << 15, |
| MULW_D_WU = 0x3fU << 15, |
| |
| DIV_W = 0x40U << 15, |
| MOD_W = 0x41U << 15, |
| DIV_WU = 0x42U << 15, |
| MOD_WU = 0x43U << 15, |
| DIV_D = 0x44U << 15, |
| MOD_D = 0x45U << 15, |
| DIV_DU = 0x46U << 15, |
| MOD_DU = 0x47U << 15, |
| |
| BREAK = 0x54U << 15, |
| |
| FADD_S = 0x201U << 15, |
| FADD_D = 0x202U << 15, |
| FSUB_S = 0x205U << 15, |
| FSUB_D = 0x206U << 15, |
| FMUL_S = 0x209U << 15, |
| FMUL_D = 0x20aU << 15, |
| FDIV_S = 0x20dU << 15, |
| FDIV_D = 0x20eU << 15, |
| FMAX_S = 0x211U << 15, |
| FMAX_D = 0x212U << 15, |
| FMIN_S = 0x215U << 15, |
| FMIN_D = 0x216U << 15, |
| FMAXA_S = 0x219U << 15, |
| FMAXA_D = 0x21aU << 15, |
| FMINA_S = 0x21dU << 15, |
| FMINA_D = 0x21eU << 15, |
| FSCALEB_S = 0x221U << 15, |
| FSCALEB_D = 0x222U << 15, |
| FCOPYSIGN_S = 0x225U << 15, |
| FCOPYSIGN_D = 0x226U << 15, |
| |
| LDX_B = 0x7000U << 15, |
| LDX_H = 0x7008U << 15, |
| LDX_W = 0x7010U << 15, |
| LDX_D = 0x7018U << 15, |
| STX_B = 0x7020U << 15, |
| STX_H = 0x7028U << 15, |
| STX_W = 0x7030U << 15, |
| STX_D = 0x7038U << 15, |
| LDX_BU = 0x7040U << 15, |
| LDX_HU = 0x7048U << 15, |
| LDX_WU = 0x7050U << 15, |
| FLDX_S = 0x7060U << 15, |
| FLDX_D = 0x7068U << 15, |
| FSTX_S = 0x7070U << 15, |
| FSTX_D = 0x7078U << 15, |
| |
| AMSWAP_W = 0x70c0U << 15, |
| AMSWAP_D = 0x70c1U << 15, |
| AMADD_W = 0x70c2U << 15, |
| AMADD_D = 0x70c3U << 15, |
| AMAND_W = 0x70c4U << 15, |
| AMAND_D = 0x70c5U << 15, |
| AMOR_W = 0x70c6U << 15, |
| AMOR_D = 0x70c7U << 15, |
| AMXOR_W = 0x70c8U << 15, |
| AMXOR_D = 0x70c9U << 15, |
| AMMAX_W = 0x70caU << 15, |
| AMMAX_D = 0x70cbU << 15, |
| AMMIN_W = 0x70ccU << 15, |
| AMMIN_D = 0x70cdU << 15, |
| AMMAX_WU = 0x70ceU << 15, |
| AMMAX_DU = 0x70cfU << 15, |
| AMMIN_WU = 0x70d0U << 15, |
| AMMIN_DU = 0x70d1U << 15, |
| AMSWAP_DB_W = 0x70d2U << 15, |
| AMSWAP_DB_D = 0x70d3U << 15, |
| AMADD_DB_W = 0x70d4U << 15, |
| AMADD_DB_D = 0x70d5U << 15, |
| AMAND_DB_W = 0x70d6U << 15, |
| AMAND_DB_D = 0x70d7U << 15, |
| AMOR_DB_W = 0x70d8U << 15, |
| AMOR_DB_D = 0x70d9U << 15, |
| AMXOR_DB_W = 0x70daU << 15, |
| AMXOR_DB_D = 0x70dbU << 15, |
| AMMAX_DB_W = 0x70dcU << 15, |
| AMMAX_DB_D = 0x70ddU << 15, |
| AMMIN_DB_W = 0x70deU << 15, |
| AMMIN_DB_D = 0x70dfU << 15, |
| AMMAX_DB_WU = 0x70e0U << 15, |
| AMMAX_DB_DU = 0x70e1U << 15, |
| AMMIN_DB_WU = 0x70e2U << 15, |
| AMMIN_DB_DU = 0x70e3U << 15, |
| |
| DBAR = 0x70e4U << 15, |
| IBAR = 0x70e5U << 15, |
| |
| CLO_W = 0X4U << 10, |
| CLZ_W = 0X5U << 10, |
| CTO_W = 0X6U << 10, |
| CTZ_W = 0X7U << 10, |
| CLO_D = 0X8U << 10, |
| CLZ_D = 0X9U << 10, |
| CTO_D = 0XaU << 10, |
| CTZ_D = 0XbU << 10, |
| REVB_2H = 0XcU << 10, |
| REVB_4H = 0XdU << 10, |
| REVB_2W = 0XeU << 10, |
| REVB_D = 0XfU << 10, |
| REVH_2W = 0X10U << 10, |
| REVH_D = 0X11U << 10, |
| BITREV_4B = 0X12U << 10, |
| BITREV_8B = 0X13U << 10, |
| BITREV_W = 0X14U << 10, |
| BITREV_D = 0X15U << 10, |
| EXT_W_H = 0X16U << 10, |
| EXT_W_B = 0X17U << 10, |
| |
| FABS_S = 0X4501U << 10, |
| FABS_D = 0X4502U << 10, |
| FNEG_S = 0X4505U << 10, |
| FNEG_D = 0X4506U << 10, |
| FLOGB_S = 0X4509U << 10, |
| FLOGB_D = 0X450aU << 10, |
| FCLASS_S = 0X450dU << 10, |
| FCLASS_D = 0X450eU << 10, |
| FSQRT_S = 0X4511U << 10, |
| FSQRT_D = 0X4512U << 10, |
| FRECIP_S = 0X4515U << 10, |
| FRECIP_D = 0X4516U << 10, |
| FRSQRT_S = 0X4519U << 10, |
| FRSQRT_D = 0X451aU << 10, |
| FMOV_S = 0X4525U << 10, |
| FMOV_D = 0X4526U << 10, |
| MOVGR2FR_W = 0X4529U << 10, |
| MOVGR2FR_D = 0X452aU << 10, |
| MOVGR2FRH_W = 0X452bU << 10, |
| MOVFR2GR_S = 0X452dU << 10, |
| MOVFR2GR_D = 0X452eU << 10, |
| MOVFRH2GR_S = 0X452fU << 10, |
| MOVGR2FCSR = 0X4530U << 10, |
| MOVFCSR2GR = 0X4532U << 10, |
| MOVFR2CF = 0X4534U << 10, |
| MOVGR2CF = 0X4536U << 10, |
| |
| FCVT_S_D = 0x4646U << 10, |
| FCVT_D_S = 0x4649U << 10, |
| FTINTRM_W_S = 0x4681U << 10, |
| FTINTRM_W_D = 0x4682U << 10, |
| FTINTRM_L_S = 0x4689U << 10, |
| FTINTRM_L_D = 0x468aU << 10, |
| FTINTRP_W_S = 0x4691U << 10, |
| FTINTRP_W_D = 0x4692U << 10, |
| FTINTRP_L_S = 0x4699U << 10, |
| FTINTRP_L_D = 0x469aU << 10, |
| FTINTRZ_W_S = 0x46a1U << 10, |
| FTINTRZ_W_D = 0x46a2U << 10, |
| FTINTRZ_L_S = 0x46a9U << 10, |
| FTINTRZ_L_D = 0x46aaU << 10, |
| FTINTRNE_W_S = 0x46b1U << 10, |
| FTINTRNE_W_D = 0x46b2U << 10, |
| FTINTRNE_L_S = 0x46b9U << 10, |
| FTINTRNE_L_D = 0x46baU << 10, |
| FTINT_W_S = 0x46c1U << 10, |
| FTINT_W_D = 0x46c2U << 10, |
| FTINT_L_S = 0x46c9U << 10, |
| FTINT_L_D = 0x46caU << 10, |
| FFINT_S_W = 0x4744U << 10, |
| FFINT_S_L = 0x4746U << 10, |
| FFINT_D_W = 0x4748U << 10, |
| FFINT_D_L = 0x474aU << 10, |
| FRINT_S = 0x4791U << 10, |
| FRINT_D = 0x4792U << 10, |
| |
| MOVCF2FR = 0x4535U << 10, |
| MOVCF2GR = 0x4537U << 10 |
| }; |
| |
| // ----- Emulated conditions. |
| // On LOONG64 we use this enum to abstract from conditional branch instructions. |
| // The 'U' prefix is used to specify unsigned comparisons. |
| 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; |
| } |
| } |
| |
| // ----- Coprocessor conditions. |
| enum FPUCondition { |
| kNoFPUCondition = -1, |
| |
| CAF = 0x00, // False. |
| SAF = 0x01, // False. |
| CLT = 0x02, // Less Than quiet |
| // SLT = 0x03, // Less Than signaling |
| CEQ = 0x04, |
| SEQ = 0x05, |
| CLE = 0x06, |
| SLE = 0x07, |
| CUN = 0x08, |
| SUN = 0x09, |
| CULT = 0x0a, |
| SULT = 0x0b, |
| CUEQ = 0x0c, |
| SUEQ = 0x0d, |
| CULE = 0x0e, |
| SULE = 0x0f, |
| CNE = 0x10, |
| SNE = 0x11, |
| COR = 0x14, |
| SOR = 0x15, |
| CUNE = 0x18, |
| SUNE = 0x19, |
| }; |
| |
| const uint32_t kFPURoundingModeShift = 8; |
| const uint32_t kFPURoundingModeMask = 0b11 << kFPURoundingModeShift; |
| |
| // FPU rounding modes. |
| enum FPURoundingMode { |
| RN = 0b00 << kFPURoundingModeShift, // Round to Nearest. |
| RZ = 0b01 << kFPURoundingModeShift, // Round towards zero. |
| RP = 0b10 << kFPURoundingModeShift, // Round towards Plus Infinity. |
| RM = 0b11 << kFPURoundingModeShift, // 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 |
| }; |
| |
| enum CheckForInexactConversion { |
| kCheckForInexactConversion, |
| kDontCheckForInexactConversion |
| }; |
| |
| enum class MaxMinKind : int { kMin = 0, kMax = 1 }; |
| |
| // ----------------------------------------------------------------------------- |
| // Hints. |
| |
| // Branch hints are not used on the LOONG64. They are defined so that they can |
| // appear in shared function signatures, but will be ignored in LOONG64 |
| // 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-loong64.cc, as they use named |
| // registers and other constants. |
| |
| // Break 0xfffff, reserved for redirected real time call. |
| const Instr rtCallRedirInstr = BREAK | call_rt_redirected; |
| // A nop instruction. (Encoding of addi_w 0 0 0). |
| const Instr nopInstr = ADDI_W; |
| |
| constexpr uint8_t kInstrSize = 4; |
| constexpr uint8_t kInstrSizeLog2 = 2; |
| |
| class InstructionBase { |
| public: |
| enum Type { |
| kOp6Type, |
| kOp7Type, |
| kOp8Type, |
| kOp10Type, |
| kOp12Type, |
| kOp14Type, |
| kOp17Type, |
| kOp22Type, |
| 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); |
| } |
| |
| // Safe to call within InstructionType(). |
| inline int RjFieldRawNoAssert() const { |
| return InstructionBits() & kRjFieldMask; |
| } |
| |
| // Get the encoding type of the instruction. |
| inline Type InstructionType() const; |
| |
| protected: |
| InstructionBase() {} |
| }; |
| |
| template <class T> |
| class InstructionGetters : public T { |
| public: |
| inline int RjValue() const { |
| return this->Bits(kRjShift + kRjBits - 1, kRjShift); |
| } |
| |
| inline int RkValue() const { |
| return this->Bits(kRkShift + kRkBits - 1, kRkShift); |
| } |
| |
| inline int RdValue() const { |
| return this->Bits(kRdShift + kRdBits - 1, kRdShift); |
| } |
| |
| inline int Sa2Value() const { |
| return this->Bits(kSaShift + kSa2Bits - 1, kSaShift); |
| } |
| |
| inline int Sa3Value() const { |
| return this->Bits(kSaShift + kSa3Bits - 1, kSaShift); |
| } |
| |
| inline int Ui5Value() const { |
| return this->Bits(kUi5Shift + kUi5Bits - 1, kUi5Shift); |
| } |
| |
| inline int Ui6Value() const { |
| return this->Bits(kUi6Shift + kUi6Bits - 1, kUi6Shift); |
| } |
| |
| inline int Ui12Value() const { |
| return this->Bits(kUi12Shift + kUi12Bits - 1, kUi12Shift); |
| } |
| |
| inline int LsbwValue() const { |
| return this->Bits(kLsbwShift + kLsbwBits - 1, kLsbwShift); |
| } |
| |
| inline int MsbwValue() const { |
| return this->Bits(kMsbwShift + kMsbwBits - 1, kMsbwShift); |
| } |
| |
| inline int LsbdValue() const { |
| return this->Bits(kLsbdShift + kLsbdBits - 1, kLsbdShift); |
| } |
| |
| inline int MsbdValue() const { |
| return this->Bits(kMsbdShift + kMsbdBits - 1, kMsbdShift); |
| } |
| |
| inline int CondValue() const { |
| return this->Bits(kCondShift + kCondBits - 1, kCondShift); |
| } |
| |
| inline int Si12Value() const { |
| return this->Bits(kSi12Shift + kSi12Bits - 1, kSi12Shift); |
| } |
| |
| inline int Si14Value() const { |
| return this->Bits(kSi14Shift + kSi14Bits - 1, kSi14Shift); |
| } |
| |
| inline int Si16Value() const { |
| return this->Bits(kSi16Shift + kSi16Bits - 1, kSi16Shift); |
| } |
| |
| inline int Si20Value() const { |
| return this->Bits(kSi20Shift + kSi20Bits - 1, kSi20Shift); |
| } |
| |
| inline int FdValue() const { |
| return this->Bits(kFdShift + kFdBits - 1, kFdShift); |
| } |
| |
| inline int FaValue() const { |
| return this->Bits(kFaShift + kFaBits - 1, kFaShift); |
| } |
| |
| inline int FjValue() const { |
| return this->Bits(kFjShift + kFjBits - 1, kFjShift); |
| } |
| |
| inline int FkValue() const { |
| return this->Bits(kFkShift + kFkBits - 1, kFkShift); |
| } |
| |
| inline int CjValue() const { |
| return this->Bits(kCjShift + kCjBits - 1, kCjShift); |
| } |
| |
| inline int CdValue() const { |
| return this->Bits(kCdShift + kCdBits - 1, kCdShift); |
| } |
| |
| inline int CaValue() const { |
| return this->Bits(kCaShift + kCaBits - 1, kCaShift); |
| } |
| |
| inline int CodeValue() const { |
| return this->Bits(kCodeShift + kCodeBits - 1, kCodeShift); |
| } |
| |
| inline int Hint5Value() const { |
| return this->Bits(kHint5Shift + kHint5Bits - 1, kHint5Shift); |
| } |
| |
| inline int Hint15Value() const { |
| return this->Bits(kHint15Shift + kHint15Bits - 1, kHint15Shift); |
| } |
| |
| inline int Offs16Value() const { |
| return this->Bits(kOffsLowShift + kOffsLowBits - 1, kOffsLowShift); |
| } |
| |
| inline int Offs21Value() const { |
| int low = this->Bits(kOffsLowShift + kOffsLowBits - 1, kOffsLowShift); |
| int high = |
| this->Bits(kOffs21HighShift + kOffs21HighBits - 1, kOffs21HighShift); |
| return ((high << kOffsLowBits) + low); |
| } |
| |
| inline int Offs26Value() const { |
| int low = this->Bits(kOffsLowShift + kOffsLowBits - 1, kOffsLowShift); |
| int high = |
| this->Bits(kOffs26HighShift + kOffs26HighBits - 1, kOffs26HighShift); |
| return ((high << kOffsLowBits) + low); |
| } |
| |
| inline int RjFieldRaw() const { |
| return this->InstructionBits() & kRjFieldMask; |
| } |
| |
| inline int RkFieldRaw() const { |
| return this->InstructionBits() & kRkFieldMask; |
| } |
| |
| inline int RdFieldRaw() const { |
| return this->InstructionBits() & kRdFieldMask; |
| } |
| |
| inline int32_t ImmValue(int bits) const { return this->Bits(bits - 1, 0); } |
| |
| /*TODO*/ |
| inline int32_t Imm12Value() const { abort(); } |
| |
| inline int32_t Imm14Value() const { abort(); } |
| |
| inline int32_t Imm16Value() const { abort(); } |
| |
| // Say if the instruction is a break. |
| bool IsTrap() const; |
| }; |
| |
| 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); |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // LOONG64 assembly various constants. |
| |
| const int kInvalidStackOffset = -1; |
| |
| static const int kNegOffset = 0x00008000; |
| |
| InstructionBase::Type InstructionBase::InstructionType() const { |
| InstructionBase::Type kType = kUnsupported; |
| |
| // Check for kOp6Type |
| switch (Bits(31, 26) << 26) { |
| case ADDU16I_D: |
| case BEQZ: |
| case BNEZ: |
| case BCZ: |
| case JIRL: |
| case B: |
| case BL: |
| case BEQ: |
| case BNE: |
| case BLT: |
| case BGE: |
| case BLTU: |
| case BGEU: |
| kType = kOp6Type; |
| break; |
| default: |
| kType = kUnsupported; |
| } |
| |
| if (kType == kUnsupported) { |
| // Check for kOp7Type |
| switch (Bits(31, 25) << 25) { |
| case LU12I_W: |
| case LU32I_D: |
| case PCADDI: |
| case PCALAU12I: |
| case PCADDU12I: |
| case PCADDU18I: |
| kType = kOp7Type; |
| break; |
| default: |
| kType = kUnsupported; |
| } |
| } |
| |
| if (kType == kUnsupported) { |
| // Check for kOp8Type |
| switch (Bits(31, 24) << 24) { |
| case LDPTR_W: |
| case STPTR_W: |
| case LDPTR_D: |
| case STPTR_D: |
| case LL_W: |
| case SC_W: |
| case LL_D: |
| case SC_D: |
| kType = kOp8Type; |
| break; |
| default: |
| kType = kUnsupported; |
| } |
| } |
| |
| if (kType == kUnsupported) { |
| // Check for kOp10Type |
| switch (Bits(31, 22) << 22) { |
| case BSTR_W: { |
| // If Bit(21) = 0, then the Opcode is not BSTR_W. |
| if (Bit(21) == 0) |
| kType = kUnsupported; |
| else |
| kType = kOp10Type; |
| break; |
| } |
| case BSTRINS_D: |
| case BSTRPICK_D: |
| case SLTI: |
| case SLTUI: |
| case ADDI_W: |
| case ADDI_D: |
| case LU52I_D: |
| case ANDI: |
| case ORI: |
| case XORI: |
| case LD_B: |
| case LD_H: |
| case LD_W: |
| case LD_D: |
| case ST_B: |
| case ST_H: |
| case ST_W: |
| case ST_D: |
| case LD_BU: |
| case LD_HU: |
| case LD_WU: |
| case FLD_S: |
| case FST_S: |
| case FLD_D: |
| case FST_D: |
| kType = kOp10Type; |
| break; |
| default: |
| kType = kUnsupported; |
| } |
| } |
| |
| if (kType == kUnsupported) { |
| // Check for kOp12Type |
| switch (Bits(31, 20) << 20) { |
| case FMADD_S: |
| case FMADD_D: |
| case FMSUB_S: |
| case FMSUB_D: |
| case FNMADD_S: |
| case FNMADD_D: |
| case FNMSUB_S: |
| case FNMSUB_D: |
| case FCMP_COND_S: |
| case FCMP_COND_D: |
| case FSEL: |
| kType = kOp12Type; |
| break; |
| default: |
| kType = kUnsupported; |
| } |
| } |
| |
| if (kType == kUnsupported) { |
| // Check for kOp14Type |
| switch (Bits(31, 18) << 18) { |
| case ALSL: |
| case BYTEPICK_W: |
| case BYTEPICK_D: |
| case ALSL_D: |
| case SLLI: |
| case SRLI: |
| case SRAI: |
| case ROTRI: |
| kType = kOp14Type; |
| break; |
| default: |
| kType = kUnsupported; |
| } |
| } |
| |
| if (kType == kUnsupported) { |
| // Check for kOp17Type |
| switch (Bits(31, 15) << 15) { |
| case ADD_W: |
| case ADD_D: |
| case SUB_W: |
| case SUB_D: |
| case SLT: |
| case SLTU: |
| case MASKEQZ: |
| case MASKNEZ: |
| case NOR: |
| case AND: |
| case OR: |
| case XOR: |
| case ORN: |
| case ANDN: |
| case SLL_W: |
| case SRL_W: |
| case SRA_W: |
| case SLL_D: |
| case SRL_D: |
| case SRA_D: |
| case ROTR_D: |
| case ROTR_W: |
| case MUL_W: |
| case MULH_W: |
| case MULH_WU: |
| case MUL_D: |
| case MULH_D: |
| case MULH_DU: |
| case MULW_D_W: |
| case MULW_D_WU: |
| case DIV_W: |
| case MOD_W: |
| case DIV_WU: |
| case MOD_WU: |
| case DIV_D: |
| case MOD_D: |
| case DIV_DU: |
| case MOD_DU: |
| case BREAK: |
| case FADD_S: |
| case FADD_D: |
| case FSUB_S: |
| case FSUB_D: |
| case FMUL_S: |
| case FMUL_D: |
| case FDIV_S: |
| case FDIV_D: |
| case FMAX_S: |
| case FMAX_D: |
| case FMIN_S: |
| case FMIN_D: |
| case FMAXA_S: |
| case FMAXA_D: |
| case FMINA_S: |
| case FMINA_D: |
| case LDX_B: |
| case LDX_H: |
| case LDX_W: |
| case LDX_D: |
| case STX_B: |
| case STX_H: |
| case STX_W: |
| case STX_D: |
| case LDX_BU: |
| case LDX_HU: |
| case LDX_WU: |
| case FLDX_S: |
| case FLDX_D: |
| case FSTX_S: |
| case FSTX_D: |
| case AMSWAP_W: |
| case AMSWAP_D: |
| case AMADD_W: |
| case AMADD_D: |
| case AMAND_W: |
| case AMAND_D: |
| case AMOR_W: |
| case AMOR_D: |
| case AMXOR_W: |
| case AMXOR_D: |
| case AMMAX_W: |
| case AMMAX_D: |
| case AMMIN_W: |
| case AMMIN_D: |
| case AMMAX_WU: |
| case AMMAX_DU: |
| case AMMIN_WU: |
| case AMMIN_DU: |
| case AMSWAP_DB_W: |
| case AMSWAP_DB_D: |
| case AMADD_DB_W: |
| case AMADD_DB_D: |
| case AMAND_DB_W: |
| case AMAND_DB_D: |
| case AMOR_DB_W: |
| case AMOR_DB_D: |
| case AMXOR_DB_W: |
| case AMXOR_DB_D: |
| case AMMAX_DB_W: |
| case AMMAX_DB_D: |
| case AMMIN_DB_W: |
| case AMMIN_DB_D: |
| case AMMAX_DB_WU: |
| case AMMAX_DB_DU: |
| case AMMIN_DB_WU: |
| case AMMIN_DB_DU: |
| case DBAR: |
| case IBAR: |
| case FSCALEB_S: |
| case FSCALEB_D: |
| case FCOPYSIGN_S: |
| case FCOPYSIGN_D: |
| kType = kOp17Type; |
| break; |
| default: |
| kType = kUnsupported; |
| } |
| } |
| |
| if (kType == kUnsupported) { |
| // Check for kOp22Type |
| switch (Bits(31, 10) << 10) { |
| case CLZ_W: |
| case CTZ_W: |
| case CLZ_D: |
| case CTZ_D: |
| case REVB_2H: |
| case REVB_4H: |
| case REVB_2W: |
| case REVB_D: |
| case REVH_2W: |
| case REVH_D: |
| case BITREV_4B: |
| case BITREV_8B: |
| case BITREV_W: |
| case BITREV_D: |
| case EXT_W_B: |
| case EXT_W_H: |
| case FABS_S: |
| case FABS_D: |
| case FNEG_S: |
| case FNEG_D: |
| case FSQRT_S: |
| case FSQRT_D: |
| case FMOV_S: |
| case FMOV_D: |
| case MOVGR2FR_W: |
| case MOVGR2FR_D: |
| case MOVGR2FRH_W: |
| case MOVFR2GR_S: |
| case MOVFR2GR_D: |
| case MOVFRH2GR_S: |
| case MOVGR2FCSR: |
| case MOVFCSR2GR: |
| case FCVT_S_D: |
| case FCVT_D_S: |
| case FTINTRM_W_S: |
| case FTINTRM_W_D: |
| case FTINTRM_L_S: |
| case FTINTRM_L_D: |
| case FTINTRP_W_S: |
| case FTINTRP_W_D: |
| case FTINTRP_L_S: |
| case FTINTRP_L_D: |
| case FTINTRZ_W_S: |
| case FTINTRZ_W_D: |
| case FTINTRZ_L_S: |
| case FTINTRZ_L_D: |
| case FTINTRNE_W_S: |
| case FTINTRNE_W_D: |
| case FTINTRNE_L_S: |
| case FTINTRNE_L_D: |
| case FTINT_W_S: |
| case FTINT_W_D: |
| case FTINT_L_S: |
| case FTINT_L_D: |
| case FFINT_S_W: |
| case FFINT_S_L: |
| case FFINT_D_W: |
| case FFINT_D_L: |
| case FRINT_S: |
| case FRINT_D: |
| case MOVFR2CF: |
| case MOVCF2FR: |
| case MOVGR2CF: |
| case MOVCF2GR: |
| case FRECIP_S: |
| case FRECIP_D: |
| case FRSQRT_S: |
| case FRSQRT_D: |
| case FCLASS_S: |
| case FCLASS_D: |
| case FLOGB_S: |
| case FLOGB_D: |
| case CLO_W: |
| case CTO_W: |
| case CLO_D: |
| case CTO_D: |
| kType = kOp22Type; |
| break; |
| default: |
| kType = kUnsupported; |
| } |
| } |
| |
| return kType; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // Instructions. |
| |
| template <class P> |
| bool InstructionGetters<P>::IsTrap() const { |
| return true; |
| } |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_CODEGEN_LOONG64_CONSTANTS_LOONG64_H_ |