HInstruction* instr = HInstruction::cast(value);
VisitInstruction(instr);
}
- allocator_->RecordUse(value, operand);
+ operand->set_virtual_register(value->id());
return operand;
}
template<int I, int T>
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
LUnallocated* result) {
- allocator_->RecordDefinition(current_instruction_, result);
+ result->set_virtual_register(current_instruction_->id());
instr->set_result(result);
return instr;
}
LUnallocated* LChunkBuilder::TempRegister() {
LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
- allocator_->RecordTemporary(operand);
+ operand->set_virtual_register(allocator_->GetVirtualRegister());
+ if (!allocator_->AllocationOk()) Abort("Not enough virtual registers.");
return operand;
}
LOperand* LChunkBuilder::FixedTemp(Register reg) {
LUnallocated* operand = ToUnallocated(reg);
- allocator_->RecordTemporary(operand);
+ ASSERT(operand->HasFixedPolicy());
return operand;
}
LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
LUnallocated* operand = ToUnallocated(reg);
- allocator_->RecordTemporary(operand);
+ ASSERT(operand->HasFixedPolicy());
return operand;
}
// Fall back to using the full code generator if it's not possible
// to use the Hydrogen-based optimizing compiler. We already have
// generated code for this from the shared function object.
- if (AlwaysFullCompiler() || !FLAG_use_hydrogen) {
+ if (AlwaysFullCompiler()) {
info->SetCode(code);
return true;
}
return false;
}
- if (graph != NULL && FLAG_build_lithium) {
+ if (graph != NULL) {
Handle<Code> optimized_code = graph->Compile(info);
if (!optimized_code.is_null()) {
info->SetCode(optimized_code);
#ifdef V8_TARGET_ARCH_MIPS
static const int kNumberOfEntries = 4096;
#else
- static const int kNumberOfEntries = 8192;
+ static const int kNumberOfEntries = 16384;
#endif
Deoptimizer(Isolate* isolate,
// Flags for Crankshaft.
DEFINE_bool(crankshaft, true, "use crankshaft")
DEFINE_string(hydrogen_filter, "", "hydrogen use/trace filter")
-DEFINE_bool(use_hydrogen, true, "use generated hydrogen for compilation")
-DEFINE_bool(build_lithium, true, "use lithium chunk builder")
-DEFINE_bool(alloc_lithium, true, "use lithium register allocator")
-DEFINE_bool(use_lithium, true, "use lithium code generator")
DEFINE_bool(use_range, true, "use hydrogen range analysis")
DEFINE_bool(eliminate_dead_phis, true, "eliminate dead phis")
DEFINE_bool(use_gvn, true, "use hydrogen global value numbering")
Handle<Code> HGraph::Compile(CompilationInfo* info) {
int values = GetMaximumValueID();
- if (values > LAllocator::max_initial_value_ids()) {
+ if (values > LUnallocated::kMaxVirtualRegisters) {
if (FLAG_trace_bailout) {
- SmartArrayPointer<char> name(
- info->shared_info()->DebugName()->ToCString());
- PrintF("Function @\"%s\" is too big.\n", *name);
+ PrintF("Not enough virtual registers for (values).\n");
}
return Handle<Code>::null();
}
-
LAllocator allocator(values, this);
LChunkBuilder builder(info, this, &allocator);
LChunk* chunk = builder.Build();
if (chunk == NULL) return Handle<Code>::null();
- if (!FLAG_alloc_lithium) return Handle<Code>::null();
-
- allocator.Allocate(chunk);
-
- if (!FLAG_use_lithium) return Handle<Code>::null();
+ if (!allocator.Allocate(chunk)) {
+ if (FLAG_trace_bailout) {
+ PrintF("Not enough virtual registers (regalloc).\n");
+ }
+ return Handle<Code>::null();
+ }
MacroAssembler assembler(info->isolate(), NULL, 0);
LCodeGen generator(chunk, &assembler, info);
HInstruction* instr = HInstruction::cast(value);
VisitInstruction(instr);
}
- allocator_->RecordUse(value, operand);
+ operand->set_virtual_register(value->id());
return operand;
}
template<int I, int T>
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
LUnallocated* result) {
- allocator_->RecordDefinition(current_instruction_, result);
+ result->set_virtual_register(current_instruction_->id());
instr->set_result(result);
return instr;
}
LUnallocated* LChunkBuilder::TempRegister() {
LUnallocated* operand =
new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
- allocator_->RecordTemporary(operand);
+ operand->set_virtual_register(allocator_->GetVirtualRegister());
+ if (!allocator_->AllocationOk()) Abort("Not enough virtual registers (temps).");
return operand;
}
LOperand* LChunkBuilder::FixedTemp(Register reg) {
LUnallocated* operand = ToUnallocated(reg);
- allocator_->RecordTemporary(operand);
+ ASSERT(operand->HasFixedPolicy());
return operand;
}
LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
LUnallocated* operand = ToUnallocated(reg);
- allocator_->RecordTemporary(operand);
+ ASSERT(operand->HasFixedPolicy());
return operand;
}
LAllocator::LAllocator(int num_values, HGraph* graph)
: chunk_(NULL),
+ allocation_ok_(true),
live_in_sets_(graph->blocks()->length()),
live_ranges_(num_values * 2),
fixed_live_ranges_(NULL),
if (i < end) instr = InstructionAt(i + 1);
if (i > start) prev_instr = InstructionAt(i - 1);
MeetConstraintsBetween(prev_instr, instr, i);
+ if (!AllocationOk()) return;
}
}
}
ASSERT(!cur_input->IsUsedAtStart());
LUnallocated* input_copy = cur_input->CopyUnconstrained();
- cur_input->set_virtual_register(next_virtual_register_++);
+ cur_input->set_virtual_register(GetVirtualRegister());
+ if(!AllocationOk()) return;
if (RequiredRegisterKind(input_copy->virtual_register()) ==
DOUBLE_REGISTERS) {
}
-void LAllocator::Allocate(LChunk* chunk) {
+bool LAllocator::Allocate(LChunk* chunk) {
ASSERT(chunk_ == NULL);
chunk_ = chunk;
MeetRegisterConstraints();
+ if (!AllocationOk()) return false;
ResolvePhis();
BuildLiveRanges();
AllocateGeneralRegisters();
+ if (!AllocationOk()) return false;
AllocateDoubleRegisters();
+ if (!AllocationOk()) return false;
PopulatePointerMaps();
if (has_osr_entry_) ProcessOsrEntry();
ConnectRanges();
ResolveControlFlow();
+ return true;
}
for (int i = 0; i < blocks->length(); ++i) {
HBasicBlock* block = blocks->at(i);
MeetRegisterConstraints(block);
+ if (!AllocationOk()) return;
}
}
// Do not spill live range eagerly if use position that can benefit from
// the register is too close to the start of live range.
SpillBetween(current, current->Start(), pos->pos());
+ if (!AllocationOk()) return;
ASSERT(UnhandledIsSorted());
continue;
}
ASSERT(!current->HasRegisterAssigned() && !current->IsSpilled());
bool result = TryAllocateFreeReg(current);
- if (!result) {
- AllocateBlockedReg(current);
- }
+ if (!AllocationOk()) return;
+
+ if (!result) AllocateBlockedReg(current);
+ if (!AllocationOk()) return;
if (current->HasRegisterAssigned()) {
AddToActive(current);
}
-void LAllocator::RecordDefinition(HInstruction* instr, LUnallocated* operand) {
- operand->set_virtual_register(instr->id());
-}
-
-
-void LAllocator::RecordTemporary(LUnallocated* operand) {
- ASSERT(next_virtual_register_ < LUnallocated::kMaxVirtualRegisters);
- if (!operand->HasFixedPolicy()) {
- operand->set_virtual_register(next_virtual_register_++);
- }
-}
-
-
-void LAllocator::RecordUse(HValue* value, LUnallocated* operand) {
- operand->set_virtual_register(value->id());
-}
-
-
-int LAllocator::max_initial_value_ids() {
- return LUnallocated::kMaxVirtualRegisters / 16;
-}
-
-
void LAllocator::AddToActive(LiveRange* range) {
TraceAlloc("Add live range %d to active\n", range->id());
active_live_ranges_.Add(range);
if (pos.Value() < current->End().Value()) {
// Register reg is available at the range start but becomes blocked before
// the range end. Split current at position where it becomes blocked.
- LiveRange* tail = SplitAt(current, pos);
+ LiveRange* tail = SplitRangeAt(current, pos);
+ if (!AllocationOk()) return false;
AddToUnhandledSorted(tail);
}
}
-LiveRange* LAllocator::SplitAt(LiveRange* range, LifetimePosition pos) {
+LiveRange* LAllocator::SplitRangeAt(LiveRange* range, LifetimePosition pos) {
ASSERT(!range->IsFixed());
TraceAlloc("Splitting live range %d at %d\n", range->id(), pos.Value());
ASSERT(pos.IsInstructionStart() ||
!chunk_->instructions()->at(pos.InstructionIndex())->IsControl());
- LiveRange* result = LiveRangeFor(next_virtual_register_++);
+ LiveRange* result = LiveRangeFor(GetVirtualRegister());
+ if (!AllocationOk()) return NULL;
range->SplitAt(pos, result);
return result;
}
LifetimePosition split_pos = FindOptimalSplitPos(start, end);
ASSERT(split_pos.Value() >= start.Value());
- return SplitAt(range, split_pos);
+ return SplitRangeAt(range, split_pos);
}
void LAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) {
- LiveRange* second_part = SplitAt(range, pos);
+ LiveRange* second_part = SplitRangeAt(range, pos);
+ if (!AllocationOk()) return;
Spill(second_part);
}
LifetimePosition start,
LifetimePosition end) {
ASSERT(start.Value() < end.Value());
- LiveRange* second_part = SplitAt(range, start);
+ LiveRange* second_part = SplitRangeAt(range, start);
+ if (!AllocationOk()) return;
if (second_part->Start().Value() < end.Value()) {
// The split result intersects with [start, end[.
static void TraceAlloc(const char* msg, ...);
- // Lithium translation support.
- // Record a use of an input operand in the current instruction.
- void RecordUse(HValue* value, LUnallocated* operand);
- // Record the definition of the output operand.
- void RecordDefinition(HInstruction* instr, LUnallocated* operand);
- // Record a temporary operand.
- void RecordTemporary(LUnallocated* operand);
-
// Checks whether the value of a given virtual register is tagged.
bool HasTaggedValue(int virtual_register) const;
// Returns the register kind required by the given virtual register.
RegisterKind RequiredRegisterKind(int virtual_register) const;
- // Control max function size.
- static int max_initial_value_ids();
-
- void Allocate(LChunk* chunk);
+ bool Allocate(LChunk* chunk);
const ZoneList<LiveRange*>* live_ranges() const { return &live_ranges_; }
const Vector<LiveRange*>* fixed_live_ranges() const {
LChunk* chunk() const { return chunk_; }
HGraph* graph() const { return graph_; }
+ int GetVirtualRegister() {
+ if (next_virtual_register_ > LUnallocated::kMaxVirtualRegisters) {
+ allocation_ok_ = false;
+ }
+ return next_virtual_register_++;
+ }
+
+ bool AllocationOk() { return allocation_ok_; }
+
void MarkAsOsrEntry() {
// There can be only one.
ASSERT(!has_osr_entry_);
// Otherwise returns the live range that starts at pos and contains
// all uses from the original range that follow pos. Uses at pos will
// still be owned by the original range after splitting.
- LiveRange* SplitAt(LiveRange* range, LifetimePosition pos);
+ LiveRange* SplitRangeAt(LiveRange* range, LifetimePosition pos);
// Split the given range in a position from the interval [start, end].
LiveRange* SplitBetween(LiveRange* range,
LChunk* chunk_;
+ // Indicates success or failure during register allocation.
+ bool allocation_ok_;
+
// During liveness analysis keep a mapping from block id to live_in sets
// for blocks already analyzed.
ZoneList<BitVector*> live_in_sets_;
HInstruction* instr = HInstruction::cast(value);
VisitInstruction(instr);
}
- allocator_->RecordUse(value, operand);
+ operand->set_virtual_register(value->id());
return operand;
}
template<int I, int T>
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
LUnallocated* result) {
- allocator_->RecordDefinition(current_instruction_, result);
+ result->set_virtual_register(current_instruction_->id());
instr->set_result(result);
return instr;
}
LUnallocated* LChunkBuilder::TempRegister() {
LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
- allocator_->RecordTemporary(operand);
+ operand->set_virtual_register(allocator_->GetVirtualRegister());
+ if (!allocator_->AllocationOk()) Abort("Not enough virtual registers.");
return operand;
}
LOperand* LChunkBuilder::FixedTemp(Register reg) {
LUnallocated* operand = ToUnallocated(reg);
- allocator_->RecordTemporary(operand);
+ ASSERT(operand->HasFixedPolicy());
return operand;
}
LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
LUnallocated* operand = ToUnallocated(reg);
- allocator_->RecordTemporary(operand);
+ ASSERT(operand->HasFixedPolicy());
return operand;
}
HInstruction* instr = HInstruction::cast(value);
VisitInstruction(instr);
}
- allocator_->RecordUse(value, operand);
+ operand->set_virtual_register(value->id());
return operand;
}
template<int I, int T>
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
LUnallocated* result) {
- allocator_->RecordDefinition(current_instruction_, result);
+ result->set_virtual_register(current_instruction_->id());
instr->set_result(result);
return instr;
}
LUnallocated* LChunkBuilder::TempRegister() {
LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
- allocator_->RecordTemporary(operand);
+ operand->set_virtual_register(allocator_->GetVirtualRegister());
+ if (!allocator_->AllocationOk()) Abort("Not enough virtual registers.");
return operand;
}
LOperand* LChunkBuilder::FixedTemp(Register reg) {
LUnallocated* operand = ToUnallocated(reg);
- allocator_->RecordTemporary(operand);
+ ASSERT(operand->HasFixedPolicy());
return operand;
}
LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
LUnallocated* operand = ToUnallocated(reg);
- allocator_->RecordTemporary(operand);
+ ASSERT(operand->HasFixedPolicy());
return operand;
}