Re-reland: Remove register index/code indirection
Previous to this patch, both the lithium and TurboFan register allocators tracked allocated registers by "indices", rather than the register codes used elsewhere in the runtime. This patch ensures that codes are used everywhere, and in the process cleans up a bunch of redundant code and adds more structure to how the set of allocatable registers is defined. Some highlights of changes: * TurboFan's RegisterConfiguration class moved to V8's top level so that it can be shared with Crankshaft. * Various "ToAllocationIndex" and related methods removed. * Code that can be easily shared between Register classes on different platforms is now shared. * The list of allocatable registers on each platform is declared as a list rather than implicitly via the register index <-> code mapping. Committed: https://crrev.com/80bc6f6e11f79524e3f1ad05579583adfd5f18b2 Cr-Commit-Position: refs/heads/master@{#30913} Committed: https://crrev.com/7b7a8205d9a00c678fb7a6e032a55fecbc1509cf Cr-Commit-Position: refs/heads/master@{#31075} Review URL: https://codereview.chromium.org/1287383003 Cr-Commit-Position: refs/heads/master@{#31087}
This commit is contained in:
parent
6f81ee6a3d
commit
5cf1c0bcf6
4
BUILD.gn
4
BUILD.gn
@ -819,8 +819,6 @@ source_set("v8_base") {
|
||||
"src/compiler/register-allocator.h",
|
||||
"src/compiler/register-allocator-verifier.cc",
|
||||
"src/compiler/register-allocator-verifier.h",
|
||||
"src/compiler/register-configuration.cc",
|
||||
"src/compiler/register-configuration.h",
|
||||
"src/compiler/representation-change.h",
|
||||
"src/compiler/schedule.cc",
|
||||
"src/compiler/schedule.h",
|
||||
@ -1150,6 +1148,8 @@ source_set("v8_base") {
|
||||
"src/regexp/regexp-macro-assembler.h",
|
||||
"src/regexp/regexp-stack.cc",
|
||||
"src/regexp/regexp-stack.h",
|
||||
"src/register-configuration.cc",
|
||||
"src/register-configuration.h",
|
||||
"src/runtime-profiler.cc",
|
||||
"src/runtime-profiler.h",
|
||||
"src/runtime/runtime-array.cc",
|
||||
|
@ -50,53 +50,11 @@ namespace internal {
|
||||
bool CpuFeatures::SupportsCrankshaft() { return IsSupported(VFP3); }
|
||||
|
||||
|
||||
int Register::NumAllocatableRegisters() {
|
||||
return kMaxNumAllocatableRegisters;
|
||||
}
|
||||
|
||||
|
||||
int DwVfpRegister::NumRegisters() {
|
||||
int DoubleRegister::NumRegisters() {
|
||||
return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
|
||||
}
|
||||
|
||||
|
||||
int DwVfpRegister::NumReservedRegisters() {
|
||||
return kNumReservedRegisters;
|
||||
}
|
||||
|
||||
|
||||
int DwVfpRegister::NumAllocatableRegisters() {
|
||||
return NumRegisters() - kNumReservedRegisters;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
int DwVfpRegister::NumAllocatableAliasedRegisters() {
|
||||
return LowDwVfpRegister::kMaxNumLowRegisters - kNumReservedRegisters;
|
||||
}
|
||||
|
||||
|
||||
int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) {
|
||||
DCHECK(!reg.is(kDoubleRegZero));
|
||||
DCHECK(!reg.is(kScratchDoubleReg));
|
||||
if (reg.code() > kDoubleRegZero.code()) {
|
||||
return reg.code() - kNumReservedRegisters;
|
||||
}
|
||||
return reg.code();
|
||||
}
|
||||
|
||||
|
||||
DwVfpRegister DwVfpRegister::FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < NumAllocatableRegisters());
|
||||
DCHECK(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
|
||||
kNumReservedRegisters - 1);
|
||||
if (index >= kDoubleRegZero.code()) {
|
||||
return from_code(index + kNumReservedRegisters);
|
||||
}
|
||||
return from_code(index);
|
||||
}
|
||||
|
||||
|
||||
void RelocInfo::apply(intptr_t delta) {
|
||||
if (RelocInfo::IsInternalReference(rmode_)) {
|
||||
// absolute code pointer inside code object moves with the code object.
|
||||
|
@ -213,18 +213,6 @@ void CpuFeatures::PrintFeatures() {
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of DwVfpRegister
|
||||
|
||||
const char* DwVfpRegister::AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < NumAllocatableRegisters());
|
||||
DCHECK(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
|
||||
kNumReservedRegisters - 1);
|
||||
if (index >= kDoubleRegZero.code()) index += kNumReservedRegisters;
|
||||
return VFPRegisters::Name(index, true);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of RelocInfo
|
||||
|
||||
@ -398,26 +386,26 @@ NeonListOperand::NeonListOperand(DoubleRegister base, int registers_count) {
|
||||
// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
|
||||
// register r is not encoded.
|
||||
const Instr kPushRegPattern =
|
||||
al | B26 | 4 | NegPreIndex | kRegister_sp_Code * B16;
|
||||
al | B26 | 4 | NegPreIndex | Register::kCode_sp * 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 | kRegister_sp_Code * B16;
|
||||
al | B26 | L | 4 | PostIndex | Register::kCode_sp * B16;
|
||||
// ldr rd, [pc, #offset]
|
||||
const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPCImmedPattern = 5 * B24 | L | kRegister_pc_Code * B16;
|
||||
const Instr kLdrPCImmedPattern = 5 * B24 | L | Register::kCode_pc * B16;
|
||||
// ldr rd, [pp, #offset]
|
||||
const Instr kLdrPpImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPpImmedPattern = 5 * B24 | L | kRegister_r8_Code * B16;
|
||||
const Instr kLdrPpImmedPattern = 5 * B24 | L | Register::kCode_r8 * B16;
|
||||
// ldr rd, [pp, rn]
|
||||
const Instr kLdrPpRegMask = 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPpRegPattern = 7 * B24 | L | kRegister_r8_Code * B16;
|
||||
const Instr kLdrPpRegPattern = 7 * B24 | L | Register::kCode_r8 * B16;
|
||||
// vldr dd, [pc, #offset]
|
||||
const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
|
||||
const Instr kVldrDPCPattern = 13 * B24 | L | kRegister_pc_Code * B16 | 11 * B8;
|
||||
const Instr kVldrDPCPattern = 13 * B24 | L | Register::kCode_pc * B16 | 11 * B8;
|
||||
// vldr dd, [pp, #offset]
|
||||
const Instr kVldrDPpMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
|
||||
const Instr kVldrDPpPattern = 13 * B24 | L | kRegister_r8_Code * B16 | 11 * B8;
|
||||
const Instr kVldrDPpPattern = 13 * B24 | L | Register::kCode_r8 * B16 | 11 * B8;
|
||||
// blxcc rm
|
||||
const Instr kBlxRegMask =
|
||||
15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
|
||||
@ -444,13 +432,13 @@ const Instr kAndBicFlip = 0xe * B21;
|
||||
|
||||
// A mask for the Rd register for push, pop, ldr, str instructions.
|
||||
const Instr kLdrRegFpOffsetPattern =
|
||||
al | B26 | L | Offset | kRegister_fp_Code * B16;
|
||||
al | B26 | L | Offset | Register::kCode_fp * B16;
|
||||
const Instr kStrRegFpOffsetPattern =
|
||||
al | B26 | Offset | kRegister_fp_Code * B16;
|
||||
al | B26 | Offset | Register::kCode_fp * B16;
|
||||
const Instr kLdrRegFpNegOffsetPattern =
|
||||
al | B26 | L | NegOffset | kRegister_fp_Code * B16;
|
||||
al | B26 | L | NegOffset | Register::kCode_fp * B16;
|
||||
const Instr kStrRegFpNegOffsetPattern =
|
||||
al | B26 | NegOffset | kRegister_fp_Code * B16;
|
||||
al | B26 | NegOffset | Register::kCode_fp * B16;
|
||||
const Instr kLdrStrInstrTypeMask = 0xffff0000;
|
||||
|
||||
|
||||
@ -626,21 +614,21 @@ Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
|
||||
|
||||
Register Assembler::GetRd(Instr instr) {
|
||||
Register reg;
|
||||
reg.code_ = Instruction::RdValue(instr);
|
||||
reg.reg_code = Instruction::RdValue(instr);
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRn(Instr instr) {
|
||||
Register reg;
|
||||
reg.code_ = Instruction::RnValue(instr);
|
||||
reg.reg_code = Instruction::RnValue(instr);
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRm(Instr instr) {
|
||||
Register reg;
|
||||
reg.code_ = Instruction::RmValue(instr);
|
||||
reg.reg_code = Instruction::RmValue(instr);
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,31 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
||||
V(r8) V(r9) V(r10) V(fp) V(ip) V(sp) V(lr) V(pc)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) V(r8)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15) \
|
||||
V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define ALLOCATABLE_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(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
|
||||
V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
|
||||
|
||||
#define ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(V) \
|
||||
V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
||||
V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) \
|
||||
// clang-format on
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum, but enum values are assignment-
|
||||
@ -71,190 +96,123 @@ namespace internal {
|
||||
// mode. This way we get the compile-time error checking in debug mode
|
||||
// and best performance in optimized code.
|
||||
|
||||
// These constants are used in several locations, including static initializers
|
||||
const int kRegister_no_reg_Code = -1;
|
||||
const int kRegister_r0_Code = 0;
|
||||
const int kRegister_r1_Code = 1;
|
||||
const int kRegister_r2_Code = 2;
|
||||
const int kRegister_r3_Code = 3;
|
||||
const int kRegister_r4_Code = 4;
|
||||
const int kRegister_r5_Code = 5;
|
||||
const int kRegister_r6_Code = 6;
|
||||
const int kRegister_r7_Code = 7;
|
||||
const int kRegister_r8_Code = 8;
|
||||
const int kRegister_r9_Code = 9;
|
||||
const int kRegister_r10_Code = 10;
|
||||
const int kRegister_fp_Code = 11;
|
||||
const int kRegister_ip_Code = 12;
|
||||
const int kRegister_sp_Code = 13;
|
||||
const int kRegister_lr_Code = 14;
|
||||
const int kRegister_pc_Code = 15;
|
||||
|
||||
// Core register
|
||||
struct Register {
|
||||
static const int kNumRegisters = 16;
|
||||
static const int kMaxNumAllocatableRegisters =
|
||||
FLAG_enable_embedded_constant_pool ? 8 : 9;
|
||||
static const int kSizeInBytes = 4;
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
inline static int NumAllocatableRegisters();
|
||||
|
||||
static int ToAllocationIndex(Register reg) {
|
||||
DCHECK(reg.code() < kMaxNumAllocatableRegisters);
|
||||
return reg.code();
|
||||
}
|
||||
|
||||
static Register FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
return from_code(index);
|
||||
}
|
||||
|
||||
static const char* AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
const char* const names[] = {
|
||||
"r0",
|
||||
"r1",
|
||||
"r2",
|
||||
"r3",
|
||||
"r4",
|
||||
"r5",
|
||||
"r6",
|
||||
"r7",
|
||||
"r8",
|
||||
};
|
||||
if (FLAG_enable_embedded_constant_pool && (index >= 7)) {
|
||||
return names[index + 1];
|
||||
}
|
||||
return names[index];
|
||||
}
|
||||
static const int kNumRegisters = Code::kAfterLast;
|
||||
|
||||
static Register from_code(int code) {
|
||||
Register r = { code };
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kNumRegisters);
|
||||
Register r = {code};
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
|
||||
bool is(Register reg) const { return code_ == reg.code_; }
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
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 code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
void set_code(int code) {
|
||||
code_ = code;
|
||||
reg_code = code;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
const Register no_reg = { kRegister_no_reg_Code };
|
||||
|
||||
const Register r0 = { kRegister_r0_Code };
|
||||
const Register r1 = { kRegister_r1_Code };
|
||||
const Register r2 = { kRegister_r2_Code };
|
||||
const Register r3 = { kRegister_r3_Code };
|
||||
const Register r4 = { kRegister_r4_Code };
|
||||
const Register r5 = { kRegister_r5_Code };
|
||||
const Register r6 = { kRegister_r6_Code };
|
||||
// Used as context register.
|
||||
const Register r7 = {kRegister_r7_Code};
|
||||
// Used as constant pool pointer register if FLAG_enable_embedded_constant_pool.
|
||||
const Register r8 = { kRegister_r8_Code };
|
||||
// Used as lithium codegen scratch register.
|
||||
const Register r9 = { kRegister_r9_Code };
|
||||
// Used as roots register.
|
||||
const Register r10 = { kRegister_r10_Code };
|
||||
const Register fp = { kRegister_fp_Code };
|
||||
const Register ip = { kRegister_ip_Code };
|
||||
const Register sp = { kRegister_sp_Code };
|
||||
const Register lr = { kRegister_lr_Code };
|
||||
const Register pc = { kRegister_pc_Code };
|
||||
// r7: context register
|
||||
// r8: constant pool pointer register if FLAG_enable_embedded_constant_pool.
|
||||
// r9: lithium scratch
|
||||
#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
const Register no_reg = {Register::kCode_no_reg};
|
||||
|
||||
// Single word VFP register.
|
||||
struct SwVfpRegister {
|
||||
static const int kSizeInBytes = 4;
|
||||
bool is_valid() const { return 0 <= code_ && code_ < 32; }
|
||||
bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
|
||||
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 code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void split_code(int* vm, int* m) const {
|
||||
DCHECK(is_valid());
|
||||
*m = code_ & 0x1;
|
||||
*vm = code_ >> 1;
|
||||
*m = reg_code & 0x1;
|
||||
*vm = reg_code >> 1;
|
||||
}
|
||||
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
|
||||
// Double word VFP register.
|
||||
struct DwVfpRegister {
|
||||
static const int kMaxNumRegisters = 32;
|
||||
struct DoubleRegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static const int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
inline static int NumRegisters();
|
||||
|
||||
// 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 const int kNumReservedRegisters = 2;
|
||||
static const int kMaxNumAllocatableRegisters = kMaxNumRegisters -
|
||||
kNumReservedRegisters;
|
||||
static const int kSizeInBytes = 8;
|
||||
|
||||
// Note: the number of registers can be different at snapshot and run-time.
|
||||
// Any code included in the snapshot must be able to run both with 16 or 32
|
||||
// registers.
|
||||
inline static int NumRegisters();
|
||||
inline static int NumReservedRegisters();
|
||||
inline static int NumAllocatableRegisters();
|
||||
|
||||
// TODO(turbofan): This is a temporary work-around required because our
|
||||
// register allocator does not yet support the aliasing of single/double
|
||||
// registers on ARM.
|
||||
inline static int NumAllocatableAliasedRegisters();
|
||||
|
||||
inline static int ToAllocationIndex(DwVfpRegister reg);
|
||||
static const char* AllocationIndexToString(int index);
|
||||
inline static DwVfpRegister FromAllocationIndex(int index);
|
||||
|
||||
static DwVfpRegister from_code(int code) {
|
||||
DwVfpRegister r = { code };
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return 0 <= code_ && code_ < kMaxNumRegisters;
|
||||
}
|
||||
bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
static DoubleRegister from_code(int code) {
|
||||
DoubleRegister r = {code};
|
||||
return r;
|
||||
}
|
||||
void split_code(int* vm, int* m) const {
|
||||
DCHECK(is_valid());
|
||||
*m = (code_ & 0x10) >> 4;
|
||||
*vm = code_ & 0x0F;
|
||||
*m = (reg_code & 0x10) >> 4;
|
||||
*vm = reg_code & 0x0F;
|
||||
}
|
||||
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
|
||||
typedef DwVfpRegister DoubleRegister;
|
||||
typedef DoubleRegister DwVfpRegister;
|
||||
|
||||
|
||||
// Double word VFP register d0-15.
|
||||
@ -262,7 +220,7 @@ struct LowDwVfpRegister {
|
||||
public:
|
||||
static const int kMaxNumLowRegisters = 16;
|
||||
operator DwVfpRegister() const {
|
||||
DwVfpRegister r = { code_ };
|
||||
DwVfpRegister r = { reg_code };
|
||||
return r;
|
||||
}
|
||||
static LowDwVfpRegister from_code(int code) {
|
||||
@ -271,30 +229,30 @@ struct LowDwVfpRegister {
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return 0 <= code_ && code_ < kMaxNumLowRegisters;
|
||||
return 0 <= reg_code && reg_code < kMaxNumLowRegisters;
|
||||
}
|
||||
bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
|
||||
bool is(LowDwVfpRegister reg) const { return code_ == reg.code_; }
|
||||
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 code_;
|
||||
return reg_code;
|
||||
}
|
||||
SwVfpRegister low() const {
|
||||
SwVfpRegister reg;
|
||||
reg.code_ = code_ * 2;
|
||||
reg.reg_code = reg_code * 2;
|
||||
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
}
|
||||
SwVfpRegister high() const {
|
||||
SwVfpRegister reg;
|
||||
reg.code_ = (code_ * 2) + 1;
|
||||
reg.reg_code = (reg_code * 2) + 1;
|
||||
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
}
|
||||
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
|
||||
@ -308,21 +266,21 @@ struct QwNeonRegister {
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return (0 <= code_) && (code_ < kMaxNumRegisters);
|
||||
return (0 <= reg_code) && (reg_code < kMaxNumRegisters);
|
||||
}
|
||||
bool is(QwNeonRegister reg) const { return code_ == reg.code_; }
|
||||
bool is(QwNeonRegister reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return code_;
|
||||
return reg_code;
|
||||
}
|
||||
void split_code(int* vm, int* m) const {
|
||||
DCHECK(is_valid());
|
||||
int encoded_code = code_ << 1;
|
||||
int encoded_code = reg_code << 1;
|
||||
*m = (encoded_code & 0x10) >> 4;
|
||||
*vm = encoded_code & 0x0F;
|
||||
}
|
||||
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
|
||||
@ -427,19 +385,19 @@ const QwNeonRegister q15 = { 15 };
|
||||
|
||||
// Coprocessor register
|
||||
struct CRegister {
|
||||
bool is_valid() const { return 0 <= code_ && code_ < 16; }
|
||||
bool is(CRegister creg) const { return code_ == creg.code_; }
|
||||
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 code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
|
||||
|
@ -51,17 +51,6 @@ const Registers::RegisterAlias Registers::aliases_[] = {
|
||||
};
|
||||
|
||||
|
||||
const char* Registers::Name(int reg) {
|
||||
const char* result;
|
||||
if ((0 <= reg) && (reg < kNumRegisters)) {
|
||||
result = names_[reg];
|
||||
} else {
|
||||
result = "noreg";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Support for VFP registers s0 to s31 (d0 to d15) and d16-d31.
|
||||
// Note that "sN:sM" is the same as "dN/2" up to d15.
|
||||
// These register names are defined in a way to match the native disassembler
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/codegen.h"
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/full-codegen/full-codegen.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/safepoint-table.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -93,7 +94,7 @@ void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
|
||||
}
|
||||
input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp()));
|
||||
input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
|
||||
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; i++) {
|
||||
input_->SetDoubleRegister(i, 0.0);
|
||||
}
|
||||
|
||||
@ -142,8 +143,7 @@ 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::kMaxNumAllocatableRegisters;
|
||||
const int kDoubleRegsSize = kDoubleSize * DwVfpRegister::kMaxNumRegisters;
|
||||
|
||||
// Save all allocatable VFP registers before messing with them.
|
||||
DCHECK(kDoubleRegZero.code() == 14);
|
||||
@ -152,11 +152,11 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
// Check CPU flags for number of registers, setting the Z condition flag.
|
||||
__ CheckFor32DRegs(ip);
|
||||
|
||||
// Push registers d0-d13, and possibly d16-d31, on the stack.
|
||||
// Push registers d0-d15, and possibly d16-d31, on the stack.
|
||||
// If d16-d31 are not pushed, decrease the stack pointer instead.
|
||||
__ vstm(db_w, sp, d16, d31, ne);
|
||||
__ sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq);
|
||||
__ vstm(db_w, sp, d0, d13);
|
||||
__ vstm(db_w, sp, d0, d15);
|
||||
|
||||
// Push all 16 registers (needed to populate FrameDescription::registers_).
|
||||
// TODO(1588) Note that using pc with stm is deprecated, so we should perhaps
|
||||
@ -211,9 +211,11 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
// Copy VFP registers to
|
||||
// double_registers_[DoubleRegister::kMaxNumAllocatableRegisters]
|
||||
int double_regs_offset = FrameDescription::double_registers_offset();
|
||||
for (int i = 0; i < DwVfpRegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
int dst_offset = i * kDoubleSize + double_regs_offset;
|
||||
int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
int dst_offset = code * kDoubleSize + double_regs_offset;
|
||||
int src_offset = code * kDoubleSize + kNumberOfRegisters * kPointerSize;
|
||||
__ vldr(d0, sp, src_offset);
|
||||
__ vstr(d0, r1, dst_offset);
|
||||
}
|
||||
|
@ -1923,7 +1923,7 @@ const char* NameConverter::NameOfConstant(byte* addr) const {
|
||||
|
||||
|
||||
const char* NameConverter::NameOfCPURegister(int reg) const {
|
||||
return v8::internal::Registers::Name(reg);
|
||||
return v8::internal::Register::from_code(reg).ToString();
|
||||
}
|
||||
|
||||
|
||||
|
@ -444,14 +444,13 @@ LPlatformChunk* LChunkBuilder::Build() {
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
|
||||
Register::ToAllocationIndex(reg));
|
||||
return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
|
||||
DoubleRegister::ToAllocationIndex(reg));
|
||||
return new (zone())
|
||||
LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,7 +72,7 @@ void LCodeGen::SaveCallerDoubles() {
|
||||
BitVector* doubles = chunk()->allocated_double_registers();
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
while (!save_iterator.Done()) {
|
||||
__ vstr(DwVfpRegister::FromAllocationIndex(save_iterator.Current()),
|
||||
__ vstr(DoubleRegister::from_code(save_iterator.Current()),
|
||||
MemOperand(sp, count * kDoubleSize));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
@ -88,8 +88,8 @@ void LCodeGen::RestoreCallerDoubles() {
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
int count = 0;
|
||||
while (!save_iterator.Done()) {
|
||||
__ vldr(DwVfpRegister::FromAllocationIndex(save_iterator.Current()),
|
||||
MemOperand(sp, count * kDoubleSize));
|
||||
__ vldr(DoubleRegister::from_code(save_iterator.Current()),
|
||||
MemOperand(sp, count * kDoubleSize));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
}
|
||||
@ -404,13 +404,13 @@ bool LCodeGen::GenerateSafepointTable() {
|
||||
}
|
||||
|
||||
|
||||
Register LCodeGen::ToRegister(int index) const {
|
||||
return Register::FromAllocationIndex(index);
|
||||
Register LCodeGen::ToRegister(int code) const {
|
||||
return Register::from_code(code);
|
||||
}
|
||||
|
||||
|
||||
DwVfpRegister LCodeGen::ToDoubleRegister(int index) const {
|
||||
return DwVfpRegister::FromAllocationIndex(index);
|
||||
DwVfpRegister LCodeGen::ToDoubleRegister(int code) const {
|
||||
return DwVfpRegister::from_code(code);
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
|
||||
#include "src/arm/macro-assembler-arm.h"
|
||||
@ -759,7 +760,8 @@ MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
|
||||
// Number of d-regs not known at snapshot time.
|
||||
DCHECK(!serializer_enabled());
|
||||
// General purpose registers are pushed last on the stack.
|
||||
int doubles_size = DwVfpRegister::NumAllocatableRegisters() * kDoubleSize;
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
int doubles_size = config->num_allocatable_double_registers() * kDoubleSize;
|
||||
int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
|
||||
return MemOperand(sp, doubles_size + register_offset);
|
||||
}
|
||||
@ -3578,8 +3580,10 @@ Register GetRegisterThatIsNotOneOf(Register reg1,
|
||||
if (reg5.is_valid()) regs |= reg5.bit();
|
||||
if (reg6.is_valid()) regs |= reg6.bit();
|
||||
|
||||
for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
|
||||
Register candidate = Register::FromAllocationIndex(i);
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
|
||||
int code = config->GetAllocatableGeneralCode(i);
|
||||
Register candidate = Register::from_code(code);
|
||||
if (regs & candidate.bit()) continue;
|
||||
return candidate;
|
||||
}
|
||||
|
@ -14,17 +14,17 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
const Register kReturnRegister0 = {kRegister_r0_Code};
|
||||
const Register kReturnRegister1 = {kRegister_r1_Code};
|
||||
const Register kJSFunctionRegister = {kRegister_r1_Code};
|
||||
const Register kContextRegister = {kRegister_r7_Code};
|
||||
const Register kInterpreterAccumulatorRegister = {kRegister_r0_Code};
|
||||
const Register kInterpreterRegisterFileRegister = {kRegister_r4_Code};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_r5_Code};
|
||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_r6_Code};
|
||||
const Register kInterpreterDispatchTableRegister = {kRegister_r8_Code};
|
||||
const Register kRuntimeCallFunctionRegister = {kRegister_r1_Code};
|
||||
const Register kRuntimeCallArgCountRegister = {kRegister_r0_Code};
|
||||
const Register kReturnRegister0 = {Register::kCode_r0};
|
||||
const Register kReturnRegister1 = {Register::kCode_r1};
|
||||
const Register kJSFunctionRegister = {Register::kCode_r1};
|
||||
const Register kContextRegister = {Register::kCode_r7};
|
||||
const Register kInterpreterAccumulatorRegister = {Register::kCode_r0};
|
||||
const Register kInterpreterRegisterFileRegister = {Register::kCode_r4};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_r5};
|
||||
const Register kInterpreterBytecodeArrayRegister = {Register::kCode_r6};
|
||||
const Register kInterpreterDispatchTableRegister = {Register::kCode_r8};
|
||||
const Register kRuntimeCallFunctionRegister = {Register::kCode_r1};
|
||||
const Register kRuntimeCallArgCountRegister = {Register::kCode_r0};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Static helper functions
|
||||
@ -36,9 +36,9 @@ inline MemOperand FieldMemOperand(Register object, int offset) {
|
||||
|
||||
|
||||
// Give alias names to registers
|
||||
const Register cp = { kRegister_r7_Code }; // JavaScript context pointer.
|
||||
const Register pp = { kRegister_r8_Code }; // Constant pool pointer.
|
||||
const Register kRootRegister = { kRegister_r10_Code }; // Roots array pointer.
|
||||
const Register cp = {Register::kCode_r7}; // JavaScript context pointer.
|
||||
const Register pp = {Register::kCode_r8}; // Constant pool pointer.
|
||||
const Register kRootRegister = {Register::kCode_r10}; // Roots array pointer.
|
||||
|
||||
// Flags used for AllocateHeapNumber
|
||||
enum TaggingMode {
|
||||
|
@ -298,7 +298,8 @@ void ArmDebugger::Debug() {
|
||||
if (strcmp(arg1, "all") == 0) {
|
||||
for (int i = 0; i < kNumRegisters; i++) {
|
||||
value = GetRegisterValue(i);
|
||||
PrintF("%3s: 0x%08x %10d", Registers::Name(i), value, value);
|
||||
PrintF("%3s: 0x%08x %10d", Register::from_code(i).ToString(),
|
||||
value, value);
|
||||
if ((argc == 3 && strcmp(arg2, "fp") == 0) &&
|
||||
i < 8 &&
|
||||
(i % 2) == 0) {
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "src/arm64/frames-arm64.h"
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/cpu.h"
|
||||
#include "src/register-configuration.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -192,8 +193,10 @@ bool RelocInfo::IsInConstantPool() {
|
||||
Register GetAllocatableRegisterThatIsNotOneOf(Register reg1, Register reg2,
|
||||
Register reg3, Register reg4) {
|
||||
CPURegList regs(reg1, reg2, reg3, reg4);
|
||||
for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
|
||||
Register candidate = Register::FromAllocationIndex(i);
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
Register candidate = Register::from_code(code);
|
||||
if (regs.IncludesAliasOf(candidate)) continue;
|
||||
return candidate;
|
||||
}
|
||||
|
@ -23,12 +23,36 @@ namespace internal {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Registers.
|
||||
#define REGISTER_CODE_LIST(R) \
|
||||
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
|
||||
R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \
|
||||
R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \
|
||||
R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTER_CODE_LIST(R) \
|
||||
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
|
||||
R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \
|
||||
R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \
|
||||
R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
|
||||
|
||||
#define GENERAL_REGISTERS(R) \
|
||||
R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \
|
||||
R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
|
||||
R(x16) R(x17) R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) \
|
||||
R(x24) R(x25) R(x26) R(x27) R(x28) R(x29) R(x30) R(x31)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(R) \
|
||||
R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \
|
||||
R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
|
||||
R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x27)
|
||||
|
||||
#define DOUBLE_REGISTERS(R) \
|
||||
R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \
|
||||
R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d15) \
|
||||
R(d16) R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) \
|
||||
R(d24) R(d25) R(d26) R(d27) R(d28) R(d29) R(d30) R(d31)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(R) \
|
||||
R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \
|
||||
R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d16) \
|
||||
R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) R(d24) \
|
||||
R(d25) R(d26) R(d27) R(d28)
|
||||
// clang-format on
|
||||
|
||||
static const int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte;
|
||||
|
||||
@ -40,6 +64,14 @@ struct FPRegister;
|
||||
|
||||
|
||||
struct CPURegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
enum RegisterType {
|
||||
// The kInvalid value is used to detect uninitialized static instances,
|
||||
// which are always zero-initialized before any constructors are called.
|
||||
@ -117,6 +149,8 @@ struct Register : public CPURegister {
|
||||
DCHECK(IsValidOrNone());
|
||||
}
|
||||
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
bool IsValid() const {
|
||||
DCHECK(IsRegister() || IsNone());
|
||||
return IsValidRegister();
|
||||
@ -130,6 +164,7 @@ struct Register : public CPURegister {
|
||||
// A few of them may be unused for now.
|
||||
|
||||
static const int kNumRegisters = kNumberOfRegisters;
|
||||
STATIC_ASSERT(kNumRegisters == Code::kAfterLast);
|
||||
static int NumRegisters() { return kNumRegisters; }
|
||||
|
||||
// We allow crankshaft to use the following registers:
|
||||
@ -146,70 +181,6 @@ struct Register : public CPURegister {
|
||||
// - "low range"
|
||||
// - "high range"
|
||||
// - "context"
|
||||
static const unsigned kAllocatableLowRangeBegin = 0;
|
||||
static const unsigned kAllocatableLowRangeEnd = 15;
|
||||
static const unsigned kAllocatableHighRangeBegin = 18;
|
||||
static const unsigned kAllocatableHighRangeEnd = 24;
|
||||
static const unsigned kAllocatableContext = 27;
|
||||
|
||||
// Gap between low and high ranges.
|
||||
static const int kAllocatableRangeGapSize =
|
||||
(kAllocatableHighRangeBegin - kAllocatableLowRangeEnd) - 1;
|
||||
|
||||
static const int kMaxNumAllocatableRegisters =
|
||||
(kAllocatableLowRangeEnd - kAllocatableLowRangeBegin + 1) +
|
||||
(kAllocatableHighRangeEnd - kAllocatableHighRangeBegin + 1) + 1; // cp
|
||||
static int NumAllocatableRegisters() { return kMaxNumAllocatableRegisters; }
|
||||
|
||||
// Return true if the register is one that crankshaft can allocate.
|
||||
bool IsAllocatable() const {
|
||||
return ((reg_code == kAllocatableContext) ||
|
||||
(reg_code <= kAllocatableLowRangeEnd) ||
|
||||
((reg_code >= kAllocatableHighRangeBegin) &&
|
||||
(reg_code <= kAllocatableHighRangeEnd)));
|
||||
}
|
||||
|
||||
static Register FromAllocationIndex(unsigned index) {
|
||||
DCHECK(index < static_cast<unsigned>(NumAllocatableRegisters()));
|
||||
// cp is the last allocatable register.
|
||||
if (index == (static_cast<unsigned>(NumAllocatableRegisters() - 1))) {
|
||||
return from_code(kAllocatableContext);
|
||||
}
|
||||
|
||||
// Handle low and high ranges.
|
||||
return (index <= kAllocatableLowRangeEnd)
|
||||
? from_code(index)
|
||||
: from_code(index + kAllocatableRangeGapSize);
|
||||
}
|
||||
|
||||
static const char* AllocationIndexToString(int index) {
|
||||
DCHECK((index >= 0) && (index < NumAllocatableRegisters()));
|
||||
DCHECK((kAllocatableLowRangeBegin == 0) &&
|
||||
(kAllocatableLowRangeEnd == 15) &&
|
||||
(kAllocatableHighRangeBegin == 18) &&
|
||||
(kAllocatableHighRangeEnd == 24) &&
|
||||
(kAllocatableContext == 27));
|
||||
const char* const names[] = {
|
||||
"x0", "x1", "x2", "x3", "x4",
|
||||
"x5", "x6", "x7", "x8", "x9",
|
||||
"x10", "x11", "x12", "x13", "x14",
|
||||
"x15", "x18", "x19", "x20", "x21",
|
||||
"x22", "x23", "x24", "x27",
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
|
||||
static int ToAllocationIndex(Register reg) {
|
||||
DCHECK(reg.IsAllocatable());
|
||||
unsigned code = reg.code();
|
||||
if (code == kAllocatableContext) {
|
||||
return NumAllocatableRegisters() - 1;
|
||||
}
|
||||
|
||||
return (code <= kAllocatableLowRangeEnd)
|
||||
? code
|
||||
: code - kAllocatableRangeGapSize;
|
||||
}
|
||||
|
||||
static Register from_code(int code) {
|
||||
// Always return an X register.
|
||||
@ -221,6 +192,14 @@ struct Register : public CPURegister {
|
||||
|
||||
|
||||
struct FPRegister : public CPURegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static FPRegister Create(unsigned code, unsigned size) {
|
||||
return FPRegister(
|
||||
CPURegister::Create(code, size, CPURegister::kFPRegister));
|
||||
@ -246,6 +225,8 @@ struct FPRegister : public CPURegister {
|
||||
DCHECK(IsValidOrNone());
|
||||
}
|
||||
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
bool IsValid() const {
|
||||
DCHECK(IsFPRegister() || IsNone());
|
||||
return IsValidFPRegister();
|
||||
@ -256,69 +237,12 @@ struct FPRegister : public CPURegister {
|
||||
|
||||
// Start of V8 compatibility section ---------------------
|
||||
static const int kMaxNumRegisters = kNumberOfFPRegisters;
|
||||
STATIC_ASSERT(kMaxNumRegisters == Code::kAfterLast);
|
||||
|
||||
// Crankshaft can use all the FP registers except:
|
||||
// - d15 which is used to keep the 0 double value
|
||||
// - d30 which is used in crankshaft as a double scratch register
|
||||
// - d31 which is used in the MacroAssembler as a double scratch register
|
||||
static const unsigned kAllocatableLowRangeBegin = 0;
|
||||
static const unsigned kAllocatableLowRangeEnd = 14;
|
||||
static const unsigned kAllocatableHighRangeBegin = 16;
|
||||
static const unsigned kAllocatableHighRangeEnd = 28;
|
||||
|
||||
static const RegList kAllocatableFPRegisters = 0x1fff7fff;
|
||||
|
||||
// Gap between low and high ranges.
|
||||
static const int kAllocatableRangeGapSize =
|
||||
(kAllocatableHighRangeBegin - kAllocatableLowRangeEnd) - 1;
|
||||
|
||||
static const int kMaxNumAllocatableRegisters =
|
||||
(kAllocatableLowRangeEnd - kAllocatableLowRangeBegin + 1) +
|
||||
(kAllocatableHighRangeEnd - kAllocatableHighRangeBegin + 1);
|
||||
static int NumAllocatableRegisters() { return kMaxNumAllocatableRegisters; }
|
||||
|
||||
// TODO(turbofan): Proper float32 support.
|
||||
static int NumAllocatableAliasedRegisters() {
|
||||
return NumAllocatableRegisters();
|
||||
}
|
||||
|
||||
// Return true if the register is one that crankshaft can allocate.
|
||||
bool IsAllocatable() const {
|
||||
return (Bit() & kAllocatableFPRegisters) != 0;
|
||||
}
|
||||
|
||||
static FPRegister FromAllocationIndex(unsigned int index) {
|
||||
DCHECK(index < static_cast<unsigned>(NumAllocatableRegisters()));
|
||||
|
||||
return (index <= kAllocatableLowRangeEnd)
|
||||
? from_code(index)
|
||||
: from_code(index + kAllocatableRangeGapSize);
|
||||
}
|
||||
|
||||
static const char* AllocationIndexToString(int index) {
|
||||
DCHECK((index >= 0) && (index < NumAllocatableRegisters()));
|
||||
DCHECK((kAllocatableLowRangeBegin == 0) &&
|
||||
(kAllocatableLowRangeEnd == 14) &&
|
||||
(kAllocatableHighRangeBegin == 16) &&
|
||||
(kAllocatableHighRangeEnd == 28));
|
||||
const char* const names[] = {
|
||||
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
|
||||
"d8", "d9", "d10", "d11", "d12", "d13", "d14",
|
||||
"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
|
||||
"d24", "d25", "d26", "d27", "d28"
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
|
||||
static int ToAllocationIndex(FPRegister reg) {
|
||||
DCHECK(reg.IsAllocatable());
|
||||
unsigned code = reg.code();
|
||||
|
||||
return (code <= kAllocatableLowRangeEnd)
|
||||
? code
|
||||
: code - kAllocatableRangeGapSize;
|
||||
}
|
||||
|
||||
static FPRegister from_code(int code) {
|
||||
// Always return a D register.
|
||||
return FPRegister::Create(code, kDRegSizeInBits);
|
||||
@ -361,7 +285,7 @@ INITIALIZE_REGISTER(Register, no_reg, 0, 0, CPURegister::kNoRegister);
|
||||
kWRegSizeInBits, CPURegister::kRegister); \
|
||||
INITIALIZE_REGISTER(Register, x##N, N, \
|
||||
kXRegSizeInBits, CPURegister::kRegister);
|
||||
REGISTER_CODE_LIST(DEFINE_REGISTERS)
|
||||
GENERAL_REGISTER_CODE_LIST(DEFINE_REGISTERS)
|
||||
#undef DEFINE_REGISTERS
|
||||
|
||||
INITIALIZE_REGISTER(Register, wcsp, kSPRegInternalCode, kWRegSizeInBits,
|
||||
@ -374,7 +298,7 @@ INITIALIZE_REGISTER(Register, csp, kSPRegInternalCode, kXRegSizeInBits,
|
||||
kSRegSizeInBits, CPURegister::kFPRegister); \
|
||||
INITIALIZE_REGISTER(FPRegister, d##N, N, \
|
||||
kDRegSizeInBits, CPURegister::kFPRegister);
|
||||
REGISTER_CODE_LIST(DEFINE_FPREGISTERS)
|
||||
GENERAL_REGISTER_CODE_LIST(DEFINE_FPREGISTERS)
|
||||
#undef DEFINE_FPREGISTERS
|
||||
|
||||
#undef INITIALIZE_REGISTER
|
||||
|
@ -118,12 +118,6 @@ const unsigned kDoubleExponentBias = 1023;
|
||||
const unsigned kFloatMantissaBits = 23;
|
||||
const unsigned kFloatExponentBits = 8;
|
||||
|
||||
#define REGISTER_CODE_LIST(R) \
|
||||
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
|
||||
R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \
|
||||
R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \
|
||||
R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
|
||||
|
||||
#define INSTRUCTION_FIELDS_LIST(V_) \
|
||||
/* Register fields */ \
|
||||
V_(Rd, 4, 0, Bits) /* Destination register. */ \
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "src/codegen.h"
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/full-codegen/full-codegen.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/safepoint-table.h"
|
||||
|
||||
|
||||
@ -75,7 +76,7 @@ void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
|
||||
input_->SetRegister(jssp.code(), reinterpret_cast<intptr_t>(frame->sp()));
|
||||
input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
|
||||
|
||||
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; i++) {
|
||||
input_->SetDoubleRegister(i, 0.0);
|
||||
}
|
||||
|
||||
@ -122,8 +123,9 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
// in the input frame.
|
||||
|
||||
// Save all allocatable floating point registers.
|
||||
CPURegList saved_fp_registers(CPURegister::kFPRegister, kDRegSizeInBits,
|
||||
FPRegister::kAllocatableFPRegisters);
|
||||
CPURegList saved_fp_registers(
|
||||
CPURegister::kFPRegister, kDRegSizeInBits,
|
||||
RegisterConfiguration::ArchDefault()->allocatable_double_codes_mask());
|
||||
__ PushCPURegList(saved_fp_registers);
|
||||
|
||||
// We save all the registers expcept jssp, sp and lr.
|
||||
|
@ -375,14 +375,13 @@ const char* LArithmeticT::Mnemonic() const {
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
|
||||
Register::ToAllocationIndex(reg));
|
||||
return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
|
||||
DoubleRegister::ToAllocationIndex(reg));
|
||||
return new (zone())
|
||||
LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
|
@ -593,7 +593,7 @@ void LCodeGen::SaveCallerDoubles() {
|
||||
while (!iterator.Done()) {
|
||||
// TODO(all): Is this supposed to save just the callee-saved doubles? It
|
||||
// looks like it's saving all of them.
|
||||
FPRegister value = FPRegister::FromAllocationIndex(iterator.Current());
|
||||
FPRegister value = FPRegister::from_code(iterator.Current());
|
||||
__ Poke(value, count * kDoubleSize);
|
||||
iterator.Advance();
|
||||
count++;
|
||||
@ -611,7 +611,7 @@ void LCodeGen::RestoreCallerDoubles() {
|
||||
while (!iterator.Done()) {
|
||||
// TODO(all): Is this supposed to restore just the callee-saved doubles? It
|
||||
// looks like it's restoring all of them.
|
||||
FPRegister value = FPRegister::FromAllocationIndex(iterator.Current());
|
||||
FPRegister value = FPRegister::from_code(iterator.Current());
|
||||
__ Peek(value, count * kDoubleSize);
|
||||
iterator.Advance();
|
||||
count++;
|
||||
@ -1157,7 +1157,7 @@ void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
|
||||
Register LCodeGen::ToRegister(LOperand* op) const {
|
||||
// TODO(all): support zero register results, as ToRegister32.
|
||||
DCHECK((op != NULL) && op->IsRegister());
|
||||
return Register::FromAllocationIndex(op->index());
|
||||
return Register::from_code(op->index());
|
||||
}
|
||||
|
||||
|
||||
@ -1181,7 +1181,7 @@ Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
|
||||
|
||||
DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
|
||||
DCHECK((op != NULL) && op->IsDoubleRegister());
|
||||
return DoubleRegister::FromAllocationIndex(op->index());
|
||||
return DoubleRegister::from_code(op->index());
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
|
||||
#include "src/arm64/frames-arm64.h"
|
||||
@ -3984,14 +3985,16 @@ void MacroAssembler::PushSafepointRegisters() {
|
||||
|
||||
void MacroAssembler::PushSafepointRegistersAndDoubles() {
|
||||
PushSafepointRegisters();
|
||||
PushCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits,
|
||||
FPRegister::kAllocatableFPRegisters));
|
||||
PushCPURegList(CPURegList(
|
||||
CPURegister::kFPRegister, kDRegSizeInBits,
|
||||
RegisterConfiguration::ArchDefault()->allocatable_double_codes_mask()));
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::PopSafepointRegistersAndDoubles() {
|
||||
PopCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits,
|
||||
FPRegister::kAllocatableFPRegisters));
|
||||
PopCPURegList(CPURegList(
|
||||
CPURegister::kFPRegister, kDRegSizeInBits,
|
||||
RegisterConfiguration::ArchDefault()->allocatable_double_codes_mask()));
|
||||
PopSafepointRegisters();
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,6 @@
|
||||
#include "src/globals.h"
|
||||
#include "src/utils.h"
|
||||
|
||||
#define REGISTER_CODE_LIST(R) \
|
||||
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
|
||||
R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \
|
||||
R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \
|
||||
R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
@ -9,12 +9,6 @@
|
||||
|
||||
#include "src/arm64/constants-arm64.h"
|
||||
|
||||
#define REGISTER_CODE_LIST(R) \
|
||||
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
|
||||
R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \
|
||||
R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \
|
||||
R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "src/regexp/jsregexp.h"
|
||||
#include "src/regexp/regexp-macro-assembler.h"
|
||||
#include "src/regexp/regexp-stack.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "src/simulator.h" // For flushing instruction cache.
|
||||
#include "src/snapshot/serialize.h"
|
||||
@ -104,6 +105,37 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Common register code.
|
||||
|
||||
const char* Register::ToString() {
|
||||
// This is the mapping of allocation indices to registers.
|
||||
DCHECK(reg_code >= 0 && reg_code < kNumRegisters);
|
||||
return RegisterConfiguration::ArchDefault()->GetGeneralRegisterName(reg_code);
|
||||
}
|
||||
|
||||
|
||||
bool Register::IsAllocatable() const {
|
||||
return ((1 << reg_code) &
|
||||
RegisterConfiguration::ArchDefault()
|
||||
->allocatable_general_codes_mask()) != 0;
|
||||
}
|
||||
|
||||
|
||||
const char* DoubleRegister::ToString() {
|
||||
// This is the mapping of allocation indices to registers.
|
||||
DCHECK(reg_code >= 0 && reg_code < kMaxNumRegisters);
|
||||
return RegisterConfiguration::ArchDefault()->GetDoubleRegisterName(reg_code);
|
||||
}
|
||||
|
||||
|
||||
bool DoubleRegister::IsAllocatable() const {
|
||||
return ((1 << reg_code) &
|
||||
RegisterConfiguration::ArchDefault()
|
||||
->allocatable_double_codes_mask()) != 0;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Common double constants.
|
||||
|
||||
|
@ -1276,8 +1276,6 @@ class ConstantPoolBuilder BASE_EMBEDDED {
|
||||
PerTypeEntryInfo info_[ConstantPoolEntry::NUMBER_OF_TYPES];
|
||||
};
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_ASSEMBLER_H_
|
||||
|
@ -15,7 +15,7 @@ namespace compiler {
|
||||
|
||||
namespace {
|
||||
LinkageLocation regloc(Register reg) {
|
||||
return LinkageLocation::ForRegister(Register::ToAllocationIndex(reg));
|
||||
return LinkageLocation::ForRegister(reg.code());
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,12 +96,11 @@ class InstructionOperandConverter {
|
||||
}
|
||||
|
||||
Register ToRegister(InstructionOperand* op) {
|
||||
return Register::FromAllocationIndex(RegisterOperand::cast(op)->index());
|
||||
return RegisterOperand::cast(op)->GetRegister();
|
||||
}
|
||||
|
||||
DoubleRegister ToDoubleRegister(InstructionOperand* op) {
|
||||
return DoubleRegister::FromAllocationIndex(
|
||||
DoubleRegisterOperand::cast(op)->index());
|
||||
return DoubleRegisterOperand::cast(op)->GetDoubleRegister();
|
||||
}
|
||||
|
||||
Constant ToConstant(InstructionOperand* op) {
|
||||
|
@ -227,8 +227,7 @@ void CodeGenerator::RecordSafepoint(ReferenceMap* references,
|
||||
index -= stackSlotToSpillSlotDelta;
|
||||
safepoint.DefinePointerSlot(index, zone());
|
||||
} else if (operand.IsRegister() && (kind & Safepoint::kWithRegisters)) {
|
||||
Register reg =
|
||||
Register::FromAllocationIndex(RegisterOperand::cast(operand).index());
|
||||
Register reg = RegisterOperand::cast(operand).GetRegister();
|
||||
safepoint.DefinePointerRegister(reg, zone());
|
||||
}
|
||||
}
|
||||
|
@ -719,13 +719,13 @@ void GraphC1Visualizer::PrintLiveRange(LiveRange* range, const char* type,
|
||||
os_ << vreg << ":" << range->relative_id() << " " << type;
|
||||
if (range->HasRegisterAssigned()) {
|
||||
AllocatedOperand op = AllocatedOperand::cast(range->GetAssignedOperand());
|
||||
int assigned_reg = op.index();
|
||||
if (op.IsDoubleRegister()) {
|
||||
os_ << " \"" << DoubleRegister::AllocationIndexToString(assigned_reg)
|
||||
<< "\"";
|
||||
DoubleRegister assigned_reg = op.GetDoubleRegister();
|
||||
os_ << " \"" << assigned_reg.ToString() << "\"";
|
||||
} else {
|
||||
DCHECK(op.IsRegister());
|
||||
os_ << " \"" << Register::AllocationIndexToString(assigned_reg) << "\"";
|
||||
Register assigned_reg = op.GetRegister();
|
||||
os_ << " \"" << assigned_reg.ToString() << "\"";
|
||||
}
|
||||
} else if (range->spilled()) {
|
||||
auto top = range->TopLevel();
|
||||
|
@ -249,7 +249,8 @@ void GreedyAllocator::TryAllocateGroup(LiveRangeGroup* group) {
|
||||
float eviction_weight = group_weight;
|
||||
int eviction_reg = -1;
|
||||
int free_reg = -1;
|
||||
for (int reg = 0; reg < num_registers(); ++reg) {
|
||||
for (int i = 0; i < num_allocatable_registers(); ++i) {
|
||||
int reg = allocatable_register_code(i);
|
||||
float weight = GetMaximumConflictingWeight(reg, group, group_weight);
|
||||
if (weight == LiveRange::kInvalidWeight) {
|
||||
free_reg = reg;
|
||||
@ -313,19 +314,20 @@ void GreedyAllocator::TryAllocateLiveRange(LiveRange* range) {
|
||||
// Seek either the first free register, or, from the set of registers
|
||||
// where the maximum conflict is lower than the candidate's weight, the one
|
||||
// with the smallest such weight.
|
||||
for (int i = 0; i < num_registers(); i++) {
|
||||
for (int i = 0; i < num_allocatable_registers(); i++) {
|
||||
int reg = allocatable_register_code(i);
|
||||
// Skip unnecessarily re-visiting the hinted register, if any.
|
||||
if (i == hinted_reg) continue;
|
||||
if (reg == hinted_reg) continue;
|
||||
float max_conflict_weight =
|
||||
GetMaximumConflictingWeight(i, range, competing_weight);
|
||||
GetMaximumConflictingWeight(reg, range, competing_weight);
|
||||
if (max_conflict_weight == LiveRange::kInvalidWeight) {
|
||||
free_reg = i;
|
||||
free_reg = reg;
|
||||
break;
|
||||
}
|
||||
if (max_conflict_weight < range->weight() &&
|
||||
max_conflict_weight < smallest_weight) {
|
||||
smallest_weight = max_conflict_weight;
|
||||
evictable_reg = i;
|
||||
evictable_reg = reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,15 +51,13 @@ class OperandGenerator {
|
||||
|
||||
InstructionOperand DefineAsFixed(Node* node, Register reg) {
|
||||
return Define(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
|
||||
Register::ToAllocationIndex(reg),
|
||||
GetVReg(node)));
|
||||
reg.code(), GetVReg(node)));
|
||||
}
|
||||
|
||||
InstructionOperand DefineAsFixed(Node* node, DoubleRegister reg) {
|
||||
return Define(node,
|
||||
UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
|
||||
DoubleRegister::ToAllocationIndex(reg),
|
||||
GetVReg(node)));
|
||||
reg.code(), GetVReg(node)));
|
||||
}
|
||||
|
||||
InstructionOperand DefineAsConstant(Node* node) {
|
||||
@ -107,15 +105,13 @@ class OperandGenerator {
|
||||
|
||||
InstructionOperand UseFixed(Node* node, Register reg) {
|
||||
return Use(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
|
||||
Register::ToAllocationIndex(reg),
|
||||
GetVReg(node)));
|
||||
reg.code(), GetVReg(node)));
|
||||
}
|
||||
|
||||
InstructionOperand UseFixed(Node* node, DoubleRegister reg) {
|
||||
return Use(node,
|
||||
UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
|
||||
DoubleRegister::ToAllocationIndex(reg),
|
||||
GetVReg(node)));
|
||||
reg.code(), GetVReg(node)));
|
||||
}
|
||||
|
||||
InstructionOperand UseImmediate(Node* node) {
|
||||
@ -142,8 +138,7 @@ class OperandGenerator {
|
||||
}
|
||||
|
||||
InstructionOperand TempRegister(Register reg) {
|
||||
return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
|
||||
Register::ToAllocationIndex(reg),
|
||||
return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, reg.code(),
|
||||
InstructionOperand::kInvalidVirtualRegister);
|
||||
}
|
||||
|
||||
|
@ -74,11 +74,15 @@ std::ostream& operator<<(std::ostream& os,
|
||||
case UnallocatedOperand::NONE:
|
||||
return os;
|
||||
case UnallocatedOperand::FIXED_REGISTER:
|
||||
return os << "(=" << conf->general_register_name(
|
||||
unalloc->fixed_register_index()) << ")";
|
||||
return os << "(="
|
||||
<< conf->GetGeneralRegisterName(
|
||||
unalloc->fixed_register_index())
|
||||
<< ")";
|
||||
case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
|
||||
return os << "(=" << conf->double_register_name(
|
||||
unalloc->fixed_register_index()) << ")";
|
||||
return os << "(="
|
||||
<< conf->GetDoubleRegisterName(
|
||||
unalloc->fixed_register_index())
|
||||
<< ")";
|
||||
case UnallocatedOperand::MUST_HAVE_REGISTER:
|
||||
return os << "(R)";
|
||||
case UnallocatedOperand::MUST_HAVE_SLOT:
|
||||
@ -111,14 +115,12 @@ std::ostream& operator<<(std::ostream& os,
|
||||
os << "[double_stack:" << DoubleStackSlotOperand::cast(op).index();
|
||||
break;
|
||||
case AllocatedOperand::REGISTER:
|
||||
os << "["
|
||||
<< conf->general_register_name(RegisterOperand::cast(op).index())
|
||||
os << "[" << RegisterOperand::cast(op).GetRegister().ToString()
|
||||
<< "|R";
|
||||
break;
|
||||
case AllocatedOperand::DOUBLE_REGISTER:
|
||||
os << "["
|
||||
<< conf->double_register_name(
|
||||
DoubleRegisterOperand::cast(op).index()) << "|R";
|
||||
os << "[" << DoubleRegisterOperand::cast(op).GetRegister().ToString()
|
||||
<< "|R";
|
||||
break;
|
||||
}
|
||||
switch (allocated.machine_type()) {
|
||||
|
@ -14,8 +14,9 @@
|
||||
#include "src/compiler/frame.h"
|
||||
#include "src/compiler/instruction-codes.h"
|
||||
#include "src/compiler/opcodes.h"
|
||||
#include "src/compiler/register-configuration.h"
|
||||
#include "src/compiler/source-position.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/zone-allocator.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -373,9 +374,23 @@ class AllocatedOperand : public InstructionOperand {
|
||||
}
|
||||
|
||||
int index() const {
|
||||
DCHECK(STACK_SLOT == allocated_kind() ||
|
||||
DOUBLE_STACK_SLOT == allocated_kind());
|
||||
return static_cast<int64_t>(value_) >> IndexField::kShift;
|
||||
}
|
||||
|
||||
Register GetRegister() const {
|
||||
DCHECK(REGISTER == allocated_kind() || DOUBLE_REGISTER == allocated_kind());
|
||||
return Register::from_code(static_cast<int64_t>(value_) >>
|
||||
IndexField::kShift);
|
||||
}
|
||||
|
||||
DoubleRegister GetDoubleRegister() const {
|
||||
DCHECK(REGISTER == allocated_kind() || DOUBLE_REGISTER == allocated_kind());
|
||||
return DoubleRegister::from_code(static_cast<int64_t>(value_) >>
|
||||
IndexField::kShift);
|
||||
}
|
||||
|
||||
AllocatedKind allocated_kind() const {
|
||||
return AllocatedKindField::decode(value_);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ namespace compiler {
|
||||
|
||||
namespace {
|
||||
LinkageLocation regloc(Register reg) {
|
||||
return LinkageLocation::ForRegister(Register::ToAllocationIndex(reg));
|
||||
return LinkageLocation::ForRegister(reg.code());
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "src/compiler/verifier.h"
|
||||
#include "src/compiler/zone-pool.h"
|
||||
#include "src/ostreams.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/type-info.h"
|
||||
#include "src/utils.h"
|
||||
|
||||
|
@ -11,6 +11,9 @@
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class RegisterConfiguration;
|
||||
|
||||
namespace compiler {
|
||||
|
||||
class CallDescriptor;
|
||||
@ -18,7 +21,6 @@ class Graph;
|
||||
class InstructionSequence;
|
||||
class Linkage;
|
||||
class PipelineData;
|
||||
class RegisterConfiguration;
|
||||
class Schedule;
|
||||
|
||||
class Pipeline {
|
||||
|
@ -218,14 +218,16 @@ void RegisterAllocatorVerifier::CheckConstraint(
|
||||
return;
|
||||
case kFixedRegister:
|
||||
CHECK(op->IsRegister());
|
||||
CHECK_EQ(RegisterOperand::cast(op)->index(), constraint->value_);
|
||||
CHECK_EQ(RegisterOperand::cast(op)->GetDoubleRegister().code(),
|
||||
constraint->value_);
|
||||
return;
|
||||
case kDoubleRegister:
|
||||
CHECK(op->IsDoubleRegister());
|
||||
return;
|
||||
case kFixedDoubleRegister:
|
||||
CHECK(op->IsDoubleRegister());
|
||||
CHECK_EQ(DoubleRegisterOperand::cast(op)->index(), constraint->value_);
|
||||
CHECK_EQ(DoubleRegisterOperand::cast(op)->GetDoubleRegister().code(),
|
||||
constraint->value_);
|
||||
return;
|
||||
case kFixedSlot:
|
||||
CHECK(op->IsStackSlot());
|
||||
|
@ -27,11 +27,26 @@ void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) {
|
||||
|
||||
|
||||
int GetRegisterCount(const RegisterConfiguration* cfg, RegisterKind kind) {
|
||||
return kind == DOUBLE_REGISTERS ? cfg->num_aliased_double_registers()
|
||||
return kind == DOUBLE_REGISTERS ? cfg->num_double_registers()
|
||||
: cfg->num_general_registers();
|
||||
}
|
||||
|
||||
|
||||
int GetAllocatableRegisterCount(const RegisterConfiguration* cfg,
|
||||
RegisterKind kind) {
|
||||
return kind == DOUBLE_REGISTERS
|
||||
? cfg->num_allocatable_aliased_double_registers()
|
||||
: cfg->num_allocatable_general_registers();
|
||||
}
|
||||
|
||||
|
||||
const int* GetAllocatableRegisterCodes(const RegisterConfiguration* cfg,
|
||||
RegisterKind kind) {
|
||||
return kind == DOUBLE_REGISTERS ? cfg->allocatable_double_codes()
|
||||
: cfg->allocatable_general_codes();
|
||||
}
|
||||
|
||||
|
||||
const InstructionBlock* GetContainingLoop(const InstructionSequence* sequence,
|
||||
const InstructionBlock* block) {
|
||||
auto index = block->loop_header();
|
||||
@ -52,11 +67,11 @@ Instruction* GetLastInstruction(InstructionSequence* code,
|
||||
}
|
||||
|
||||
|
||||
bool IsOutputRegisterOf(Instruction* instr, int index) {
|
||||
bool IsOutputRegisterOf(Instruction* instr, Register reg) {
|
||||
for (size_t i = 0; i < instr->OutputCount(); i++) {
|
||||
auto output = instr->OutputAt(i);
|
||||
if (output->IsRegister() &&
|
||||
RegisterOperand::cast(output)->index() == index) {
|
||||
RegisterOperand::cast(output)->GetRegister().is(reg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -64,11 +79,11 @@ bool IsOutputRegisterOf(Instruction* instr, int index) {
|
||||
}
|
||||
|
||||
|
||||
bool IsOutputDoubleRegisterOf(Instruction* instr, int index) {
|
||||
bool IsOutputDoubleRegisterOf(Instruction* instr, DoubleRegister reg) {
|
||||
for (size_t i = 0; i < instr->OutputCount(); i++) {
|
||||
auto output = instr->OutputAt(i);
|
||||
if (output->IsDoubleRegister() &&
|
||||
DoubleRegisterOperand::cast(output)->index() == index) {
|
||||
DoubleRegisterOperand::cast(output)->GetDoubleRegister().is(reg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -129,7 +144,7 @@ bool UsePosition::HasHint() const {
|
||||
}
|
||||
|
||||
|
||||
bool UsePosition::HintRegister(int* register_index) const {
|
||||
bool UsePosition::HintRegister(int* register_code) const {
|
||||
if (hint_ == nullptr) return false;
|
||||
switch (HintTypeField::decode(flags_)) {
|
||||
case UsePositionHintType::kNone:
|
||||
@ -139,20 +154,25 @@ bool UsePosition::HintRegister(int* register_index) const {
|
||||
auto use_pos = reinterpret_cast<UsePosition*>(hint_);
|
||||
int assigned_register = AssignedRegisterField::decode(use_pos->flags_);
|
||||
if (assigned_register == kUnassignedRegister) return false;
|
||||
*register_index = assigned_register;
|
||||
*register_code = assigned_register;
|
||||
return true;
|
||||
}
|
||||
case UsePositionHintType::kOperand: {
|
||||
auto operand = reinterpret_cast<InstructionOperand*>(hint_);
|
||||
int assigned_register = AllocatedOperand::cast(operand)->index();
|
||||
*register_index = assigned_register;
|
||||
int assigned_register =
|
||||
operand->IsRegister()
|
||||
? RegisterOperand::cast(operand)->GetRegister().code()
|
||||
: DoubleRegisterOperand::cast(operand)
|
||||
->GetDoubleRegister()
|
||||
.code();
|
||||
*register_code = assigned_register;
|
||||
return true;
|
||||
}
|
||||
case UsePositionHintType::kPhi: {
|
||||
auto phi = reinterpret_cast<RegisterAllocationData::PhiMapValue*>(hint_);
|
||||
int assigned_register = phi->assigned_register();
|
||||
if (assigned_register == kUnassignedRegister) return false;
|
||||
*register_index = assigned_register;
|
||||
*register_code = assigned_register;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1213,6 +1233,10 @@ RegisterAllocationData::RegisterAllocationData(
|
||||
debug_name_(debug_name),
|
||||
config_(config),
|
||||
phi_map_(allocation_zone()),
|
||||
allocatable_codes_(this->config()->num_general_registers(), -1,
|
||||
allocation_zone()),
|
||||
allocatable_double_codes_(this->config()->num_double_registers(), -1,
|
||||
allocation_zone()),
|
||||
live_in_sets_(code->InstructionBlockCount(), nullptr, allocation_zone()),
|
||||
live_out_sets_(code->InstructionBlockCount(), nullptr, allocation_zone()),
|
||||
live_ranges_(code->VirtualRegisterCount() * 2, nullptr,
|
||||
@ -1233,7 +1257,7 @@ RegisterAllocationData::RegisterAllocationData(
|
||||
assigned_registers_ = new (code_zone())
|
||||
BitVector(this->config()->num_general_registers(), code_zone());
|
||||
assigned_double_registers_ = new (code_zone())
|
||||
BitVector(this->config()->num_aliased_double_registers(), code_zone());
|
||||
BitVector(this->config()->num_double_registers(), code_zone());
|
||||
this->frame()->SetAllocatedRegisters(assigned_registers_);
|
||||
this->frame()->SetAllocatedDoubleRegisters(assigned_double_registers_);
|
||||
}
|
||||
@ -1772,7 +1796,7 @@ TopLevelLiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) {
|
||||
|
||||
|
||||
TopLevelLiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) {
|
||||
DCHECK(index < config()->num_aliased_double_registers());
|
||||
DCHECK(index < config()->num_double_registers());
|
||||
auto result = data()->fixed_double_live_ranges()[index];
|
||||
if (result == nullptr) {
|
||||
result = data()->NewLiveRange(FixedDoubleLiveRangeID(index), kRepFloat64);
|
||||
@ -1793,10 +1817,11 @@ TopLevelLiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand) {
|
||||
return data()->GetOrCreateLiveRangeFor(
|
||||
ConstantOperand::cast(operand)->virtual_register());
|
||||
} else if (operand->IsRegister()) {
|
||||
return FixedLiveRangeFor(RegisterOperand::cast(operand)->index());
|
||||
return FixedLiveRangeFor(
|
||||
RegisterOperand::cast(operand)->GetRegister().code());
|
||||
} else if (operand->IsDoubleRegister()) {
|
||||
return FixedDoubleLiveRangeFor(
|
||||
DoubleRegisterOperand::cast(operand)->index());
|
||||
DoubleRegisterOperand::cast(operand)->GetDoubleRegister().code());
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1886,9 +1911,10 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block,
|
||||
}
|
||||
|
||||
if (instr->ClobbersRegisters()) {
|
||||
for (int i = 0; i < config()->num_general_registers(); ++i) {
|
||||
if (!IsOutputRegisterOf(instr, i)) {
|
||||
auto range = FixedLiveRangeFor(i);
|
||||
for (int i = 0; i < config()->num_allocatable_general_registers(); ++i) {
|
||||
int code = config()->GetAllocatableGeneralCode(i);
|
||||
if (!IsOutputRegisterOf(instr, Register::from_code(code))) {
|
||||
auto range = FixedLiveRangeFor(code);
|
||||
range->AddUseInterval(curr_position, curr_position.End(),
|
||||
allocation_zone());
|
||||
}
|
||||
@ -1896,9 +1922,11 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block,
|
||||
}
|
||||
|
||||
if (instr->ClobbersDoubleRegisters()) {
|
||||
for (int i = 0; i < config()->num_aliased_double_registers(); ++i) {
|
||||
if (!IsOutputDoubleRegisterOf(instr, i)) {
|
||||
auto range = FixedDoubleLiveRangeFor(i);
|
||||
for (int i = 0; i < config()->num_allocatable_aliased_double_registers();
|
||||
++i) {
|
||||
int code = config()->GetAllocatableDoubleCode(i);
|
||||
if (!IsOutputDoubleRegisterOf(instr, DoubleRegister::from_code(code))) {
|
||||
auto range = FixedDoubleLiveRangeFor(code);
|
||||
range->AddUseInterval(curr_position, curr_position.End(),
|
||||
allocation_zone());
|
||||
}
|
||||
@ -2144,7 +2172,11 @@ RegisterAllocator::RegisterAllocator(RegisterAllocationData* data,
|
||||
RegisterKind kind)
|
||||
: data_(data),
|
||||
mode_(kind),
|
||||
num_registers_(GetRegisterCount(data->config(), kind)) {}
|
||||
num_registers_(GetRegisterCount(data->config(), kind)),
|
||||
num_allocatable_registers_(
|
||||
GetAllocatableRegisterCount(data->config(), kind)),
|
||||
allocatable_register_codes_(
|
||||
GetAllocatableRegisterCodes(data->config(), kind)) {}
|
||||
|
||||
|
||||
LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range,
|
||||
@ -2267,11 +2299,11 @@ const ZoneVector<TopLevelLiveRange*>& RegisterAllocator::GetFixedRegisters()
|
||||
}
|
||||
|
||||
|
||||
const char* RegisterAllocator::RegisterName(int allocation_index) const {
|
||||
const char* RegisterAllocator::RegisterName(int register_code) const {
|
||||
if (mode() == GENERAL_REGISTERS) {
|
||||
return data()->config()->general_register_name(allocation_index);
|
||||
return data()->config()->GetGeneralRegisterName(register_code);
|
||||
} else {
|
||||
return data()->config()->double_register_name(allocation_index);
|
||||
return data()->config()->GetDoubleRegisterName(register_code);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2510,6 +2542,9 @@ bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) {
|
||||
for (auto cur_active : active_live_ranges()) {
|
||||
free_until_pos[cur_active->assigned_register()] =
|
||||
LifetimePosition::GapFromInstructionIndex(0);
|
||||
TRACE("Register %s is free until pos %d (1)\n",
|
||||
RegisterName(cur_active->assigned_register()),
|
||||
LifetimePosition::GapFromInstructionIndex(0).value());
|
||||
}
|
||||
|
||||
for (auto cur_inactive : inactive_live_ranges()) {
|
||||
@ -2518,6 +2553,8 @@ bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) {
|
||||
if (!next_intersection.IsValid()) continue;
|
||||
int cur_reg = cur_inactive->assigned_register();
|
||||
free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection);
|
||||
TRACE("Register %s is free until pos %d (2)\n", RegisterName(cur_reg),
|
||||
Min(free_until_pos[cur_reg], next_intersection).value());
|
||||
}
|
||||
|
||||
int hint_register;
|
||||
@ -2539,10 +2576,11 @@ bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) {
|
||||
}
|
||||
|
||||
// Find the register which stays free for the longest time.
|
||||
int reg = 0;
|
||||
for (int i = 1; i < num_registers(); ++i) {
|
||||
if (free_until_pos[i] > free_until_pos[reg]) {
|
||||
reg = i;
|
||||
int reg = allocatable_register_code(0);
|
||||
for (int i = 1; i < num_allocatable_registers(); ++i) {
|
||||
int code = allocatable_register_code(i);
|
||||
if (free_until_pos[code] > free_until_pos[reg]) {
|
||||
reg = code;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2617,10 +2655,11 @@ void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) {
|
||||
}
|
||||
}
|
||||
|
||||
int reg = 0;
|
||||
for (int i = 1; i < num_registers(); ++i) {
|
||||
if (use_pos[i] > use_pos[reg]) {
|
||||
reg = i;
|
||||
int reg = allocatable_register_code(0);
|
||||
for (int i = 1; i < num_allocatable_registers(); ++i) {
|
||||
int code = allocatable_register_code(i);
|
||||
if (use_pos[code] > use_pos[reg]) {
|
||||
reg = code;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "src/compiler/instruction.h"
|
||||
#include "src/ostreams.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/zone-containers.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -241,15 +242,15 @@ class UsePosition final : public ZoneObject {
|
||||
void set_next(UsePosition* next) { next_ = next; }
|
||||
|
||||
// For hinting only.
|
||||
void set_assigned_register(int register_index) {
|
||||
flags_ = AssignedRegisterField::update(flags_, register_index);
|
||||
void set_assigned_register(int register_code) {
|
||||
flags_ = AssignedRegisterField::update(flags_, register_code);
|
||||
}
|
||||
|
||||
UsePositionHintType hint_type() const {
|
||||
return HintTypeField::decode(flags_);
|
||||
}
|
||||
bool HasHint() const;
|
||||
bool HintRegister(int* register_index) const;
|
||||
bool HintRegister(int* register_code) const;
|
||||
void ResolveHint(UsePosition* use_pos);
|
||||
bool IsResolved() const {
|
||||
return hint_type() != UsePositionHintType::kUnresolved;
|
||||
@ -666,9 +667,9 @@ class RegisterAllocationData final : public ZoneObject {
|
||||
|
||||
// For hinting.
|
||||
int assigned_register() const { return assigned_register_; }
|
||||
void set_assigned_register(int register_index) {
|
||||
void set_assigned_register(int register_code) {
|
||||
DCHECK_EQ(assigned_register_, kUnassignedRegister);
|
||||
assigned_register_ = register_index;
|
||||
assigned_register_ = register_code;
|
||||
}
|
||||
void UnsetAssignedRegister() { assigned_register_ = kUnassignedRegister; }
|
||||
|
||||
@ -769,6 +770,8 @@ class RegisterAllocationData final : public ZoneObject {
|
||||
const char* const debug_name_;
|
||||
const RegisterConfiguration* const config_;
|
||||
PhiMap phi_map_;
|
||||
ZoneVector<int> allocatable_codes_;
|
||||
ZoneVector<int> allocatable_double_codes_;
|
||||
ZoneVector<BitVector*> live_in_sets_;
|
||||
ZoneVector<BitVector*> live_out_sets_;
|
||||
ZoneVector<TopLevelLiveRange*> live_ranges_;
|
||||
@ -886,6 +889,10 @@ class RegisterAllocator : public ZoneObject {
|
||||
InstructionSequence* code() const { return data()->code(); }
|
||||
RegisterKind mode() const { return mode_; }
|
||||
int num_registers() const { return num_registers_; }
|
||||
int num_allocatable_registers() const { return num_allocatable_registers_; }
|
||||
int allocatable_register_code(int allocatable_index) const {
|
||||
return allocatable_register_codes_[allocatable_index];
|
||||
}
|
||||
|
||||
Zone* allocation_zone() const { return data()->allocation_zone(); }
|
||||
|
||||
@ -921,6 +928,8 @@ class RegisterAllocator : public ZoneObject {
|
||||
RegisterAllocationData* const data_;
|
||||
const RegisterKind mode_;
|
||||
const int num_registers_;
|
||||
int num_allocatable_registers_;
|
||||
const int* allocatable_register_codes_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
|
||||
};
|
||||
|
@ -1,76 +0,0 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/register-configuration.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
namespace {
|
||||
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >=
|
||||
Register::kNumRegisters);
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxDoubleRegisters >=
|
||||
DoubleRegister::kMaxNumRegisters);
|
||||
|
||||
class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
|
||||
public:
|
||||
ArchDefaultRegisterConfiguration()
|
||||
: RegisterConfiguration(Register::kMaxNumAllocatableRegisters,
|
||||
#if V8_TARGET_ARCH_X87
|
||||
1,
|
||||
1,
|
||||
#else
|
||||
DoubleRegister::NumAllocatableRegisters(),
|
||||
DoubleRegister::NumAllocatableAliasedRegisters(),
|
||||
#endif
|
||||
general_register_name_table_,
|
||||
double_register_name_table_) {
|
||||
DCHECK_EQ(Register::kMaxNumAllocatableRegisters,
|
||||
Register::NumAllocatableRegisters());
|
||||
for (int i = 0; i < Register::kMaxNumAllocatableRegisters; ++i) {
|
||||
general_register_name_table_[i] = Register::AllocationIndexToString(i);
|
||||
}
|
||||
DCHECK_GE(DoubleRegister::kMaxNumAllocatableRegisters,
|
||||
DoubleRegister::NumAllocatableRegisters());
|
||||
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
|
||||
double_register_name_table_[i] =
|
||||
DoubleRegister::AllocationIndexToString(i);
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
general_register_name_table_[Register::kMaxNumAllocatableRegisters];
|
||||
const char*
|
||||
double_register_name_table_[DoubleRegister::kMaxNumAllocatableRegisters];
|
||||
};
|
||||
|
||||
|
||||
static base::LazyInstance<ArchDefaultRegisterConfiguration>::type
|
||||
kDefaultRegisterConfiguration = LAZY_INSTANCE_INITIALIZER;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
const RegisterConfiguration* RegisterConfiguration::ArchDefault() {
|
||||
return &kDefaultRegisterConfiguration.Get();
|
||||
}
|
||||
|
||||
RegisterConfiguration::RegisterConfiguration(
|
||||
int num_general_registers, int num_double_registers,
|
||||
int num_aliased_double_registers, const char* const* general_register_names,
|
||||
const char* const* double_register_names)
|
||||
: num_general_registers_(num_general_registers),
|
||||
num_double_registers_(num_double_registers),
|
||||
num_aliased_double_registers_(num_aliased_double_registers),
|
||||
general_register_names_(general_register_names),
|
||||
double_register_names_(double_register_names) {}
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -1,56 +0,0 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_COMPILER_REGISTER_CONFIGURATION_H_
|
||||
#define V8_COMPILER_REGISTER_CONFIGURATION_H_
|
||||
|
||||
#include "src/base/macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
// An architecture independent representation of the sets of registers available
|
||||
// for instruction creation.
|
||||
class RegisterConfiguration {
|
||||
public:
|
||||
// Architecture independent maxes.
|
||||
static const int kMaxGeneralRegisters = 32;
|
||||
static const int kMaxDoubleRegisters = 32;
|
||||
|
||||
static const RegisterConfiguration* ArchDefault();
|
||||
|
||||
RegisterConfiguration(int num_general_registers, int num_double_registers,
|
||||
int num_aliased_double_registers,
|
||||
const char* const* general_register_name,
|
||||
const char* const* double_register_name);
|
||||
|
||||
int num_general_registers() const { return num_general_registers_; }
|
||||
int num_double_registers() const { return num_double_registers_; }
|
||||
int num_aliased_double_registers() const {
|
||||
return num_aliased_double_registers_;
|
||||
}
|
||||
|
||||
const char* general_register_name(int offset) const {
|
||||
DCHECK(offset >= 0 && offset < kMaxGeneralRegisters);
|
||||
return general_register_names_[offset];
|
||||
}
|
||||
const char* double_register_name(int offset) const {
|
||||
DCHECK(offset >= 0 && offset < kMaxDoubleRegisters);
|
||||
return double_register_names_[offset];
|
||||
}
|
||||
|
||||
private:
|
||||
const int num_general_registers_;
|
||||
const int num_double_registers_;
|
||||
const int num_aliased_double_registers_;
|
||||
const char* const* general_register_names_;
|
||||
const char* const* double_register_names_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_REGISTER_CONFIGURATION_H_
|
@ -2072,7 +2072,7 @@ void Translation::StoreBoolRegister(Register reg) {
|
||||
|
||||
void Translation::StoreDoubleRegister(DoubleRegister reg) {
|
||||
buffer_->Add(DOUBLE_REGISTER, zone());
|
||||
buffer_->Add(DoubleRegister::ToAllocationIndex(reg), zone());
|
||||
buffer_->Add(reg.code(), zone());
|
||||
}
|
||||
|
||||
|
||||
@ -2925,7 +2925,7 @@ TranslatedValue TranslatedState::CreateNextTranslatedValue(
|
||||
double value = registers->GetDoubleRegister(input_reg);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "%e ; %s (bool)", value,
|
||||
DoubleRegister::AllocationIndexToString(input_reg));
|
||||
DoubleRegister::from_code(input_reg).ToString());
|
||||
}
|
||||
return TranslatedValue::NewDouble(this, value);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/frames-inl.h"
|
||||
#include "src/full-codegen/full-codegen.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/safepoint-table.h"
|
||||
#include "src/scopeinfo.h"
|
||||
#include "src/string-stream.h"
|
||||
@ -658,8 +659,9 @@ void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const {
|
||||
if (safepoint_entry.has_doubles()) {
|
||||
// Number of doubles not known at snapshot time.
|
||||
DCHECK(!isolate()->serializer_enabled());
|
||||
parameters_base += DoubleRegister::NumAllocatableRegisters() *
|
||||
kDoubleSize / kPointerSize;
|
||||
parameters_base += RegisterConfiguration::ArchDefault()
|
||||
->num_allocatable_double_registers() *
|
||||
kDoubleSize / kPointerSize;
|
||||
}
|
||||
|
||||
// Visit the registers that contain pointers if any.
|
||||
|
@ -13526,10 +13526,10 @@ void HTracer::TraceLiveRange(LiveRange* range, const char* type,
|
||||
int assigned_reg = op->index();
|
||||
if (op->IsDoubleRegister()) {
|
||||
trace_.Add(" \"%s\"",
|
||||
DoubleRegister::AllocationIndexToString(assigned_reg));
|
||||
DoubleRegister::from_code(assigned_reg).ToString());
|
||||
} else {
|
||||
DCHECK(op->IsRegister());
|
||||
trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
|
||||
trace_.Add(" \"%s\"", Register::from_code(assigned_reg).ToString());
|
||||
}
|
||||
} else if (range->IsSpilled()) {
|
||||
LOperand* op = range->TopLevel()->GetSpillOperand();
|
||||
|
@ -42,10 +42,48 @@
|
||||
#include "src/assembler.h"
|
||||
#include "src/compiler.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(eax) \
|
||||
V(ecx) \
|
||||
V(edx) \
|
||||
V(ebx) \
|
||||
V(esp) \
|
||||
V(ebp) \
|
||||
V(esi) \
|
||||
V(edi)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(eax) \
|
||||
V(ecx) \
|
||||
V(edx) \
|
||||
V(ebx) \
|
||||
V(esi) \
|
||||
V(edi)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(xmm0) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7)
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum, but enum values are assignment-
|
||||
@ -68,151 +106,86 @@ namespace internal {
|
||||
// and best performance in optimized code.
|
||||
//
|
||||
struct Register {
|
||||
static const int kMaxNumAllocatableRegisters = 6;
|
||||
static int NumAllocatableRegisters() {
|
||||
return kMaxNumAllocatableRegisters;
|
||||
}
|
||||
static const int kNumRegisters = 8;
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static inline const char* AllocationIndexToString(int index);
|
||||
|
||||
static inline int ToAllocationIndex(Register reg);
|
||||
|
||||
static inline Register FromAllocationIndex(int index);
|
||||
static const int kNumRegisters = Code::kAfterLast;
|
||||
|
||||
static Register from_code(int code) {
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kNumRegisters);
|
||||
Register r = { code };
|
||||
Register r = {code};
|
||||
return r;
|
||||
}
|
||||
bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
|
||||
bool is(Register reg) const { return code_ == reg.code_; }
|
||||
// eax, ebx, ecx and edx are byte registers, the rest are not.
|
||||
bool is_byte_register() const { return code_ <= 3; }
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
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 code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
bool is_byte_register() const { return reg_code <= 3; }
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
const int kRegister_eax_Code = 0;
|
||||
const int kRegister_ecx_Code = 1;
|
||||
const int kRegister_edx_Code = 2;
|
||||
const int kRegister_ebx_Code = 3;
|
||||
const int kRegister_esp_Code = 4;
|
||||
const int kRegister_ebp_Code = 5;
|
||||
const int kRegister_esi_Code = 6;
|
||||
const int kRegister_edi_Code = 7;
|
||||
const int kRegister_no_reg_Code = -1;
|
||||
|
||||
const Register eax = { kRegister_eax_Code };
|
||||
const Register ecx = { kRegister_ecx_Code };
|
||||
const Register edx = { kRegister_edx_Code };
|
||||
const Register ebx = { kRegister_ebx_Code };
|
||||
const Register esp = { kRegister_esp_Code };
|
||||
const Register ebp = { kRegister_ebp_Code };
|
||||
const Register esi = { kRegister_esi_Code };
|
||||
const Register edi = { kRegister_edi_Code };
|
||||
const Register no_reg = { kRegister_no_reg_Code };
|
||||
#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
const Register no_reg = {Register::kCode_no_reg};
|
||||
|
||||
|
||||
inline const char* Register::AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
// This is the mapping of allocation indices to registers.
|
||||
const char* const kNames[] = { "eax", "ecx", "edx", "ebx", "esi", "edi" };
|
||||
return kNames[index];
|
||||
}
|
||||
struct DoubleRegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static const int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
inline int Register::ToAllocationIndex(Register reg) {
|
||||
DCHECK(reg.is_valid() && !reg.is(esp) && !reg.is(ebp));
|
||||
return (reg.code() >= 6) ? reg.code() - 2 : reg.code();
|
||||
}
|
||||
|
||||
|
||||
inline Register Register::FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
return (index >= 4) ? from_code(index + 2) : from_code(index);
|
||||
}
|
||||
|
||||
|
||||
struct XMMRegister {
|
||||
static const int kMaxNumAllocatableRegisters = 7;
|
||||
static const int kMaxNumRegisters = 8;
|
||||
static int NumAllocatableRegisters() {
|
||||
return kMaxNumAllocatableRegisters;
|
||||
}
|
||||
|
||||
// TODO(turbofan): Proper support for float32.
|
||||
static int NumAllocatableAliasedRegisters() {
|
||||
return NumAllocatableRegisters();
|
||||
}
|
||||
|
||||
static int ToAllocationIndex(XMMRegister reg) {
|
||||
DCHECK(reg.code() != 0);
|
||||
return reg.code() - 1;
|
||||
}
|
||||
|
||||
static XMMRegister FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
return from_code(index + 1);
|
||||
}
|
||||
|
||||
static XMMRegister from_code(int code) {
|
||||
XMMRegister result = { code };
|
||||
static DoubleRegister from_code(int code) {
|
||||
DoubleRegister result = {code};
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return 0 <= code_ && code_ < kMaxNumRegisters;
|
||||
}
|
||||
bool IsAllocatable() const;
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return code_;
|
||||
return reg_code;
|
||||
}
|
||||
|
||||
bool is(XMMRegister reg) const { return code_ == reg.code_; }
|
||||
bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
|
||||
|
||||
static const char* AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
const char* const names[] = {
|
||||
"xmm1",
|
||||
"xmm2",
|
||||
"xmm3",
|
||||
"xmm4",
|
||||
"xmm5",
|
||||
"xmm6",
|
||||
"xmm7"
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
const char* ToString();
|
||||
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
#define DECLARE_REGISTER(R) \
|
||||
const DoubleRegister R = {DoubleRegister::kCode_##R};
|
||||
DOUBLE_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
const DoubleRegister no_double_reg = {DoubleRegister::kCode_no_reg};
|
||||
|
||||
typedef XMMRegister DoubleRegister;
|
||||
|
||||
|
||||
const XMMRegister xmm0 = { 0 };
|
||||
const XMMRegister xmm1 = { 1 };
|
||||
const XMMRegister xmm2 = { 2 };
|
||||
const XMMRegister xmm3 = { 3 };
|
||||
const XMMRegister xmm4 = { 4 };
|
||||
const XMMRegister xmm5 = { 5 };
|
||||
const XMMRegister xmm6 = { 6 };
|
||||
const XMMRegister xmm7 = { 7 };
|
||||
const XMMRegister no_xmm_reg = { -1 };
|
||||
|
||||
typedef DoubleRegister XMMRegister;
|
||||
|
||||
enum Condition {
|
||||
// any value < 0 is considered no_condition
|
||||
|
@ -320,13 +320,15 @@ class RecordWriteStub: public PlatformCodeStub {
|
||||
Register GetRegThatIsNotEcxOr(Register r1,
|
||||
Register r2,
|
||||
Register r3) {
|
||||
for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
|
||||
Register candidate = Register::FromAllocationIndex(i);
|
||||
if (candidate.is(ecx)) continue;
|
||||
if (candidate.is(r1)) continue;
|
||||
if (candidate.is(r2)) continue;
|
||||
if (candidate.is(r3)) continue;
|
||||
return candidate;
|
||||
for (int i = 0; i < Register::kNumRegisters; i++) {
|
||||
Register candidate = Register::from_code(i);
|
||||
if (candidate.IsAllocatable()) {
|
||||
if (candidate.is(ecx)) continue;
|
||||
if (candidate.is(r1)) continue;
|
||||
if (candidate.is(r2)) continue;
|
||||
if (candidate.is(r3)) continue;
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return no_reg;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/full-codegen/full-codegen.h"
|
||||
#include "src/ia32/frames-ia32.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/safepoint-table.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -181,7 +182,7 @@ void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
|
||||
}
|
||||
input_->SetRegister(esp.code(), reinterpret_cast<intptr_t>(frame->sp()));
|
||||
input_->SetRegister(ebp.code(), reinterpret_cast<intptr_t>(frame->fp()));
|
||||
for (int i = 0; i < XMMRegister::kMaxNumAllocatableRegisters; i++) {
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
input_->SetDoubleRegister(i, 0.0);
|
||||
}
|
||||
|
||||
@ -203,7 +204,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < XMMRegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
@ -233,12 +234,13 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
// Save all general purpose registers before messing with them.
|
||||
const int kNumberOfRegisters = Register::kNumRegisters;
|
||||
|
||||
const int kDoubleRegsSize = kDoubleSize *
|
||||
XMMRegister::kMaxNumAllocatableRegisters;
|
||||
const int kDoubleRegsSize = kDoubleSize * XMMRegister::kMaxNumRegisters;
|
||||
__ sub(esp, Immediate(kDoubleRegsSize));
|
||||
for (int i = 0; i < XMMRegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i);
|
||||
int offset = i * kDoubleSize;
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
XMMRegister xmm_reg = XMMRegister::from_code(code);
|
||||
int offset = code * kDoubleSize;
|
||||
__ movsd(Operand(esp, offset), xmm_reg);
|
||||
}
|
||||
|
||||
@ -288,9 +290,10 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
|
||||
int double_regs_offset = FrameDescription::double_registers_offset();
|
||||
// Fill in the double input registers.
|
||||
for (int i = 0; i < XMMRegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
int dst_offset = i * kDoubleSize + double_regs_offset;
|
||||
int src_offset = i * kDoubleSize;
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
int dst_offset = code * kDoubleSize + double_regs_offset;
|
||||
int src_offset = code * kDoubleSize;
|
||||
__ movsd(xmm0, Operand(esp, src_offset));
|
||||
__ movsd(Operand(ebx, dst_offset), xmm0);
|
||||
}
|
||||
@ -371,9 +374,10 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
__ j(below, &outer_push_loop);
|
||||
|
||||
// In case of a failed STUB, we have to restore the XMM registers.
|
||||
for (int i = 0; i < XMMRegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i);
|
||||
int src_offset = i * kDoubleSize + double_regs_offset;
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
XMMRegister xmm_reg = XMMRegister::from_code(code);
|
||||
int src_offset = code * kDoubleSize + double_regs_offset;
|
||||
__ movsd(xmm_reg, Operand(ebx, src_offset));
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ void LCodeGen::SaveCallerDoubles() {
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
while (!save_iterator.Done()) {
|
||||
__ movsd(MemOperand(esp, count * kDoubleSize),
|
||||
XMMRegister::FromAllocationIndex(save_iterator.Current()));
|
||||
XMMRegister::from_code(save_iterator.Current()));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
}
|
||||
@ -116,8 +116,8 @@ void LCodeGen::RestoreCallerDoubles() {
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
int count = 0;
|
||||
while (!save_iterator.Done()) {
|
||||
__ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()),
|
||||
MemOperand(esp, count * kDoubleSize));
|
||||
__ movsd(XMMRegister::from_code(save_iterator.Current()),
|
||||
MemOperand(esp, count * kDoubleSize));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
}
|
||||
@ -514,13 +514,13 @@ bool LCodeGen::GenerateSafepointTable() {
|
||||
}
|
||||
|
||||
|
||||
Register LCodeGen::ToRegister(int index) const {
|
||||
return Register::FromAllocationIndex(index);
|
||||
Register LCodeGen::ToRegister(int code) const {
|
||||
return Register::from_code(code);
|
||||
}
|
||||
|
||||
|
||||
XMMRegister LCodeGen::ToDoubleRegister(int index) const {
|
||||
return XMMRegister::FromAllocationIndex(index);
|
||||
XMMRegister LCodeGen::ToDoubleRegister(int code) const {
|
||||
return XMMRegister::from_code(code);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "src/ia32/lithium-codegen-ia32.h"
|
||||
#include "src/ia32/lithium-gap-resolver-ia32.h"
|
||||
#include "src/register-configuration.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -165,10 +166,13 @@ int LGapResolver::CountSourceUses(LOperand* operand) {
|
||||
|
||||
|
||||
Register LGapResolver::GetFreeRegisterNot(Register reg) {
|
||||
int skip_index = reg.is(no_reg) ? -1 : Register::ToAllocationIndex(reg);
|
||||
for (int i = 0; i < Register::NumAllocatableRegisters(); ++i) {
|
||||
if (source_uses_[i] == 0 && destination_uses_[i] > 0 && i != skip_index) {
|
||||
return Register::FromAllocationIndex(i);
|
||||
int skip_index = reg.is(no_reg) ? -1 : reg.code();
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
|
||||
int code = config->GetAllocatableGeneralCode(i);
|
||||
if (source_uses_[code] == 0 && destination_uses_[code] > 0 &&
|
||||
code != skip_index) {
|
||||
return Register::from_code(code);
|
||||
}
|
||||
}
|
||||
return no_reg;
|
||||
@ -178,10 +182,11 @@ Register LGapResolver::GetFreeRegisterNot(Register reg) {
|
||||
bool LGapResolver::HasBeenReset() {
|
||||
if (!moves_.is_empty()) return false;
|
||||
if (spilled_register_ >= 0) return false;
|
||||
|
||||
for (int i = 0; i < Register::NumAllocatableRegisters(); ++i) {
|
||||
if (source_uses_[i] != 0) return false;
|
||||
if (destination_uses_[i] != 0) return false;
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
|
||||
int code = config->GetAllocatableGeneralCode(i);
|
||||
if (source_uses_[code] != 0) return false;
|
||||
if (destination_uses_[code] != 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -204,7 +209,7 @@ void LGapResolver::Verify() {
|
||||
|
||||
void LGapResolver::Finish() {
|
||||
if (spilled_register_ >= 0) {
|
||||
__ pop(Register::FromAllocationIndex(spilled_register_));
|
||||
__ pop(Register::from_code(spilled_register_));
|
||||
spilled_register_ = -1;
|
||||
}
|
||||
moves_.Rewind(0);
|
||||
@ -213,7 +218,7 @@ void LGapResolver::Finish() {
|
||||
|
||||
void LGapResolver::EnsureRestored(LOperand* operand) {
|
||||
if (operand->IsRegister() && operand->index() == spilled_register_) {
|
||||
__ pop(Register::FromAllocationIndex(spilled_register_));
|
||||
__ pop(Register::from_code(spilled_register_));
|
||||
spilled_register_ = -1;
|
||||
}
|
||||
}
|
||||
@ -222,7 +227,7 @@ void LGapResolver::EnsureRestored(LOperand* operand) {
|
||||
Register LGapResolver::EnsureTempRegister() {
|
||||
// 1. We may have already spilled to create a temp register.
|
||||
if (spilled_register_ >= 0) {
|
||||
return Register::FromAllocationIndex(spilled_register_);
|
||||
return Register::from_code(spilled_register_);
|
||||
}
|
||||
|
||||
// 2. We may have a free register that we can use without spilling.
|
||||
@ -231,19 +236,21 @@ Register LGapResolver::EnsureTempRegister() {
|
||||
|
||||
// 3. Prefer to spill a register that is not used in any remaining move
|
||||
// because it will not need to be restored until the end.
|
||||
for (int i = 0; i < Register::NumAllocatableRegisters(); ++i) {
|
||||
if (source_uses_[i] == 0 && destination_uses_[i] == 0) {
|
||||
Register scratch = Register::FromAllocationIndex(i);
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
|
||||
int code = config->GetAllocatableGeneralCode(i);
|
||||
if (source_uses_[code] == 0 && destination_uses_[code] == 0) {
|
||||
Register scratch = Register::from_code(code);
|
||||
__ push(scratch);
|
||||
spilled_register_ = i;
|
||||
spilled_register_ = code;
|
||||
return scratch;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Use an arbitrary register. Register 0 is as arbitrary as any other.
|
||||
Register scratch = Register::FromAllocationIndex(0);
|
||||
spilled_register_ = config->GetAllocatableGeneralCode(0);
|
||||
Register scratch = Register::from_code(spilled_register_);
|
||||
__ push(scratch);
|
||||
spilled_register_ = 0;
|
||||
return scratch;
|
||||
}
|
||||
|
||||
|
@ -72,8 +72,8 @@ class LGapResolver final BASE_EMBEDDED {
|
||||
ZoneList<LMoveOperands> moves_;
|
||||
|
||||
// Source and destination use counts for the general purpose registers.
|
||||
int source_uses_[Register::kMaxNumAllocatableRegisters];
|
||||
int destination_uses_[Register::kMaxNumAllocatableRegisters];
|
||||
int source_uses_[Register::kNumRegisters];
|
||||
int destination_uses_[DoubleRegister::kMaxNumRegisters];
|
||||
|
||||
// If we had to spill on demand, the currently spilled register's
|
||||
// allocation index.
|
||||
|
@ -482,14 +482,13 @@ LPlatformChunk* LChunkBuilder::Build() {
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
|
||||
Register::ToAllocationIndex(reg));
|
||||
return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
|
||||
XMMRegister::ToAllocationIndex(reg));
|
||||
return new (zone())
|
||||
LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,17 +14,17 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
const Register kReturnRegister0 = {kRegister_eax_Code};
|
||||
const Register kReturnRegister1 = {kRegister_edx_Code};
|
||||
const Register kJSFunctionRegister = {kRegister_edi_Code};
|
||||
const Register kContextRegister = {kRegister_esi_Code};
|
||||
const Register kInterpreterAccumulatorRegister = {kRegister_eax_Code};
|
||||
const Register kInterpreterRegisterFileRegister = {kRegister_edx_Code};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_ecx_Code};
|
||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_edi_Code};
|
||||
const Register kInterpreterDispatchTableRegister = {kRegister_ebx_Code};
|
||||
const Register kRuntimeCallFunctionRegister = {kRegister_ebx_Code};
|
||||
const Register kRuntimeCallArgCountRegister = {kRegister_eax_Code};
|
||||
const Register kReturnRegister0 = {Register::kCode_eax};
|
||||
const Register kReturnRegister1 = {Register::kCode_edx};
|
||||
const Register kJSFunctionRegister = {Register::kCode_edi};
|
||||
const Register kContextRegister = {Register::kCode_esi};
|
||||
const Register kInterpreterAccumulatorRegister = {Register::kCode_eax};
|
||||
const Register kInterpreterRegisterFileRegister = {Register::kCode_edx};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_ecx};
|
||||
const Register kInterpreterBytecodeArrayRegister = {Register::kCode_edi};
|
||||
const Register kInterpreterDispatchTableRegister = {Register::kCode_ebx};
|
||||
const Register kRuntimeCallFunctionRegister = {Register::kCode_ebx};
|
||||
const Register kRuntimeCallArgCountRegister = {Register::kCode_eax};
|
||||
|
||||
// Spill slots used by interpreter dispatch calling convention.
|
||||
const int kInterpreterContextSpillSlot = -1;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "src/hydrogen.h"
|
||||
#include "src/lithium-inl.h"
|
||||
#include "src/lithium-allocator-inl.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/string-stream.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -585,7 +586,7 @@ void LAllocator::AddInitialIntervals(HBasicBlock* block,
|
||||
|
||||
|
||||
int LAllocator::FixedDoubleLiveRangeID(int index) {
|
||||
return -index - 1 - Register::kMaxNumAllocatableRegisters;
|
||||
return -index - 1 - Register::kNumRegisters;
|
||||
}
|
||||
|
||||
|
||||
@ -617,7 +618,7 @@ LOperand* LAllocator::AllocateFixed(LUnallocated* operand,
|
||||
|
||||
|
||||
LiveRange* LAllocator::FixedLiveRangeFor(int index) {
|
||||
DCHECK(index < Register::kMaxNumAllocatableRegisters);
|
||||
DCHECK(index < Register::kNumRegisters);
|
||||
LiveRange* result = fixed_live_ranges_[index];
|
||||
if (result == NULL) {
|
||||
result = new(zone()) LiveRange(FixedLiveRangeID(index), chunk()->zone());
|
||||
@ -631,7 +632,7 @@ LiveRange* LAllocator::FixedLiveRangeFor(int index) {
|
||||
|
||||
|
||||
LiveRange* LAllocator::FixedDoubleLiveRangeFor(int index) {
|
||||
DCHECK(index < DoubleRegister::NumAllocatableRegisters());
|
||||
DCHECK(index < DoubleRegister::kMaxNumRegisters);
|
||||
LiveRange* result = fixed_double_live_ranges_[index];
|
||||
if (result == NULL) {
|
||||
result = new(zone()) LiveRange(FixedDoubleLiveRangeID(index),
|
||||
@ -939,25 +940,27 @@ void LAllocator::ProcessInstructions(HBasicBlock* block, BitVector* live) {
|
||||
}
|
||||
|
||||
if (instr->ClobbersRegisters()) {
|
||||
for (int i = 0; i < Register::kMaxNumAllocatableRegisters; ++i) {
|
||||
if (output == NULL || !output->IsRegister() ||
|
||||
output->index() != i) {
|
||||
LiveRange* range = FixedLiveRangeFor(i);
|
||||
range->AddUseInterval(curr_position,
|
||||
curr_position.InstructionEnd(),
|
||||
zone());
|
||||
for (int i = 0; i < Register::kNumRegisters; ++i) {
|
||||
if (Register::from_code(i).IsAllocatable()) {
|
||||
if (output == NULL || !output->IsRegister() ||
|
||||
output->index() != i) {
|
||||
LiveRange* range = FixedLiveRangeFor(i);
|
||||
range->AddUseInterval(curr_position,
|
||||
curr_position.InstructionEnd(), zone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (instr->ClobbersDoubleRegisters(isolate())) {
|
||||
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
|
||||
if (output == NULL || !output->IsDoubleRegister() ||
|
||||
output->index() != i) {
|
||||
LiveRange* range = FixedDoubleLiveRangeFor(i);
|
||||
range->AddUseInterval(curr_position,
|
||||
curr_position.InstructionEnd(),
|
||||
zone());
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; ++i) {
|
||||
if (DoubleRegister::from_code(i).IsAllocatable()) {
|
||||
if (output == NULL || !output->IsDoubleRegister() ||
|
||||
output->index() != i) {
|
||||
LiveRange* range = FixedDoubleLiveRangeFor(i);
|
||||
range->AddUseInterval(curr_position,
|
||||
curr_position.InstructionEnd(), zone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1069,11 +1072,9 @@ bool LAllocator::Allocate(LChunk* chunk) {
|
||||
DCHECK(chunk_ == NULL);
|
||||
chunk_ = static_cast<LPlatformChunk*>(chunk);
|
||||
assigned_registers_ =
|
||||
new(chunk->zone()) BitVector(Register::NumAllocatableRegisters(),
|
||||
chunk->zone());
|
||||
assigned_double_registers_ =
|
||||
new(chunk->zone()) BitVector(DoubleRegister::NumAllocatableRegisters(),
|
||||
chunk->zone());
|
||||
new (chunk->zone()) BitVector(Register::kNumRegisters, chunk->zone());
|
||||
assigned_double_registers_ = new (chunk->zone())
|
||||
BitVector(DoubleRegister::kMaxNumRegisters, chunk->zone());
|
||||
MeetRegisterConstraints();
|
||||
if (!AllocationOk()) return false;
|
||||
ResolvePhis();
|
||||
@ -1460,7 +1461,10 @@ void LAllocator::PopulatePointerMaps() {
|
||||
|
||||
void LAllocator::AllocateGeneralRegisters() {
|
||||
LAllocatorPhase phase("L_Allocate general registers", this);
|
||||
num_registers_ = Register::NumAllocatableRegisters();
|
||||
num_registers_ =
|
||||
RegisterConfiguration::ArchDefault()->num_allocatable_general_registers();
|
||||
allocatable_register_codes_ =
|
||||
RegisterConfiguration::ArchDefault()->allocatable_general_codes();
|
||||
mode_ = GENERAL_REGISTERS;
|
||||
AllocateRegisters();
|
||||
}
|
||||
@ -1468,7 +1472,10 @@ void LAllocator::AllocateGeneralRegisters() {
|
||||
|
||||
void LAllocator::AllocateDoubleRegisters() {
|
||||
LAllocatorPhase phase("L_Allocate double registers", this);
|
||||
num_registers_ = DoubleRegister::NumAllocatableRegisters();
|
||||
num_registers_ =
|
||||
RegisterConfiguration::ArchDefault()->num_allocatable_double_registers();
|
||||
allocatable_register_codes_ =
|
||||
RegisterConfiguration::ArchDefault()->allocatable_double_codes();
|
||||
mode_ = DOUBLE_REGISTERS;
|
||||
AllocateRegisters();
|
||||
}
|
||||
@ -1492,7 +1499,7 @@ void LAllocator::AllocateRegisters() {
|
||||
DCHECK(inactive_live_ranges_.is_empty());
|
||||
|
||||
if (mode_ == DOUBLE_REGISTERS) {
|
||||
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
|
||||
for (int i = 0; i < fixed_double_live_ranges_.length(); ++i) {
|
||||
LiveRange* current = fixed_double_live_ranges_.at(i);
|
||||
if (current != NULL) {
|
||||
AddToInactive(current);
|
||||
@ -1586,9 +1593,9 @@ void LAllocator::AllocateRegisters() {
|
||||
|
||||
const char* LAllocator::RegisterName(int allocation_index) {
|
||||
if (mode_ == GENERAL_REGISTERS) {
|
||||
return Register::AllocationIndexToString(allocation_index);
|
||||
return Register::from_code(allocation_index).ToString();
|
||||
} else {
|
||||
return DoubleRegister::AllocationIndexToString(allocation_index);
|
||||
return DoubleRegister::from_code(allocation_index).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1750,16 +1757,12 @@ void LAllocator::InactiveToActive(LiveRange* range) {
|
||||
}
|
||||
|
||||
|
||||
// TryAllocateFreeReg and AllocateBlockedReg assume this
|
||||
// when allocating local arrays.
|
||||
STATIC_ASSERT(DoubleRegister::kMaxNumAllocatableRegisters >=
|
||||
Register::kMaxNumAllocatableRegisters);
|
||||
|
||||
|
||||
bool LAllocator::TryAllocateFreeReg(LiveRange* current) {
|
||||
LifetimePosition free_until_pos[DoubleRegister::kMaxNumAllocatableRegisters];
|
||||
DCHECK(DoubleRegister::kMaxNumRegisters >= Register::kNumRegisters);
|
||||
|
||||
for (int i = 0; i < num_registers_; i++) {
|
||||
LifetimePosition free_until_pos[DoubleRegister::kMaxNumRegisters];
|
||||
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; i++) {
|
||||
free_until_pos[i] = LifetimePosition::MaxPosition();
|
||||
}
|
||||
|
||||
@ -1800,10 +1803,11 @@ bool LAllocator::TryAllocateFreeReg(LiveRange* current) {
|
||||
}
|
||||
|
||||
// Find the register which stays free for the longest time.
|
||||
int reg = 0;
|
||||
int reg = allocatable_register_codes_[0];
|
||||
for (int i = 1; i < RegisterCount(); ++i) {
|
||||
if (free_until_pos[i].Value() > free_until_pos[reg].Value()) {
|
||||
reg = i;
|
||||
int code = allocatable_register_codes_[i];
|
||||
if (free_until_pos[code].Value() > free_until_pos[reg].Value()) {
|
||||
reg = code;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1845,10 +1849,10 @@ void LAllocator::AllocateBlockedReg(LiveRange* current) {
|
||||
}
|
||||
|
||||
|
||||
LifetimePosition use_pos[DoubleRegister::kMaxNumAllocatableRegisters];
|
||||
LifetimePosition block_pos[DoubleRegister::kMaxNumAllocatableRegisters];
|
||||
LifetimePosition use_pos[DoubleRegister::kMaxNumRegisters];
|
||||
LifetimePosition block_pos[DoubleRegister::kMaxNumRegisters];
|
||||
|
||||
for (int i = 0; i < num_registers_; i++) {
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; i++) {
|
||||
use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
|
||||
}
|
||||
|
||||
@ -1883,10 +1887,11 @@ void LAllocator::AllocateBlockedReg(LiveRange* current) {
|
||||
}
|
||||
}
|
||||
|
||||
int reg = 0;
|
||||
int reg = allocatable_register_codes_[0];
|
||||
for (int i = 1; i < RegisterCount(); ++i) {
|
||||
if (use_pos[i].Value() > use_pos[reg].Value()) {
|
||||
reg = i;
|
||||
int code = allocatable_register_codes_[i];
|
||||
if (use_pos[code].Value() > use_pos[reg].Value()) {
|
||||
reg = code;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,9 +520,8 @@ class LAllocator BASE_EMBEDDED {
|
||||
ZoneList<LiveRange*> live_ranges_;
|
||||
|
||||
// Lists of live ranges
|
||||
EmbeddedVector<LiveRange*, Register::kMaxNumAllocatableRegisters>
|
||||
fixed_live_ranges_;
|
||||
EmbeddedVector<LiveRange*, DoubleRegister::kMaxNumAllocatableRegisters>
|
||||
EmbeddedVector<LiveRange*, Register::kNumRegisters> fixed_live_ranges_;
|
||||
EmbeddedVector<LiveRange*, DoubleRegister::kMaxNumRegisters>
|
||||
fixed_double_live_ranges_;
|
||||
ZoneList<LiveRange*> unhandled_live_ranges_;
|
||||
ZoneList<LiveRange*> active_live_ranges_;
|
||||
@ -536,6 +535,7 @@ class LAllocator BASE_EMBEDDED {
|
||||
|
||||
RegisterKind mode_;
|
||||
int num_registers_;
|
||||
const int* allocatable_register_codes_;
|
||||
|
||||
BitVector* assigned_registers_;
|
||||
BitVector* assigned_double_registers_;
|
||||
|
@ -56,24 +56,22 @@ void LOperand::PrintTo(StringStream* stream) {
|
||||
break;
|
||||
case LUnallocated::FIXED_REGISTER: {
|
||||
int reg_index = unalloc->fixed_register_index();
|
||||
if (reg_index < 0 ||
|
||||
reg_index >= Register::kMaxNumAllocatableRegisters) {
|
||||
if (reg_index < 0 || reg_index >= Register::kNumRegisters) {
|
||||
stream->Add("(=invalid_reg#%d)", reg_index);
|
||||
} else {
|
||||
const char* register_name =
|
||||
Register::AllocationIndexToString(reg_index);
|
||||
Register::from_code(reg_index).ToString();
|
||||
stream->Add("(=%s)", register_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LUnallocated::FIXED_DOUBLE_REGISTER: {
|
||||
int reg_index = unalloc->fixed_register_index();
|
||||
if (reg_index < 0 ||
|
||||
reg_index >= DoubleRegister::kMaxNumAllocatableRegisters) {
|
||||
if (reg_index < 0 || reg_index >= DoubleRegister::kMaxNumRegisters) {
|
||||
stream->Add("(=invalid_double_reg#%d)", reg_index);
|
||||
} else {
|
||||
const char* double_register_name =
|
||||
DoubleRegister::AllocationIndexToString(reg_index);
|
||||
DoubleRegister::from_code(reg_index).ToString();
|
||||
stream->Add("(=%s)", double_register_name);
|
||||
}
|
||||
break;
|
||||
@ -106,21 +104,19 @@ void LOperand::PrintTo(StringStream* stream) {
|
||||
break;
|
||||
case REGISTER: {
|
||||
int reg_index = index();
|
||||
if (reg_index < 0 || reg_index >= Register::kMaxNumAllocatableRegisters) {
|
||||
if (reg_index < 0 || reg_index >= Register::kNumRegisters) {
|
||||
stream->Add("(=invalid_reg#%d|R)", reg_index);
|
||||
} else {
|
||||
stream->Add("[%s|R]", Register::AllocationIndexToString(reg_index));
|
||||
stream->Add("[%s|R]", Register::from_code(reg_index).ToString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DOUBLE_REGISTER: {
|
||||
int reg_index = index();
|
||||
if (reg_index < 0 ||
|
||||
reg_index >= DoubleRegister::kMaxNumAllocatableRegisters) {
|
||||
if (reg_index < 0 || reg_index >= DoubleRegister::kMaxNumRegisters) {
|
||||
stream->Add("(=invalid_double_reg#%d|R)", reg_index);
|
||||
} else {
|
||||
stream->Add("[%s|R]",
|
||||
DoubleRegister::AllocationIndexToString(reg_index));
|
||||
stream->Add("[%s|R]", DoubleRegister::from_code(reg_index).ToString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -84,36 +84,6 @@ bool Operand::is_reg() const {
|
||||
}
|
||||
|
||||
|
||||
int Register::NumAllocatableRegisters() {
|
||||
return kMaxNumAllocatableRegisters;
|
||||
}
|
||||
|
||||
|
||||
int DoubleRegister::NumRegisters() {
|
||||
return FPURegister::kMaxNumRegisters;
|
||||
}
|
||||
|
||||
|
||||
int DoubleRegister::NumAllocatableRegisters() {
|
||||
return FPURegister::kMaxNumAllocatableRegisters;
|
||||
}
|
||||
|
||||
|
||||
int DoubleRegister::NumAllocatableAliasedRegisters() {
|
||||
return NumAllocatableRegisters();
|
||||
}
|
||||
|
||||
|
||||
int FPURegister::ToAllocationIndex(FPURegister reg) {
|
||||
DCHECK(reg.code() % 2 == 0);
|
||||
DCHECK(reg.code() / 2 < kMaxNumAllocatableRegisters);
|
||||
DCHECK(reg.is_valid());
|
||||
DCHECK(!reg.is(kDoubleRegZero));
|
||||
DCHECK(!reg.is(kLithiumScratchDouble));
|
||||
return (reg.code() / 2);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RelocInfo.
|
||||
|
||||
|
@ -64,28 +64,6 @@ static unsigned CpuFeaturesImpliedByCompiler() {
|
||||
}
|
||||
|
||||
|
||||
const char* DoubleRegister::AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
const char* const names[] = {
|
||||
"f0",
|
||||
"f2",
|
||||
"f4",
|
||||
"f6",
|
||||
"f8",
|
||||
"f10",
|
||||
"f12",
|
||||
"f14",
|
||||
"f16",
|
||||
"f18",
|
||||
"f20",
|
||||
"f22",
|
||||
"f24",
|
||||
"f26"
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
|
||||
|
||||
void CpuFeatures::ProbeImpl(bool cross_compile) {
|
||||
supported_ |= CpuFeaturesImpliedByCompiler();
|
||||
|
||||
@ -250,31 +228,31 @@ MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
|
||||
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 | (kRegister_sp_Code << kRsShift)
|
||||
| (kRegister_sp_Code << kRtShift)
|
||||
| (kPointerSize & kImm16Mask); // NOLINT
|
||||
const Instr kPopInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
|
||||
(Register::kCode_sp << kRtShift) |
|
||||
(kPointerSize & kImm16Mask); // NOLINT
|
||||
// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
|
||||
const Instr kPushInstruction = ADDIU | (kRegister_sp_Code << kRsShift)
|
||||
| (kRegister_sp_Code << kRtShift)
|
||||
| (-kPointerSize & kImm16Mask); // NOLINT
|
||||
const Instr kPushInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
|
||||
(Register::kCode_sp << kRtShift) |
|
||||
(-kPointerSize & kImm16Mask); // NOLINT
|
||||
// sw(r, MemOperand(sp, 0))
|
||||
const Instr kPushRegPattern = SW | (kRegister_sp_Code << kRsShift)
|
||||
| (0 & kImm16Mask); // NOLINT
|
||||
const Instr kPushRegPattern =
|
||||
SW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
// lw(r, MemOperand(sp, 0))
|
||||
const Instr kPopRegPattern = LW | (kRegister_sp_Code << kRsShift)
|
||||
| (0 & kImm16Mask); // NOLINT
|
||||
const Instr kPopRegPattern =
|
||||
LW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kLwRegFpOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
|
||||
| (0 & kImm16Mask); // NOLINT
|
||||
const Instr kLwRegFpOffsetPattern =
|
||||
LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kSwRegFpOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
|
||||
| (0 & kImm16Mask); // NOLINT
|
||||
const Instr kSwRegFpOffsetPattern =
|
||||
SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kLwRegFpNegOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
|
||||
| (kNegOffset & kImm16Mask); // NOLINT
|
||||
const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
|
||||
(kNegOffset & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kSwRegFpNegOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
|
||||
| (kNegOffset & kImm16Mask); // NOLINT
|
||||
const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
|
||||
(kNegOffset & kImm16Mask); // NOLINT
|
||||
// A mask for the Rt register for push, pop, lw, sw instructions.
|
||||
const Instr kRtMask = kRtFieldMask;
|
||||
const Instr kLwSwInstrTypeMask = 0xffe00000;
|
||||
@ -334,21 +312,21 @@ void Assembler::CodeTargetAlign() {
|
||||
|
||||
Register Assembler::GetRtReg(Instr instr) {
|
||||
Register rt;
|
||||
rt.code_ = (instr & kRtFieldMask) >> kRtShift;
|
||||
rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
|
||||
return rt;
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRsReg(Instr instr) {
|
||||
Register rs;
|
||||
rs.code_ = (instr & kRsFieldMask) >> kRsShift;
|
||||
rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
|
||||
return rs;
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRdReg(Instr instr) {
|
||||
Register rd;
|
||||
rd.code_ = (instr & kRdFieldMask) >> kRdShift;
|
||||
rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
|
||||
return rd;
|
||||
}
|
||||
|
||||
@ -1942,14 +1920,14 @@ void Assembler::movn(Register rd, Register rs, Register rt) {
|
||||
|
||||
void Assembler::movt(Register rd, Register rs, uint16_t cc) {
|
||||
Register rt;
|
||||
rt.code_ = (cc & 0x0007) << 2 | 1;
|
||||
rt.reg_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.code_ = (cc & 0x0007) << 2 | 0;
|
||||
rt.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
|
||||
}
|
||||
|
||||
@ -2233,7 +2211,7 @@ void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
|
||||
void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r2));
|
||||
FPURegister ft;
|
||||
ft.code_ = (cc & 0x0007) << 2 | 1;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
@ -2241,7 +2219,7 @@ void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r2));
|
||||
FPURegister ft;
|
||||
ft.code_ = (cc & 0x0007) << 2 | 1;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
@ -2249,7 +2227,7 @@ void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r2));
|
||||
FPURegister ft;
|
||||
ft.code_ = (cc & 0x0007) << 2 | 0;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
@ -2257,7 +2235,7 @@ void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r2));
|
||||
FPURegister ft;
|
||||
ft.code_ = (cc & 0x0007) << 2 | 0;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,28 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
|
||||
V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(t7) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
|
||||
V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
|
||||
V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(s7)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
|
||||
V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
|
||||
V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
|
||||
V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
|
||||
V(f16) V(f18) V(f20) V(f22) V(f24) V(f26)
|
||||
// clang-format on
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum, but enum values are assignment-
|
||||
@ -72,13 +94,19 @@ namespace internal {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register and FPURegister.
|
||||
|
||||
// Core register.
|
||||
struct Register {
|
||||
static const int kNumRegisters = v8::internal::kNumRegisters;
|
||||
static const int kMaxNumAllocatableRegisters = 14; // v0 through t6 and cp.
|
||||
static const int kSizeInBytes = 4;
|
||||
static const int kCpRegister = 23; // cp (s7) is the 23rd register.
|
||||
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static const int kNumRegisters = Code::kAfterLast;
|
||||
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
static const int kMantissaOffset = 0;
|
||||
static const int kExponentOffset = 4;
|
||||
@ -89,117 +117,37 @@ struct Register {
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
|
||||
inline static int NumAllocatableRegisters();
|
||||
|
||||
static int ToAllocationIndex(Register reg) {
|
||||
DCHECK((reg.code() - 2) < (kMaxNumAllocatableRegisters - 1) ||
|
||||
reg.is(from_code(kCpRegister)));
|
||||
return reg.is(from_code(kCpRegister)) ?
|
||||
kMaxNumAllocatableRegisters - 1 : // Return last index for 'cp'.
|
||||
reg.code() - 2; // zero_reg and 'at' are skipped.
|
||||
}
|
||||
|
||||
static Register FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
return index == kMaxNumAllocatableRegisters - 1 ?
|
||||
from_code(kCpRegister) : // Last index is always the 'cp' register.
|
||||
from_code(index + 2); // zero_reg and 'at' are skipped.
|
||||
}
|
||||
|
||||
static const char* AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
const char* const names[] = {
|
||||
"v0",
|
||||
"v1",
|
||||
"a0",
|
||||
"a1",
|
||||
"a2",
|
||||
"a3",
|
||||
"t0",
|
||||
"t1",
|
||||
"t2",
|
||||
"t3",
|
||||
"t4",
|
||||
"t5",
|
||||
"t6",
|
||||
"s7",
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
|
||||
static Register from_code(int code) {
|
||||
Register r = { code };
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kNumRegisters);
|
||||
Register r = {code};
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
|
||||
bool is(Register reg) const { return code_ == reg.code_; }
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
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 code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
#define REGISTER(N, C) \
|
||||
const int kRegister_ ## N ## _Code = C; \
|
||||
const Register N = { C }
|
||||
|
||||
REGISTER(no_reg, -1);
|
||||
// Always zero.
|
||||
REGISTER(zero_reg, 0);
|
||||
// at: Reserved for synthetic instructions.
|
||||
REGISTER(at, 1);
|
||||
// v0, v1: Used when returning multiple values from subroutines.
|
||||
REGISTER(v0, 2);
|
||||
REGISTER(v1, 3);
|
||||
// a0 - a4: Used to pass non-FP parameters.
|
||||
REGISTER(a0, 4);
|
||||
REGISTER(a1, 5);
|
||||
REGISTER(a2, 6);
|
||||
REGISTER(a3, 7);
|
||||
// t0 - t9: Can be used without reservation, act as temporary registers and are
|
||||
// allowed to be destroyed by subroutines.
|
||||
REGISTER(t0, 8);
|
||||
REGISTER(t1, 9);
|
||||
REGISTER(t2, 10);
|
||||
REGISTER(t3, 11);
|
||||
REGISTER(t4, 12);
|
||||
REGISTER(t5, 13);
|
||||
REGISTER(t6, 14);
|
||||
REGISTER(t7, 15);
|
||||
// s0 - s7: Subroutine register variables. Subroutines that write to these
|
||||
// registers must restore their values before exiting so that the caller can
|
||||
// expect the values to be preserved.
|
||||
REGISTER(s0, 16);
|
||||
REGISTER(s1, 17);
|
||||
REGISTER(s2, 18);
|
||||
REGISTER(s3, 19);
|
||||
REGISTER(s4, 20);
|
||||
REGISTER(s5, 21);
|
||||
REGISTER(s6, 22);
|
||||
REGISTER(s7, 23);
|
||||
REGISTER(t8, 24);
|
||||
REGISTER(t9, 25);
|
||||
// k0, k1: Reserved for system calls and interrupt handlers.
|
||||
REGISTER(k0, 26);
|
||||
REGISTER(k1, 27);
|
||||
// gp: Reserved.
|
||||
REGISTER(gp, 28);
|
||||
// sp: Stack pointer.
|
||||
REGISTER(sp, 29);
|
||||
// fp: Frame pointer.
|
||||
REGISTER(fp, 30);
|
||||
// ra: Return address pointer.
|
||||
REGISTER(ra, 31);
|
||||
|
||||
#undef REGISTER
|
||||
// s7: context register
|
||||
// s3: lithium scratch
|
||||
// s4: lithium scratch2
|
||||
#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
const Register no_reg = {Register::kCode_no_reg};
|
||||
|
||||
|
||||
int ToNumber(Register reg);
|
||||
@ -207,75 +155,70 @@ int ToNumber(Register reg);
|
||||
Register ToRegister(int num);
|
||||
|
||||
// Coprocessor register.
|
||||
struct FPURegister {
|
||||
static const int kMaxNumRegisters = v8::internal::kNumFPURegisters;
|
||||
struct DoubleRegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static const 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).
|
||||
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0.
|
||||
// f28: 0.0
|
||||
// f30: scratch register.
|
||||
static const int kNumReservedRegisters = 2;
|
||||
static const int kMaxNumAllocatableRegisters = kMaxNumRegisters / 2 -
|
||||
kNumReservedRegisters;
|
||||
|
||||
inline static int NumRegisters();
|
||||
inline static int NumAllocatableRegisters();
|
||||
|
||||
// TODO(turbofan): Proper support for float32.
|
||||
inline static int NumAllocatableAliasedRegisters();
|
||||
|
||||
inline static int ToAllocationIndex(FPURegister reg);
|
||||
static const char* AllocationIndexToString(int index);
|
||||
|
||||
static FPURegister FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
return from_code(index * 2);
|
||||
}
|
||||
|
||||
static FPURegister from_code(int code) {
|
||||
FPURegister r = { code };
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_valid() const { return 0 <= code_ && code_ < kMaxNumRegisters ; }
|
||||
bool is(FPURegister creg) const { return code_ == creg.code_; }
|
||||
FPURegister low() const {
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
|
||||
DoubleRegister low() const {
|
||||
// Find low reg of a Double-reg pair, which is the reg itself.
|
||||
DCHECK(code_ % 2 == 0); // Specified Double reg must be even.
|
||||
FPURegister reg;
|
||||
reg.code_ = code_;
|
||||
DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
|
||||
DoubleRegister reg;
|
||||
reg.reg_code = reg_code;
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
}
|
||||
FPURegister high() const {
|
||||
DoubleRegister high() const {
|
||||
// Find high reg of a Doubel-reg pair, which is reg + 1.
|
||||
DCHECK(code_ % 2 == 0); // Specified Double reg must be even.
|
||||
FPURegister reg;
|
||||
reg.code_ = code_ + 1;
|
||||
DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
|
||||
DoubleRegister reg;
|
||||
reg.reg_code = reg_code + 1;
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
}
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
static DoubleRegister from_code(int code) {
|
||||
DoubleRegister r = {code};
|
||||
return r;
|
||||
}
|
||||
void setcode(int f) {
|
||||
code_ = f;
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0.
|
||||
// f28: 0.0
|
||||
// f30: scratch register.
|
||||
|
||||
// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
|
||||
// 32-bit registers, f0 through f31. When used as 'double' they are used
|
||||
// in pairs, starting with the even numbered register. So a double operation
|
||||
@ -285,43 +228,43 @@ struct FPURegister {
|
||||
// but it is not in common use. Someday we will want to support this in v8.)
|
||||
|
||||
// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
|
||||
typedef FPURegister DoubleRegister;
|
||||
typedef FPURegister FloatRegister;
|
||||
typedef DoubleRegister FPURegister;
|
||||
typedef DoubleRegister FloatRegister;
|
||||
|
||||
const FPURegister no_freg = { -1 };
|
||||
const DoubleRegister no_freg = {-1};
|
||||
|
||||
const FPURegister f0 = { 0 }; // Return value in hard float mode.
|
||||
const FPURegister f1 = { 1 };
|
||||
const FPURegister f2 = { 2 };
|
||||
const FPURegister f3 = { 3 };
|
||||
const FPURegister f4 = { 4 };
|
||||
const FPURegister f5 = { 5 };
|
||||
const FPURegister f6 = { 6 };
|
||||
const FPURegister f7 = { 7 };
|
||||
const FPURegister f8 = { 8 };
|
||||
const FPURegister f9 = { 9 };
|
||||
const FPURegister f10 = { 10 };
|
||||
const FPURegister f11 = { 11 };
|
||||
const FPURegister f12 = { 12 }; // Arg 0 in hard float mode.
|
||||
const FPURegister f13 = { 13 };
|
||||
const FPURegister f14 = { 14 }; // Arg 1 in hard float mode.
|
||||
const FPURegister f15 = { 15 };
|
||||
const FPURegister f16 = { 16 };
|
||||
const FPURegister f17 = { 17 };
|
||||
const FPURegister f18 = { 18 };
|
||||
const FPURegister f19 = { 19 };
|
||||
const FPURegister f20 = { 20 };
|
||||
const FPURegister f21 = { 21 };
|
||||
const FPURegister f22 = { 22 };
|
||||
const FPURegister f23 = { 23 };
|
||||
const FPURegister f24 = { 24 };
|
||||
const FPURegister f25 = { 25 };
|
||||
const FPURegister f26 = { 26 };
|
||||
const FPURegister f27 = { 27 };
|
||||
const FPURegister f28 = { 28 };
|
||||
const FPURegister f29 = { 29 };
|
||||
const FPURegister f30 = { 30 };
|
||||
const FPURegister f31 = { 31 };
|
||||
const DoubleRegister f0 = {0}; // Return value in hard float mode.
|
||||
const DoubleRegister f1 = {1};
|
||||
const DoubleRegister f2 = {2};
|
||||
const DoubleRegister f3 = {3};
|
||||
const DoubleRegister f4 = {4};
|
||||
const DoubleRegister f5 = {5};
|
||||
const DoubleRegister f6 = {6};
|
||||
const DoubleRegister f7 = {7};
|
||||
const DoubleRegister f8 = {8};
|
||||
const DoubleRegister f9 = {9};
|
||||
const DoubleRegister f10 = {10};
|
||||
const DoubleRegister f11 = {11};
|
||||
const DoubleRegister f12 = {12}; // Arg 0 in hard float mode.
|
||||
const DoubleRegister f13 = {13};
|
||||
const DoubleRegister f14 = {14}; // Arg 1 in hard float mode.
|
||||
const DoubleRegister f15 = {15};
|
||||
const DoubleRegister f16 = {16};
|
||||
const DoubleRegister f17 = {17};
|
||||
const DoubleRegister f18 = {18};
|
||||
const DoubleRegister f19 = {19};
|
||||
const DoubleRegister f20 = {20};
|
||||
const DoubleRegister f21 = {21};
|
||||
const DoubleRegister f22 = {22};
|
||||
const DoubleRegister f23 = {23};
|
||||
const DoubleRegister f24 = {24};
|
||||
const DoubleRegister f25 = {25};
|
||||
const DoubleRegister f26 = {26};
|
||||
const DoubleRegister f27 = {27};
|
||||
const DoubleRegister f28 = {28};
|
||||
const DoubleRegister f29 = {29};
|
||||
const DoubleRegister f30 = {30};
|
||||
const DoubleRegister f31 = {31};
|
||||
|
||||
// Register aliases.
|
||||
// cp is assumed to be a callee saved register.
|
||||
@ -341,22 +284,22 @@ const FPURegister f31 = { 31 };
|
||||
// FPU (coprocessor 1) control registers.
|
||||
// Currently only FCSR (#31) is implemented.
|
||||
struct FPUControlRegister {
|
||||
bool is_valid() const { return code_ == kFCSRRegister; }
|
||||
bool is(FPUControlRegister creg) const { return code_ == creg.code_; }
|
||||
bool is_valid() const { return reg_code == kFCSRRegister; }
|
||||
bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
code_ = f;
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
const FPUControlRegister no_fpucreg = { kInvalidFPUControlRegister };
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/codegen.h"
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/full-codegen/full-codegen.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/safepoint-table.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -88,7 +89,7 @@ void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
|
||||
}
|
||||
input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp()));
|
||||
input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
|
||||
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; i++) {
|
||||
input_->SetDoubleRegister(i, 0.0);
|
||||
}
|
||||
|
||||
@ -139,14 +140,15 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
RegList restored_regs = kJSCallerSaved | kCalleeSaved;
|
||||
RegList saved_regs = restored_regs | sp.bit() | ra.bit();
|
||||
|
||||
const int kDoubleRegsSize =
|
||||
kDoubleSize * FPURegister::kMaxNumAllocatableRegisters;
|
||||
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kMaxNumRegisters;
|
||||
|
||||
// Save all FPU registers before messing with them.
|
||||
__ Subu(sp, sp, Operand(kDoubleRegsSize));
|
||||
for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
|
||||
int offset = i * kDoubleSize;
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
const DoubleRegister fpu_reg = DoubleRegister::from_code(code);
|
||||
int offset = code * kDoubleSize;
|
||||
__ sdc1(fpu_reg, MemOperand(sp, offset));
|
||||
}
|
||||
|
||||
@ -215,9 +217,10 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
int double_regs_offset = FrameDescription::double_registers_offset();
|
||||
// Copy FPU registers to
|
||||
// double_registers_[DoubleRegister::kNumAllocatableRegisters]
|
||||
for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
|
||||
int dst_offset = i * kDoubleSize + double_regs_offset;
|
||||
int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
int dst_offset = code * kDoubleSize + double_regs_offset;
|
||||
int src_offset = code * kDoubleSize + kNumberOfRegisters * kPointerSize;
|
||||
__ ldc1(f0, MemOperand(sp, src_offset));
|
||||
__ sdc1(f0, MemOperand(a1, dst_offset));
|
||||
}
|
||||
@ -284,9 +287,10 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
__ BranchShort(&outer_push_loop, lt, t0, Operand(a1));
|
||||
|
||||
__ lw(a1, MemOperand(a0, Deoptimizer::input_offset()));
|
||||
for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
|
||||
int src_offset = i * kDoubleSize + double_regs_offset;
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
const DoubleRegister fpu_reg = DoubleRegister::from_code(code);
|
||||
int src_offset = code * kDoubleSize + double_regs_offset;
|
||||
__ ldc1(fpu_reg, MemOperand(a1, src_offset));
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ void LCodeGen::SaveCallerDoubles() {
|
||||
BitVector* doubles = chunk()->allocated_double_registers();
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
while (!save_iterator.Done()) {
|
||||
__ sdc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
|
||||
__ sdc1(DoubleRegister::from_code(save_iterator.Current()),
|
||||
MemOperand(sp, count * kDoubleSize));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
@ -112,7 +112,7 @@ void LCodeGen::RestoreCallerDoubles() {
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
int count = 0;
|
||||
while (!save_iterator.Done()) {
|
||||
__ ldc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
|
||||
__ ldc1(DoubleRegister::from_code(save_iterator.Current()),
|
||||
MemOperand(sp, count * kDoubleSize));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
@ -402,12 +402,12 @@ bool LCodeGen::GenerateSafepointTable() {
|
||||
|
||||
|
||||
Register LCodeGen::ToRegister(int index) const {
|
||||
return Register::FromAllocationIndex(index);
|
||||
return Register::from_code(index);
|
||||
}
|
||||
|
||||
|
||||
DoubleRegister LCodeGen::ToDoubleRegister(int index) const {
|
||||
return DoubleRegister::FromAllocationIndex(index);
|
||||
return DoubleRegister::from_code(index);
|
||||
}
|
||||
|
||||
|
||||
|
@ -451,14 +451,13 @@ LPlatformChunk* LChunkBuilder::Build() {
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
|
||||
Register::ToAllocationIndex(reg));
|
||||
return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
|
||||
DoubleRegister::ToAllocationIndex(reg));
|
||||
return new (zone())
|
||||
LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "src/codegen.h"
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/mips/macro-assembler-mips.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -146,7 +147,7 @@ MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
|
||||
MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
|
||||
UNIMPLEMENTED_MIPS();
|
||||
// General purpose registers are pushed last on the stack.
|
||||
int doubles_size = FPURegister::NumAllocatableRegisters() * kDoubleSize;
|
||||
int doubles_size = DoubleRegister::kMaxNumRegisters * kDoubleSize;
|
||||
int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
|
||||
return MemOperand(sp, doubles_size + register_offset);
|
||||
}
|
||||
@ -3681,7 +3682,7 @@ void MacroAssembler::CopyFields(Register dst,
|
||||
// Find a temp register in temps list.
|
||||
for (int i = 0; i < kNumRegisters; i++) {
|
||||
if ((temps & (1 << i)) != 0) {
|
||||
tmp.code_ = i;
|
||||
tmp.reg_code = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -5778,8 +5779,10 @@ Register GetRegisterThatIsNotOneOf(Register reg1,
|
||||
if (reg5.is_valid()) regs |= reg5.bit();
|
||||
if (reg6.is_valid()) regs |= reg6.bit();
|
||||
|
||||
for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
|
||||
Register candidate = Register::FromAllocationIndex(i);
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
|
||||
int code = config->GetAllocatableGeneralCode(i);
|
||||
Register candidate = Register::from_code(code);
|
||||
if (regs & candidate.bit()) continue;
|
||||
return candidate;
|
||||
}
|
||||
|
@ -13,17 +13,17 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
const Register kReturnRegister0 = {kRegister_v0_Code};
|
||||
const Register kReturnRegister1 = {kRegister_v1_Code};
|
||||
const Register kJSFunctionRegister = {kRegister_a1_Code};
|
||||
const Register kReturnRegister0 = {Register::kCode_v0};
|
||||
const Register kReturnRegister1 = {Register::kCode_v1};
|
||||
const Register kJSFunctionRegister = {Register::kCode_a1};
|
||||
const Register kContextRegister = {Register::kCpRegister};
|
||||
const Register kInterpreterAccumulatorRegister = {kRegister_v0_Code};
|
||||
const Register kInterpreterRegisterFileRegister = {kRegister_t3_Code};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_t4_Code};
|
||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_t5_Code};
|
||||
const Register kInterpreterDispatchTableRegister = {kRegister_t6_Code};
|
||||
const Register kRuntimeCallFunctionRegister = {kRegister_a1_Code};
|
||||
const Register kRuntimeCallArgCountRegister = {kRegister_a0_Code};
|
||||
const Register kInterpreterAccumulatorRegister = {Register::kCode_v0};
|
||||
const Register kInterpreterRegisterFileRegister = {Register::kCode_t3};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_t4};
|
||||
const Register kInterpreterBytecodeArrayRegister = {Register::kCode_t5};
|
||||
const Register kInterpreterDispatchTableRegister = {Register::kCode_t6};
|
||||
const Register kRuntimeCallFunctionRegister = {Register::kCode_a1};
|
||||
const Register kRuntimeCallArgCountRegister = {Register::kCode_a0};
|
||||
|
||||
// Forward declaration.
|
||||
class JumpTarget;
|
||||
|
@ -84,36 +84,6 @@ bool Operand::is_reg() const {
|
||||
}
|
||||
|
||||
|
||||
int Register::NumAllocatableRegisters() {
|
||||
return kMaxNumAllocatableRegisters;
|
||||
}
|
||||
|
||||
|
||||
int DoubleRegister::NumRegisters() {
|
||||
return FPURegister::kMaxNumRegisters;
|
||||
}
|
||||
|
||||
|
||||
int DoubleRegister::NumAllocatableRegisters() {
|
||||
return FPURegister::kMaxNumAllocatableRegisters;
|
||||
}
|
||||
|
||||
|
||||
int DoubleRegister::NumAllocatableAliasedRegisters() {
|
||||
return NumAllocatableRegisters();
|
||||
}
|
||||
|
||||
|
||||
int FPURegister::ToAllocationIndex(FPURegister reg) {
|
||||
DCHECK(reg.code() % 2 == 0);
|
||||
DCHECK(reg.code() / 2 < kMaxNumAllocatableRegisters);
|
||||
DCHECK(reg.is_valid());
|
||||
DCHECK(!reg.is(kDoubleRegZero));
|
||||
DCHECK(!reg.is(kLithiumScratchDouble));
|
||||
return (reg.code() / 2);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RelocInfo.
|
||||
|
||||
|
@ -64,28 +64,6 @@ static unsigned CpuFeaturesImpliedByCompiler() {
|
||||
}
|
||||
|
||||
|
||||
const char* DoubleRegister::AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
const char* const names[] = {
|
||||
"f0",
|
||||
"f2",
|
||||
"f4",
|
||||
"f6",
|
||||
"f8",
|
||||
"f10",
|
||||
"f12",
|
||||
"f14",
|
||||
"f16",
|
||||
"f18",
|
||||
"f20",
|
||||
"f22",
|
||||
"f24",
|
||||
"f26"
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
|
||||
|
||||
void CpuFeatures::ProbeImpl(bool cross_compile) {
|
||||
supported_ |= CpuFeaturesImpliedByCompiler();
|
||||
|
||||
@ -229,31 +207,31 @@ MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
|
||||
static const int kNegOffset = 0x00008000;
|
||||
// daddiu(sp, sp, 8) aka Pop() operation or part of Pop(r)
|
||||
// operations as post-increment of sp.
|
||||
const Instr kPopInstruction = DADDIU | (kRegister_sp_Code << kRsShift)
|
||||
| (kRegister_sp_Code << kRtShift)
|
||||
| (kPointerSize & kImm16Mask); // NOLINT
|
||||
const Instr kPopInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
|
||||
(Register::kCode_sp << kRtShift) |
|
||||
(kPointerSize & kImm16Mask); // NOLINT
|
||||
// daddiu(sp, sp, -8) part of Push(r) operation as pre-decrement of sp.
|
||||
const Instr kPushInstruction = DADDIU | (kRegister_sp_Code << kRsShift)
|
||||
| (kRegister_sp_Code << kRtShift)
|
||||
| (-kPointerSize & kImm16Mask); // NOLINT
|
||||
const Instr kPushInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
|
||||
(Register::kCode_sp << kRtShift) |
|
||||
(-kPointerSize & kImm16Mask); // NOLINT
|
||||
// sd(r, MemOperand(sp, 0))
|
||||
const Instr kPushRegPattern = SD | (kRegister_sp_Code << kRsShift)
|
||||
| (0 & kImm16Mask); // NOLINT
|
||||
const Instr kPushRegPattern =
|
||||
SD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
// ld(r, MemOperand(sp, 0))
|
||||
const Instr kPopRegPattern = LD | (kRegister_sp_Code << kRsShift)
|
||||
| (0 & kImm16Mask); // NOLINT
|
||||
const Instr kPopRegPattern =
|
||||
LD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kLwRegFpOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
|
||||
| (0 & kImm16Mask); // NOLINT
|
||||
const Instr kLwRegFpOffsetPattern =
|
||||
LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kSwRegFpOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
|
||||
| (0 & kImm16Mask); // NOLINT
|
||||
const Instr kSwRegFpOffsetPattern =
|
||||
SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kLwRegFpNegOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
|
||||
| (kNegOffset & kImm16Mask); // NOLINT
|
||||
const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
|
||||
(kNegOffset & kImm16Mask); // NOLINT
|
||||
|
||||
const Instr kSwRegFpNegOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
|
||||
| (kNegOffset & kImm16Mask); // NOLINT
|
||||
const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
|
||||
(kNegOffset & kImm16Mask); // NOLINT
|
||||
// A mask for the Rt register for push, pop, lw, sw instructions.
|
||||
const Instr kRtMask = kRtFieldMask;
|
||||
const Instr kLwSwInstrTypeMask = 0xffe00000;
|
||||
@ -314,21 +292,21 @@ void Assembler::CodeTargetAlign() {
|
||||
|
||||
Register Assembler::GetRtReg(Instr instr) {
|
||||
Register rt;
|
||||
rt.code_ = (instr & kRtFieldMask) >> kRtShift;
|
||||
rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
|
||||
return rt;
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRsReg(Instr instr) {
|
||||
Register rs;
|
||||
rs.code_ = (instr & kRsFieldMask) >> kRsShift;
|
||||
rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
|
||||
return rs;
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRdReg(Instr instr) {
|
||||
Register rd;
|
||||
rd.code_ = (instr & kRdFieldMask) >> kRdShift;
|
||||
rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
|
||||
return rd;
|
||||
}
|
||||
|
||||
@ -2211,14 +2189,14 @@ void Assembler::movn(Register rd, Register rs, Register rt) {
|
||||
|
||||
void Assembler::movt(Register rd, Register rs, uint16_t cc) {
|
||||
Register rt;
|
||||
rt.code_ = (cc & 0x0007) << 2 | 1;
|
||||
rt.reg_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.code_ = (cc & 0x0007) << 2 | 0;
|
||||
rt.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
|
||||
}
|
||||
|
||||
@ -2520,7 +2498,7 @@ 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.code_ = (cc & 0x0007) << 2 | 1;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
@ -2528,7 +2506,7 @@ void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
FPURegister ft;
|
||||
ft.code_ = (cc & 0x0007) << 2 | 1;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 1;
|
||||
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
@ -2536,7 +2514,7 @@ void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
FPURegister ft;
|
||||
ft.code_ = (cc & 0x0007) << 2 | 0;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
@ -2544,7 +2522,7 @@ void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
FPURegister ft;
|
||||
ft.code_ = (cc & 0x0007) << 2 | 0;
|
||||
ft.reg_code = (cc & 0x0007) << 2 | 0;
|
||||
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,28 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// clang-format off
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
|
||||
V(a4) V(a5) V(a6) V(a7) V(t0) V(t1) V(t2) V(t3) \
|
||||
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
|
||||
V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
|
||||
V(a4) V(a5) V(a6) V(a7) V(t0) V(t1) V(t2) V(s7)
|
||||
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
|
||||
V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
|
||||
V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
|
||||
V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
|
||||
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
|
||||
V(f16) V(f18) V(f20) V(f22) V(f24) V(f26)
|
||||
// clang-format on
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum, but enum values are assignment-
|
||||
@ -72,11 +94,7 @@ namespace internal {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register and FPURegister.
|
||||
|
||||
// Core register.
|
||||
struct Register {
|
||||
static const int kNumRegisters = v8::internal::kNumRegisters;
|
||||
static const int kMaxNumAllocatableRegisters = 14; // v0 through t2 and cp.
|
||||
static const int kSizeInBytes = 8;
|
||||
static const int kCpRegister = 23; // cp (s7) is the 23rd register.
|
||||
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
@ -89,117 +107,47 @@ struct Register {
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
|
||||
inline static int NumAllocatableRegisters();
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static int ToAllocationIndex(Register reg) {
|
||||
DCHECK((reg.code() - 2) < (kMaxNumAllocatableRegisters - 1) ||
|
||||
reg.is(from_code(kCpRegister)));
|
||||
return reg.is(from_code(kCpRegister)) ?
|
||||
kMaxNumAllocatableRegisters - 1 : // Return last index for 'cp'.
|
||||
reg.code() - 2; // zero_reg and 'at' are skipped.
|
||||
}
|
||||
|
||||
static Register FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
return index == kMaxNumAllocatableRegisters - 1 ?
|
||||
from_code(kCpRegister) : // Last index is always the 'cp' register.
|
||||
from_code(index + 2); // zero_reg and 'at' are skipped.
|
||||
}
|
||||
|
||||
static const char* AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
const char* const names[] = {
|
||||
"v0",
|
||||
"v1",
|
||||
"a0",
|
||||
"a1",
|
||||
"a2",
|
||||
"a3",
|
||||
"a4",
|
||||
"a5",
|
||||
"a6",
|
||||
"a7",
|
||||
"t0",
|
||||
"t1",
|
||||
"t2",
|
||||
"s7",
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
static const 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 <= code_ && code_ < kNumRegisters; }
|
||||
bool is(Register reg) const { return code_ == reg.code_; }
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
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 code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
#define REGISTER(N, C) \
|
||||
const int kRegister_ ## N ## _Code = C; \
|
||||
const Register N = { C }
|
||||
|
||||
REGISTER(no_reg, -1);
|
||||
// Always zero.
|
||||
REGISTER(zero_reg, 0);
|
||||
// at: Reserved for synthetic instructions.
|
||||
REGISTER(at, 1);
|
||||
// v0, v1: Used when returning multiple values from subroutines.
|
||||
REGISTER(v0, 2);
|
||||
REGISTER(v1, 3);
|
||||
// a0 - a4: Used to pass non-FP parameters.
|
||||
REGISTER(a0, 4);
|
||||
REGISTER(a1, 5);
|
||||
REGISTER(a2, 6);
|
||||
REGISTER(a3, 7);
|
||||
// a4 - a7 t0 - t3: Can be used without reservation, act as temporary registers
|
||||
// and are allowed to be destroyed by subroutines.
|
||||
REGISTER(a4, 8);
|
||||
REGISTER(a5, 9);
|
||||
REGISTER(a6, 10);
|
||||
REGISTER(a7, 11);
|
||||
REGISTER(t0, 12);
|
||||
REGISTER(t1, 13);
|
||||
REGISTER(t2, 14);
|
||||
REGISTER(t3, 15);
|
||||
// s0 - s7: Subroutine register variables. Subroutines that write to these
|
||||
// registers must restore their values before exiting so that the caller can
|
||||
// expect the values to be preserved.
|
||||
REGISTER(s0, 16);
|
||||
REGISTER(s1, 17);
|
||||
REGISTER(s2, 18);
|
||||
REGISTER(s3, 19);
|
||||
REGISTER(s4, 20);
|
||||
REGISTER(s5, 21);
|
||||
REGISTER(s6, 22);
|
||||
REGISTER(s7, 23);
|
||||
REGISTER(t8, 24);
|
||||
REGISTER(t9, 25);
|
||||
// k0, k1: Reserved for system calls and interrupt handlers.
|
||||
REGISTER(k0, 26);
|
||||
REGISTER(k1, 27);
|
||||
// gp: Reserved.
|
||||
REGISTER(gp, 28);
|
||||
// sp: Stack pointer.
|
||||
REGISTER(sp, 29);
|
||||
// fp: Frame pointer.
|
||||
REGISTER(fp, 30);
|
||||
// ra: Return address pointer.
|
||||
REGISTER(ra, 31);
|
||||
|
||||
#undef REGISTER
|
||||
// s7: context register
|
||||
// s3: lithium scratch
|
||||
// s4: lithium scratch2
|
||||
#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
const Register no_reg = {Register::kCode_no_reg};
|
||||
|
||||
|
||||
int ToNumber(Register reg);
|
||||
@ -207,77 +155,72 @@ int ToNumber(Register reg);
|
||||
Register ToRegister(int num);
|
||||
|
||||
// Coprocessor register.
|
||||
struct FPURegister {
|
||||
static const int kMaxNumRegisters = v8::internal::kNumFPURegisters;
|
||||
struct DoubleRegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static const 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).
|
||||
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0.
|
||||
// f28: 0.0
|
||||
// f30: scratch register.
|
||||
static const int kNumReservedRegisters = 2;
|
||||
static const int kMaxNumAllocatableRegisters = kMaxNumRegisters / 2 -
|
||||
kNumReservedRegisters;
|
||||
|
||||
inline static int NumRegisters();
|
||||
inline static int NumAllocatableRegisters();
|
||||
|
||||
// TODO(turbofan): Proper support for float32.
|
||||
inline static int NumAllocatableAliasedRegisters();
|
||||
|
||||
inline static int ToAllocationIndex(FPURegister reg);
|
||||
static const char* AllocationIndexToString(int index);
|
||||
|
||||
static FPURegister FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
return from_code(index * 2);
|
||||
}
|
||||
|
||||
static FPURegister from_code(int code) {
|
||||
FPURegister r = { code };
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_valid() const { return 0 <= code_ && code_ < kMaxNumRegisters ; }
|
||||
bool is(FPURegister creg) const { return code_ == creg.code_; }
|
||||
FPURegister low() const {
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
|
||||
DoubleRegister 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(code_ % 2 == 0); // Specified Double reg must be even.
|
||||
FPURegister reg;
|
||||
reg.code_ = code_;
|
||||
DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
|
||||
DoubleRegister reg;
|
||||
reg.reg_code = reg_code;
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
}
|
||||
FPURegister high() const {
|
||||
DoubleRegister 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(code_ % 2 == 0); // Specified Double reg must be even.
|
||||
FPURegister reg;
|
||||
reg.code_ = code_ + 1;
|
||||
DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
|
||||
DoubleRegister reg;
|
||||
reg.reg_code = reg_code + 1;
|
||||
DCHECK(reg.is_valid());
|
||||
return reg;
|
||||
}
|
||||
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
|
||||
static DoubleRegister from_code(int code) {
|
||||
DoubleRegister r = {code};
|
||||
return r;
|
||||
}
|
||||
void setcode(int f) {
|
||||
code_ = f;
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0.
|
||||
// f28: 0.0
|
||||
// f30: scratch register.
|
||||
|
||||
// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
|
||||
// 32-bit registers, f0 through f31. When used as 'double' they are used
|
||||
// in pairs, starting with the even numbered register. So a double operation
|
||||
@ -287,43 +230,43 @@ struct FPURegister {
|
||||
// but it is not in common use. Someday we will want to support this in v8.)
|
||||
|
||||
// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
|
||||
typedef FPURegister DoubleRegister;
|
||||
typedef FPURegister FloatRegister;
|
||||
typedef DoubleRegister FPURegister;
|
||||
typedef DoubleRegister FloatRegister;
|
||||
|
||||
const FPURegister no_freg = { -1 };
|
||||
const DoubleRegister no_freg = {-1};
|
||||
|
||||
const FPURegister f0 = { 0 }; // Return value in hard float mode.
|
||||
const FPURegister f1 = { 1 };
|
||||
const FPURegister f2 = { 2 };
|
||||
const FPURegister f3 = { 3 };
|
||||
const FPURegister f4 = { 4 };
|
||||
const FPURegister f5 = { 5 };
|
||||
const FPURegister f6 = { 6 };
|
||||
const FPURegister f7 = { 7 };
|
||||
const FPURegister f8 = { 8 };
|
||||
const FPURegister f9 = { 9 };
|
||||
const FPURegister f10 = { 10 };
|
||||
const FPURegister f11 = { 11 };
|
||||
const FPURegister f12 = { 12 }; // Arg 0 in hard float mode.
|
||||
const FPURegister f13 = { 13 };
|
||||
const FPURegister f14 = { 14 }; // Arg 1 in hard float mode.
|
||||
const FPURegister f15 = { 15 };
|
||||
const FPURegister f16 = { 16 };
|
||||
const FPURegister f17 = { 17 };
|
||||
const FPURegister f18 = { 18 };
|
||||
const FPURegister f19 = { 19 };
|
||||
const FPURegister f20 = { 20 };
|
||||
const FPURegister f21 = { 21 };
|
||||
const FPURegister f22 = { 22 };
|
||||
const FPURegister f23 = { 23 };
|
||||
const FPURegister f24 = { 24 };
|
||||
const FPURegister f25 = { 25 };
|
||||
const FPURegister f26 = { 26 };
|
||||
const FPURegister f27 = { 27 };
|
||||
const FPURegister f28 = { 28 };
|
||||
const FPURegister f29 = { 29 };
|
||||
const FPURegister f30 = { 30 };
|
||||
const FPURegister f31 = { 31 };
|
||||
const DoubleRegister f0 = {0}; // Return value in hard float mode.
|
||||
const DoubleRegister f1 = {1};
|
||||
const DoubleRegister f2 = {2};
|
||||
const DoubleRegister f3 = {3};
|
||||
const DoubleRegister f4 = {4};
|
||||
const DoubleRegister f5 = {5};
|
||||
const DoubleRegister f6 = {6};
|
||||
const DoubleRegister f7 = {7};
|
||||
const DoubleRegister f8 = {8};
|
||||
const DoubleRegister f9 = {9};
|
||||
const DoubleRegister f10 = {10};
|
||||
const DoubleRegister f11 = {11};
|
||||
const DoubleRegister f12 = {12}; // Arg 0 in hard float mode.
|
||||
const DoubleRegister f13 = {13};
|
||||
const DoubleRegister f14 = {14}; // Arg 1 in hard float mode.
|
||||
const DoubleRegister f15 = {15};
|
||||
const DoubleRegister f16 = {16};
|
||||
const DoubleRegister f17 = {17};
|
||||
const DoubleRegister f18 = {18};
|
||||
const DoubleRegister f19 = {19};
|
||||
const DoubleRegister f20 = {20};
|
||||
const DoubleRegister f21 = {21};
|
||||
const DoubleRegister f22 = {22};
|
||||
const DoubleRegister f23 = {23};
|
||||
const DoubleRegister f24 = {24};
|
||||
const DoubleRegister f25 = {25};
|
||||
const DoubleRegister f26 = {26};
|
||||
const DoubleRegister f27 = {27};
|
||||
const DoubleRegister f28 = {28};
|
||||
const DoubleRegister f29 = {29};
|
||||
const DoubleRegister f30 = {30};
|
||||
const DoubleRegister f31 = {31};
|
||||
|
||||
// Register aliases.
|
||||
// cp is assumed to be a callee saved register.
|
||||
@ -343,22 +286,22 @@ const FPURegister f31 = { 31 };
|
||||
// FPU (coprocessor 1) control registers.
|
||||
// Currently only FCSR (#31) is implemented.
|
||||
struct FPUControlRegister {
|
||||
bool is_valid() const { return code_ == kFCSRRegister; }
|
||||
bool is(FPUControlRegister creg) const { return code_ == creg.code_; }
|
||||
bool is_valid() const { return reg_code == kFCSRRegister; }
|
||||
bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
DCHECK(is_valid());
|
||||
return 1 << code_;
|
||||
return 1 << reg_code;
|
||||
}
|
||||
void setcode(int f) {
|
||||
code_ = f;
|
||||
reg_code = f;
|
||||
DCHECK(is_valid());
|
||||
}
|
||||
// Unfortunately we can't make this private in a struct.
|
||||
int code_;
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
const FPUControlRegister no_fpucreg = { kInvalidFPUControlRegister };
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/codegen.h"
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/full-codegen/full-codegen.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/safepoint-table.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -88,7 +89,7 @@ void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
|
||||
}
|
||||
input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp()));
|
||||
input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
|
||||
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; i++) {
|
||||
input_->SetDoubleRegister(i, 0.0);
|
||||
}
|
||||
|
||||
@ -139,14 +140,15 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
RegList restored_regs = kJSCallerSaved | kCalleeSaved;
|
||||
RegList saved_regs = restored_regs | sp.bit() | ra.bit();
|
||||
|
||||
const int kDoubleRegsSize =
|
||||
kDoubleSize * FPURegister::kMaxNumAllocatableRegisters;
|
||||
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kMaxNumRegisters;
|
||||
|
||||
// Save all FPU registers before messing with them.
|
||||
__ Dsubu(sp, sp, Operand(kDoubleRegsSize));
|
||||
for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
|
||||
int offset = i * kDoubleSize;
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
const DoubleRegister fpu_reg = DoubleRegister::from_code(code);
|
||||
int offset = code * kDoubleSize;
|
||||
__ sdc1(fpu_reg, MemOperand(sp, offset));
|
||||
}
|
||||
|
||||
@ -221,9 +223,10 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
int double_regs_offset = FrameDescription::double_registers_offset();
|
||||
// Copy FPU registers to
|
||||
// double_registers_[DoubleRegister::kNumAllocatableRegisters]
|
||||
for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
|
||||
int dst_offset = i * kDoubleSize + double_regs_offset;
|
||||
int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
int dst_offset = code * kDoubleSize + double_regs_offset;
|
||||
int src_offset = code * kDoubleSize + kNumberOfRegisters * kPointerSize;
|
||||
__ ldc1(f0, MemOperand(sp, src_offset));
|
||||
__ sdc1(f0, MemOperand(a1, dst_offset));
|
||||
}
|
||||
@ -289,9 +292,10 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
__ BranchShort(&outer_push_loop, lt, a4, Operand(a1));
|
||||
|
||||
__ ld(a1, MemOperand(a0, Deoptimizer::input_offset()));
|
||||
for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
|
||||
int src_offset = i * kDoubleSize + double_regs_offset;
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
const DoubleRegister fpu_reg = DoubleRegister::from_code(code);
|
||||
int src_offset = code * kDoubleSize + double_regs_offset;
|
||||
__ ldc1(fpu_reg, MemOperand(a1, src_offset));
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ void LCodeGen::SaveCallerDoubles() {
|
||||
BitVector* doubles = chunk()->allocated_double_registers();
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
while (!save_iterator.Done()) {
|
||||
__ sdc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
|
||||
__ sdc1(DoubleRegister::from_code(save_iterator.Current()),
|
||||
MemOperand(sp, count * kDoubleSize));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
@ -87,7 +87,7 @@ void LCodeGen::RestoreCallerDoubles() {
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
int count = 0;
|
||||
while (!save_iterator.Done()) {
|
||||
__ ldc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
|
||||
__ ldc1(DoubleRegister::from_code(save_iterator.Current()),
|
||||
MemOperand(sp, count * kDoubleSize));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
@ -385,12 +385,12 @@ bool LCodeGen::GenerateSafepointTable() {
|
||||
|
||||
|
||||
Register LCodeGen::ToRegister(int index) const {
|
||||
return Register::FromAllocationIndex(index);
|
||||
return Register::from_code(index);
|
||||
}
|
||||
|
||||
|
||||
DoubleRegister LCodeGen::ToDoubleRegister(int index) const {
|
||||
return DoubleRegister::FromAllocationIndex(index);
|
||||
return DoubleRegister::from_code(index);
|
||||
}
|
||||
|
||||
|
||||
|
@ -451,14 +451,13 @@ LPlatformChunk* LChunkBuilder::Build() {
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
|
||||
Register::ToAllocationIndex(reg));
|
||||
return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
|
||||
DoubleRegister::ToAllocationIndex(reg));
|
||||
return new (zone())
|
||||
LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "src/codegen.h"
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/mips64/macro-assembler-mips64.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -148,7 +149,7 @@ MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
|
||||
MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
|
||||
UNIMPLEMENTED_MIPS();
|
||||
// General purpose registers are pushed last on the stack.
|
||||
int doubles_size = FPURegister::NumAllocatableRegisters() * kDoubleSize;
|
||||
int doubles_size = DoubleRegister::kMaxNumRegisters * kDoubleSize;
|
||||
int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
|
||||
return MemOperand(sp, doubles_size + register_offset);
|
||||
}
|
||||
@ -3761,7 +3762,7 @@ void MacroAssembler::CopyFields(Register dst,
|
||||
// Find a temp register in temps list.
|
||||
for (int i = 0; i < kNumRegisters; i++) {
|
||||
if ((temps & (1 << i)) != 0) {
|
||||
tmp.code_ = i;
|
||||
tmp.reg_code = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -6042,8 +6043,10 @@ Register GetRegisterThatIsNotOneOf(Register reg1,
|
||||
if (reg5.is_valid()) regs |= reg5.bit();
|
||||
if (reg6.is_valid()) regs |= reg6.bit();
|
||||
|
||||
for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
|
||||
Register candidate = Register::FromAllocationIndex(i);
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
|
||||
int code = config->GetAllocatableGeneralCode(i);
|
||||
Register candidate = Register::from_code(code);
|
||||
if (regs & candidate.bit()) continue;
|
||||
return candidate;
|
||||
}
|
||||
|
@ -13,17 +13,17 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
const Register kReturnRegister0 = {kRegister_v0_Code};
|
||||
const Register kReturnRegister1 = {kRegister_v1_Code};
|
||||
const Register kJSFunctionRegister = {kRegister_a1_Code};
|
||||
const Register kContextRegister = {kRegister_s7_Code};
|
||||
const Register kInterpreterAccumulatorRegister = {kRegister_v0_Code};
|
||||
const Register kInterpreterRegisterFileRegister = {kRegister_a7_Code};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_t0_Code};
|
||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_t1_Code};
|
||||
const Register kInterpreterDispatchTableRegister = {kRegister_t2_Code};
|
||||
const Register kRuntimeCallFunctionRegister = {kRegister_a1_Code};
|
||||
const Register kRuntimeCallArgCountRegister = {kRegister_a0_Code};
|
||||
const Register kReturnRegister0 = {Register::kCode_v0};
|
||||
const Register kReturnRegister1 = {Register::kCode_v1};
|
||||
const Register kJSFunctionRegister = {Register::kCode_a1};
|
||||
const Register kContextRegister = {Register::kCpRegister};
|
||||
const Register kInterpreterAccumulatorRegister = {Register::kCode_v0};
|
||||
const Register kInterpreterRegisterFileRegister = {Register::kCode_a7};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_t0};
|
||||
const Register kInterpreterBytecodeArrayRegister = {Register::kCode_t1};
|
||||
const Register kInterpreterDispatchTableRegister = {Register::kCode_t2};
|
||||
const Register kRuntimeCallFunctionRegister = {Register::kCode_a1};
|
||||
const Register kRuntimeCallArgCountRegister = {Register::kCode_a0};
|
||||
|
||||
// Forward declaration.
|
||||
class JumpTarget;
|
||||
|
@ -12252,7 +12252,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
|
||||
|
||||
case Translation::DOUBLE_REGISTER: {
|
||||
int reg_code = iterator.Next();
|
||||
os << "{input=" << DoubleRegister::AllocationIndexToString(reg_code)
|
||||
os << "{input=" << DoubleRegister::from_code(reg_code).ToString()
|
||||
<< "}";
|
||||
break;
|
||||
}
|
||||
|
146
src/register-configuration.cc
Normal file
146
src/register-configuration.cc
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
#define REGISTER_COUNT(R) 1 +
|
||||
static const int kMaxAllocatableGeneralRegisterCount =
|
||||
ALLOCATABLE_GENERAL_REGISTERS(REGISTER_COUNT)0;
|
||||
static const int kMaxAllocatableDoubleRegisterCount =
|
||||
ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_COUNT)0;
|
||||
|
||||
static const char* const kGeneralRegisterNames[] = {
|
||||
#define REGISTER_NAME(R) #R,
|
||||
GENERAL_REGISTERS(REGISTER_NAME)
|
||||
#undef REGISTER_NAME
|
||||
};
|
||||
|
||||
static const char* const kDoubleRegisterNames[] = {
|
||||
#define REGISTER_NAME(R) #R,
|
||||
DOUBLE_REGISTERS(REGISTER_NAME)
|
||||
#undef REGISTER_NAME
|
||||
};
|
||||
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >=
|
||||
Register::kNumRegisters);
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxDoubleRegisters >=
|
||||
DoubleRegister::kMaxNumRegisters);
|
||||
|
||||
class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
|
||||
public:
|
||||
ArchDefaultRegisterConfiguration()
|
||||
: RegisterConfiguration(
|
||||
Register::kNumRegisters, DoubleRegister::kMaxNumRegisters,
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
kMaxAllocatableGeneralRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
#elif V8_TARGET_ARCH_X87
|
||||
kMaxAllocatableGeneralRegisterCount, 1, 1,
|
||||
#elif V8_TARGET_ARCH_X64
|
||||
kMaxAllocatableGeneralRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
#elif V8_TARGET_ARCH_ARM
|
||||
FLAG_enable_embedded_constant_pool
|
||||
? (kMaxAllocatableGeneralRegisterCount - 1)
|
||||
: kMaxAllocatableGeneralRegisterCount,
|
||||
CpuFeatures::IsSupported(VFP32DREGS)
|
||||
? kMaxAllocatableDoubleRegisterCount
|
||||
: (ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT)0),
|
||||
ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT)0,
|
||||
#elif V8_TARGET_ARCH_ARM64
|
||||
kMaxAllocatableGeneralRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
#elif V8_TARGET_ARCH_MIPS
|
||||
kMaxAllocatableGeneralRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
#elif V8_TARGET_ARCH_MIPS64
|
||||
kMaxAllocatableGeneralRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
kMaxAllocatableDoubleRegisterCount,
|
||||
#else
|
||||
GetAllocatableGeneralRegisterCount(),
|
||||
GetAllocatableDoubleRegisterCount(),
|
||||
GetAllocatableAliasedDoubleRegisterCount(),
|
||||
#endif
|
||||
GetAllocatableGeneralCodes(), GetAllocatableDoubleCodes(),
|
||||
kGeneralRegisterNames, kDoubleRegisterNames) {
|
||||
}
|
||||
|
||||
const char* general_register_name_table_[Register::kNumRegisters];
|
||||
const char* double_register_name_table_[DoubleRegister::kMaxNumRegisters];
|
||||
|
||||
private:
|
||||
friend struct Register;
|
||||
friend struct DoubleRegister;
|
||||
|
||||
static const int* GetAllocatableGeneralCodes() {
|
||||
#define REGISTER_CODE(R) Register::kCode_##R,
|
||||
static const int general_codes[] = {
|
||||
ALLOCATABLE_GENERAL_REGISTERS(REGISTER_CODE)};
|
||||
#undef REGISTER_CODE
|
||||
return general_codes;
|
||||
}
|
||||
|
||||
static const int* GetAllocatableDoubleCodes() {
|
||||
#define REGISTER_CODE(R) DoubleRegister::kCode_##R,
|
||||
static const int double_codes[] = {
|
||||
ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_CODE)};
|
||||
#undef REGISTER_CODE
|
||||
return double_codes;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static base::LazyInstance<ArchDefaultRegisterConfiguration>::type
|
||||
kDefaultRegisterConfiguration = LAZY_INSTANCE_INITIALIZER;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
const RegisterConfiguration* RegisterConfiguration::ArchDefault() {
|
||||
return &kDefaultRegisterConfiguration.Get();
|
||||
}
|
||||
|
||||
RegisterConfiguration::RegisterConfiguration(
|
||||
int num_general_registers, int num_double_registers,
|
||||
int num_allocatable_general_registers, int num_allocatable_double_registers,
|
||||
int num_allocatable_aliased_double_registers,
|
||||
const int* allocatable_general_codes, const int* allocatable_double_codes,
|
||||
const char* const* general_register_names,
|
||||
const char* const* double_register_names)
|
||||
: num_general_registers_(num_general_registers),
|
||||
num_double_registers_(num_double_registers),
|
||||
num_allocatable_general_registers_(num_allocatable_general_registers),
|
||||
num_allocatable_double_registers_(num_allocatable_double_registers),
|
||||
num_allocatable_aliased_double_registers_(
|
||||
num_allocatable_aliased_double_registers),
|
||||
allocatable_general_codes_mask_(0),
|
||||
allocatable_double_codes_mask_(0),
|
||||
allocatable_general_codes_(allocatable_general_codes),
|
||||
allocatable_double_codes_(allocatable_double_codes),
|
||||
general_register_names_(general_register_names),
|
||||
double_register_names_(double_register_names) {
|
||||
for (int i = 0; i < num_allocatable_general_registers_; ++i) {
|
||||
allocatable_general_codes_mask_ |= (1 << allocatable_general_codes_[i]);
|
||||
}
|
||||
for (int i = 0; i < num_allocatable_double_registers_; ++i) {
|
||||
allocatable_double_codes_mask_ |= (1 << allocatable_double_codes_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#undef REGISTER_COUNT
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
88
src/register-configuration.h
Normal file
88
src/register-configuration.h
Normal file
@ -0,0 +1,88 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_COMPILER_REGISTER_CONFIGURATION_H_
|
||||
#define V8_COMPILER_REGISTER_CONFIGURATION_H_
|
||||
|
||||
#include "src/base/macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// An architecture independent representation of the sets of registers available
|
||||
// for instruction creation.
|
||||
class RegisterConfiguration {
|
||||
public:
|
||||
// Architecture independent maxes.
|
||||
static const int kMaxGeneralRegisters = 32;
|
||||
static const int kMaxDoubleRegisters = 32;
|
||||
|
||||
static const RegisterConfiguration* ArchDefault();
|
||||
|
||||
RegisterConfiguration(int num_general_registers, int num_double_registers,
|
||||
int num_allocatable_general_registers,
|
||||
int num_allocatable_double_registers,
|
||||
int num_allocatable_aliased_double_registers,
|
||||
const int* allocatable_general_codes,
|
||||
const int* allocatable_double_codes,
|
||||
char const* const* general_names,
|
||||
char const* const* double_names);
|
||||
|
||||
int num_general_registers() const { return num_general_registers_; }
|
||||
int num_double_registers() const { return num_double_registers_; }
|
||||
int num_allocatable_general_registers() const {
|
||||
return num_allocatable_general_registers_;
|
||||
}
|
||||
int num_allocatable_double_registers() const {
|
||||
return num_allocatable_double_registers_;
|
||||
}
|
||||
// TODO(turbofan): This is a temporary work-around required because our
|
||||
// register allocator does not yet support the aliasing of single/double
|
||||
// registers on ARM.
|
||||
int num_allocatable_aliased_double_registers() const {
|
||||
return num_allocatable_aliased_double_registers_;
|
||||
}
|
||||
int32_t allocatable_general_codes_mask() const {
|
||||
return allocatable_general_codes_mask_;
|
||||
}
|
||||
int32_t allocatable_double_codes_mask() const {
|
||||
return allocatable_double_codes_mask_;
|
||||
}
|
||||
int GetAllocatableGeneralCode(int index) const {
|
||||
return allocatable_general_codes_[index];
|
||||
}
|
||||
int GetAllocatableDoubleCode(int index) const {
|
||||
return allocatable_double_codes_[index];
|
||||
}
|
||||
const char* GetGeneralRegisterName(int code) const {
|
||||
return general_register_names_[code];
|
||||
}
|
||||
const char* GetDoubleRegisterName(int code) const {
|
||||
return double_register_names_[code];
|
||||
}
|
||||
const int* allocatable_general_codes() const {
|
||||
return allocatable_general_codes_;
|
||||
}
|
||||
const int* allocatable_double_codes() const {
|
||||
return allocatable_double_codes_;
|
||||
}
|
||||
|
||||
private:
|
||||
const int num_general_registers_;
|
||||
const int num_double_registers_;
|
||||
int num_allocatable_general_registers_;
|
||||
int num_allocatable_double_registers_;
|
||||
int num_allocatable_aliased_double_registers_;
|
||||
int32_t allocatable_general_codes_mask_;
|
||||
int32_t allocatable_double_codes_mask_;
|
||||
const int* allocatable_general_codes_;
|
||||
const int* allocatable_double_codes_;
|
||||
char const* const* general_register_names_;
|
||||
char const* const* double_register_names_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_REGISTER_CONFIGURATION_H_
|
@ -115,20 +115,6 @@ void CpuFeatures::PrintFeatures() {
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Register constants.
|
||||
|
||||
const int
|
||||
Register::kRegisterCodeByAllocationIndex[kMaxNumAllocatableRegisters] = {
|
||||
// rax, rbx, rdx, rcx, rsi, rdi, r8, r9, r11, r12, r14, r15
|
||||
0, 3, 2, 1, 6, 7, 8, 9, 11, 12, 14, 15
|
||||
};
|
||||
|
||||
const int Register::kAllocationIndexByRegisterCode[kNumRegisters] = {
|
||||
0, 3, 2, 1, -1, -1, 4, 5, 6, 7, -1, 8, 9, -1, 10, 11
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Operand
|
||||
|
||||
|
@ -47,6 +47,39 @@ namespace internal {
|
||||
|
||||
// Utility functions
|
||||
|
||||
#define GENERAL_REGISTERS(V) \
|
||||
V(rax) \
|
||||
V(rcx) \
|
||||
V(rdx) \
|
||||
V(rbx) \
|
||||
V(rsp) \
|
||||
V(rbp) \
|
||||
V(rsi) \
|
||||
V(rdi) \
|
||||
V(r8) \
|
||||
V(r9) \
|
||||
V(r10) \
|
||||
V(r11) \
|
||||
V(r12) \
|
||||
V(r13) \
|
||||
V(r14) \
|
||||
V(r15)
|
||||
|
||||
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
||||
V(rax) \
|
||||
V(rbx) \
|
||||
V(rdx) \
|
||||
V(rcx) \
|
||||
V(rsi) \
|
||||
V(rdi) \
|
||||
V(r8) \
|
||||
V(r9) \
|
||||
V(r11) \
|
||||
V(r12) \
|
||||
V(r14) \
|
||||
V(r15)
|
||||
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
// 1) We would prefer to use an enum, but enum values are assignment-
|
||||
@ -68,226 +101,153 @@ namespace internal {
|
||||
// mode. This way we get the compile-time error checking in debug mode
|
||||
// and best performance in optimized code.
|
||||
//
|
||||
|
||||
struct Register {
|
||||
// The non-allocatable registers are:
|
||||
// rsp - stack pointer
|
||||
// rbp - frame pointer
|
||||
// r10 - fixed scratch register
|
||||
// r13 - root register
|
||||
static const int kMaxNumAllocatableRegisters = 12;
|
||||
static int NumAllocatableRegisters() {
|
||||
return kMaxNumAllocatableRegisters;
|
||||
}
|
||||
static const int kNumRegisters = 16;
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
GENERAL_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static int ToAllocationIndex(Register reg) {
|
||||
return kAllocationIndexByRegisterCode[reg.code()];
|
||||
}
|
||||
|
||||
static Register FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
Register result = { kRegisterCodeByAllocationIndex[index] };
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
const char* const names[] = {
|
||||
"rax",
|
||||
"rbx",
|
||||
"rdx",
|
||||
"rcx",
|
||||
"rsi",
|
||||
"rdi",
|
||||
"r8",
|
||||
"r9",
|
||||
"r11",
|
||||
"r12",
|
||||
"r14",
|
||||
"r15"
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
static const int kNumRegisters = Code::kAfterLast;
|
||||
|
||||
static Register from_code(int code) {
|
||||
Register r = { code };
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kNumRegisters);
|
||||
Register r = {code};
|
||||
return r;
|
||||
}
|
||||
bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
|
||||
bool is(Register reg) const { return code_ == reg.code_; }
|
||||
// rax, rbx, rcx and rdx are byte registers, the rest are not.
|
||||
bool is_byte_register() const { return code_ <= 3; }
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
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 code_;
|
||||
return reg_code;
|
||||
}
|
||||
int bit() const {
|
||||
return 1 << code_;
|
||||
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 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 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 code_;
|
||||
|
||||
private:
|
||||
static const int kRegisterCodeByAllocationIndex[kMaxNumAllocatableRegisters];
|
||||
static const int kAllocationIndexByRegisterCode[kNumRegisters];
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
const int kRegister_rax_Code = 0;
|
||||
const int kRegister_rcx_Code = 1;
|
||||
const int kRegister_rdx_Code = 2;
|
||||
const int kRegister_rbx_Code = 3;
|
||||
const int kRegister_rsp_Code = 4;
|
||||
const int kRegister_rbp_Code = 5;
|
||||
const int kRegister_rsi_Code = 6;
|
||||
const int kRegister_rdi_Code = 7;
|
||||
const int kRegister_r8_Code = 8;
|
||||
const int kRegister_r9_Code = 9;
|
||||
const int kRegister_r10_Code = 10;
|
||||
const int kRegister_r11_Code = 11;
|
||||
const int kRegister_r12_Code = 12;
|
||||
const int kRegister_r13_Code = 13;
|
||||
const int kRegister_r14_Code = 14;
|
||||
const int kRegister_r15_Code = 15;
|
||||
const int kRegister_no_reg_Code = -1;
|
||||
|
||||
const Register rax = { kRegister_rax_Code };
|
||||
const Register rcx = { kRegister_rcx_Code };
|
||||
const Register rdx = { kRegister_rdx_Code };
|
||||
const Register rbx = { kRegister_rbx_Code };
|
||||
const Register rsp = { kRegister_rsp_Code };
|
||||
const Register rbp = { kRegister_rbp_Code };
|
||||
const Register rsi = { kRegister_rsi_Code };
|
||||
const Register rdi = { kRegister_rdi_Code };
|
||||
const Register r8 = { kRegister_r8_Code };
|
||||
const Register r9 = { kRegister_r9_Code };
|
||||
const Register r10 = { kRegister_r10_Code };
|
||||
const Register r11 = { kRegister_r11_Code };
|
||||
const Register r12 = { kRegister_r12_Code };
|
||||
const Register r13 = { kRegister_r13_Code };
|
||||
const Register r14 = { kRegister_r14_Code };
|
||||
const Register r15 = { kRegister_r15_Code };
|
||||
const Register no_reg = { kRegister_no_reg_Code };
|
||||
#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
|
||||
GENERAL_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
const Register no_reg = {Register::kCode_no_reg};
|
||||
|
||||
|
||||
#ifdef _WIN64
|
||||
// Windows calling convention
|
||||
const Register arg_reg_1 = { kRegister_rcx_Code };
|
||||
const Register arg_reg_2 = { kRegister_rdx_Code };
|
||||
const Register arg_reg_3 = { kRegister_r8_Code };
|
||||
const Register arg_reg_4 = { kRegister_r9_Code };
|
||||
const Register arg_reg_1 = {Register::kCode_rcx};
|
||||
const Register arg_reg_2 = {Register::kCode_rdx};
|
||||
const Register arg_reg_3 = {Register::kCode_r8};
|
||||
const Register arg_reg_4 = {Register::kCode_r9};
|
||||
#else
|
||||
// AMD64 calling convention
|
||||
const Register arg_reg_1 = { kRegister_rdi_Code };
|
||||
const Register arg_reg_2 = { kRegister_rsi_Code };
|
||||
const Register arg_reg_3 = { kRegister_rdx_Code };
|
||||
const Register arg_reg_4 = { kRegister_rcx_Code };
|
||||
const Register arg_reg_1 = {Register::kCode_rdi};
|
||||
const Register arg_reg_2 = {Register::kCode_rsi};
|
||||
const Register arg_reg_3 = {Register::kCode_rdx};
|
||||
const Register arg_reg_4 = {Register::kCode_rcx};
|
||||
#endif // _WIN64
|
||||
|
||||
struct XMMRegister {
|
||||
static const int kMaxNumRegisters = 16;
|
||||
static const int kMaxNumAllocatableRegisters = 15;
|
||||
static int NumAllocatableRegisters() {
|
||||
return kMaxNumAllocatableRegisters;
|
||||
}
|
||||
|
||||
// TODO(turbofan): Proper support for float32.
|
||||
static int NumAllocatableAliasedRegisters() {
|
||||
return NumAllocatableRegisters();
|
||||
}
|
||||
#define DOUBLE_REGISTERS(V) \
|
||||
V(xmm0) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7) \
|
||||
V(xmm8) \
|
||||
V(xmm9) \
|
||||
V(xmm10) \
|
||||
V(xmm11) \
|
||||
V(xmm12) \
|
||||
V(xmm13) \
|
||||
V(xmm14) \
|
||||
V(xmm15)
|
||||
|
||||
static int ToAllocationIndex(XMMRegister reg) {
|
||||
DCHECK(reg.code() != 0);
|
||||
return reg.code() - 1;
|
||||
}
|
||||
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
||||
V(xmm1) \
|
||||
V(xmm2) \
|
||||
V(xmm3) \
|
||||
V(xmm4) \
|
||||
V(xmm5) \
|
||||
V(xmm6) \
|
||||
V(xmm7) \
|
||||
V(xmm8) \
|
||||
V(xmm9) \
|
||||
V(xmm10) \
|
||||
V(xmm11) \
|
||||
V(xmm12) \
|
||||
V(xmm13) \
|
||||
V(xmm14) \
|
||||
V(xmm15)
|
||||
|
||||
static XMMRegister FromAllocationIndex(int index) {
|
||||
DCHECK(0 <= index && index < kMaxNumAllocatableRegisters);
|
||||
XMMRegister result = { index + 1 };
|
||||
|
||||
struct DoubleRegister {
|
||||
enum Code {
|
||||
#define REGISTER_CODE(R) kCode_##R,
|
||||
DOUBLE_REGISTERS(REGISTER_CODE)
|
||||
#undef REGISTER_CODE
|
||||
kAfterLast,
|
||||
kCode_no_reg = -1
|
||||
};
|
||||
|
||||
static const int kMaxNumRegisters = Code::kAfterLast;
|
||||
|
||||
static DoubleRegister from_code(int code) {
|
||||
DoubleRegister result = {code};
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* AllocationIndexToString(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
const char* const names[] = {
|
||||
"xmm1",
|
||||
"xmm2",
|
||||
"xmm3",
|
||||
"xmm4",
|
||||
"xmm5",
|
||||
"xmm6",
|
||||
"xmm7",
|
||||
"xmm8",
|
||||
"xmm9",
|
||||
"xmm10",
|
||||
"xmm11",
|
||||
"xmm12",
|
||||
"xmm13",
|
||||
"xmm14",
|
||||
"xmm15"
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
|
||||
static XMMRegister from_code(int code) {
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kMaxNumRegisters);
|
||||
XMMRegister r = { code };
|
||||
return r;
|
||||
}
|
||||
bool is_valid() const { return 0 <= code_ && code_ < kMaxNumRegisters; }
|
||||
bool is(XMMRegister reg) const { return code_ == reg.code_; }
|
||||
const char* ToString();
|
||||
bool IsAllocatable() const;
|
||||
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
|
||||
bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
|
||||
int code() const {
|
||||
DCHECK(is_valid());
|
||||
return code_;
|
||||
return reg_code;
|
||||
}
|
||||
|
||||
// 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 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 code_ & 0x7;
|
||||
}
|
||||
int low_bits() const { return reg_code & 0x7; }
|
||||
|
||||
int code_;
|
||||
// Unfortunately we can't make this private in a struct when initializing
|
||||
// by assignment.
|
||||
int reg_code;
|
||||
};
|
||||
|
||||
const XMMRegister xmm0 = { 0 };
|
||||
const XMMRegister xmm1 = { 1 };
|
||||
const XMMRegister xmm2 = { 2 };
|
||||
const XMMRegister xmm3 = { 3 };
|
||||
const XMMRegister xmm4 = { 4 };
|
||||
const XMMRegister xmm5 = { 5 };
|
||||
const XMMRegister xmm6 = { 6 };
|
||||
const XMMRegister xmm7 = { 7 };
|
||||
const XMMRegister xmm8 = { 8 };
|
||||
const XMMRegister xmm9 = { 9 };
|
||||
const XMMRegister xmm10 = { 10 };
|
||||
const XMMRegister xmm11 = { 11 };
|
||||
const XMMRegister xmm12 = { 12 };
|
||||
const XMMRegister xmm13 = { 13 };
|
||||
const XMMRegister xmm14 = { 14 };
|
||||
const XMMRegister xmm15 = { 15 };
|
||||
|
||||
#define DECLARE_REGISTER(R) \
|
||||
const DoubleRegister R = {DoubleRegister::kCode_##R};
|
||||
DOUBLE_REGISTERS(DECLARE_REGISTER)
|
||||
#undef DECLARE_REGISTER
|
||||
const DoubleRegister no_double_reg = {DoubleRegister::kCode_no_reg};
|
||||
|
||||
|
||||
typedef XMMRegister DoubleRegister;
|
||||
|
||||
typedef DoubleRegister XMMRegister;
|
||||
|
||||
enum Condition {
|
||||
// any value < 0 is considered no_condition
|
||||
|
@ -294,13 +294,15 @@ class RecordWriteStub: public PlatformCodeStub {
|
||||
Register GetRegThatIsNotRcxOr(Register r1,
|
||||
Register r2,
|
||||
Register r3) {
|
||||
for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
|
||||
Register candidate = Register::FromAllocationIndex(i);
|
||||
if (candidate.is(rcx)) continue;
|
||||
if (candidate.is(r1)) continue;
|
||||
if (candidate.is(r2)) continue;
|
||||
if (candidate.is(r3)) continue;
|
||||
return candidate;
|
||||
for (int i = 0; i < Register::kNumRegisters; i++) {
|
||||
Register candidate = Register::from_code(i);
|
||||
if (candidate.IsAllocatable()) {
|
||||
if (candidate.is(rcx)) continue;
|
||||
if (candidate.is(r1)) continue;
|
||||
if (candidate.is(r2)) continue;
|
||||
if (candidate.is(r3)) continue;
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return no_reg;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "src/codegen.h"
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/full-codegen/full-codegen.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/safepoint-table.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -95,7 +96,7 @@ void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
|
||||
}
|
||||
input_->SetRegister(rsp.code(), reinterpret_cast<intptr_t>(frame->sp()));
|
||||
input_->SetRegister(rbp.code(), reinterpret_cast<intptr_t>(frame->fp()));
|
||||
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; i++) {
|
||||
input_->SetDoubleRegister(i, 0.0);
|
||||
}
|
||||
|
||||
@ -117,7 +118,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < XMMRegister::NumAllocatableRegisters(); ++i) {
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
@ -138,13 +139,14 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
// Save all general purpose registers before messing with them.
|
||||
const int kNumberOfRegisters = Register::kNumRegisters;
|
||||
|
||||
const int kDoubleRegsSize = kDoubleSize *
|
||||
XMMRegister::NumAllocatableRegisters();
|
||||
const int kDoubleRegsSize = kDoubleSize * XMMRegister::kMaxNumRegisters;
|
||||
__ subp(rsp, Immediate(kDoubleRegsSize));
|
||||
|
||||
for (int i = 0; i < XMMRegister::NumAllocatableRegisters(); ++i) {
|
||||
XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i);
|
||||
int offset = i * kDoubleSize;
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
XMMRegister xmm_reg = XMMRegister::from_code(code);
|
||||
int offset = code * kDoubleSize;
|
||||
__ movsd(Operand(rsp, offset), xmm_reg);
|
||||
}
|
||||
|
||||
@ -210,7 +212,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::NumAllocatableRegisters(); i++) {
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
|
||||
int dst_offset = i * kDoubleSize + double_regs_offset;
|
||||
__ popq(Operand(rbx, dst_offset));
|
||||
}
|
||||
@ -274,9 +276,10 @@ void Deoptimizer::TableEntryGenerator::Generate() {
|
||||
__ cmpp(rax, rdx);
|
||||
__ j(below, &outer_push_loop);
|
||||
|
||||
for (int i = 0; i < XMMRegister::NumAllocatableRegisters(); ++i) {
|
||||
XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i);
|
||||
int src_offset = i * kDoubleSize + double_regs_offset;
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
int code = config->GetAllocatableDoubleCode(i);
|
||||
XMMRegister xmm_reg = XMMRegister::from_code(code);
|
||||
int src_offset = code * kDoubleSize + double_regs_offset;
|
||||
__ movsd(xmm_reg, Operand(rbx, src_offset));
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ void LCodeGen::SaveCallerDoubles() {
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
while (!save_iterator.Done()) {
|
||||
__ movsd(MemOperand(rsp, count * kDoubleSize),
|
||||
XMMRegister::FromAllocationIndex(save_iterator.Current()));
|
||||
XMMRegister::from_code(save_iterator.Current()));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
}
|
||||
@ -104,7 +104,7 @@ void LCodeGen::RestoreCallerDoubles() {
|
||||
BitVector::Iterator save_iterator(doubles);
|
||||
int count = 0;
|
||||
while (!save_iterator.Done()) {
|
||||
__ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()),
|
||||
__ movsd(XMMRegister::from_code(save_iterator.Current()),
|
||||
MemOperand(rsp, count * kDoubleSize));
|
||||
save_iterator.Advance();
|
||||
count++;
|
||||
@ -436,12 +436,12 @@ bool LCodeGen::GenerateSafepointTable() {
|
||||
|
||||
|
||||
Register LCodeGen::ToRegister(int index) const {
|
||||
return Register::FromAllocationIndex(index);
|
||||
return Register::from_code(index);
|
||||
}
|
||||
|
||||
|
||||
XMMRegister LCodeGen::ToDoubleRegister(int index) const {
|
||||
return XMMRegister::FromAllocationIndex(index);
|
||||
return XMMRegister::from_code(index);
|
||||
}
|
||||
|
||||
|
||||
|
@ -470,14 +470,13 @@ LPlatformChunk* LChunkBuilder::Build() {
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
|
||||
Register::ToAllocationIndex(reg));
|
||||
return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
|
||||
return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
|
||||
XMMRegister::ToAllocationIndex(reg));
|
||||
return new (zone())
|
||||
LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/codegen.h"
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/x64/assembler-x64.h"
|
||||
#include "src/x64/macro-assembler-x64.h"
|
||||
|
||||
@ -729,7 +730,8 @@ void MacroAssembler::GetBuiltinEntry(Register target,
|
||||
}
|
||||
|
||||
|
||||
#define REG(Name) { kRegister_ ## Name ## _Code }
|
||||
#define REG(Name) \
|
||||
{ Register::kCode_##Name }
|
||||
|
||||
static const Register saved_regs[] = {
|
||||
REG(rax), REG(rcx), REG(rdx), REG(rbx), REG(rbp), REG(rsi), REG(rdi), REG(r8),
|
||||
@ -3710,12 +3712,14 @@ void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space,
|
||||
#endif
|
||||
// Optionally save all XMM registers.
|
||||
if (save_doubles) {
|
||||
int space = XMMRegister::kMaxNumAllocatableRegisters * kDoubleSize +
|
||||
arg_stack_space * kRegisterSize;
|
||||
int space = XMMRegister::kMaxNumRegisters * kDoubleSize +
|
||||
arg_stack_space * kRegisterSize;
|
||||
subp(rsp, Immediate(space));
|
||||
int offset = -2 * kPointerSize;
|
||||
for (int i = 0; i < XMMRegister::NumAllocatableRegisters(); i++) {
|
||||
XMMRegister reg = XMMRegister::FromAllocationIndex(i);
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
DoubleRegister reg =
|
||||
DoubleRegister::from_code(config->GetAllocatableDoubleCode(i));
|
||||
movsd(Operand(rbp, offset - ((i + 1) * kDoubleSize)), reg);
|
||||
}
|
||||
} else if (arg_stack_space > 0) {
|
||||
@ -3758,8 +3762,10 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) {
|
||||
// r15 : argv
|
||||
if (save_doubles) {
|
||||
int offset = -2 * kPointerSize;
|
||||
for (int i = 0; i < XMMRegister::NumAllocatableRegisters(); i++) {
|
||||
XMMRegister reg = XMMRegister::FromAllocationIndex(i);
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
|
||||
DoubleRegister reg =
|
||||
DoubleRegister::from_code(config->GetAllocatableDoubleCode(i));
|
||||
movsd(reg, Operand(rbp, offset - ((i + 1) * kDoubleSize)));
|
||||
}
|
||||
}
|
||||
|
@ -16,17 +16,17 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers for calling conventions.
|
||||
const Register kReturnRegister0 = {kRegister_rax_Code};
|
||||
const Register kReturnRegister1 = {kRegister_rdx_Code};
|
||||
const Register kJSFunctionRegister = {kRegister_rdi_Code};
|
||||
const Register kContextRegister = {kRegister_rsi_Code};
|
||||
const Register kInterpreterAccumulatorRegister = {kRegister_rax_Code};
|
||||
const Register kInterpreterRegisterFileRegister = {kRegister_r11_Code};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_r12_Code};
|
||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_r14_Code};
|
||||
const Register kInterpreterDispatchTableRegister = {kRegister_r15_Code};
|
||||
const Register kRuntimeCallFunctionRegister = {kRegister_rbx_Code};
|
||||
const Register kRuntimeCallArgCountRegister = {kRegister_rax_Code};
|
||||
const Register kReturnRegister0 = {Register::kCode_rax};
|
||||
const Register kReturnRegister1 = {Register::kCode_rdx};
|
||||
const Register kJSFunctionRegister = {Register::kCode_rdi};
|
||||
const Register kContextRegister = {Register::kCode_rsi};
|
||||
const Register kInterpreterAccumulatorRegister = {Register::kCode_rax};
|
||||
const Register kInterpreterRegisterFileRegister = {Register::kCode_r11};
|
||||
const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_r12};
|
||||
const Register kInterpreterBytecodeArrayRegister = {Register::kCode_r14};
|
||||
const Register kInterpreterDispatchTableRegister = {Register::kCode_r15};
|
||||
const Register kRuntimeCallFunctionRegister = {Register::kCode_rbx};
|
||||
const Register kRuntimeCallArgCountRegister = {Register::kCode_rax};
|
||||
|
||||
// Default scratch register used by MacroAssembler (and other code that needs
|
||||
// a spare register). The register isn't callee save, and not used by the
|
||||
|
@ -76,10 +76,6 @@ struct Register {
|
||||
|
||||
static inline const char* AllocationIndexToString(int index);
|
||||
|
||||
static inline int ToAllocationIndex(Register reg);
|
||||
|
||||
static inline Register FromAllocationIndex(int index);
|
||||
|
||||
static Register from_code(int code) {
|
||||
DCHECK(code >= 0);
|
||||
DCHECK(code < kNumRegisters);
|
||||
@ -132,18 +128,6 @@ inline const char* Register::AllocationIndexToString(int index) {
|
||||
}
|
||||
|
||||
|
||||
inline int Register::ToAllocationIndex(Register reg) {
|
||||
DCHECK(reg.is_valid() && !reg.is(esp) && !reg.is(ebp));
|
||||
return (reg.code() >= 6) ? reg.code() - 2 : reg.code();
|
||||
}
|
||||
|
||||
|
||||
inline Register Register::FromAllocationIndex(int index) {
|
||||
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
|
||||
return (index >= 4) ? from_code(index + 2) : from_code(index);
|
||||
}
|
||||
|
||||
|
||||
struct X87Register {
|
||||
static const int kMaxNumAllocatableRegisters = 6;
|
||||
static const int kMaxNumRegisters = 8;
|
||||
|
@ -73,7 +73,13 @@ class InterpreterState {
|
||||
AllocatedOperand::AllocatedKind kind;
|
||||
int index;
|
||||
if (!is_constant) {
|
||||
index = AllocatedOperand::cast(op).index();
|
||||
if (op.IsRegister()) {
|
||||
index = AllocatedOperand::cast(op).GetRegister().code();
|
||||
} else if (op.IsDoubleRegister()) {
|
||||
index = AllocatedOperand::cast(op).GetDoubleRegister().code();
|
||||
} else {
|
||||
index = AllocatedOperand::cast(op).index();
|
||||
}
|
||||
kind = AllocatedOperand::cast(op).allocated_kind();
|
||||
} else {
|
||||
index = ConstantOperand::cast(op).virtual_register();
|
||||
@ -90,7 +96,9 @@ class InterpreterState {
|
||||
return ConstantOperand(key.index);
|
||||
}
|
||||
return AllocatedOperand(
|
||||
key.kind, InstructionSequence::DefaultRepresentation(), key.index);
|
||||
key.kind,
|
||||
v8::internal::compiler::InstructionSequence::DefaultRepresentation(),
|
||||
key.index);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/machine-type.h"
|
||||
#include "src/compiler/raw-machine-assembler.h"
|
||||
#include "src/register-configuration.h"
|
||||
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/codegen-tester.h"
|
||||
@ -35,8 +36,9 @@ typedef double float64;
|
||||
// to select a representative set.
|
||||
class Pairs {
|
||||
public:
|
||||
Pairs(int max_pairs, int range)
|
||||
Pairs(int max_pairs, int range, const int* codes)
|
||||
: range_(range),
|
||||
codes_(codes),
|
||||
max_pairs_(std::min(max_pairs, range_ * range_)),
|
||||
counter_(0) {}
|
||||
|
||||
@ -46,37 +48,33 @@ class Pairs {
|
||||
do {
|
||||
// Find the next pair.
|
||||
if (exhaustive()) {
|
||||
*r0 = counter_ % range_;
|
||||
*r1 = counter_ / range_;
|
||||
*r0 = codes_[counter_ % range_];
|
||||
*r1 = codes_[counter_ / range_];
|
||||
} else {
|
||||
// Try each integer at least once for both r0 and r1.
|
||||
int index = counter_ / 2;
|
||||
if (counter_ & 1) {
|
||||
*r0 = index % range_;
|
||||
*r1 = index / range_;
|
||||
*r0 = codes_[index % range_];
|
||||
*r1 = codes_[index / range_];
|
||||
} else {
|
||||
*r1 = index % range_;
|
||||
*r0 = index / range_;
|
||||
*r1 = codes_[index % range_];
|
||||
*r0 = codes_[index / range_];
|
||||
}
|
||||
}
|
||||
counter_++;
|
||||
if (same_is_ok) break;
|
||||
if (*r0 == *r1) {
|
||||
if (counter_ >= max_pairs_) {
|
||||
// For the last hurrah, reg#0 with reg#n-1
|
||||
*r0 = 0;
|
||||
*r1 = range_ - 1;
|
||||
break;
|
||||
}
|
||||
if ((same_is_ok) || (*r0 != *r1)) break;
|
||||
if (counter_ == max_pairs_) {
|
||||
// For the last hurrah, reg#0 with reg#n-1
|
||||
*r0 = codes_[0];
|
||||
*r1 = codes_[range_ - 1];
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
DCHECK(*r0 >= 0 && *r0 < range_);
|
||||
DCHECK(*r1 >= 0 && *r1 < range_);
|
||||
}
|
||||
|
||||
private:
|
||||
int range_;
|
||||
const int* codes_;
|
||||
int max_pairs_;
|
||||
int counter_;
|
||||
bool exhaustive() { return max_pairs_ == (range_ * range_); }
|
||||
@ -86,7 +84,12 @@ class Pairs {
|
||||
// Pairs of general purpose registers.
|
||||
class RegisterPairs : public Pairs {
|
||||
public:
|
||||
RegisterPairs() : Pairs(100, Register::kMaxNumAllocatableRegisters) {}
|
||||
RegisterPairs()
|
||||
: Pairs(
|
||||
100, RegisterConfiguration::ArchDefault()
|
||||
->num_allocatable_general_registers(),
|
||||
RegisterConfiguration::ArchDefault()->allocatable_general_codes()) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -94,7 +97,10 @@ class RegisterPairs : public Pairs {
|
||||
class Float32RegisterPairs : public Pairs {
|
||||
public:
|
||||
Float32RegisterPairs()
|
||||
: Pairs(100, DoubleRegister::NumAllocatableAliasedRegisters()) {}
|
||||
: Pairs(
|
||||
100, RegisterConfiguration::ArchDefault()
|
||||
->num_allocatable_aliased_double_registers(),
|
||||
RegisterConfiguration::ArchDefault()->allocatable_double_codes()) {}
|
||||
};
|
||||
|
||||
|
||||
@ -102,7 +108,10 @@ class Float32RegisterPairs : public Pairs {
|
||||
class Float64RegisterPairs : public Pairs {
|
||||
public:
|
||||
Float64RegisterPairs()
|
||||
: Pairs(100, DoubleRegister::NumAllocatableAliasedRegisters()) {}
|
||||
: Pairs(
|
||||
100, RegisterConfiguration::ArchDefault()
|
||||
->num_allocatable_aliased_double_registers(),
|
||||
RegisterConfiguration::ArchDefault()->allocatable_double_codes()) {}
|
||||
};
|
||||
|
||||
|
||||
@ -624,9 +633,12 @@ static void Test_RunInt32SubWithRet(int retreg) {
|
||||
|
||||
|
||||
// Separate tests for parallelization.
|
||||
#define TEST_INT32_SUB_WITH_RET(x) \
|
||||
TEST(Run_Int32Sub_all_allocatable_pairs_##x) { \
|
||||
if (Register::kMaxNumAllocatableRegisters > x) Test_RunInt32SubWithRet(x); \
|
||||
#define TEST_INT32_SUB_WITH_RET(x) \
|
||||
TEST(Run_Int32Sub_all_allocatable_pairs_##x) { \
|
||||
if (x < Register::kNumRegisters && \
|
||||
Register::from_code(x).IsAllocatable()) { \
|
||||
Test_RunInt32SubWithRet(x); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@ -677,7 +689,8 @@ TEST(Run_CopyTwentyInt32_all_allocatable_pairs) {
|
||||
while (pairs.More()) {
|
||||
Zone zone;
|
||||
int parray[2];
|
||||
int rarray[] = {0};
|
||||
int rarray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableGeneralCode(0)};
|
||||
pairs.Next(&parray[0], &parray[1], false);
|
||||
Allocator params(parray, 2, nullptr, 0);
|
||||
Allocator rets(rarray, 1, nullptr, 0);
|
||||
@ -724,17 +737,20 @@ static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) {
|
||||
static void Test_Int32_WeightedSum_of_size(int count) {
|
||||
if (DISABLE_NATIVE_STACK_PARAMS) return;
|
||||
Int32Signature sig(count);
|
||||
for (int p0 = 0; p0 < Register::kMaxNumAllocatableRegisters; p0++) {
|
||||
Zone zone;
|
||||
for (int p0 = 0; p0 < Register::kNumRegisters; p0++) {
|
||||
if (Register::from_code(p0).IsAllocatable()) {
|
||||
Zone zone;
|
||||
|
||||
int parray[] = {p0};
|
||||
int rarray[] = {0};
|
||||
Allocator params(parray, 1, nullptr, 0);
|
||||
Allocator rets(rarray, 1, nullptr, 0);
|
||||
RegisterConfig config(params, rets);
|
||||
CallDescriptor* desc = config.Create(&zone, &sig);
|
||||
Run_Computation<int32_t>(desc, Build_Int32_WeightedSum,
|
||||
Compute_Int32_WeightedSum, 257 + count);
|
||||
int parray[] = {p0};
|
||||
int rarray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableGeneralCode(0)};
|
||||
Allocator params(parray, 1, nullptr, 0);
|
||||
Allocator rets(rarray, 1, nullptr, 0);
|
||||
RegisterConfig config(params, rets);
|
||||
CallDescriptor* desc = config.Create(&zone, &sig);
|
||||
Run_Computation<int32_t>(desc, Build_Int32_WeightedSum,
|
||||
Compute_Int32_WeightedSum, 257 + count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -782,8 +798,10 @@ template <int which>
|
||||
void Test_Int32_Select() {
|
||||
if (DISABLE_NATIVE_STACK_PARAMS) return;
|
||||
|
||||
int parray[] = {0};
|
||||
int rarray[] = {0};
|
||||
int parray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableGeneralCode(0)};
|
||||
int rarray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableGeneralCode(0)};
|
||||
Allocator params(parray, 1, nullptr, 0);
|
||||
Allocator rets(rarray, 1, nullptr, 0);
|
||||
RegisterConfig config(params, rets);
|
||||
@ -819,10 +837,13 @@ TEST_INT32_SELECT(63)
|
||||
|
||||
|
||||
TEST(Int64Select_registers) {
|
||||
if (Register::kMaxNumAllocatableRegisters < 2) return;
|
||||
if (RegisterConfiguration::ArchDefault()
|
||||
->num_allocatable_general_registers() < 2)
|
||||
return;
|
||||
if (kPointerSize < 8) return; // TODO(titzer): int64 on 32-bit platforms
|
||||
|
||||
int rarray[] = {0};
|
||||
int rarray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableGeneralCode(0)};
|
||||
ArgsBuffer<int64_t>::Sig sig(2);
|
||||
|
||||
RegisterPairs pairs;
|
||||
@ -842,9 +863,13 @@ TEST(Int64Select_registers) {
|
||||
|
||||
|
||||
TEST(Float32Select_registers) {
|
||||
if (RegisterConfiguration::ArchDefault()->num_double_registers() < 2) return;
|
||||
if (RegisterConfiguration::ArchDefault()->num_allocatable_double_registers() <
|
||||
2) {
|
||||
return;
|
||||
}
|
||||
|
||||
int rarray[] = {0};
|
||||
int rarray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableDoubleCode(0)};
|
||||
ArgsBuffer<float32>::Sig sig(2);
|
||||
|
||||
Float32RegisterPairs pairs;
|
||||
@ -864,9 +889,14 @@ TEST(Float32Select_registers) {
|
||||
|
||||
|
||||
TEST(Float64Select_registers) {
|
||||
if (RegisterConfiguration::ArchDefault()->num_double_registers() < 2) return;
|
||||
|
||||
int rarray[] = {0};
|
||||
if (RegisterConfiguration::ArchDefault()->num_allocatable_double_registers() <
|
||||
2)
|
||||
return;
|
||||
if (RegisterConfiguration::ArchDefault()
|
||||
->num_allocatable_general_registers() < 2)
|
||||
return;
|
||||
int rarray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableDoubleCode(0)};
|
||||
ArgsBuffer<float64>::Sig sig(2);
|
||||
|
||||
Float64RegisterPairs pairs;
|
||||
@ -887,7 +917,8 @@ TEST(Float64Select_registers) {
|
||||
|
||||
TEST(Float32Select_stack_params_return_reg) {
|
||||
if (DISABLE_NATIVE_STACK_PARAMS) return;
|
||||
int rarray[] = {0};
|
||||
int rarray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableDoubleCode(0)};
|
||||
Allocator params(nullptr, 0, nullptr, 0);
|
||||
Allocator rets(nullptr, 0, rarray, 1);
|
||||
RegisterConfig config(params, rets);
|
||||
@ -908,7 +939,8 @@ TEST(Float32Select_stack_params_return_reg) {
|
||||
|
||||
TEST(Float64Select_stack_params_return_reg) {
|
||||
if (DISABLE_NATIVE_STACK_PARAMS) return;
|
||||
int rarray[] = {0};
|
||||
int rarray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableDoubleCode(0)};
|
||||
Allocator params(nullptr, 0, nullptr, 0);
|
||||
Allocator rets(nullptr, 0, rarray, 1);
|
||||
RegisterConfig config(params, rets);
|
||||
@ -962,7 +994,8 @@ static void Build_Select_With_Call(CallDescriptor* desc,
|
||||
TEST(Float64StackParamsToStackParams) {
|
||||
if (DISABLE_NATIVE_STACK_PARAMS) return;
|
||||
|
||||
int rarray[] = {0};
|
||||
int rarray[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableDoubleCode(0)};
|
||||
Allocator params(nullptr, 0, nullptr, 0);
|
||||
Allocator rets(nullptr, 0, rarray, 1);
|
||||
|
||||
@ -1005,10 +1038,18 @@ void MixedParamTest(int start) {
|
||||
const int num_params = static_cast<int>(arraysize(types) - start);
|
||||
|
||||
// Build call descriptor
|
||||
int parray[] = {0, 1};
|
||||
int rarray[] = {0};
|
||||
Allocator palloc(parray, 2, parray, 2);
|
||||
Allocator ralloc(rarray, 1, rarray, 1);
|
||||
int parray_gp[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableGeneralCode(0),
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableGeneralCode(1)};
|
||||
int rarray_gp[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableGeneralCode(0)};
|
||||
int parray_fp[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableDoubleCode(0),
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableDoubleCode(1)};
|
||||
int rarray_fp[] = {
|
||||
RegisterConfiguration::ArchDefault()->GetAllocatableDoubleCode(0)};
|
||||
Allocator palloc(parray_gp, 2, parray_fp, 2);
|
||||
Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
|
||||
RegisterConfig config(palloc, ralloc);
|
||||
|
||||
for (int which = 0; which < num_params; which++) {
|
||||
|
@ -76,11 +76,13 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
// Save registers make sure they don't get clobbered.
|
||||
int source_reg_offset = kDoubleSize;
|
||||
int reg_num = 0;
|
||||
for (; reg_num < Register::NumAllocatableRegisters(); ++reg_num) {
|
||||
for (; reg_num < Register::kNumRegisters; ++reg_num) {
|
||||
Register reg = Register::from_code(reg_num);
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ push(reg);
|
||||
source_reg_offset += kPointerSize;
|
||||
if (reg.IsAllocatable()) {
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ push(reg);
|
||||
source_reg_offset += kPointerSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,11 +107,13 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
// Make sure no registers have been unexpectedly clobbered
|
||||
for (--reg_num; reg_num >= 0; --reg_num) {
|
||||
Register reg = Register::from_code(reg_num);
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ ldr(ip, MemOperand(sp, 0));
|
||||
__ cmp(reg, ip);
|
||||
__ Assert(eq, kRegisterWasClobbered);
|
||||
__ add(sp, sp, Operand(kPointerSize));
|
||||
if (reg.IsAllocatable()) {
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ ldr(ip, MemOperand(sp, 0));
|
||||
__ cmp(reg, ip);
|
||||
__ Assert(eq, kRegisterWasClobbered);
|
||||
__ add(sp, sp, Operand(kPointerSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,11 +72,13 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
// Save registers make sure they don't get clobbered.
|
||||
int source_reg_offset = kDoubleSize;
|
||||
int reg_num = 0;
|
||||
for (; reg_num < Register::NumAllocatableRegisters(); ++reg_num) {
|
||||
for (; reg_num < Register::kNumRegisters; ++reg_num) {
|
||||
Register reg = Register::from_code(reg_num);
|
||||
if (!reg.is(destination_reg)) {
|
||||
queue.Queue(reg);
|
||||
source_reg_offset += kPointerSize;
|
||||
if (reg.IsAllocatable()) {
|
||||
if (!reg.is(destination_reg)) {
|
||||
queue.Queue(reg);
|
||||
source_reg_offset += kPointerSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Re-push the double argument.
|
||||
@ -101,10 +103,12 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
// // Make sure no registers have been unexpectedly clobbered
|
||||
for (--reg_num; reg_num >= 0; --reg_num) {
|
||||
Register reg = Register::from_code(reg_num);
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ Pop(ip0);
|
||||
__ cmp(reg, ip0);
|
||||
__ Assert(eq, kRegisterWasClobbered);
|
||||
if (reg.IsAllocatable()) {
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ Pop(ip0);
|
||||
__ cmp(reg, ip0);
|
||||
__ Assert(eq, kRegisterWasClobbered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,11 +70,13 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
int param_offset = 7 * kPointerSize;
|
||||
// Save registers make sure they don't get clobbered.
|
||||
int reg_num = 0;
|
||||
for (; reg_num < Register::NumAllocatableRegisters(); ++reg_num) {
|
||||
Register reg = Register::FromAllocationIndex(reg_num);
|
||||
if (!reg.is(esp) && !reg.is(ebp) && !reg.is(destination_reg)) {
|
||||
__ push(reg);
|
||||
param_offset += kPointerSize;
|
||||
for (; reg_num < Register::kNumRegisters; ++reg_num) {
|
||||
Register reg = Register::from_code(reg_num);
|
||||
if (reg.IsAllocatable()) {
|
||||
if (!reg.is(esp) && !reg.is(ebp) && !reg.is(destination_reg)) {
|
||||
__ push(reg);
|
||||
param_offset += kPointerSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,11 +91,13 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
|
||||
// Make sure no registers have been unexpectedly clobbered
|
||||
for (--reg_num; reg_num >= 0; --reg_num) {
|
||||
Register reg = Register::FromAllocationIndex(reg_num);
|
||||
if (!reg.is(esp) && !reg.is(ebp) && !reg.is(destination_reg)) {
|
||||
__ cmp(reg, MemOperand(esp, 0));
|
||||
__ Assert(equal, kRegisterWasClobbered);
|
||||
__ add(esp, Immediate(kPointerSize));
|
||||
Register reg = Register::from_code(reg_num);
|
||||
if (reg.IsAllocatable()) {
|
||||
if (!reg.is(esp) && !reg.is(ebp) && !reg.is(destination_reg)) {
|
||||
__ cmp(reg, MemOperand(esp, 0));
|
||||
__ Assert(equal, kRegisterWasClobbered);
|
||||
__ add(esp, Immediate(kPointerSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "src/factory.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/mips/constants-mips.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-code-stubs.h"
|
||||
@ -79,11 +80,13 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
// Save registers make sure they don't get clobbered.
|
||||
int source_reg_offset = kDoubleSize;
|
||||
int reg_num = 2;
|
||||
for (; reg_num < Register::NumAllocatableRegisters(); ++reg_num) {
|
||||
for (; reg_num < Register::kNumRegisters; ++reg_num) {
|
||||
Register reg = Register::from_code(reg_num);
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ push(reg);
|
||||
source_reg_offset += kPointerSize;
|
||||
if (reg.IsAllocatable()) {
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ push(reg);
|
||||
source_reg_offset += kPointerSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,10 +111,12 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
// Make sure no registers have been unexpectedly clobbered
|
||||
for (--reg_num; reg_num >= 2; --reg_num) {
|
||||
Register reg = Register::from_code(reg_num);
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ lw(at, MemOperand(sp, 0));
|
||||
__ Assert(eq, kRegisterWasClobbered, reg, Operand(at));
|
||||
__ Addu(sp, sp, Operand(kPointerSize));
|
||||
if (reg.IsAllocatable()) {
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ lw(at, MemOperand(sp, 0));
|
||||
__ Assert(eq, kRegisterWasClobbered, reg, Operand(at));
|
||||
__ Addu(sp, sp, Operand(kPointerSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "src/factory.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/mips64/constants-mips64.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-code-stubs.h"
|
||||
@ -79,7 +80,8 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
// Save registers make sure they don't get clobbered.
|
||||
int source_reg_offset = kDoubleSize;
|
||||
int reg_num = 2;
|
||||
for (; reg_num < Register::NumAllocatableRegisters(); ++reg_num) {
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
for (; reg_num < config->num_allocatable_general_registers(); ++reg_num) {
|
||||
Register reg = Register::from_code(reg_num);
|
||||
if (!reg.is(destination_reg)) {
|
||||
__ push(reg);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "src/code-stubs.h"
|
||||
#include "src/factory.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-code-stubs.h"
|
||||
|
||||
@ -62,20 +63,24 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
__ pushq(rsi);
|
||||
__ pushq(rdi);
|
||||
|
||||
|
||||
const RegisterConfiguration* config = RegisterConfiguration::ArchDefault();
|
||||
if (!source_reg.is(rsp)) {
|
||||
// The argument we pass to the stub is not a heap number, but instead
|
||||
// stack-allocated and offset-wise made to look like a heap number for
|
||||
// the stub. We create that "heap number" after pushing all allocatable
|
||||
// registers.
|
||||
int double_argument_slot =
|
||||
(Register::NumAllocatableRegisters() - 1) * kPointerSize + kDoubleSize;
|
||||
(config->num_allocatable_general_registers() - 1) * kPointerSize +
|
||||
kDoubleSize;
|
||||
__ leaq(source_reg, MemOperand(rsp, -double_argument_slot - offset));
|
||||
}
|
||||
|
||||
// Save registers make sure they don't get clobbered.
|
||||
int reg_num = 0;
|
||||
for (; reg_num < Register::NumAllocatableRegisters(); ++reg_num) {
|
||||
Register reg = Register::FromAllocationIndex(reg_num);
|
||||
for (; reg_num < config->num_allocatable_general_registers(); ++reg_num) {
|
||||
Register reg =
|
||||
Register::from_code(config->GetAllocatableGeneralCode(reg_num));
|
||||
if (!reg.is(rsp) && !reg.is(rbp) && !reg.is(destination_reg)) {
|
||||
__ pushq(reg);
|
||||
}
|
||||
@ -92,7 +97,8 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
|
||||
|
||||
// Make sure no registers have been unexpectedly clobbered
|
||||
for (--reg_num; reg_num >= 0; --reg_num) {
|
||||
Register reg = Register::FromAllocationIndex(reg_num);
|
||||
Register reg =
|
||||
Register::from_code(config->GetAllocatableGeneralCode(reg_num));
|
||||
if (!reg.is(rsp) && !reg.is(rbp) && !reg.is(destination_reg)) {
|
||||
__ cmpq(reg, MemOperand(rsp, 0));
|
||||
__ Assert(equal, kRegisterWasClobbered);
|
||||
|
@ -127,8 +127,7 @@ bool InstructionSelectorTest::Stream::IsFixed(const InstructionOperand* operand,
|
||||
if (!operand->IsUnallocated()) return false;
|
||||
const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
|
||||
if (!unallocated->HasFixedRegisterPolicy()) return false;
|
||||
const int index = Register::ToAllocationIndex(reg);
|
||||
return unallocated->fixed_register_index() == index;
|
||||
return unallocated->fixed_register_index() == reg.code();
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,6 +20,14 @@ static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
|
||||
RegisterConfiguration::kMaxDoubleRegisters)];
|
||||
|
||||
|
||||
namespace {
|
||||
static int allocatable_codes[InstructionSequenceTest::kDefaultNRegs] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7};
|
||||
static int allocatable_double_codes[InstructionSequenceTest::kDefaultNRegs] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7};
|
||||
}
|
||||
|
||||
|
||||
static void InitializeRegisterNames() {
|
||||
char* loc = register_names_;
|
||||
for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
|
||||
@ -59,8 +67,10 @@ void InstructionSequenceTest::SetNumRegs(int num_general_registers,
|
||||
RegisterConfiguration* InstructionSequenceTest::config() {
|
||||
if (config_.is_empty()) {
|
||||
config_.Reset(new RegisterConfiguration(
|
||||
num_general_registers_, num_double_registers_, num_double_registers_,
|
||||
general_register_names_, double_register_names_));
|
||||
num_general_registers_, num_double_registers_, num_general_registers_,
|
||||
num_double_registers_, num_double_registers_, allocatable_codes,
|
||||
allocatable_double_codes, general_register_names_,
|
||||
double_register_names_));
|
||||
}
|
||||
return config_.get();
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace compiler {
|
||||
|
||||
class InstructionSequenceTest : public TestWithIsolateAndZone {
|
||||
public:
|
||||
static const int kDefaultNRegs = 4;
|
||||
static const int kDefaultNRegs = 8;
|
||||
static const int kNoValue = kMinInt;
|
||||
|
||||
typedef RpoNumber Rpo;
|
||||
|
@ -41,7 +41,8 @@ bool AllocatedOperandMatches(
|
||||
const AllocatedOperand& op,
|
||||
const InstructionSequenceTest::TestOperand& test_op) {
|
||||
return AreOperandsOfSameType(op, test_op) &&
|
||||
(op.index() == test_op.value_ ||
|
||||
((op.IsRegister() ? op.GetRegister().code() : op.index()) ==
|
||||
test_op.value_ ||
|
||||
test_op.value_ == InstructionSequenceTest::kNoValue);
|
||||
}
|
||||
|
||||
|
@ -585,8 +585,6 @@
|
||||
'../../src/compiler/register-allocator.h',
|
||||
'../../src/compiler/register-allocator-verifier.cc',
|
||||
'../../src/compiler/register-allocator-verifier.h',
|
||||
'../../src/compiler/register-configuration.cc',
|
||||
'../../src/compiler/register-configuration.h',
|
||||
'../../src/compiler/representation-change.h',
|
||||
'../../src/compiler/schedule.cc',
|
||||
'../../src/compiler/schedule.h',
|
||||
@ -914,6 +912,8 @@
|
||||
'../../src/regexp/regexp-macro-assembler.h',
|
||||
'../../src/regexp/regexp-stack.cc',
|
||||
'../../src/regexp/regexp-stack.h',
|
||||
'../../src/register-configuration.cc',
|
||||
'../../src/register-configuration.h',
|
||||
'../../src/rewriter.cc',
|
||||
'../../src/rewriter.h',
|
||||
'../../src/runtime-profiler.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user