Commit 1ca08865 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

Reland "[regalloc] Introduce deferred fixed ranges"

This is a reland of b1769313

Original change's description:
> [regalloc] Introduce deferred fixed ranges
> 
> Fixed ranges are used to express register constraints in the
> allocator. This change splits these fixed ranges into one for
> normal code and deferred code. The former are handeled as before
> whereas the latter are only made visible while allocating
> registers for deferred code.
> 
> This prevents forward looking decisions in normal code to be
> impacted by register constraints from deferred code.
> 
> Change-Id: I67d562bb41166194e62765d5ab051bc961054fc7
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1477742
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#60322}

Change-Id: I1a31150256eb5608db985b144aab7ea457169d0d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1530810
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60364}
parent 28770a88
......@@ -651,7 +651,11 @@ std::ostream& operator<<(std::ostream& os,
const InstructionSequence* code = printable_block.code_;
os << "B" << block->rpo_number();
os << ": AO#" << block->ao_number();
if (block->ao_number().IsValid()) {
os << ": AO#" << block->ao_number();
} else {
os << ": AO#?";
}
if (block->IsDeferred()) os << " (deferred)";
if (!block->needs_frame()) os << " (no frame)";
if (block->must_construct_frame()) os << " (construct frame)";
......
......@@ -162,6 +162,7 @@ void LiveRangeMerger::MarkRangesSpilledInDeferredBlocks() {
}
}
if (child == nullptr) {
DCHECK(!data()->is_turbo_control_flow_aware_allocation());
top->TreatAsSpilledInDeferredBlock(data()->allocation_zone(),
code->InstructionBlockCount());
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -401,11 +401,12 @@ class PipelineData {
}
void InitializeRegisterAllocationData(const RegisterConfiguration* config,
CallDescriptor* call_descriptor) {
CallDescriptor* call_descriptor,
RegisterAllocationFlags flags) {
DCHECK_NULL(register_allocation_data_);
register_allocation_data_ = new (register_allocation_zone())
RegisterAllocationData(config, register_allocation_zone(), frame(),
sequence(), debug_name());
sequence(), flags, debug_name());
}
void InitializeOsrHelper() {
......@@ -914,6 +915,12 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
if (FLAG_inline_accessors) {
compilation_info()->MarkAsAccessorInliningEnabled();
}
if (FLAG_turbo_control_flow_aware_allocation) {
compilation_info()->MarkAsTurboControlFlowAwareAllocation();
}
if (FLAG_turbo_preprocess_ranges) {
compilation_info()->MarkAsTurboPreprocessRanges();
}
// This is the bottleneck for computing and setting poisoning level in the
// optimizing compiler.
......@@ -2522,6 +2529,12 @@ bool Pipeline::AllocateRegistersForTesting(const RegisterConfiguration* config,
bool run_verifier) {
OptimizedCompilationInfo info(ArrayVector("testing"), sequence->zone(),
Code::STUB);
if (FLAG_turbo_control_flow_aware_allocation) {
info.MarkAsTurboControlFlowAwareAllocation();
}
if (FLAG_turbo_preprocess_ranges) {
info.MarkAsTurboPreprocessRanges();
}
ZoneStats zone_stats(sequence->isolate()->allocator());
PipelineData data(&zone_stats, &info, sequence->isolate(), sequence);
data.InitializeFrameData(nullptr);
......@@ -2862,7 +2875,14 @@ void PipelineImpl::AllocateRegisters(const RegisterConfiguration* config,
data_->sequence()->ValidateDeferredBlockExitPaths();
#endif
data->InitializeRegisterAllocationData(config, call_descriptor);
RegisterAllocationFlags flags;
if (data->info()->is_turbo_control_flow_aware_allocation()) {
flags |= RegisterAllocationFlag::kTurboControlFlowAwareAllocation;
}
if (data->info()->is_turbo_preprocess_ranges()) {
flags |= RegisterAllocationFlag::kTurboPreprocessRanges;
}
data->InitializeRegisterAllocationData(config, call_descriptor, flags);
if (info()->is_osr()) data->osr_helper()->SetupFrame(data->frame());
Run<MeetRegisterConstraintsPhase>();
......@@ -2883,7 +2903,7 @@ void PipelineImpl::AllocateRegisters(const RegisterConfiguration* config,
data->register_allocation_data());
}
if (FLAG_turbo_preprocess_ranges) {
if (info()->is_turbo_preprocess_ranges()) {
Run<SplinterLiveRangesPhase>();
if (info()->trace_turbo_json_enabled() &&
!data->MayHaveUnverifiableGraph()) {
......@@ -2899,7 +2919,7 @@ void PipelineImpl::AllocateRegisters(const RegisterConfiguration* config,
Run<AllocateFPRegistersPhase<LinearScanAllocator>>();
}
if (FLAG_turbo_preprocess_ranges) {
if (info()->is_turbo_preprocess_ranges()) {
Run<MergeSplintersPhase>();
}
......
......@@ -434,7 +434,7 @@ DEFINE_BOOL(print_deopt_stress, false, "print number of possible deopt points")
// Flags for TurboFan.
DEFINE_BOOL(turbo_sp_frame_access, false,
"use stack pointer-relative access to frame wherever possible")
DEFINE_BOOL(turbo_preprocess_ranges, true,
DEFINE_BOOL(turbo_preprocess_ranges, false,
"run pre-register allocation heuristics")
DEFINE_BOOL(turbo_control_flow_aware_allocation, false,
"consider control flow while allocating registers")
......
......@@ -55,7 +55,9 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
kTraceTurboJson = 1 << 14,
kTraceTurboGraph = 1 << 15,
kTraceTurboScheduled = 1 << 16,
kWasmRuntimeExceptionSupport = 1 << 17
kWasmRuntimeExceptionSupport = 1 << 17,
kTurboControlFlowAwareAllocation = 1 << 18,
kTurboPreprocessRanges = 1 << 19
};
// Construct a compilation info for optimized compilation.
......@@ -84,6 +86,18 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
// Flags used by optimized compilation.
void MarkAsTurboControlFlowAwareAllocation() {
SetFlag(kTurboControlFlowAwareAllocation);
}
bool is_turbo_control_flow_aware_allocation() const {
return GetFlag(kTurboControlFlowAwareAllocation);
}
void MarkAsTurboPreprocessRanges() { SetFlag(kTurboPreprocessRanges); }
bool is_turbo_preprocess_ranges() const {
return GetFlag(kTurboPreprocessRanges);
}
void MarkAsFunctionContextSpecializing() {
SetFlag(kFunctionContextSpecializing);
}
......
......@@ -113,6 +113,11 @@ TEST_F(RegisterAllocatorTest, SimpleLoop) {
// while(true) { i++ }
StartBlock();
auto i_reg = DefineConstant();
// Add a branch around the loop to ensure the end-block
// is connected.
EndBlock(Branch(Reg(DefineConstant()), 3, 1));
StartBlock();
EndBlock();
{
......@@ -127,6 +132,9 @@ TEST_F(RegisterAllocatorTest, SimpleLoop) {
EndLoop();
}
StartBlock();
EndBlock();
Allocate();
}
......@@ -617,10 +625,10 @@ TEST_F(RegisterAllocatorTest, SingleDeferredBlockSpill) {
const int var_def_index = 1;
const int call_index = 3;
int expect_no_moves =
FLAG_turbo_preprocess_ranges ? var_def_index : call_index;
int expect_spill_move =
FLAG_turbo_preprocess_ranges ? call_index : var_def_index;
const bool spill_in_deferred =
FLAG_turbo_preprocess_ranges || FLAG_turbo_control_flow_aware_allocation;
int expect_no_moves = spill_in_deferred ? var_def_index : call_index;
int expect_spill_move = spill_in_deferred ? call_index : var_def_index;
// We should have no parallel moves at the "expect_no_moves" position.
EXPECT_EQ(
......@@ -685,6 +693,67 @@ TEST_F(RegisterAllocatorTest, MultipleDeferredBlockSpills) {
GetParallelMoveCount(start_of_b3, Instruction::START, sequence()));
}
TEST_F(RegisterAllocatorTest, ValidMultipleDeferredBlockSpills) {
if (!FLAG_turbo_control_flow_aware_allocation) return;
StartBlock(); // B0
auto var1 = EmitOI(Reg(0));
auto var2 = EmitOI(Reg(1));
auto var3 = EmitOI(Reg(2));
EndBlock(Branch(Reg(var1, 0), 1, 2));
StartBlock(true); // B1
EmitCall(Slot(-2), Slot(var1));
EndBlock(Jump(5));
StartBlock(); // B2
EmitNop();
EndBlock();
StartBlock(); // B3
EmitNop();
EndBlock(Branch(Reg(var2, 0), 1, 2));
StartBlock(true); // B4
EmitCall(Slot(-1), Slot(var2));
EndBlock(Jump(2));
StartBlock(); // B5
EmitNop();
EndBlock();
StartBlock(); // B6
Return(Reg(var3, 2));
EndBlock();
const int def_of_v2 = 2;
const int call_in_b1 = 4;
const int call_in_b4 = 10;
const int end_of_b1 = 5;
const int end_of_b4 = 11;
const int start_of_b6 = 14;
Allocate();
const int var3_reg = 2;
const int var3_slot = 2;
EXPECT_FALSE(IsParallelMovePresent(def_of_v2, Instruction::START, sequence(),
Reg(var3_reg), Slot()));
EXPECT_TRUE(IsParallelMovePresent(call_in_b1, Instruction::START, sequence(),
Reg(var3_reg), Slot(var3_slot)));
EXPECT_TRUE(IsParallelMovePresent(end_of_b1, Instruction::START, sequence(),
Slot(var3_slot), Reg()));
EXPECT_TRUE(IsParallelMovePresent(call_in_b4, Instruction::START, sequence(),
Reg(var3_reg), Slot(var3_slot)));
EXPECT_TRUE(IsParallelMovePresent(end_of_b4, Instruction::START, sequence(),
Slot(var3_slot), Reg()));
EXPECT_EQ(0,
GetParallelMoveCount(start_of_b6, Instruction::START, sequence()));
}
namespace {
enum class ParameterType { kFixedSlot, kSlot, kRegister, kFixedRegister };
......
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