Allow more virtual registers to be encoded in LUnallocated.

This is a preparation which allows us to bump the virtual register width
from 15 to 18 bit without sacrificing width for other fields inside an
unallocated lithium operand.

R=svenpanne@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14513 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2013-05-02 09:51:07 +00:00
parent c092da378b
commit 47608c900a
8 changed files with 154 additions and 93 deletions

View File

@ -2453,7 +2453,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
if (spill_index > LUnallocated::kMaxFixedIndex) { if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
Abort("Too many spill slots needed for OSR"); Abort("Too many spill slots needed for OSR");
spill_index = 0; spill_index = 0;
} }

View File

@ -299,14 +299,14 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
// //
// The encoding is as a signed value, with parameters and receiver using // The encoding is as a signed value, with parameters and receiver using
// the negative indices and locals the non-negative ones. // the negative indices and locals the non-negative ones.
const int parameter_limit = -LUnallocated::kMinFixedIndex; const int parameter_limit = -LUnallocated::kMinFixedSlotIndex;
Scope* scope = info()->scope(); Scope* scope = info()->scope();
if ((scope->num_parameters() + 1) > parameter_limit) { if ((scope->num_parameters() + 1) > parameter_limit) {
info()->set_bailout_reason("too many parameters"); info()->set_bailout_reason("too many parameters");
return AbortOptimization(); return AbortOptimization();
} }
const int locals_limit = LUnallocated::kMaxFixedIndex; const int locals_limit = LUnallocated::kMaxFixedSlotIndex;
if (!info()->osr_ast_id().IsNone() && if (!info()->osr_ast_id().IsNone() &&
scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) { scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) {
info()->set_bailout_reason("too many parameters/locals"); info()->set_bailout_reason("too many parameters/locals");

View File

@ -2584,7 +2584,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
if (spill_index > LUnallocated::kMaxFixedIndex) { if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
Abort("Too many spill slots needed for OSR"); Abort("Too many spill slots needed for OSR");
spill_index = 0; spill_index = 0;
} }

View File

@ -625,13 +625,13 @@ LOperand* LAllocator::AllocateFixed(LUnallocated* operand,
bool is_tagged) { bool is_tagged) {
TraceAlloc("Allocating fixed reg for op %d\n", operand->virtual_register()); TraceAlloc("Allocating fixed reg for op %d\n", operand->virtual_register());
ASSERT(operand->HasFixedPolicy()); ASSERT(operand->HasFixedPolicy());
if (operand->policy() == LUnallocated::FIXED_SLOT) { if (operand->HasFixedSlotPolicy()) {
operand->ConvertTo(LOperand::STACK_SLOT, operand->fixed_index()); operand->ConvertTo(LOperand::STACK_SLOT, operand->fixed_slot_index());
} else if (operand->policy() == LUnallocated::FIXED_REGISTER) { } else if (operand->HasFixedRegisterPolicy()) {
int reg_index = operand->fixed_index(); int reg_index = operand->fixed_register_index();
operand->ConvertTo(LOperand::REGISTER, reg_index); operand->ConvertTo(LOperand::REGISTER, reg_index);
} else if (operand->policy() == LUnallocated::FIXED_DOUBLE_REGISTER) { } else if (operand->HasFixedDoubleRegisterPolicy()) {
int reg_index = operand->fixed_index(); int reg_index = operand->fixed_register_index();
operand->ConvertTo(LOperand::DOUBLE_REGISTER, reg_index); operand->ConvertTo(LOperand::DOUBLE_REGISTER, reg_index);
} else { } else {
UNREACHABLE(); UNREACHABLE();
@ -846,7 +846,7 @@ void LAllocator::MeetConstraintsBetween(LInstruction* first,
bool is_tagged = HasTaggedValue(cur_input->virtual_register()); bool is_tagged = HasTaggedValue(cur_input->virtual_register());
AllocateFixed(cur_input, gap_index + 1, is_tagged); AllocateFixed(cur_input, gap_index + 1, is_tagged);
AddConstraintsGapMove(gap_index, input_copy, cur_input); AddConstraintsGapMove(gap_index, input_copy, cur_input);
} else if (cur_input->policy() == LUnallocated::WRITABLE_REGISTER) { } else if (cur_input->HasWritableRegisterPolicy()) {
// The live range of writable input registers always goes until the end // The live range of writable input registers always goes until the end
// of the instruction. // of the instruction.
ASSERT(!cur_input->IsUsedAtStart()); ASSERT(!cur_input->IsUsedAtStart());

View File

@ -58,24 +58,27 @@ void LOperand::PrintTo(StringStream* stream) {
case UNALLOCATED: case UNALLOCATED:
unalloc = LUnallocated::cast(this); unalloc = LUnallocated::cast(this);
stream->Add("v%d", unalloc->virtual_register()); stream->Add("v%d", unalloc->virtual_register());
switch (unalloc->policy()) { if (unalloc->basic_policy() == LUnallocated::FIXED_SLOT) {
stream->Add("(=%dS)", unalloc->fixed_slot_index());
break;
}
switch (unalloc->extended_policy()) {
case LUnallocated::NONE: case LUnallocated::NONE:
break; break;
case LUnallocated::FIXED_REGISTER: { case LUnallocated::FIXED_REGISTER: {
int reg_index = unalloc->fixed_register_index();
const char* register_name = const char* register_name =
Register::AllocationIndexToString(unalloc->fixed_index()); Register::AllocationIndexToString(reg_index);
stream->Add("(=%s)", register_name); stream->Add("(=%s)", register_name);
break; break;
} }
case LUnallocated::FIXED_DOUBLE_REGISTER: { case LUnallocated::FIXED_DOUBLE_REGISTER: {
int reg_index = unalloc->fixed_register_index();
const char* double_register_name = const char* double_register_name =
DoubleRegister::AllocationIndexToString(unalloc->fixed_index()); DoubleRegister::AllocationIndexToString(reg_index);
stream->Add("(=%s)", double_register_name); stream->Add("(=%s)", double_register_name);
break; break;
} }
case LUnallocated::FIXED_SLOT:
stream->Add("(=%dS)", unalloc->fixed_index());
break;
case LUnallocated::MUST_HAVE_REGISTER: case LUnallocated::MUST_HAVE_REGISTER:
stream->Add("(R)"); stream->Add("(R)");
break; break;

View File

@ -92,12 +92,16 @@ class LOperand: public ZoneObject {
class LUnallocated: public LOperand { class LUnallocated: public LOperand {
public: public:
enum Policy { enum BasicPolicy {
FIXED_SLOT,
EXTENDED_POLICY
};
enum ExtendedPolicy {
NONE, NONE,
ANY, ANY,
FIXED_REGISTER, FIXED_REGISTER,
FIXED_DOUBLE_REGISTER, FIXED_DOUBLE_REGISTER,
FIXED_SLOT,
MUST_HAVE_REGISTER, MUST_HAVE_REGISTER,
WRITABLE_REGISTER, WRITABLE_REGISTER,
SAME_AS_FIRST_INPUT SAME_AS_FIRST_INPUT
@ -117,76 +121,32 @@ class LUnallocated: public LOperand {
USED_AT_END USED_AT_END
}; };
explicit LUnallocated(Policy policy) : LOperand(UNALLOCATED, 0) { explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) {
Initialize(policy, 0, USED_AT_END); value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
value_ |= ExtendedPolicyField::encode(policy);
value_ |= LifetimeField::encode(USED_AT_END);
} }
LUnallocated(Policy policy, int fixed_index) : LOperand(UNALLOCATED, 0) { LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
Initialize(policy, fixed_index, USED_AT_END); ASSERT(policy == FIXED_SLOT);
value_ |= BasicPolicyField::encode(policy);
value_ |= index << FixedSlotIndexField::kShift;
ASSERT(this->fixed_slot_index() == index);
} }
LUnallocated(Policy policy, Lifetime lifetime) : LOperand(UNALLOCATED, 0) { LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
Initialize(policy, 0, lifetime); ASSERT(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
value_ |= ExtendedPolicyField::encode(policy);
value_ |= LifetimeField::encode(USED_AT_END);
value_ |= FixedRegisterField::encode(index);
} }
// The superclass has a KindField. Some policies have a signed fixed LUnallocated(ExtendedPolicy policy, Lifetime lifetime)
// index in the upper bits. : LOperand(UNALLOCATED, 0) {
static const int kPolicyWidth = 3; value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
static const int kLifetimeWidth = 1; value_ |= ExtendedPolicyField::encode(policy);
static const int kVirtualRegisterWidth = 15; value_ |= LifetimeField::encode(lifetime);
static const int kPolicyShift = kKindFieldWidth;
static const int kLifetimeShift = kPolicyShift + kPolicyWidth;
static const int kVirtualRegisterShift = kLifetimeShift + kLifetimeWidth;
static const int kFixedIndexShift =
kVirtualRegisterShift + kVirtualRegisterWidth;
static const int kFixedIndexWidth = 32 - kFixedIndexShift;
STATIC_ASSERT(kFixedIndexWidth > 5);
class PolicyField : public BitField<Policy, kPolicyShift, kPolicyWidth> { };
class LifetimeField
: public BitField<Lifetime, kLifetimeShift, kLifetimeWidth> {
};
class VirtualRegisterField
: public BitField<unsigned,
kVirtualRegisterShift,
kVirtualRegisterWidth> {
};
static const int kMaxVirtualRegisters = 1 << kVirtualRegisterWidth;
static const int kMaxFixedIndex = (1 << (kFixedIndexWidth - 1)) - 1;
static const int kMinFixedIndex = -(1 << (kFixedIndexWidth - 1));
bool HasAnyPolicy() const {
return policy() == ANY;
}
bool HasFixedPolicy() const {
return policy() == FIXED_REGISTER ||
policy() == FIXED_DOUBLE_REGISTER ||
policy() == FIXED_SLOT;
}
bool HasRegisterPolicy() const {
return policy() == WRITABLE_REGISTER || policy() == MUST_HAVE_REGISTER;
}
bool HasSameAsInputPolicy() const {
return policy() == SAME_AS_FIRST_INPUT;
}
Policy policy() const { return PolicyField::decode(value_); }
void set_policy(Policy policy) {
value_ = PolicyField::update(value_, policy);
}
int fixed_index() const {
return static_cast<int>(value_) >> kFixedIndexShift;
}
int virtual_register() const {
return VirtualRegisterField::decode(value_);
}
void set_virtual_register(unsigned id) {
value_ = VirtualRegisterField::update(value_, id);
} }
LUnallocated* CopyUnconstrained(Zone* zone) { LUnallocated* CopyUnconstrained(Zone* zone) {
@ -200,16 +160,114 @@ class LUnallocated: public LOperand {
return reinterpret_cast<LUnallocated*>(op); return reinterpret_cast<LUnallocated*>(op);
} }
bool IsUsedAtStart() { // The encoding used for LUnallocated operands depends on the policy that is
return LifetimeField::decode(value_) == USED_AT_START; // stored within the operand. The FIXED_SLOT policy uses a compact encoding
// because it accommodates a larger pay-load.
//
// For FIXED_SLOT policy:
// +------------------------------------------+
// | slot_index | vreg | 0 | 001 |
// +------------------------------------------+
//
// For all other (extended) policies:
// +------------------------------------------+
// | reg_index | L | PPP | vreg | 1 | 001 | L ... Lifetime
// +------------------------------------------+ P ... Policy
//
// The slot index is a signed value which requires us to decode it manually
// instead of using the BitField utility class.
// The superclass has a KindField.
STATIC_ASSERT(kKindFieldWidth == 3);
// BitFields for all unallocated operands.
class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {};
// TODO(mstarzinger): Bump this from 15 bit to 18 bit in a follow-up CL.
class VirtualRegisterField : public BitField<unsigned, 4, 15> {};
// BitFields specific to BasicPolicy::FIXED_SLOT.
class FixedSlotIndexField : public BitField<int, 22, 10> {};
// BitFields specific to BasicPolicy::EXTENDED_POLICY.
class ExtendedPolicyField : public BitField<ExtendedPolicy, 22, 3> {};
class LifetimeField : public BitField<Lifetime, 25, 1> {};
class FixedRegisterField : public BitField<int, 26, 6> {};
static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1;
static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));
// Predicates for the operand policy.
bool HasAnyPolicy() const {
return basic_policy() == EXTENDED_POLICY &&
extended_policy() == ANY;
}
bool HasFixedPolicy() const {
return basic_policy() == FIXED_SLOT ||
extended_policy() == FIXED_REGISTER ||
extended_policy() == FIXED_DOUBLE_REGISTER;
}
bool HasRegisterPolicy() const {
return basic_policy() == EXTENDED_POLICY && (
extended_policy() == WRITABLE_REGISTER ||
extended_policy() == MUST_HAVE_REGISTER);
}
bool HasSameAsInputPolicy() const {
return basic_policy() == EXTENDED_POLICY &&
extended_policy() == SAME_AS_FIRST_INPUT;
}
bool HasFixedSlotPolicy() const {
return basic_policy() == FIXED_SLOT;
}
bool HasFixedRegisterPolicy() const {
return basic_policy() == EXTENDED_POLICY &&
extended_policy() == FIXED_REGISTER;
}
bool HasFixedDoubleRegisterPolicy() const {
return basic_policy() == EXTENDED_POLICY &&
extended_policy() == FIXED_DOUBLE_REGISTER;
}
bool HasWritableRegisterPolicy() const {
return basic_policy() == EXTENDED_POLICY &&
extended_policy() == WRITABLE_REGISTER;
} }
private: // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
void Initialize(Policy policy, int fixed_index, Lifetime lifetime) { BasicPolicy basic_policy() const {
value_ |= PolicyField::encode(policy); return BasicPolicyField::decode(value_);
value_ |= LifetimeField::encode(lifetime); }
value_ |= fixed_index << kFixedIndexShift;
ASSERT(this->fixed_index() == fixed_index); // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
ExtendedPolicy extended_policy() const {
ASSERT(basic_policy() == EXTENDED_POLICY);
return ExtendedPolicyField::decode(value_);
}
// [fixed_slot_index]: Only for FIXED_SLOT.
int fixed_slot_index() const {
ASSERT(HasFixedSlotPolicy());
return static_cast<int>(value_) >> FixedSlotIndexField::kShift;
}
// [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
int fixed_register_index() const {
ASSERT(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
return FixedRegisterField::decode(value_);
}
// [virtual_register]: The virtual register ID for this operand.
int virtual_register() const {
return VirtualRegisterField::decode(value_);
}
void set_virtual_register(unsigned id) {
value_ = VirtualRegisterField::update(value_, id);
}
// [lifetime]: Only for non-FIXED_SLOT.
bool IsUsedAtStart() {
ASSERT(basic_policy() == EXTENDED_POLICY);
return LifetimeField::decode(value_) == USED_AT_START;
} }
}; };

View File

@ -2328,7 +2328,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
if (spill_index > LUnallocated::kMaxFixedIndex) { if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
Abort("Too many spill slots needed for OSR"); Abort("Too many spill slots needed for OSR");
spill_index = 0; spill_index = 0;
} }

View File

@ -2384,7 +2384,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
if (spill_index > LUnallocated::kMaxFixedIndex) { if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
Abort("Too many spill slots needed for OSR"); Abort("Too many spill slots needed for OSR");
spill_index = 0; spill_index = 0;
} }