Commit 2e5845f1 authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: Re-reland: Remove register index/code indirection.

    port 5cf1c0bc (r31087).

    original commit message:
    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.

    additional comment:
    This patch must be work with CL https://codereview.chromium.org/1405673003/
    and CL https://codereview.chromium.org/1413343002/
    which provide the needed register allocation common code change in
    v8 for this CL

BUG=

Review URL: https://codereview.chromium.org/1410393004

Cr-Commit-Position: refs/heads/master@{#31494}
parent cfcc019a
......@@ -518,13 +518,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);
}
X87Register LCodeGen::ToX87Register(int index) const {
return X87Register::FromAllocationIndex(index);
X87Register LCodeGen::ToX87Register(int code) const {
return X87Register::from_code(code);
}
......@@ -700,7 +700,7 @@ void LCodeGen::X87Stack::CommitWrite(X87Register reg) {
DCHECK(is_mutable_);
// Assert the reg is prepared to write, but not on the virtual stack yet
DCHECK(!Contains(reg) && stack_[stack_depth_].is(reg) &&
stack_depth_ < X87Register::kMaxNumAllocatableRegisters);
stack_depth_ < X87Register::kMaxNumAllocatableRegisters);
stack_depth_++;
}
......
......@@ -5,6 +5,7 @@
#if V8_TARGET_ARCH_X87
#include "src/crankshaft/x87/lithium-gap-resolver-x87.h"
#include "src/register-configuration.h"
#include "src/crankshaft/x87/lithium-codegen-x87.h"
......@@ -166,10 +167,14 @@ 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(RegisterConfiguration::CRANKSHAFT);
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;
......@@ -179,10 +184,12 @@ 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(RegisterConfiguration::CRANKSHAFT);
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;
}
......@@ -205,7 +212,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);
......@@ -214,7 +221,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;
}
}
......@@ -223,7 +230,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.
......@@ -232,19 +239,22 @@ 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(RegisterConfiguration::CRANKSHAFT);
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(X87Register reg) {
return new (zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
X87Register::ToAllocationIndex(reg));
return new (zone())
LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
}
......
......@@ -41,10 +41,47 @@
#include "src/assembler.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(stX_0) \
V(stX_1) \
V(stX_2) \
V(stX_3) \
V(stX_4) \
V(stX_5) \
V(stX_6) \
V(stX_7)
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
V(stX_0) \
V(stX_1) \
V(stX_2) \
V(stX_3) \
V(stX_4) \
V(stX_5)
// CPU Registers.
//
// 1) We would prefer to use an enum, but enum values are assignment-
......@@ -67,129 +104,87 @@ 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 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 };
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 X87Register {
static const int kMaxNumAllocatableRegisters = 6;
static const int kMaxNumRegisters = 8;
static int NumAllocatableRegisters() {
return kMaxNumAllocatableRegisters;
}
// TODO(turbofan): Proper support for float32.
static int NumAllocatableAliasedRegisters() {
return NumAllocatableRegisters();
}
#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};
static int ToAllocationIndex(X87Register reg) {
return reg.code_;
}
struct DoubleRegister {
enum Code {
#define REGISTER_CODE(R) kCode_##R,
DOUBLE_REGISTERS(REGISTER_CODE)
#undef REGISTER_CODE
kAfterLast,
kCode_no_reg = -1
};
static const char* AllocationIndexToString(int index) {
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
const char* const names[] = {
"stX_0", "stX_1", "stX_2", "stX_3", "stX_4",
"stX_5", "stX_6", "stX_7"
};
return names[index];
}
static const int kMaxNumRegisters = Code::kAfterLast;
static const int kMaxNumAllocatableRegisters = 6;
static X87Register FromAllocationIndex(int index) {
DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
X87Register result;
result.code_ = index;
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(X87Register reg) const {
return code_ == reg.code_;
}
int code_;
};
bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
const char* ToString();
typedef X87Register DoubleRegister;
int reg_code;
};
const X87Register stX_0 = { 0 };
const X87Register stX_1 = { 1 };
const X87Register stX_2 = { 2 };
const X87Register stX_3 = { 3 };
const X87Register stX_4 = { 4 };
const X87Register stX_5 = { 5 };
const X87Register stX_6 = { 6 };
const X87Register stX_7 = { 7 };
#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 DoubleRegister X87Register;
enum Condition {
// any value < 0 is considered no_condition
......
......@@ -309,13 +309,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;
......
......@@ -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"
#include "src/x87/frames-x87.h"
......@@ -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 < DoubleRegister::NumAllocatableRegisters(); i++) {
for (int i = 0; i < X87Register::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 < X87Register::kMaxNumAllocatableRegisters; ++i) {
for (int i = 0; i < X87Register::kMaxNumRegisters; ++i) {
double double_value = input_->GetDoubleRegister(i);
output_frame->SetDoubleRegister(i, double_value);
}
......@@ -233,8 +234,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
// Save all general purpose registers before messing with them.
const int kNumberOfRegisters = Register::kNumRegisters;
const int kDoubleRegsSize =
kDoubleSize * X87Register::kMaxNumAllocatableRegisters;
const int kDoubleRegsSize = kDoubleSize * X87Register::kMaxNumRegisters;
// Reserve space for x87 fp registers.
__ sub(esp, Immediate(kDoubleRegsSize));
......@@ -312,10 +312,13 @@ void Deoptimizer::TableEntryGenerator::Generate() {
}
int double_regs_offset = FrameDescription::double_registers_offset();
const RegisterConfiguration* config =
RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
// Fill in the double input registers.
for (int i = 0; i < X87Register::kMaxNumAllocatableRegisters; ++i) {
int dst_offset = i * kDoubleSize + double_regs_offset;
int src_offset = i * kDoubleSize;
int code = config->GetAllocatableDoubleCode(i);
int dst_offset = code * kDoubleSize + double_regs_offset;
int src_offset = code * kDoubleSize;
__ fld_d(Operand(esp, src_offset));
__ fstp_d(Operand(ebx, dst_offset));
}
......
......@@ -14,16 +14,16 @@ 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 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 kRuntimeCallFunctionRegister = {Register::kCode_ebx};
const Register kRuntimeCallArgCountRegister = {Register::kCode_eax};
// Spill slots used by interpreter dispatch calling convention.
const int kInterpreterDispatchTableSpillSlot = -1;
......
......@@ -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));
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment