[assembler] Make Register et al. real classes
Up to now, each architecture defined all Register types as structs, with lots of redundancy. An often found comment noted that they cannot be classes due to initialization order problems. As these problems are gone with C++11 constexpr constants, I now tried making Registers classes again. All register types now inherit from RegisterBase, which provides a default set of methods and named constructors (like ::from_code, code(), bit(), is_valid(), ...). This design allows to guarantee an interesting property: Each register is either valid, or it's the no_reg register. There are no other invalid registers. This is guaranteed statically by the constexpr constructor, and dynamically by ::from_code. I decided to disallow the default constructor completely, so instead of "Register reg;" you now need "Register reg = no_reg;". This makes explicit how the Register is initialized. I did this change to the x64, ia32, arm, arm64, mips and mips64 ports. Overall, code got much more compact and more safe. In theory, it should also increase performance (since the is_valid() check is simpler), but this is probably not measurable. R=mstarzinger@chromium.org Change-Id: I5ccfa4050daf4e146a557970e9d37fd3d2788d4a Reviewed-on: https://chromium-review.googlesource.com/650927 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#47847}
This commit is contained in:
parent
8f3ba46a6e
commit
9e995e12ca
@ -43,6 +43,14 @@ T* NewArray(size_t size) {
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename = typename std::enable_if<IS_TRIVIALLY_COPYABLE(T)>::type>
|
||||
T* NewArray(size_t size, T default_val) {
|
||||
T* result = reinterpret_cast<T*>(NewArray<uint8_t>(sizeof(T) * size));
|
||||
for (size_t i = 0; i < size; ++i) result[i] = default_val;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DeleteArray(T* array) {
|
||||
delete[] array;
|
||||
|
@ -179,35 +179,22 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
|
||||
}
|
||||
}
|
||||
|
||||
Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) : rmode_(rmode) {
|
||||
value_.immediate = immediate;
|
||||
rmode_ = rmode;
|
||||
}
|
||||
|
||||
Operand Operand::Zero() { return Operand(static_cast<int32_t>(0)); }
|
||||
|
||||
Operand::Operand(const ExternalReference& f) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(const ExternalReference& f)
|
||||
: rmode_(RelocInfo::EXTERNAL_REFERENCE) {
|
||||
value_.immediate = reinterpret_cast<int32_t>(f.address());
|
||||
rmode_ = RelocInfo::EXTERNAL_REFERENCE;
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(Smi* value) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(Smi* value) : rmode_(RelocInfo::NONE32) {
|
||||
value_.immediate = reinterpret_cast<intptr_t>(value);
|
||||
rmode_ = RelocInfo::NONE32;
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(Register rm) {
|
||||
rm_ = rm;
|
||||
rs_ = no_reg;
|
||||
shift_op_ = LSL;
|
||||
shift_imm_ = 0;
|
||||
}
|
||||
|
||||
Operand::Operand(Register rm) : rm_(rm), shift_op_(LSL), shift_imm_(0) {}
|
||||
|
||||
void Assembler::CheckBuffer() {
|
||||
if (buffer_space() <= kGap) {
|
||||
|
@ -413,12 +413,8 @@ Operand Operand::EmbeddedCode(CodeStub* stub) {
|
||||
return result;
|
||||
}
|
||||
|
||||
MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) {
|
||||
rn_ = rn;
|
||||
rm_ = no_reg;
|
||||
offset_ = offset;
|
||||
am_ = am;
|
||||
|
||||
MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am)
|
||||
: rn_(rn), rm_(no_reg), offset_(offset), am_(am) {
|
||||
// Accesses below the stack pointer are not safe, and are prohibited by the
|
||||
// ABI. We can check obvious violations here.
|
||||
if (rn.is(sp)) {
|
||||
@ -427,38 +423,27 @@ MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) {
|
||||
}
|
||||
}
|
||||
|
||||
MemOperand::MemOperand(Register rn, Register rm, AddrMode am)
|
||||
: rn_(rn), rm_(rm), shift_op_(LSL), shift_imm_(0), am_(am) {}
|
||||
|
||||
MemOperand::MemOperand(Register rn, Register rm, AddrMode am) {
|
||||
rn_ = rn;
|
||||
rm_ = rm;
|
||||
shift_op_ = LSL;
|
||||
shift_imm_ = 0;
|
||||
am_ = am;
|
||||
}
|
||||
|
||||
|
||||
MemOperand::MemOperand(Register rn, Register rm,
|
||||
ShiftOp shift_op, int shift_imm, AddrMode am) {
|
||||
MemOperand::MemOperand(Register rn, Register rm, ShiftOp shift_op,
|
||||
int shift_imm, AddrMode am)
|
||||
: rn_(rn),
|
||||
rm_(rm),
|
||||
shift_op_(shift_op),
|
||||
shift_imm_(shift_imm & 31),
|
||||
am_(am) {
|
||||
DCHECK(is_uint5(shift_imm));
|
||||
rn_ = rn;
|
||||
rm_ = rm;
|
||||
shift_op_ = shift_op;
|
||||
shift_imm_ = shift_imm & 31;
|
||||
am_ = am;
|
||||
}
|
||||
|
||||
|
||||
NeonMemOperand::NeonMemOperand(Register rn, AddrMode am, int align) {
|
||||
NeonMemOperand::NeonMemOperand(Register rn, AddrMode am, int align)
|
||||
: rn_(rn), rm_(am == Offset ? pc : sp) {
|
||||
DCHECK((am == Offset) || (am == PostIndex));
|
||||
rn_ = rn;
|
||||
rm_ = (am == Offset) ? pc : sp;
|
||||
SetAlignment(align);
|
||||
}
|
||||
|
||||
|
||||
NeonMemOperand::NeonMemOperand(Register rn, Register rm, int align) {
|
||||
rn_ = rn;
|
||||
rm_ = rm;
|
||||
NeonMemOperand::NeonMemOperand(Register rn, Register rm, int align)
|
||||
: rn_(rn), rm_(rm) {
|
||||
SetAlignment(align);
|
||||
}
|
||||
|
||||
@ -507,18 +492,16 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
|
||||
|
||||
// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
|
||||
// register r is not encoded.
|
||||
const Instr kPushRegPattern =
|
||||
al | B26 | 4 | NegPreIndex | Register::kCode_sp * B16;
|
||||
const Instr kPushRegPattern = al | B26 | 4 | NegPreIndex | sp.code() * B16;
|
||||
// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
|
||||
// register r is not encoded.
|
||||
const Instr kPopRegPattern =
|
||||
al | B26 | L | 4 | PostIndex | Register::kCode_sp * B16;
|
||||
const Instr kPopRegPattern = al | B26 | L | 4 | PostIndex | sp.code() * B16;
|
||||
// ldr rd, [pc, #offset]
|
||||
const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPCImmedPattern = 5 * B24 | L | Register::kCode_pc * B16;
|
||||
const Instr kLdrPCImmedPattern = 5 * B24 | L | pc.code() * B16;
|
||||
// vldr dd, [pc, #offset]
|
||||
const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
|
||||
const Instr kVldrDPCPattern = 13 * B24 | L | Register::kCode_pc * B16 | 11 * B8;
|
||||
const Instr kVldrDPCPattern = 13 * B24 | L | pc.code() * B16 | 11 * B8;
|
||||
// blxcc rm
|
||||
const Instr kBlxRegMask =
|
||||
15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
|
||||
@ -544,14 +527,11 @@ const Instr kAddSubFlip = 0x6 * B21;
|
||||
const Instr kAndBicFlip = 0xe * B21;
|
||||
|
||||
// A mask for the Rd register for push, pop, ldr, str instructions.
|
||||
const Instr kLdrRegFpOffsetPattern =
|
||||
al | B26 | L | Offset | Register::kCode_fp * B16;
|
||||
const Instr kStrRegFpOffsetPattern =
|
||||
al | B26 | Offset | Register::kCode_fp * B16;
|
||||
const Instr kLdrRegFpOffsetPattern = al | B26 | L | Offset | fp.code() * B16;
|
||||
const Instr kStrRegFpOffsetPattern = al | B26 | Offset | fp.code() * B16;
|
||||
const Instr kLdrRegFpNegOffsetPattern =
|
||||
al | B26 | L | NegOffset | Register::kCode_fp * B16;
|
||||
const Instr kStrRegFpNegOffsetPattern =
|
||||
al | B26 | NegOffset | Register::kCode_fp * B16;
|
||||
al | B26 | L | NegOffset | fp.code() * B16;
|
||||
const Instr kStrRegFpNegOffsetPattern = al | B26 | NegOffset | fp.code() * B16;
|
||||
const Instr kLdrStrInstrTypeMask = 0xffff0000;
|
||||
|
||||
Assembler::Assembler(IsolateData isolate_data, void* buffer, int buffer_size)
|
||||
@ -722,23 +702,17 @@ Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
|
||||
|
||||
|
||||
Register Assembler::GetRd(Instr instr) {
|
||||
Register reg;
|
||||
reg.reg_code = Instruction::RdValue(instr);
|
||||
return reg;
|
||||
return Register::from_code(Instruction::RdValue(instr));
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRn(Instr instr) {
|
||||
Register reg;
|
||||
reg.reg_code = Instruction::RnValue(instr);
|
||||
return reg;
|
||||
return Register::from_code(Instruction::RnValue(instr));
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRm(Instr instr) {
|
||||
Register reg;
|
||||
reg.reg_code = Instruction::RmValue(instr);
|
||||
return reg;
|
||||
return Register::from_code(Instruction::RmValue(instr));
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,12 +65,17 @@ namespace internal {
|
||||
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(V) \
|
||||
#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) \
|
||||
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)
|
||||
@ -83,7 +88,11 @@ namespace internal {
|
||||
|
||||
#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) \
|
||||
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
|
||||
@ -140,248 +149,142 @@ const int kNumSafepointRegisters = 16;
|
||||
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
|
||||
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
|
||||
|
||||
// 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.
|
||||
|
||||
struct Register {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static constexpr int kNumRegisters = Code::kAfterLast;
|
||||
|
||||
static Register from_code(int code) {
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kNumRegisters);
|
||||
Register r = {code};
|
||||
return r;
|
||||
}
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
|
||||
bool is(Register reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void set_code(int code) {
|
||||
reg_code = code;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
static_assert(IS_TRIVIALLY_COPYABLE(Register) &&
|
||||
sizeof(Register) == sizeof(int),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
// r7: context register
|
||||
// r9: lithium scratch
|
||||
#define DECLARE_REGISTER(R) constexpr Register R = {Register::kCode_##R};
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr Register no_reg = {Register::kCode_no_reg};
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
constexpr bool kSimpleFPAliasing = false;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
// Single word VFP register.
|
||||
struct SwVfpRegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
FLOAT_REGISTERS(REGISTER_CODE)
|
||||
enum SwVfpRegisterCode {
|
||||
#define REGISTER_CODE(R) kSwVfpCode_##R,
|
||||
FLOAT_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static constexpr int kMaxNumRegisters = Code::kAfterLast;
|
||||
kSwVfpAfterLast
|
||||
};
|
||||
|
||||
// Single word VFP register.
|
||||
class SwVfpRegister : public RegisterBase<SwVfpRegister, kSwVfpAfterLast> {
|
||||
public:
|
||||
static constexpr int kSizeInBytes = 4;
|
||||
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < 32; }
|
||||
bool is(SwVfpRegister reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
static SwVfpRegister from_code(int code) {
|
||||
SwVfpRegister r = {code};
|
||||
return r;
|
||||
}
|
||||
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(reg_code, vm, m);
|
||||
}
|
||||
void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
|
||||
|
||||
int reg_code;
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr SwVfpRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
static_assert(IS_TRIVIALLY_COPYABLE(SwVfpRegister) &&
|
||||
sizeof(SwVfpRegister) == sizeof(int),
|
||||
"SwVfpRegister can efficiently be passed by value");
|
||||
|
||||
typedef SwVfpRegister FloatRegister;
|
||||
|
||||
// Double word VFP register.
|
||||
struct DwVfpRegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static constexpr int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
inline static int NumRegisters();
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
// Double word VFP register.
|
||||
class DwVfpRegister : public RegisterBase<DwVfpRegister, 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;
|
||||
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(DwVfpRegister reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
inline static int NumRegisters();
|
||||
|
||||
static DwVfpRegister from_code(int code) {
|
||||
DwVfpRegister r = {code};
|
||||
return r;
|
||||
}
|
||||
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(reg_code, vm, m);
|
||||
}
|
||||
void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
|
||||
|
||||
int reg_code;
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
friend class LowDwVfpRegister;
|
||||
explicit constexpr DwVfpRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
static_assert(IS_TRIVIALLY_COPYABLE(DwVfpRegister) &&
|
||||
sizeof(DwVfpRegister) == sizeof(int),
|
||||
"DwVfpRegister can efficiently be passed by value");
|
||||
|
||||
typedef DwVfpRegister DoubleRegister;
|
||||
|
||||
|
||||
// Double word VFP register d0-15.
|
||||
struct LowDwVfpRegister {
|
||||
class LowDwVfpRegister
|
||||
: public RegisterBase<LowDwVfpRegister, kDoubleCode_d16> {
|
||||
public:
|
||||
static constexpr int kMaxNumLowRegisters = 16;
|
||||
constexpr operator DwVfpRegister() const {
|
||||
return DwVfpRegister { reg_code };
|
||||
}
|
||||
static LowDwVfpRegister from_code(int code) {
|
||||
LowDwVfpRegister r = { code };
|
||||
return r;
|
||||
}
|
||||
constexpr operator DwVfpRegister() const { return DwVfpRegister(reg_code_); }
|
||||
|
||||
bool is_valid() const {
|
||||
return 0 <= reg_code && reg_code < kMaxNumLowRegisters;
|
||||
}
|
||||
bool is(DwVfpRegister reg) const { return reg_code == reg.reg_code; }
|
||||
bool is(LowDwVfpRegister reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
SwVfpRegister low() const {
|
||||
SwVfpRegister reg;
|
||||
reg.reg_code = reg_code * 2;
|
||||
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
}
|
||||
SwVfpRegister low() const { return SwVfpRegister::from_code(code() * 2); }
|
||||
SwVfpRegister high() const {
|
||||
SwVfpRegister reg;
|
||||
reg.reg_code = (reg_code * 2) + 1;
|
||||
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
return SwVfpRegister::from_code(code() * 2 + 1);
|
||||
}
|
||||
|
||||
int reg_code;
|
||||
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.
|
||||
struct QwNeonRegister {
|
||||
static constexpr int kMaxNumRegisters = 16;
|
||||
|
||||
static QwNeonRegister from_code(int code) {
|
||||
QwNeonRegister r = { code };
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return (0 <= reg_code) && (reg_code < kMaxNumRegisters);
|
||||
}
|
||||
bool is(QwNeonRegister reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
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(reg_code, vm, m);
|
||||
}
|
||||
DwVfpRegister low() const {
|
||||
DwVfpRegister reg;
|
||||
reg.reg_code = reg_code * 2;
|
||||
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
}
|
||||
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 {
|
||||
DwVfpRegister reg;
|
||||
reg.reg_code = reg_code * 2 + 1;
|
||||
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
return DwVfpRegister::from_code(code() * 2 + 1);
|
||||
}
|
||||
|
||||
int reg_code;
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr QwNeonRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
|
||||
@ -389,92 +292,42 @@ 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)".
|
||||
constexpr SwVfpRegister s0 = { 0 };
|
||||
constexpr SwVfpRegister s1 = { 1 };
|
||||
constexpr SwVfpRegister s2 = { 2 };
|
||||
constexpr SwVfpRegister s3 = { 3 };
|
||||
constexpr SwVfpRegister s4 = { 4 };
|
||||
constexpr SwVfpRegister s5 = { 5 };
|
||||
constexpr SwVfpRegister s6 = { 6 };
|
||||
constexpr SwVfpRegister s7 = { 7 };
|
||||
constexpr SwVfpRegister s8 = { 8 };
|
||||
constexpr SwVfpRegister s9 = { 9 };
|
||||
constexpr SwVfpRegister s10 = { 10 };
|
||||
constexpr SwVfpRegister s11 = { 11 };
|
||||
constexpr SwVfpRegister s12 = { 12 };
|
||||
constexpr SwVfpRegister s13 = { 13 };
|
||||
constexpr SwVfpRegister s14 = { 14 };
|
||||
constexpr SwVfpRegister s15 = { 15 };
|
||||
constexpr SwVfpRegister s16 = { 16 };
|
||||
constexpr SwVfpRegister s17 = { 17 };
|
||||
constexpr SwVfpRegister s18 = { 18 };
|
||||
constexpr SwVfpRegister s19 = { 19 };
|
||||
constexpr SwVfpRegister s20 = { 20 };
|
||||
constexpr SwVfpRegister s21 = { 21 };
|
||||
constexpr SwVfpRegister s22 = { 22 };
|
||||
constexpr SwVfpRegister s23 = { 23 };
|
||||
constexpr SwVfpRegister s24 = { 24 };
|
||||
constexpr SwVfpRegister s25 = { 25 };
|
||||
constexpr SwVfpRegister s26 = { 26 };
|
||||
constexpr SwVfpRegister s27 = { 27 };
|
||||
constexpr SwVfpRegister s28 = { 28 };
|
||||
constexpr SwVfpRegister s29 = { 29 };
|
||||
constexpr SwVfpRegister s30 = { 30 };
|
||||
constexpr SwVfpRegister s31 = { 31 };
|
||||
#define DECLARE_FLOAT_REGISTER(R) \
|
||||
constexpr SwVfpRegister R = SwVfpRegister::from_code<kSwVfpCode_##R>();
|
||||
FLOAT_REGISTERS(DECLARE_FLOAT_REGISTER)
|
||||
#undef DECLARE_FLOAT_REGISTER
|
||||
|
||||
constexpr DwVfpRegister no_dreg = { -1 };
|
||||
constexpr LowDwVfpRegister d0 = { 0 };
|
||||
constexpr LowDwVfpRegister d1 = { 1 };
|
||||
constexpr LowDwVfpRegister d2 = { 2 };
|
||||
constexpr LowDwVfpRegister d3 = { 3 };
|
||||
constexpr LowDwVfpRegister d4 = { 4 };
|
||||
constexpr LowDwVfpRegister d5 = { 5 };
|
||||
constexpr LowDwVfpRegister d6 = { 6 };
|
||||
constexpr LowDwVfpRegister d7 = { 7 };
|
||||
constexpr LowDwVfpRegister d8 = { 8 };
|
||||
constexpr LowDwVfpRegister d9 = { 9 };
|
||||
constexpr LowDwVfpRegister d10 = { 10 };
|
||||
constexpr LowDwVfpRegister d11 = { 11 };
|
||||
constexpr LowDwVfpRegister d12 = { 12 };
|
||||
constexpr LowDwVfpRegister d13 = { 13 };
|
||||
constexpr LowDwVfpRegister d14 = { 14 };
|
||||
constexpr LowDwVfpRegister d15 = { 15 };
|
||||
constexpr DwVfpRegister d16 = { 16 };
|
||||
constexpr DwVfpRegister d17 = { 17 };
|
||||
constexpr DwVfpRegister d18 = { 18 };
|
||||
constexpr DwVfpRegister d19 = { 19 };
|
||||
constexpr DwVfpRegister d20 = { 20 };
|
||||
constexpr DwVfpRegister d21 = { 21 };
|
||||
constexpr DwVfpRegister d22 = { 22 };
|
||||
constexpr DwVfpRegister d23 = { 23 };
|
||||
constexpr DwVfpRegister d24 = { 24 };
|
||||
constexpr DwVfpRegister d25 = { 25 };
|
||||
constexpr DwVfpRegister d26 = { 26 };
|
||||
constexpr DwVfpRegister d27 = { 27 };
|
||||
constexpr DwVfpRegister d28 = { 28 };
|
||||
constexpr DwVfpRegister d29 = { 29 };
|
||||
constexpr DwVfpRegister d30 = { 30 };
|
||||
constexpr DwVfpRegister d31 = { 31 };
|
||||
#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
|
||||
|
||||
constexpr QwNeonRegister q0 = { 0 };
|
||||
constexpr QwNeonRegister q1 = { 1 };
|
||||
constexpr QwNeonRegister q2 = { 2 };
|
||||
constexpr QwNeonRegister q3 = { 3 };
|
||||
constexpr QwNeonRegister q4 = { 4 };
|
||||
constexpr QwNeonRegister q5 = { 5 };
|
||||
constexpr QwNeonRegister q6 = { 6 };
|
||||
constexpr QwNeonRegister q7 = { 7 };
|
||||
constexpr QwNeonRegister q8 = { 8 };
|
||||
constexpr QwNeonRegister q9 = { 9 };
|
||||
constexpr QwNeonRegister q10 = { 10 };
|
||||
constexpr QwNeonRegister q11 = { 11 };
|
||||
constexpr QwNeonRegister q12 = { 12 };
|
||||
constexpr QwNeonRegister q13 = { 13 };
|
||||
constexpr QwNeonRegister q14 = { 14 };
|
||||
constexpr QwNeonRegister q15 = { 15 };
|
||||
#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;
|
||||
@ -487,43 +340,12 @@ constexpr LowDwVfpRegister kScratchDoubleReg = d14;
|
||||
constexpr QwNeonRegister kScratchQuadReg = q7;
|
||||
constexpr LowDwVfpRegister kScratchDoubleReg2 = d15;
|
||||
|
||||
// Coprocessor register
|
||||
struct CRegister {
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < 16; }
|
||||
bool is(CRegister 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;
|
||||
}
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
|
||||
constexpr CRegister no_creg = { -1 };
|
||||
|
||||
constexpr CRegister cr0 = { 0 };
|
||||
constexpr CRegister cr1 = { 1 };
|
||||
constexpr CRegister cr2 = { 2 };
|
||||
constexpr CRegister cr3 = { 3 };
|
||||
constexpr CRegister cr4 = { 4 };
|
||||
constexpr CRegister cr5 = { 5 };
|
||||
constexpr CRegister cr6 = { 6 };
|
||||
constexpr CRegister cr7 = { 7 };
|
||||
constexpr CRegister cr8 = { 8 };
|
||||
constexpr CRegister cr9 = { 9 };
|
||||
constexpr CRegister cr10 = { 10 };
|
||||
constexpr CRegister cr11 = { 11 };
|
||||
constexpr CRegister cr12 = { 12 };
|
||||
constexpr CRegister cr13 = { 13 };
|
||||
constexpr CRegister cr14 = { 14 };
|
||||
constexpr CRegister cr15 = { 15 };
|
||||
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 {
|
||||
@ -639,8 +461,8 @@ class Operand BASE_EMBEDDED {
|
||||
|
||||
|
||||
private:
|
||||
Register rm_;
|
||||
Register rs_;
|
||||
Register rm_ = no_reg;
|
||||
Register rs_ = no_reg;
|
||||
ShiftOp shift_op_;
|
||||
int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
|
||||
union Value {
|
||||
@ -1791,13 +1613,13 @@ class Assembler : public AssemblerBase {
|
||||
bool VfpRegisterIsAvailable(DwVfpRegister reg) {
|
||||
DCHECK(reg.is_valid());
|
||||
return IsEnabled(VFP32DREGS) ||
|
||||
(reg.reg_code < LowDwVfpRegister::kMaxNumLowRegisters);
|
||||
(reg.code() < LowDwVfpRegister::kNumRegisters);
|
||||
}
|
||||
|
||||
bool VfpRegisterIsAvailable(QwNeonRegister reg) {
|
||||
DCHECK(reg.is_valid());
|
||||
return IsEnabled(VFP32DREGS) ||
|
||||
(reg.reg_code < LowDwVfpRegister::kMaxNumLowRegisters / 2);
|
||||
(reg.code() < LowDwVfpRegister::kNumRegisters / 2);
|
||||
}
|
||||
|
||||
inline void emit(Instr x);
|
||||
|
@ -410,14 +410,11 @@ void CEntryStub::Generate(MacroAssembler* masm) {
|
||||
// r0:r1: result
|
||||
// sp: stack pointer
|
||||
// fp: frame pointer
|
||||
Register argc;
|
||||
if (argv_in_register()) {
|
||||
// We don't want to pop arguments so set argc to no_reg.
|
||||
argc = no_reg;
|
||||
} else {
|
||||
// Callee-saved register r4 still holds argc.
|
||||
argc = r4;
|
||||
}
|
||||
Register argc = argv_in_register()
|
||||
// We don't want to pop arguments so set argc to no_reg.
|
||||
? no_reg
|
||||
// Callee-saved register r4 still holds argc.
|
||||
: r4;
|
||||
__ LeaveExitFrame(save_doubles(), argc, true);
|
||||
__ mov(pc, lr);
|
||||
|
||||
|
@ -124,12 +124,11 @@ class RecordWriteStub: public PlatformCodeStub {
|
||||
// the caller.
|
||||
class RegisterAllocation {
|
||||
public:
|
||||
RegisterAllocation(Register object,
|
||||
Register address,
|
||||
Register scratch0)
|
||||
RegisterAllocation(Register object, Register address, Register scratch0)
|
||||
: object_(object),
|
||||
address_(address),
|
||||
scratch0_(scratch0) {
|
||||
scratch0_(scratch0),
|
||||
scratch1_(no_reg) {
|
||||
DCHECK(!AreAliased(scratch0, object, address, no_reg));
|
||||
scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
// Everything but pc, lr and ip which will be saved but not restored.
|
||||
RegList restored_regs = kJSCallerSaved | kCalleeSaved | ip.bit();
|
||||
|
||||
const int kDoubleRegsSize = kDoubleSize * DwVfpRegister::kMaxNumRegisters;
|
||||
const int kFloatRegsSize = kFloatSize * SwVfpRegister::kMaxNumRegisters;
|
||||
const int kDoubleRegsSize = kDoubleSize * DwVfpRegister::kNumRegisters;
|
||||
const int kFloatRegsSize = kFloatSize * SwVfpRegister::kNumRegisters;
|
||||
|
||||
// Save all allocatable VFP registers before messing with them.
|
||||
DCHECK(kDoubleRegZero.code() == 13);
|
||||
@ -115,7 +115,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
}
|
||||
|
||||
// Copy VFP registers to
|
||||
// double_registers_[DoubleRegister::kMaxNumAllocatableRegisters]
|
||||
// double_registers_[DoubleRegister::kNumAllocatableRegisters]
|
||||
int double_regs_offset = FrameDescription::double_registers_offset();
|
||||
const RegisterConfiguration* config = RegisterConfiguration::Default();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
@ -128,7 +128,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
}
|
||||
|
||||
// Copy VFP registers to
|
||||
// float_registers_[FloatRegister::kMaxNumAllocatableRegisters]
|
||||
// float_registers_[FloatRegister::kNumAllocatableRegisters]
|
||||
int float_regs_offset = FrameDescription::float_registers_offset();
|
||||
for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
|
||||
int code = config->GetAllocatableFloatCode(i);
|
||||
|
@ -27,13 +27,13 @@ void EhFrameWriter::WriteInitialStateInCie() {
|
||||
// static
|
||||
int EhFrameWriter::RegisterToDwarfCode(Register name) {
|
||||
switch (name.code()) {
|
||||
case Register::kCode_fp:
|
||||
case kRegCode_fp:
|
||||
return kFpDwarfCode;
|
||||
case Register::kCode_sp:
|
||||
case kRegCode_sp:
|
||||
return kSpDwarfCode;
|
||||
case Register::kCode_lr:
|
||||
case kRegCode_lr:
|
||||
return kLrDwarfCode;
|
||||
case Register::kCode_r0:
|
||||
case kRegCode_r0:
|
||||
return kR0DwarfCode;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
|
@ -894,8 +894,8 @@ void TurboAssembler::VmovLow(DwVfpRegister dst, Register src) {
|
||||
}
|
||||
|
||||
void TurboAssembler::VmovExtended(Register dst, int src_code) {
|
||||
DCHECK_LE(SwVfpRegister::kMaxNumRegisters, src_code);
|
||||
DCHECK_GT(SwVfpRegister::kMaxNumRegisters * 2, src_code);
|
||||
DCHECK_LE(SwVfpRegister::kNumRegisters, src_code);
|
||||
DCHECK_GT(SwVfpRegister::kNumRegisters * 2, src_code);
|
||||
if (src_code & 0x1) {
|
||||
VmovHigh(dst, DwVfpRegister::from_code(src_code / 2));
|
||||
} else {
|
||||
@ -904,8 +904,8 @@ void TurboAssembler::VmovExtended(Register dst, int src_code) {
|
||||
}
|
||||
|
||||
void TurboAssembler::VmovExtended(int dst_code, Register src) {
|
||||
DCHECK_LE(SwVfpRegister::kMaxNumRegisters, dst_code);
|
||||
DCHECK_GT(SwVfpRegister::kMaxNumRegisters * 2, dst_code);
|
||||
DCHECK_LE(SwVfpRegister::kNumRegisters, dst_code);
|
||||
DCHECK_GT(SwVfpRegister::kNumRegisters * 2, dst_code);
|
||||
if (dst_code & 0x1) {
|
||||
VmovHigh(DwVfpRegister::from_code(dst_code / 2), src);
|
||||
} else {
|
||||
@ -916,8 +916,8 @@ void TurboAssembler::VmovExtended(int dst_code, Register src) {
|
||||
void TurboAssembler::VmovExtended(int dst_code, int src_code) {
|
||||
if (src_code == dst_code) return;
|
||||
|
||||
if (src_code < SwVfpRegister::kMaxNumRegisters &&
|
||||
dst_code < SwVfpRegister::kMaxNumRegisters) {
|
||||
if (src_code < SwVfpRegister::kNumRegisters &&
|
||||
dst_code < SwVfpRegister::kNumRegisters) {
|
||||
// src and dst are both s-registers.
|
||||
vmov(SwVfpRegister::from_code(dst_code),
|
||||
SwVfpRegister::from_code(src_code));
|
||||
@ -955,13 +955,13 @@ void TurboAssembler::VmovExtended(int dst_code, int src_code) {
|
||||
// s-registers.
|
||||
int scratchSCode = kScratchDoubleReg.low().code();
|
||||
int scratchSCode2 = kScratchDoubleReg2.low().code();
|
||||
if (src_code < SwVfpRegister::kMaxNumRegisters) {
|
||||
if (src_code < SwVfpRegister::kNumRegisters) {
|
||||
// src is an s-register, dst is not.
|
||||
vmov(kScratchDoubleReg, dst_d_reg);
|
||||
vmov(SwVfpRegister::from_code(scratchSCode + dst_offset),
|
||||
SwVfpRegister::from_code(src_code));
|
||||
vmov(dst_d_reg, kScratchDoubleReg);
|
||||
} else if (dst_code < SwVfpRegister::kMaxNumRegisters) {
|
||||
} else if (dst_code < SwVfpRegister::kNumRegisters) {
|
||||
// dst is an s-register, src is not.
|
||||
vmov(kScratchDoubleReg, src_d_reg);
|
||||
vmov(SwVfpRegister::from_code(dst_code),
|
||||
@ -978,7 +978,7 @@ void TurboAssembler::VmovExtended(int dst_code, int src_code) {
|
||||
}
|
||||
|
||||
void TurboAssembler::VmovExtended(int dst_code, const MemOperand& src) {
|
||||
if (dst_code < SwVfpRegister::kMaxNumRegisters) {
|
||||
if (dst_code < SwVfpRegister::kNumRegisters) {
|
||||
vldr(SwVfpRegister::from_code(dst_code), src);
|
||||
} else {
|
||||
// TODO(bbudge) If Neon supported, use load single lane form of vld1.
|
||||
@ -990,7 +990,7 @@ void TurboAssembler::VmovExtended(int dst_code, const MemOperand& src) {
|
||||
}
|
||||
|
||||
void TurboAssembler::VmovExtended(const MemOperand& dst, int src_code) {
|
||||
if (src_code < SwVfpRegister::kMaxNumRegisters) {
|
||||
if (src_code < SwVfpRegister::kNumRegisters) {
|
||||
vstr(SwVfpRegister::from_code(src_code), dst);
|
||||
} else {
|
||||
// TODO(bbudge) If Neon supported, use store single lane form of vst1.
|
||||
@ -1269,7 +1269,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
|
||||
SaveFPRegs(sp, scratch);
|
||||
// Note that d0 will be accessible at
|
||||
// fp - ExitFrameConstants::kFrameSize -
|
||||
// DwVfpRegister::kMaxNumRegisters * kDoubleSize,
|
||||
// DwVfpRegister::kNumRegisters * kDoubleSize,
|
||||
// since the sp slot and code slot were pushed after the fp.
|
||||
}
|
||||
|
||||
@ -1316,8 +1316,7 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
|
||||
if (save_doubles) {
|
||||
// Calculate the stack location of the saved doubles and restore them.
|
||||
const int offset = ExitFrameConstants::kFixedFrameSizeFromFp;
|
||||
sub(r3, fp,
|
||||
Operand(offset + DwVfpRegister::kMaxNumRegisters * kDoubleSize));
|
||||
sub(r3, fp, Operand(offset + DwVfpRegister::kNumRegisters * kDoubleSize));
|
||||
RestoreFPRegs(r3, scratch);
|
||||
}
|
||||
|
||||
|
@ -27,132 +27,83 @@ void RelocInfo::apply(intptr_t delta) {
|
||||
*p += delta; // Relocate entry.
|
||||
}
|
||||
|
||||
inline int CPURegister::code() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_code;
|
||||
}
|
||||
|
||||
|
||||
inline CPURegister::RegisterType CPURegister::type() const {
|
||||
DCHECK(IsValidOrNone());
|
||||
return reg_type;
|
||||
}
|
||||
inline CPURegister::RegisterType CPURegister::type() const { return reg_type_; }
|
||||
|
||||
inline RegList CPURegister::bit() const {
|
||||
DCHECK(static_cast<size_t>(reg_code) < (sizeof(RegList) * kBitsPerByte));
|
||||
return IsValid() ? 1UL << reg_code : 0;
|
||||
DCHECK(static_cast<size_t>(reg_code_) < (sizeof(RegList) * kBitsPerByte));
|
||||
return IsValid() ? 1UL << reg_code_ : 0;
|
||||
}
|
||||
|
||||
|
||||
inline int CPURegister::SizeInBits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size;
|
||||
return reg_size_;
|
||||
}
|
||||
|
||||
|
||||
inline int CPURegister::SizeInBytes() const {
|
||||
DCHECK(IsValid());
|
||||
DCHECK(SizeInBits() % 8 == 0);
|
||||
return reg_size / 8;
|
||||
return reg_size_ / 8;
|
||||
}
|
||||
|
||||
inline bool CPURegister::Is8Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size == 8;
|
||||
return reg_size_ == 8;
|
||||
}
|
||||
|
||||
inline bool CPURegister::Is16Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size == 16;
|
||||
return reg_size_ == 16;
|
||||
}
|
||||
|
||||
inline bool CPURegister::Is32Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size == 32;
|
||||
return reg_size_ == 32;
|
||||
}
|
||||
|
||||
|
||||
inline bool CPURegister::Is64Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size == 64;
|
||||
return reg_size_ == 64;
|
||||
}
|
||||
|
||||
inline bool CPURegister::Is128Bits() const {
|
||||
DCHECK(IsValid());
|
||||
return reg_size == 128;
|
||||
return reg_size_ == 128;
|
||||
}
|
||||
|
||||
inline bool CPURegister::IsValid() const {
|
||||
if (IsValidRegister() || IsValidVRegister()) {
|
||||
DCHECK(!IsNone());
|
||||
return true;
|
||||
} else {
|
||||
DCHECK(IsNone());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool CPURegister::IsValidRegister() const {
|
||||
return IsRegister() &&
|
||||
((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits)) &&
|
||||
((reg_code < kNumberOfRegisters) || (reg_code == kSPRegInternalCode));
|
||||
}
|
||||
|
||||
inline bool CPURegister::IsValidVRegister() const {
|
||||
return IsVRegister() &&
|
||||
((reg_size == kBRegSizeInBits) || (reg_size == kHRegSizeInBits) ||
|
||||
(reg_size == kSRegSizeInBits) || (reg_size == kDRegSizeInBits) ||
|
||||
(reg_size == kQRegSizeInBits)) &&
|
||||
(reg_code < kNumberOfVRegisters);
|
||||
}
|
||||
|
||||
inline bool CPURegister::IsNone() const {
|
||||
// kNoRegister types should always have size 0 and code 0.
|
||||
DCHECK((reg_type != kNoRegister) || (reg_code == 0));
|
||||
DCHECK((reg_type != kNoRegister) || (reg_size == 0));
|
||||
|
||||
return reg_type == kNoRegister;
|
||||
}
|
||||
inline bool CPURegister::IsValid() const { return reg_type_ != kNoRegister; }
|
||||
|
||||
inline bool CPURegister::IsNone() const { return reg_type_ == kNoRegister; }
|
||||
|
||||
inline bool CPURegister::Is(const CPURegister& other) const {
|
||||
DCHECK(IsValidOrNone() && other.IsValidOrNone());
|
||||
return Aliases(other) && (reg_size == other.reg_size);
|
||||
return Aliases(other) && (reg_size_ == other.reg_size_);
|
||||
}
|
||||
|
||||
|
||||
inline bool CPURegister::Aliases(const CPURegister& other) const {
|
||||
DCHECK(IsValidOrNone() && other.IsValidOrNone());
|
||||
return (reg_code == other.reg_code) && (reg_type == other.reg_type);
|
||||
return (reg_code_ == other.reg_code_) && (reg_type_ == other.reg_type_);
|
||||
}
|
||||
|
||||
inline bool CPURegister::IsRegister() const { return reg_type_ == kRegister; }
|
||||
|
||||
inline bool CPURegister::IsRegister() const {
|
||||
return reg_type == kRegister;
|
||||
}
|
||||
|
||||
inline bool CPURegister::IsVRegister() const { return reg_type == kVRegister; }
|
||||
inline bool CPURegister::IsVRegister() const { return reg_type_ == kVRegister; }
|
||||
|
||||
inline bool CPURegister::IsSameSizeAndType(const CPURegister& other) const {
|
||||
return (reg_size == other.reg_size) && (reg_type == other.reg_type);
|
||||
}
|
||||
|
||||
|
||||
inline bool CPURegister::IsValidOrNone() const {
|
||||
return IsValid() || IsNone();
|
||||
return (reg_size_ == other.reg_size_) && (reg_type_ == other.reg_type_);
|
||||
}
|
||||
|
||||
|
||||
inline bool CPURegister::IsZero() const {
|
||||
DCHECK(IsValid());
|
||||
return IsRegister() && (reg_code == kZeroRegCode);
|
||||
return IsRegister() && (reg_code_ == kZeroRegCode);
|
||||
}
|
||||
|
||||
|
||||
inline bool CPURegister::IsSP() const {
|
||||
DCHECK(IsValid());
|
||||
return IsRegister() && (reg_code == kSPRegInternalCode);
|
||||
return IsRegister() && (reg_code_ == kSPRegInternalCode);
|
||||
}
|
||||
|
||||
|
||||
@ -254,44 +205,53 @@ inline VRegister VRegister::VRegFromCode(unsigned code) {
|
||||
}
|
||||
|
||||
inline Register CPURegister::W() const {
|
||||
DCHECK(IsValidRegister());
|
||||
return Register::WRegFromCode(reg_code);
|
||||
DCHECK(IsRegister());
|
||||
return Register::WRegFromCode(reg_code_);
|
||||
}
|
||||
|
||||
inline Register CPURegister::Reg() const {
|
||||
DCHECK(IsRegister());
|
||||
return Register::Create(reg_code_, reg_size_);
|
||||
}
|
||||
|
||||
inline VRegister CPURegister::VReg() const {
|
||||
DCHECK(IsVRegister());
|
||||
return VRegister::Create(reg_code_, reg_size_);
|
||||
}
|
||||
|
||||
inline Register CPURegister::X() const {
|
||||
DCHECK(IsValidRegister());
|
||||
return Register::XRegFromCode(reg_code);
|
||||
DCHECK(IsRegister());
|
||||
return Register::XRegFromCode(reg_code_);
|
||||
}
|
||||
|
||||
inline VRegister CPURegister::V() const {
|
||||
DCHECK(IsValidVRegister());
|
||||
return VRegister::VRegFromCode(reg_code);
|
||||
DCHECK(IsVRegister());
|
||||
return VRegister::VRegFromCode(reg_code_);
|
||||
}
|
||||
|
||||
inline VRegister CPURegister::B() const {
|
||||
DCHECK(IsValidVRegister());
|
||||
return VRegister::BRegFromCode(reg_code);
|
||||
DCHECK(IsVRegister());
|
||||
return VRegister::BRegFromCode(reg_code_);
|
||||
}
|
||||
|
||||
inline VRegister CPURegister::H() const {
|
||||
DCHECK(IsValidVRegister());
|
||||
return VRegister::HRegFromCode(reg_code);
|
||||
DCHECK(IsVRegister());
|
||||
return VRegister::HRegFromCode(reg_code_);
|
||||
}
|
||||
|
||||
inline VRegister CPURegister::S() const {
|
||||
DCHECK(IsValidVRegister());
|
||||
return VRegister::SRegFromCode(reg_code);
|
||||
DCHECK(IsVRegister());
|
||||
return VRegister::SRegFromCode(reg_code_);
|
||||
}
|
||||
|
||||
inline VRegister CPURegister::D() const {
|
||||
DCHECK(IsValidVRegister());
|
||||
return VRegister::DRegFromCode(reg_code);
|
||||
DCHECK(IsVRegister());
|
||||
return VRegister::DRegFromCode(reg_code_);
|
||||
}
|
||||
|
||||
inline VRegister CPURegister::Q() const {
|
||||
DCHECK(IsValidVRegister());
|
||||
return VRegister::QRegFromCode(reg_code);
|
||||
DCHECK(IsVRegister());
|
||||
return VRegister::QRegFromCode(reg_code_);
|
||||
}
|
||||
|
||||
|
||||
@ -541,15 +501,12 @@ MemOperand::MemOperand(Register base,
|
||||
DCHECK(shift == LSL);
|
||||
}
|
||||
|
||||
|
||||
MemOperand::MemOperand(Register base, const Operand& offset, AddrMode addrmode)
|
||||
: base_(base), addrmode_(addrmode) {
|
||||
: base_(base), regoffset_(NoReg), addrmode_(addrmode) {
|
||||
DCHECK(base.Is64Bits() && !base.IsZero());
|
||||
|
||||
if (offset.IsImmediate()) {
|
||||
offset_ = offset.ImmediateValue();
|
||||
|
||||
regoffset_ = NoReg;
|
||||
} else if (offset.IsShiftedRegister()) {
|
||||
DCHECK((addrmode == Offset) || (addrmode == PostIndex));
|
||||
|
||||
|
@ -88,43 +88,39 @@ const int kNumSafepointRegisters = 32;
|
||||
|
||||
// Some CPURegister methods can return Register and VRegister types, so we
|
||||
// need to declare them in advance.
|
||||
struct Register;
|
||||
struct VRegister;
|
||||
class Register;
|
||||
class VRegister;
|
||||
|
||||
struct CPURegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class CPURegister : public RegisterBase<CPURegister, kRegAfterLast> {
|
||||
public:
|
||||
enum RegisterType {
|
||||
// The kInvalid value is used to detect uninitialized static instances,
|
||||
// which are always zero-initialized before any constructors are called.
|
||||
kInvalid = 0,
|
||||
kRegister,
|
||||
kVRegister,
|
||||
kNoRegister
|
||||
};
|
||||
|
||||
constexpr CPURegister() : CPURegister(0, 0, CPURegister::kNoRegister) {}
|
||||
|
||||
constexpr CPURegister(int reg_code, int reg_size, RegisterType reg_type,
|
||||
int lane_count = 1)
|
||||
: reg_code(reg_code),
|
||||
reg_size(reg_size),
|
||||
reg_type(reg_type),
|
||||
lane_count(lane_count) {}
|
||||
|
||||
static CPURegister Create(int reg_code, int reg_size, RegisterType reg_type,
|
||||
int lane_count = 1) {
|
||||
CPURegister r = {reg_code, reg_size, reg_type, lane_count};
|
||||
return r;
|
||||
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};
|
||||
}
|
||||
|
||||
int code() const;
|
||||
RegisterType type() const;
|
||||
RegList bit() const;
|
||||
int SizeInBits() const;
|
||||
@ -135,9 +131,6 @@ struct CPURegister {
|
||||
bool Is64Bits() const;
|
||||
bool Is128Bits() const;
|
||||
bool IsValid() const;
|
||||
bool IsValidOrNone() const;
|
||||
bool IsValidRegister() const;
|
||||
bool IsValidVRegister() const;
|
||||
bool IsNone() const;
|
||||
bool Is(const CPURegister& other) const;
|
||||
bool Aliases(const CPURegister& other) const;
|
||||
@ -150,8 +143,8 @@ struct CPURegister {
|
||||
|
||||
bool IsFPRegister() const { return IsS() || IsD(); }
|
||||
|
||||
bool IsW() const { return IsValidRegister() && Is32Bits(); }
|
||||
bool IsX() const { return IsValidRegister() && Is64Bits(); }
|
||||
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.
|
||||
@ -166,6 +159,9 @@ struct CPURegister {
|
||||
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;
|
||||
@ -181,25 +177,51 @@ struct CPURegister {
|
||||
bool is(const CPURegister& other) const { return Is(other); }
|
||||
bool is_valid() const { return IsValid(); }
|
||||
|
||||
int reg_code;
|
||||
int reg_size;
|
||||
RegisterType reg_type;
|
||||
int lane_count;
|
||||
};
|
||||
protected:
|
||||
int reg_size_;
|
||||
RegisterType reg_type_;
|
||||
|
||||
friend class RegisterBase;
|
||||
|
||||
struct Register : public CPURegister {
|
||||
static Register Create(int code, int size) {
|
||||
return Register(CPURegister::Create(code, size, CPURegister::kRegister));
|
||||
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);
|
||||
}
|
||||
|
||||
constexpr Register() : CPURegister() {}
|
||||
static constexpr bool IsValidVRegister(int code, int size) {
|
||||
return (size == kBRegSizeInBits || size == kHRegSizeInBits ||
|
||||
size == kSRegSizeInBits || size == kDRegSizeInBits ||
|
||||
size == kQRegSizeInBits) &&
|
||||
code < kNumberOfVRegisters;
|
||||
}
|
||||
|
||||
constexpr explicit Register(const CPURegister& r) : CPURegister(r) {}
|
||||
static constexpr bool IsValid(int code, int size, RegisterType type) {
|
||||
return (type == kRegister && IsValidRegister(code, size)) ||
|
||||
(type == kVRegister && IsValidVRegister(code, size));
|
||||
}
|
||||
|
||||
bool IsValid() const {
|
||||
DCHECK(IsRegister() || IsNone());
|
||||
return IsValidRegister();
|
||||
static constexpr bool IsNone(int code, int size, RegisterType type) {
|
||||
return type == kNoRegister && code == 0 && size == 0;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(IS_TRIVIALLY_COPYABLE(CPURegister),
|
||||
"CPURegister can efficiently be passed by value");
|
||||
|
||||
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);
|
||||
@ -209,10 +231,6 @@ struct Register : public CPURegister {
|
||||
// These memebers are necessary for compilation.
|
||||
// A few of them may be unused for now.
|
||||
|
||||
static constexpr int kNumRegisters = kNumberOfRegisters;
|
||||
STATIC_ASSERT(kNumRegisters == Code::kAfterLast);
|
||||
static int NumRegisters() { return kNumRegisters; }
|
||||
|
||||
// We allow crankshaft to use the following registers:
|
||||
// - x0 to x15
|
||||
// - x18 to x24
|
||||
@ -234,26 +252,40 @@ struct Register : public CPURegister {
|
||||
}
|
||||
|
||||
// End of V8 compatibility section -----------------------
|
||||
//
|
||||
private:
|
||||
constexpr explicit Register(const CPURegister& r) : CPURegister(r) {}
|
||||
};
|
||||
|
||||
static_assert(IS_TRIVIALLY_COPYABLE(Register),
|
||||
"Register can efficiently be passed by value");
|
||||
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
struct VRegister : public CPURegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
static VRegister Create(int reg_code, int reg_size, int lane_count = 1) {
|
||||
DCHECK(base::bits::IsPowerOfTwo(lane_count) && (lane_count <= 16));
|
||||
VRegister v(CPURegister::Create(reg_code, reg_size, CPURegister::kVRegister,
|
||||
lane_count));
|
||||
DCHECK(v.IsValidVRegister());
|
||||
return v;
|
||||
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) {
|
||||
@ -262,15 +294,6 @@ struct VRegister : public CPURegister {
|
||||
return VRegister::Create(reg_code, reg_size, reg_count);
|
||||
}
|
||||
|
||||
constexpr VRegister() : CPURegister() {}
|
||||
|
||||
constexpr explicit VRegister(const CPURegister& r) : CPURegister(r) {}
|
||||
|
||||
bool IsValid() const {
|
||||
DCHECK(IsVRegister() || IsNone());
|
||||
return IsValidVRegister();
|
||||
}
|
||||
|
||||
static VRegister BRegFromCode(unsigned code);
|
||||
static VRegister HRegFromCode(unsigned code);
|
||||
static VRegister SRegFromCode(unsigned code);
|
||||
@ -303,14 +326,14 @@ struct VRegister : public CPURegister {
|
||||
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)); }
|
||||
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
|
||||
@ -333,22 +356,22 @@ struct VRegister : public CPURegister {
|
||||
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 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);
|
||||
return (reg_size_ == other.reg_size_) && (lane_count_ == other.lane_count_);
|
||||
}
|
||||
|
||||
int LaneCount() const { return lane_count; }
|
||||
int LaneCount() const { return lane_count_; }
|
||||
|
||||
unsigned LaneSizeInBytes() const { return SizeInBytes() / lane_count; }
|
||||
unsigned LaneSizeInBytes() const { return SizeInBytes() / lane_count_; }
|
||||
|
||||
unsigned LaneSizeInBits() const { return LaneSizeInBytes() * 8; }
|
||||
|
||||
// Start of V8 compatibility section ---------------------
|
||||
static constexpr int kMaxNumRegisters = kNumberOfVRegisters;
|
||||
STATIC_ASSERT(kMaxNumRegisters == Code::kAfterLast);
|
||||
STATIC_ASSERT(kMaxNumRegisters == kDoubleAfterLast);
|
||||
|
||||
// Crankshaft can use all the V registers except:
|
||||
// - d15 which is used to keep the 0 double value
|
||||
@ -359,51 +382,52 @@ struct VRegister : public CPURegister {
|
||||
return VRegister::Create(code, kDRegSizeInBits);
|
||||
}
|
||||
// End of V8 compatibility section -----------------------
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(CPURegister) == sizeof(Register),
|
||||
"CPURegister must be same size as Register");
|
||||
static_assert(sizeof(CPURegister) == sizeof(VRegister),
|
||||
"CPURegister must be same size as VRegister");
|
||||
|
||||
#define DEFINE_REGISTER(register_class, name, code, size, type) \
|
||||
constexpr register_class name { CPURegister(code, size, type) }
|
||||
#define ALIAS_REGISTER(register_class, alias, name) \
|
||||
constexpr register_class alias = name
|
||||
static_assert(IS_TRIVIALLY_COPYABLE(VRegister),
|
||||
"VRegister can efficiently be passed by value");
|
||||
|
||||
// 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.
|
||||
DEFINE_REGISTER(Register, NoReg, 0, 0, CPURegister::kNoRegister);
|
||||
DEFINE_REGISTER(VRegister, NoVReg, 0, 0, CPURegister::kNoRegister);
|
||||
DEFINE_REGISTER(CPURegister, NoCPUReg, 0, 0, CPURegister::kNoRegister);
|
||||
constexpr Register NoReg = Register::no_reg();
|
||||
constexpr VRegister NoVReg = VRegister::no_reg();
|
||||
constexpr CPURegister NoCPUReg = CPURegister::no_reg();
|
||||
|
||||
// v8 compatibility.
|
||||
DEFINE_REGISTER(Register, no_reg, 0, 0, CPURegister::kNoRegister);
|
||||
constexpr Register no_reg = NoReg;
|
||||
|
||||
#define DEFINE_REGISTERS(N) \
|
||||
DEFINE_REGISTER(Register, w##N, N, kWRegSizeInBits, CPURegister::kRegister); \
|
||||
DEFINE_REGISTER(Register, x##N, N, kXRegSizeInBits, CPURegister::kRegister);
|
||||
#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, wcsp, kSPRegInternalCode, kWRegSizeInBits,
|
||||
CPURegister::kRegister);
|
||||
DEFINE_REGISTER(Register, csp, kSPRegInternalCode, kXRegSizeInBits,
|
||||
CPURegister::kRegister);
|
||||
DEFINE_REGISTER(Register, wcsp, kSPRegInternalCode, kWRegSizeInBits);
|
||||
DEFINE_REGISTER(Register, csp, kSPRegInternalCode, kXRegSizeInBits);
|
||||
|
||||
#define DEFINE_VREGISTERS(N) \
|
||||
DEFINE_REGISTER(VRegister, b##N, N, kBRegSizeInBits, \
|
||||
CPURegister::kVRegister); \
|
||||
DEFINE_REGISTER(VRegister, h##N, N, kHRegSizeInBits, \
|
||||
CPURegister::kVRegister); \
|
||||
DEFINE_REGISTER(VRegister, s##N, N, kSRegSizeInBits, \
|
||||
CPURegister::kVRegister); \
|
||||
DEFINE_REGISTER(VRegister, d##N, N, kDRegSizeInBits, \
|
||||
CPURegister::kVRegister); \
|
||||
DEFINE_REGISTER(VRegister, q##N, N, kQRegSizeInBits, \
|
||||
CPURegister::kVRegister); \
|
||||
DEFINE_REGISTER(VRegister, v##N, N, kQRegSizeInBits, CPURegister::kVRegister);
|
||||
#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
|
||||
|
||||
|
@ -859,8 +859,8 @@ RecordWriteStub::RegisterAllocation::RegisterAllocation(Register object,
|
||||
CPURegList pool_available = GetValidRegistersForAllocation();
|
||||
CPURegList used_regs(object, address, scratch);
|
||||
pool_available.Remove(used_regs);
|
||||
scratch1_ = Register(pool_available.PopLowestIndex());
|
||||
scratch2_ = Register(pool_available.PopLowestIndex());
|
||||
scratch1_ = pool_available.PopLowestIndex().Reg();
|
||||
scratch2_ = pool_available.PopLowestIndex().Reg();
|
||||
|
||||
// The scratch registers will be restored by other means so we don't need
|
||||
// to save them with the other caller saved registers.
|
||||
|
@ -181,8 +181,8 @@ class RecordWriteStub: public PlatformCodeStub {
|
||||
Register object_;
|
||||
Register address_;
|
||||
Register scratch0_;
|
||||
Register scratch1_;
|
||||
Register scratch2_;
|
||||
Register scratch1_ = NoReg;
|
||||
Register scratch2_ = NoReg;
|
||||
CPURegList saved_regs_;
|
||||
CPURegList saved_fp_regs_;
|
||||
|
||||
|
@ -29,15 +29,15 @@ void EhFrameWriter::WriteInitialStateInCie() {
|
||||
// static
|
||||
int EhFrameWriter::RegisterToDwarfCode(Register name) {
|
||||
switch (name.code()) {
|
||||
case Register::kCode_x28:
|
||||
case kRegCode_x28:
|
||||
return kJsSpDwarfCode;
|
||||
case Register::kCode_x29:
|
||||
case kRegCode_x29:
|
||||
return kFpDwarfCode;
|
||||
case Register::kCode_x30:
|
||||
case kRegCode_x30:
|
||||
return kLrDwarfCode;
|
||||
case Register::kCode_x31:
|
||||
case kRegCode_x31:
|
||||
return kCSpDwarfCode;
|
||||
case Register::kCode_x0:
|
||||
case kRegCode_x0:
|
||||
return kX0DwarfCode;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
|
@ -3610,12 +3610,12 @@ void MacroAssembler::PrintfNoPreserve(const char * format,
|
||||
if (kPCSVarargs.IncludesAliasOf(args[i]) ||
|
||||
kPCSVarargsFP.IncludesAliasOf(args[i])) {
|
||||
if (args[i].IsRegister()) {
|
||||
Register old_arg = Register(args[i]);
|
||||
Register old_arg = args[i].Reg();
|
||||
Register new_arg = temps.AcquireSameSizeAs(old_arg);
|
||||
Mov(new_arg, old_arg);
|
||||
args[i] = new_arg;
|
||||
} else {
|
||||
VRegister old_arg = VRegister(args[i]);
|
||||
VRegister old_arg = args[i].VReg();
|
||||
VRegister new_arg = temps.AcquireSameSizeAs(old_arg);
|
||||
Fmov(new_arg, old_arg);
|
||||
args[i] = new_arg;
|
||||
@ -3628,13 +3628,13 @@ void MacroAssembler::PrintfNoPreserve(const char * format,
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
DCHECK(pcs[i].type() == args[i].type());
|
||||
if (pcs[i].IsRegister()) {
|
||||
Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);
|
||||
Mov(pcs[i].Reg(), args[i].Reg(), kDiscardForSameWReg);
|
||||
} else {
|
||||
DCHECK(pcs[i].IsVRegister());
|
||||
if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) {
|
||||
Fmov(VRegister(pcs[i]), VRegister(args[i]));
|
||||
Fmov(pcs[i].VReg(), args[i].VReg());
|
||||
} else {
|
||||
Fcvt(VRegister(pcs[i]), VRegister(args[i]));
|
||||
Fcvt(pcs[i].VReg(), args[i].VReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1254,6 +1254,60 @@ class HeapObjectRequest {
|
||||
int offset_;
|
||||
};
|
||||
|
||||
// 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 {
|
||||
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};
|
||||
}
|
||||
|
||||
static SubType from_code(int code) {
|
||||
DCHECK_LE(0, code);
|
||||
DCHECK_GT(kNumRegisters, code);
|
||||
return SubType{code};
|
||||
}
|
||||
|
||||
bool is_valid() const { return reg_code_ != kCode_no_reg; }
|
||||
|
||||
// TODO(clemensh): Remove this, use operator== and operator!=.
|
||||
bool is(SubType reg) const { return reg_code_ == reg.reg_code_; }
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code_;
|
||||
}
|
||||
|
||||
int bit() const { return 1 << code(); }
|
||||
|
||||
inline bool operator==(SubType other) const {
|
||||
return reg_code_ == other.reg_code_;
|
||||
}
|
||||
inline bool operator!=(SubType other) const { return !(*this == other); }
|
||||
|
||||
protected:
|
||||
explicit constexpr RegisterBase(int code) : reg_code_(code) {}
|
||||
int reg_code_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
#endif // V8_ASSEMBLER_H_
|
||||
|
@ -643,7 +643,7 @@ void FlushPendingPushRegisters(TurboAssembler* tasm,
|
||||
break;
|
||||
}
|
||||
frame_access_state->IncreaseSPDelta(pending_pushes->size());
|
||||
pending_pushes->resize(0);
|
||||
pending_pushes->clear();
|
||||
}
|
||||
|
||||
void AdjustStackPointerForTailCall(
|
||||
@ -966,12 +966,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kArchStackSlot: {
|
||||
FrameOffset offset =
|
||||
frame_access_state()->GetFrameOffset(i.InputInt32(0));
|
||||
Register base;
|
||||
if (offset.from_stack_pointer()) {
|
||||
base = sp;
|
||||
} else {
|
||||
base = fp;
|
||||
}
|
||||
Register base = offset.from_stack_pointer() ? sp : fp;
|
||||
__ add(i.OutputRegister(0), base, Operand(offset.offset()));
|
||||
break;
|
||||
}
|
||||
@ -2811,7 +2806,7 @@ void CodeGenerator::FinishFrame(Frame* frame) {
|
||||
|
||||
if (saves_fp != 0) {
|
||||
// Save callee-saved FP registers.
|
||||
STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
|
||||
STATIC_ASSERT(DwVfpRegister::kNumRegisters == 32);
|
||||
uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
|
||||
uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
|
||||
DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
|
||||
@ -2908,7 +2903,7 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
|
||||
if (saves_fp != 0) {
|
||||
// Save callee-saved FP registers.
|
||||
STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
|
||||
STATIC_ASSERT(DwVfpRegister::kNumRegisters == 32);
|
||||
uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
|
||||
uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
|
||||
DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
|
||||
@ -2935,7 +2930,7 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
|
||||
// Restore FP registers.
|
||||
const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
|
||||
if (saves_fp != 0) {
|
||||
STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
|
||||
STATIC_ASSERT(DwVfpRegister::kNumRegisters == 32);
|
||||
uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
|
||||
uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
|
||||
__ vldm(ia_w, sp, DwVfpRegister::from_code(first),
|
||||
|
@ -977,12 +977,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kArchStackSlot: {
|
||||
FrameOffset offset =
|
||||
frame_access_state()->GetFrameOffset(i.InputInt32(0));
|
||||
Register base;
|
||||
if (offset.from_stack_pointer()) {
|
||||
base = __ StackPointer();
|
||||
} else {
|
||||
base = fp;
|
||||
}
|
||||
Register base = offset.from_stack_pointer() ? __ StackPointer() : fp;
|
||||
__ Add(i.OutputRegister(0), base, Operand(offset.offset()));
|
||||
break;
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
|
||||
RelocInfo::Mode rmode_buffer) \
|
||||
: OutOfLineCode(gen), \
|
||||
result_(result), \
|
||||
buffer_reg_({-1}), \
|
||||
buffer_reg_(no_reg), \
|
||||
buffer_int_(buffer), \
|
||||
index1_(index1), \
|
||||
index2_(index2), \
|
||||
@ -479,7 +479,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
|
||||
RelocInfo::Mode rmode_buffer) \
|
||||
: OutOfLineCode(gen), \
|
||||
result_(result), \
|
||||
buffer_reg_({-1}), \
|
||||
buffer_reg_(no_reg), \
|
||||
buffer_int_(buffer), \
|
||||
index1_(index1), \
|
||||
index2_(index2), \
|
||||
@ -582,7 +582,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
|
||||
XMMRegister value, RelocInfo::Mode rmode_length, \
|
||||
RelocInfo::Mode rmode_buffer) \
|
||||
: OutOfLineCode(gen), \
|
||||
buffer_reg_({-1}), \
|
||||
buffer_reg_(no_reg), \
|
||||
buffer_int_(buffer), \
|
||||
index1_(index1), \
|
||||
index2_(index2), \
|
||||
@ -681,7 +681,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
|
||||
Value value, RelocInfo::Mode rmode_length, \
|
||||
RelocInfo::Mode rmode_buffer) \
|
||||
: OutOfLineCode(gen), \
|
||||
buffer_reg_({-1}), \
|
||||
buffer_reg_(no_reg), \
|
||||
buffer_int_(buffer), \
|
||||
index1_(index1), \
|
||||
index2_(index2), \
|
||||
@ -1173,12 +1173,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kArchStackSlot: {
|
||||
FrameOffset offset =
|
||||
frame_access_state()->GetFrameOffset(i.InputInt32(0));
|
||||
Register base;
|
||||
if (offset.from_stack_pointer()) {
|
||||
base = esp;
|
||||
} else {
|
||||
base = ebp;
|
||||
}
|
||||
Register base = offset.from_stack_pointer() ? esp : ebp;
|
||||
__ lea(i.OutputRegister(), Operand(base, offset.offset()));
|
||||
break;
|
||||
}
|
||||
@ -2020,7 +2015,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIA32I32x4Neg: {
|
||||
XMMRegister dst = i.OutputSimd128Register();
|
||||
Operand src = i.InputOperand(0);
|
||||
Register ireg = {dst.code()};
|
||||
Register ireg = Register::from_code(dst.code());
|
||||
if (src.is_reg(ireg)) {
|
||||
__ Pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
|
||||
__ Psignd(dst, kScratchDoubleReg);
|
||||
|
@ -1104,12 +1104,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kArchStackSlot: {
|
||||
FrameOffset offset =
|
||||
frame_access_state()->GetFrameOffset(i.InputInt32(0));
|
||||
Register base;
|
||||
if (offset.from_stack_pointer()) {
|
||||
base = rsp;
|
||||
} else {
|
||||
base = rbp;
|
||||
}
|
||||
Register base = offset.from_stack_pointer() ? rsp : rbp;
|
||||
__ leaq(i.OutputRegister(), Operand(base, offset.offset()));
|
||||
break;
|
||||
}
|
||||
@ -3123,7 +3118,7 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
__ subp(rsp, Immediate(stack_size));
|
||||
// Store the registers on the stack.
|
||||
int slot_idx = 0;
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
if (!((1 << i) & saves_fp)) continue;
|
||||
__ movdqu(Operand(rsp, kQuadWordSize * slot_idx),
|
||||
XMMRegister::from_code(i));
|
||||
@ -3157,7 +3152,7 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
|
||||
const int stack_size = saves_fp_count * kQuadWordSize;
|
||||
// Load the registers from the stack.
|
||||
int slot_idx = 0;
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
if (!((1 << i) & saves_fp)) continue;
|
||||
__ movdqu(XMMRegister::from_code(i),
|
||||
Operand(rsp, kQuadWordSize * slot_idx));
|
||||
|
@ -634,8 +634,8 @@ class RegisterValues {
|
||||
static_assert(sizeof(Float64) == kDoubleSize, "size mismatch");
|
||||
|
||||
intptr_t registers_[Register::kNumRegisters];
|
||||
Float32 float_registers_[FloatRegister::kMaxNumRegisters];
|
||||
Float64 double_registers_[DoubleRegister::kMaxNumRegisters];
|
||||
Float32 float_registers_[FloatRegister::kNumRegisters];
|
||||
Float64 double_registers_[DoubleRegister::kNumRegisters];
|
||||
};
|
||||
|
||||
|
||||
|
@ -390,7 +390,7 @@ Operand::Operand(Register reg) {
|
||||
|
||||
|
||||
Operand::Operand(XMMRegister xmm_reg) {
|
||||
Register reg = { xmm_reg.code() };
|
||||
Register reg = Register::from_code(xmm_reg.code());
|
||||
set_modrm(3, reg);
|
||||
}
|
||||
|
||||
|
@ -2971,37 +2971,37 @@ void Assembler::vcmpps(XMMRegister dst, XMMRegister src1, const Operand& src2,
|
||||
}
|
||||
|
||||
void Assembler::vpsllw(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {6};
|
||||
XMMRegister iop = XMMRegister::from_code(6);
|
||||
vinstr(0x71, iop, dst, Operand(src), k66, k0F, kWIG);
|
||||
EMIT(imm8);
|
||||
}
|
||||
|
||||
void Assembler::vpslld(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {6};
|
||||
XMMRegister iop = XMMRegister::from_code(6);
|
||||
vinstr(0x72, iop, dst, Operand(src), k66, k0F, kWIG);
|
||||
EMIT(imm8);
|
||||
}
|
||||
|
||||
void Assembler::vpsrlw(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {2};
|
||||
XMMRegister iop = XMMRegister::from_code(2);
|
||||
vinstr(0x71, iop, dst, Operand(src), k66, k0F, kWIG);
|
||||
EMIT(imm8);
|
||||
}
|
||||
|
||||
void Assembler::vpsrld(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {2};
|
||||
XMMRegister iop = XMMRegister::from_code(2);
|
||||
vinstr(0x72, iop, dst, Operand(src), k66, k0F, kWIG);
|
||||
EMIT(imm8);
|
||||
}
|
||||
|
||||
void Assembler::vpsraw(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {4};
|
||||
XMMRegister iop = XMMRegister::from_code(4);
|
||||
vinstr(0x71, iop, dst, Operand(src), k66, k0F, kWIG);
|
||||
EMIT(imm8);
|
||||
}
|
||||
|
||||
void Assembler::vpsrad(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {4};
|
||||
XMMRegister iop = XMMRegister::from_code(4);
|
||||
vinstr(0x72, iop, dst, Operand(src), k66, k0F, kWIG);
|
||||
EMIT(imm8);
|
||||
}
|
||||
@ -3101,7 +3101,7 @@ void Assembler::bmi2(SIMDPrefix pp, byte op, Register reg, Register vreg,
|
||||
void Assembler::rorx(Register dst, const Operand& src, byte imm8) {
|
||||
DCHECK(IsEnabled(BMI2));
|
||||
DCHECK(is_uint8(imm8));
|
||||
Register vreg = {0}; // VEX.vvvv unused
|
||||
Register vreg = Register::from_code<0>(); // VEX.vvvv unused
|
||||
EnsureSpace ensure_space(this);
|
||||
emit_vex_prefix(vreg, kLZ, kF2, k0F3A, kW0);
|
||||
EMIT(0xF0);
|
||||
@ -3151,7 +3151,7 @@ void Assembler::vinstr(byte op, XMMRegister dst, XMMRegister src1,
|
||||
}
|
||||
|
||||
void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
|
||||
Register ireg = { reg.code() };
|
||||
Register ireg = Register::from_code(reg.code());
|
||||
emit_operand(ireg, adr);
|
||||
}
|
||||
|
||||
@ -3187,7 +3187,7 @@ void Assembler::emit_vex_prefix(XMMRegister vreg, VectorLength l, SIMDPrefix pp,
|
||||
|
||||
void Assembler::emit_vex_prefix(Register vreg, VectorLength l, SIMDPrefix pp,
|
||||
LeadingOpcode mm, VexW w) {
|
||||
XMMRegister ivreg = {vreg.code()};
|
||||
XMMRegister ivreg = XMMRegister::from_code(vreg.code());
|
||||
emit_vex_prefix(ivreg, l, pp, mm, w);
|
||||
}
|
||||
|
||||
@ -3255,7 +3255,7 @@ void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) {
|
||||
|
||||
void Assembler::emit_arith(int sel, Operand dst, const Immediate& x) {
|
||||
DCHECK((0 <= sel) && (sel <= 7));
|
||||
Register ireg = { sel };
|
||||
Register ireg = Register::from_code(sel);
|
||||
if (x.is_int8()) {
|
||||
EMIT(0x83); // using a sign-extended 8-bit immediate.
|
||||
emit_operand(ireg, dst);
|
||||
|
@ -103,95 +103,45 @@ const int kNumJSCallerSaved = 5;
|
||||
// Number of registers for which space is reserved in safepoints.
|
||||
const int kNumSafepointRegisters = 8;
|
||||
|
||||
// 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.
|
||||
//
|
||||
struct Register {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static constexpr int kNumRegisters = Code::kAfterLast;
|
||||
|
||||
static Register from_code(int code) {
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kNumRegisters);
|
||||
Register r = {code};
|
||||
return r;
|
||||
}
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
|
||||
bool is(Register reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
bool is_byte_register() const { return reg_code <= 3; }
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
#define DEFINE_REGISTER(R) constexpr Register R = {Register::kCode_##R};
|
||||
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) {}
|
||||
};
|
||||
|
||||
static_assert(IS_TRIVIALLY_COPYABLE(Register) &&
|
||||
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::kCode_no_reg};
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
struct XMMRegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
enum DoubleCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
static constexpr int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
static XMMRegister from_code(int code) {
|
||||
XMMRegister result = {code};
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
|
||||
bool is(XMMRegister reg) const { return reg_code == reg.reg_code; }
|
||||
|
||||
int reg_code;
|
||||
class XMMRegister : public RegisterBase<XMMRegister, kDoubleAfterLast> {
|
||||
friend class RegisterBase<XMMRegister, kDoubleAfterLast>;
|
||||
explicit constexpr XMMRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
typedef XMMRegister FloatRegister;
|
||||
@ -201,10 +151,10 @@ typedef XMMRegister DoubleRegister;
|
||||
typedef XMMRegister Simd128Register;
|
||||
|
||||
#define DEFINE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = {DoubleRegister::kCode_##R};
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DEFINE_REGISTER)
|
||||
#undef DEFINE_REGISTER
|
||||
constexpr DoubleRegister no_double_reg = {DoubleRegister::kCode_no_reg};
|
||||
constexpr DoubleRegister no_double_reg = DoubleRegister::no_reg();
|
||||
|
||||
enum Condition {
|
||||
// any value < 0 is considered no_condition
|
||||
@ -1490,20 +1440,11 @@ class Assembler : public AssemblerBase {
|
||||
bmi1(0xf7, dst, src2, src1);
|
||||
}
|
||||
void blsi(Register dst, Register src) { blsi(dst, Operand(src)); }
|
||||
void blsi(Register dst, const Operand& src) {
|
||||
Register ireg = {3};
|
||||
bmi1(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsi(Register dst, const Operand& src) { bmi1(0xf3, ebx, dst, src); }
|
||||
void blsmsk(Register dst, Register src) { blsmsk(dst, Operand(src)); }
|
||||
void blsmsk(Register dst, const Operand& src) {
|
||||
Register ireg = {2};
|
||||
bmi1(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsmsk(Register dst, const Operand& src) { bmi1(0xf3, edx, dst, src); }
|
||||
void blsr(Register dst, Register src) { blsr(dst, Operand(src)); }
|
||||
void blsr(Register dst, const Operand& src) {
|
||||
Register ireg = {1};
|
||||
bmi1(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsr(Register dst, const Operand& src) { bmi1(0xf3, ecx, dst, src); }
|
||||
void tzcnt(Register dst, Register src) { tzcnt(dst, Operand(src)); }
|
||||
void tzcnt(Register dst, const Operand& src);
|
||||
|
||||
|
@ -43,8 +43,8 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
|
||||
// restore them.
|
||||
__ pushad();
|
||||
if (save_doubles()) {
|
||||
__ sub(esp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters));
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
__ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
XMMRegister reg = XMMRegister::from_code(i);
|
||||
__ movsd(Operand(esp, i * kDoubleSize), reg);
|
||||
}
|
||||
@ -59,11 +59,11 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
|
||||
ExternalReference::store_buffer_overflow_function(isolate()),
|
||||
argument_count);
|
||||
if (save_doubles()) {
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
XMMRegister reg = XMMRegister::from_code(i);
|
||||
__ movsd(reg, Operand(esp, i * kDoubleSize));
|
||||
}
|
||||
__ add(esp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters));
|
||||
__ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
|
||||
}
|
||||
__ popad();
|
||||
__ ret(0);
|
||||
@ -114,7 +114,7 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
|
||||
MemOperand exponent_operand(MemOperand(input_reg,
|
||||
double_offset + kDoubleSize / 2));
|
||||
|
||||
Register scratch1;
|
||||
Register scratch1 = no_reg;
|
||||
{
|
||||
Register scratch_candidates[3] = { ebx, edx, edi };
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
@ -176,15 +176,14 @@ class RecordWriteStub: public PlatformCodeStub {
|
||||
// that must be preserved and one scratch register provided by the caller.
|
||||
class RegisterAllocation {
|
||||
public:
|
||||
RegisterAllocation(Register object,
|
||||
Register address,
|
||||
Register scratch0)
|
||||
RegisterAllocation(Register object, Register address, Register scratch0)
|
||||
: object_orig_(object),
|
||||
address_orig_(address),
|
||||
scratch0_orig_(scratch0),
|
||||
object_(object),
|
||||
address_(address),
|
||||
scratch0_(scratch0) {
|
||||
scratch0_(scratch0),
|
||||
scratch1_(no_reg) {
|
||||
DCHECK(!AreAliased(scratch0, object, address, no_reg));
|
||||
scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
|
||||
if (scratch0.is(ecx)) {
|
||||
|
@ -23,7 +23,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
// Save all general purpose registers before messing with them.
|
||||
const int kNumberOfRegisters = Register::kNumRegisters;
|
||||
|
||||
const int kDoubleRegsSize = kDoubleSize * XMMRegister::kMaxNumRegisters;
|
||||
const int kDoubleRegsSize = kDoubleSize * XMMRegister::kNumRegisters;
|
||||
__ sub(esp, Immediate(kDoubleRegsSize));
|
||||
const RegisterConfiguration* config = RegisterConfiguration::Default();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
@ -34,7 +34,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
}
|
||||
|
||||
STATIC_ASSERT(kFloatSize == kPointerSize);
|
||||
const int kFloatRegsSize = kFloatSize * XMMRegister::kMaxNumRegisters;
|
||||
const int kFloatRegsSize = kFloatSize * XMMRegister::kNumRegisters;
|
||||
__ sub(esp, Immediate(kFloatRegsSize));
|
||||
for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
|
||||
int code = config->GetAllocatableFloatCode(i);
|
||||
@ -95,7 +95,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
|
||||
int float_regs_offset = FrameDescription::float_registers_offset();
|
||||
// Fill in the float input registers.
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
int dst_offset = i * kFloatSize + float_regs_offset;
|
||||
__ pop(Operand(ebx, dst_offset));
|
||||
}
|
||||
|
@ -90,14 +90,9 @@ void MacroAssembler::PushRoot(Heap::RootListIndex index) {
|
||||
}
|
||||
}
|
||||
|
||||
#define REG(Name) \
|
||||
{ Register::kCode_##Name }
|
||||
static constexpr Register saved_regs[] = {eax, ecx, edx};
|
||||
|
||||
static const Register saved_regs[] = {REG(eax), REG(ecx), REG(edx)};
|
||||
|
||||
#undef REG
|
||||
|
||||
static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
|
||||
static constexpr int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
|
||||
|
||||
int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
|
||||
Register exclusion1,
|
||||
@ -113,7 +108,7 @@ int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
|
||||
|
||||
if (fp_mode == kSaveFPRegs) {
|
||||
// Count all XMM registers except XMM0.
|
||||
bytes += kDoubleSize * (XMMRegister::kMaxNumRegisters - 1);
|
||||
bytes += kDoubleSize * (XMMRegister::kNumRegisters - 1);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
@ -135,9 +130,9 @@ int TurboAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
|
||||
|
||||
if (fp_mode == kSaveFPRegs) {
|
||||
// Save all XMM registers except XMM0.
|
||||
int delta = kDoubleSize * (XMMRegister::kMaxNumRegisters - 1);
|
||||
int delta = kDoubleSize * (XMMRegister::kNumRegisters - 1);
|
||||
sub(esp, Immediate(delta));
|
||||
for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) {
|
||||
for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
|
||||
XMMRegister reg = XMMRegister::from_code(i);
|
||||
movsd(Operand(esp, (i - 1) * kDoubleSize), reg);
|
||||
}
|
||||
@ -152,8 +147,8 @@ int TurboAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
|
||||
int bytes = 0;
|
||||
if (fp_mode == kSaveFPRegs) {
|
||||
// Restore all XMM registers except XMM0.
|
||||
int delta = kDoubleSize * (XMMRegister::kMaxNumRegisters - 1);
|
||||
for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) {
|
||||
int delta = kDoubleSize * (XMMRegister::kNumRegisters - 1);
|
||||
for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
|
||||
XMMRegister reg = XMMRegister::from_code(i);
|
||||
movsd(reg, Operand(esp, (i - 1) * kDoubleSize));
|
||||
}
|
||||
@ -748,11 +743,10 @@ void MacroAssembler::EnterExitFramePrologue(StackFrame::Type frame_type) {
|
||||
void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
|
||||
// Optionally save all XMM registers.
|
||||
if (save_doubles) {
|
||||
int space = XMMRegister::kMaxNumRegisters * kDoubleSize +
|
||||
argc * kPointerSize;
|
||||
int space = XMMRegister::kNumRegisters * kDoubleSize + argc * kPointerSize;
|
||||
sub(esp, Immediate(space));
|
||||
const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
XMMRegister reg = XMMRegister::from_code(i);
|
||||
movsd(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg);
|
||||
}
|
||||
@ -795,7 +789,7 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) {
|
||||
// Optionally restore all XMM registers.
|
||||
if (save_doubles) {
|
||||
const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
XMMRegister reg = XMMRegister::from_code(i);
|
||||
movsd(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize)));
|
||||
}
|
||||
|
@ -20,11 +20,13 @@ class AccessCompilerData {
|
||||
bool IsInitialized() const { return load_calling_convention_ != nullptr; }
|
||||
void Initialize(int load_register_count, const Register* load_registers,
|
||||
int store_register_count, const Register* store_registers) {
|
||||
load_calling_convention_.reset(NewArray<Register>(load_register_count));
|
||||
load_calling_convention_.reset(
|
||||
NewArray<Register>(load_register_count, no_reg));
|
||||
for (int i = 0; i < load_register_count; ++i) {
|
||||
load_calling_convention_[i] = load_registers[i];
|
||||
}
|
||||
store_calling_convention_.reset(NewArray<Register>(store_register_count));
|
||||
store_calling_convention_.reset(
|
||||
NewArray<Register>(store_register_count, no_reg));
|
||||
for (int i = 0; i < store_register_count; ++i) {
|
||||
store_calling_convention_[i] = store_registers[i];
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ void CallInterfaceDescriptorData::InitializePlatformSpecific(
|
||||
register_param_count_ = register_parameter_count;
|
||||
|
||||
// InterfaceDescriptor owns a copy of the registers array.
|
||||
register_params_.reset(NewArray<Register>(register_parameter_count));
|
||||
register_params_.reset(NewArray<Register>(register_parameter_count, no_reg));
|
||||
for (int i = 0; i < register_parameter_count; i++) {
|
||||
register_params_[i] = registers[i];
|
||||
}
|
||||
|
@ -54,31 +54,21 @@ bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(MIPS_SIMD); }
|
||||
// -----------------------------------------------------------------------------
|
||||
// Operand and MemOperand.
|
||||
|
||||
Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(int32_t immediate, RelocInfo::Mode rmode)
|
||||
: rm_(no_reg), rmode_(rmode) {
|
||||
value_.immediate = immediate;
|
||||
rmode_ = rmode;
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(const ExternalReference& f) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(const ExternalReference& f)
|
||||
: rm_(no_reg), rmode_(RelocInfo::EXTERNAL_REFERENCE) {
|
||||
value_.immediate = reinterpret_cast<int32_t>(f.address());
|
||||
rmode_ = RelocInfo::EXTERNAL_REFERENCE;
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(Smi* value) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(Smi* value) : rm_(no_reg), rmode_(RelocInfo::NONE32) {
|
||||
value_.immediate = reinterpret_cast<intptr_t>(value);
|
||||
rmode_ = RelocInfo::NONE32;
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(Register rm) {
|
||||
rm_ = rm;
|
||||
}
|
||||
|
||||
Operand::Operand(Register rm) : rm_(rm) {}
|
||||
|
||||
bool Operand::is_reg() const {
|
||||
return rm_.is_valid();
|
||||
|
@ -214,10 +214,9 @@ void RelocInfo::set_embedded_size(Isolate* isolate, uint32_t size,
|
||||
// Implementation of Operand and MemOperand.
|
||||
// See assembler-mips-inl.h for inlined constructors.
|
||||
|
||||
Operand::Operand(Handle<HeapObject> handle) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(Handle<HeapObject> handle)
|
||||
: rm_(no_reg), rmode_(RelocInfo::EMBEDDED_OBJECT) {
|
||||
value_.immediate = reinterpret_cast<intptr_t>(handle.address());
|
||||
rmode_ = RelocInfo::EMBEDDED_OBJECT;
|
||||
}
|
||||
|
||||
Operand Operand::EmbeddedNumber(double value) {
|
||||
@ -271,31 +270,31 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
|
||||
static const int kNegOffset = 0x00008000;
|
||||
// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
|
||||
// operations as post-increment of sp.
|
||||
const Instr kPopInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
|
||||
(Register::kCode_sp << kRtShift) |
|
||||
const Instr kPopInstruction = ADDIU | (sp.code() << kRsShift) |
|
||||
(sp.code() << kRtShift) |
|
||||
(kPointerSize & kImm16Mask); // NOLINT
|
||||
// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
|
||||
const Instr kPushInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
|
||||
(Register::kCode_sp << kRtShift) |
|
||||
const Instr kPushInstruction = ADDIU | (sp.code() << kRsShift) |
|
||||
(sp.code() << kRtShift) |
|
||||
(-kPointerSize & kImm16Mask); // NOLINT
|
||||
// sw(r, MemOperand(sp, 0))
|
||||
const Instr kPushRegPattern =
|
||||
SW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
SW | (sp.code() << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
// lw(r, MemOperand(sp, 0))
|
||||
const Instr kPopRegPattern =
|
||||
LW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
LW | (sp.code() << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kLwRegFpOffsetPattern =
|
||||
LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
LW | (fp.code() << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kSwRegFpOffsetPattern =
|
||||
SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
SW | (fp.code() << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
|
||||
(kNegOffset & kImm16Mask); // NOLINT
|
||||
const Instr kLwRegFpNegOffsetPattern =
|
||||
LW | (fp.code() << kRsShift) | (kNegOffset & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
|
||||
(kNegOffset & kImm16Mask); // NOLINT
|
||||
const Instr kSwRegFpNegOffsetPattern =
|
||||
SW | (fp.code() << kRsShift) | (kNegOffset & kImm16Mask); // NOLINT
|
||||
// A mask for the Rt register for push, pop, lw, sw instructions.
|
||||
const Instr kRtMask = kRtFieldMask;
|
||||
const Instr kLwSwInstrTypeMask = 0xffe00000;
|
||||
@ -357,23 +356,17 @@ void Assembler::CodeTargetAlign() {
|
||||
|
||||
|
||||
Register Assembler::GetRtReg(Instr instr) {
|
||||
Register rt;
|
||||
rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
|
||||
return rt;
|
||||
return Register::from_code((instr & kRtFieldMask) >> kRtShift);
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRsReg(Instr instr) {
|
||||
Register rs;
|
||||
rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
|
||||
return rs;
|
||||
return Register::from_code((instr & kRsFieldMask) >> kRsShift);
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRdReg(Instr instr) {
|
||||
Register rd;
|
||||
rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
|
||||
return rd;
|
||||
return Register::from_code((instr & kRdFieldMask) >> kRdShift);
|
||||
}
|
||||
|
||||
|
||||
@ -2357,15 +2350,13 @@ void Assembler::movn(Register rd, Register rs, Register rt) {
|
||||
|
||||
|
||||
void Assembler::movt(Register rd, Register rs, uint16_t cc) {
|
||||
Register rt;
|
||||
rt.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
Register rt = Register::from_code((cc & 0x0007) << 2 | 1);
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movf(Register rd, Register rs, uint16_t cc) {
|
||||
Register rt;
|
||||
rt.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
Register rt = Register::from_code((cc & 0x0007) << 2 | 0);
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
|
||||
}
|
||||
|
||||
@ -2584,32 +2575,28 @@ void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
|
||||
|
||||
void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(!IsMipsArchVariant(kMips32r6));
|
||||
FPURegister ft;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
FPURegister ft = FPURegister::from_code((cc & 0x0007) << 2 | 1);
|
||||
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(!IsMipsArchVariant(kMips32r6));
|
||||
FPURegister ft;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
FPURegister ft = FPURegister::from_code((cc & 0x0007) << 2 | 1);
|
||||
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(!IsMipsArchVariant(kMips32r6));
|
||||
FPURegister ft;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
FPURegister ft = FPURegister::from_code((cc & 0x0007) << 2 | 0);
|
||||
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(!IsMipsArchVariant(kMips32r6));
|
||||
FPURegister ft;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
FPURegister ft = FPURegister::from_code((cc & 0x0007) << 2 | 0);
|
||||
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
@ -200,17 +200,15 @@ const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register and FPURegister.
|
||||
|
||||
struct Register {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static constexpr int kNumRegisters = Code::kAfterLast;
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
class Register : public RegisterBase<Register, kRegAfterLast> {
|
||||
public:
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
static constexpr int kMantissaOffset = 0;
|
||||
static constexpr int kExponentOffset = 4;
|
||||
@ -221,34 +219,19 @@ struct Register {
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
|
||||
|
||||
static Register from_code(int code) {
|
||||
DCHECK_LE(0, code);
|
||||
DCHECK_GT(kNumRegisters, code);
|
||||
return Register{code};
|
||||
}
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
|
||||
bool is(Register reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// s7: context register
|
||||
// s3: lithium scratch
|
||||
// s4: lithium scratch2
|
||||
#define DECLARE_REGISTER(R) constexpr Register R = {Register::kCode_##R};
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr Register no_reg = {Register::kCode_no_reg};
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
int ToNumber(Register reg);
|
||||
|
||||
@ -257,100 +240,43 @@ Register ToRegister(int num);
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
// Coprocessor register.
|
||||
struct FPURegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = kInvalidFPURegister
|
||||
};
|
||||
kDoubleAfterLast
|
||||
};
|
||||
|
||||
static constexpr int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
inline static int NumRegisters();
|
||||
|
||||
// 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).
|
||||
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(FPURegister reg) const { return reg_code == reg.reg_code; }
|
||||
// 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(reg_code % 2 == 0); // Specified Double reg must be even.
|
||||
FPURegister reg;
|
||||
reg.reg_code = reg_code;
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
DCHECK(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(reg_code % 2 == 0); // Specified Double reg must be even.
|
||||
FPURegister reg;
|
||||
reg.reg_code = reg_code + 1;
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
DCHECK(code() % 2 == 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code() + 1);
|
||||
}
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr FPURegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
static FPURegister from_code(int code) {
|
||||
FPURegister r = {code};
|
||||
return r;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
enum MSARegisterCode {
|
||||
#define REGISTER_CODE(R) kMsaCode_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kMsaAfterLast
|
||||
};
|
||||
|
||||
// MIPS SIMD (MSA) register
|
||||
struct MSARegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = kInvalidMSARegister
|
||||
};
|
||||
|
||||
static const int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
inline static int NumRegisters();
|
||||
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(MSARegister reg) const { return reg_code == reg.reg_code; }
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
static MSARegister from_code(int code) {
|
||||
MSARegister r = {code};
|
||||
return r;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
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
|
||||
@ -371,78 +297,22 @@ typedef FPURegister FloatRegister;
|
||||
|
||||
typedef FPURegister DoubleRegister;
|
||||
|
||||
constexpr DoubleRegister no_freg = {kInvalidFPURegister};
|
||||
#define DECLARE_DOUBLE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
|
||||
#undef DECLARE_DOUBLE_REGISTER
|
||||
|
||||
constexpr DoubleRegister f0 = {0}; // Return value in hard float mode.
|
||||
constexpr DoubleRegister f1 = {1};
|
||||
constexpr DoubleRegister f2 = {2};
|
||||
constexpr DoubleRegister f3 = {3};
|
||||
constexpr DoubleRegister f4 = {4};
|
||||
constexpr DoubleRegister f5 = {5};
|
||||
constexpr DoubleRegister f6 = {6};
|
||||
constexpr DoubleRegister f7 = {7};
|
||||
constexpr DoubleRegister f8 = {8};
|
||||
constexpr DoubleRegister f9 = {9};
|
||||
constexpr DoubleRegister f10 = {10};
|
||||
constexpr DoubleRegister f11 = {11};
|
||||
constexpr DoubleRegister f12 = {12}; // Arg 0 in hard float mode.
|
||||
constexpr DoubleRegister f13 = {13};
|
||||
constexpr DoubleRegister f14 = {14}; // Arg 1 in hard float mode.
|
||||
constexpr DoubleRegister f15 = {15};
|
||||
constexpr DoubleRegister f16 = {16};
|
||||
constexpr DoubleRegister f17 = {17};
|
||||
constexpr DoubleRegister f18 = {18};
|
||||
constexpr DoubleRegister f19 = {19};
|
||||
constexpr DoubleRegister f20 = {20};
|
||||
constexpr DoubleRegister f21 = {21};
|
||||
constexpr DoubleRegister f22 = {22};
|
||||
constexpr DoubleRegister f23 = {23};
|
||||
constexpr DoubleRegister f24 = {24};
|
||||
constexpr DoubleRegister f25 = {25};
|
||||
constexpr DoubleRegister f26 = {26};
|
||||
constexpr DoubleRegister f27 = {27};
|
||||
constexpr DoubleRegister f28 = {28};
|
||||
constexpr DoubleRegister f29 = {29};
|
||||
constexpr DoubleRegister f30 = {30};
|
||||
constexpr DoubleRegister f31 = {31};
|
||||
constexpr DoubleRegister no_freg = DoubleRegister::no_reg();
|
||||
|
||||
// SIMD registers.
|
||||
typedef MSARegister Simd128Register;
|
||||
|
||||
const Simd128Register no_msareg = {kInvalidMSARegister};
|
||||
#define DECLARE_SIMD128_REGISTER(R) \
|
||||
constexpr Simd128Register R = Simd128Register::from_code<kMsaCode_##R>();
|
||||
SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
|
||||
#undef DECLARE_SIMD128_REGISTER
|
||||
|
||||
constexpr Simd128Register w0 = {0};
|
||||
constexpr Simd128Register w1 = {1};
|
||||
constexpr Simd128Register w2 = {2};
|
||||
constexpr Simd128Register w3 = {3};
|
||||
constexpr Simd128Register w4 = {4};
|
||||
constexpr Simd128Register w5 = {5};
|
||||
constexpr Simd128Register w6 = {6};
|
||||
constexpr Simd128Register w7 = {7};
|
||||
constexpr Simd128Register w8 = {8};
|
||||
constexpr Simd128Register w9 = {9};
|
||||
constexpr Simd128Register w10 = {10};
|
||||
constexpr Simd128Register w11 = {11};
|
||||
constexpr Simd128Register w12 = {12};
|
||||
constexpr Simd128Register w13 = {13};
|
||||
constexpr Simd128Register w14 = {14};
|
||||
constexpr Simd128Register w15 = {15};
|
||||
constexpr Simd128Register w16 = {16};
|
||||
constexpr Simd128Register w17 = {17};
|
||||
constexpr Simd128Register w18 = {18};
|
||||
constexpr Simd128Register w19 = {19};
|
||||
constexpr Simd128Register w20 = {20};
|
||||
constexpr Simd128Register w21 = {21};
|
||||
constexpr Simd128Register w22 = {22};
|
||||
constexpr Simd128Register w23 = {23};
|
||||
constexpr Simd128Register w24 = {24};
|
||||
constexpr Simd128Register w25 = {25};
|
||||
constexpr Simd128Register w26 = {26};
|
||||
constexpr Simd128Register w27 = {27};
|
||||
constexpr Simd128Register w28 = {28};
|
||||
constexpr Simd128Register w29 = {29};
|
||||
constexpr Simd128Register w30 = {30};
|
||||
constexpr Simd128Register w31 = {31};
|
||||
const Simd128Register no_msareg = Simd128Register::no_reg();
|
||||
|
||||
// Register aliases.
|
||||
// cp is assumed to be a callee saved register.
|
||||
|
@ -515,14 +515,11 @@ void CEntryStub::Generate(MacroAssembler* masm) {
|
||||
// v0:v1: result
|
||||
// sp: stack pointer
|
||||
// fp: frame pointer
|
||||
Register argc;
|
||||
if (argv_in_register()) {
|
||||
// We don't want to pop arguments so set argc to no_reg.
|
||||
argc = no_reg;
|
||||
} else {
|
||||
// s0: still holds argc (callee-saved).
|
||||
argc = s0;
|
||||
}
|
||||
Register argc = argv_in_register()
|
||||
// We don't want to pop arguments so set argc to no_reg.
|
||||
? no_reg
|
||||
// s0: still holds argc (callee-saved).
|
||||
: s0;
|
||||
__ LeaveExitFrame(save_doubles(), argc, true, EMIT_RETURN);
|
||||
|
||||
// Handling of exception.
|
||||
|
@ -155,12 +155,11 @@ class RecordWriteStub: public PlatformCodeStub {
|
||||
// the caller.
|
||||
class RegisterAllocation {
|
||||
public:
|
||||
RegisterAllocation(Register object,
|
||||
Register address,
|
||||
Register scratch0)
|
||||
RegisterAllocation(Register object, Register address, Register scratch0)
|
||||
: object_(object),
|
||||
address_(address),
|
||||
scratch0_(scratch0) {
|
||||
scratch0_(scratch0),
|
||||
scratch1_(no_reg) {
|
||||
DCHECK(!AreAliased(scratch0, object, address, no_reg));
|
||||
scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
RegList restored_regs = kJSCallerSaved | kCalleeSaved;
|
||||
RegList saved_regs = restored_regs | sp.bit() | ra.bit();
|
||||
|
||||
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kMaxNumRegisters;
|
||||
const int kFloatRegsSize = kFloatSize * FloatRegister::kMaxNumRegisters;
|
||||
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kNumRegisters;
|
||||
const int kFloatRegsSize = kFloatSize * FloatRegister::kNumRegisters;
|
||||
|
||||
// Save all FPU registers before messing with them.
|
||||
__ Subu(sp, sp, Operand(kDoubleRegsSize));
|
||||
|
@ -544,7 +544,7 @@ void TurboAssembler::Mul(Register rd_hi, Register rd_lo, Register rs,
|
||||
|
||||
void TurboAssembler::Mulu(Register rd_hi, Register rd_lo, Register rs,
|
||||
const Operand& rt) {
|
||||
Register reg;
|
||||
Register reg = no_reg;
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
if (rt.is_reg()) {
|
||||
@ -1246,8 +1246,7 @@ void TurboAssembler::Ldc1(FPURegister fd, const MemOperand& src) {
|
||||
AdjustBaseAndOffset(tmp, OffsetAccessType::TWO_ACCESSES);
|
||||
lwc1(fd, MemOperand(tmp.rm(), tmp.offset() + Register::kMantissaOffset));
|
||||
if (IsFp32Mode()) { // fp32 mode.
|
||||
FPURegister nextfpreg;
|
||||
nextfpreg.setcode(fd.code() + 1);
|
||||
FPURegister nextfpreg = FPURegister::from_code(fd.code() + 1);
|
||||
lwc1(nextfpreg,
|
||||
MemOperand(tmp.rm(), tmp.offset() + Register::kExponentOffset));
|
||||
} else {
|
||||
@ -1270,8 +1269,7 @@ void TurboAssembler::Sdc1(FPURegister fd, const MemOperand& src) {
|
||||
AdjustBaseAndOffset(tmp, OffsetAccessType::TWO_ACCESSES);
|
||||
swc1(fd, MemOperand(tmp.rm(), tmp.offset() + Register::kMantissaOffset));
|
||||
if (IsFp32Mode()) { // fp32 mode.
|
||||
FPURegister nextfpreg;
|
||||
nextfpreg.setcode(fd.code() + 1);
|
||||
FPURegister nextfpreg = FPURegister::from_code(fd.code() + 1);
|
||||
swc1(nextfpreg,
|
||||
MemOperand(tmp.rm(), tmp.offset() + Register::kExponentOffset));
|
||||
} else {
|
||||
@ -2673,7 +2671,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
bc(offset);
|
||||
break;
|
||||
case eq:
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
// Pre R6 beq is used here to make the code patchable. Otherwise bc
|
||||
// should be used which has no condition field so is not patchable.
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -2691,7 +2689,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
}
|
||||
break;
|
||||
case ne:
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
// Pre R6 bne is used here to make the code patchable. Otherwise we
|
||||
// should not generate any instruction.
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -2712,7 +2710,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
// Signed comparison.
|
||||
case greater:
|
||||
// rs > rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -2730,7 +2728,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case greater_equal:
|
||||
// rs >= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
bc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -2749,7 +2747,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case less:
|
||||
// rs < rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -2767,7 +2765,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case less_equal:
|
||||
// rs <= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
bc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -2788,7 +2786,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
// Unsigned comparison.
|
||||
case Ugreater:
|
||||
// rs > rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset21, scratch, rt))
|
||||
@ -2806,7 +2804,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case Ugreater_equal:
|
||||
// rs >= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
bc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -2825,7 +2823,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case Uless:
|
||||
// rs < rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset21, scratch, rt))
|
||||
@ -2842,7 +2840,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case Uless_equal:
|
||||
// rs <= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
bc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -3153,7 +3151,7 @@ bool TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
|
||||
// Signed comparison.
|
||||
case greater:
|
||||
// rs > rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -3171,7 +3169,7 @@ bool TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case greater_equal:
|
||||
// rs >= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
balc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -3190,7 +3188,7 @@ bool TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case less:
|
||||
// rs < rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -3208,7 +3206,7 @@ bool TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case less_equal:
|
||||
// rs <= r2
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
balc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -4964,10 +4962,10 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
|
||||
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
|
||||
And(sp, sp, Operand(-frame_alignment)); // Align stack.
|
||||
}
|
||||
int space = FPURegister::kMaxNumRegisters * kDoubleSize;
|
||||
int space = FPURegister::kNumRegisters * kDoubleSize;
|
||||
Subu(sp, sp, Operand(space));
|
||||
// Remember: we only need to save every 2nd double FPU value.
|
||||
for (int i = 0; i < FPURegister::kMaxNumRegisters; i+=2) {
|
||||
for (int i = 0; i < FPURegister::kNumRegisters; i += 2) {
|
||||
FPURegister reg = FPURegister::from_code(i);
|
||||
Sdc1(reg, MemOperand(sp, i * kDoubleSize));
|
||||
}
|
||||
@ -4999,7 +4997,7 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
|
||||
if (save_doubles) {
|
||||
// Remember: we only need to restore every 2nd double FPU value.
|
||||
lw(t8, MemOperand(fp, ExitFrameConstants::kSPOffset));
|
||||
for (int i = 0; i < FPURegister::kMaxNumRegisters; i+=2) {
|
||||
for (int i = 0; i < FPURegister::kNumRegisters; i += 2) {
|
||||
FPURegister reg = FPURegister::from_code(i);
|
||||
Ldc1(reg, MemOperand(t8, i * kDoubleSize + kPointerSize));
|
||||
}
|
||||
|
@ -54,31 +54,21 @@ bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(MIPS_SIMD); }
|
||||
// -----------------------------------------------------------------------------
|
||||
// Operand and MemOperand.
|
||||
|
||||
Operand::Operand(int64_t immediate, RelocInfo::Mode rmode) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(int64_t immediate, RelocInfo::Mode rmode)
|
||||
: rm_(no_reg), rmode_(rmode) {
|
||||
value_.immediate = immediate;
|
||||
rmode_ = rmode;
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(const ExternalReference& f) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(const ExternalReference& f)
|
||||
: rm_(no_reg), rmode_(RelocInfo::EXTERNAL_REFERENCE) {
|
||||
value_.immediate = reinterpret_cast<int64_t>(f.address());
|
||||
rmode_ = RelocInfo::EXTERNAL_REFERENCE;
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(Smi* value) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(Smi* value) : rm_(no_reg), rmode_(RelocInfo::NONE32) {
|
||||
value_.immediate = reinterpret_cast<intptr_t>(value);
|
||||
rmode_ = RelocInfo::NONE32;
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(Register rm) {
|
||||
rm_ = rm;
|
||||
}
|
||||
|
||||
Operand::Operand(Register rm) : rm_(rm) {}
|
||||
|
||||
bool Operand::is_reg() const {
|
||||
return rm_.is_valid();
|
||||
|
@ -193,10 +193,9 @@ void RelocInfo::set_embedded_size(Isolate* isolate, uint32_t size,
|
||||
// Implementation of Operand and MemOperand.
|
||||
// See assembler-mips-inl.h for inlined constructors.
|
||||
|
||||
Operand::Operand(Handle<HeapObject> handle) {
|
||||
rm_ = no_reg;
|
||||
Operand::Operand(Handle<HeapObject> handle)
|
||||
: rm_(no_reg), rmode_(RelocInfo::EMBEDDED_OBJECT) {
|
||||
value_.immediate = reinterpret_cast<intptr_t>(handle.address());
|
||||
rmode_ = RelocInfo::EMBEDDED_OBJECT;
|
||||
}
|
||||
|
||||
Operand Operand::EmbeddedNumber(double value) {
|
||||
@ -250,31 +249,31 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
|
||||
|
||||
// daddiu(sp, sp, 8) aka Pop() operation or part of Pop(r)
|
||||
// operations as post-increment of sp.
|
||||
const Instr kPopInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
|
||||
(Register::kCode_sp << kRtShift) |
|
||||
const Instr kPopInstruction = DADDIU | (sp.code() << kRsShift) |
|
||||
(sp.code() << kRtShift) |
|
||||
(kPointerSize & kImm16Mask); // NOLINT
|
||||
// daddiu(sp, sp, -8) part of Push(r) operation as pre-decrement of sp.
|
||||
const Instr kPushInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
|
||||
(Register::kCode_sp << kRtShift) |
|
||||
const Instr kPushInstruction = DADDIU | (sp.code() << kRsShift) |
|
||||
(sp.code() << kRtShift) |
|
||||
(-kPointerSize & kImm16Mask); // NOLINT
|
||||
// Sd(r, MemOperand(sp, 0))
|
||||
const Instr kPushRegPattern =
|
||||
SD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
SD | (sp.code() << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
// Ld(r, MemOperand(sp, 0))
|
||||
const Instr kPopRegPattern =
|
||||
LD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
LD | (sp.code() << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kLwRegFpOffsetPattern =
|
||||
LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
LW | (fp.code() << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kSwRegFpOffsetPattern =
|
||||
SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
SW | (fp.code() << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
|
||||
(kNegOffset & kImm16Mask); // NOLINT
|
||||
const Instr kLwRegFpNegOffsetPattern =
|
||||
LW | (fp.code() << kRsShift) | (kNegOffset & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
|
||||
(kNegOffset & kImm16Mask); // NOLINT
|
||||
const Instr kSwRegFpNegOffsetPattern =
|
||||
SW | (fp.code() << kRsShift) | (kNegOffset & kImm16Mask); // NOLINT
|
||||
// A mask for the Rt register for push, pop, lw, sw instructions.
|
||||
const Instr kRtMask = kRtFieldMask;
|
||||
const Instr kLwSwInstrTypeMask = 0xffe00000;
|
||||
@ -337,23 +336,17 @@ void Assembler::CodeTargetAlign() {
|
||||
|
||||
|
||||
Register Assembler::GetRtReg(Instr instr) {
|
||||
Register rt;
|
||||
rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
|
||||
return rt;
|
||||
return Register::from_code((instr & kRtFieldMask) >> kRtShift);
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRsReg(Instr instr) {
|
||||
Register rs;
|
||||
rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
|
||||
return rs;
|
||||
return Register::from_code((instr & kRsFieldMask) >> kRsShift);
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRdReg(Instr instr) {
|
||||
Register rd;
|
||||
rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
|
||||
return rd;
|
||||
return Register::from_code((instr & kRdFieldMask) >> kRdShift);
|
||||
}
|
||||
|
||||
|
||||
@ -2606,15 +2599,13 @@ void Assembler::movn(Register rd, Register rs, Register rt) {
|
||||
|
||||
|
||||
void Assembler::movt(Register rd, Register rs, uint16_t cc) {
|
||||
Register rt;
|
||||
rt.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
Register rt = Register::from_code((cc & 0x0007) << 2 | 1);
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movf(Register rd, Register rs, uint16_t cc) {
|
||||
Register rt;
|
||||
rt.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
Register rt = Register::from_code((cc & 0x0007) << 2 | 0);
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
|
||||
}
|
||||
|
||||
@ -2960,32 +2951,28 @@ void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
|
||||
|
||||
void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
FPURegister ft;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
FPURegister ft = FPURegister::from_code((cc & 0x0007) << 2 | 1);
|
||||
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
FPURegister ft;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
FPURegister ft = FPURegister::from_code((cc & 0x0007) << 2 | 1);
|
||||
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
FPURegister ft;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
FPURegister ft = FPURegister::from_code((cc & 0x0007) << 2 | 0);
|
||||
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
FPURegister ft;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
FPURegister ft = FPURegister::from_code((cc & 0x0007) << 2 | 0);
|
||||
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,15 @@ const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register and FPURegister.
|
||||
|
||||
struct Register {
|
||||
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;
|
||||
@ -210,45 +218,20 @@ struct Register {
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static constexpr int kNumRegisters = Code::kAfterLast;
|
||||
|
||||
static Register from_code(int code) {
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kNumRegisters);
|
||||
Register r = { code };
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
|
||||
bool is(Register reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr Register(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
// s7: context register
|
||||
// s3: lithium scratch
|
||||
// s4: lithium scratch2
|
||||
#define DECLARE_REGISTER(R) constexpr Register R = {Register::kCode_##R};
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr Register R = Register::from_code<kRegCode_##R>();
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr Register no_reg = {Register::kCode_no_reg};
|
||||
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
int ToNumber(Register reg);
|
||||
|
||||
@ -257,103 +240,49 @@ Register ToRegister(int num);
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
// Coprocessor register.
|
||||
struct FPURegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = kInvalidFPURegister
|
||||
};
|
||||
|
||||
static constexpr int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
inline static int NumRegisters();
|
||||
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).
|
||||
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(FPURegister reg) const { return reg_code == reg.reg_code; }
|
||||
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(reg_code % 2 == 0); // Specified Double reg must be even.
|
||||
FPURegister reg;
|
||||
reg.reg_code = reg_code;
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
DCHECK(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(reg_code % 2 == 0); // Specified Double reg must be even.
|
||||
FPURegister reg;
|
||||
reg.reg_code = reg_code + 1;
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
DCHECK(code() % 2 == 0); // Specified Double reg must be even.
|
||||
return FPURegister::from_code(code() + 1);
|
||||
}
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
private:
|
||||
friend class RegisterBase;
|
||||
explicit constexpr FPURegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
static FPURegister from_code(int code) {
|
||||
FPURegister r = {code};
|
||||
return r;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
enum MSARegisterCode {
|
||||
#define REGISTER_CODE(R) kMsaCode_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kMsaAfterLast
|
||||
};
|
||||
|
||||
// MIPS SIMD (MSA) register
|
||||
struct MSARegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
SIMD128_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = kInvalidMSARegister
|
||||
};
|
||||
|
||||
static const int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
inline static int NumRegisters();
|
||||
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(MSARegister reg) const { return reg_code == reg.reg_code; }
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
static MSARegister from_code(int code) {
|
||||
MSARegister r = {code};
|
||||
return r;
|
||||
}
|
||||
void setcode(int f) {
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int reg_code;
|
||||
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
|
||||
@ -374,78 +303,22 @@ typedef FPURegister FloatRegister;
|
||||
|
||||
typedef FPURegister DoubleRegister;
|
||||
|
||||
constexpr DoubleRegister no_freg = {kInvalidFPURegister};
|
||||
#define DECLARE_DOUBLE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
|
||||
#undef DECLARE_DOUBLE_REGISTER
|
||||
|
||||
constexpr DoubleRegister f0 = {0}; // Return value in hard float mode.
|
||||
constexpr DoubleRegister f1 = {1};
|
||||
constexpr DoubleRegister f2 = {2};
|
||||
constexpr DoubleRegister f3 = {3};
|
||||
constexpr DoubleRegister f4 = {4};
|
||||
constexpr DoubleRegister f5 = {5};
|
||||
constexpr DoubleRegister f6 = {6};
|
||||
constexpr DoubleRegister f7 = {7};
|
||||
constexpr DoubleRegister f8 = {8};
|
||||
constexpr DoubleRegister f9 = {9};
|
||||
constexpr DoubleRegister f10 = {10};
|
||||
constexpr DoubleRegister f11 = {11};
|
||||
constexpr DoubleRegister f12 = {12}; // Arg 0 in hard float mode.
|
||||
constexpr DoubleRegister f13 = {13};
|
||||
constexpr DoubleRegister f14 = {14}; // Arg 1 in hard float mode.
|
||||
constexpr DoubleRegister f15 = {15};
|
||||
constexpr DoubleRegister f16 = {16};
|
||||
constexpr DoubleRegister f17 = {17};
|
||||
constexpr DoubleRegister f18 = {18};
|
||||
constexpr DoubleRegister f19 = {19};
|
||||
constexpr DoubleRegister f20 = {20};
|
||||
constexpr DoubleRegister f21 = {21};
|
||||
constexpr DoubleRegister f22 = {22};
|
||||
constexpr DoubleRegister f23 = {23};
|
||||
constexpr DoubleRegister f24 = {24};
|
||||
constexpr DoubleRegister f25 = {25};
|
||||
constexpr DoubleRegister f26 = {26};
|
||||
constexpr DoubleRegister f27 = {27};
|
||||
constexpr DoubleRegister f28 = {28};
|
||||
constexpr DoubleRegister f29 = {29};
|
||||
constexpr DoubleRegister f30 = {30};
|
||||
constexpr DoubleRegister f31 = {31};
|
||||
constexpr DoubleRegister no_freg = DoubleRegister::no_reg();
|
||||
|
||||
// SIMD registers.
|
||||
typedef MSARegister Simd128Register;
|
||||
|
||||
const Simd128Register no_msareg = {kInvalidMSARegister};
|
||||
#define DECLARE_SIMD128_REGISTER(R) \
|
||||
constexpr Simd128Register R = Simd128Register::from_code<kMsaCode_##R>();
|
||||
SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
|
||||
#undef DECLARE_SIMD128_REGISTER
|
||||
|
||||
constexpr Simd128Register w0 = {0};
|
||||
constexpr Simd128Register w1 = {1};
|
||||
constexpr Simd128Register w2 = {2};
|
||||
constexpr Simd128Register w3 = {3};
|
||||
constexpr Simd128Register w4 = {4};
|
||||
constexpr Simd128Register w5 = {5};
|
||||
constexpr Simd128Register w6 = {6};
|
||||
constexpr Simd128Register w7 = {7};
|
||||
constexpr Simd128Register w8 = {8};
|
||||
constexpr Simd128Register w9 = {9};
|
||||
constexpr Simd128Register w10 = {10};
|
||||
constexpr Simd128Register w11 = {11};
|
||||
constexpr Simd128Register w12 = {12};
|
||||
constexpr Simd128Register w13 = {13};
|
||||
constexpr Simd128Register w14 = {14};
|
||||
constexpr Simd128Register w15 = {15};
|
||||
constexpr Simd128Register w16 = {16};
|
||||
constexpr Simd128Register w17 = {17};
|
||||
constexpr Simd128Register w18 = {18};
|
||||
constexpr Simd128Register w19 = {19};
|
||||
constexpr Simd128Register w20 = {20};
|
||||
constexpr Simd128Register w21 = {21};
|
||||
constexpr Simd128Register w22 = {22};
|
||||
constexpr Simd128Register w23 = {23};
|
||||
constexpr Simd128Register w24 = {24};
|
||||
constexpr Simd128Register w25 = {25};
|
||||
constexpr Simd128Register w26 = {26};
|
||||
constexpr Simd128Register w27 = {27};
|
||||
constexpr Simd128Register w28 = {28};
|
||||
constexpr Simd128Register w29 = {29};
|
||||
constexpr Simd128Register w30 = {30};
|
||||
constexpr Simd128Register w31 = {31};
|
||||
const Simd128Register no_msareg = Simd128Register::no_reg();
|
||||
|
||||
// Register aliases.
|
||||
// cp is assumed to be a callee saved register.
|
||||
|
@ -513,14 +513,11 @@ void CEntryStub::Generate(MacroAssembler* masm) {
|
||||
// v0:v1: result
|
||||
// sp: stack pointer
|
||||
// fp: frame pointer
|
||||
Register argc;
|
||||
if (argv_in_register()) {
|
||||
// We don't want to pop arguments so set argc to no_reg.
|
||||
argc = no_reg;
|
||||
} else {
|
||||
// s0: still holds argc (callee-saved).
|
||||
argc = s0;
|
||||
}
|
||||
Register argc = argv_in_register()
|
||||
// We don't want to pop arguments so set argc to no_reg.
|
||||
? no_reg
|
||||
// s0: still holds argc (callee-saved).
|
||||
: s0;
|
||||
__ LeaveExitFrame(save_doubles(), argc, true, EMIT_RETURN);
|
||||
|
||||
// Handling of exception.
|
||||
|
@ -156,12 +156,11 @@ class RecordWriteStub: public PlatformCodeStub {
|
||||
// the caller.
|
||||
class RegisterAllocation {
|
||||
public:
|
||||
RegisterAllocation(Register object,
|
||||
Register address,
|
||||
Register scratch0)
|
||||
RegisterAllocation(Register object, Register address, Register scratch0)
|
||||
: object_(object),
|
||||
address_(address),
|
||||
scratch0_(scratch0) {
|
||||
scratch0_(scratch0),
|
||||
scratch1_(no_reg) {
|
||||
DCHECK(!AreAliased(scratch0, object, address, no_reg));
|
||||
scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
RegList restored_regs = kJSCallerSaved | kCalleeSaved;
|
||||
RegList saved_regs = restored_regs | sp.bit() | ra.bit();
|
||||
|
||||
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kMaxNumRegisters;
|
||||
const int kFloatRegsSize = kFloatSize * FloatRegister::kMaxNumRegisters;
|
||||
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kNumRegisters;
|
||||
const int kFloatRegsSize = kFloatSize * FloatRegister::kNumRegisters;
|
||||
|
||||
// Save all double FPU registers before messing with them.
|
||||
__ Dsubu(sp, sp, Operand(kDoubleRegsSize));
|
||||
|
@ -3136,7 +3136,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
bc(offset);
|
||||
break;
|
||||
case eq:
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
// Pre R6 beq is used here to make the code patchable. Otherwise bc
|
||||
// should be used which has no condition field so is not patchable.
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -3154,7 +3154,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
}
|
||||
break;
|
||||
case ne:
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
// Pre R6 bne is used here to make the code patchable. Otherwise we
|
||||
// should not generate any instruction.
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -3175,7 +3175,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
// Signed comparison.
|
||||
case greater:
|
||||
// rs > rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -3193,7 +3193,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case greater_equal:
|
||||
// rs >= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
bc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -3212,7 +3212,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case less:
|
||||
// rs < rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -3230,7 +3230,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case less_equal:
|
||||
// rs <= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
bc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -3251,7 +3251,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
// Unsigned comparison.
|
||||
case Ugreater:
|
||||
// rs > rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset21, scratch, rt))
|
||||
@ -3269,7 +3269,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case Ugreater_equal:
|
||||
// rs >= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
bc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -3288,7 +3288,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case Uless:
|
||||
// rs < rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset21, scratch, rt))
|
||||
@ -3305,7 +3305,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case Uless_equal:
|
||||
// rs <= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
bc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -3618,7 +3618,7 @@ bool TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
|
||||
// Signed comparison.
|
||||
case greater:
|
||||
// rs > rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -3636,7 +3636,7 @@ bool TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case greater_equal:
|
||||
// rs >= rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
balc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -3655,7 +3655,7 @@ bool TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case less:
|
||||
// rs < rt
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
break; // No code needs to be emitted.
|
||||
} else if (rs.is(zero_reg)) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset16, scratch, rt))
|
||||
@ -3673,7 +3673,7 @@ bool TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
|
||||
break;
|
||||
case less_equal:
|
||||
// rs <= r2
|
||||
if (rs.code() == rt.rm().reg_code) {
|
||||
if (rs.code() == rt.rm().code()) {
|
||||
if (!CalculateOffset(L, offset, OffsetSize::kOffset26)) return false;
|
||||
balc(offset);
|
||||
} else if (rs.is(zero_reg)) {
|
||||
@ -5207,7 +5207,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
|
||||
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
|
||||
if (save_doubles) {
|
||||
// The stack is already aligned to 0 modulo 8 for stores with sdc1.
|
||||
int kNumOfSavedRegisters = FPURegister::kMaxNumRegisters / 2;
|
||||
int kNumOfSavedRegisters = FPURegister::kNumRegisters / 2;
|
||||
int space = kNumOfSavedRegisters * kDoubleSize;
|
||||
Dsubu(sp, sp, Operand(space));
|
||||
// Remember: we only need to save every 2nd double FPU value.
|
||||
@ -5242,7 +5242,7 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
|
||||
// Optionally restore all double registers.
|
||||
if (save_doubles) {
|
||||
// Remember: we only need to restore every 2nd double FPU value.
|
||||
int kNumOfSavedRegisters = FPURegister::kMaxNumRegisters / 2;
|
||||
int kNumOfSavedRegisters = FPURegister::kNumRegisters / 2;
|
||||
Dsubu(t8, fp, Operand(ExitFrameConstants::kFixedFrameSizeFromFp +
|
||||
kNumOfSavedRegisters * kDoubleSize));
|
||||
for (int i = 0; i < kNumOfSavedRegisters; i++) {
|
||||
|
@ -154,7 +154,6 @@ void RegExpMacroAssemblerARM64::AdvanceCurrentPosition(int by) {
|
||||
void RegExpMacroAssemblerARM64::AdvanceRegister(int reg, int by) {
|
||||
DCHECK((reg >= 0) && (reg < num_registers_));
|
||||
if (by != 0) {
|
||||
Register to_advance;
|
||||
RegisterState register_state = GetRegisterState(reg);
|
||||
switch (register_state) {
|
||||
case STACKED:
|
||||
@ -162,15 +161,17 @@ void RegExpMacroAssemblerARM64::AdvanceRegister(int reg, int by) {
|
||||
__ Add(w10, w10, by);
|
||||
__ Str(w10, register_location(reg));
|
||||
break;
|
||||
case CACHED_LSW:
|
||||
to_advance = GetCachedRegister(reg);
|
||||
case CACHED_LSW: {
|
||||
Register to_advance = GetCachedRegister(reg);
|
||||
__ Add(to_advance, to_advance, by);
|
||||
break;
|
||||
case CACHED_MSW:
|
||||
to_advance = GetCachedRegister(reg);
|
||||
}
|
||||
case CACHED_MSW: {
|
||||
Register to_advance = GetCachedRegister(reg);
|
||||
__ Add(to_advance, to_advance,
|
||||
static_cast<int64_t>(by) << kWRegSizeInBits);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
@ -1179,19 +1180,17 @@ void RegExpMacroAssemblerARM64::PushRegister(int register_index,
|
||||
|
||||
|
||||
void RegExpMacroAssemblerARM64::ReadCurrentPositionFromRegister(int reg) {
|
||||
Register cached_register;
|
||||
RegisterState register_state = GetRegisterState(reg);
|
||||
switch (register_state) {
|
||||
case STACKED:
|
||||
__ Ldr(current_input_offset(), register_location(reg));
|
||||
break;
|
||||
case CACHED_LSW:
|
||||
cached_register = GetCachedRegister(reg);
|
||||
__ Mov(current_input_offset(), cached_register.W());
|
||||
__ Mov(current_input_offset(), GetCachedRegister(reg).W());
|
||||
break;
|
||||
case CACHED_MSW:
|
||||
cached_register = GetCachedRegister(reg);
|
||||
__ Lsr(current_input_offset().X(), cached_register, kWRegSizeInBits);
|
||||
__ Lsr(current_input_offset().X(), GetCachedRegister(reg),
|
||||
kWRegSizeInBits);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -1495,7 +1494,7 @@ Register RegExpMacroAssemblerARM64::GetRegister(int register_index,
|
||||
if (num_registers_ <= register_index) {
|
||||
num_registers_ = register_index + 1;
|
||||
}
|
||||
Register result;
|
||||
Register result = NoReg;
|
||||
RegisterState register_state = GetRegisterState(register_index);
|
||||
switch (register_state) {
|
||||
case STACKED:
|
||||
@ -1527,22 +1526,23 @@ void RegExpMacroAssemblerARM64::StoreRegister(int register_index,
|
||||
num_registers_ = register_index + 1;
|
||||
}
|
||||
|
||||
Register cached_register;
|
||||
RegisterState register_state = GetRegisterState(register_index);
|
||||
switch (register_state) {
|
||||
case STACKED:
|
||||
__ Str(source, register_location(register_index));
|
||||
break;
|
||||
case CACHED_LSW:
|
||||
cached_register = GetCachedRegister(register_index);
|
||||
case CACHED_LSW: {
|
||||
Register cached_register = GetCachedRegister(register_index);
|
||||
if (!source.Is(cached_register.W())) {
|
||||
__ Bfi(cached_register, source.X(), 0, kWRegSizeInBits);
|
||||
}
|
||||
break;
|
||||
case CACHED_MSW:
|
||||
cached_register = GetCachedRegister(register_index);
|
||||
}
|
||||
case CACHED_MSW: {
|
||||
Register cached_register = GetCachedRegister(register_index);
|
||||
__ Bfi(cached_register, source.X(), kWRegSizeInBits, kWRegSizeInBits);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
|
@ -18,11 +18,11 @@ static const int kMaxAllocatableDoubleRegisterCount =
|
||||
ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_COUNT)0;
|
||||
|
||||
static const int kAllocatableGeneralCodes[] = {
|
||||
#define REGISTER_CODE(R) Register::kCode_##R,
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
ALLOCATABLE_GENERAL_REGISTERS(REGISTER_CODE)};
|
||||
#undef REGISTER_CODE
|
||||
|
||||
#define REGISTER_CODE(R) DoubleRegister::kCode_##R,
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
static const int kAllocatableDoubleCodes[] = {
|
||||
ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_CODE)};
|
||||
#if V8_TARGET_ARCH_ARM
|
||||
@ -58,11 +58,11 @@ static const char* const kSimd128RegisterNames[] = {
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >=
|
||||
Register::kNumRegisters);
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
|
||||
FloatRegister::kMaxNumRegisters);
|
||||
FloatRegister::kNumRegisters);
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
|
||||
DoubleRegister::kMaxNumRegisters);
|
||||
DoubleRegister::kNumRegisters);
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
|
||||
Simd128Register::kMaxNumRegisters);
|
||||
Simd128Register::kNumRegisters);
|
||||
|
||||
static int get_num_allocatable_general_registers() {
|
||||
return
|
||||
@ -126,7 +126,7 @@ class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
|
||||
public:
|
||||
ArchDefaultRegisterConfiguration()
|
||||
: RegisterConfiguration(
|
||||
Register::kNumRegisters, DoubleRegister::kMaxNumRegisters,
|
||||
Register::kNumRegisters, DoubleRegister::kNumRegisters,
|
||||
get_num_allocatable_general_registers(),
|
||||
get_num_allocatable_double_registers(), kAllocatableGeneralCodes,
|
||||
get_allocatable_double_codes(),
|
||||
@ -155,7 +155,7 @@ class RestrictedRegisterConfiguration : public RegisterConfiguration {
|
||||
std::unique_ptr<int[]> allocatable_general_register_codes,
|
||||
std::unique_ptr<char const* []> allocatable_general_register_names)
|
||||
: RegisterConfiguration(
|
||||
Register::kNumRegisters, DoubleRegister::kMaxNumRegisters,
|
||||
Register::kNumRegisters, DoubleRegister::kNumRegisters,
|
||||
num_allocatable_general_registers,
|
||||
get_num_allocatable_double_registers(),
|
||||
allocatable_general_register_codes.get(),
|
||||
|
@ -14,7 +14,7 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
struct Register;
|
||||
class Register;
|
||||
|
||||
class SafepointEntry BASE_EMBEDDED {
|
||||
public:
|
||||
|
@ -234,9 +234,9 @@ void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg,
|
||||
void Assembler::emit_vex_prefix(Register reg, Register vreg, Register rm,
|
||||
VectorLength l, SIMDPrefix pp, LeadingOpcode mm,
|
||||
VexW w) {
|
||||
XMMRegister ireg = {reg.code()};
|
||||
XMMRegister ivreg = {vreg.code()};
|
||||
XMMRegister irm = {rm.code()};
|
||||
XMMRegister ireg = XMMRegister::from_code(reg.code());
|
||||
XMMRegister ivreg = XMMRegister::from_code(vreg.code());
|
||||
XMMRegister irm = XMMRegister::from_code(rm.code());
|
||||
emit_vex_prefix(ireg, ivreg, irm, l, pp, mm, w);
|
||||
}
|
||||
|
||||
@ -258,8 +258,8 @@ void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg,
|
||||
void Assembler::emit_vex_prefix(Register reg, Register vreg, const Operand& rm,
|
||||
VectorLength l, SIMDPrefix pp, LeadingOpcode mm,
|
||||
VexW w) {
|
||||
XMMRegister ireg = {reg.code()};
|
||||
XMMRegister ivreg = {vreg.code()};
|
||||
XMMRegister ireg = XMMRegister::from_code(reg.code());
|
||||
XMMRegister ivreg = XMMRegister::from_code(vreg.code());
|
||||
emit_vex_prefix(ireg, ivreg, rm, l, pp, mm, w);
|
||||
}
|
||||
|
||||
|
@ -4110,7 +4110,7 @@ void Assembler::vfmass(byte op, XMMRegister dst, XMMRegister src1,
|
||||
void Assembler::vmovd(XMMRegister dst, Register src) {
|
||||
DCHECK(IsEnabled(AVX));
|
||||
EnsureSpace ensure_space(this);
|
||||
XMMRegister isrc = {src.code()};
|
||||
XMMRegister isrc = XMMRegister::from_code(src.code());
|
||||
emit_vex_prefix(dst, xmm0, isrc, kL128, k66, k0F, kW0);
|
||||
emit(0x6e);
|
||||
emit_sse_operand(dst, src);
|
||||
@ -4129,7 +4129,7 @@ void Assembler::vmovd(XMMRegister dst, const Operand& src) {
|
||||
void Assembler::vmovd(Register dst, XMMRegister src) {
|
||||
DCHECK(IsEnabled(AVX));
|
||||
EnsureSpace ensure_space(this);
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
emit_vex_prefix(src, xmm0, idst, kL128, k66, k0F, kW0);
|
||||
emit(0x7e);
|
||||
emit_sse_operand(src, dst);
|
||||
@ -4139,7 +4139,7 @@ void Assembler::vmovd(Register dst, XMMRegister src) {
|
||||
void Assembler::vmovq(XMMRegister dst, Register src) {
|
||||
DCHECK(IsEnabled(AVX));
|
||||
EnsureSpace ensure_space(this);
|
||||
XMMRegister isrc = {src.code()};
|
||||
XMMRegister isrc = XMMRegister::from_code(src.code());
|
||||
emit_vex_prefix(dst, xmm0, isrc, kL128, k66, k0F, kW1);
|
||||
emit(0x6e);
|
||||
emit_sse_operand(dst, src);
|
||||
@ -4158,7 +4158,7 @@ void Assembler::vmovq(XMMRegister dst, const Operand& src) {
|
||||
void Assembler::vmovq(Register dst, XMMRegister src) {
|
||||
DCHECK(IsEnabled(AVX));
|
||||
EnsureSpace ensure_space(this);
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
emit_vex_prefix(src, xmm0, idst, kL128, k66, k0F, kW1);
|
||||
emit(0x7e);
|
||||
emit_sse_operand(src, dst);
|
||||
@ -4474,7 +4474,7 @@ void Assembler::bmi2l(SIMDPrefix pp, byte op, Register reg, Register vreg,
|
||||
void Assembler::rorxq(Register dst, Register src, byte imm8) {
|
||||
DCHECK(IsEnabled(BMI2));
|
||||
DCHECK(is_uint8(imm8));
|
||||
Register vreg = {0}; // VEX.vvvv unused
|
||||
Register vreg = Register::from_code<0>(); // VEX.vvvv unused
|
||||
EnsureSpace ensure_space(this);
|
||||
emit_vex_prefix(dst, vreg, src, kLZ, kF2, k0F3A, kW1);
|
||||
emit(0xF0);
|
||||
@ -4486,7 +4486,7 @@ void Assembler::rorxq(Register dst, Register src, byte imm8) {
|
||||
void Assembler::rorxq(Register dst, const Operand& src, byte imm8) {
|
||||
DCHECK(IsEnabled(BMI2));
|
||||
DCHECK(is_uint8(imm8));
|
||||
Register vreg = {0}; // VEX.vvvv unused
|
||||
Register vreg = Register::from_code<0>(); // VEX.vvvv unused
|
||||
EnsureSpace ensure_space(this);
|
||||
emit_vex_prefix(dst, vreg, src, kLZ, kF2, k0F3A, kW1);
|
||||
emit(0xF0);
|
||||
@ -4498,7 +4498,7 @@ void Assembler::rorxq(Register dst, const Operand& src, byte imm8) {
|
||||
void Assembler::rorxl(Register dst, Register src, byte imm8) {
|
||||
DCHECK(IsEnabled(BMI2));
|
||||
DCHECK(is_uint8(imm8));
|
||||
Register vreg = {0}; // VEX.vvvv unused
|
||||
Register vreg = Register::from_code<0>(); // VEX.vvvv unused
|
||||
EnsureSpace ensure_space(this);
|
||||
emit_vex_prefix(dst, vreg, src, kLZ, kF2, k0F3A, kW0);
|
||||
emit(0xF0);
|
||||
@ -4510,7 +4510,7 @@ void Assembler::rorxl(Register dst, Register src, byte imm8) {
|
||||
void Assembler::rorxl(Register dst, const Operand& src, byte imm8) {
|
||||
DCHECK(IsEnabled(BMI2));
|
||||
DCHECK(is_uint8(imm8));
|
||||
Register vreg = {0}; // VEX.vvvv unused
|
||||
Register vreg = Register::from_code<0>(); // VEX.vvvv unused
|
||||
EnsureSpace ensure_space(this);
|
||||
emit_vex_prefix(dst, vreg, src, kLZ, kF2, k0F3A, kW0);
|
||||
emit(0xF0);
|
||||
@ -4775,14 +4775,13 @@ void Assembler::pshufd(XMMRegister dst, const Operand& src, uint8_t shuffle) {
|
||||
}
|
||||
|
||||
void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
|
||||
Register ireg = { reg.code() };
|
||||
Register ireg = Register::from_code(reg.code());
|
||||
emit_operand(ireg, adr);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::emit_sse_operand(Register reg, const Operand& adr) {
|
||||
Register ireg = {reg.code()};
|
||||
emit_operand(ireg, adr);
|
||||
emit_operand(reg, adr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,85 +96,50 @@ const int kNumJSCallerSaved = 5;
|
||||
// Number of registers for which space is reserved in safepoints.
|
||||
const int kNumSafepointRegisters = 16;
|
||||
|
||||
// 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.
|
||||
//
|
||||
struct Register {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
enum RegisterCode {
|
||||
#define REGISTER_CODE(R) kRegCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static constexpr int kNumRegisters = Code::kAfterLast;
|
||||
|
||||
static Register from_code(int code) {
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kNumRegisters);
|
||||
Register r = {code};
|
||||
return r;
|
||||
}
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
|
||||
bool is(Register reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
// Unfortunately we can't make this private in a struct when initializing
|
||||
// by assignment.
|
||||
int reg_code;
|
||||
kRegAfterLast
|
||||
};
|
||||
|
||||
#define DECLARE_REGISTER(R) constexpr Register R = {Register::kCode_##R};
|
||||
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) {}
|
||||
};
|
||||
|
||||
static_assert(IS_TRIVIALLY_COPYABLE(Register) &&
|
||||
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::kCode_no_reg};
|
||||
constexpr Register no_reg = Register::no_reg();
|
||||
|
||||
#ifdef _WIN64
|
||||
// Windows calling convention
|
||||
constexpr Register arg_reg_1 = {Register::kCode_rcx};
|
||||
constexpr Register arg_reg_2 = {Register::kCode_rdx};
|
||||
constexpr Register arg_reg_3 = {Register::kCode_r8};
|
||||
constexpr Register arg_reg_4 = {Register::kCode_r9};
|
||||
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 = {Register::kCode_rdi};
|
||||
constexpr Register arg_reg_2 = {Register::kCode_rsi};
|
||||
constexpr Register arg_reg_3 = {Register::kCode_rdx};
|
||||
constexpr Register arg_reg_4 = {Register::kCode_rcx};
|
||||
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
|
||||
|
||||
|
||||
@ -219,41 +184,31 @@ constexpr Register arg_reg_4 = {Register::kCode_rcx};
|
||||
constexpr bool kSimpleFPAliasing = true;
|
||||
constexpr bool kSimdMaskRegisters = false;
|
||||
|
||||
struct XMMRegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
enum DoubleRegisterCode {
|
||||
#define REGISTER_CODE(R) kDoubleCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static constexpr int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
static XMMRegister from_code(int code) {
|
||||
XMMRegister result = {code};
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(XMMRegister reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return reg_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; }
|
||||
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; }
|
||||
int low_bits() const { return reg_code_ & 0x7; }
|
||||
|
||||
// Unfortunately we can't make this private in a struct when initializing
|
||||
// by assignment.
|
||||
int reg_code;
|
||||
private:
|
||||
friend class RegisterBase<XMMRegister, kDoubleAfterLast>;
|
||||
explicit constexpr XMMRegister(int code) : RegisterBase(code) {}
|
||||
};
|
||||
|
||||
static_assert(IS_TRIVIALLY_COPYABLE(XMMRegister) &&
|
||||
sizeof(XMMRegister) == sizeof(int),
|
||||
"XMMRegister can efficiently be passed by value");
|
||||
|
||||
typedef XMMRegister FloatRegister;
|
||||
|
||||
typedef XMMRegister DoubleRegister;
|
||||
@ -261,10 +216,10 @@ typedef XMMRegister DoubleRegister;
|
||||
typedef XMMRegister Simd128Register;
|
||||
|
||||
#define DECLARE_REGISTER(R) \
|
||||
constexpr DoubleRegister R = {DoubleRegister::kCode_##R};
|
||||
constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
|
||||
DOUBLE_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
constexpr DoubleRegister no_double_reg = {DoubleRegister::kCode_no_reg};
|
||||
constexpr DoubleRegister no_double_reg = DoubleRegister::no_reg();
|
||||
|
||||
enum Condition {
|
||||
// any value < 0 is considered no_condition
|
||||
@ -1531,13 +1486,11 @@ class Assembler : public AssemblerBase {
|
||||
#undef AVX_SP_3
|
||||
|
||||
void vpsrlq(XMMRegister dst, XMMRegister src, byte imm8) {
|
||||
XMMRegister iop = {2};
|
||||
vpd(0x73, iop, dst, src);
|
||||
vpd(0x73, xmm2, dst, src);
|
||||
emit(imm8);
|
||||
}
|
||||
void vpsllq(XMMRegister dst, XMMRegister src, byte imm8) {
|
||||
XMMRegister iop = {6};
|
||||
vpd(0x73, iop, dst, src);
|
||||
vpd(0x73, xmm6, dst, src);
|
||||
emit(imm8);
|
||||
}
|
||||
void vcvtss2sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
|
||||
@ -1547,67 +1500,67 @@ class Assembler : public AssemblerBase {
|
||||
vinstr(0x5a, dst, src1, src2, kF3, k0F, kWIG);
|
||||
}
|
||||
void vcvtlsi2sd(XMMRegister dst, XMMRegister src1, Register src2) {
|
||||
XMMRegister isrc2 = {src2.code()};
|
||||
XMMRegister isrc2 = XMMRegister::from_code(src2.code());
|
||||
vinstr(0x2a, dst, src1, isrc2, kF2, k0F, kW0);
|
||||
}
|
||||
void vcvtlsi2sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
|
||||
vinstr(0x2a, dst, src1, src2, kF2, k0F, kW0);
|
||||
}
|
||||
void vcvtlsi2ss(XMMRegister dst, XMMRegister src1, Register src2) {
|
||||
XMMRegister isrc2 = {src2.code()};
|
||||
XMMRegister isrc2 = XMMRegister::from_code(src2.code());
|
||||
vinstr(0x2a, dst, src1, isrc2, kF3, k0F, kW0);
|
||||
}
|
||||
void vcvtlsi2ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
|
||||
vinstr(0x2a, dst, src1, src2, kF3, k0F, kW0);
|
||||
}
|
||||
void vcvtqsi2ss(XMMRegister dst, XMMRegister src1, Register src2) {
|
||||
XMMRegister isrc2 = {src2.code()};
|
||||
XMMRegister isrc2 = XMMRegister::from_code(src2.code());
|
||||
vinstr(0x2a, dst, src1, isrc2, kF3, k0F, kW1);
|
||||
}
|
||||
void vcvtqsi2ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
|
||||
vinstr(0x2a, dst, src1, src2, kF3, k0F, kW1);
|
||||
}
|
||||
void vcvtqsi2sd(XMMRegister dst, XMMRegister src1, Register src2) {
|
||||
XMMRegister isrc2 = {src2.code()};
|
||||
XMMRegister isrc2 = XMMRegister::from_code(src2.code());
|
||||
vinstr(0x2a, dst, src1, isrc2, kF2, k0F, kW1);
|
||||
}
|
||||
void vcvtqsi2sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
|
||||
vinstr(0x2a, dst, src1, src2, kF2, k0F, kW1);
|
||||
}
|
||||
void vcvttss2si(Register dst, XMMRegister src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x2c, idst, xmm0, src, kF3, k0F, kW0);
|
||||
}
|
||||
void vcvttss2si(Register dst, const Operand& src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x2c, idst, xmm0, src, kF3, k0F, kW0);
|
||||
}
|
||||
void vcvttsd2si(Register dst, XMMRegister src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x2c, idst, xmm0, src, kF2, k0F, kW0);
|
||||
}
|
||||
void vcvttsd2si(Register dst, const Operand& src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x2c, idst, xmm0, src, kF2, k0F, kW0);
|
||||
}
|
||||
void vcvttss2siq(Register dst, XMMRegister src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x2c, idst, xmm0, src, kF3, k0F, kW1);
|
||||
}
|
||||
void vcvttss2siq(Register dst, const Operand& src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x2c, idst, xmm0, src, kF3, k0F, kW1);
|
||||
}
|
||||
void vcvttsd2siq(Register dst, XMMRegister src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x2c, idst, xmm0, src, kF2, k0F, kW1);
|
||||
}
|
||||
void vcvttsd2siq(Register dst, const Operand& src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x2c, idst, xmm0, src, kF2, k0F, kW1);
|
||||
}
|
||||
void vcvtsd2si(Register dst, XMMRegister src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x2d, idst, xmm0, src, kF2, k0F, kW0);
|
||||
}
|
||||
void vucomisd(XMMRegister dst, XMMRegister src) {
|
||||
@ -1664,11 +1617,11 @@ class Assembler : public AssemblerBase {
|
||||
vpd(0x11, src, xmm0, dst);
|
||||
}
|
||||
void vmovmskps(Register dst, XMMRegister src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vps(0x50, idst, xmm0, src);
|
||||
}
|
||||
void vmovmskpd(Register dst, XMMRegister src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vpd(0x50, idst, xmm0, src);
|
||||
}
|
||||
void vcmpps(XMMRegister dst, XMMRegister src1, XMMRegister src2, int8_t cmp) {
|
||||
@ -1717,37 +1670,31 @@ class Assembler : public AssemblerBase {
|
||||
vinstr(0xF0, dst, xmm0, src, kF2, k0F, kWIG);
|
||||
}
|
||||
void vpsllw(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {6};
|
||||
vinstr(0x71, iop, dst, src, k66, k0F, kWIG);
|
||||
vinstr(0x71, xmm6, dst, src, k66, k0F, kWIG);
|
||||
emit(imm8);
|
||||
}
|
||||
void vpsrlw(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {2};
|
||||
vinstr(0x71, iop, dst, src, k66, k0F, kWIG);
|
||||
vinstr(0x71, xmm2, dst, src, k66, k0F, kWIG);
|
||||
emit(imm8);
|
||||
}
|
||||
void vpsraw(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {4};
|
||||
vinstr(0x71, iop, dst, src, k66, k0F, kWIG);
|
||||
vinstr(0x71, xmm4, dst, src, k66, k0F, kWIG);
|
||||
emit(imm8);
|
||||
}
|
||||
void vpslld(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {6};
|
||||
vinstr(0x72, iop, dst, src, k66, k0F, kWIG);
|
||||
vinstr(0x72, xmm6, dst, src, k66, k0F, kWIG);
|
||||
emit(imm8);
|
||||
}
|
||||
void vpsrld(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {2};
|
||||
vinstr(0x72, iop, dst, src, k66, k0F, kWIG);
|
||||
vinstr(0x72, xmm2, dst, src, k66, k0F, kWIG);
|
||||
emit(imm8);
|
||||
}
|
||||
void vpsrad(XMMRegister dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister iop = {4};
|
||||
vinstr(0x72, iop, dst, src, k66, k0F, kWIG);
|
||||
vinstr(0x72, xmm4, dst, src, k66, k0F, kWIG);
|
||||
emit(imm8);
|
||||
}
|
||||
void vpextrb(Register dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x14, src, xmm0, idst, k66, k0F3A, kW0);
|
||||
emit(imm8);
|
||||
}
|
||||
@ -1756,7 +1703,7 @@ class Assembler : public AssemblerBase {
|
||||
emit(imm8);
|
||||
}
|
||||
void vpextrw(Register dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0xc5, idst, xmm0, src, k66, k0F, kW0);
|
||||
emit(imm8);
|
||||
}
|
||||
@ -1765,7 +1712,7 @@ class Assembler : public AssemblerBase {
|
||||
emit(imm8);
|
||||
}
|
||||
void vpextrd(Register dst, XMMRegister src, int8_t imm8) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
XMMRegister idst = XMMRegister::from_code(dst.code());
|
||||
vinstr(0x16, src, xmm0, idst, k66, k0F3A, kW0);
|
||||
emit(imm8);
|
||||
}
|
||||
@ -1774,7 +1721,7 @@ class Assembler : public AssemblerBase {
|
||||
emit(imm8);
|
||||
}
|
||||
void vpinsrb(XMMRegister dst, XMMRegister src1, Register src2, int8_t imm8) {
|
||||
XMMRegister isrc = {src2.code()};
|
||||
XMMRegister isrc = XMMRegister::from_code(src2.code());
|
||||
vinstr(0x20, dst, src1, isrc, k66, k0F3A, kW0);
|
||||
emit(imm8);
|
||||
}
|
||||
@ -1784,7 +1731,7 @@ class Assembler : public AssemblerBase {
|
||||
emit(imm8);
|
||||
}
|
||||
void vpinsrw(XMMRegister dst, XMMRegister src1, Register src2, int8_t imm8) {
|
||||
XMMRegister isrc = {src2.code()};
|
||||
XMMRegister isrc = XMMRegister::from_code(src2.code());
|
||||
vinstr(0xc4, dst, src1, isrc, k66, k0F, kW0);
|
||||
emit(imm8);
|
||||
}
|
||||
@ -1794,7 +1741,7 @@ class Assembler : public AssemblerBase {
|
||||
emit(imm8);
|
||||
}
|
||||
void vpinsrd(XMMRegister dst, XMMRegister src1, Register src2, int8_t imm8) {
|
||||
XMMRegister isrc = {src2.code()};
|
||||
XMMRegister isrc = XMMRegister::from_code(src2.code());
|
||||
vinstr(0x22, dst, src1, isrc, k66, k0F3A, kW0);
|
||||
emit(imm8);
|
||||
}
|
||||
@ -1838,54 +1785,18 @@ class Assembler : public AssemblerBase {
|
||||
void bextrl(Register dst, const Operand& src1, Register src2) {
|
||||
bmi1l(0xf7, dst, src2, src1);
|
||||
}
|
||||
void blsiq(Register dst, Register src) {
|
||||
Register ireg = {3};
|
||||
bmi1q(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsiq(Register dst, const Operand& src) {
|
||||
Register ireg = {3};
|
||||
bmi1q(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsil(Register dst, Register src) {
|
||||
Register ireg = {3};
|
||||
bmi1l(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsil(Register dst, const Operand& src) {
|
||||
Register ireg = {3};
|
||||
bmi1l(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsmskq(Register dst, Register src) {
|
||||
Register ireg = {2};
|
||||
bmi1q(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsmskq(Register dst, const Operand& src) {
|
||||
Register ireg = {2};
|
||||
bmi1q(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsmskl(Register dst, Register src) {
|
||||
Register ireg = {2};
|
||||
bmi1l(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsmskl(Register dst, const Operand& src) {
|
||||
Register ireg = {2};
|
||||
bmi1l(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsrq(Register dst, Register src) {
|
||||
Register ireg = {1};
|
||||
bmi1q(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsrq(Register dst, const Operand& src) {
|
||||
Register ireg = {1};
|
||||
bmi1q(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsrl(Register dst, Register src) {
|
||||
Register ireg = {1};
|
||||
bmi1l(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsrl(Register dst, const Operand& src) {
|
||||
Register ireg = {1};
|
||||
bmi1l(0xf3, ireg, dst, src);
|
||||
}
|
||||
void blsiq(Register dst, Register src) { bmi1q(0xf3, rbx, dst, src); }
|
||||
void blsiq(Register dst, const Operand& src) { bmi1q(0xf3, rbx, dst, src); }
|
||||
void blsil(Register dst, Register src) { bmi1l(0xf3, rbx, dst, src); }
|
||||
void blsil(Register dst, const Operand& src) { bmi1l(0xf3, rbx, dst, src); }
|
||||
void blsmskq(Register dst, Register src) { bmi1q(0xf3, rdx, dst, src); }
|
||||
void blsmskq(Register dst, const Operand& src) { bmi1q(0xf3, rdx, dst, src); }
|
||||
void blsmskl(Register dst, Register src) { bmi1l(0xf3, rdx, dst, src); }
|
||||
void blsmskl(Register dst, const Operand& src) { bmi1l(0xf3, rdx, dst, src); }
|
||||
void blsrq(Register dst, Register src) { bmi1q(0xf3, rcx, dst, src); }
|
||||
void blsrq(Register dst, const Operand& src) { bmi1q(0xf3, rcx, dst, src); }
|
||||
void blsrl(Register dst, Register src) { bmi1l(0xf3, rcx, dst, src); }
|
||||
void blsrl(Register dst, const Operand& src) { bmi1l(0xf3, rcx, dst, src); }
|
||||
void tzcntq(Register dst, Register src);
|
||||
void tzcntq(Register dst, const Operand& src);
|
||||
void tzcntl(Register dst, Register src);
|
||||
|
@ -88,7 +88,7 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
|
||||
MemOperand exponent_operand(MemOperand(input_reg,
|
||||
double_offset + kDoubleSize / 2));
|
||||
|
||||
Register scratch1;
|
||||
Register scratch1 = no_reg;
|
||||
Register scratch_candidates[3] = { rbx, rdx, rdi };
|
||||
for (int i = 0; i < 3; i++) {
|
||||
scratch1 = scratch_candidates[i];
|
||||
|
@ -168,15 +168,14 @@ class RecordWriteStub: public PlatformCodeStub {
|
||||
// that must be preserved and one scratch register provided by the caller.
|
||||
class RegisterAllocation {
|
||||
public:
|
||||
RegisterAllocation(Register object,
|
||||
Register address,
|
||||
Register scratch0)
|
||||
RegisterAllocation(Register object, Register address, Register scratch0)
|
||||
: object_orig_(object),
|
||||
address_orig_(address),
|
||||
scratch0_orig_(scratch0),
|
||||
object_(object),
|
||||
address_(address),
|
||||
scratch0_(scratch0) {
|
||||
scratch0_(scratch0),
|
||||
scratch1_(no_reg) {
|
||||
DCHECK(!AreAliased(scratch0, object, address, no_reg));
|
||||
scratch1_ = GetRegThatIsNotRcxOr(object_, address_, scratch0_);
|
||||
if (scratch0.is(rcx)) {
|
||||
|
@ -24,7 +24,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
// Save all general purpose registers before messing with them.
|
||||
const int kNumberOfRegisters = Register::kNumRegisters;
|
||||
|
||||
const int kDoubleRegsSize = kDoubleSize * XMMRegister::kMaxNumRegisters;
|
||||
const int kDoubleRegsSize = kDoubleSize * XMMRegister::kNumRegisters;
|
||||
__ subp(rsp, Immediate(kDoubleRegsSize));
|
||||
|
||||
const RegisterConfiguration* config = RegisterConfiguration::Default();
|
||||
@ -35,7 +35,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
__ Movsd(Operand(rsp, offset), xmm_reg);
|
||||
}
|
||||
|
||||
const int kFloatRegsSize = kFloatSize * XMMRegister::kMaxNumRegisters;
|
||||
const int kFloatRegsSize = kFloatSize * XMMRegister::kNumRegisters;
|
||||
__ subp(rsp, Immediate(kFloatRegsSize));
|
||||
|
||||
for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
|
||||
@ -113,7 +113,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
|
||||
// Fill in the float input registers.
|
||||
int float_regs_offset = FrameDescription::float_registers_offset();
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
int src_offset = i * kFloatSize;
|
||||
int dst_offset = i * kFloatSize + float_regs_offset;
|
||||
__ movl(rcx, Operand(rsp, src_offset));
|
||||
@ -123,7 +123,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
|
||||
// Fill in the double input registers.
|
||||
int double_regs_offset = FrameDescription::double_registers_offset();
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
int dst_offset = i * kDoubleSize + double_regs_offset;
|
||||
__ popq(Operand(rbx, dst_offset));
|
||||
}
|
||||
|
@ -29,11 +29,11 @@ void EhFrameWriter::WriteInitialStateInCie() {
|
||||
// static
|
||||
int EhFrameWriter::RegisterToDwarfCode(Register name) {
|
||||
switch (name.code()) {
|
||||
case Register::kCode_rbp:
|
||||
case kRegCode_rbp:
|
||||
return kRbpDwarfCode;
|
||||
case Register::kCode_rsp:
|
||||
case kRegCode_rsp:
|
||||
return kRspDwarfCode;
|
||||
case Register::kCode_rax:
|
||||
case kRegCode_rax:
|
||||
return kRaxDwarfCode;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
|
@ -563,17 +563,10 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
|
||||
jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
#define REG(Name) \
|
||||
{ Register::kCode_##Name }
|
||||
static constexpr Register saved_regs[] = {rax, rcx, rdx, rbx, rbp, rsi,
|
||||
rdi, r8, r9, r10, r11};
|
||||
|
||||
static const Register saved_regs[] = {
|
||||
REG(rax), REG(rcx), REG(rdx), REG(rbx), REG(rbp), REG(rsi), REG(rdi), REG(r8),
|
||||
REG(r9), REG(r10), REG(r11)
|
||||
};
|
||||
|
||||
#undef REG
|
||||
|
||||
static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
|
||||
static constexpr int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
|
||||
|
||||
int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
|
||||
Register exclusion1,
|
||||
@ -589,7 +582,7 @@ int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
|
||||
|
||||
// R12 to r15 are callee save on all platforms.
|
||||
if (fp_mode == kSaveFPRegs) {
|
||||
bytes += kDoubleSize * XMMRegister::kMaxNumRegisters;
|
||||
bytes += kDoubleSize * XMMRegister::kNumRegisters;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
@ -611,9 +604,9 @@ int TurboAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
|
||||
|
||||
// R12 to r15 are callee save on all platforms.
|
||||
if (fp_mode == kSaveFPRegs) {
|
||||
int delta = kDoubleSize * XMMRegister::kMaxNumRegisters;
|
||||
int delta = kDoubleSize * XMMRegister::kNumRegisters;
|
||||
subp(rsp, Immediate(delta));
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
XMMRegister reg = XMMRegister::from_code(i);
|
||||
Movsd(Operand(rsp, i * kDoubleSize), reg);
|
||||
}
|
||||
@ -627,12 +620,12 @@ int TurboAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
|
||||
Register exclusion2, Register exclusion3) {
|
||||
int bytes = 0;
|
||||
if (fp_mode == kSaveFPRegs) {
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
|
||||
XMMRegister reg = XMMRegister::from_code(i);
|
||||
Movsd(reg, Operand(rsp, i * kDoubleSize));
|
||||
}
|
||||
int delta = kDoubleSize * XMMRegister::kMaxNumRegisters;
|
||||
addp(rsp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters));
|
||||
int delta = kDoubleSize * XMMRegister::kNumRegisters;
|
||||
addp(rsp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
|
||||
bytes += delta;
|
||||
}
|
||||
|
||||
@ -3063,7 +3056,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space,
|
||||
#endif
|
||||
// Optionally save all XMM registers.
|
||||
if (save_doubles) {
|
||||
int space = XMMRegister::kMaxNumRegisters * kDoubleSize +
|
||||
int space = XMMRegister::kNumRegisters * kDoubleSize +
|
||||
arg_stack_space * kRegisterSize;
|
||||
subp(rsp, Immediate(space));
|
||||
int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
|
||||
|
@ -12366,10 +12366,10 @@ static void PushPopJsspSimpleHelper(int reg_count,
|
||||
reg_count = CountSetBits(allowed, kNumberOfRegisters);
|
||||
}
|
||||
// Work out which registers to use, based on reg_size.
|
||||
Register r[kNumberOfRegisters];
|
||||
Register x[kNumberOfRegisters];
|
||||
RegList list = PopulateRegisterArray(NULL, x, r, reg_size, reg_count,
|
||||
allowed);
|
||||
auto r = CreateRegisterArray<Register, kNumberOfRegisters>();
|
||||
auto x = CreateRegisterArray<Register, kNumberOfRegisters>();
|
||||
RegList list = PopulateRegisterArray(NULL, x.data(), r.data(), reg_size,
|
||||
reg_count, allowed);
|
||||
|
||||
// The literal base is chosen to have two useful properties:
|
||||
// * When multiplied by small values (such as a register index), this value
|
||||
@ -12550,10 +12550,10 @@ static void PushPopFPJsspSimpleHelper(int reg_count,
|
||||
reg_count = CountSetBits(allowed, kNumberOfVRegisters);
|
||||
}
|
||||
// Work out which registers to use, based on reg_size.
|
||||
VRegister v[kNumberOfRegisters];
|
||||
VRegister d[kNumberOfRegisters];
|
||||
RegList list =
|
||||
PopulateVRegisterArray(NULL, d, v, reg_size, reg_count, allowed);
|
||||
auto v = CreateRegisterArray<VRegister, kNumberOfRegisters>();
|
||||
auto d = CreateRegisterArray<VRegister, kNumberOfRegisters>();
|
||||
RegList list = PopulateVRegisterArray(NULL, d.data(), v.data(), reg_size,
|
||||
reg_count, allowed);
|
||||
|
||||
// The literal base is chosen to have two useful properties:
|
||||
// * When multiplied (using an integer) by small values (such as a register
|
||||
@ -12719,9 +12719,9 @@ static void PushPopJsspMixedMethodsHelper(int claim, int reg_size) {
|
||||
static RegList const allowed =
|
||||
~(x8.bit() | x9.bit() | jssp.bit() | xzr.bit());
|
||||
// Work out which registers to use, based on reg_size.
|
||||
Register r[10];
|
||||
Register x[10];
|
||||
PopulateRegisterArray(NULL, x, r, reg_size, 10, allowed);
|
||||
auto r = CreateRegisterArray<Register, 10>();
|
||||
auto x = CreateRegisterArray<Register, 10>();
|
||||
PopulateRegisterArray(NULL, x.data(), r.data(), reg_size, 10, allowed);
|
||||
|
||||
// Calculate some handy register lists.
|
||||
RegList r0_to_r3 = 0;
|
||||
@ -12824,9 +12824,10 @@ static void PushPopJsspWXOverlapHelper(int reg_count, int claim) {
|
||||
if (reg_count == kPushPopJsspMaxRegCount) {
|
||||
reg_count = CountSetBits(allowed, kNumberOfRegisters);
|
||||
}
|
||||
Register w[kNumberOfRegisters];
|
||||
Register x[kNumberOfRegisters];
|
||||
RegList list = PopulateRegisterArray(w, x, NULL, 0, reg_count, allowed);
|
||||
auto w = CreateRegisterArray<Register, kNumberOfRegisters>();
|
||||
auto x = CreateRegisterArray<Register, kNumberOfRegisters>();
|
||||
RegList list =
|
||||
PopulateRegisterArray(w.data(), x.data(), NULL, 0, reg_count, allowed);
|
||||
|
||||
// The number of W-sized slots we expect to pop. When we pop, we alternate
|
||||
// between W and X registers, so we need reg_count*1.5 W-sized slots.
|
||||
@ -13904,23 +13905,23 @@ TEST(isvalid) {
|
||||
CHECK(d31.IsValid());
|
||||
CHECK(s31.IsValid());
|
||||
|
||||
CHECK(x0.IsValidRegister());
|
||||
CHECK(w0.IsValidRegister());
|
||||
CHECK(xzr.IsValidRegister());
|
||||
CHECK(wzr.IsValidRegister());
|
||||
CHECK(csp.IsValidRegister());
|
||||
CHECK(wcsp.IsValidRegister());
|
||||
CHECK(!x0.IsValidVRegister());
|
||||
CHECK(!w0.IsValidVRegister());
|
||||
CHECK(!xzr.IsValidVRegister());
|
||||
CHECK(!wzr.IsValidVRegister());
|
||||
CHECK(!csp.IsValidVRegister());
|
||||
CHECK(!wcsp.IsValidVRegister());
|
||||
CHECK(x0.IsRegister());
|
||||
CHECK(w0.IsRegister());
|
||||
CHECK(xzr.IsRegister());
|
||||
CHECK(wzr.IsRegister());
|
||||
CHECK(csp.IsRegister());
|
||||
CHECK(wcsp.IsRegister());
|
||||
CHECK(!x0.IsVRegister());
|
||||
CHECK(!w0.IsVRegister());
|
||||
CHECK(!xzr.IsVRegister());
|
||||
CHECK(!wzr.IsVRegister());
|
||||
CHECK(!csp.IsVRegister());
|
||||
CHECK(!wcsp.IsVRegister());
|
||||
|
||||
CHECK(d0.IsValidVRegister());
|
||||
CHECK(s0.IsValidVRegister());
|
||||
CHECK(!d0.IsValidRegister());
|
||||
CHECK(!s0.IsValidRegister());
|
||||
CHECK(d0.IsVRegister());
|
||||
CHECK(s0.IsVRegister());
|
||||
CHECK(!d0.IsRegister());
|
||||
CHECK(!s0.IsRegister());
|
||||
|
||||
// Test the same as before, but using CPURegister types. This shouldn't make
|
||||
// any difference.
|
||||
@ -13939,23 +13940,23 @@ TEST(isvalid) {
|
||||
CHECK(static_cast<CPURegister>(d31).IsValid());
|
||||
CHECK(static_cast<CPURegister>(s31).IsValid());
|
||||
|
||||
CHECK(static_cast<CPURegister>(x0).IsValidRegister());
|
||||
CHECK(static_cast<CPURegister>(w0).IsValidRegister());
|
||||
CHECK(static_cast<CPURegister>(xzr).IsValidRegister());
|
||||
CHECK(static_cast<CPURegister>(wzr).IsValidRegister());
|
||||
CHECK(static_cast<CPURegister>(csp).IsValidRegister());
|
||||
CHECK(static_cast<CPURegister>(wcsp).IsValidRegister());
|
||||
CHECK(!static_cast<CPURegister>(x0).IsValidVRegister());
|
||||
CHECK(!static_cast<CPURegister>(w0).IsValidVRegister());
|
||||
CHECK(!static_cast<CPURegister>(xzr).IsValidVRegister());
|
||||
CHECK(!static_cast<CPURegister>(wzr).IsValidVRegister());
|
||||
CHECK(!static_cast<CPURegister>(csp).IsValidVRegister());
|
||||
CHECK(!static_cast<CPURegister>(wcsp).IsValidVRegister());
|
||||
CHECK(static_cast<CPURegister>(x0).IsRegister());
|
||||
CHECK(static_cast<CPURegister>(w0).IsRegister());
|
||||
CHECK(static_cast<CPURegister>(xzr).IsRegister());
|
||||
CHECK(static_cast<CPURegister>(wzr).IsRegister());
|
||||
CHECK(static_cast<CPURegister>(csp).IsRegister());
|
||||
CHECK(static_cast<CPURegister>(wcsp).IsRegister());
|
||||
CHECK(!static_cast<CPURegister>(x0).IsVRegister());
|
||||
CHECK(!static_cast<CPURegister>(w0).IsVRegister());
|
||||
CHECK(!static_cast<CPURegister>(xzr).IsVRegister());
|
||||
CHECK(!static_cast<CPURegister>(wzr).IsVRegister());
|
||||
CHECK(!static_cast<CPURegister>(csp).IsVRegister());
|
||||
CHECK(!static_cast<CPURegister>(wcsp).IsVRegister());
|
||||
|
||||
CHECK(static_cast<CPURegister>(d0).IsValidVRegister());
|
||||
CHECK(static_cast<CPURegister>(s0).IsValidVRegister());
|
||||
CHECK(!static_cast<CPURegister>(d0).IsValidRegister());
|
||||
CHECK(!static_cast<CPURegister>(s0).IsValidRegister());
|
||||
CHECK(static_cast<CPURegister>(d0).IsVRegister());
|
||||
CHECK(static_cast<CPURegister>(s0).IsVRegister());
|
||||
CHECK(!static_cast<CPURegister>(d0).IsRegister());
|
||||
CHECK(!static_cast<CPURegister>(s0).IsRegister());
|
||||
}
|
||||
|
||||
TEST(areconsecutive) {
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "src/arm64/assembler-arm64-inl.h"
|
||||
#include "src/arm64/utils-arm64.h"
|
||||
#include "src/base/template-utils.h"
|
||||
#include "src/macro-assembler-inl.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-utils-arm64.h"
|
||||
@ -227,7 +228,6 @@ bool EqualRegisters(const RegisterDump* a, const RegisterDump* b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
RegList PopulateRegisterArray(Register* w, Register* x, Register* r,
|
||||
int reg_size, int reg_count, RegList allowed) {
|
||||
RegList list = 0;
|
||||
|
@ -212,6 +212,12 @@ bool EqualNzcv(uint32_t expected, uint32_t result);
|
||||
|
||||
bool EqualRegisters(const RegisterDump* a, const RegisterDump* b);
|
||||
|
||||
// Create an array of type {RegType}, size {Size}, filled with {NoReg}.
|
||||
template <typename RegType, size_t Size>
|
||||
std::array<RegType, Size> CreateRegisterArray() {
|
||||
return base::make_array<Size>([](size_t) { return RegType::no_reg(); });
|
||||
}
|
||||
|
||||
// Populate the w, x and r arrays with registers from the 'allowed' mask. The
|
||||
// r array will be populated with <reg_size>-sized registers,
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user