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
parent c092da37
......@@ -2453,7 +2453,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
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");
spill_index = 0;
}
......
......@@ -299,14 +299,14 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
//
// The encoding is as a signed value, with parameters and receiver using
// 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();
if ((scope->num_parameters() + 1) > parameter_limit) {
info()->set_bailout_reason("too many parameters");
return AbortOptimization();
}
const int locals_limit = LUnallocated::kMaxFixedIndex;
const int locals_limit = LUnallocated::kMaxFixedSlotIndex;
if (!info()->osr_ast_id().IsNone() &&
scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) {
info()->set_bailout_reason("too many parameters/locals");
......
......@@ -2584,7 +2584,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
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");
spill_index = 0;
}
......
......@@ -625,13 +625,13 @@ LOperand* LAllocator::AllocateFixed(LUnallocated* operand,
bool is_tagged) {
TraceAlloc("Allocating fixed reg for op %d\n", operand->virtual_register());
ASSERT(operand->HasFixedPolicy());
if (operand->policy() == LUnallocated::FIXED_SLOT) {
operand->ConvertTo(LOperand::STACK_SLOT, operand->fixed_index());
} else if (operand->policy() == LUnallocated::FIXED_REGISTER) {
int reg_index = operand->fixed_index();
if (operand->HasFixedSlotPolicy()) {
operand->ConvertTo(LOperand::STACK_SLOT, operand->fixed_slot_index());
} else if (operand->HasFixedRegisterPolicy()) {
int reg_index = operand->fixed_register_index();
operand->ConvertTo(LOperand::REGISTER, reg_index);
} else if (operand->policy() == LUnallocated::FIXED_DOUBLE_REGISTER) {
int reg_index = operand->fixed_index();
} else if (operand->HasFixedDoubleRegisterPolicy()) {
int reg_index = operand->fixed_register_index();
operand->ConvertTo(LOperand::DOUBLE_REGISTER, reg_index);
} else {
UNREACHABLE();
......@@ -846,7 +846,7 @@ void LAllocator::MeetConstraintsBetween(LInstruction* first,
bool is_tagged = HasTaggedValue(cur_input->virtual_register());
AllocateFixed(cur_input, gap_index + 1, is_tagged);
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
// of the instruction.
ASSERT(!cur_input->IsUsedAtStart());
......
......@@ -58,24 +58,27 @@ void LOperand::PrintTo(StringStream* stream) {
case UNALLOCATED:
unalloc = LUnallocated::cast(this);
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:
break;
case LUnallocated::FIXED_REGISTER: {
int reg_index = unalloc->fixed_register_index();
const char* register_name =
Register::AllocationIndexToString(unalloc->fixed_index());
Register::AllocationIndexToString(reg_index);
stream->Add("(=%s)", register_name);
break;
}
case LUnallocated::FIXED_DOUBLE_REGISTER: {
int reg_index = unalloc->fixed_register_index();
const char* double_register_name =
DoubleRegister::AllocationIndexToString(unalloc->fixed_index());
DoubleRegister::AllocationIndexToString(reg_index);
stream->Add("(=%s)", double_register_name);
break;
}
case LUnallocated::FIXED_SLOT:
stream->Add("(=%dS)", unalloc->fixed_index());
break;
case LUnallocated::MUST_HAVE_REGISTER:
stream->Add("(R)");
break;
......
......@@ -92,12 +92,16 @@ class LOperand: public ZoneObject {
class LUnallocated: public LOperand {
public:
enum Policy {
enum BasicPolicy {
FIXED_SLOT,
EXTENDED_POLICY
};
enum ExtendedPolicy {
NONE,
ANY,
FIXED_REGISTER,
FIXED_DOUBLE_REGISTER,
FIXED_SLOT,
MUST_HAVE_REGISTER,
WRITABLE_REGISTER,
SAME_AS_FIRST_INPUT
......@@ -117,99 +121,153 @@ class LUnallocated: public LOperand {
USED_AT_END
};
explicit LUnallocated(Policy policy) : LOperand(UNALLOCATED, 0) {
Initialize(policy, 0, USED_AT_END);
explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) {
value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
value_ |= ExtendedPolicyField::encode(policy);
value_ |= LifetimeField::encode(USED_AT_END);
}
LUnallocated(Policy policy, int fixed_index) : LOperand(UNALLOCATED, 0) {
Initialize(policy, fixed_index, USED_AT_END);
LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
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) {
Initialize(policy, 0, lifetime);
LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
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
// index in the upper bits.
static const int kPolicyWidth = 3;
static const int kLifetimeWidth = 1;
static const int kVirtualRegisterWidth = 15;
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> {
};
LUnallocated(ExtendedPolicy policy, Lifetime lifetime)
: LOperand(UNALLOCATED, 0) {
value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
value_ |= ExtendedPolicyField::encode(policy);
value_ |= LifetimeField::encode(lifetime);
}
class VirtualRegisterField
: public BitField<unsigned,
kVirtualRegisterShift,
kVirtualRegisterWidth> {
};
LUnallocated* CopyUnconstrained(Zone* zone) {
LUnallocated* result = new(zone) LUnallocated(ANY);
result->set_virtual_register(virtual_register());
return result;
}
static const int kMaxVirtualRegisters = 1 << kVirtualRegisterWidth;
static const int kMaxFixedIndex = (1 << (kFixedIndexWidth - 1)) - 1;
static const int kMinFixedIndex = -(1 << (kFixedIndexWidth - 1));
static LUnallocated* cast(LOperand* op) {
ASSERT(op->IsUnallocated());
return reinterpret_cast<LUnallocated*>(op);
}
// The encoding used for LUnallocated operands depends on the policy that is
// 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 policy() == ANY;
return basic_policy() == EXTENDED_POLICY &&
extended_policy() == ANY;
}
bool HasFixedPolicy() const {
return policy() == FIXED_REGISTER ||
policy() == FIXED_DOUBLE_REGISTER ||
policy() == FIXED_SLOT;
return basic_policy() == FIXED_SLOT ||
extended_policy() == FIXED_REGISTER ||
extended_policy() == FIXED_DOUBLE_REGISTER;
}
bool HasRegisterPolicy() const {
return policy() == WRITABLE_REGISTER || policy() == MUST_HAVE_REGISTER;
return basic_policy() == EXTENDED_POLICY && (
extended_policy() == WRITABLE_REGISTER ||
extended_policy() == MUST_HAVE_REGISTER);
}
bool HasSameAsInputPolicy() const {
return policy() == SAME_AS_FIRST_INPUT;
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;
}
Policy policy() const { return PolicyField::decode(value_); }
void set_policy(Policy policy) {
value_ = PolicyField::update(value_, policy);
bool HasFixedDoubleRegisterPolicy() const {
return basic_policy() == EXTENDED_POLICY &&
extended_policy() == FIXED_DOUBLE_REGISTER;
}
int fixed_index() const {
return static_cast<int>(value_) >> kFixedIndexShift;
bool HasWritableRegisterPolicy() const {
return basic_policy() == EXTENDED_POLICY &&
extended_policy() == WRITABLE_REGISTER;
}
int virtual_register() const {
return VirtualRegisterField::decode(value_);
// [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
BasicPolicy basic_policy() const {
return BasicPolicyField::decode(value_);
}
void set_virtual_register(unsigned id) {
value_ = VirtualRegisterField::update(value_, id);
// [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
ExtendedPolicy extended_policy() const {
ASSERT(basic_policy() == EXTENDED_POLICY);
return ExtendedPolicyField::decode(value_);
}
LUnallocated* CopyUnconstrained(Zone* zone) {
LUnallocated* result = new(zone) LUnallocated(ANY);
result->set_virtual_register(virtual_register());
return result;
// [fixed_slot_index]: Only for FIXED_SLOT.
int fixed_slot_index() const {
ASSERT(HasFixedSlotPolicy());
return static_cast<int>(value_) >> FixedSlotIndexField::kShift;
}
static LUnallocated* cast(LOperand* op) {
ASSERT(op->IsUnallocated());
return reinterpret_cast<LUnallocated*>(op);
// [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
int fixed_register_index() const {
ASSERT(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
return FixedRegisterField::decode(value_);
}
bool IsUsedAtStart() {
return LifetimeField::decode(value_) == USED_AT_START;
// [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);
}
private:
void Initialize(Policy policy, int fixed_index, Lifetime lifetime) {
value_ |= PolicyField::encode(policy);
value_ |= LifetimeField::encode(lifetime);
value_ |= fixed_index << kFixedIndexShift;
ASSERT(this->fixed_index() == fixed_index);
// [lifetime]: Only for non-FIXED_SLOT.
bool IsUsedAtStart() {
ASSERT(basic_policy() == EXTENDED_POLICY);
return LifetimeField::decode(value_) == USED_AT_START;
}
};
......
......@@ -2328,7 +2328,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
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");
spill_index = 0;
}
......
......@@ -2384,7 +2384,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
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");
spill_index = 0;
}
......
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