[assembler] Factor out Registers from assembler.h
This refactoring reduces the LoC after preprocessor expansion by 370,322 gen ( 21 files): 71,503 to 1,631,168 ( 23x) src ( 624 files): 367,639 to 53,231,764 ( 145x) test ( 392 files): 490,770 to 37,450,839 ( 76x) third_party ( 432 files): 239,085 to 9,547,902 ( 40x) total ( 1521 files): 1,183,681 to 102,836,194 ( 87x) gen ( 21 files): 71,503 to 1,613,222 ( 23x) src ( 624 files): 367,634 to 52,964,046 ( 144x) test ( 392 files): 490,771 to 37,366,181 ( 76x) third_party ( 432 files): 239,085 to 9,547,902 ( 40x) total ( 1521 files): 1,183,677 to 102,465,872 ( 87x) Bug: v8:8562 Change-Id: Ib4e771c37471a2ff19c5538e62c038943cc74eaf Reviewed-on: https://chromium-review.googlesource.com/c/1382469 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Cr-Commit-Position: refs/heads/master@{#58349}
This commit is contained in:
parent
f2c2742c50
commit
5c38b47af5
11
BUILD.gn
11
BUILD.gn
@ -2527,8 +2527,10 @@ v8_source_set("v8_base") {
|
||||
"src/regexp/regexp-stack.h",
|
||||
"src/regexp/regexp-utils.cc",
|
||||
"src/regexp/regexp-utils.h",
|
||||
"src/register-arch.h",
|
||||
"src/register-configuration.cc",
|
||||
"src/register-configuration.h",
|
||||
"src/register.h",
|
||||
"src/reglist.h",
|
||||
"src/reloc-info.cc",
|
||||
"src/reloc-info.h",
|
||||
@ -2812,6 +2814,7 @@ v8_source_set("v8_base") {
|
||||
"src/ia32/interface-descriptors-ia32.cc",
|
||||
"src/ia32/macro-assembler-ia32.cc",
|
||||
"src/ia32/macro-assembler-ia32.h",
|
||||
"src/ia32/register-ia32.h",
|
||||
"src/ia32/simulator-ia32.cc",
|
||||
"src/ia32/simulator-ia32.h",
|
||||
"src/ia32/sse-instr.h",
|
||||
@ -2846,6 +2849,7 @@ v8_source_set("v8_base") {
|
||||
"src/x64/interface-descriptors-x64.cc",
|
||||
"src/x64/macro-assembler-x64.cc",
|
||||
"src/x64/macro-assembler-x64.h",
|
||||
"src/x64/register-x64.h",
|
||||
"src/x64/simulator-x64.cc",
|
||||
"src/x64/simulator-x64.h",
|
||||
"src/x64/sse-instr.h",
|
||||
@ -2881,6 +2885,7 @@ v8_source_set("v8_base") {
|
||||
"src/arm/interface-descriptors-arm.cc",
|
||||
"src/arm/macro-assembler-arm.cc",
|
||||
"src/arm/macro-assembler-arm.h",
|
||||
"src/arm/register-arm.h",
|
||||
"src/arm/simulator-arm.cc",
|
||||
"src/arm/simulator-arm.h",
|
||||
"src/compiler/backend/arm/code-generator-arm.cc",
|
||||
@ -2920,6 +2925,8 @@ v8_source_set("v8_base") {
|
||||
"src/arm64/macro-assembler-arm64-inl.h",
|
||||
"src/arm64/macro-assembler-arm64.cc",
|
||||
"src/arm64/macro-assembler-arm64.h",
|
||||
"src/arm64/register-arm64.cc",
|
||||
"src/arm64/register-arm64.h",
|
||||
"src/arm64/simulator-arm64.cc",
|
||||
"src/arm64/simulator-arm64.h",
|
||||
"src/arm64/simulator-logic-arm64.cc",
|
||||
@ -2964,6 +2971,7 @@ v8_source_set("v8_base") {
|
||||
"src/mips/interface-descriptors-mips.cc",
|
||||
"src/mips/macro-assembler-mips.cc",
|
||||
"src/mips/macro-assembler-mips.h",
|
||||
"src/mips/register-mips.h",
|
||||
"src/mips/simulator-mips.cc",
|
||||
"src/mips/simulator-mips.h",
|
||||
"src/regexp/mips/regexp-macro-assembler-mips.cc",
|
||||
@ -2991,6 +2999,7 @@ v8_source_set("v8_base") {
|
||||
"src/mips64/interface-descriptors-mips64.cc",
|
||||
"src/mips64/macro-assembler-mips64.cc",
|
||||
"src/mips64/macro-assembler-mips64.h",
|
||||
"src/mips64/register-mips64.h",
|
||||
"src/mips64/simulator-mips64.cc",
|
||||
"src/mips64/simulator-mips64.h",
|
||||
"src/regexp/mips64/regexp-macro-assembler-mips64.cc",
|
||||
@ -3019,6 +3028,7 @@ v8_source_set("v8_base") {
|
||||
"src/ppc/interface-descriptors-ppc.cc",
|
||||
"src/ppc/macro-assembler-ppc.cc",
|
||||
"src/ppc/macro-assembler-ppc.h",
|
||||
"src/ppc/register-ppc.h",
|
||||
"src/ppc/simulator-ppc.cc",
|
||||
"src/ppc/simulator-ppc.h",
|
||||
"src/regexp/ppc/regexp-macro-assembler-ppc.cc",
|
||||
@ -3049,6 +3059,7 @@ v8_source_set("v8_base") {
|
||||
"src/s390/interface-descriptors-s390.cc",
|
||||
"src/s390/macro-assembler-s390.cc",
|
||||
"src/s390/macro-assembler-s390.h",
|
||||
"src/s390/register-s390.h",
|
||||
"src/s390/simulator-s390.cc",
|
||||
"src/s390/simulator-s390.h",
|
||||
"src/wasm/baseline/s390/liftoff-assembler-s390.h",
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "src/arm/constants-arm.h"
|
||||
#include "src/arm/register-arm.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/boxed-float.h"
|
||||
#include "src/constant-pool.h"
|
||||
@ -52,324 +53,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(fp) V(ip) V(sp) V(lr) V(pc)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9)
|
||||
|
||||
#define FLOAT_REGISTERS(V) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) \
|
||||
V(s8) V(s9) V(s10) V(s11) V(s12) V(s13) V(s14) V(s15) \
|
||||
V(s16) V(s17) V(s18) V(s19) V(s20) V(s21) V(s22) V(s23) \
|
||||
V(s24) V(s25) V(s26) V(s27) V(s28) V(s29) V(s30) V(s31)
|
||||
|
||||
#define LOW_DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15)
|
||||
|
||||
#define NON_LOW_DOUBLE_REGISTERS(V) \
|
||||
V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
LOW_DOUBLE_REGISTERS(V) NON_LOW_DOUBLE_REGISTERS(V)
|
||||
|
||||
#define SIMD128_REGISTERS(V) \
|
||||
V(q0) V(q1) V(q2) V(q3) V(q4) V(q5) V(q6) V(q7) \
|
||||
V(q8) V(q9) V(q10) V(q11) V(q12) V(q13) V(q14) V(q15)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) \
|
||||
V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d15)
|
||||
|
||||
#define C_REGISTERS(V) \
|
||||
V(cr0) V(cr1) V(cr2) V(cr3) V(cr4) V(cr5) V(cr6) V(cr7) \
|
||||
V(cr8) V(cr9) V(cr10) V(cr11) V(cr12) V(cr15)
|
||||
// clang-format on
|
||||
|
||||
// The ARM ABI does not specify the usage of register r9, which may be reserved
|
||||
// as the static base or thread register on some platforms, in which case we
|
||||
// leave it alone. Adjust the value of kR9Available accordingly:
|
||||
const int kR9Available = 1; // 1 if available to us, 0 if reserved
|
||||
|
||||
// Register list in load/store instructions
|
||||
// Note that the bit values must match those used in actual instruction encoding
|
||||
const int kNumRegs = 16;
|
||||
|
||||
// Caller-saved/arguments registers
|
||||
const RegList kJSCallerSaved =
|
||||
1 << 0 | // r0 a1
|
||||
1 << 1 | // r1 a2
|
||||
1 << 2 | // r2 a3
|
||||
1 << 3; // r3 a4
|
||||
|
||||
const int kNumJSCallerSaved = 4;
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript
|
||||
const RegList kCalleeSaved =
|
||||
1 << 4 | // r4 v1
|
||||
1 << 5 | // r5 v2
|
||||
1 << 6 | // r6 v3
|
||||
1 << 7 | // r7 v4 (cp in JavaScript code)
|
||||
1 << 8 | // r8 v5 (pp in JavaScript code)
|
||||
kR9Available << 9 | // r9 v6
|
||||
1 << 10 | // r10 v7
|
||||
1 << 11; // r11 v8 (fp in JavaScript code)
|
||||
|
||||
// When calling into C++ (only for C++ calls that can't cause a GC).
|
||||
// The call code will take care of lr, fp, etc.
|
||||
const RegList kCallerSaved =
|
||||
1 << 0 | // r0
|
||||
1 << 1 | // r1
|
||||
1 << 2 | // r2
|
||||
1 << 3 | // r3
|
||||
1 << 9; // r9
|
||||
|
||||
const int kNumCalleeSaved = 7 + kR9Available;
|
||||
|
||||
// Double registers d8 to d15 are callee-saved.
|
||||
const int kNumDoubleCalleeSaved = 8;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
// TODO(regis): Only 8 registers may actually be sufficient. Revisit.
|
||||
const int kNumSafepointRegisters = 16;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
// r7: context register
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = false;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum SwVfpRegisterCode {
|
||||
#define REGISTER_CODE(R) kSwVfpCode_##R,
|
||||
FLOAT_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kSwVfpAfterLast
|
||||
};
|
||||
|
||||
// Representation of a list of non-overlapping VFP registers. This list
|
||||
// represents the data layout of VFP registers as a bitfield:
|
||||
// S registers cover 1 bit
|
||||
// D registers cover 2 bits
|
||||
// Q registers cover 4 bits
|
||||
//
|
||||
// This way, we make sure no registers in the list ever overlap. However, a list
|
||||
// may represent multiple different sets of registers,
|
||||
// e.g. [d0 s2 s3] <=> [s0 s1 d1].
|
||||
typedef uint64_t VfpRegList;
|
||||
|
||||
// Single word VFP register.
|
||||
class SwVfpRegister : public RegisterBase<SwVfpRegister, kSwVfpAfterLast> {
|
||||
public:
|
||||
static constexpr int kSizeInBytes = 4;
|
||||
|
||||
static void split_code(int reg_code, int* vm, int* m) {
|
||||
DCHECK(from_code(reg_code).is_valid());
|
||||
*m = reg_code & 0x1;
|
||||
*vm = reg_code >> 1;
|
||||
}
|
||||
void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
|
||||
VfpRegList ToVfpRegList() const {
|
||||
DCHECK(is_valid());
|
||||
// Each bit in the list corresponds to a S register.
|
||||
return uint64_t{0x1} << code();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr SwVfpRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(SwVfpRegister);
|
||||
static_assert(sizeof(SwVfpRegister) == sizeof(int),
|
||||
"SwVfpRegister can efficiently be passed by value");
|
||||
|
||||
typedef SwVfpRegister FloatRegister;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Double word VFP register.
|
||||
class DwVfpRegister : public RegisterBase<DwVfpRegister, kDoubleAfterLast> {
|
||||
public:
|
||||
static constexpr int kSizeInBytes = 8;
|
||||
|
||||
inline static int NumRegisters();
|
||||
|
||||
static void split_code(int reg_code, int* vm, int* m) {
|
||||
DCHECK(from_code(reg_code).is_valid());
|
||||
*m = (reg_code & 0x10) >> 4;
|
||||
*vm = reg_code & 0x0F;
|
||||
}
|
||||
void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
|
||||
VfpRegList ToVfpRegList() const {
|
||||
DCHECK(is_valid());
|
||||
// A D register overlaps two S registers.
|
||||
return uint64_t{0x3} << (code() * 2);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
friend class LowDwVfpRegister;
|
||||
explicit constexpr DwVfpRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(DwVfpRegister);
|
||||
static_assert(sizeof(DwVfpRegister) == sizeof(int),
|
||||
"DwVfpRegister can efficiently be passed by value");
|
||||
|
||||
typedef DwVfpRegister DoubleRegister;
|
||||
|
||||
|
||||
// Double word VFP register d0-15.
|
||||
class LowDwVfpRegister
|
||||
: public RegisterBase<LowDwVfpRegister, kDoubleCode_d16> {
|
||||
public:
|
||||
constexpr operator DwVfpRegister() const { return DwVfpRegister(reg_code_); }
|
||||
|
||||
SwVfpRegister low() const { return SwVfpRegister::from_code(code() * 2); }
|
||||
SwVfpRegister high() const {
|
||||
return SwVfpRegister::from_code(code() * 2 + 1);
|
||||
}
|
||||
VfpRegList ToVfpRegList() const {
|
||||
DCHECK(is_valid());
|
||||
// A D register overlaps two S registers.
|
||||
return uint64_t{0x3} << (code() * 2);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr LowDwVfpRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
enum Simd128RegisterCode {
|
||||
#define REGISTER_CODE(R) kSimd128Code_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kSimd128AfterLast
|
||||
};
|
||||
|
||||
// Quad word NEON register.
|
||||
class QwNeonRegister : public RegisterBase<QwNeonRegister, kSimd128AfterLast> {
|
||||
public:
|
||||
static void split_code(int reg_code, int* vm, int* m) {
|
||||
DCHECK(from_code(reg_code).is_valid());
|
||||
int encoded_code = reg_code << 1;
|
||||
*m = (encoded_code & 0x10) >> 4;
|
||||
*vm = encoded_code & 0x0F;
|
||||
}
|
||||
void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
|
||||
DwVfpRegister low() const { return DwVfpRegister::from_code(code() * 2); }
|
||||
DwVfpRegister high() const {
|
||||
return DwVfpRegister::from_code(code() * 2 + 1);
|
||||
}
|
||||
VfpRegList ToVfpRegList() const {
|
||||
DCHECK(is_valid());
|
||||
// A Q register overlaps four S registers.
|
||||
return uint64_t{0xf} << (code() * 4);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr QwNeonRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
|
||||
typedef QwNeonRegister QuadRegister;
|
||||
|
||||
typedef QwNeonRegister Simd128Register;
|
||||
|
||||
enum CRegisterCode {
|
||||
#define REGISTER_CODE(R) kCCode_##R,
|
||||
C_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kCAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register
|
||||
class CRegister : public RegisterBase<CRegister, kCAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr CRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// Support for the VFP registers s0 to s31 (d0 to d15).
|
||||
// Note that "s(N):s(N+1)" is the same as "d(N/2)".
|
||||
#define DECLARE_FLOAT_REGISTER(R) \
|
||||
constexpr SwVfpRegister R = SwVfpRegister::from_code<kSwVfpCode_##R>();
|
||||
FLOAT_REGISTERS(DECLARE_FLOAT_REGISTER)
|
||||
#undef DECLARE_FLOAT_REGISTER
|
||||
|
||||
#define DECLARE_LOW_DOUBLE_REGISTER(R) \
|
||||
constexpr LowDwVfpRegister R = LowDwVfpRegister::from_code<kDoubleCode_##R>();
|
||||
LOW_DOUBLE_REGISTERS(DECLARE_LOW_DOUBLE_REGISTER)
|
||||
#undef DECLARE_LOW_DOUBLE_REGISTER
|
||||
|
||||
#define DECLARE_DOUBLE_REGISTER(R) \
|
||||
constexpr DwVfpRegister R = DwVfpRegister::from_code<kDoubleCode_##R>();
|
||||
NON_LOW_DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
|
||||
#undef DECLARE_DOUBLE_REGISTER
|
||||
|
||||
constexpr DwVfpRegister no_dreg = DwVfpRegister::no_reg();
|
||||
|
||||
#define DECLARE_SIMD128_REGISTER(R) \
|
||||
constexpr Simd128Register R = Simd128Register::from_code<kSimd128Code_##R>();
|
||||
SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
|
||||
#undef DECLARE_SIMD128_REGISTER
|
||||
|
||||
// Aliases for double registers.
|
||||
constexpr LowDwVfpRegister kFirstCalleeSavedDoubleReg = d8;
|
||||
constexpr LowDwVfpRegister kLastCalleeSavedDoubleReg = d15;
|
||||
constexpr LowDwVfpRegister kDoubleRegZero = d13;
|
||||
|
||||
constexpr CRegister no_creg = CRegister::no_reg();
|
||||
|
||||
#define DECLARE_C_REGISTER(R) \
|
||||
constexpr CRegister R = CRegister::from_code<kCCode_##R>();
|
||||
C_REGISTERS(DECLARE_C_REGISTER)
|
||||
#undef DECLARE_C_REGISTER
|
||||
|
||||
// Coprocessor number
|
||||
enum Coprocessor {
|
||||
p0 = 0,
|
||||
@ -1746,14 +1429,6 @@ class UseScratchRegisterScope {
|
||||
VfpRegList old_available_vfp_;
|
||||
};
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(SwVfpRegister, FLOAT_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(DwVfpRegister, DOUBLE_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(LowDwVfpRegister, LOW_DOUBLE_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(QwNeonRegister, SIMD128_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(CRegister, C_REGISTERS);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -30,11 +30,11 @@
|
||||
|
||||
#if V8_TARGET_ARCH_ARM
|
||||
|
||||
#include "src/arm/assembler-arm.h"
|
||||
#include "src/arm/constants-arm.h"
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "src/disasm.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -5,7 +5,8 @@
|
||||
#if V8_TARGET_ARCH_ARM
|
||||
|
||||
#include "src/interface-descriptors.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
#include "src/frames.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -17,32 +17,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = r0;
|
||||
constexpr Register kReturnRegister1 = r1;
|
||||
constexpr Register kReturnRegister2 = r2;
|
||||
constexpr Register kJSFunctionRegister = r1;
|
||||
constexpr Register kContextRegister = r7;
|
||||
constexpr Register kAllocateSizeRegister = r1;
|
||||
constexpr Register kSpeculationPoisonRegister = r9;
|
||||
constexpr Register kInterpreterAccumulatorRegister = r0;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = r5;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = r6;
|
||||
constexpr Register kInterpreterDispatchTableRegister = r8;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = r0;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = r2;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = r3;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = r2;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = ip;
|
||||
constexpr Register kRuntimeCallFunctionRegister = r1;
|
||||
constexpr Register kRuntimeCallArgCountRegister = r0;
|
||||
constexpr Register kRuntimeCallArgvRegister = r2;
|
||||
constexpr Register kWasmInstanceRegister = r3;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = r4;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Static helper functions
|
||||
|
||||
@ -51,11 +25,6 @@ inline MemOperand FieldMemOperand(Register object, int offset) {
|
||||
return MemOperand(object, offset - kHeapObjectTag);
|
||||
}
|
||||
|
||||
|
||||
// Give alias names to registers
|
||||
constexpr Register cp = r7; // JavaScript context pointer.
|
||||
constexpr Register kRootRegister = r10; // Roots array pointer.
|
||||
|
||||
enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
|
||||
enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
|
||||
enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
|
||||
|
369
src/arm/register-arm.h
Normal file
369
src/arm/register-arm.h
Normal file
@ -0,0 +1,369 @@
|
||||
// Copyright 2018 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_ARM_REGISTER_ARM_H_
|
||||
#define V8_ARM_REGISTER_ARM_H_
|
||||
|
||||
#include "src/register.h"
|
||||
#include "src/reglist.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(fp) V(ip) V(sp) V(lr) V(pc)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9)
|
||||
|
||||
#define FLOAT_REGISTERS(V) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) \
|
||||
V(s8) V(s9) V(s10) V(s11) V(s12) V(s13) V(s14) V(s15) \
|
||||
V(s16) V(s17) V(s18) V(s19) V(s20) V(s21) V(s22) V(s23) \
|
||||
V(s24) V(s25) V(s26) V(s27) V(s28) V(s29) V(s30) V(s31)
|
||||
|
||||
#define LOW_DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15)
|
||||
|
||||
#define NON_LOW_DOUBLE_REGISTERS(V) \
|
||||
V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
LOW_DOUBLE_REGISTERS(V) NON_LOW_DOUBLE_REGISTERS(V)
|
||||
|
||||
#define SIMD128_REGISTERS(V) \
|
||||
V(q0) V(q1) V(q2) V(q3) V(q4) V(q5) V(q6) V(q7) \
|
||||
V(q8) V(q9) V(q10) V(q11) V(q12) V(q13) V(q14) V(q15)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) \
|
||||
V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d15)
|
||||
|
||||
#define C_REGISTERS(V) \
|
||||
V(cr0) V(cr1) V(cr2) V(cr3) V(cr4) V(cr5) V(cr6) V(cr7) \
|
||||
V(cr8) V(cr9) V(cr10) V(cr11) V(cr12) V(cr15)
|
||||
// clang-format on
|
||||
|
||||
// The ARM ABI does not specify the usage of register r9, which may be reserved
|
||||
// as the static base or thread register on some platforms, in which case we
|
||||
// leave it alone. Adjust the value of kR9Available accordingly:
|
||||
const int kR9Available = 1; // 1 if available to us, 0 if reserved
|
||||
|
||||
// Register list in load/store instructions
|
||||
// Note that the bit values must match those used in actual instruction encoding
|
||||
const int kNumRegs = 16;
|
||||
|
||||
// Caller-saved/arguments registers
|
||||
const RegList kJSCallerSaved = 1 << 0 | // r0 a1
|
||||
1 << 1 | // r1 a2
|
||||
1 << 2 | // r2 a3
|
||||
1 << 3; // r3 a4
|
||||
|
||||
const int kNumJSCallerSaved = 4;
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript
|
||||
const RegList kCalleeSaved = 1 << 4 | // r4 v1
|
||||
1 << 5 | // r5 v2
|
||||
1 << 6 | // r6 v3
|
||||
1 << 7 | // r7 v4 (cp in JavaScript code)
|
||||
1 << 8 | // r8 v5 (pp in JavaScript code)
|
||||
kR9Available << 9 | // r9 v6
|
||||
1 << 10 | // r10 v7
|
||||
1 << 11; // r11 v8 (fp in JavaScript code)
|
||||
|
||||
// When calling into C++ (only for C++ calls that can't cause a GC).
|
||||
// The call code will take care of lr, fp, etc.
|
||||
const RegList kCallerSaved = 1 << 0 | // r0
|
||||
1 << 1 | // r1
|
||||
1 << 2 | // r2
|
||||
1 << 3 | // r3
|
||||
1 << 9; // r9
|
||||
|
||||
const int kNumCalleeSaved = 7 + kR9Available;
|
||||
|
||||
// Double registers d8 to d15 are callee-saved.
|
||||
const int kNumDoubleCalleeSaved = 8;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
// TODO(regis): Only 8 registers may actually be sufficient. Revisit.
|
||||
const int kNumSafepointRegisters = 16;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
friend class RegisterBase;
|
||||
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
// r7: context register
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = false;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum SwVfpRegisterCode {
|
||||
#define REGISTER_CODE(R) kSwVfpCode_##R,
|
||||
FLOAT_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kSwVfpAfterLast
|
||||
};
|
||||
|
||||
// Representation of a list of non-overlapping VFP registers. This list
|
||||
// represents the data layout of VFP registers as a bitfield:
|
||||
// S registers cover 1 bit
|
||||
// D registers cover 2 bits
|
||||
// Q registers cover 4 bits
|
||||
//
|
||||
// This way, we make sure no registers in the list ever overlap. However, a list
|
||||
// may represent multiple different sets of registers,
|
||||
// e.g. [d0 s2 s3] <=> [s0 s1 d1].
|
||||
typedef uint64_t VfpRegList;
|
||||
|
||||
// Single word VFP register.
|
||||
class SwVfpRegister : public RegisterBase<SwVfpRegister, kSwVfpAfterLast> {
|
||||
public:
|
||||
static constexpr int kSizeInBytes = 4;
|
||||
|
||||
static void split_code(int reg_code, int* vm, int* m) {
|
||||
DCHECK(from_code(reg_code).is_valid());
|
||||
*m = reg_code & 0x1;
|
||||
*vm = reg_code >> 1;
|
||||
}
|
||||
void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
|
||||
VfpRegList ToVfpRegList() const {
|
||||
DCHECK(is_valid());
|
||||
// Each bit in the list corresponds to a S register.
|
||||
return uint64_t{0x1} << code();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr SwVfpRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(SwVfpRegister);
|
||||
static_assert(sizeof(SwVfpRegister) == sizeof(int),
|
||||
"SwVfpRegister can efficiently be passed by value");
|
||||
|
||||
typedef SwVfpRegister FloatRegister;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Double word VFP register.
|
||||
class DwVfpRegister : public RegisterBase<DwVfpRegister, kDoubleAfterLast> {
|
||||
public:
|
||||
static constexpr int kSizeInBytes = 8;
|
||||
|
||||
inline static int NumRegisters();
|
||||
|
||||
static void split_code(int reg_code, int* vm, int* m) {
|
||||
DCHECK(from_code(reg_code).is_valid());
|
||||
*m = (reg_code & 0x10) >> 4;
|
||||
*vm = reg_code & 0x0F;
|
||||
}
|
||||
void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
|
||||
VfpRegList ToVfpRegList() const {
|
||||
DCHECK(is_valid());
|
||||
// A D register overlaps two S registers.
|
||||
return uint64_t{0x3} << (code() * 2);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
friend class LowDwVfpRegister;
|
||||
explicit constexpr DwVfpRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(DwVfpRegister);
|
||||
static_assert(sizeof(DwVfpRegister) == sizeof(int),
|
||||
"DwVfpRegister can efficiently be passed by value");
|
||||
|
||||
typedef DwVfpRegister DoubleRegister;
|
||||
|
||||
// Double word VFP register d0-15.
|
||||
class LowDwVfpRegister
|
||||
: public RegisterBase<LowDwVfpRegister, kDoubleCode_d16> {
|
||||
public:
|
||||
constexpr operator DwVfpRegister() const { return DwVfpRegister(reg_code_); }
|
||||
|
||||
SwVfpRegister low() const { return SwVfpRegister::from_code(code() * 2); }
|
||||
SwVfpRegister high() const {
|
||||
return SwVfpRegister::from_code(code() * 2 + 1);
|
||||
}
|
||||
VfpRegList ToVfpRegList() const {
|
||||
DCHECK(is_valid());
|
||||
// A D register overlaps two S registers.
|
||||
return uint64_t{0x3} << (code() * 2);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr LowDwVfpRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
enum Simd128RegisterCode {
|
||||
#define REGISTER_CODE(R) kSimd128Code_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kSimd128AfterLast
|
||||
};
|
||||
|
||||
// Quad word NEON register.
|
||||
class QwNeonRegister : public RegisterBase<QwNeonRegister, kSimd128AfterLast> {
|
||||
public:
|
||||
static void split_code(int reg_code, int* vm, int* m) {
|
||||
DCHECK(from_code(reg_code).is_valid());
|
||||
int encoded_code = reg_code << 1;
|
||||
*m = (encoded_code & 0x10) >> 4;
|
||||
*vm = encoded_code & 0x0F;
|
||||
}
|
||||
void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
|
||||
DwVfpRegister low() const { return DwVfpRegister::from_code(code() * 2); }
|
||||
DwVfpRegister high() const {
|
||||
return DwVfpRegister::from_code(code() * 2 + 1);
|
||||
}
|
||||
VfpRegList ToVfpRegList() const {
|
||||
DCHECK(is_valid());
|
||||
// A Q register overlaps four S registers.
|
||||
return uint64_t{0xf} << (code() * 4);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr QwNeonRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
typedef QwNeonRegister QuadRegister;
|
||||
|
||||
typedef QwNeonRegister Simd128Register;
|
||||
|
||||
enum CRegisterCode {
|
||||
#define REGISTER_CODE(R) kCCode_##R,
|
||||
C_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kCAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register
|
||||
class CRegister : public RegisterBase<CRegister, kCAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr CRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// Support for the VFP registers s0 to s31 (d0 to d15).
|
||||
// Note that "s(N):s(N+1)" is the same as "d(N/2)".
|
||||
#define DECLARE_FLOAT_REGISTER(R) \
|
||||
constexpr SwVfpRegister R = SwVfpRegister::from_code<kSwVfpCode_##R>();
|
||||
FLOAT_REGISTERS(DECLARE_FLOAT_REGISTER)
|
||||
#undef DECLARE_FLOAT_REGISTER
|
||||
|
||||
#define DECLARE_LOW_DOUBLE_REGISTER(R) \
|
||||
constexpr LowDwVfpRegister R = LowDwVfpRegister::from_code<kDoubleCode_##R>();
|
||||
LOW_DOUBLE_REGISTERS(DECLARE_LOW_DOUBLE_REGISTER)
|
||||
#undef DECLARE_LOW_DOUBLE_REGISTER
|
||||
|
||||
#define DECLARE_DOUBLE_REGISTER(R) \
|
||||
constexpr DwVfpRegister R = DwVfpRegister::from_code<kDoubleCode_##R>();
|
||||
NON_LOW_DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
|
||||
#undef DECLARE_DOUBLE_REGISTER
|
||||
|
||||
constexpr DwVfpRegister no_dreg = DwVfpRegister::no_reg();
|
||||
|
||||
#define DECLARE_SIMD128_REGISTER(R) \
|
||||
constexpr Simd128Register R = Simd128Register::from_code<kSimd128Code_##R>();
|
||||
SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
|
||||
#undef DECLARE_SIMD128_REGISTER
|
||||
|
||||
// Aliases for double registers.
|
||||
constexpr LowDwVfpRegister kFirstCalleeSavedDoubleReg = d8;
|
||||
constexpr LowDwVfpRegister kLastCalleeSavedDoubleReg = d15;
|
||||
constexpr LowDwVfpRegister kDoubleRegZero = d13;
|
||||
|
||||
constexpr CRegister no_creg = CRegister::no_reg();
|
||||
|
||||
#define DECLARE_C_REGISTER(R) \
|
||||
constexpr CRegister R = CRegister::from_code<kCCode_##R>();
|
||||
C_REGISTERS(DECLARE_C_REGISTER)
|
||||
#undef DECLARE_C_REGISTER
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(SwVfpRegister, FLOAT_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(DwVfpRegister, DOUBLE_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(LowDwVfpRegister, LOW_DOUBLE_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(QwNeonRegister, SIMD128_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(CRegister, C_REGISTERS);
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = r0;
|
||||
constexpr Register kReturnRegister1 = r1;
|
||||
constexpr Register kReturnRegister2 = r2;
|
||||
constexpr Register kJSFunctionRegister = r1;
|
||||
constexpr Register kContextRegister = r7;
|
||||
constexpr Register kAllocateSizeRegister = r1;
|
||||
constexpr Register kSpeculationPoisonRegister = r9;
|
||||
constexpr Register kInterpreterAccumulatorRegister = r0;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = r5;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = r6;
|
||||
constexpr Register kInterpreterDispatchTableRegister = r8;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = r0;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = r2;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = r3;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = r2;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = ip;
|
||||
constexpr Register kRuntimeCallFunctionRegister = r1;
|
||||
constexpr Register kRuntimeCallArgCountRegister = r0;
|
||||
constexpr Register kRuntimeCallArgvRegister = r2;
|
||||
constexpr Register kWasmInstanceRegister = r3;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = r4;
|
||||
|
||||
// Give alias names to registers
|
||||
constexpr Register cp = r7; // JavaScript context pointer.
|
||||
constexpr Register kRootRegister = r10; // Roots array pointer.
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_ARM_REGISTER_ARM_H_
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "src/arm64/constants-arm64.h"
|
||||
#include "src/arm64/instructions-arm64.h"
|
||||
#include "src/arm64/register-arm64.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/constant-pool.h"
|
||||
@ -27,663 +28,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Registers.
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTER_CODE_LIST(R) \
|
||||
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
|
||||
R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \
|
||||
R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \
|
||||
R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
|
||||
|
||||
#define GENERAL_REGISTERS(R) \
|
||||
R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \
|
||||
R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
|
||||
R(x16) R(x17) R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) \
|
||||
R(x24) R(x25) R(x26) R(x27) R(x28) R(x29) R(x30) R(x31)
|
||||
|
||||
#if defined(V8_OS_WIN)
|
||||
// x18 is reserved as platform register on Windows ARM64.
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(R) \
|
||||
R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \
|
||||
R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
|
||||
R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x25) \
|
||||
R(x27) R(x28)
|
||||
#else
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(R) \
|
||||
R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \
|
||||
R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
|
||||
R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x25) \
|
||||
R(x27) R(x28)
|
||||
#endif
|
||||
|
||||
#define FLOAT_REGISTERS(V) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) \
|
||||
V(s8) V(s9) V(s10) V(s11) V(s12) V(s13) V(s14) V(s15) \
|
||||
V(s16) V(s17) V(s18) V(s19) V(s20) V(s21) V(s22) V(s23) \
|
||||
V(s24) V(s25) V(s26) V(s27) V(s28) V(s29) V(s30) V(s31)
|
||||
|
||||
#define DOUBLE_REGISTERS(R) \
|
||||
R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \
|
||||
R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d15) \
|
||||
R(d16) R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) \
|
||||
R(d24) R(d25) R(d26) R(d27) R(d28) R(d29) R(d30) R(d31)
|
||||
|
||||
#define SIMD128_REGISTERS(V) \
|
||||
V(q0) V(q1) V(q2) V(q3) V(q4) V(q5) V(q6) V(q7) \
|
||||
V(q8) V(q9) V(q10) V(q11) V(q12) V(q13) V(q14) V(q15) \
|
||||
V(q16) V(q17) V(q18) V(q19) V(q20) V(q21) V(q22) V(q23) \
|
||||
V(q24) V(q25) V(q26) V(q27) V(q28) V(q29) V(q30) V(q31)
|
||||
|
||||
// Register d29 could be allocated, but we keep an even length list here, in
|
||||
// order to make stack alignment easier for save and restore.
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(R) \
|
||||
R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \
|
||||
R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d16) \
|
||||
R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) R(d24) \
|
||||
R(d25) R(d26) R(d27) R(d28)
|
||||
// clang-format on
|
||||
|
||||
constexpr int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte;
|
||||
|
||||
const int kNumRegs = kNumberOfRegisters;
|
||||
// Registers x0-x17 are caller-saved.
|
||||
const int kNumJSCallerSaved = 18;
|
||||
const RegList kJSCallerSaved = 0x3ffff;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of eight.
|
||||
// TODO(all): Refine this number.
|
||||
const int kNumSafepointRegisters = 32;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
#define kSafepointSavedRegisters CPURegList::GetSafepointSavedRegisters().list()
|
||||
#define kNumSafepointSavedRegisters \
|
||||
CPURegList::GetSafepointSavedRegisters().Count()
|
||||
|
||||
// Some CPURegister methods can return Register and VRegister types, so we
|
||||
// need to declare them in advance.
|
||||
class Register;
|
||||
class VRegister;
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class CPURegister : public RegisterBase<CPURegister, kRegAfterLast> {
|
||||
public:
|
||||
enum RegisterType {
|
||||
kRegister,
|
||||
kVRegister,
|
||||
kNoRegister
|
||||
};
|
||||
|
||||
static constexpr CPURegister no_reg() {
|
||||
return CPURegister{0, 0, kNoRegister};
|
||||
}
|
||||
|
||||
template <int code, int size, RegisterType type>
|
||||
static constexpr CPURegister Create() {
|
||||
static_assert(IsValid(code, size, type), "Cannot create invalid registers");
|
||||
return CPURegister{code, size, type};
|
||||
}
|
||||
|
||||
static CPURegister Create(int code, int size, RegisterType type) {
|
||||
DCHECK(IsValid(code, size, type));
|
||||
return CPURegister{code, size, type};
|
||||
}
|
||||
|
||||
RegisterType type() const { return reg_type_; }
|
||||
int SizeInBits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_;
|
||||
}
|
||||
int SizeInBytes() const {
|
||||
DCHECK(IsValid());
|
||||
DCHECK_EQ(SizeInBits() % 8, 0);
|
||||
return reg_size_ / 8;
|
||||
}
|
||||
bool Is8Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 8;
|
||||
}
|
||||
bool Is16Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 16;
|
||||
}
|
||||
bool Is32Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 32;
|
||||
}
|
||||
bool Is64Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 64;
|
||||
}
|
||||
bool Is128Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 128;
|
||||
}
|
||||
bool IsValid() const { return reg_type_ != kNoRegister; }
|
||||
bool IsNone() const { return reg_type_ == kNoRegister; }
|
||||
bool Is(const CPURegister& other) const {
|
||||
return Aliases(other) && (reg_size_ == other.reg_size_);
|
||||
}
|
||||
bool Aliases(const CPURegister& other) const {
|
||||
return (reg_code_ == other.reg_code_) && (reg_type_ == other.reg_type_);
|
||||
}
|
||||
|
||||
bool IsZero() const;
|
||||
bool IsSP() const;
|
||||
|
||||
bool IsRegister() const { return reg_type_ == kRegister; }
|
||||
bool IsVRegister() const { return reg_type_ == kVRegister; }
|
||||
|
||||
bool IsFPRegister() const { return IsS() || IsD(); }
|
||||
|
||||
bool IsW() const { return IsRegister() && Is32Bits(); }
|
||||
bool IsX() const { return IsRegister() && Is64Bits(); }
|
||||
|
||||
// These assertions ensure that the size and type of the register are as
|
||||
// described. They do not consider the number of lanes that make up a vector.
|
||||
// So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD()
|
||||
// does not imply Is1D() or Is8B().
|
||||
// Check the number of lanes, ie. the format of the vector, using methods such
|
||||
// as Is8B(), Is1D(), etc. in the VRegister class.
|
||||
bool IsV() const { return IsVRegister(); }
|
||||
bool IsB() const { return IsV() && Is8Bits(); }
|
||||
bool IsH() const { return IsV() && Is16Bits(); }
|
||||
bool IsS() const { return IsV() && Is32Bits(); }
|
||||
bool IsD() const { return IsV() && Is64Bits(); }
|
||||
bool IsQ() const { return IsV() && Is128Bits(); }
|
||||
|
||||
Register Reg() const;
|
||||
VRegister VReg() const;
|
||||
|
||||
Register X() const;
|
||||
Register W() const;
|
||||
VRegister V() const;
|
||||
VRegister B() const;
|
||||
VRegister H() const;
|
||||
VRegister D() const;
|
||||
VRegister S() const;
|
||||
VRegister Q() const;
|
||||
|
||||
bool IsSameSizeAndType(const CPURegister& other) const;
|
||||
|
||||
bool is(const CPURegister& other) const { return Is(other); }
|
||||
bool is_valid() const { return IsValid(); }
|
||||
|
||||
protected:
|
||||
int reg_size_;
|
||||
RegisterType reg_type_;
|
||||
|
||||
#if defined(V8_OS_WIN) && !defined(__clang__)
|
||||
// MSVC has problem to parse template base class as friend class.
|
||||
friend RegisterBase;
|
||||
#else
|
||||
friend class RegisterBase;
|
||||
#endif
|
||||
|
||||
constexpr CPURegister(int code, int size, RegisterType type)
|
||||
: RegisterBase(code), reg_size_(size), reg_type_(type) {}
|
||||
|
||||
static constexpr bool IsValidRegister(int code, int size) {
|
||||
return (size == kWRegSizeInBits || size == kXRegSizeInBits) &&
|
||||
(code < kNumberOfRegisters || code == kSPRegInternalCode);
|
||||
}
|
||||
|
||||
static constexpr bool IsValidVRegister(int code, int size) {
|
||||
return (size == kBRegSizeInBits || size == kHRegSizeInBits ||
|
||||
size == kSRegSizeInBits || size == kDRegSizeInBits ||
|
||||
size == kQRegSizeInBits) &&
|
||||
code < kNumberOfVRegisters;
|
||||
}
|
||||
|
||||
static constexpr bool IsValid(int code, int size, RegisterType type) {
|
||||
return (type == kRegister && IsValidRegister(code, size)) ||
|
||||
(type == kVRegister && IsValidVRegister(code, size));
|
||||
}
|
||||
|
||||
static constexpr bool IsNone(int code, int size, RegisterType type) {
|
||||
return type == kNoRegister && code == 0 && size == 0;
|
||||
}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(CPURegister);
|
||||
|
||||
class Register : public CPURegister {
|
||||
public:
|
||||
static constexpr Register no_reg() { return Register(CPURegister::no_reg()); }
|
||||
|
||||
template <int code, int size>
|
||||
static constexpr Register Create() {
|
||||
return Register(CPURegister::Create<code, size, CPURegister::kRegister>());
|
||||
}
|
||||
|
||||
static Register Create(int code, int size) {
|
||||
return Register(CPURegister::Create(code, size, CPURegister::kRegister));
|
||||
}
|
||||
|
||||
static Register XRegFromCode(unsigned code);
|
||||
static Register WRegFromCode(unsigned code);
|
||||
|
||||
static Register from_code(int code) {
|
||||
// Always return an X register.
|
||||
return Register::Create(code, kXRegSizeInBits);
|
||||
}
|
||||
|
||||
template <int code>
|
||||
static Register from_code() {
|
||||
// Always return an X register.
|
||||
return Register::Create<code, kXRegSizeInBits>();
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr explicit Register(const CPURegister& r) : CPURegister(r) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
|
||||
constexpr bool kPadArguments = true;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
class VRegister : public CPURegister {
|
||||
public:
|
||||
static constexpr VRegister no_reg() {
|
||||
return VRegister(CPURegister::no_reg(), 0);
|
||||
}
|
||||
|
||||
template <int code, int size, int lane_count = 1>
|
||||
static constexpr VRegister Create() {
|
||||
static_assert(IsValidLaneCount(lane_count), "Invalid lane count");
|
||||
return VRegister(CPURegister::Create<code, size, kVRegister>(), lane_count);
|
||||
}
|
||||
|
||||
static VRegister Create(int code, int size, int lane_count = 1) {
|
||||
DCHECK(IsValidLaneCount(lane_count));
|
||||
return VRegister(CPURegister::Create(code, size, CPURegister::kVRegister),
|
||||
lane_count);
|
||||
}
|
||||
|
||||
static VRegister Create(int reg_code, VectorFormat format) {
|
||||
int reg_size = RegisterSizeInBitsFromFormat(format);
|
||||
int reg_count = IsVectorFormat(format) ? LaneCountFromFormat(format) : 1;
|
||||
return VRegister::Create(reg_code, reg_size, reg_count);
|
||||
}
|
||||
|
||||
static VRegister BRegFromCode(unsigned code);
|
||||
static VRegister HRegFromCode(unsigned code);
|
||||
static VRegister SRegFromCode(unsigned code);
|
||||
static VRegister DRegFromCode(unsigned code);
|
||||
static VRegister QRegFromCode(unsigned code);
|
||||
static VRegister VRegFromCode(unsigned code);
|
||||
|
||||
VRegister V8B() const {
|
||||
return VRegister::Create(code(), kDRegSizeInBits, 8);
|
||||
}
|
||||
VRegister V16B() const {
|
||||
return VRegister::Create(code(), kQRegSizeInBits, 16);
|
||||
}
|
||||
VRegister V4H() const {
|
||||
return VRegister::Create(code(), kDRegSizeInBits, 4);
|
||||
}
|
||||
VRegister V8H() const {
|
||||
return VRegister::Create(code(), kQRegSizeInBits, 8);
|
||||
}
|
||||
VRegister V2S() const {
|
||||
return VRegister::Create(code(), kDRegSizeInBits, 2);
|
||||
}
|
||||
VRegister V4S() const {
|
||||
return VRegister::Create(code(), kQRegSizeInBits, 4);
|
||||
}
|
||||
VRegister V2D() const {
|
||||
return VRegister::Create(code(), kQRegSizeInBits, 2);
|
||||
}
|
||||
VRegister V1D() const {
|
||||
return VRegister::Create(code(), kDRegSizeInBits, 1);
|
||||
}
|
||||
|
||||
bool Is8B() const { return (Is64Bits() && (lane_count_ == 8)); }
|
||||
bool Is16B() const { return (Is128Bits() && (lane_count_ == 16)); }
|
||||
bool Is4H() const { return (Is64Bits() && (lane_count_ == 4)); }
|
||||
bool Is8H() const { return (Is128Bits() && (lane_count_ == 8)); }
|
||||
bool Is2S() const { return (Is64Bits() && (lane_count_ == 2)); }
|
||||
bool Is4S() const { return (Is128Bits() && (lane_count_ == 4)); }
|
||||
bool Is1D() const { return (Is64Bits() && (lane_count_ == 1)); }
|
||||
bool Is2D() const { return (Is128Bits() && (lane_count_ == 2)); }
|
||||
|
||||
// For consistency, we assert the number of lanes of these scalar registers,
|
||||
// even though there are no vectors of equivalent total size with which they
|
||||
// could alias.
|
||||
bool Is1B() const {
|
||||
DCHECK(!(Is8Bits() && IsVector()));
|
||||
return Is8Bits();
|
||||
}
|
||||
bool Is1H() const {
|
||||
DCHECK(!(Is16Bits() && IsVector()));
|
||||
return Is16Bits();
|
||||
}
|
||||
bool Is1S() const {
|
||||
DCHECK(!(Is32Bits() && IsVector()));
|
||||
return Is32Bits();
|
||||
}
|
||||
|
||||
bool IsLaneSizeB() const { return LaneSizeInBits() == kBRegSizeInBits; }
|
||||
bool IsLaneSizeH() const { return LaneSizeInBits() == kHRegSizeInBits; }
|
||||
bool IsLaneSizeS() const { return LaneSizeInBits() == kSRegSizeInBits; }
|
||||
bool IsLaneSizeD() const { return LaneSizeInBits() == kDRegSizeInBits; }
|
||||
|
||||
bool IsScalar() const { return lane_count_ == 1; }
|
||||
bool IsVector() const { return lane_count_ > 1; }
|
||||
|
||||
bool IsSameFormat(const VRegister& other) const {
|
||||
return (reg_size_ == other.reg_size_) && (lane_count_ == other.lane_count_);
|
||||
}
|
||||
|
||||
int LaneCount() const { return lane_count_; }
|
||||
|
||||
unsigned LaneSizeInBytes() const { return SizeInBytes() / lane_count_; }
|
||||
|
||||
unsigned LaneSizeInBits() const { return LaneSizeInBytes() * 8; }
|
||||
|
||||
static constexpr int kMaxNumRegisters = kNumberOfVRegisters;
|
||||
STATIC_ASSERT(kMaxNumRegisters == kDoubleAfterLast);
|
||||
|
||||
static VRegister from_code(int code) {
|
||||
// Always return a D register.
|
||||
return VRegister::Create(code, kDRegSizeInBits);
|
||||
}
|
||||
|
||||
private:
|
||||
int lane_count_;
|
||||
|
||||
constexpr explicit VRegister(const CPURegister& r, int lane_count)
|
||||
: CPURegister(r), lane_count_(lane_count) {}
|
||||
|
||||
static constexpr bool IsValidLaneCount(int lane_count) {
|
||||
return base::bits::IsPowerOfTwo(lane_count) && lane_count <= 16;
|
||||
}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(VRegister);
|
||||
|
||||
// No*Reg is used to indicate an unused argument, or an error case. Note that
|
||||
// these all compare equal (using the Is() method). The Register and VRegister
|
||||
// variants are provided for convenience.
|
||||
constexpr Register NoReg = Register::no_reg();
|
||||
constexpr VRegister NoVReg = VRegister::no_reg();
|
||||
constexpr CPURegister NoCPUReg = CPURegister::no_reg();
|
||||
constexpr Register no_reg = NoReg;
|
||||
constexpr VRegister no_dreg = NoVReg;
|
||||
|
||||
#define DEFINE_REGISTER(register_class, name, ...) \
|
||||
constexpr register_class name = register_class::Create<__VA_ARGS__>()
|
||||
#define ALIAS_REGISTER(register_class, alias, name) \
|
||||
constexpr register_class alias = name
|
||||
|
||||
#define DEFINE_REGISTERS(N) \
|
||||
DEFINE_REGISTER(Register, w##N, N, kWRegSizeInBits); \
|
||||
DEFINE_REGISTER(Register, x##N, N, kXRegSizeInBits);
|
||||
GENERAL_REGISTER_CODE_LIST(DEFINE_REGISTERS)
|
||||
#undef DEFINE_REGISTERS
|
||||
|
||||
DEFINE_REGISTER(Register, wsp, kSPRegInternalCode, kWRegSizeInBits);
|
||||
DEFINE_REGISTER(Register, sp, kSPRegInternalCode, kXRegSizeInBits);
|
||||
|
||||
#define DEFINE_VREGISTERS(N) \
|
||||
DEFINE_REGISTER(VRegister, b##N, N, kBRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, h##N, N, kHRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, s##N, N, kSRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, d##N, N, kDRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, q##N, N, kQRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, v##N, N, kQRegSizeInBits);
|
||||
GENERAL_REGISTER_CODE_LIST(DEFINE_VREGISTERS)
|
||||
#undef DEFINE_VREGISTERS
|
||||
|
||||
#undef DEFINE_REGISTER
|
||||
|
||||
// Registers aliases.
|
||||
ALIAS_REGISTER(VRegister, v8_, v8); // Avoid conflicts with namespace v8.
|
||||
ALIAS_REGISTER(Register, ip0, x16);
|
||||
ALIAS_REGISTER(Register, ip1, x17);
|
||||
ALIAS_REGISTER(Register, wip0, w16);
|
||||
ALIAS_REGISTER(Register, wip1, w17);
|
||||
// Root register.
|
||||
ALIAS_REGISTER(Register, kRootRegister, x26);
|
||||
ALIAS_REGISTER(Register, rr, x26);
|
||||
// Context pointer register.
|
||||
ALIAS_REGISTER(Register, cp, x27);
|
||||
ALIAS_REGISTER(Register, fp, x29);
|
||||
ALIAS_REGISTER(Register, lr, x30);
|
||||
ALIAS_REGISTER(Register, xzr, x31);
|
||||
ALIAS_REGISTER(Register, wzr, w31);
|
||||
|
||||
// Register used for padding stack slots.
|
||||
ALIAS_REGISTER(Register, padreg, x31);
|
||||
|
||||
// Keeps the 0 double value.
|
||||
ALIAS_REGISTER(VRegister, fp_zero, d15);
|
||||
// MacroAssembler fixed V Registers.
|
||||
ALIAS_REGISTER(VRegister, fp_fixed1, d28);
|
||||
ALIAS_REGISTER(VRegister, fp_fixed2, d29);
|
||||
|
||||
// MacroAssembler scratch V registers.
|
||||
ALIAS_REGISTER(VRegister, fp_scratch, d30);
|
||||
ALIAS_REGISTER(VRegister, fp_scratch1, d30);
|
||||
ALIAS_REGISTER(VRegister, fp_scratch2, d31);
|
||||
|
||||
#undef ALIAS_REGISTER
|
||||
|
||||
// AreAliased returns true if any of the named registers overlap. Arguments set
|
||||
// to NoReg are ignored. The system stack pointer may be specified.
|
||||
bool AreAliased(const CPURegister& reg1,
|
||||
const CPURegister& reg2,
|
||||
const CPURegister& reg3 = NoReg,
|
||||
const CPURegister& reg4 = NoReg,
|
||||
const CPURegister& reg5 = NoReg,
|
||||
const CPURegister& reg6 = NoReg,
|
||||
const CPURegister& reg7 = NoReg,
|
||||
const CPURegister& reg8 = NoReg);
|
||||
|
||||
// AreSameSizeAndType returns true if all of the specified registers have the
|
||||
// same size, and are of the same type. The system stack pointer may be
|
||||
// specified. Arguments set to NoReg are ignored, as are any subsequent
|
||||
// arguments. At least one argument (reg1) must be valid (not NoCPUReg).
|
||||
bool AreSameSizeAndType(
|
||||
const CPURegister& reg1, const CPURegister& reg2 = NoCPUReg,
|
||||
const CPURegister& reg3 = NoCPUReg, const CPURegister& reg4 = NoCPUReg,
|
||||
const CPURegister& reg5 = NoCPUReg, const CPURegister& reg6 = NoCPUReg,
|
||||
const CPURegister& reg7 = NoCPUReg, const CPURegister& reg8 = NoCPUReg);
|
||||
|
||||
// AreSameFormat returns true if all of the specified VRegisters have the same
|
||||
// vector format. Arguments set to NoVReg are ignored, as are any subsequent
|
||||
// arguments. At least one argument (reg1) must be valid (not NoVReg).
|
||||
bool AreSameFormat(const VRegister& reg1, const VRegister& reg2,
|
||||
const VRegister& reg3 = NoVReg,
|
||||
const VRegister& reg4 = NoVReg);
|
||||
|
||||
// AreConsecutive returns true if all of the specified VRegisters are
|
||||
// consecutive in the register file. Arguments may be set to NoVReg, and if so,
|
||||
// subsequent arguments must also be NoVReg. At least one argument (reg1) must
|
||||
// be valid (not NoVReg).
|
||||
bool AreConsecutive(const VRegister& reg1, const VRegister& reg2,
|
||||
const VRegister& reg3 = NoVReg,
|
||||
const VRegister& reg4 = NoVReg);
|
||||
|
||||
typedef VRegister FloatRegister;
|
||||
typedef VRegister DoubleRegister;
|
||||
typedef VRegister Simd128Register;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Lists of registers.
|
||||
class CPURegList {
|
||||
public:
|
||||
template <typename... CPURegisters>
|
||||
explicit CPURegList(CPURegister reg0, CPURegisters... regs)
|
||||
: list_(CPURegister::ListOf(reg0, regs...)),
|
||||
size_(reg0.SizeInBits()),
|
||||
type_(reg0.type()) {
|
||||
DCHECK(AreSameSizeAndType(reg0, regs...));
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
CPURegList(CPURegister::RegisterType type, int size, RegList list)
|
||||
: list_(list), size_(size), type_(type) {
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
CPURegList(CPURegister::RegisterType type, int size, int first_reg,
|
||||
int last_reg)
|
||||
: size_(size), type_(type) {
|
||||
DCHECK(
|
||||
((type == CPURegister::kRegister) && (last_reg < kNumberOfRegisters)) ||
|
||||
((type == CPURegister::kVRegister) &&
|
||||
(last_reg < kNumberOfVRegisters)));
|
||||
DCHECK(last_reg >= first_reg);
|
||||
list_ = (1ULL << (last_reg + 1)) - 1;
|
||||
list_ &= ~((1ULL << first_reg) - 1);
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
CPURegister::RegisterType type() const {
|
||||
DCHECK(IsValid());
|
||||
return type_;
|
||||
}
|
||||
|
||||
RegList list() const {
|
||||
DCHECK(IsValid());
|
||||
return list_;
|
||||
}
|
||||
|
||||
inline void set_list(RegList new_list) {
|
||||
DCHECK(IsValid());
|
||||
list_ = new_list;
|
||||
}
|
||||
|
||||
// Combine another CPURegList into this one. Registers that already exist in
|
||||
// this list are left unchanged. The type and size of the registers in the
|
||||
// 'other' list must match those in this list.
|
||||
void Combine(const CPURegList& other);
|
||||
|
||||
// Remove every register in the other CPURegList from this one. Registers that
|
||||
// do not exist in this list are ignored. The type of the registers in the
|
||||
// 'other' list must match those in this list.
|
||||
void Remove(const CPURegList& other);
|
||||
|
||||
// Variants of Combine and Remove which take CPURegisters.
|
||||
void Combine(const CPURegister& other);
|
||||
void Remove(const CPURegister& other1,
|
||||
const CPURegister& other2 = NoCPUReg,
|
||||
const CPURegister& other3 = NoCPUReg,
|
||||
const CPURegister& other4 = NoCPUReg);
|
||||
|
||||
// Variants of Combine and Remove which take a single register by its code;
|
||||
// the type and size of the register is inferred from this list.
|
||||
void Combine(int code);
|
||||
void Remove(int code);
|
||||
|
||||
// Remove all callee-saved registers from the list. This can be useful when
|
||||
// preparing registers for an AAPCS64 function call, for example.
|
||||
void RemoveCalleeSaved();
|
||||
|
||||
CPURegister PopLowestIndex();
|
||||
CPURegister PopHighestIndex();
|
||||
|
||||
// AAPCS64 callee-saved registers.
|
||||
static CPURegList GetCalleeSaved(int size = kXRegSizeInBits);
|
||||
static CPURegList GetCalleeSavedV(int size = kDRegSizeInBits);
|
||||
|
||||
// AAPCS64 caller-saved registers. Note that this includes lr.
|
||||
// TODO(all): Determine how we handle d8-d15 being callee-saved, but the top
|
||||
// 64-bits being caller-saved.
|
||||
static CPURegList GetCallerSaved(int size = kXRegSizeInBits);
|
||||
static CPURegList GetCallerSavedV(int size = kDRegSizeInBits);
|
||||
|
||||
// Registers saved as safepoints.
|
||||
static CPURegList GetSafepointSavedRegisters();
|
||||
|
||||
bool IsEmpty() const {
|
||||
DCHECK(IsValid());
|
||||
return list_ == 0;
|
||||
}
|
||||
|
||||
bool IncludesAliasOf(const CPURegister& other1,
|
||||
const CPURegister& other2 = NoCPUReg,
|
||||
const CPURegister& other3 = NoCPUReg,
|
||||
const CPURegister& other4 = NoCPUReg) const {
|
||||
DCHECK(IsValid());
|
||||
RegList list = 0;
|
||||
if (!other1.IsNone() && (other1.type() == type_)) list |= other1.bit();
|
||||
if (!other2.IsNone() && (other2.type() == type_)) list |= other2.bit();
|
||||
if (!other3.IsNone() && (other3.type() == type_)) list |= other3.bit();
|
||||
if (!other4.IsNone() && (other4.type() == type_)) list |= other4.bit();
|
||||
return (list_ & list) != 0;
|
||||
}
|
||||
|
||||
int Count() const {
|
||||
DCHECK(IsValid());
|
||||
return CountSetBits(list_, kRegListSizeInBits);
|
||||
}
|
||||
|
||||
int RegisterSizeInBits() const {
|
||||
DCHECK(IsValid());
|
||||
return size_;
|
||||
}
|
||||
|
||||
int RegisterSizeInBytes() const {
|
||||
int size_in_bits = RegisterSizeInBits();
|
||||
DCHECK_EQ(size_in_bits % kBitsPerByte, 0);
|
||||
return size_in_bits / kBitsPerByte;
|
||||
}
|
||||
|
||||
int TotalSizeInBytes() const {
|
||||
DCHECK(IsValid());
|
||||
return RegisterSizeInBytes() * Count();
|
||||
}
|
||||
|
||||
private:
|
||||
RegList list_;
|
||||
int size_;
|
||||
CPURegister::RegisterType type_;
|
||||
|
||||
bool IsValid() const {
|
||||
constexpr RegList kValidRegisters{0x8000000ffffffff};
|
||||
constexpr RegList kValidVRegisters{0x0000000ffffffff};
|
||||
switch (type_) {
|
||||
case CPURegister::kRegister:
|
||||
return (list_ & kValidRegisters) == list_;
|
||||
case CPURegister::kVRegister:
|
||||
return (list_ & kValidVRegisters) == list_;
|
||||
case CPURegister::kNoRegister:
|
||||
return list_ == 0;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// AAPCS64 callee-saved registers.
|
||||
#define kCalleeSaved CPURegList::GetCalleeSaved()
|
||||
#define kCalleeSavedV CPURegList::GetCalleeSavedV()
|
||||
|
||||
// AAPCS64 caller-saved registers. Note that this includes lr.
|
||||
#define kCallerSaved CPURegList::GetCallerSaved()
|
||||
#define kCallerSavedV CPURegList::GetCallerSavedV()
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Immediates.
|
||||
class Immediate {
|
||||
@ -2875,10 +2219,6 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||
return reinterpret_cast<byte*>(instr) - buffer_;
|
||||
}
|
||||
|
||||
static const char* GetSpecialRegisterName(int code) {
|
||||
return (code == kSPRegInternalCode) ? "sp" : "UNKNOWN";
|
||||
}
|
||||
|
||||
// Register encoding.
|
||||
static Instr Rd(CPURegister rd) {
|
||||
DCHECK_NE(rd.code(), kSPRegInternalCode);
|
||||
@ -3632,9 +2972,6 @@ class EnsureSpace {
|
||||
}
|
||||
};
|
||||
|
||||
// Define a {RegisterName} method for {CPURegister}.
|
||||
DEFINE_REGISTER_NAMES(CPURegister, GENERAL_REGISTERS);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "src/arm64/utils-arm64.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "src/disasm.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -343,289 +343,6 @@ uint64_t InstructionSequence::InlineData() const {
|
||||
return payload;
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatHalfWidth(VectorFormat vform) {
|
||||
DCHECK(vform == kFormat8H || vform == kFormat4S || vform == kFormat2D ||
|
||||
vform == kFormatH || vform == kFormatS || vform == kFormatD);
|
||||
switch (vform) {
|
||||
case kFormat8H:
|
||||
return kFormat8B;
|
||||
case kFormat4S:
|
||||
return kFormat4H;
|
||||
case kFormat2D:
|
||||
return kFormat2S;
|
||||
case kFormatH:
|
||||
return kFormatB;
|
||||
case kFormatS:
|
||||
return kFormatH;
|
||||
case kFormatD:
|
||||
return kFormatS;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatDoubleWidth(VectorFormat vform) {
|
||||
DCHECK(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S ||
|
||||
vform == kFormatB || vform == kFormatH || vform == kFormatS);
|
||||
switch (vform) {
|
||||
case kFormat8B:
|
||||
return kFormat8H;
|
||||
case kFormat4H:
|
||||
return kFormat4S;
|
||||
case kFormat2S:
|
||||
return kFormat2D;
|
||||
case kFormatB:
|
||||
return kFormatH;
|
||||
case kFormatH:
|
||||
return kFormatS;
|
||||
case kFormatS:
|
||||
return kFormatD;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatFillQ(VectorFormat vform) {
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormat8B:
|
||||
case kFormat16B:
|
||||
return kFormat16B;
|
||||
case kFormatH:
|
||||
case kFormat4H:
|
||||
case kFormat8H:
|
||||
return kFormat8H;
|
||||
case kFormatS:
|
||||
case kFormat2S:
|
||||
case kFormat4S:
|
||||
return kFormat4S;
|
||||
case kFormatD:
|
||||
case kFormat1D:
|
||||
case kFormat2D:
|
||||
return kFormat2D;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform) {
|
||||
switch (vform) {
|
||||
case kFormat4H:
|
||||
return kFormat8B;
|
||||
case kFormat8H:
|
||||
return kFormat16B;
|
||||
case kFormat2S:
|
||||
return kFormat4H;
|
||||
case kFormat4S:
|
||||
return kFormat8H;
|
||||
case kFormat1D:
|
||||
return kFormat2S;
|
||||
case kFormat2D:
|
||||
return kFormat4S;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatDoubleLanes(VectorFormat vform) {
|
||||
DCHECK(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S);
|
||||
switch (vform) {
|
||||
case kFormat8B:
|
||||
return kFormat16B;
|
||||
case kFormat4H:
|
||||
return kFormat8H;
|
||||
case kFormat2S:
|
||||
return kFormat4S;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatHalfLanes(VectorFormat vform) {
|
||||
DCHECK(vform == kFormat16B || vform == kFormat8H || vform == kFormat4S);
|
||||
switch (vform) {
|
||||
case kFormat16B:
|
||||
return kFormat8B;
|
||||
case kFormat8H:
|
||||
return kFormat4H;
|
||||
case kFormat4S:
|
||||
return kFormat2S;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat ScalarFormatFromLaneSize(int laneSize) {
|
||||
switch (laneSize) {
|
||||
case 8:
|
||||
return kFormatB;
|
||||
case 16:
|
||||
return kFormatH;
|
||||
case 32:
|
||||
return kFormatS;
|
||||
case 64:
|
||||
return kFormatD;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat ScalarFormatFromFormat(VectorFormat vform) {
|
||||
return ScalarFormatFromLaneSize(LaneSizeInBitsFromFormat(vform));
|
||||
}
|
||||
|
||||
unsigned RegisterSizeInBytesFromFormat(VectorFormat vform) {
|
||||
return RegisterSizeInBitsFromFormat(vform) / 8;
|
||||
}
|
||||
|
||||
unsigned RegisterSizeInBitsFromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
return kBRegSizeInBits;
|
||||
case kFormatH:
|
||||
return kHRegSizeInBits;
|
||||
case kFormatS:
|
||||
return kSRegSizeInBits;
|
||||
case kFormatD:
|
||||
return kDRegSizeInBits;
|
||||
case kFormat8B:
|
||||
case kFormat4H:
|
||||
case kFormat2S:
|
||||
case kFormat1D:
|
||||
return kDRegSizeInBits;
|
||||
default:
|
||||
return kQRegSizeInBits;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned LaneSizeInBitsFromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormat8B:
|
||||
case kFormat16B:
|
||||
return 8;
|
||||
case kFormatH:
|
||||
case kFormat4H:
|
||||
case kFormat8H:
|
||||
return 16;
|
||||
case kFormatS:
|
||||
case kFormat2S:
|
||||
case kFormat4S:
|
||||
return 32;
|
||||
case kFormatD:
|
||||
case kFormat1D:
|
||||
case kFormat2D:
|
||||
return 64;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
int LaneSizeInBytesFromFormat(VectorFormat vform) {
|
||||
return LaneSizeInBitsFromFormat(vform) / 8;
|
||||
}
|
||||
|
||||
int LaneSizeInBytesLog2FromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormat8B:
|
||||
case kFormat16B:
|
||||
return 0;
|
||||
case kFormatH:
|
||||
case kFormat4H:
|
||||
case kFormat8H:
|
||||
return 1;
|
||||
case kFormatS:
|
||||
case kFormat2S:
|
||||
case kFormat4S:
|
||||
return 2;
|
||||
case kFormatD:
|
||||
case kFormat1D:
|
||||
case kFormat2D:
|
||||
return 3;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
int LaneCountFromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormat16B:
|
||||
return 16;
|
||||
case kFormat8B:
|
||||
case kFormat8H:
|
||||
return 8;
|
||||
case kFormat4H:
|
||||
case kFormat4S:
|
||||
return 4;
|
||||
case kFormat2S:
|
||||
case kFormat2D:
|
||||
return 2;
|
||||
case kFormat1D:
|
||||
case kFormatB:
|
||||
case kFormatH:
|
||||
case kFormatS:
|
||||
case kFormatD:
|
||||
return 1;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
int MaxLaneCountFromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormat8B:
|
||||
case kFormat16B:
|
||||
return 16;
|
||||
case kFormatH:
|
||||
case kFormat4H:
|
||||
case kFormat8H:
|
||||
return 8;
|
||||
case kFormatS:
|
||||
case kFormat2S:
|
||||
case kFormat4S:
|
||||
return 4;
|
||||
case kFormatD:
|
||||
case kFormat1D:
|
||||
case kFormat2D:
|
||||
return 2;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Does 'vform' indicate a vector format or a scalar format?
|
||||
bool IsVectorFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormatH:
|
||||
case kFormatS:
|
||||
case kFormatD:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t MaxIntFromFormat(VectorFormat vform) {
|
||||
return INT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform));
|
||||
}
|
||||
|
||||
int64_t MinIntFromFormat(VectorFormat vform) {
|
||||
return INT64_MIN >> (64 - LaneSizeInBitsFromFormat(vform));
|
||||
}
|
||||
|
||||
uint64_t MaxUintFromFormat(VectorFormat vform) {
|
||||
return UINT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform));
|
||||
}
|
||||
|
||||
NEONFormatDecoder::NEONFormatDecoder(const Instruction* instr) {
|
||||
instrbits_ = instr->InstructionBits();
|
||||
SetFormatMaps(IntegerFormatMap());
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define V8_ARM64_INSTRUCTIONS_ARM64_H_
|
||||
|
||||
#include "src/arm64/constants-arm64.h"
|
||||
#include "src/arm64/register-arm64.h"
|
||||
#include "src/arm64/utils-arm64.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/utils.h"
|
||||
@ -453,49 +454,6 @@ class Instruction {
|
||||
void SetBranchImmTarget(Instruction* target);
|
||||
};
|
||||
|
||||
// Functions for handling NEON vector format information.
|
||||
enum VectorFormat {
|
||||
kFormatUndefined = 0xffffffff,
|
||||
kFormat8B = NEON_8B,
|
||||
kFormat16B = NEON_16B,
|
||||
kFormat4H = NEON_4H,
|
||||
kFormat8H = NEON_8H,
|
||||
kFormat2S = NEON_2S,
|
||||
kFormat4S = NEON_4S,
|
||||
kFormat1D = NEON_1D,
|
||||
kFormat2D = NEON_2D,
|
||||
|
||||
// Scalar formats. We add the scalar bit to distinguish between scalar and
|
||||
// vector enumerations; the bit is always set in the encoding of scalar ops
|
||||
// and always clear for vector ops. Although kFormatD and kFormat1D appear
|
||||
// to be the same, their meaning is subtly different. The first is a scalar
|
||||
// operation, the second a vector operation that only affects one lane.
|
||||
kFormatB = NEON_B | NEONScalar,
|
||||
kFormatH = NEON_H | NEONScalar,
|
||||
kFormatS = NEON_S | NEONScalar,
|
||||
kFormatD = NEON_D | NEONScalar
|
||||
};
|
||||
|
||||
VectorFormat VectorFormatHalfWidth(VectorFormat vform);
|
||||
VectorFormat VectorFormatDoubleWidth(VectorFormat vform);
|
||||
VectorFormat VectorFormatDoubleLanes(VectorFormat vform);
|
||||
VectorFormat VectorFormatHalfLanes(VectorFormat vform);
|
||||
VectorFormat ScalarFormatFromLaneSize(int lanesize);
|
||||
VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform);
|
||||
VectorFormat VectorFormatFillQ(VectorFormat vform);
|
||||
VectorFormat ScalarFormatFromFormat(VectorFormat vform);
|
||||
unsigned RegisterSizeInBitsFromFormat(VectorFormat vform);
|
||||
unsigned RegisterSizeInBytesFromFormat(VectorFormat vform);
|
||||
int LaneSizeInBytesFromFormat(VectorFormat vform);
|
||||
unsigned LaneSizeInBitsFromFormat(VectorFormat vform);
|
||||
int LaneSizeInBytesLog2FromFormat(VectorFormat vform);
|
||||
int LaneCountFromFormat(VectorFormat vform);
|
||||
int MaxLaneCountFromFormat(VectorFormat vform);
|
||||
bool IsVectorFormat(VectorFormat vform);
|
||||
int64_t MaxIntFromFormat(VectorFormat vform);
|
||||
int64_t MinIntFromFormat(VectorFormat vform);
|
||||
uint64_t MaxUintFromFormat(VectorFormat vform);
|
||||
|
||||
// Where Instruction looks at instructions generated by the Assembler,
|
||||
// InstructionSequence looks at instructions sequences generated by the
|
||||
// MacroAssembler.
|
||||
|
@ -5,7 +5,8 @@
|
||||
#if V8_TARGET_ARCH_ARM64
|
||||
|
||||
#include "src/interface-descriptors.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
#include "src/frames.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -44,39 +44,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = x0;
|
||||
constexpr Register kReturnRegister1 = x1;
|
||||
constexpr Register kReturnRegister2 = x2;
|
||||
constexpr Register kJSFunctionRegister = x1;
|
||||
constexpr Register kContextRegister = cp;
|
||||
constexpr Register kAllocateSizeRegister = x1;
|
||||
|
||||
#if defined(V8_OS_WIN)
|
||||
// x18 is reserved as platform register on Windows ARM64.
|
||||
constexpr Register kSpeculationPoisonRegister = x23;
|
||||
#else
|
||||
constexpr Register kSpeculationPoisonRegister = x18;
|
||||
#endif
|
||||
|
||||
constexpr Register kInterpreterAccumulatorRegister = x0;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = x19;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = x20;
|
||||
constexpr Register kInterpreterDispatchTableRegister = x21;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = x0;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = x2;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = x3;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = x2;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = ip0;
|
||||
constexpr Register kRuntimeCallFunctionRegister = x1;
|
||||
constexpr Register kRuntimeCallArgCountRegister = x0;
|
||||
constexpr Register kRuntimeCallArgvRegister = x11;
|
||||
constexpr Register kWasmInstanceRegister = x7;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = x8;
|
||||
|
||||
#define LS_MACRO_LIST(V) \
|
||||
V(Ldrb, Register&, rt, LDRB_w) \
|
||||
V(Strb, Register&, rt, STRB_w) \
|
||||
|
298
src/arm64/register-arm64.cc
Normal file
298
src/arm64/register-arm64.cc
Normal file
@ -0,0 +1,298 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
#if V8_TARGET_ARCH_ARM64
|
||||
|
||||
#include "src/arm64/register-arm64.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
VectorFormat VectorFormatHalfWidth(VectorFormat vform) {
|
||||
DCHECK(vform == kFormat8H || vform == kFormat4S || vform == kFormat2D ||
|
||||
vform == kFormatH || vform == kFormatS || vform == kFormatD);
|
||||
switch (vform) {
|
||||
case kFormat8H:
|
||||
return kFormat8B;
|
||||
case kFormat4S:
|
||||
return kFormat4H;
|
||||
case kFormat2D:
|
||||
return kFormat2S;
|
||||
case kFormatH:
|
||||
return kFormatB;
|
||||
case kFormatS:
|
||||
return kFormatH;
|
||||
case kFormatD:
|
||||
return kFormatS;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatDoubleWidth(VectorFormat vform) {
|
||||
DCHECK(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S ||
|
||||
vform == kFormatB || vform == kFormatH || vform == kFormatS);
|
||||
switch (vform) {
|
||||
case kFormat8B:
|
||||
return kFormat8H;
|
||||
case kFormat4H:
|
||||
return kFormat4S;
|
||||
case kFormat2S:
|
||||
return kFormat2D;
|
||||
case kFormatB:
|
||||
return kFormatH;
|
||||
case kFormatH:
|
||||
return kFormatS;
|
||||
case kFormatS:
|
||||
return kFormatD;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatFillQ(VectorFormat vform) {
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormat8B:
|
||||
case kFormat16B:
|
||||
return kFormat16B;
|
||||
case kFormatH:
|
||||
case kFormat4H:
|
||||
case kFormat8H:
|
||||
return kFormat8H;
|
||||
case kFormatS:
|
||||
case kFormat2S:
|
||||
case kFormat4S:
|
||||
return kFormat4S;
|
||||
case kFormatD:
|
||||
case kFormat1D:
|
||||
case kFormat2D:
|
||||
return kFormat2D;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform) {
|
||||
switch (vform) {
|
||||
case kFormat4H:
|
||||
return kFormat8B;
|
||||
case kFormat8H:
|
||||
return kFormat16B;
|
||||
case kFormat2S:
|
||||
return kFormat4H;
|
||||
case kFormat4S:
|
||||
return kFormat8H;
|
||||
case kFormat1D:
|
||||
return kFormat2S;
|
||||
case kFormat2D:
|
||||
return kFormat4S;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatDoubleLanes(VectorFormat vform) {
|
||||
DCHECK(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S);
|
||||
switch (vform) {
|
||||
case kFormat8B:
|
||||
return kFormat16B;
|
||||
case kFormat4H:
|
||||
return kFormat8H;
|
||||
case kFormat2S:
|
||||
return kFormat4S;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat VectorFormatHalfLanes(VectorFormat vform) {
|
||||
DCHECK(vform == kFormat16B || vform == kFormat8H || vform == kFormat4S);
|
||||
switch (vform) {
|
||||
case kFormat16B:
|
||||
return kFormat8B;
|
||||
case kFormat8H:
|
||||
return kFormat4H;
|
||||
case kFormat4S:
|
||||
return kFormat2S;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat ScalarFormatFromLaneSize(int laneSize) {
|
||||
switch (laneSize) {
|
||||
case 8:
|
||||
return kFormatB;
|
||||
case 16:
|
||||
return kFormatH;
|
||||
case 32:
|
||||
return kFormatS;
|
||||
case 64:
|
||||
return kFormatD;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
VectorFormat ScalarFormatFromFormat(VectorFormat vform) {
|
||||
return ScalarFormatFromLaneSize(LaneSizeInBitsFromFormat(vform));
|
||||
}
|
||||
|
||||
unsigned RegisterSizeInBytesFromFormat(VectorFormat vform) {
|
||||
return RegisterSizeInBitsFromFormat(vform) / 8;
|
||||
}
|
||||
|
||||
unsigned RegisterSizeInBitsFromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
return kBRegSizeInBits;
|
||||
case kFormatH:
|
||||
return kHRegSizeInBits;
|
||||
case kFormatS:
|
||||
return kSRegSizeInBits;
|
||||
case kFormatD:
|
||||
return kDRegSizeInBits;
|
||||
case kFormat8B:
|
||||
case kFormat4H:
|
||||
case kFormat2S:
|
||||
case kFormat1D:
|
||||
return kDRegSizeInBits;
|
||||
default:
|
||||
return kQRegSizeInBits;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned LaneSizeInBitsFromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormat8B:
|
||||
case kFormat16B:
|
||||
return 8;
|
||||
case kFormatH:
|
||||
case kFormat4H:
|
||||
case kFormat8H:
|
||||
return 16;
|
||||
case kFormatS:
|
||||
case kFormat2S:
|
||||
case kFormat4S:
|
||||
return 32;
|
||||
case kFormatD:
|
||||
case kFormat1D:
|
||||
case kFormat2D:
|
||||
return 64;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
int LaneSizeInBytesFromFormat(VectorFormat vform) {
|
||||
return LaneSizeInBitsFromFormat(vform) / 8;
|
||||
}
|
||||
|
||||
int LaneSizeInBytesLog2FromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormat8B:
|
||||
case kFormat16B:
|
||||
return 0;
|
||||
case kFormatH:
|
||||
case kFormat4H:
|
||||
case kFormat8H:
|
||||
return 1;
|
||||
case kFormatS:
|
||||
case kFormat2S:
|
||||
case kFormat4S:
|
||||
return 2;
|
||||
case kFormatD:
|
||||
case kFormat1D:
|
||||
case kFormat2D:
|
||||
return 3;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
int LaneCountFromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormat16B:
|
||||
return 16;
|
||||
case kFormat8B:
|
||||
case kFormat8H:
|
||||
return 8;
|
||||
case kFormat4H:
|
||||
case kFormat4S:
|
||||
return 4;
|
||||
case kFormat2S:
|
||||
case kFormat2D:
|
||||
return 2;
|
||||
case kFormat1D:
|
||||
case kFormatB:
|
||||
case kFormatH:
|
||||
case kFormatS:
|
||||
case kFormatD:
|
||||
return 1;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
int MaxLaneCountFromFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormat8B:
|
||||
case kFormat16B:
|
||||
return 16;
|
||||
case kFormatH:
|
||||
case kFormat4H:
|
||||
case kFormat8H:
|
||||
return 8;
|
||||
case kFormatS:
|
||||
case kFormat2S:
|
||||
case kFormat4S:
|
||||
return 4;
|
||||
case kFormatD:
|
||||
case kFormat1D:
|
||||
case kFormat2D:
|
||||
return 2;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Does 'vform' indicate a vector format or a scalar format?
|
||||
bool IsVectorFormat(VectorFormat vform) {
|
||||
DCHECK_NE(vform, kFormatUndefined);
|
||||
switch (vform) {
|
||||
case kFormatB:
|
||||
case kFormatH:
|
||||
case kFormatS:
|
||||
case kFormatD:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t MaxIntFromFormat(VectorFormat vform) {
|
||||
return INT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform));
|
||||
}
|
||||
|
||||
int64_t MinIntFromFormat(VectorFormat vform) {
|
||||
return INT64_MIN >> (64 - LaneSizeInBitsFromFormat(vform));
|
||||
}
|
||||
|
||||
uint64_t MaxUintFromFormat(VectorFormat vform) {
|
||||
return UINT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_TARGET_ARCH_ARM64
|
752
src/arm64/register-arm64.h
Normal file
752
src/arm64/register-arm64.h
Normal file
@ -0,0 +1,752 @@
|
||||
// Copyright 2018 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_ARM64_REGISTER_ARM64_H_
|
||||
#define V8_ARM64_REGISTER_ARM64_H_
|
||||
|
||||
#include "src/arm64/utils-arm64.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/register.h"
|
||||
#include "src/reglist.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Registers.
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTER_CODE_LIST(R) \
|
||||
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
|
||||
R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \
|
||||
R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \
|
||||
R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
|
||||
|
||||
#define GENERAL_REGISTERS(R) \
|
||||
R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \
|
||||
R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
|
||||
R(x16) R(x17) R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) \
|
||||
R(x24) R(x25) R(x26) R(x27) R(x28) R(x29) R(x30) R(x31)
|
||||
|
||||
#if defined(V8_OS_WIN)
|
||||
// x18 is reserved as platform register on Windows ARM64.
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(R) \
|
||||
R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \
|
||||
R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
|
||||
R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x25) \
|
||||
R(x27) R(x28)
|
||||
#else
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(R) \
|
||||
R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \
|
||||
R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
|
||||
R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x25) \
|
||||
R(x27) R(x28)
|
||||
#endif
|
||||
|
||||
#define FLOAT_REGISTERS(V) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) \
|
||||
V(s8) V(s9) V(s10) V(s11) V(s12) V(s13) V(s14) V(s15) \
|
||||
V(s16) V(s17) V(s18) V(s19) V(s20) V(s21) V(s22) V(s23) \
|
||||
V(s24) V(s25) V(s26) V(s27) V(s28) V(s29) V(s30) V(s31)
|
||||
|
||||
#define DOUBLE_REGISTERS(R) \
|
||||
R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \
|
||||
R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d15) \
|
||||
R(d16) R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) \
|
||||
R(d24) R(d25) R(d26) R(d27) R(d28) R(d29) R(d30) R(d31)
|
||||
|
||||
#define SIMD128_REGISTERS(V) \
|
||||
V(q0) V(q1) V(q2) V(q3) V(q4) V(q5) V(q6) V(q7) \
|
||||
V(q8) V(q9) V(q10) V(q11) V(q12) V(q13) V(q14) V(q15) \
|
||||
V(q16) V(q17) V(q18) V(q19) V(q20) V(q21) V(q22) V(q23) \
|
||||
V(q24) V(q25) V(q26) V(q27) V(q28) V(q29) V(q30) V(q31)
|
||||
|
||||
// Register d29 could be allocated, but we keep an even length list here, in
|
||||
// order to make stack alignment easier for save and restore.
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(R) \
|
||||
R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \
|
||||
R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d16) \
|
||||
R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) R(d24) \
|
||||
R(d25) R(d26) R(d27) R(d28)
|
||||
// clang-format on
|
||||
|
||||
constexpr int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte;
|
||||
|
||||
const int kNumRegs = kNumberOfRegisters;
|
||||
// Registers x0-x17 are caller-saved.
|
||||
const int kNumJSCallerSaved = 18;
|
||||
const RegList kJSCallerSaved = 0x3ffff;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of eight.
|
||||
// TODO(all): Refine this number.
|
||||
const int kNumSafepointRegisters = 32;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
#define kSafepointSavedRegisters CPURegList::GetSafepointSavedRegisters().list()
|
||||
#define kNumSafepointSavedRegisters \
|
||||
CPURegList::GetSafepointSavedRegisters().Count()
|
||||
|
||||
// Some CPURegister methods can return Register and VRegister types, so we
|
||||
// need to declare them in advance.
|
||||
class Register;
|
||||
class VRegister;
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class CPURegister : public RegisterBase<CPURegister, kRegAfterLast> {
|
||||
public:
|
||||
enum RegisterType { kRegister, kVRegister, kNoRegister };
|
||||
|
||||
static constexpr CPURegister no_reg() {
|
||||
return CPURegister{0, 0, kNoRegister};
|
||||
}
|
||||
|
||||
template <int code, int size, RegisterType type>
|
||||
static constexpr CPURegister Create() {
|
||||
static_assert(IsValid(code, size, type), "Cannot create invalid registers");
|
||||
return CPURegister{code, size, type};
|
||||
}
|
||||
|
||||
static CPURegister Create(int code, int size, RegisterType type) {
|
||||
DCHECK(IsValid(code, size, type));
|
||||
return CPURegister{code, size, type};
|
||||
}
|
||||
|
||||
RegisterType type() const { return reg_type_; }
|
||||
int SizeInBits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_;
|
||||
}
|
||||
int SizeInBytes() const {
|
||||
DCHECK(IsValid());
|
||||
DCHECK_EQ(SizeInBits() % 8, 0);
|
||||
return reg_size_ / 8;
|
||||
}
|
||||
bool Is8Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 8;
|
||||
}
|
||||
bool Is16Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 16;
|
||||
}
|
||||
bool Is32Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 32;
|
||||
}
|
||||
bool Is64Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 64;
|
||||
}
|
||||
bool Is128Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size_ == 128;
|
||||
}
|
||||
bool IsValid() const { return reg_type_ != kNoRegister; }
|
||||
bool IsNone() const { return reg_type_ == kNoRegister; }
|
||||
bool Is(const CPURegister& other) const {
|
||||
return Aliases(other) && (reg_size_ == other.reg_size_);
|
||||
}
|
||||
bool Aliases(const CPURegister& other) const {
|
||||
return (reg_code_ == other.reg_code_) && (reg_type_ == other.reg_type_);
|
||||
}
|
||||
|
||||
bool IsZero() const;
|
||||
bool IsSP() const;
|
||||
|
||||
bool IsRegister() const { return reg_type_ == kRegister; }
|
||||
bool IsVRegister() const { return reg_type_ == kVRegister; }
|
||||
|
||||
bool IsFPRegister() const { return IsS() || IsD(); }
|
||||
|
||||
bool IsW() const { return IsRegister() && Is32Bits(); }
|
||||
bool IsX() const { return IsRegister() && Is64Bits(); }
|
||||
|
||||
// These assertions ensure that the size and type of the register are as
|
||||
// described. They do not consider the number of lanes that make up a vector.
|
||||
// So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD()
|
||||
// does not imply Is1D() or Is8B().
|
||||
// Check the number of lanes, ie. the format of the vector, using methods such
|
||||
// as Is8B(), Is1D(), etc. in the VRegister class.
|
||||
bool IsV() const { return IsVRegister(); }
|
||||
bool IsB() const { return IsV() && Is8Bits(); }
|
||||
bool IsH() const { return IsV() && Is16Bits(); }
|
||||
bool IsS() const { return IsV() && Is32Bits(); }
|
||||
bool IsD() const { return IsV() && Is64Bits(); }
|
||||
bool IsQ() const { return IsV() && Is128Bits(); }
|
||||
|
||||
Register Reg() const;
|
||||
VRegister VReg() const;
|
||||
|
||||
Register X() const;
|
||||
Register W() const;
|
||||
VRegister V() const;
|
||||
VRegister B() const;
|
||||
VRegister H() const;
|
||||
VRegister D() const;
|
||||
VRegister S() const;
|
||||
VRegister Q() const;
|
||||
|
||||
bool IsSameSizeAndType(const CPURegister& other) const;
|
||||
|
||||
bool is(const CPURegister& other) const { return Is(other); }
|
||||
bool is_valid() const { return IsValid(); }
|
||||
|
||||
protected:
|
||||
int reg_size_;
|
||||
RegisterType reg_type_;
|
||||
|
||||
#if defined(V8_OS_WIN) && !defined(__clang__)
|
||||
// MSVC has problem to parse template base class as friend class.
|
||||
friend RegisterBase;
|
||||
#else
|
||||
friend class RegisterBase;
|
||||
#endif
|
||||
|
||||
constexpr CPURegister(int code, int size, RegisterType type)
|
||||
: RegisterBase(code), reg_size_(size), reg_type_(type) {}
|
||||
|
||||
static constexpr bool IsValidRegister(int code, int size) {
|
||||
return (size == kWRegSizeInBits || size == kXRegSizeInBits) &&
|
||||
(code < kNumberOfRegisters || code == kSPRegInternalCode);
|
||||
}
|
||||
|
||||
static constexpr bool IsValidVRegister(int code, int size) {
|
||||
return (size == kBRegSizeInBits || size == kHRegSizeInBits ||
|
||||
size == kSRegSizeInBits || size == kDRegSizeInBits ||
|
||||
size == kQRegSizeInBits) &&
|
||||
code < kNumberOfVRegisters;
|
||||
}
|
||||
|
||||
static constexpr bool IsValid(int code, int size, RegisterType type) {
|
||||
return (type == kRegister && IsValidRegister(code, size)) ||
|
||||
(type == kVRegister && IsValidVRegister(code, size));
|
||||
}
|
||||
|
||||
static constexpr bool IsNone(int code, int size, RegisterType type) {
|
||||
return type == kNoRegister && code == 0 && size == 0;
|
||||
}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(CPURegister);
|
||||
|
||||
class Register : public CPURegister {
|
||||
public:
|
||||
static constexpr Register no_reg() { return Register(CPURegister::no_reg()); }
|
||||
|
||||
template <int code, int size>
|
||||
static constexpr Register Create() {
|
||||
return Register(CPURegister::Create<code, size, CPURegister::kRegister>());
|
||||
}
|
||||
|
||||
static Register Create(int code, int size) {
|
||||
return Register(CPURegister::Create(code, size, CPURegister::kRegister));
|
||||
}
|
||||
|
||||
static Register XRegFromCode(unsigned code);
|
||||
static Register WRegFromCode(unsigned code);
|
||||
|
||||
static Register from_code(int code) {
|
||||
// Always return an X register.
|
||||
return Register::Create(code, kXRegSizeInBits);
|
||||
}
|
||||
|
||||
template <int code>
|
||||
static Register from_code() {
|
||||
// Always return an X register.
|
||||
return Register::Create<code, kXRegSizeInBits>();
|
||||
}
|
||||
|
||||
static const char* GetSpecialRegisterName(int code) {
|
||||
return (code == kSPRegInternalCode) ? "sp" : "UNKNOWN";
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr explicit Register(const CPURegister& r) : CPURegister(r) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
|
||||
constexpr bool kPadArguments = true;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Functions for handling NEON vector format information.
|
||||
enum VectorFormat {
|
||||
kFormatUndefined = 0xffffffff,
|
||||
kFormat8B = NEON_8B,
|
||||
kFormat16B = NEON_16B,
|
||||
kFormat4H = NEON_4H,
|
||||
kFormat8H = NEON_8H,
|
||||
kFormat2S = NEON_2S,
|
||||
kFormat4S = NEON_4S,
|
||||
kFormat1D = NEON_1D,
|
||||
kFormat2D = NEON_2D,
|
||||
|
||||
// Scalar formats. We add the scalar bit to distinguish between scalar and
|
||||
// vector enumerations; the bit is always set in the encoding of scalar ops
|
||||
// and always clear for vector ops. Although kFormatD and kFormat1D appear
|
||||
// to be the same, their meaning is subtly different. The first is a scalar
|
||||
// operation, the second a vector operation that only affects one lane.
|
||||
kFormatB = NEON_B | NEONScalar,
|
||||
kFormatH = NEON_H | NEONScalar,
|
||||
kFormatS = NEON_S | NEONScalar,
|
||||
kFormatD = NEON_D | NEONScalar
|
||||
};
|
||||
|
||||
VectorFormat VectorFormatHalfWidth(VectorFormat vform);
|
||||
VectorFormat VectorFormatDoubleWidth(VectorFormat vform);
|
||||
VectorFormat VectorFormatDoubleLanes(VectorFormat vform);
|
||||
VectorFormat VectorFormatHalfLanes(VectorFormat vform);
|
||||
VectorFormat ScalarFormatFromLaneSize(int lanesize);
|
||||
VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform);
|
||||
VectorFormat VectorFormatFillQ(VectorFormat vform);
|
||||
VectorFormat ScalarFormatFromFormat(VectorFormat vform);
|
||||
unsigned RegisterSizeInBitsFromFormat(VectorFormat vform);
|
||||
unsigned RegisterSizeInBytesFromFormat(VectorFormat vform);
|
||||
int LaneSizeInBytesFromFormat(VectorFormat vform);
|
||||
unsigned LaneSizeInBitsFromFormat(VectorFormat vform);
|
||||
int LaneSizeInBytesLog2FromFormat(VectorFormat vform);
|
||||
int LaneCountFromFormat(VectorFormat vform);
|
||||
int MaxLaneCountFromFormat(VectorFormat vform);
|
||||
bool IsVectorFormat(VectorFormat vform);
|
||||
int64_t MaxIntFromFormat(VectorFormat vform);
|
||||
int64_t MinIntFromFormat(VectorFormat vform);
|
||||
uint64_t MaxUintFromFormat(VectorFormat vform);
|
||||
|
||||
class VRegister : public CPURegister {
|
||||
public:
|
||||
static constexpr VRegister no_reg() {
|
||||
return VRegister(CPURegister::no_reg(), 0);
|
||||
}
|
||||
|
||||
template <int code, int size, int lane_count = 1>
|
||||
static constexpr VRegister Create() {
|
||||
static_assert(IsValidLaneCount(lane_count), "Invalid lane count");
|
||||
return VRegister(CPURegister::Create<code, size, kVRegister>(), lane_count);
|
||||
}
|
||||
|
||||
static VRegister Create(int code, int size, int lane_count = 1) {
|
||||
DCHECK(IsValidLaneCount(lane_count));
|
||||
return VRegister(CPURegister::Create(code, size, CPURegister::kVRegister),
|
||||
lane_count);
|
||||
}
|
||||
|
||||
static VRegister Create(int reg_code, VectorFormat format) {
|
||||
int reg_size = RegisterSizeInBitsFromFormat(format);
|
||||
int reg_count = IsVectorFormat(format) ? LaneCountFromFormat(format) : 1;
|
||||
return VRegister::Create(reg_code, reg_size, reg_count);
|
||||
}
|
||||
|
||||
static VRegister BRegFromCode(unsigned code);
|
||||
static VRegister HRegFromCode(unsigned code);
|
||||
static VRegister SRegFromCode(unsigned code);
|
||||
static VRegister DRegFromCode(unsigned code);
|
||||
static VRegister QRegFromCode(unsigned code);
|
||||
static VRegister VRegFromCode(unsigned code);
|
||||
|
||||
VRegister V8B() const {
|
||||
return VRegister::Create(code(), kDRegSizeInBits, 8);
|
||||
}
|
||||
VRegister V16B() const {
|
||||
return VRegister::Create(code(), kQRegSizeInBits, 16);
|
||||
}
|
||||
VRegister V4H() const {
|
||||
return VRegister::Create(code(), kDRegSizeInBits, 4);
|
||||
}
|
||||
VRegister V8H() const {
|
||||
return VRegister::Create(code(), kQRegSizeInBits, 8);
|
||||
}
|
||||
VRegister V2S() const {
|
||||
return VRegister::Create(code(), kDRegSizeInBits, 2);
|
||||
}
|
||||
VRegister V4S() const {
|
||||
return VRegister::Create(code(), kQRegSizeInBits, 4);
|
||||
}
|
||||
VRegister V2D() const {
|
||||
return VRegister::Create(code(), kQRegSizeInBits, 2);
|
||||
}
|
||||
VRegister V1D() const {
|
||||
return VRegister::Create(code(), kDRegSizeInBits, 1);
|
||||
}
|
||||
|
||||
bool Is8B() const { return (Is64Bits() && (lane_count_ == 8)); }
|
||||
bool Is16B() const { return (Is128Bits() && (lane_count_ == 16)); }
|
||||
bool Is4H() const { return (Is64Bits() && (lane_count_ == 4)); }
|
||||
bool Is8H() const { return (Is128Bits() && (lane_count_ == 8)); }
|
||||
bool Is2S() const { return (Is64Bits() && (lane_count_ == 2)); }
|
||||
bool Is4S() const { return (Is128Bits() && (lane_count_ == 4)); }
|
||||
bool Is1D() const { return (Is64Bits() && (lane_count_ == 1)); }
|
||||
bool Is2D() const { return (Is128Bits() && (lane_count_ == 2)); }
|
||||
|
||||
// For consistency, we assert the number of lanes of these scalar registers,
|
||||
// even though there are no vectors of equivalent total size with which they
|
||||
// could alias.
|
||||
bool Is1B() const {
|
||||
DCHECK(!(Is8Bits() && IsVector()));
|
||||
return Is8Bits();
|
||||
}
|
||||
bool Is1H() const {
|
||||
DCHECK(!(Is16Bits() && IsVector()));
|
||||
return Is16Bits();
|
||||
}
|
||||
bool Is1S() const {
|
||||
DCHECK(!(Is32Bits() && IsVector()));
|
||||
return Is32Bits();
|
||||
}
|
||||
|
||||
bool IsLaneSizeB() const { return LaneSizeInBits() == kBRegSizeInBits; }
|
||||
bool IsLaneSizeH() const { return LaneSizeInBits() == kHRegSizeInBits; }
|
||||
bool IsLaneSizeS() const { return LaneSizeInBits() == kSRegSizeInBits; }
|
||||
bool IsLaneSizeD() const { return LaneSizeInBits() == kDRegSizeInBits; }
|
||||
|
||||
bool IsScalar() const { return lane_count_ == 1; }
|
||||
bool IsVector() const { return lane_count_ > 1; }
|
||||
|
||||
bool IsSameFormat(const VRegister& other) const {
|
||||
return (reg_size_ == other.reg_size_) && (lane_count_ == other.lane_count_);
|
||||
}
|
||||
|
||||
int LaneCount() const { return lane_count_; }
|
||||
|
||||
unsigned LaneSizeInBytes() const { return SizeInBytes() / lane_count_; }
|
||||
|
||||
unsigned LaneSizeInBits() const { return LaneSizeInBytes() * 8; }
|
||||
|
||||
static constexpr int kMaxNumRegisters = kNumberOfVRegisters;
|
||||
STATIC_ASSERT(kMaxNumRegisters == kDoubleAfterLast);
|
||||
|
||||
static VRegister from_code(int code) {
|
||||
// Always return a D register.
|
||||
return VRegister::Create(code, kDRegSizeInBits);
|
||||
}
|
||||
|
||||
private:
|
||||
int lane_count_;
|
||||
|
||||
constexpr explicit VRegister(const CPURegister& r, int lane_count)
|
||||
: CPURegister(r), lane_count_(lane_count) {}
|
||||
|
||||
static constexpr bool IsValidLaneCount(int lane_count) {
|
||||
return base::bits::IsPowerOfTwo(lane_count) && lane_count <= 16;
|
||||
}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(VRegister);
|
||||
|
||||
// No*Reg is used to indicate an unused argument, or an error case. Note that
|
||||
// these all compare equal (using the Is() method). The Register and VRegister
|
||||
// variants are provided for convenience.
|
||||
constexpr Register NoReg = Register::no_reg();
|
||||
constexpr VRegister NoVReg = VRegister::no_reg();
|
||||
constexpr CPURegister NoCPUReg = CPURegister::no_reg();
|
||||
constexpr Register no_reg = NoReg;
|
||||
constexpr VRegister no_dreg = NoVReg;
|
||||
|
||||
#define DEFINE_REGISTER(register_class, name, ...) \
|
||||
constexpr register_class name = register_class::Create<__VA_ARGS__>()
|
||||
#define ALIAS_REGISTER(register_class, alias, name) \
|
||||
constexpr register_class alias = name
|
||||
|
||||
#define DEFINE_REGISTERS(N) \
|
||||
DEFINE_REGISTER(Register, w##N, N, kWRegSizeInBits); \
|
||||
DEFINE_REGISTER(Register, x##N, N, kXRegSizeInBits);
|
||||
GENERAL_REGISTER_CODE_LIST(DEFINE_REGISTERS)
|
||||
#undef DEFINE_REGISTERS
|
||||
|
||||
DEFINE_REGISTER(Register, wsp, kSPRegInternalCode, kWRegSizeInBits);
|
||||
DEFINE_REGISTER(Register, sp, kSPRegInternalCode, kXRegSizeInBits);
|
||||
|
||||
#define DEFINE_VREGISTERS(N) \
|
||||
DEFINE_REGISTER(VRegister, b##N, N, kBRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, h##N, N, kHRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, s##N, N, kSRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, d##N, N, kDRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, q##N, N, kQRegSizeInBits); \
|
||||
DEFINE_REGISTER(VRegister, v##N, N, kQRegSizeInBits);
|
||||
GENERAL_REGISTER_CODE_LIST(DEFINE_VREGISTERS)
|
||||
#undef DEFINE_VREGISTERS
|
||||
|
||||
#undef DEFINE_REGISTER
|
||||
|
||||
// Registers aliases.
|
||||
ALIAS_REGISTER(VRegister, v8_, v8); // Avoid conflicts with namespace v8.
|
||||
ALIAS_REGISTER(Register, ip0, x16);
|
||||
ALIAS_REGISTER(Register, ip1, x17);
|
||||
ALIAS_REGISTER(Register, wip0, w16);
|
||||
ALIAS_REGISTER(Register, wip1, w17);
|
||||
// Root register.
|
||||
ALIAS_REGISTER(Register, kRootRegister, x26);
|
||||
ALIAS_REGISTER(Register, rr, x26);
|
||||
// Context pointer register.
|
||||
ALIAS_REGISTER(Register, cp, x27);
|
||||
ALIAS_REGISTER(Register, fp, x29);
|
||||
ALIAS_REGISTER(Register, lr, x30);
|
||||
ALIAS_REGISTER(Register, xzr, x31);
|
||||
ALIAS_REGISTER(Register, wzr, w31);
|
||||
|
||||
// Register used for padding stack slots.
|
||||
ALIAS_REGISTER(Register, padreg, x31);
|
||||
|
||||
// Keeps the 0 double value.
|
||||
ALIAS_REGISTER(VRegister, fp_zero, d15);
|
||||
// MacroAssembler fixed V Registers.
|
||||
ALIAS_REGISTER(VRegister, fp_fixed1, d28);
|
||||
ALIAS_REGISTER(VRegister, fp_fixed2, d29);
|
||||
|
||||
// MacroAssembler scratch V registers.
|
||||
ALIAS_REGISTER(VRegister, fp_scratch, d30);
|
||||
ALIAS_REGISTER(VRegister, fp_scratch1, d30);
|
||||
ALIAS_REGISTER(VRegister, fp_scratch2, d31);
|
||||
|
||||
#undef ALIAS_REGISTER
|
||||
|
||||
// AreAliased returns true if any of the named registers overlap. Arguments set
|
||||
// to NoReg are ignored. The system stack pointer may be specified.
|
||||
bool AreAliased(const CPURegister& reg1, const CPURegister& reg2,
|
||||
const CPURegister& reg3 = NoReg,
|
||||
const CPURegister& reg4 = NoReg,
|
||||
const CPURegister& reg5 = NoReg,
|
||||
const CPURegister& reg6 = NoReg,
|
||||
const CPURegister& reg7 = NoReg,
|
||||
const CPURegister& reg8 = NoReg);
|
||||
|
||||
// AreSameSizeAndType returns true if all of the specified registers have the
|
||||
// same size, and are of the same type. The system stack pointer may be
|
||||
// specified. Arguments set to NoReg are ignored, as are any subsequent
|
||||
// arguments. At least one argument (reg1) must be valid (not NoCPUReg).
|
||||
bool AreSameSizeAndType(
|
||||
const CPURegister& reg1, const CPURegister& reg2 = NoCPUReg,
|
||||
const CPURegister& reg3 = NoCPUReg, const CPURegister& reg4 = NoCPUReg,
|
||||
const CPURegister& reg5 = NoCPUReg, const CPURegister& reg6 = NoCPUReg,
|
||||
const CPURegister& reg7 = NoCPUReg, const CPURegister& reg8 = NoCPUReg);
|
||||
|
||||
// AreSameFormat returns true if all of the specified VRegisters have the same
|
||||
// vector format. Arguments set to NoVReg are ignored, as are any subsequent
|
||||
// arguments. At least one argument (reg1) must be valid (not NoVReg).
|
||||
bool AreSameFormat(const VRegister& reg1, const VRegister& reg2,
|
||||
const VRegister& reg3 = NoVReg,
|
||||
const VRegister& reg4 = NoVReg);
|
||||
|
||||
// AreConsecutive returns true if all of the specified VRegisters are
|
||||
// consecutive in the register file. Arguments may be set to NoVReg, and if so,
|
||||
// subsequent arguments must also be NoVReg. At least one argument (reg1) must
|
||||
// be valid (not NoVReg).
|
||||
bool AreConsecutive(const VRegister& reg1, const VRegister& reg2,
|
||||
const VRegister& reg3 = NoVReg,
|
||||
const VRegister& reg4 = NoVReg);
|
||||
|
||||
typedef VRegister FloatRegister;
|
||||
typedef VRegister DoubleRegister;
|
||||
typedef VRegister Simd128Register;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Lists of registers.
|
||||
class CPURegList {
|
||||
public:
|
||||
template <typename... CPURegisters>
|
||||
explicit CPURegList(CPURegister reg0, CPURegisters... regs)
|
||||
: list_(CPURegister::ListOf(reg0, regs...)),
|
||||
size_(reg0.SizeInBits()),
|
||||
type_(reg0.type()) {
|
||||
DCHECK(AreSameSizeAndType(reg0, regs...));
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
CPURegList(CPURegister::RegisterType type, int size, RegList list)
|
||||
: list_(list), size_(size), type_(type) {
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
CPURegList(CPURegister::RegisterType type, int size, int first_reg,
|
||||
int last_reg)
|
||||
: size_(size), type_(type) {
|
||||
DCHECK(
|
||||
((type == CPURegister::kRegister) && (last_reg < kNumberOfRegisters)) ||
|
||||
((type == CPURegister::kVRegister) &&
|
||||
(last_reg < kNumberOfVRegisters)));
|
||||
DCHECK(last_reg >= first_reg);
|
||||
list_ = (1ULL << (last_reg + 1)) - 1;
|
||||
list_ &= ~((1ULL << first_reg) - 1);
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
CPURegister::RegisterType type() const {
|
||||
DCHECK(IsValid());
|
||||
return type_;
|
||||
}
|
||||
|
||||
RegList list() const {
|
||||
DCHECK(IsValid());
|
||||
return list_;
|
||||
}
|
||||
|
||||
inline void set_list(RegList new_list) {
|
||||
DCHECK(IsValid());
|
||||
list_ = new_list;
|
||||
}
|
||||
|
||||
// Combine another CPURegList into this one. Registers that already exist in
|
||||
// this list are left unchanged. The type and size of the registers in the
|
||||
// 'other' list must match those in this list.
|
||||
void Combine(const CPURegList& other);
|
||||
|
||||
// Remove every register in the other CPURegList from this one. Registers that
|
||||
// do not exist in this list are ignored. The type of the registers in the
|
||||
// 'other' list must match those in this list.
|
||||
void Remove(const CPURegList& other);
|
||||
|
||||
// Variants of Combine and Remove which take CPURegisters.
|
||||
void Combine(const CPURegister& other);
|
||||
void Remove(const CPURegister& other1, const CPURegister& other2 = NoCPUReg,
|
||||
const CPURegister& other3 = NoCPUReg,
|
||||
const CPURegister& other4 = NoCPUReg);
|
||||
|
||||
// Variants of Combine and Remove which take a single register by its code;
|
||||
// the type and size of the register is inferred from this list.
|
||||
void Combine(int code);
|
||||
void Remove(int code);
|
||||
|
||||
// Remove all callee-saved registers from the list. This can be useful when
|
||||
// preparing registers for an AAPCS64 function call, for example.
|
||||
void RemoveCalleeSaved();
|
||||
|
||||
CPURegister PopLowestIndex();
|
||||
CPURegister PopHighestIndex();
|
||||
|
||||
// AAPCS64 callee-saved registers.
|
||||
static CPURegList GetCalleeSaved(int size = kXRegSizeInBits);
|
||||
static CPURegList GetCalleeSavedV(int size = kDRegSizeInBits);
|
||||
|
||||
// AAPCS64 caller-saved registers. Note that this includes lr.
|
||||
// TODO(all): Determine how we handle d8-d15 being callee-saved, but the top
|
||||
// 64-bits being caller-saved.
|
||||
static CPURegList GetCallerSaved(int size = kXRegSizeInBits);
|
||||
static CPURegList GetCallerSavedV(int size = kDRegSizeInBits);
|
||||
|
||||
// Registers saved as safepoints.
|
||||
static CPURegList GetSafepointSavedRegisters();
|
||||
|
||||
bool IsEmpty() const {
|
||||
DCHECK(IsValid());
|
||||
return list_ == 0;
|
||||
}
|
||||
|
||||
bool IncludesAliasOf(const CPURegister& other1,
|
||||
const CPURegister& other2 = NoCPUReg,
|
||||
const CPURegister& other3 = NoCPUReg,
|
||||
const CPURegister& other4 = NoCPUReg) const {
|
||||
DCHECK(IsValid());
|
||||
RegList list = 0;
|
||||
if (!other1.IsNone() && (other1.type() == type_)) list |= other1.bit();
|
||||
if (!other2.IsNone() && (other2.type() == type_)) list |= other2.bit();
|
||||
if (!other3.IsNone() && (other3.type() == type_)) list |= other3.bit();
|
||||
if (!other4.IsNone() && (other4.type() == type_)) list |= other4.bit();
|
||||
return (list_ & list) != 0;
|
||||
}
|
||||
|
||||
int Count() const {
|
||||
DCHECK(IsValid());
|
||||
return CountSetBits(list_, kRegListSizeInBits);
|
||||
}
|
||||
|
||||
int RegisterSizeInBits() const {
|
||||
DCHECK(IsValid());
|
||||
return size_;
|
||||
}
|
||||
|
||||
int RegisterSizeInBytes() const {
|
||||
int size_in_bits = RegisterSizeInBits();
|
||||
DCHECK_EQ(size_in_bits % kBitsPerByte, 0);
|
||||
return size_in_bits / kBitsPerByte;
|
||||
}
|
||||
|
||||
int TotalSizeInBytes() const {
|
||||
DCHECK(IsValid());
|
||||
return RegisterSizeInBytes() * Count();
|
||||
}
|
||||
|
||||
private:
|
||||
RegList list_;
|
||||
int size_;
|
||||
CPURegister::RegisterType type_;
|
||||
|
||||
bool IsValid() const {
|
||||
constexpr RegList kValidRegisters{0x8000000ffffffff};
|
||||
constexpr RegList kValidVRegisters{0x0000000ffffffff};
|
||||
switch (type_) {
|
||||
case CPURegister::kRegister:
|
||||
return (list_ & kValidRegisters) == list_;
|
||||
case CPURegister::kVRegister:
|
||||
return (list_ & kValidVRegisters) == list_;
|
||||
case CPURegister::kNoRegister:
|
||||
return list_ == 0;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// AAPCS64 callee-saved registers.
|
||||
#define kCalleeSaved CPURegList::GetCalleeSaved()
|
||||
#define kCalleeSavedV CPURegList::GetCalleeSavedV()
|
||||
|
||||
// AAPCS64 caller-saved registers. Note that this includes lr.
|
||||
#define kCallerSaved CPURegList::GetCallerSaved()
|
||||
#define kCallerSavedV CPURegList::GetCallerSavedV()
|
||||
|
||||
// Define a {RegisterName} method for {CPURegister}.
|
||||
DEFINE_REGISTER_NAMES(CPURegister, GENERAL_REGISTERS);
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = x0;
|
||||
constexpr Register kReturnRegister1 = x1;
|
||||
constexpr Register kReturnRegister2 = x2;
|
||||
constexpr Register kJSFunctionRegister = x1;
|
||||
constexpr Register kContextRegister = cp;
|
||||
constexpr Register kAllocateSizeRegister = x1;
|
||||
|
||||
#if defined(V8_OS_WIN)
|
||||
// x18 is reserved as platform register on Windows ARM64.
|
||||
constexpr Register kSpeculationPoisonRegister = x23;
|
||||
#else
|
||||
constexpr Register kSpeculationPoisonRegister = x18;
|
||||
#endif
|
||||
|
||||
constexpr Register kInterpreterAccumulatorRegister = x0;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = x19;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = x20;
|
||||
constexpr Register kInterpreterDispatchTableRegister = x21;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = x0;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = x2;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = x3;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = x2;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = ip0;
|
||||
constexpr Register kRuntimeCallFunctionRegister = x1;
|
||||
constexpr Register kRuntimeCallArgCountRegister = x0;
|
||||
constexpr Register kRuntimeCallArgvRegister = x11;
|
||||
constexpr Register kWasmInstanceRegister = x7;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = x8;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_ARM64_REGISTER_ARM64_H_
|
111
src/assembler.h
111
src/assembler.h
@ -236,9 +236,6 @@ class V8_EXPORT_PRIVATE AssemblerBase : public Malloced {
|
||||
return FlushICache(reinterpret_cast<void*>(start), size);
|
||||
}
|
||||
|
||||
// Used to print the name of some special registers.
|
||||
static const char* GetSpecialRegisterName(int code) { return "UNKNOWN"; }
|
||||
|
||||
// Record an inline code comment that can be used by a disassembler.
|
||||
// Use --code-comments to enable.
|
||||
void RecordComment(const char* msg) {
|
||||
@ -385,114 +382,6 @@ double power_helper(double x, double y);
|
||||
double power_double_int(double x, int y);
|
||||
double power_double_double(double x, double y);
|
||||
|
||||
|
||||
// Base type for CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum for registers, but enum values are
|
||||
// assignment-compatible with int, which has caused code-generation bugs.
|
||||
//
|
||||
// 2) By not using an enum, we are possibly preventing the compiler from
|
||||
// doing certain constant folds, which may significantly reduce the
|
||||
// code generated for some assembly instructions (because they boil down
|
||||
// to a few constants). If this is a problem, we could change the code
|
||||
// such that we use an enum in optimized mode, and the class in debug
|
||||
// mode. This way we get the compile-time error checking in debug mode
|
||||
// and best performance in optimized code.
|
||||
template <typename SubType, int kAfterLastRegister>
|
||||
class RegisterBase {
|
||||
// Internal enum class; used for calling constexpr methods, where we need to
|
||||
// pass an integral type as template parameter.
|
||||
enum class RegisterCode : int { kFirst = 0, kAfterLast = kAfterLastRegister };
|
||||
|
||||
public:
|
||||
static constexpr int kCode_no_reg = -1;
|
||||
static constexpr int kNumRegisters = kAfterLastRegister;
|
||||
|
||||
static constexpr SubType no_reg() { return SubType{kCode_no_reg}; }
|
||||
|
||||
template <int code>
|
||||
static constexpr SubType from_code() {
|
||||
static_assert(code >= 0 && code < kNumRegisters, "must be valid reg code");
|
||||
return SubType{code};
|
||||
}
|
||||
|
||||
constexpr operator RegisterCode() const {
|
||||
return static_cast<RegisterCode>(reg_code_);
|
||||
}
|
||||
|
||||
template <RegisterCode reg_code>
|
||||
static constexpr int code() {
|
||||
static_assert(
|
||||
reg_code >= RegisterCode::kFirst && reg_code < RegisterCode::kAfterLast,
|
||||
"must be valid reg");
|
||||
return static_cast<int>(reg_code);
|
||||
}
|
||||
|
||||
template <RegisterCode reg_code>
|
||||
static constexpr int is_valid() {
|
||||
return static_cast<int>(reg_code) != kCode_no_reg;
|
||||
}
|
||||
|
||||
template <RegisterCode reg_code>
|
||||
static constexpr RegList bit() {
|
||||
return is_valid<reg_code>() ? RegList{1} << code<reg_code>() : RegList{};
|
||||
}
|
||||
|
||||
static SubType from_code(int code) {
|
||||
DCHECK_LE(0, code);
|
||||
DCHECK_GT(kNumRegisters, code);
|
||||
return SubType{code};
|
||||
}
|
||||
|
||||
// Constexpr version (pass registers as template parameters).
|
||||
template <RegisterCode... reg_codes>
|
||||
static constexpr RegList ListOf() {
|
||||
return CombineRegLists(RegisterBase::bit<reg_codes>()...);
|
||||
}
|
||||
|
||||
// Non-constexpr version (pass registers as method parameters).
|
||||
template <typename... Register>
|
||||
static RegList ListOf(Register... regs) {
|
||||
return CombineRegLists(regs.bit()...);
|
||||
}
|
||||
|
||||
constexpr bool is_valid() const { return reg_code_ != kCode_no_reg; }
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code_;
|
||||
}
|
||||
|
||||
RegList bit() const { return is_valid() ? RegList{1} << code() : RegList{}; }
|
||||
|
||||
inline constexpr bool operator==(SubType other) const {
|
||||
return reg_code_ == other.reg_code_;
|
||||
}
|
||||
inline constexpr bool operator!=(SubType other) const {
|
||||
return reg_code_ != other.reg_code_;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit constexpr RegisterBase(int code) : reg_code_(code) {}
|
||||
int reg_code_;
|
||||
};
|
||||
|
||||
// Helper macros to define a {RegisterName} method based on a macro list
|
||||
// containing all names.
|
||||
#define DEFINE_REGISTER_NAMES_NAME(name) #name,
|
||||
#define DEFINE_REGISTER_NAMES(RegType, LIST) \
|
||||
inline const char* RegisterName(RegType reg) { \
|
||||
static constexpr const char* Names[] = {LIST(DEFINE_REGISTER_NAMES_NAME)}; \
|
||||
STATIC_ASSERT(arraysize(Names) == RegType::kNumRegisters); \
|
||||
return reg.is_valid() ? Names[reg.code()] : "invalid"; \
|
||||
}
|
||||
|
||||
template <typename RegType,
|
||||
typename = decltype(RegisterName(std::declval<RegType>()))>
|
||||
inline std::ostream& operator<<(std::ostream& os, RegType reg) {
|
||||
return os << RegisterName(reg);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
#endif // V8_ASSEMBLER_H_
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "src/compiler/backend/unwinding-info-writer.h"
|
||||
#include "src/compiler/osr.h"
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/safepoint-table.h"
|
||||
#include "src/source-position-table.h"
|
||||
#include "src/trap-handler/trap-handler.h"
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/cpu-features.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/zone/zone-containers.h"
|
||||
|
||||
|
@ -178,7 +178,7 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) {
|
||||
const char* name =
|
||||
allocated.register_code() < Register::kNumRegisters
|
||||
? RegisterName(Register::from_code(allocated.register_code()))
|
||||
: Assembler::GetSpecialRegisterName(allocated.register_code());
|
||||
: Register::GetSpecialRegisterName(allocated.register_code());
|
||||
os << "[" << name << "|R";
|
||||
} else if (op.IsDoubleRegister()) {
|
||||
os << "[" << DoubleRegister::from_code(allocated.register_code())
|
||||
|
@ -16,8 +16,9 @@
|
||||
#include "src/compiler/frame.h"
|
||||
#include "src/compiler/opcodes.h"
|
||||
#include "src/double.h"
|
||||
#include "src/external-reference.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/register-arch.h"
|
||||
#include "src/source-position.h"
|
||||
#include "src/zone/zone-allocator.h"
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/backend/instruction-scheduler.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
#include "src/roots-inl.h"
|
||||
#include "src/turbo-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -34,6 +34,7 @@ namespace internal {
|
||||
// Forward declarations.
|
||||
class AsmWasmData;
|
||||
class AsyncGeneratorRequest;
|
||||
struct AssemblerOptions;
|
||||
class BigInt;
|
||||
class CallInterfaceDescriptor;
|
||||
class Callable;
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "src/compiler/frame.h"
|
||||
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -1065,7 +1065,7 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperandAsJSON& o) {
|
||||
if (allocated->register_code() < Register::kNumRegisters) {
|
||||
os << Register::from_code(allocated->register_code());
|
||||
} else {
|
||||
os << Assembler::GetSpecialRegisterName(allocated->register_code());
|
||||
os << Register::GetSpecialRegisterName(allocated->register_code());
|
||||
}
|
||||
} else if (op->IsDoubleRegister()) {
|
||||
os << DoubleRegister::from_code(allocated->register_code());
|
||||
|
@ -12,10 +12,10 @@
|
||||
#include "src/globals.h"
|
||||
#include "src/interface-descriptors.h"
|
||||
#include "src/machine-type.h"
|
||||
#include "src/register-arch.h"
|
||||
#include "src/reglist.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "src/signature.h"
|
||||
#include "src/turbo-assembler.h"
|
||||
#include "src/zone/zone.h"
|
||||
|
||||
namespace v8 {
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/ia32/constants-ia32.h"
|
||||
#include "src/ia32/register-ia32.h"
|
||||
#include "src/ia32/sse-instr.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/label.h"
|
||||
@ -50,114 +51,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(eax) \
|
||||
V(ecx) \
|
||||
V(edx) \
|
||||
V(ebx) \
|
||||
V(esp) \
|
||||
V(ebp) \
|
||||
V(esi) \
|
||||
V(edi)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(eax) \
|
||||
V(ecx) \
|
||||
V(edx) \
|
||||
V(esi) \
|
||||
V(edi)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(xmm0) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS DOUBLE_REGISTERS
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7)
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
bool is_byte_register() const { return reg_code_ <= 3; }
|
||||
|
||||
private:
|
||||
friend class RegisterBase<Register, kRegAfterLast>;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
class XMMRegister : public RegisterBase<XMMRegister, kDoubleAfterLast> {
|
||||
friend class RegisterBase<XMMRegister, kDoubleAfterLast>;
|
||||
explicit constexpr XMMRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
typedef XMMRegister FloatRegister;
|
||||
|
||||
typedef XMMRegister DoubleRegister;
|
||||
|
||||
typedef XMMRegister Simd128Register;
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
// Note that the bit values must match those used in actual instruction encoding
|
||||
constexpr int kNumRegs = 8;
|
||||
|
||||
// Caller-saved registers
|
||||
constexpr RegList kJSCallerSaved =
|
||||
Register::ListOf<eax, ecx, edx,
|
||||
ebx, // used as a caller-saved register in JavaScript code
|
||||
edi // callee function
|
||||
>();
|
||||
|
||||
constexpr int kNumJSCallerSaved = 5;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints.
|
||||
constexpr int kNumSafepointRegisters = 8;
|
||||
|
||||
enum Condition {
|
||||
// any value < 0 is considered no_condition
|
||||
no_condition = -1,
|
||||
@ -1890,10 +1783,6 @@ class EnsureSpace {
|
||||
#endif
|
||||
};
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(XMMRegister, DOUBLE_REGISTERS)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
|
||||
#include "src/interface-descriptors.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
#include "src/frames.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -17,43 +17,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = eax;
|
||||
constexpr Register kReturnRegister1 = edx;
|
||||
constexpr Register kReturnRegister2 = edi;
|
||||
constexpr Register kJSFunctionRegister = edi;
|
||||
constexpr Register kContextRegister = esi;
|
||||
constexpr Register kAllocateSizeRegister = edx;
|
||||
constexpr Register kInterpreterAccumulatorRegister = eax;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = edx;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = edi;
|
||||
constexpr Register kInterpreterDispatchTableRegister = esi;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = eax;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = ecx;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = edx;
|
||||
|
||||
// The ExtraArg1Register not part of the real JS calling convention and is
|
||||
// mostly there to simplify consistent interface descriptor definitions across
|
||||
// platforms. Note that on ia32 it aliases kJavaScriptCallCodeStartRegister.
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = ecx;
|
||||
|
||||
// The off-heap trampoline does not need a register on ia32 (it uses a
|
||||
// pc-relative call instead).
|
||||
constexpr Register kOffHeapTrampolineRegister = no_reg;
|
||||
|
||||
constexpr Register kRuntimeCallFunctionRegister = edx;
|
||||
constexpr Register kRuntimeCallArgCountRegister = eax;
|
||||
constexpr Register kRuntimeCallArgvRegister = ecx;
|
||||
constexpr Register kWasmInstanceRegister = esi;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = edi;
|
||||
|
||||
constexpr Register kRootRegister = ebx;
|
||||
|
||||
// TODO(860429): Remove remaining poisoning infrastructure on ia32.
|
||||
constexpr Register kSpeculationPoisonRegister = no_reg;
|
||||
|
||||
// Convenience for platform-independent signatures. We do not normally
|
||||
// distinguish memory operands from other operands on ia32.
|
||||
typedef Operand MemOperand;
|
||||
|
166
src/ia32/register-ia32.h
Normal file
166
src/ia32/register-ia32.h
Normal file
@ -0,0 +1,166 @@
|
||||
// Copyright 2018 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_IA32_REGISTER_IA32_H_
|
||||
#define V8_IA32_REGISTER_IA32_H_
|
||||
|
||||
#include "src/register.h"
|
||||
#include "src/reglist.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(eax) \
|
||||
V(ecx) \
|
||||
V(edx) \
|
||||
V(ebx) \
|
||||
V(esp) \
|
||||
V(ebp) \
|
||||
V(esi) \
|
||||
V(edi)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(eax) \
|
||||
V(ecx) \
|
||||
V(edx) \
|
||||
V(esi) \
|
||||
V(edi)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(xmm0) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS DOUBLE_REGISTERS
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7)
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
bool is_byte_register() const { return reg_code_ <= 3; }
|
||||
|
||||
private:
|
||||
friend class RegisterBase<Register, kRegAfterLast>;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
class XMMRegister : public RegisterBase<XMMRegister, kDoubleAfterLast> {
|
||||
friend class RegisterBase<XMMRegister, kDoubleAfterLast>;
|
||||
explicit constexpr XMMRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
typedef XMMRegister FloatRegister;
|
||||
|
||||
typedef XMMRegister DoubleRegister;
|
||||
|
||||
typedef XMMRegister Simd128Register;
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
// Note that the bit values must match those used in actual instruction encoding
|
||||
constexpr int kNumRegs = 8;
|
||||
|
||||
// Caller-saved registers
|
||||
constexpr RegList kJSCallerSaved =
|
||||
Register::ListOf<eax, ecx, edx,
|
||||
ebx, // used as a caller-saved register in JavaScript code
|
||||
edi // callee function
|
||||
>();
|
||||
|
||||
constexpr int kNumJSCallerSaved = 5;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints.
|
||||
constexpr int kNumSafepointRegisters = 8;
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(XMMRegister, DOUBLE_REGISTERS)
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = eax;
|
||||
constexpr Register kReturnRegister1 = edx;
|
||||
constexpr Register kReturnRegister2 = edi;
|
||||
constexpr Register kJSFunctionRegister = edi;
|
||||
constexpr Register kContextRegister = esi;
|
||||
constexpr Register kAllocateSizeRegister = edx;
|
||||
constexpr Register kInterpreterAccumulatorRegister = eax;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = edx;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = edi;
|
||||
constexpr Register kInterpreterDispatchTableRegister = esi;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = eax;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = ecx;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = edx;
|
||||
|
||||
// The ExtraArg1Register not part of the real JS calling convention and is
|
||||
// mostly there to simplify consistent interface descriptor definitions across
|
||||
// platforms. Note that on ia32 it aliases kJavaScriptCallCodeStartRegister.
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = ecx;
|
||||
|
||||
// The off-heap trampoline does not need a register on ia32 (it uses a
|
||||
// pc-relative call instead).
|
||||
constexpr Register kOffHeapTrampolineRegister = no_reg;
|
||||
|
||||
constexpr Register kRuntimeCallFunctionRegister = edx;
|
||||
constexpr Register kRuntimeCallArgCountRegister = eax;
|
||||
constexpr Register kRuntimeCallArgvRegister = ecx;
|
||||
constexpr Register kWasmInstanceRegister = esi;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = edi;
|
||||
|
||||
constexpr Register kRootRegister = ebx;
|
||||
|
||||
// TODO(860429): Remove remaining poisoning infrastructure on ia32.
|
||||
constexpr Register kSpeculationPoisonRegister = no_reg;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_IA32_REGISTER_IA32_H_
|
@ -6,7 +6,6 @@
|
||||
#define V8_IC_CALL_OPTIMIZATION_H_
|
||||
|
||||
#include "src/api-arguments.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/objects.h"
|
||||
|
||||
namespace v8 {
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "src/ic/ic-stats.h"
|
||||
#include "src/ic/stub-cache.h"
|
||||
#include "src/isolate-inl.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/objects/api-callbacks.h"
|
||||
#include "src/objects/data-handler-inl.h"
|
||||
#include "src/objects/hash-table-inl.h"
|
||||
|
@ -7,10 +7,10 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "src/assembler-arch.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/machine-type.h"
|
||||
#include "src/register-arch.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
#include "src/interpreter/interpreter.h"
|
||||
#include "src/machine-type.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/zone/zone.h"
|
||||
|
||||
|
@ -44,345 +44,12 @@
|
||||
#include "src/external-reference.h"
|
||||
#include "src/label.h"
|
||||
#include "src/mips/constants-mips.h"
|
||||
#include "src/mips/register-mips.h"
|
||||
#include "src/objects/smi.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
|
||||
V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(t7) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
|
||||
V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(a0) V(a1) V(a2) V(a3) \
|
||||
V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(s7) \
|
||||
V(v0) V(v1)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
|
||||
V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
|
||||
V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
|
||||
V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS(V) \
|
||||
V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \
|
||||
V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \
|
||||
V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \
|
||||
V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
|
||||
V(f16) V(f18) V(f20) V(f22) V(f24)
|
||||
// clang-format on
|
||||
|
||||
// Register lists.
|
||||
// Note that the bit values must match those used in actual instruction
|
||||
// encoding.
|
||||
const int kNumRegs = 32;
|
||||
|
||||
const RegList kJSCallerSaved = 1 << 2 | // v0
|
||||
1 << 3 | // v1
|
||||
1 << 4 | // a0
|
||||
1 << 5 | // a1
|
||||
1 << 6 | // a2
|
||||
1 << 7 | // a3
|
||||
1 << 8 | // t0
|
||||
1 << 9 | // t1
|
||||
1 << 10 | // t2
|
||||
1 << 11 | // t3
|
||||
1 << 12 | // t4
|
||||
1 << 13 | // t5
|
||||
1 << 14 | // t6
|
||||
1 << 15; // t7
|
||||
|
||||
const int kNumJSCallerSaved = 14;
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript.
|
||||
const RegList kCalleeSaved = 1 << 16 | // s0
|
||||
1 << 17 | // s1
|
||||
1 << 18 | // s2
|
||||
1 << 19 | // s3
|
||||
1 << 20 | // s4
|
||||
1 << 21 | // s5
|
||||
1 << 22 | // s6 (roots in Javascript code)
|
||||
1 << 23 | // s7 (cp in Javascript code)
|
||||
1 << 30; // fp/s8
|
||||
|
||||
const int kNumCalleeSaved = 9;
|
||||
|
||||
const RegList kCalleeSavedFPU = 1 << 20 | // f20
|
||||
1 << 22 | // f22
|
||||
1 << 24 | // f24
|
||||
1 << 26 | // f26
|
||||
1 << 28 | // f28
|
||||
1 << 30; // f30
|
||||
|
||||
const int kNumCalleeSavedFPU = 6;
|
||||
|
||||
const RegList kCallerSavedFPU = 1 << 0 | // f0
|
||||
1 << 2 | // f2
|
||||
1 << 4 | // f4
|
||||
1 << 6 | // f6
|
||||
1 << 8 | // f8
|
||||
1 << 10 | // f10
|
||||
1 << 12 | // f12
|
||||
1 << 14 | // f14
|
||||
1 << 16 | // f16
|
||||
1 << 18; // f18
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
const int kNumSafepointRegisters = 24;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
const int kUndefIndex = -1;
|
||||
// Map with indexes on stack that corresponds to codes of saved registers.
|
||||
const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg
|
||||
kUndefIndex, // at
|
||||
0, // v0
|
||||
1, // v1
|
||||
2, // a0
|
||||
3, // a1
|
||||
4, // a2
|
||||
5, // a3
|
||||
6, // t0
|
||||
7, // t1
|
||||
8, // t2
|
||||
9, // t3
|
||||
10, // t4
|
||||
11, // t5
|
||||
12, // t6
|
||||
13, // t7
|
||||
14, // s0
|
||||
15, // s1
|
||||
16, // s2
|
||||
17, // s3
|
||||
18, // s4
|
||||
19, // s5
|
||||
20, // s6
|
||||
21, // s7
|
||||
kUndefIndex, // t8
|
||||
kUndefIndex, // t9
|
||||
kUndefIndex, // k0
|
||||
kUndefIndex, // k1
|
||||
kUndefIndex, // gp
|
||||
kUndefIndex, // sp
|
||||
22, // fp
|
||||
kUndefIndex};
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum, but enum values are assignment-
|
||||
// compatible with int, which has caused code-generation bugs.
|
||||
//
|
||||
// 2) We would prefer to use a class instead of a struct but we don't like
|
||||
// the register initialization to depend on the particular initialization
|
||||
// order (which appears to be different on OS X, Linux, and Windows for the
|
||||
// installed versions of C++ we tried). Using a struct permits C-style
|
||||
// "initialization". Also, the Register objects cannot be const as this
|
||||
// forces initialization stubs in MSVC, making us dependent on initialization
|
||||
// order.
|
||||
//
|
||||
// 3) By not using an enum, we are possibly preventing the compiler from
|
||||
// doing certain constant folds, which may significantly reduce the
|
||||
// code generated for some assembly instructions (because they boil down
|
||||
// to a few constants). If this is a problem, we could change the code
|
||||
// such that we use an enum in optimized mode, and the struct in debug
|
||||
// mode. This way we get the compile-time error checking in debug mode
|
||||
// and best performance in optimized code.
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register and FPURegister.
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
static constexpr int kMantissaOffset = 0;
|
||||
static constexpr int kExponentOffset = 4;
|
||||
#elif defined(V8_TARGET_BIG_ENDIAN)
|
||||
static constexpr int kMantissaOffset = 4;
|
||||
static constexpr int kExponentOffset = 0;
|
||||
#else
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// s7: context register
|
||||
// s3: scratch register
|
||||
// s4: scratch register 2
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
int ToNumber(Register reg);
|
||||
|
||||
Register ToRegister(int num);
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register.
|
||||
class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
|
||||
public:
|
||||
FPURegister low() const {
|
||||
// Find low reg of a Double-reg pair, which is the reg itself.
|
||||
DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code());
|
||||
}
|
||||
FPURegister high() const {
|
||||
// Find high reg of a Doubel-reg pair, which is reg + 1.
|
||||
DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code() + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr FPURegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
enum MSARegisterCode {
|
||||
#define REGISTER_CODE(R) kMsaCode_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kMsaAfterLast
|
||||
};
|
||||
|
||||
// MIPS SIMD (MSA) register
|
||||
class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr MSARegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0.
|
||||
// f28: 0.0
|
||||
// f30: scratch register.
|
||||
|
||||
// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
|
||||
// 32-bit registers, f0 through f31. When used as 'double' they are used
|
||||
// in pairs, starting with the even numbered register. So a double operation
|
||||
// on f0 really uses f0 and f1.
|
||||
// (Modern mips hardware also supports 32 64-bit registers, via setting
|
||||
// (priviledged) Status Register FR bit to 1. This is used by the N32 ABI,
|
||||
// but it is not in common use. Someday we will want to support this in v8.)
|
||||
|
||||
// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
|
||||
typedef FPURegister FloatRegister;
|
||||
|
||||
typedef FPURegister DoubleRegister;
|
||||
|
||||
#define DECLARE_DOUBLE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
|
||||
#undef DECLARE_DOUBLE_REGISTER
|
||||
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
// SIMD registers.
|
||||
typedef MSARegister Simd128Register;
|
||||
|
||||
#define DECLARE_SIMD128_REGISTER(R) \
|
||||
constexpr Simd128Register R = Simd128Register::from_code<kMsaCode_##R>();
|
||||
SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
|
||||
#undef DECLARE_SIMD128_REGISTER
|
||||
|
||||
const Simd128Register no_msareg = Simd128Register::no_reg();
|
||||
|
||||
// Register aliases.
|
||||
// cp is assumed to be a callee saved register.
|
||||
constexpr Register kRootRegister = s6;
|
||||
constexpr Register cp = s7;
|
||||
constexpr Register kScratchReg = s3;
|
||||
constexpr Register kScratchReg2 = s4;
|
||||
constexpr DoubleRegister kScratchDoubleReg = f30;
|
||||
constexpr DoubleRegister kDoubleRegZero = f28;
|
||||
// Used on mips32r6 for compare operations.
|
||||
constexpr DoubleRegister kDoubleCompareReg = f26;
|
||||
// MSA zero and scratch regs must have the same numbers as FPU zero and scratch
|
||||
constexpr Simd128Register kSimd128RegZero = w28;
|
||||
constexpr Simd128Register kSimd128ScratchReg = w30;
|
||||
|
||||
// FPU (coprocessor 1) control registers.
|
||||
// Currently only FCSR (#31) is implemented.
|
||||
struct FPUControlRegister {
|
||||
bool is_valid() const { return reg_code == kFCSRRegister; }
|
||||
bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
|
||||
constexpr FPUControlRegister FCSR = {kFCSRRegister};
|
||||
|
||||
// MSA control registers
|
||||
struct MSAControlRegister {
|
||||
bool is_valid() const {
|
||||
return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister);
|
||||
}
|
||||
bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister};
|
||||
constexpr MSAControlRegister MSAIR = {kMSAIRRegister};
|
||||
constexpr MSAControlRegister MSACSR = {kMSACSRRegister};
|
||||
|
||||
// Allow programmer to use Branch Delay Slot of Branches, Jumps, Calls.
|
||||
enum BranchDelaySlot { USE_DELAY_SLOT, PROTECT };
|
||||
|
||||
@ -2254,10 +1921,6 @@ class UseScratchRegisterScope {
|
||||
RegList old_available_;
|
||||
};
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -5,7 +5,8 @@
|
||||
#if V8_TARGET_ARCH_MIPS
|
||||
|
||||
#include "src/interface-descriptors.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
#include "src/frames.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -17,32 +17,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = v0;
|
||||
constexpr Register kReturnRegister1 = v1;
|
||||
constexpr Register kReturnRegister2 = a0;
|
||||
constexpr Register kJSFunctionRegister = a1;
|
||||
constexpr Register kContextRegister = s7;
|
||||
constexpr Register kAllocateSizeRegister = a0;
|
||||
constexpr Register kSpeculationPoisonRegister = t3;
|
||||
constexpr Register kInterpreterAccumulatorRegister = v0;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = t4;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = t5;
|
||||
constexpr Register kInterpreterDispatchTableRegister = t6;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = a0;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = a2;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = a3;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = a2;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = at;
|
||||
constexpr Register kRuntimeCallFunctionRegister = a1;
|
||||
constexpr Register kRuntimeCallArgCountRegister = a0;
|
||||
constexpr Register kRuntimeCallArgvRegister = a2;
|
||||
constexpr Register kWasmInstanceRegister = a0;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
|
||||
|
||||
// Forward declarations
|
||||
enum class AbortReason : uint8_t;
|
||||
|
||||
|
382
src/mips/register-mips.h
Normal file
382
src/mips/register-mips.h
Normal file
@ -0,0 +1,382 @@
|
||||
// Copyright 2018 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_MIPS_REGISTER_MIPS_H_
|
||||
#define V8_MIPS_REGISTER_MIPS_H_
|
||||
|
||||
#include "src/mips/constants-mips.h"
|
||||
#include "src/register.h"
|
||||
#include "src/reglist.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
|
||||
V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(t7) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
|
||||
V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(a0) V(a1) V(a2) V(a3) \
|
||||
V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(s7) \
|
||||
V(v0) V(v1)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
|
||||
V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
|
||||
V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
|
||||
V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS(V) \
|
||||
V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \
|
||||
V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \
|
||||
V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \
|
||||
V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
|
||||
V(f16) V(f18) V(f20) V(f22) V(f24)
|
||||
// clang-format on
|
||||
|
||||
// Register lists.
|
||||
// Note that the bit values must match those used in actual instruction
|
||||
// encoding.
|
||||
const int kNumRegs = 32;
|
||||
|
||||
const RegList kJSCallerSaved = 1 << 2 | // v0
|
||||
1 << 3 | // v1
|
||||
1 << 4 | // a0
|
||||
1 << 5 | // a1
|
||||
1 << 6 | // a2
|
||||
1 << 7 | // a3
|
||||
1 << 8 | // t0
|
||||
1 << 9 | // t1
|
||||
1 << 10 | // t2
|
||||
1 << 11 | // t3
|
||||
1 << 12 | // t4
|
||||
1 << 13 | // t5
|
||||
1 << 14 | // t6
|
||||
1 << 15; // t7
|
||||
|
||||
const int kNumJSCallerSaved = 14;
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript.
|
||||
const RegList kCalleeSaved = 1 << 16 | // s0
|
||||
1 << 17 | // s1
|
||||
1 << 18 | // s2
|
||||
1 << 19 | // s3
|
||||
1 << 20 | // s4
|
||||
1 << 21 | // s5
|
||||
1 << 22 | // s6 (roots in Javascript code)
|
||||
1 << 23 | // s7 (cp in Javascript code)
|
||||
1 << 30; // fp/s8
|
||||
|
||||
const int kNumCalleeSaved = 9;
|
||||
|
||||
const RegList kCalleeSavedFPU = 1 << 20 | // f20
|
||||
1 << 22 | // f22
|
||||
1 << 24 | // f24
|
||||
1 << 26 | // f26
|
||||
1 << 28 | // f28
|
||||
1 << 30; // f30
|
||||
|
||||
const int kNumCalleeSavedFPU = 6;
|
||||
|
||||
const RegList kCallerSavedFPU = 1 << 0 | // f0
|
||||
1 << 2 | // f2
|
||||
1 << 4 | // f4
|
||||
1 << 6 | // f6
|
||||
1 << 8 | // f8
|
||||
1 << 10 | // f10
|
||||
1 << 12 | // f12
|
||||
1 << 14 | // f14
|
||||
1 << 16 | // f16
|
||||
1 << 18; // f18
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
const int kNumSafepointRegisters = 24;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
const int kUndefIndex = -1;
|
||||
// Map with indexes on stack that corresponds to codes of saved registers.
|
||||
const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg
|
||||
kUndefIndex, // at
|
||||
0, // v0
|
||||
1, // v1
|
||||
2, // a0
|
||||
3, // a1
|
||||
4, // a2
|
||||
5, // a3
|
||||
6, // t0
|
||||
7, // t1
|
||||
8, // t2
|
||||
9, // t3
|
||||
10, // t4
|
||||
11, // t5
|
||||
12, // t6
|
||||
13, // t7
|
||||
14, // s0
|
||||
15, // s1
|
||||
16, // s2
|
||||
17, // s3
|
||||
18, // s4
|
||||
19, // s5
|
||||
20, // s6
|
||||
21, // s7
|
||||
kUndefIndex, // t8
|
||||
kUndefIndex, // t9
|
||||
kUndefIndex, // k0
|
||||
kUndefIndex, // k1
|
||||
kUndefIndex, // gp
|
||||
kUndefIndex, // sp
|
||||
22, // fp
|
||||
kUndefIndex};
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum, but enum values are assignment-
|
||||
// compatible with int, which has caused code-generation bugs.
|
||||
//
|
||||
// 2) We would prefer to use a class instead of a struct but we don't like
|
||||
// the register initialization to depend on the particular initialization
|
||||
// order (which appears to be different on OS X, Linux, and Windows for the
|
||||
// installed versions of C++ we tried). Using a struct permits C-style
|
||||
// "initialization". Also, the Register objects cannot be const as this
|
||||
// forces initialization stubs in MSVC, making us dependent on initialization
|
||||
// order.
|
||||
//
|
||||
// 3) By not using an enum, we are possibly preventing the compiler from
|
||||
// doing certain constant folds, which may significantly reduce the
|
||||
// code generated for some assembly instructions (because they boil down
|
||||
// to a few constants). If this is a problem, we could change the code
|
||||
// such that we use an enum in optimized mode, and the struct in debug
|
||||
// mode. This way we get the compile-time error checking in debug mode
|
||||
// and best performance in optimized code.
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register and FPURegister.
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
static constexpr int kMantissaOffset = 0;
|
||||
static constexpr int kExponentOffset = 4;
|
||||
#elif defined(V8_TARGET_BIG_ENDIAN)
|
||||
static constexpr int kMantissaOffset = 4;
|
||||
static constexpr int kExponentOffset = 0;
|
||||
#else
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// s7: context register
|
||||
// s3: scratch register
|
||||
// s4: scratch register 2
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
int ToNumber(Register reg);
|
||||
|
||||
Register ToRegister(int num);
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register.
|
||||
class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
|
||||
public:
|
||||
FPURegister low() const {
|
||||
// Find low reg of a Double-reg pair, which is the reg itself.
|
||||
DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code());
|
||||
}
|
||||
FPURegister high() const {
|
||||
// Find high reg of a Doubel-reg pair, which is reg + 1.
|
||||
DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code() + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr FPURegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
enum MSARegisterCode {
|
||||
#define REGISTER_CODE(R) kMsaCode_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kMsaAfterLast
|
||||
};
|
||||
|
||||
// MIPS SIMD (MSA) register
|
||||
class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr MSARegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0.
|
||||
// f28: 0.0
|
||||
// f30: scratch register.
|
||||
|
||||
// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
|
||||
// 32-bit registers, f0 through f31. When used as 'double' they are used
|
||||
// in pairs, starting with the even numbered register. So a double operation
|
||||
// on f0 really uses f0 and f1.
|
||||
// (Modern mips hardware also supports 32 64-bit registers, via setting
|
||||
// (priviledged) Status Register FR bit to 1. This is used by the N32 ABI,
|
||||
// but it is not in common use. Someday we will want to support this in v8.)
|
||||
|
||||
// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
|
||||
typedef FPURegister FloatRegister;
|
||||
|
||||
typedef FPURegister DoubleRegister;
|
||||
|
||||
#define DECLARE_DOUBLE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
|
||||
#undef DECLARE_DOUBLE_REGISTER
|
||||
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
// SIMD registers.
|
||||
typedef MSARegister Simd128Register;
|
||||
|
||||
#define DECLARE_SIMD128_REGISTER(R) \
|
||||
constexpr Simd128Register R = Simd128Register::from_code<kMsaCode_##R>();
|
||||
SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
|
||||
#undef DECLARE_SIMD128_REGISTER
|
||||
|
||||
const Simd128Register no_msareg = Simd128Register::no_reg();
|
||||
|
||||
// Register aliases.
|
||||
// cp is assumed to be a callee saved register.
|
||||
constexpr Register kRootRegister = s6;
|
||||
constexpr Register cp = s7;
|
||||
constexpr Register kScratchReg = s3;
|
||||
constexpr Register kScratchReg2 = s4;
|
||||
constexpr DoubleRegister kScratchDoubleReg = f30;
|
||||
constexpr DoubleRegister kDoubleRegZero = f28;
|
||||
// Used on mips32r6 for compare operations.
|
||||
constexpr DoubleRegister kDoubleCompareReg = f26;
|
||||
// MSA zero and scratch regs must have the same numbers as FPU zero and scratch
|
||||
constexpr Simd128Register kSimd128RegZero = w28;
|
||||
constexpr Simd128Register kSimd128ScratchReg = w30;
|
||||
|
||||
// FPU (coprocessor 1) control registers.
|
||||
// Currently only FCSR (#31) is implemented.
|
||||
struct FPUControlRegister {
|
||||
bool is_valid() const { return reg_code == kFCSRRegister; }
|
||||
bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
|
||||
constexpr FPUControlRegister FCSR = {kFCSRRegister};
|
||||
|
||||
// MSA control registers
|
||||
struct MSAControlRegister {
|
||||
bool is_valid() const {
|
||||
return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister);
|
||||
}
|
||||
bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister};
|
||||
constexpr MSAControlRegister MSAIR = {kMSAIRRegister};
|
||||
constexpr MSAControlRegister MSACSR = {kMSACSRRegister};
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS)
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = v0;
|
||||
constexpr Register kReturnRegister1 = v1;
|
||||
constexpr Register kReturnRegister2 = a0;
|
||||
constexpr Register kJSFunctionRegister = a1;
|
||||
constexpr Register kContextRegister = s7;
|
||||
constexpr Register kAllocateSizeRegister = a0;
|
||||
constexpr Register kSpeculationPoisonRegister = t3;
|
||||
constexpr Register kInterpreterAccumulatorRegister = v0;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = t4;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = t5;
|
||||
constexpr Register kInterpreterDispatchTableRegister = t6;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = a0;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = a2;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = a3;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = a2;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = at;
|
||||
constexpr Register kRuntimeCallFunctionRegister = a1;
|
||||
constexpr Register kRuntimeCallArgCountRegister = a0;
|
||||
constexpr Register kRuntimeCallArgvRegister = a2;
|
||||
constexpr Register kWasmInstanceRegister = a0;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_MIPS_REGISTER_MIPS_H_
|
@ -44,352 +44,12 @@
|
||||
#include "src/external-reference.h"
|
||||
#include "src/label.h"
|
||||
#include "src/mips64/constants-mips64.h"
|
||||
#include "src/mips64/register-mips64.h"
|
||||
#include "src/objects/smi.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
|
||||
V(a4) V(a5) V(a6) V(a7) V(t0) V(t1) V(t2) V(t3) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
|
||||
V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(a0) V(a1) V(a2) V(a3) \
|
||||
V(a4) V(a5) V(a6) V(a7) V(t0) V(t1) V(t2) V(s7) \
|
||||
V(v0) V(v1)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
|
||||
V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
|
||||
V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
|
||||
V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS(V) \
|
||||
V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \
|
||||
V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \
|
||||
V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \
|
||||
V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
|
||||
V(f16) V(f18) V(f20) V(f22) V(f24) V(f26)
|
||||
// clang-format on
|
||||
|
||||
// Note that the bit values must match those used in actual instruction
|
||||
// encoding.
|
||||
const int kNumRegs = 32;
|
||||
|
||||
const RegList kJSCallerSaved = 1 << 2 | // v0
|
||||
1 << 3 | // v1
|
||||
1 << 4 | // a0
|
||||
1 << 5 | // a1
|
||||
1 << 6 | // a2
|
||||
1 << 7 | // a3
|
||||
1 << 8 | // a4
|
||||
1 << 9 | // a5
|
||||
1 << 10 | // a6
|
||||
1 << 11 | // a7
|
||||
1 << 12 | // t0
|
||||
1 << 13 | // t1
|
||||
1 << 14 | // t2
|
||||
1 << 15; // t3
|
||||
|
||||
const int kNumJSCallerSaved = 14;
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript.
|
||||
const RegList kCalleeSaved = 1 << 16 | // s0
|
||||
1 << 17 | // s1
|
||||
1 << 18 | // s2
|
||||
1 << 19 | // s3
|
||||
1 << 20 | // s4
|
||||
1 << 21 | // s5
|
||||
1 << 22 | // s6 (roots in Javascript code)
|
||||
1 << 23 | // s7 (cp in Javascript code)
|
||||
1 << 30; // fp/s8
|
||||
|
||||
const int kNumCalleeSaved = 9;
|
||||
|
||||
const RegList kCalleeSavedFPU = 1 << 20 | // f20
|
||||
1 << 22 | // f22
|
||||
1 << 24 | // f24
|
||||
1 << 26 | // f26
|
||||
1 << 28 | // f28
|
||||
1 << 30; // f30
|
||||
|
||||
const int kNumCalleeSavedFPU = 6;
|
||||
|
||||
const RegList kCallerSavedFPU = 1 << 0 | // f0
|
||||
1 << 2 | // f2
|
||||
1 << 4 | // f4
|
||||
1 << 6 | // f6
|
||||
1 << 8 | // f8
|
||||
1 << 10 | // f10
|
||||
1 << 12 | // f12
|
||||
1 << 14 | // f14
|
||||
1 << 16 | // f16
|
||||
1 << 18; // f18
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
const int kNumSafepointRegisters = 24;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
const int kUndefIndex = -1;
|
||||
// Map with indexes on stack that corresponds to codes of saved registers.
|
||||
const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg
|
||||
kUndefIndex, // at
|
||||
0, // v0
|
||||
1, // v1
|
||||
2, // a0
|
||||
3, // a1
|
||||
4, // a2
|
||||
5, // a3
|
||||
6, // a4
|
||||
7, // a5
|
||||
8, // a6
|
||||
9, // a7
|
||||
10, // t0
|
||||
11, // t1
|
||||
12, // t2
|
||||
13, // t3
|
||||
14, // s0
|
||||
15, // s1
|
||||
16, // s2
|
||||
17, // s3
|
||||
18, // s4
|
||||
19, // s5
|
||||
20, // s6
|
||||
21, // s7
|
||||
kUndefIndex, // t8
|
||||
kUndefIndex, // t9
|
||||
kUndefIndex, // k0
|
||||
kUndefIndex, // k1
|
||||
kUndefIndex, // gp
|
||||
kUndefIndex, // sp
|
||||
22, // fp
|
||||
kUndefIndex};
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum, but enum values are assignment-
|
||||
// compatible with int, which has caused code-generation bugs.
|
||||
//
|
||||
// 2) We would prefer to use a class instead of a struct but we don't like
|
||||
// the register initialization to depend on the particular initialization
|
||||
// order (which appears to be different on OS X, Linux, and Windows for the
|
||||
// installed versions of C++ we tried). Using a struct permits C-style
|
||||
// "initialization". Also, the Register objects cannot be const as this
|
||||
// forces initialization stubs in MSVC, making us dependent on initialization
|
||||
// order.
|
||||
//
|
||||
// 3) By not using an enum, we are possibly preventing the compiler from
|
||||
// doing certain constant folds, which may significantly reduce the
|
||||
// code generated for some assembly instructions (because they boil down
|
||||
// to a few constants). If this is a problem, we could change the code
|
||||
// such that we use an enum in optimized mode, and the struct in debug
|
||||
// mode. This way we get the compile-time error checking in debug mode
|
||||
// and best performance in optimized code.
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register and FPURegister.
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
static constexpr int kMantissaOffset = 0;
|
||||
static constexpr int kExponentOffset = 4;
|
||||
#elif defined(V8_TARGET_BIG_ENDIAN)
|
||||
static constexpr int kMantissaOffset = 4;
|
||||
static constexpr int kExponentOffset = 0;
|
||||
#else
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// s7: context register
|
||||
// s3: scratch register
|
||||
// s4: scratch register 2
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
int ToNumber(Register reg);
|
||||
|
||||
Register ToRegister(int num);
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register.
|
||||
class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
|
||||
public:
|
||||
// TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
|
||||
// to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
|
||||
// number of Double regs (64-bit regs, or FPU-reg-pairs).
|
||||
|
||||
FPURegister low() const {
|
||||
// TODO(plind): Create DCHECK for FR=0 mode. This usage suspect for FR=1.
|
||||
// Find low reg of a Double-reg pair, which is the reg itself.
|
||||
DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code());
|
||||
}
|
||||
FPURegister high() const {
|
||||
// TODO(plind): Create DCHECK for FR=0 mode. This usage illegal in FR=1.
|
||||
// Find high reg of a Doubel-reg pair, which is reg + 1.
|
||||
DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code() + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr FPURegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
enum MSARegisterCode {
|
||||
#define REGISTER_CODE(R) kMsaCode_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kMsaAfterLast
|
||||
};
|
||||
|
||||
// MIPS SIMD (MSA) register
|
||||
class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr MSARegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0.
|
||||
// f28: 0.0
|
||||
// f30: scratch register.
|
||||
|
||||
// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
|
||||
// 32-bit registers, f0 through f31. When used as 'double' they are used
|
||||
// in pairs, starting with the even numbered register. So a double operation
|
||||
// on f0 really uses f0 and f1.
|
||||
// (Modern mips hardware also supports 32 64-bit registers, via setting
|
||||
// (privileged) Status Register FR bit to 1. This is used by the N32 ABI,
|
||||
// but it is not in common use. Someday we will want to support this in v8.)
|
||||
|
||||
// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
|
||||
typedef FPURegister FloatRegister;
|
||||
|
||||
typedef FPURegister DoubleRegister;
|
||||
|
||||
#define DECLARE_DOUBLE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
|
||||
#undef DECLARE_DOUBLE_REGISTER
|
||||
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
// SIMD registers.
|
||||
typedef MSARegister Simd128Register;
|
||||
|
||||
#define DECLARE_SIMD128_REGISTER(R) \
|
||||
constexpr Simd128Register R = Simd128Register::from_code<kMsaCode_##R>();
|
||||
SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
|
||||
#undef DECLARE_SIMD128_REGISTER
|
||||
|
||||
const Simd128Register no_msareg = Simd128Register::no_reg();
|
||||
|
||||
// Register aliases.
|
||||
// cp is assumed to be a callee saved register.
|
||||
constexpr Register kRootRegister = s6;
|
||||
constexpr Register cp = s7;
|
||||
constexpr Register kScratchReg = s3;
|
||||
constexpr Register kScratchReg2 = s4;
|
||||
constexpr DoubleRegister kScratchDoubleReg = f30;
|
||||
constexpr DoubleRegister kDoubleRegZero = f28;
|
||||
// Used on mips64r6 for compare operations.
|
||||
// We use the last non-callee saved odd register for N64 ABI
|
||||
constexpr DoubleRegister kDoubleCompareReg = f23;
|
||||
// MSA zero and scratch regs must have the same numbers as FPU zero and scratch
|
||||
constexpr Simd128Register kSimd128RegZero = w28;
|
||||
constexpr Simd128Register kSimd128ScratchReg = w30;
|
||||
|
||||
// FPU (coprocessor 1) control registers.
|
||||
// Currently only FCSR (#31) is implemented.
|
||||
struct FPUControlRegister {
|
||||
bool is_valid() const { return reg_code == kFCSRRegister; }
|
||||
bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
|
||||
constexpr FPUControlRegister FCSR = {kFCSRRegister};
|
||||
|
||||
// MSA control registers
|
||||
struct MSAControlRegister {
|
||||
bool is_valid() const {
|
||||
return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister);
|
||||
}
|
||||
bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister};
|
||||
constexpr MSAControlRegister MSAIR = {kMSAIRRegister};
|
||||
constexpr MSAControlRegister MSACSR = {kMSACSRRegister};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Machine instruction Operands.
|
||||
constexpr int kSmiShift = kSmiTagSize + kSmiShiftSize;
|
||||
@ -2289,11 +1949,6 @@ class UseScratchRegisterScope {
|
||||
RegList old_available_;
|
||||
};
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
#if V8_TARGET_ARCH_MIPS64
|
||||
|
||||
#include "src/interface-descriptors.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
#include "src/frames.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -16,32 +16,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = v0;
|
||||
constexpr Register kReturnRegister1 = v1;
|
||||
constexpr Register kReturnRegister2 = a0;
|
||||
constexpr Register kJSFunctionRegister = a1;
|
||||
constexpr Register kContextRegister = s7;
|
||||
constexpr Register kAllocateSizeRegister = a0;
|
||||
constexpr Register kSpeculationPoisonRegister = a7;
|
||||
constexpr Register kInterpreterAccumulatorRegister = v0;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = t0;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = t1;
|
||||
constexpr Register kInterpreterDispatchTableRegister = t2;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = a0;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = a2;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = a3;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = a2;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = at;
|
||||
constexpr Register kRuntimeCallFunctionRegister = a1;
|
||||
constexpr Register kRuntimeCallArgCountRegister = a0;
|
||||
constexpr Register kRuntimeCallArgvRegister = a2;
|
||||
constexpr Register kWasmInstanceRegister = a0;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
|
||||
|
||||
// Forward declarations.
|
||||
enum class AbortReason : uint8_t;
|
||||
|
||||
|
389
src/mips64/register-mips64.h
Normal file
389
src/mips64/register-mips64.h
Normal file
@ -0,0 +1,389 @@
|
||||
// Copyright 2018 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_MIPS64_REGISTER_MIPS64_H_
|
||||
#define V8_MIPS64_REGISTER_MIPS64_H_
|
||||
|
||||
#include "src/mips64/constants-mips64.h"
|
||||
#include "src/register.h"
|
||||
#include "src/reglist.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
|
||||
V(a4) V(a5) V(a6) V(a7) V(t0) V(t1) V(t2) V(t3) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
|
||||
V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(a0) V(a1) V(a2) V(a3) \
|
||||
V(a4) V(a5) V(a6) V(a7) V(t0) V(t1) V(t2) V(s7) \
|
||||
V(v0) V(v1)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
|
||||
V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
|
||||
V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
|
||||
V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS(V) \
|
||||
V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \
|
||||
V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \
|
||||
V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \
|
||||
V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
|
||||
V(f16) V(f18) V(f20) V(f22) V(f24) V(f26)
|
||||
// clang-format on
|
||||
|
||||
// Note that the bit values must match those used in actual instruction
|
||||
// encoding.
|
||||
const int kNumRegs = 32;
|
||||
|
||||
const RegList kJSCallerSaved = 1 << 2 | // v0
|
||||
1 << 3 | // v1
|
||||
1 << 4 | // a0
|
||||
1 << 5 | // a1
|
||||
1 << 6 | // a2
|
||||
1 << 7 | // a3
|
||||
1 << 8 | // a4
|
||||
1 << 9 | // a5
|
||||
1 << 10 | // a6
|
||||
1 << 11 | // a7
|
||||
1 << 12 | // t0
|
||||
1 << 13 | // t1
|
||||
1 << 14 | // t2
|
||||
1 << 15; // t3
|
||||
|
||||
const int kNumJSCallerSaved = 14;
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript.
|
||||
const RegList kCalleeSaved = 1 << 16 | // s0
|
||||
1 << 17 | // s1
|
||||
1 << 18 | // s2
|
||||
1 << 19 | // s3
|
||||
1 << 20 | // s4
|
||||
1 << 21 | // s5
|
||||
1 << 22 | // s6 (roots in Javascript code)
|
||||
1 << 23 | // s7 (cp in Javascript code)
|
||||
1 << 30; // fp/s8
|
||||
|
||||
const int kNumCalleeSaved = 9;
|
||||
|
||||
const RegList kCalleeSavedFPU = 1 << 20 | // f20
|
||||
1 << 22 | // f22
|
||||
1 << 24 | // f24
|
||||
1 << 26 | // f26
|
||||
1 << 28 | // f28
|
||||
1 << 30; // f30
|
||||
|
||||
const int kNumCalleeSavedFPU = 6;
|
||||
|
||||
const RegList kCallerSavedFPU = 1 << 0 | // f0
|
||||
1 << 2 | // f2
|
||||
1 << 4 | // f4
|
||||
1 << 6 | // f6
|
||||
1 << 8 | // f8
|
||||
1 << 10 | // f10
|
||||
1 << 12 | // f12
|
||||
1 << 14 | // f14
|
||||
1 << 16 | // f16
|
||||
1 << 18; // f18
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
const int kNumSafepointRegisters = 24;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
const int kUndefIndex = -1;
|
||||
// Map with indexes on stack that corresponds to codes of saved registers.
|
||||
const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg
|
||||
kUndefIndex, // at
|
||||
0, // v0
|
||||
1, // v1
|
||||
2, // a0
|
||||
3, // a1
|
||||
4, // a2
|
||||
5, // a3
|
||||
6, // a4
|
||||
7, // a5
|
||||
8, // a6
|
||||
9, // a7
|
||||
10, // t0
|
||||
11, // t1
|
||||
12, // t2
|
||||
13, // t3
|
||||
14, // s0
|
||||
15, // s1
|
||||
16, // s2
|
||||
17, // s3
|
||||
18, // s4
|
||||
19, // s5
|
||||
20, // s6
|
||||
21, // s7
|
||||
kUndefIndex, // t8
|
||||
kUndefIndex, // t9
|
||||
kUndefIndex, // k0
|
||||
kUndefIndex, // k1
|
||||
kUndefIndex, // gp
|
||||
kUndefIndex, // sp
|
||||
22, // fp
|
||||
kUndefIndex};
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum, but enum values are assignment-
|
||||
// compatible with int, which has caused code-generation bugs.
|
||||
//
|
||||
// 2) We would prefer to use a class instead of a struct but we don't like
|
||||
// the register initialization to depend on the particular initialization
|
||||
// order (which appears to be different on OS X, Linux, and Windows for the
|
||||
// installed versions of C++ we tried). Using a struct permits C-style
|
||||
// "initialization". Also, the Register objects cannot be const as this
|
||||
// forces initialization stubs in MSVC, making us dependent on initialization
|
||||
// order.
|
||||
//
|
||||
// 3) By not using an enum, we are possibly preventing the compiler from
|
||||
// doing certain constant folds, which may significantly reduce the
|
||||
// code generated for some assembly instructions (because they boil down
|
||||
// to a few constants). If this is a problem, we could change the code
|
||||
// such that we use an enum in optimized mode, and the struct in debug
|
||||
// mode. This way we get the compile-time error checking in debug mode
|
||||
// and best performance in optimized code.
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register and FPURegister.
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
static constexpr int kMantissaOffset = 0;
|
||||
static constexpr int kExponentOffset = 4;
|
||||
#elif defined(V8_TARGET_BIG_ENDIAN)
|
||||
static constexpr int kMantissaOffset = 4;
|
||||
static constexpr int kExponentOffset = 0;
|
||||
#else
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// s7: context register
|
||||
// s3: scratch register
|
||||
// s4: scratch register 2
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
int ToNumber(Register reg);
|
||||
|
||||
Register ToRegister(int num);
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register.
|
||||
class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
|
||||
public:
|
||||
// TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
|
||||
// to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
|
||||
// number of Double regs (64-bit regs, or FPU-reg-pairs).
|
||||
|
||||
FPURegister low() const {
|
||||
// TODO(plind): Create DCHECK for FR=0 mode. This usage suspect for FR=1.
|
||||
// Find low reg of a Double-reg pair, which is the reg itself.
|
||||
DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code());
|
||||
}
|
||||
FPURegister high() const {
|
||||
// TODO(plind): Create DCHECK for FR=0 mode. This usage illegal in FR=1.
|
||||
// Find high reg of a Doubel-reg pair, which is reg + 1.
|
||||
DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code() + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr FPURegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
enum MSARegisterCode {
|
||||
#define REGISTER_CODE(R) kMsaCode_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kMsaAfterLast
|
||||
};
|
||||
|
||||
// MIPS SIMD (MSA) register
|
||||
class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr MSARegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0.
|
||||
// f28: 0.0
|
||||
// f30: scratch register.
|
||||
|
||||
// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
|
||||
// 32-bit registers, f0 through f31. When used as 'double' they are used
|
||||
// in pairs, starting with the even numbered register. So a double operation
|
||||
// on f0 really uses f0 and f1.
|
||||
// (Modern mips hardware also supports 32 64-bit registers, via setting
|
||||
// (privileged) Status Register FR bit to 1. This is used by the N32 ABI,
|
||||
// but it is not in common use. Someday we will want to support this in v8.)
|
||||
|
||||
// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
|
||||
typedef FPURegister FloatRegister;
|
||||
|
||||
typedef FPURegister DoubleRegister;
|
||||
|
||||
#define DECLARE_DOUBLE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
|
||||
#undef DECLARE_DOUBLE_REGISTER
|
||||
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
// SIMD registers.
|
||||
typedef MSARegister Simd128Register;
|
||||
|
||||
#define DECLARE_SIMD128_REGISTER(R) \
|
||||
constexpr Simd128Register R = Simd128Register::from_code<kMsaCode_##R>();
|
||||
SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
|
||||
#undef DECLARE_SIMD128_REGISTER
|
||||
|
||||
const Simd128Register no_msareg = Simd128Register::no_reg();
|
||||
|
||||
// Register aliases.
|
||||
// cp is assumed to be a callee saved register.
|
||||
constexpr Register kRootRegister = s6;
|
||||
constexpr Register cp = s7;
|
||||
constexpr Register kScratchReg = s3;
|
||||
constexpr Register kScratchReg2 = s4;
|
||||
constexpr DoubleRegister kScratchDoubleReg = f30;
|
||||
constexpr DoubleRegister kDoubleRegZero = f28;
|
||||
// Used on mips64r6 for compare operations.
|
||||
// We use the last non-callee saved odd register for N64 ABI
|
||||
constexpr DoubleRegister kDoubleCompareReg = f23;
|
||||
// MSA zero and scratch regs must have the same numbers as FPU zero and scratch
|
||||
constexpr Simd128Register kSimd128RegZero = w28;
|
||||
constexpr Simd128Register kSimd128ScratchReg = w30;
|
||||
|
||||
// FPU (coprocessor 1) control registers.
|
||||
// Currently only FCSR (#31) is implemented.
|
||||
struct FPUControlRegister {
|
||||
bool is_valid() const { return reg_code == kFCSRRegister; }
|
||||
bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
|
||||
constexpr FPUControlRegister FCSR = {kFCSRRegister};
|
||||
|
||||
// MSA control registers
|
||||
struct MSAControlRegister {
|
||||
bool is_valid() const {
|
||||
return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister);
|
||||
}
|
||||
bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister};
|
||||
constexpr MSAControlRegister MSAIR = {kMSAIRRegister};
|
||||
constexpr MSAControlRegister MSACSR = {kMSACSRRegister};
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS)
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = v0;
|
||||
constexpr Register kReturnRegister1 = v1;
|
||||
constexpr Register kReturnRegister2 = a0;
|
||||
constexpr Register kJSFunctionRegister = a1;
|
||||
constexpr Register kContextRegister = s7;
|
||||
constexpr Register kAllocateSizeRegister = a0;
|
||||
constexpr Register kSpeculationPoisonRegister = a7;
|
||||
constexpr Register kInterpreterAccumulatorRegister = v0;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = t0;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = t1;
|
||||
constexpr Register kInterpreterDispatchTableRegister = t2;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = a0;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = a2;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = a3;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = a2;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = at;
|
||||
constexpr Register kRuntimeCallFunctionRegister = a1;
|
||||
constexpr Register kRuntimeCallArgCountRegister = a0;
|
||||
constexpr Register kRuntimeCallArgvRegister = a2;
|
||||
constexpr Register kWasmInstanceRegister = a0;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_MIPS64_REGISTER_MIPS64_H_
|
@ -13,7 +13,6 @@
|
||||
#include "src/elements.h"
|
||||
#include "src/field-type.h"
|
||||
#include "src/layout-descriptor.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects/arguments-inl.h"
|
||||
#include "src/objects/bigint.h"
|
||||
|
@ -50,317 +50,13 @@
|
||||
#include "src/label.h"
|
||||
#include "src/objects/smi.h"
|
||||
#include "src/ppc/constants-ppc.h"
|
||||
|
||||
#if V8_HOST_ARCH_PPC && \
|
||||
(V8_OS_AIX || (V8_TARGET_ARCH_PPC64 && V8_TARGET_BIG_ENDIAN))
|
||||
#define ABI_USES_FUNCTION_DESCRIPTORS 1
|
||||
#else
|
||||
#define ABI_USES_FUNCTION_DESCRIPTORS 0
|
||||
#endif
|
||||
|
||||
#if !V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64
|
||||
#define ABI_PASSES_HANDLES_IN_REGS 1
|
||||
#else
|
||||
#define ABI_PASSES_HANDLES_IN_REGS 0
|
||||
#endif
|
||||
|
||||
#if !V8_HOST_ARCH_PPC || !V8_TARGET_ARCH_PPC64 || V8_TARGET_LITTLE_ENDIAN
|
||||
#define ABI_RETURNS_OBJECT_PAIRS_IN_REGS 1
|
||||
#else
|
||||
#define ABI_RETURNS_OBJECT_PAIRS_IN_REGS 0
|
||||
#endif
|
||||
|
||||
#if !V8_HOST_ARCH_PPC || (V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN)
|
||||
#define ABI_CALL_VIA_IP 1
|
||||
#else
|
||||
#define ABI_CALL_VIA_IP 0
|
||||
#endif
|
||||
|
||||
#if !V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64
|
||||
#define ABI_TOC_REGISTER 2
|
||||
#else
|
||||
#define ABI_TOC_REGISTER 13
|
||||
#endif
|
||||
#include "src/ppc/register-ppc.h"
|
||||
|
||||
#define INSTR_AND_DATA_CACHE_COHERENCY LWSYNC
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(r0) V(sp) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(r11) V(ip) V(r13) V(r14) V(r15) \
|
||||
V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
|
||||
V(r24) V(r25) V(r26) V(r27) V(r28) V(r29) V(r30) V(fp)
|
||||
|
||||
#if V8_EMBEDDED_CONSTANT_POOL
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(r14) V(r15) \
|
||||
V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
|
||||
V(r24) V(r25) V(r26) V(r27) V(r30)
|
||||
#else
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(r14) V(r15) \
|
||||
V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
|
||||
V(r24) V(r25) V(r26) V(r27) V(r28) V(r30)
|
||||
#endif
|
||||
|
||||
#define LOW_DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15)
|
||||
|
||||
#define NON_LOW_DOUBLE_REGISTERS(V) \
|
||||
V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
LOW_DOUBLE_REGISTERS(V) NON_LOW_DOUBLE_REGISTERS(V)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS DOUBLE_REGISTERS
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d15) \
|
||||
V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define C_REGISTERS(V) \
|
||||
V(cr0) V(cr1) V(cr2) V(cr3) V(cr4) V(cr5) V(cr6) V(cr7) \
|
||||
V(cr8) V(cr9) V(cr10) V(cr11) V(cr12) V(cr15)
|
||||
// clang-format on
|
||||
|
||||
// Register list in load/store instructions
|
||||
// Note that the bit values must match those used in actual instruction encoding
|
||||
const int kNumRegs = 32;
|
||||
|
||||
// Caller-saved/arguments registers
|
||||
const RegList kJSCallerSaved = 1 << 3 | // r3 a1
|
||||
1 << 4 | // r4 a2
|
||||
1 << 5 | // r5 a3
|
||||
1 << 6 | // r6 a4
|
||||
1 << 7 | // r7 a5
|
||||
1 << 8 | // r8 a6
|
||||
1 << 9 | // r9 a7
|
||||
1 << 10 | // r10 a8
|
||||
1 << 11;
|
||||
|
||||
const int kNumJSCallerSaved = 9;
|
||||
|
||||
// Return the code of the n-th caller-saved register available to JavaScript
|
||||
// e.g. JSCallerSavedReg(0) returns r0.code() == 0
|
||||
int JSCallerSavedCode(int n);
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript
|
||||
const RegList kCalleeSaved = 1 << 14 | // r14
|
||||
1 << 15 | // r15
|
||||
1 << 16 | // r16
|
||||
1 << 17 | // r17
|
||||
1 << 18 | // r18
|
||||
1 << 19 | // r19
|
||||
1 << 20 | // r20
|
||||
1 << 21 | // r21
|
||||
1 << 22 | // r22
|
||||
1 << 23 | // r23
|
||||
1 << 24 | // r24
|
||||
1 << 25 | // r25
|
||||
1 << 26 | // r26
|
||||
1 << 27 | // r27
|
||||
1 << 28 | // r28
|
||||
1 << 29 | // r29
|
||||
1 << 30 | // r20
|
||||
1 << 31; // r31
|
||||
|
||||
const int kNumCalleeSaved = 18;
|
||||
|
||||
const RegList kCallerSavedDoubles = 1 << 0 | // d0
|
||||
1 << 1 | // d1
|
||||
1 << 2 | // d2
|
||||
1 << 3 | // d3
|
||||
1 << 4 | // d4
|
||||
1 << 5 | // d5
|
||||
1 << 6 | // d6
|
||||
1 << 7 | // d7
|
||||
1 << 8 | // d8
|
||||
1 << 9 | // d9
|
||||
1 << 10 | // d10
|
||||
1 << 11 | // d11
|
||||
1 << 12 | // d12
|
||||
1 << 13; // d13
|
||||
|
||||
const int kNumCallerSavedDoubles = 14;
|
||||
|
||||
const RegList kCalleeSavedDoubles = 1 << 14 | // d14
|
||||
1 << 15 | // d15
|
||||
1 << 16 | // d16
|
||||
1 << 17 | // d17
|
||||
1 << 18 | // d18
|
||||
1 << 19 | // d19
|
||||
1 << 20 | // d20
|
||||
1 << 21 | // d21
|
||||
1 << 22 | // d22
|
||||
1 << 23 | // d23
|
||||
1 << 24 | // d24
|
||||
1 << 25 | // d25
|
||||
1 << 26 | // d26
|
||||
1 << 27 | // d27
|
||||
1 << 28 | // d28
|
||||
1 << 29 | // d29
|
||||
1 << 30 | // d30
|
||||
1 << 31; // d31
|
||||
|
||||
const int kNumCalleeSavedDoubles = 18;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
const int kNumSafepointRegisters = 32;
|
||||
|
||||
// The following constants describe the stack frame linkage area as
|
||||
// defined by the ABI. Note that kNumRequiredStackFrameSlots must
|
||||
// satisfy alignment requirements (rounding up if required).
|
||||
#if V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN // ppc64le linux
|
||||
// [0] back chain
|
||||
// [1] condition register save area
|
||||
// [2] link register save area
|
||||
// [3] TOC save area
|
||||
// [4] Parameter1 save area
|
||||
// ...
|
||||
// [11] Parameter8 save area
|
||||
// [12] Parameter9 slot (if necessary)
|
||||
// ...
|
||||
const int kNumRequiredStackFrameSlots = 12;
|
||||
const int kStackFrameLRSlot = 2;
|
||||
const int kStackFrameExtraParamSlot = 12;
|
||||
#else // AIX
|
||||
// [0] back chain
|
||||
// [1] condition register save area
|
||||
// [2] link register save area
|
||||
// [3] reserved for compiler
|
||||
// [4] reserved by binder
|
||||
// [5] TOC save area
|
||||
// [6] Parameter1 save area
|
||||
// ...
|
||||
// [13] Parameter8 save area
|
||||
// [14] Parameter9 slot (if necessary)
|
||||
// ...
|
||||
const int kNumRequiredStackFrameSlots = 14;
|
||||
const int kStackFrameLRSlot = 2;
|
||||
const int kStackFrameExtraParamSlot = 14;
|
||||
#endif
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
#if V8_TARGET_LITTLE_ENDIAN
|
||||
static constexpr int kMantissaOffset = 0;
|
||||
static constexpr int kExponentOffset = 4;
|
||||
#else
|
||||
static constexpr int kMantissaOffset = 4;
|
||||
static constexpr int kExponentOffset = 0;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
// Aliases
|
||||
constexpr Register kConstantPoolRegister = r28; // Constant pool.
|
||||
constexpr Register kRootRegister = r29; // Roots array pointer.
|
||||
constexpr Register cp = r30; // JavaScript context pointer.
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Double word FP register.
|
||||
class DoubleRegister : public RegisterBase<DoubleRegister, kDoubleAfterLast> {
|
||||
public:
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0, that does not fit in the immediate field of vmov instructions.
|
||||
// d14: 0.0
|
||||
// d15: scratch register.
|
||||
static constexpr int kSizeInBytes = 8;
|
||||
inline static int NumRegisters();
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr DoubleRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(DoubleRegister);
|
||||
static_assert(sizeof(DoubleRegister) == sizeof(int),
|
||||
"DoubleRegister can efficiently be passed by value");
|
||||
|
||||
typedef DoubleRegister FloatRegister;
|
||||
|
||||
// TODO(ppc) Define SIMD registers.
|
||||
typedef DoubleRegister Simd128Register;
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
constexpr DoubleRegister kFirstCalleeSavedDoubleReg = d14;
|
||||
constexpr DoubleRegister kLastCalleeSavedDoubleReg = d31;
|
||||
constexpr DoubleRegister kDoubleRegZero = d14;
|
||||
constexpr DoubleRegister kScratchDoubleReg = d13;
|
||||
|
||||
Register ToRegister(int num);
|
||||
|
||||
enum CRegisterCode {
|
||||
#define REGISTER_CODE(R) kCCode_##R,
|
||||
C_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kCAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register
|
||||
class CRegister : public RegisterBase<CRegister, kCAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr CRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
constexpr CRegister no_creg = CRegister::no_reg();
|
||||
#define DECLARE_C_REGISTER(R) \
|
||||
constexpr CRegister R = CRegister::from_code<kCCode_##R>();
|
||||
C_REGISTERS(DECLARE_C_REGISTER)
|
||||
#undef DECLARE_C_REGISTER
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Machine instruction Operands
|
||||
|
||||
@ -1638,11 +1334,6 @@ class PatchingAssembler : public Assembler {
|
||||
~PatchingAssembler();
|
||||
};
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(DoubleRegister, DOUBLE_REGISTERS);
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -20,6 +20,36 @@
|
||||
#define UNIMPLEMENTED_PPC()
|
||||
#endif
|
||||
|
||||
#if V8_HOST_ARCH_PPC && \
|
||||
(V8_OS_AIX || (V8_TARGET_ARCH_PPC64 && V8_TARGET_BIG_ENDIAN))
|
||||
#define ABI_USES_FUNCTION_DESCRIPTORS 1
|
||||
#else
|
||||
#define ABI_USES_FUNCTION_DESCRIPTORS 0
|
||||
#endif
|
||||
|
||||
#if !V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64
|
||||
#define ABI_PASSES_HANDLES_IN_REGS 1
|
||||
#else
|
||||
#define ABI_PASSES_HANDLES_IN_REGS 0
|
||||
#endif
|
||||
|
||||
#if !V8_HOST_ARCH_PPC || !V8_TARGET_ARCH_PPC64 || V8_TARGET_LITTLE_ENDIAN
|
||||
#define ABI_RETURNS_OBJECT_PAIRS_IN_REGS 1
|
||||
#else
|
||||
#define ABI_RETURNS_OBJECT_PAIRS_IN_REGS 0
|
||||
#endif
|
||||
|
||||
#if !V8_HOST_ARCH_PPC || (V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN)
|
||||
#define ABI_CALL_VIA_IP 1
|
||||
#else
|
||||
#define ABI_CALL_VIA_IP 0
|
||||
#endif
|
||||
|
||||
#if !V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64
|
||||
#define ABI_TOC_REGISTER 2
|
||||
#else
|
||||
#define ABI_TOC_REGISTER 13
|
||||
#endif
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
#if V8_TARGET_ARCH_PPC
|
||||
|
||||
#include "src/interface-descriptors.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
#include "src/frames.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -18,32 +18,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = r3;
|
||||
constexpr Register kReturnRegister1 = r4;
|
||||
constexpr Register kReturnRegister2 = r5;
|
||||
constexpr Register kJSFunctionRegister = r4;
|
||||
constexpr Register kContextRegister = r30;
|
||||
constexpr Register kAllocateSizeRegister = r4;
|
||||
constexpr Register kSpeculationPoisonRegister = r14;
|
||||
constexpr Register kInterpreterAccumulatorRegister = r3;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = r15;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = r16;
|
||||
constexpr Register kInterpreterDispatchTableRegister = r17;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = r3;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = r5;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = r6;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = r5;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = ip;
|
||||
constexpr Register kRuntimeCallFunctionRegister = r4;
|
||||
constexpr Register kRuntimeCallArgCountRegister = r3;
|
||||
constexpr Register kRuntimeCallArgvRegister = r5;
|
||||
constexpr Register kWasmInstanceRegister = r10;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = r15;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Static helper functions
|
||||
|
||||
|
321
src/ppc/register-ppc.h
Normal file
321
src/ppc/register-ppc.h
Normal file
@ -0,0 +1,321 @@
|
||||
// Copyright 2018 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_PPC_REGISTER_PPC_H_
|
||||
#define V8_PPC_REGISTER_PPC_H_
|
||||
|
||||
#include "src/register.h"
|
||||
#include "src/reglist.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(r0) V(sp) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(r11) V(ip) V(r13) V(r14) V(r15) \
|
||||
V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
|
||||
V(r24) V(r25) V(r26) V(r27) V(r28) V(r29) V(r30) V(fp)
|
||||
|
||||
#if V8_EMBEDDED_CONSTANT_POOL
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(r14) V(r15) \
|
||||
V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
|
||||
V(r24) V(r25) V(r26) V(r27) V(r30)
|
||||
#else
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(r14) V(r15) \
|
||||
V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
|
||||
V(r24) V(r25) V(r26) V(r27) V(r28) V(r30)
|
||||
#endif
|
||||
|
||||
#define LOW_DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15)
|
||||
|
||||
#define NON_LOW_DOUBLE_REGISTERS(V) \
|
||||
V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
LOW_DOUBLE_REGISTERS(V) NON_LOW_DOUBLE_REGISTERS(V)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS DOUBLE_REGISTERS
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d15) \
|
||||
V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define C_REGISTERS(V) \
|
||||
V(cr0) V(cr1) V(cr2) V(cr3) V(cr4) V(cr5) V(cr6) V(cr7) \
|
||||
V(cr8) V(cr9) V(cr10) V(cr11) V(cr12) V(cr15)
|
||||
// clang-format on
|
||||
|
||||
// Register list in load/store instructions
|
||||
// Note that the bit values must match those used in actual instruction encoding
|
||||
const int kNumRegs = 32;
|
||||
|
||||
// Caller-saved/arguments registers
|
||||
const RegList kJSCallerSaved = 1 << 3 | // r3 a1
|
||||
1 << 4 | // r4 a2
|
||||
1 << 5 | // r5 a3
|
||||
1 << 6 | // r6 a4
|
||||
1 << 7 | // r7 a5
|
||||
1 << 8 | // r8 a6
|
||||
1 << 9 | // r9 a7
|
||||
1 << 10 | // r10 a8
|
||||
1 << 11;
|
||||
|
||||
const int kNumJSCallerSaved = 9;
|
||||
|
||||
// Return the code of the n-th caller-saved register available to JavaScript
|
||||
// e.g. JSCallerSavedReg(0) returns r0.code() == 0
|
||||
int JSCallerSavedCode(int n);
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript
|
||||
const RegList kCalleeSaved = 1 << 14 | // r14
|
||||
1 << 15 | // r15
|
||||
1 << 16 | // r16
|
||||
1 << 17 | // r17
|
||||
1 << 18 | // r18
|
||||
1 << 19 | // r19
|
||||
1 << 20 | // r20
|
||||
1 << 21 | // r21
|
||||
1 << 22 | // r22
|
||||
1 << 23 | // r23
|
||||
1 << 24 | // r24
|
||||
1 << 25 | // r25
|
||||
1 << 26 | // r26
|
||||
1 << 27 | // r27
|
||||
1 << 28 | // r28
|
||||
1 << 29 | // r29
|
||||
1 << 30 | // r20
|
||||
1 << 31; // r31
|
||||
|
||||
const int kNumCalleeSaved = 18;
|
||||
|
||||
const RegList kCallerSavedDoubles = 1 << 0 | // d0
|
||||
1 << 1 | // d1
|
||||
1 << 2 | // d2
|
||||
1 << 3 | // d3
|
||||
1 << 4 | // d4
|
||||
1 << 5 | // d5
|
||||
1 << 6 | // d6
|
||||
1 << 7 | // d7
|
||||
1 << 8 | // d8
|
||||
1 << 9 | // d9
|
||||
1 << 10 | // d10
|
||||
1 << 11 | // d11
|
||||
1 << 12 | // d12
|
||||
1 << 13; // d13
|
||||
|
||||
const int kNumCallerSavedDoubles = 14;
|
||||
|
||||
const RegList kCalleeSavedDoubles = 1 << 14 | // d14
|
||||
1 << 15 | // d15
|
||||
1 << 16 | // d16
|
||||
1 << 17 | // d17
|
||||
1 << 18 | // d18
|
||||
1 << 19 | // d19
|
||||
1 << 20 | // d20
|
||||
1 << 21 | // d21
|
||||
1 << 22 | // d22
|
||||
1 << 23 | // d23
|
||||
1 << 24 | // d24
|
||||
1 << 25 | // d25
|
||||
1 << 26 | // d26
|
||||
1 << 27 | // d27
|
||||
1 << 28 | // d28
|
||||
1 << 29 | // d29
|
||||
1 << 30 | // d30
|
||||
1 << 31; // d31
|
||||
|
||||
const int kNumCalleeSavedDoubles = 18;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
const int kNumSafepointRegisters = 32;
|
||||
|
||||
// The following constants describe the stack frame linkage area as
|
||||
// defined by the ABI. Note that kNumRequiredStackFrameSlots must
|
||||
// satisfy alignment requirements (rounding up if required).
|
||||
#if V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN // ppc64le linux
|
||||
// [0] back chain
|
||||
// [1] condition register save area
|
||||
// [2] link register save area
|
||||
// [3] TOC save area
|
||||
// [4] Parameter1 save area
|
||||
// ...
|
||||
// [11] Parameter8 save area
|
||||
// [12] Parameter9 slot (if necessary)
|
||||
// ...
|
||||
const int kNumRequiredStackFrameSlots = 12;
|
||||
const int kStackFrameLRSlot = 2;
|
||||
const int kStackFrameExtraParamSlot = 12;
|
||||
#else // AIX
|
||||
// [0] back chain
|
||||
// [1] condition register save area
|
||||
// [2] link register save area
|
||||
// [3] reserved for compiler
|
||||
// [4] reserved by binder
|
||||
// [5] TOC save area
|
||||
// [6] Parameter1 save area
|
||||
// ...
|
||||
// [13] Parameter8 save area
|
||||
// [14] Parameter9 slot (if necessary)
|
||||
// ...
|
||||
const int kNumRequiredStackFrameSlots = 14;
|
||||
const int kStackFrameLRSlot = 2;
|
||||
const int kStackFrameExtraParamSlot = 14;
|
||||
#endif
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
#if V8_TARGET_LITTLE_ENDIAN
|
||||
static constexpr int kMantissaOffset = 0;
|
||||
static constexpr int kExponentOffset = 4;
|
||||
#else
|
||||
static constexpr int kMantissaOffset = 4;
|
||||
static constexpr int kExponentOffset = 0;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
// Aliases
|
||||
constexpr Register kConstantPoolRegister = r28; // Constant pool.
|
||||
constexpr Register kRootRegister = r29; // Roots array pointer.
|
||||
constexpr Register cp = r30; // JavaScript context pointer.
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Double word FP register.
|
||||
class DoubleRegister : public RegisterBase<DoubleRegister, kDoubleAfterLast> {
|
||||
public:
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0, that does not fit in the immediate field of vmov instructions.
|
||||
// d14: 0.0
|
||||
// d15: scratch register.
|
||||
static constexpr int kSizeInBytes = 8;
|
||||
inline static int NumRegisters();
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr DoubleRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(DoubleRegister);
|
||||
static_assert(sizeof(DoubleRegister) == sizeof(int),
|
||||
"DoubleRegister can efficiently be passed by value");
|
||||
|
||||
typedef DoubleRegister FloatRegister;
|
||||
|
||||
// TODO(ppc) Define SIMD registers.
|
||||
typedef DoubleRegister Simd128Register;
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
constexpr DoubleRegister kFirstCalleeSavedDoubleReg = d14;
|
||||
constexpr DoubleRegister kLastCalleeSavedDoubleReg = d31;
|
||||
constexpr DoubleRegister kDoubleRegZero = d14;
|
||||
constexpr DoubleRegister kScratchDoubleReg = d13;
|
||||
|
||||
Register ToRegister(int num);
|
||||
|
||||
enum CRegisterCode {
|
||||
#define REGISTER_CODE(R) kCCode_##R,
|
||||
C_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kCAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register
|
||||
class CRegister : public RegisterBase<CRegister, kCAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr CRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
constexpr CRegister no_creg = CRegister::no_reg();
|
||||
#define DECLARE_C_REGISTER(R) \
|
||||
constexpr CRegister R = CRegister::from_code<kCCode_##R>();
|
||||
C_REGISTERS(DECLARE_C_REGISTER)
|
||||
#undef DECLARE_C_REGISTER
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(DoubleRegister, DOUBLE_REGISTERS);
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = r3;
|
||||
constexpr Register kReturnRegister1 = r4;
|
||||
constexpr Register kReturnRegister2 = r5;
|
||||
constexpr Register kJSFunctionRegister = r4;
|
||||
constexpr Register kContextRegister = r30;
|
||||
constexpr Register kAllocateSizeRegister = r4;
|
||||
constexpr Register kSpeculationPoisonRegister = r14;
|
||||
constexpr Register kInterpreterAccumulatorRegister = r3;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = r15;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = r16;
|
||||
constexpr Register kInterpreterDispatchTableRegister = r17;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = r3;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = r5;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = r6;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = r5;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = ip;
|
||||
constexpr Register kRuntimeCallFunctionRegister = r4;
|
||||
constexpr Register kRuntimeCallArgCountRegister = r3;
|
||||
constexpr Register kRuntimeCallArgvRegister = r5;
|
||||
constexpr Register kWasmInstanceRegister = r10;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = r15;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_PPC_REGISTER_PPC_H_
|
31
src/register-arch.h
Normal file
31
src/register-arch.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2018 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_REGISTER_ARCH_H_
|
||||
#define V8_REGISTER_ARCH_H_
|
||||
|
||||
#include "src/register.h"
|
||||
#include "src/reglist.h"
|
||||
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
#include "src/ia32/register-ia32.h"
|
||||
#elif V8_TARGET_ARCH_X64
|
||||
#include "src/x64/register-x64.h"
|
||||
#elif V8_TARGET_ARCH_ARM64
|
||||
#include "src/arm64/register-arm64.h"
|
||||
#elif V8_TARGET_ARCH_ARM
|
||||
#include "src/arm/register-arm.h"
|
||||
#elif V8_TARGET_ARCH_PPC
|
||||
#include "src/ppc/register-ppc.h"
|
||||
#elif V8_TARGET_ARCH_MIPS
|
||||
#include "src/mips/register-mips.h"
|
||||
#elif V8_TARGET_ARCH_MIPS64
|
||||
#include "src/mips64/register-mips64.h"
|
||||
#elif V8_TARGET_ARCH_S390
|
||||
#include "src/s360/register-s360.h"
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
|
||||
#endif // V8_REGISTER_ARCH_H_
|
@ -3,8 +3,10 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/base/lazy-instance.h"
|
||||
#include "src/cpu-features.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/register-arch.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
126
src/register.h
Normal file
126
src/register.h
Normal file
@ -0,0 +1,126 @@
|
||||
// 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_REGISTER_H_
|
||||
#define V8_REGISTER_H_
|
||||
|
||||
#include "src/reglist.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Base type for CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum for registers, but enum values are
|
||||
// assignment-compatible with int, which has caused code-generation bugs.
|
||||
//
|
||||
// 2) By not using an enum, we are possibly preventing the compiler from
|
||||
// doing certain constant folds, which may significantly reduce the
|
||||
// code generated for some assembly instructions (because they boil down
|
||||
// to a few constants). If this is a problem, we could change the code
|
||||
// such that we use an enum in optimized mode, and the class in debug
|
||||
// mode. This way we get the compile-time error checking in debug mode
|
||||
// and best performance in optimized code.
|
||||
template <typename SubType, int kAfterLastRegister>
|
||||
class RegisterBase {
|
||||
// Internal enum class; used for calling constexpr methods, where we need to
|
||||
// pass an integral type as template parameter.
|
||||
enum class RegisterCode : int { kFirst = 0, kAfterLast = kAfterLastRegister };
|
||||
|
||||
public:
|
||||
static constexpr int kCode_no_reg = -1;
|
||||
static constexpr int kNumRegisters = kAfterLastRegister;
|
||||
|
||||
static constexpr SubType no_reg() { return SubType{kCode_no_reg}; }
|
||||
|
||||
template <int code>
|
||||
static constexpr SubType from_code() {
|
||||
static_assert(code >= 0 && code < kNumRegisters, "must be valid reg code");
|
||||
return SubType{code};
|
||||
}
|
||||
|
||||
constexpr operator RegisterCode() const {
|
||||
return static_cast<RegisterCode>(reg_code_);
|
||||
}
|
||||
|
||||
template <RegisterCode reg_code>
|
||||
static constexpr int code() {
|
||||
static_assert(
|
||||
reg_code >= RegisterCode::kFirst && reg_code < RegisterCode::kAfterLast,
|
||||
"must be valid reg");
|
||||
return static_cast<int>(reg_code);
|
||||
}
|
||||
|
||||
template <RegisterCode reg_code>
|
||||
static constexpr int is_valid() {
|
||||
return static_cast<int>(reg_code) != kCode_no_reg;
|
||||
}
|
||||
|
||||
template <RegisterCode reg_code>
|
||||
static constexpr RegList bit() {
|
||||
return is_valid<reg_code>() ? RegList{1} << code<reg_code>() : RegList{};
|
||||
}
|
||||
|
||||
static SubType from_code(int code) {
|
||||
DCHECK_LE(0, code);
|
||||
DCHECK_GT(kNumRegisters, code);
|
||||
return SubType{code};
|
||||
}
|
||||
|
||||
// Constexpr version (pass registers as template parameters).
|
||||
template <RegisterCode... reg_codes>
|
||||
static constexpr RegList ListOf() {
|
||||
return CombineRegLists(RegisterBase::bit<reg_codes>()...);
|
||||
}
|
||||
|
||||
// Non-constexpr version (pass registers as method parameters).
|
||||
template <typename... Register>
|
||||
static RegList ListOf(Register... regs) {
|
||||
return CombineRegLists(regs.bit()...);
|
||||
}
|
||||
|
||||
constexpr bool is_valid() const { return reg_code_ != kCode_no_reg; }
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code_;
|
||||
}
|
||||
|
||||
RegList bit() const { return is_valid() ? RegList{1} << code() : RegList{}; }
|
||||
|
||||
inline constexpr bool operator==(SubType other) const {
|
||||
return reg_code_ == other.reg_code_;
|
||||
}
|
||||
inline constexpr bool operator!=(SubType other) const {
|
||||
return reg_code_ != other.reg_code_;
|
||||
}
|
||||
|
||||
// Used to print the name of some special registers.
|
||||
static const char* GetSpecialRegisterName(int code) { return "UNKNOWN"; }
|
||||
|
||||
protected:
|
||||
explicit constexpr RegisterBase(int code) : reg_code_(code) {}
|
||||
int reg_code_;
|
||||
};
|
||||
|
||||
template <typename RegType,
|
||||
typename = decltype(RegisterName(std::declval<RegType>()))>
|
||||
inline std::ostream& operator<<(std::ostream& os, RegType reg) {
|
||||
return os << RegisterName(reg);
|
||||
}
|
||||
|
||||
// Helper macros to define a {RegisterName} method based on a macro list
|
||||
// containing all names.
|
||||
#define DEFINE_REGISTER_NAMES_NAME(name) #name,
|
||||
#define DEFINE_REGISTER_NAMES(RegType, LIST) \
|
||||
inline const char* RegisterName(RegType reg) { \
|
||||
static constexpr const char* Names[] = {LIST(DEFINE_REGISTER_NAMES_NAME)}; \
|
||||
STATIC_ASSERT(arraysize(Names) == RegType::kNumRegisters); \
|
||||
return reg.is_valid() ? Names[reg.code()] : "invalid"; \
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
#endif // V8_REGISTER_H_
|
@ -82,268 +82,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(fp) V(ip) V(r13) V(r14) V(sp)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r13)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS DOUBLE_REGISTERS
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d15) V(d0)
|
||||
|
||||
#define C_REGISTERS(V) \
|
||||
V(cr0) V(cr1) V(cr2) V(cr3) V(cr4) V(cr5) V(cr6) V(cr7) \
|
||||
V(cr8) V(cr9) V(cr10) V(cr11) V(cr12) V(cr15)
|
||||
// clang-format on
|
||||
|
||||
// Register list in load/store instructions
|
||||
// Note that the bit values must match those used in actual instruction encoding
|
||||
const int kNumRegs = 16;
|
||||
|
||||
// Caller-saved/arguments registers
|
||||
const RegList kJSCallerSaved = 1 << 1 | 1 << 2 | // r2 a1
|
||||
1 << 3 | // r3 a2
|
||||
1 << 4 | // r4 a3
|
||||
1 << 5; // r5 a4
|
||||
|
||||
const int kNumJSCallerSaved = 5;
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript
|
||||
const RegList kCalleeSaved =
|
||||
1 << 6 | // r6 (argument passing in CEntryStub)
|
||||
// (HandleScope logic in MacroAssembler)
|
||||
1 << 7 | // r7 (argument passing in CEntryStub)
|
||||
// (HandleScope logic in MacroAssembler)
|
||||
1 << 8 | // r8 (argument passing in CEntryStub)
|
||||
// (HandleScope logic in MacroAssembler)
|
||||
1 << 9 | // r9 (HandleScope logic in MacroAssembler)
|
||||
1 << 10 | // r10 (Roots register in Javascript)
|
||||
1 << 11 | // r11 (fp in Javascript)
|
||||
1 << 12 | // r12 (ip in Javascript)
|
||||
1 << 13; // r13 (cp in Javascript)
|
||||
// 1 << 15; // r15 (sp in Javascript)
|
||||
|
||||
const int kNumCalleeSaved = 8;
|
||||
|
||||
#ifdef V8_TARGET_ARCH_S390X
|
||||
|
||||
const RegList kCallerSavedDoubles = 1 << 0 | // d0
|
||||
1 << 1 | // d1
|
||||
1 << 2 | // d2
|
||||
1 << 3 | // d3
|
||||
1 << 4 | // d4
|
||||
1 << 5 | // d5
|
||||
1 << 6 | // d6
|
||||
1 << 7; // d7
|
||||
|
||||
const int kNumCallerSavedDoubles = 8;
|
||||
|
||||
const RegList kCalleeSavedDoubles = 1 << 8 | // d8
|
||||
1 << 9 | // d9
|
||||
1 << 10 | // d10
|
||||
1 << 11 | // d11
|
||||
1 << 12 | // d12
|
||||
1 << 13 | // d12
|
||||
1 << 14 | // d12
|
||||
1 << 15; // d13
|
||||
|
||||
const int kNumCalleeSavedDoubles = 8;
|
||||
|
||||
#else
|
||||
|
||||
const RegList kCallerSavedDoubles = 1 << 14 | // d14
|
||||
1 << 15 | // d15
|
||||
1 << 0 | // d0
|
||||
1 << 1 | // d1
|
||||
1 << 2 | // d2
|
||||
1 << 3 | // d3
|
||||
1 << 5 | // d5
|
||||
1 << 7 | // d7
|
||||
1 << 8 | // d8
|
||||
1 << 9 | // d9
|
||||
1 << 10 | // d10
|
||||
1 << 11 | // d10
|
||||
1 << 12 | // d10
|
||||
1 << 13; // d11
|
||||
|
||||
const int kNumCallerSavedDoubles = 14;
|
||||
|
||||
const RegList kCalleeSavedDoubles = 1 << 4 | // d4
|
||||
1 << 6; // d6
|
||||
|
||||
const int kNumCalleeSavedDoubles = 2;
|
||||
|
||||
#endif
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
// TODO(regis): Only 8 registers may actually be sufficient. Revisit.
|
||||
const int kNumSafepointRegisters = 16;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
// The following constants describe the stack frame linkage area as
|
||||
// defined by the ABI.
|
||||
|
||||
#if V8_TARGET_ARCH_S390X
|
||||
// [0] Back Chain
|
||||
// [1] Reserved for compiler use
|
||||
// [2] GPR 2
|
||||
// [3] GPR 3
|
||||
// ...
|
||||
// [15] GPR 15
|
||||
// [16] FPR 0
|
||||
// [17] FPR 2
|
||||
// [18] FPR 4
|
||||
// [19] FPR 6
|
||||
const int kNumRequiredStackFrameSlots = 20;
|
||||
const int kStackFrameRASlot = 14;
|
||||
const int kStackFrameSPSlot = 15;
|
||||
const int kStackFrameExtraParamSlot = 20;
|
||||
#else
|
||||
// [0] Back Chain
|
||||
// [1] Reserved for compiler use
|
||||
// [2] GPR 2
|
||||
// [3] GPR 3
|
||||
// ...
|
||||
// [15] GPR 15
|
||||
// [16..17] FPR 0
|
||||
// [18..19] FPR 2
|
||||
// [20..21] FPR 4
|
||||
// [22..23] FPR 6
|
||||
const int kNumRequiredStackFrameSlots = 24;
|
||||
const int kStackFrameRASlot = 14;
|
||||
const int kStackFrameSPSlot = 15;
|
||||
const int kStackFrameExtraParamSlot = 24;
|
||||
#endif
|
||||
|
||||
// zLinux ABI requires caller frames to include sufficient space for
|
||||
// callee preserved register save area.
|
||||
#if V8_TARGET_ARCH_S390X
|
||||
const int kCalleeRegisterSaveAreaSize = 160;
|
||||
#elif V8_TARGET_ARCH_S390
|
||||
const int kCalleeRegisterSaveAreaSize = 96;
|
||||
#else
|
||||
const int kCalleeRegisterSaveAreaSize = 0;
|
||||
#endif
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
#if V8_TARGET_LITTLE_ENDIAN
|
||||
static constexpr int kMantissaOffset = 0;
|
||||
static constexpr int kExponentOffset = 4;
|
||||
#else
|
||||
static constexpr int kMantissaOffset = 4;
|
||||
static constexpr int kExponentOffset = 0;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
// Register aliases
|
||||
constexpr Register kRootRegister = r10; // Roots array pointer.
|
||||
constexpr Register cp = r13; // JavaScript context pointer.
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Double word VFP register.
|
||||
class DoubleRegister : public RegisterBase<DoubleRegister, kDoubleAfterLast> {
|
||||
public:
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0, that does not fit in the immediate field of vmov instructions.
|
||||
// d14: 0.0
|
||||
// d15: scratch register.
|
||||
static constexpr int kSizeInBytes = 8;
|
||||
inline static int NumRegisters();
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
|
||||
explicit constexpr DoubleRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(DoubleRegister);
|
||||
static_assert(sizeof(DoubleRegister) == sizeof(int),
|
||||
"DoubleRegister can efficiently be passed by value");
|
||||
|
||||
typedef DoubleRegister FloatRegister;
|
||||
|
||||
// TODO(john.yan) Define SIMD registers.
|
||||
typedef DoubleRegister Simd128Register;
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
constexpr DoubleRegister kDoubleRegZero = d14;
|
||||
constexpr DoubleRegister kScratchDoubleReg = d13;
|
||||
|
||||
Register ToRegister(int num);
|
||||
|
||||
enum CRegisterCode {
|
||||
#define REGISTER_CODE(R) kCCode_##R,
|
||||
C_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kCAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register
|
||||
class CRegister : public RegisterBase<CRegister, kCAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr CRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
constexpr CRegister no_creg = CRegister::no_reg();
|
||||
#define DECLARE_C_REGISTER(R) \
|
||||
constexpr CRegister R = CRegister::from_code<kCCode_##R>();
|
||||
C_REGISTERS(DECLARE_C_REGISTER)
|
||||
#undef DECLARE_C_REGISTER
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Machine instruction Operands
|
||||
|
||||
@ -1663,11 +1401,6 @@ class EnsureSpace {
|
||||
explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
|
||||
};
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(DoubleRegister, DOUBLE_REGISTERS);
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
#if V8_TARGET_ARCH_S390
|
||||
|
||||
#include "src/interface-descriptors.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
#include "src/frames.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -17,32 +17,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = r2;
|
||||
constexpr Register kReturnRegister1 = r3;
|
||||
constexpr Register kReturnRegister2 = r4;
|
||||
constexpr Register kJSFunctionRegister = r3;
|
||||
constexpr Register kContextRegister = r13;
|
||||
constexpr Register kAllocateSizeRegister = r3;
|
||||
constexpr Register kSpeculationPoisonRegister = r9;
|
||||
constexpr Register kInterpreterAccumulatorRegister = r2;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = r6;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = r7;
|
||||
constexpr Register kInterpreterDispatchTableRegister = r8;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = r2;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = r4;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = r5;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = r4;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = ip;
|
||||
constexpr Register kRuntimeCallFunctionRegister = r3;
|
||||
constexpr Register kRuntimeCallArgCountRegister = r2;
|
||||
constexpr Register kRuntimeCallArgvRegister = r4;
|
||||
constexpr Register kWasmInstanceRegister = r6;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = r7;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Static helper functions
|
||||
|
||||
|
309
src/s390/register-s390.h
Normal file
309
src/s390/register-s390.h
Normal file
@ -0,0 +1,309 @@
|
||||
// Copyright 2018 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_S390_REGISTER_S390_H_
|
||||
#define V8_S390_REGISTER_S390_H_
|
||||
|
||||
#include "src/register.h"
|
||||
#include "src/reglist.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(fp) V(ip) V(r13) V(r14) V(sp)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r13)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS DOUBLE_REGISTERS
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d15) V(d0)
|
||||
|
||||
#define C_REGISTERS(V) \
|
||||
V(cr0) V(cr1) V(cr2) V(cr3) V(cr4) V(cr5) V(cr6) V(cr7) \
|
||||
V(cr8) V(cr9) V(cr10) V(cr11) V(cr12) V(cr15)
|
||||
// clang-format on
|
||||
|
||||
// Register list in load/store instructions
|
||||
// Note that the bit values must match those used in actual instruction encoding
|
||||
const int kNumRegs = 16;
|
||||
|
||||
// Caller-saved/arguments registers
|
||||
const RegList kJSCallerSaved = 1 << 1 | 1 << 2 | // r2 a1
|
||||
1 << 3 | // r3 a2
|
||||
1 << 4 | // r4 a3
|
||||
1 << 5; // r5 a4
|
||||
|
||||
const int kNumJSCallerSaved = 5;
|
||||
|
||||
// Callee-saved registers preserved when switching from C to JavaScript
|
||||
const RegList kCalleeSaved =
|
||||
1 << 6 | // r6 (argument passing in CEntryStub)
|
||||
// (HandleScope logic in MacroAssembler)
|
||||
1 << 7 | // r7 (argument passing in CEntryStub)
|
||||
// (HandleScope logic in MacroAssembler)
|
||||
1 << 8 | // r8 (argument passing in CEntryStub)
|
||||
// (HandleScope logic in MacroAssembler)
|
||||
1 << 9 | // r9 (HandleScope logic in MacroAssembler)
|
||||
1 << 10 | // r10 (Roots register in Javascript)
|
||||
1 << 11 | // r11 (fp in Javascript)
|
||||
1 << 12 | // r12 (ip in Javascript)
|
||||
1 << 13; // r13 (cp in Javascript)
|
||||
// 1 << 15; // r15 (sp in Javascript)
|
||||
|
||||
const int kNumCalleeSaved = 8;
|
||||
|
||||
#ifdef V8_TARGET_ARCH_S390X
|
||||
|
||||
const RegList kCallerSavedDoubles = 1 << 0 | // d0
|
||||
1 << 1 | // d1
|
||||
1 << 2 | // d2
|
||||
1 << 3 | // d3
|
||||
1 << 4 | // d4
|
||||
1 << 5 | // d5
|
||||
1 << 6 | // d6
|
||||
1 << 7; // d7
|
||||
|
||||
const int kNumCallerSavedDoubles = 8;
|
||||
|
||||
const RegList kCalleeSavedDoubles = 1 << 8 | // d8
|
||||
1 << 9 | // d9
|
||||
1 << 10 | // d10
|
||||
1 << 11 | // d11
|
||||
1 << 12 | // d12
|
||||
1 << 13 | // d12
|
||||
1 << 14 | // d12
|
||||
1 << 15; // d13
|
||||
|
||||
const int kNumCalleeSavedDoubles = 8;
|
||||
|
||||
#else
|
||||
|
||||
const RegList kCallerSavedDoubles = 1 << 14 | // d14
|
||||
1 << 15 | // d15
|
||||
1 << 0 | // d0
|
||||
1 << 1 | // d1
|
||||
1 << 2 | // d2
|
||||
1 << 3 | // d3
|
||||
1 << 5 | // d5
|
||||
1 << 7 | // d7
|
||||
1 << 8 | // d8
|
||||
1 << 9 | // d9
|
||||
1 << 10 | // d10
|
||||
1 << 11 | // d10
|
||||
1 << 12 | // d10
|
||||
1 << 13; // d11
|
||||
|
||||
const int kNumCallerSavedDoubles = 14;
|
||||
|
||||
const RegList kCalleeSavedDoubles = 1 << 4 | // d4
|
||||
1 << 6; // d6
|
||||
|
||||
const int kNumCalleeSavedDoubles = 2;
|
||||
|
||||
#endif
|
||||
|
||||
// Number of registers for which space is reserved in safepoints. Must be a
|
||||
// multiple of 8.
|
||||
// TODO(regis): Only 8 registers may actually be sufficient. Revisit.
|
||||
const int kNumSafepointRegisters = 16;
|
||||
|
||||
// Define the list of registers actually saved at safepoints.
|
||||
// Note that the number of saved registers may be smaller than the reserved
|
||||
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
// The following constants describe the stack frame linkage area as
|
||||
// defined by the ABI.
|
||||
|
||||
#if V8_TARGET_ARCH_S390X
|
||||
// [0] Back Chain
|
||||
// [1] Reserved for compiler use
|
||||
// [2] GPR 2
|
||||
// [3] GPR 3
|
||||
// ...
|
||||
// [15] GPR 15
|
||||
// [16] FPR 0
|
||||
// [17] FPR 2
|
||||
// [18] FPR 4
|
||||
// [19] FPR 6
|
||||
const int kNumRequiredStackFrameSlots = 20;
|
||||
const int kStackFrameRASlot = 14;
|
||||
const int kStackFrameSPSlot = 15;
|
||||
const int kStackFrameExtraParamSlot = 20;
|
||||
#else
|
||||
// [0] Back Chain
|
||||
// [1] Reserved for compiler use
|
||||
// [2] GPR 2
|
||||
// [3] GPR 3
|
||||
// ...
|
||||
// [15] GPR 15
|
||||
// [16..17] FPR 0
|
||||
// [18..19] FPR 2
|
||||
// [20..21] FPR 4
|
||||
// [22..23] FPR 6
|
||||
const int kNumRequiredStackFrameSlots = 24;
|
||||
const int kStackFrameRASlot = 14;
|
||||
const int kStackFrameSPSlot = 15;
|
||||
const int kStackFrameExtraParamSlot = 24;
|
||||
#endif
|
||||
|
||||
// zLinux ABI requires caller frames to include sufficient space for
|
||||
// callee preserved register save area.
|
||||
#if V8_TARGET_ARCH_S390X
|
||||
const int kCalleeRegisterSaveAreaSize = 160;
|
||||
#elif V8_TARGET_ARCH_S390
|
||||
const int kCalleeRegisterSaveAreaSize = 96;
|
||||
#else
|
||||
const int kCalleeRegisterSaveAreaSize = 0;
|
||||
#endif
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
#if V8_TARGET_LITTLE_ENDIAN
|
||||
static constexpr int kMantissaOffset = 0;
|
||||
static constexpr int kExponentOffset = 4;
|
||||
#else
|
||||
static constexpr int kMantissaOffset = 4;
|
||||
static constexpr int kExponentOffset = 0;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
// Register aliases
|
||||
constexpr Register kRootRegister = r10; // Roots array pointer.
|
||||
constexpr Register cp = r13; // JavaScript context pointer.
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Double word VFP register.
|
||||
class DoubleRegister : public RegisterBase<DoubleRegister, kDoubleAfterLast> {
|
||||
public:
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0, that does not fit in the immediate field of vmov instructions.
|
||||
// d14: 0.0
|
||||
// d15: scratch register.
|
||||
static constexpr int kSizeInBytes = 8;
|
||||
inline static int NumRegisters();
|
||||
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
|
||||
explicit constexpr DoubleRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(DoubleRegister);
|
||||
static_assert(sizeof(DoubleRegister) == sizeof(int),
|
||||
"DoubleRegister can efficiently be passed by value");
|
||||
|
||||
typedef DoubleRegister FloatRegister;
|
||||
|
||||
// TODO(john.yan) Define SIMD registers.
|
||||
typedef DoubleRegister Simd128Register;
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
constexpr DoubleRegister kDoubleRegZero = d14;
|
||||
constexpr DoubleRegister kScratchDoubleReg = d13;
|
||||
|
||||
Register ToRegister(int num);
|
||||
|
||||
enum CRegisterCode {
|
||||
#define REGISTER_CODE(R) kCCode_##R,
|
||||
C_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kCAfterLast
|
||||
};
|
||||
|
||||
// Coprocessor register
|
||||
class CRegister : public RegisterBase<CRegister, kCAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr CRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
constexpr CRegister no_creg = CRegister::no_reg();
|
||||
#define DECLARE_C_REGISTER(R) \
|
||||
constexpr CRegister R = CRegister::from_code<kCCode_##R>();
|
||||
C_REGISTERS(DECLARE_C_REGISTER)
|
||||
#undef DECLARE_C_REGISTER
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS);
|
||||
DEFINE_REGISTER_NAMES(DoubleRegister, DOUBLE_REGISTERS);
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = r2;
|
||||
constexpr Register kReturnRegister1 = r3;
|
||||
constexpr Register kReturnRegister2 = r4;
|
||||
constexpr Register kJSFunctionRegister = r3;
|
||||
constexpr Register kContextRegister = r13;
|
||||
constexpr Register kAllocateSizeRegister = r3;
|
||||
constexpr Register kSpeculationPoisonRegister = r9;
|
||||
constexpr Register kInterpreterAccumulatorRegister = r2;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = r6;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = r7;
|
||||
constexpr Register kInterpreterDispatchTableRegister = r8;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = r2;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = r4;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = r5;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = r4;
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = ip;
|
||||
constexpr Register kRuntimeCallFunctionRegister = r3;
|
||||
constexpr Register kRuntimeCallArgCountRegister = r2;
|
||||
constexpr Register kRuntimeCallArgvRegister = r4;
|
||||
constexpr Register kWasmInstanceRegister = r6;
|
||||
constexpr Register kWasmCompileLazyFuncIndexRegister = r7;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_S390_REGISTER_S390_H_
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include "src/assembler-inl.h"
|
||||
#include "src/callable.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "src/base/template-utils.h"
|
||||
#include "src/counters.h"
|
||||
#include "src/flags.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/ostreams.h"
|
||||
#include "src/v8.h"
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "src/label.h"
|
||||
#include "src/objects/smi.h"
|
||||
#include "src/x64/constants-x64.h"
|
||||
#include "src/x64/register-x64.h"
|
||||
#include "src/x64/sse-instr.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -52,177 +53,6 @@ namespace internal {
|
||||
|
||||
// Utility functions
|
||||
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(rax) \
|
||||
V(rcx) \
|
||||
V(rdx) \
|
||||
V(rbx) \
|
||||
V(rsp) \
|
||||
V(rbp) \
|
||||
V(rsi) \
|
||||
V(rdi) \
|
||||
V(r8) \
|
||||
V(r9) \
|
||||
V(r10) \
|
||||
V(r11) \
|
||||
V(r12) \
|
||||
V(r13) \
|
||||
V(r14) \
|
||||
V(r15)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(rax) \
|
||||
V(rbx) \
|
||||
V(rdx) \
|
||||
V(rcx) \
|
||||
V(rsi) \
|
||||
V(rdi) \
|
||||
V(r8) \
|
||||
V(r9) \
|
||||
V(r11) \
|
||||
V(r12) \
|
||||
V(r14) \
|
||||
V(r15)
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
bool is_byte_register() const { return reg_code_ <= 3; }
|
||||
// Return the high bit of the register code as a 0 or 1. Used often
|
||||
// when constructing the REX prefix byte.
|
||||
int high_bit() const { return reg_code_ >> 3; }
|
||||
// Return the 3 low bits of the register code. Used when encoding registers
|
||||
// in modR/M, SIB, and opcode bytes.
|
||||
int low_bits() const { return reg_code_ & 0x7; }
|
||||
|
||||
private:
|
||||
friend class RegisterBase<Register, kRegAfterLast>;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
constexpr int kNumRegs = 16;
|
||||
|
||||
constexpr RegList kJSCallerSaved =
|
||||
Register::ListOf<rax, rcx, rdx,
|
||||
rbx, // used as a caller-saved register in JavaScript code
|
||||
rdi // callee function
|
||||
>();
|
||||
|
||||
constexpr int kNumJSCallerSaved = 5;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints.
|
||||
constexpr int kNumSafepointRegisters = 16;
|
||||
|
||||
#ifdef _WIN64
|
||||
// Windows calling convention
|
||||
constexpr Register arg_reg_1 = rcx;
|
||||
constexpr Register arg_reg_2 = rdx;
|
||||
constexpr Register arg_reg_3 = r8;
|
||||
constexpr Register arg_reg_4 = r9;
|
||||
#else
|
||||
// AMD64 calling convention
|
||||
constexpr Register arg_reg_1 = rdi;
|
||||
constexpr Register arg_reg_2 = rsi;
|
||||
constexpr Register arg_reg_3 = rdx;
|
||||
constexpr Register arg_reg_4 = rcx;
|
||||
#endif // _WIN64
|
||||
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(xmm0) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7) \
|
||||
V(xmm8) \
|
||||
V(xmm9) \
|
||||
V(xmm10) \
|
||||
V(xmm11) \
|
||||
V(xmm12) \
|
||||
V(xmm13) \
|
||||
V(xmm14) \
|
||||
V(xmm15)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS DOUBLE_REGISTERS
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(xmm0) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7) \
|
||||
V(xmm8) \
|
||||
V(xmm9) \
|
||||
V(xmm10) \
|
||||
V(xmm11) \
|
||||
V(xmm12) \
|
||||
V(xmm13) \
|
||||
V(xmm14)
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
class XMMRegister : public RegisterBase<XMMRegister, kDoubleAfterLast> {
|
||||
public:
|
||||
// Return the high bit of the register code as a 0 or 1. Used often
|
||||
// when constructing the REX prefix byte.
|
||||
int high_bit() const { return reg_code_ >> 3; }
|
||||
// Return the 3 low bits of the register code. Used when encoding registers
|
||||
// in modR/M, SIB, and opcode bytes.
|
||||
int low_bits() const { return reg_code_ & 0x7; }
|
||||
|
||||
private:
|
||||
friend class RegisterBase<XMMRegister, kDoubleAfterLast>;
|
||||
explicit constexpr XMMRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(XMMRegister);
|
||||
static_assert(sizeof(XMMRegister) == sizeof(int),
|
||||
"XMMRegister can efficiently be passed by value");
|
||||
|
||||
typedef XMMRegister FloatRegister;
|
||||
|
||||
typedef XMMRegister DoubleRegister;
|
||||
|
||||
typedef XMMRegister Simd128Register;
|
||||
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
enum Condition {
|
||||
// any value < 0 is considered no_condition
|
||||
no_condition = -1,
|
||||
@ -2450,10 +2280,6 @@ class EnsureSpace {
|
||||
#endif
|
||||
};
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(XMMRegister, DOUBLE_REGISTERS)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "src/base/lazy-instance.h"
|
||||
#include "src/base/v8-fallthrough.h"
|
||||
#include "src/disasm.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/x64/register-x64.h"
|
||||
#include "src/x64/sse-instr.h"
|
||||
|
||||
namespace disasm {
|
||||
|
@ -5,7 +5,8 @@
|
||||
#if V8_TARGET_ARCH_X64
|
||||
|
||||
#include "src/interface-descriptors.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
#include "src/frames.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -18,39 +18,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = rax;
|
||||
constexpr Register kReturnRegister1 = rdx;
|
||||
constexpr Register kReturnRegister2 = r8;
|
||||
constexpr Register kJSFunctionRegister = rdi;
|
||||
constexpr Register kContextRegister = rsi;
|
||||
constexpr Register kAllocateSizeRegister = rdx;
|
||||
constexpr Register kSpeculationPoisonRegister = r12;
|
||||
constexpr Register kInterpreterAccumulatorRegister = rax;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = r9;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = r14;
|
||||
constexpr Register kInterpreterDispatchTableRegister = r15;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = rax;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = rcx;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = rdx;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = rbx;
|
||||
|
||||
constexpr Register kRuntimeCallFunctionRegister = rbx;
|
||||
constexpr Register kRuntimeCallArgCountRegister = rax;
|
||||
constexpr Register kRuntimeCallArgvRegister = r15;
|
||||
constexpr Register kWasmInstanceRegister = rsi;
|
||||
|
||||
// Default scratch register used by MacroAssembler (and other code that needs
|
||||
// a spare register). The register isn't callee save, and not used by the
|
||||
// function calling convention.
|
||||
constexpr Register kScratchRegister = r10;
|
||||
constexpr XMMRegister kScratchDoubleReg = xmm15;
|
||||
constexpr Register kRootRegister = r13; // callee save
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = kScratchRegister;
|
||||
|
||||
// Convenience for platform-independent signatures.
|
||||
typedef Operand MemOperand;
|
||||
|
||||
|
224
src/x64/register-x64.h
Normal file
224
src/x64/register-x64.h
Normal file
@ -0,0 +1,224 @@
|
||||
// Copyright 2018 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_X64_REGISTER_X64_H_
|
||||
#define V8_X64_REGISTER_X64_H_
|
||||
|
||||
#include "src/register.h"
|
||||
#include "src/reglist.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(rax) \
|
||||
V(rcx) \
|
||||
V(rdx) \
|
||||
V(rbx) \
|
||||
V(rsp) \
|
||||
V(rbp) \
|
||||
V(rsi) \
|
||||
V(rdi) \
|
||||
V(r8) \
|
||||
V(r9) \
|
||||
V(r10) \
|
||||
V(r11) \
|
||||
V(r12) \
|
||||
V(r13) \
|
||||
V(r14) \
|
||||
V(r15)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(rax) \
|
||||
V(rbx) \
|
||||
V(rdx) \
|
||||
V(rcx) \
|
||||
V(rsi) \
|
||||
V(rdi) \
|
||||
V(r8) \
|
||||
V(r9) \
|
||||
V(r11) \
|
||||
V(r12) \
|
||||
V(r14) \
|
||||
V(r15)
|
||||
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
bool is_byte_register() const { return reg_code_ <= 3; }
|
||||
// Return the high bit of the register code as a 0 or 1. Used often
|
||||
// when constructing the REX prefix byte.
|
||||
int high_bit() const { return reg_code_ >> 3; }
|
||||
// Return the 3 low bits of the register code. Used when encoding registers
|
||||
// in modR/M, SIB, and opcode bytes.
|
||||
int low_bits() const { return reg_code_ & 0x7; }
|
||||
|
||||
private:
|
||||
friend class RegisterBase<Register, kRegAfterLast>;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(Register);
|
||||
static_assert(sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
constexpr int kNumRegs = 16;
|
||||
|
||||
constexpr RegList kJSCallerSaved =
|
||||
Register::ListOf<rax, rcx, rdx,
|
||||
rbx, // used as a caller-saved register in JavaScript code
|
||||
rdi // callee function
|
||||
>();
|
||||
|
||||
constexpr int kNumJSCallerSaved = 5;
|
||||
|
||||
// Number of registers for which space is reserved in safepoints.
|
||||
constexpr int kNumSafepointRegisters = 16;
|
||||
|
||||
#ifdef _WIN64
|
||||
// Windows calling convention
|
||||
constexpr Register arg_reg_1 = rcx;
|
||||
constexpr Register arg_reg_2 = rdx;
|
||||
constexpr Register arg_reg_3 = r8;
|
||||
constexpr Register arg_reg_4 = r9;
|
||||
#else
|
||||
// AMD64 calling convention
|
||||
constexpr Register arg_reg_1 = rdi;
|
||||
constexpr Register arg_reg_2 = rsi;
|
||||
constexpr Register arg_reg_3 = rdx;
|
||||
constexpr Register arg_reg_4 = rcx;
|
||||
#endif // _WIN64
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(xmm0) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7) \
|
||||
V(xmm8) \
|
||||
V(xmm9) \
|
||||
V(xmm10) \
|
||||
V(xmm11) \
|
||||
V(xmm12) \
|
||||
V(xmm13) \
|
||||
V(xmm14) \
|
||||
V(xmm15)
|
||||
|
||||
#define FLOAT_REGISTERS DOUBLE_REGISTERS
|
||||
#define SIMD128_REGISTERS DOUBLE_REGISTERS
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(xmm0) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7) \
|
||||
V(xmm8) \
|
||||
V(xmm9) \
|
||||
V(xmm10) \
|
||||
V(xmm11) \
|
||||
V(xmm12) \
|
||||
V(xmm13) \
|
||||
V(xmm14)
|
||||
|
||||
constexpr bool kPadArguments = false;
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
class XMMRegister : public RegisterBase<XMMRegister, kDoubleAfterLast> {
|
||||
public:
|
||||
// Return the high bit of the register code as a 0 or 1. Used often
|
||||
// when constructing the REX prefix byte.
|
||||
int high_bit() const { return reg_code_ >> 3; }
|
||||
// Return the 3 low bits of the register code. Used when encoding registers
|
||||
// in modR/M, SIB, and opcode bytes.
|
||||
int low_bits() const { return reg_code_ & 0x7; }
|
||||
|
||||
private:
|
||||
friend class RegisterBase<XMMRegister, kDoubleAfterLast>;
|
||||
explicit constexpr XMMRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(XMMRegister);
|
||||
static_assert(sizeof(XMMRegister) == sizeof(int),
|
||||
"XMMRegister can efficiently be passed by value");
|
||||
|
||||
typedef XMMRegister FloatRegister;
|
||||
|
||||
typedef XMMRegister DoubleRegister;
|
||||
|
||||
typedef XMMRegister Simd128Register;
|
||||
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
|
||||
|
||||
// Define {RegisterName} methods for the register types.
|
||||
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
|
||||
DEFINE_REGISTER_NAMES(XMMRegister, DOUBLE_REGISTERS)
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
constexpr Register kReturnRegister0 = rax;
|
||||
constexpr Register kReturnRegister1 = rdx;
|
||||
constexpr Register kReturnRegister2 = r8;
|
||||
constexpr Register kJSFunctionRegister = rdi;
|
||||
constexpr Register kContextRegister = rsi;
|
||||
constexpr Register kAllocateSizeRegister = rdx;
|
||||
constexpr Register kSpeculationPoisonRegister = r12;
|
||||
constexpr Register kInterpreterAccumulatorRegister = rax;
|
||||
constexpr Register kInterpreterBytecodeOffsetRegister = r9;
|
||||
constexpr Register kInterpreterBytecodeArrayRegister = r14;
|
||||
constexpr Register kInterpreterDispatchTableRegister = r15;
|
||||
|
||||
constexpr Register kJavaScriptCallArgCountRegister = rax;
|
||||
constexpr Register kJavaScriptCallCodeStartRegister = rcx;
|
||||
constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
|
||||
constexpr Register kJavaScriptCallNewTargetRegister = rdx;
|
||||
constexpr Register kJavaScriptCallExtraArg1Register = rbx;
|
||||
|
||||
constexpr Register kRuntimeCallFunctionRegister = rbx;
|
||||
constexpr Register kRuntimeCallArgCountRegister = rax;
|
||||
constexpr Register kRuntimeCallArgvRegister = r15;
|
||||
constexpr Register kWasmInstanceRegister = rsi;
|
||||
|
||||
// Default scratch register used by MacroAssembler (and other code that needs
|
||||
// a spare register). The register isn't callee save, and not used by the
|
||||
// function calling convention.
|
||||
constexpr Register kScratchRegister = r10;
|
||||
constexpr XMMRegister kScratchDoubleReg = xmm15;
|
||||
constexpr Register kRootRegister = r13; // callee save
|
||||
|
||||
constexpr Register kOffHeapTrampolineRegister = kScratchRegister;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_X64_REGISTER_X64_H_
|
@ -5,6 +5,7 @@
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
|
||||
#include "src/api-inl.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/compiler.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/pipeline.h"
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_
|
||||
#define V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/compiler/backend/instruction-selector.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
|
Loading…
Reference in New Issue
Block a user