[TurboProp] Remove the second schedule for TurboProp.

This rearranges the TurboProp pipeline to avoid the need for a second
schedule of the graph. To do this, it moves the final schedule creation
before effect-control-linearization (which used a temporary schedule
previously, and with TurboFan). It then enables the block updater in the
graph assembler for effect control linearization and does select and
memory lowering in a new ScheduledMachineLowering phase to maintain
this existing schedule during these lowering passes.

BUG=v8:9684

Change-Id: I6a7790b010f8b152dd01d85aa95ee5d4f99087a5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1847351
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64537}
This commit is contained in:
Ross McIlroy 2019-10-23 16:36:21 +01:00 committed by Commit Bot
parent e0c1ca5a30
commit 22fd955507
15 changed files with 292 additions and 115 deletions

View File

@ -1828,6 +1828,8 @@ v8_compiler_sources = [
"src/compiler/representation-change.h", "src/compiler/representation-change.h",
"src/compiler/schedule.cc", "src/compiler/schedule.cc",
"src/compiler/schedule.h", "src/compiler/schedule.h",
"src/compiler/scheduled-machine-lowering.cc",
"src/compiler/scheduled-machine-lowering.h",
"src/compiler/scheduler.cc", "src/compiler/scheduler.cc",
"src/compiler/scheduler.h", "src/compiler/scheduler.h",
"src/compiler/select-lowering.cc", "src/compiler/select-lowering.cc",

View File

@ -34,14 +34,17 @@ class EffectControlLinearizer {
Zone* temp_zone, Zone* temp_zone,
SourcePositionTable* source_positions, SourcePositionTable* source_positions,
NodeOriginTable* node_origins, NodeOriginTable* node_origins,
MaskArrayIndexEnable mask_array_index) MaskArrayIndexEnable mask_array_index,
MaintainSchedule maintain_schedule)
: js_graph_(js_graph), : js_graph_(js_graph),
schedule_(schedule), schedule_(schedule),
temp_zone_(temp_zone), temp_zone_(temp_zone),
mask_array_index_(mask_array_index), mask_array_index_(mask_array_index),
maintain_schedule_(maintain_schedule),
source_positions_(source_positions), source_positions_(source_positions),
node_origins_(node_origins), node_origins_(node_origins),
graph_assembler_(js_graph, temp_zone), graph_assembler_(js_graph, temp_zone,
should_maintain_schedule() ? schedule : nullptr),
frame_state_zapper_(nullptr) {} frame_state_zapper_(nullptr) {}
void Run(); void Run();
@ -253,6 +256,10 @@ class EffectControlLinearizer {
void TransitionElementsTo(Node* node, Node* array, ElementsKind from, void TransitionElementsTo(Node* node, Node* array, ElementsKind from,
ElementsKind to); ElementsKind to);
bool should_maintain_schedule() const {
return maintain_schedule_ == MaintainSchedule::kMaintain;
}
Factory* factory() const { return isolate()->factory(); } Factory* factory() const { return isolate()->factory(); }
Isolate* isolate() const { return jsgraph()->isolate(); } Isolate* isolate() const { return jsgraph()->isolate(); }
JSGraph* jsgraph() const { return js_graph_; } JSGraph* jsgraph() const { return js_graph_; }
@ -270,6 +277,7 @@ class EffectControlLinearizer {
Schedule* schedule_; Schedule* schedule_;
Zone* temp_zone_; Zone* temp_zone_;
MaskArrayIndexEnable mask_array_index_; MaskArrayIndexEnable mask_array_index_;
MaintainSchedule maintain_schedule_;
RegionObservability region_observability_ = RegionObservability::kObservable; RegionObservability region_observability_ = RegionObservability::kObservable;
SourcePositionTable* source_positions_; SourcePositionTable* source_positions_;
NodeOriginTable* node_origins_; NodeOriginTable* node_origins_;
@ -544,6 +552,8 @@ void EffectControlLinearizer::Run() {
ZoneVector<BasicBlock*> pending_block_controls(temp_zone()); ZoneVector<BasicBlock*> pending_block_controls(temp_zone());
NodeVector inputs_buffer(temp_zone()); NodeVector inputs_buffer(temp_zone());
// TODO(rmcilroy) We should not depend on having rpo_order on schedule, and
// instead just do our own RPO walk here.
for (BasicBlock* block : *(schedule()->rpo_order())) { for (BasicBlock* block : *(schedule()->rpo_order())) {
gasm()->Reset(block); gasm()->Reset(block);
@ -704,7 +714,8 @@ void EffectControlLinearizer::Run() {
break; break;
} }
if (block->control() == BasicBlock::kBranch) { if (!should_maintain_schedule() &&
block->control() == BasicBlock::kBranch) {
TryCloneBranch(block->control_input(), block, temp_zone(), graph(), TryCloneBranch(block->control_input(), block, temp_zone(), graph(),
common(), &block_effects, source_positions_, common(), &block_effects, source_positions_,
node_origins_); node_origins_);
@ -732,6 +743,7 @@ void EffectControlLinearizer::Run() {
UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block,
&block_effects); &block_effects);
} }
schedule_->rpo_order()->clear(); schedule_->rpo_order()->clear();
} }
@ -757,6 +769,13 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state) {
source_positions_->GetSourcePosition(node)); source_positions_->GetSourcePosition(node));
NodeOriginTable::Scope origin_scope(node_origins_, "process node", node); NodeOriginTable::Scope origin_scope(node_origins_, "process node", node);
// If basic block is unreachable after this point, update the node's effect
// and control inputs to mark it as dead, but don't process further.
if (gasm()->current_effect() == jsgraph()->Dead()) {
UpdateEffectControlForNode(node);
return;
}
// If the node needs to be wired into the effect/control chain, do this // If the node needs to be wired into the effect/control chain, do this
// here. Pass current frame state for lowering to eager deoptimization. // here. Pass current frame state for lowering to eager deoptimization.
if (TryWireInStateEffect(node, *frame_state)) { if (TryWireInStateEffect(node, *frame_state)) {
@ -6053,10 +6072,11 @@ Node* EffectControlLinearizer::LowerDateNow(Node* node) {
void LinearizeEffectControl(JSGraph* graph, Schedule* schedule, Zone* temp_zone, void LinearizeEffectControl(JSGraph* graph, Schedule* schedule, Zone* temp_zone,
SourcePositionTable* source_positions, SourcePositionTable* source_positions,
NodeOriginTable* node_origins, NodeOriginTable* node_origins,
MaskArrayIndexEnable mask_array_index) { MaskArrayIndexEnable mask_array_index,
MaintainSchedule maintain_schedule) {
EffectControlLinearizer linearizer(graph, schedule, temp_zone, EffectControlLinearizer linearizer(graph, schedule, temp_zone,
source_positions, node_origins, source_positions, node_origins,
mask_array_index); mask_array_index, maintain_schedule);
linearizer.Run(); linearizer.Run();
} }

View File

@ -24,10 +24,12 @@ class SourcePositionTable;
enum class MaskArrayIndexEnable { kDoNotMaskArrayIndex, kMaskArrayIndex }; enum class MaskArrayIndexEnable { kDoNotMaskArrayIndex, kMaskArrayIndex };
enum class MaintainSchedule { kMaintain, kDiscard };
V8_EXPORT_PRIVATE void LinearizeEffectControl( V8_EXPORT_PRIVATE void LinearizeEffectControl(
JSGraph* graph, Schedule* schedule, Zone* temp_zone, JSGraph* graph, Schedule* schedule, Zone* temp_zone,
SourcePositionTable* source_positions, NodeOriginTable* node_origins, SourcePositionTable* source_positions, NodeOriginTable* node_origins,
MaskArrayIndexEnable mask_array_index); MaskArrayIndexEnable mask_array_index, MaintainSchedule maintain_schedule);
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal

View File

@ -261,11 +261,16 @@ void GraphAssembler::BasicBlockUpdater::AddThrow(Node* node) {
} }
schedule_->AddThrow(current_block_, node); schedule_->AddThrow(current_block_, node);
// Clear original successors and update the original control and control input // Clear original successors and replace the block's original control and
// to the throw, since this block is now connected directly to end(). // control input to the throw, since this block is now connected directly to
saved_successors_.clear(); // the end.
if (original_control_input_ != nullptr) {
NodeProperties::ReplaceUses(original_control_input_, node, nullptr, node);
original_control_input_->Kill();
}
original_control_input_ = node; original_control_input_ = node;
original_control_ = BasicBlock::kThrow; original_control_ = BasicBlock::kThrow;
saved_successors_.clear();
} }
void GraphAssembler::BasicBlockUpdater::UpdateSuccessors(BasicBlock* block) { void GraphAssembler::BasicBlockUpdater::UpdateSuccessors(BasicBlock* block) {
@ -317,19 +322,14 @@ BasicBlock* GraphAssembler::BasicBlockUpdater::Finalize(BasicBlock* original) {
return block; return block;
} }
GraphAssembler::GraphAssembler(JSGraph* jsgraph, Zone* zone) GraphAssembler::GraphAssembler(JSGraph* jsgraph, Zone* zone, Schedule* schedule)
: temp_zone_(zone), : temp_zone_(zone),
jsgraph_(jsgraph), jsgraph_(jsgraph),
current_effect_(nullptr), current_effect_(nullptr),
current_control_(nullptr), current_control_(nullptr),
block_updater_(nullptr) {} block_updater_(schedule != nullptr ? new BasicBlockUpdater(
schedule, jsgraph->graph(), zone)
GraphAssembler::GraphAssembler(JSGraph* jsgraph, Schedule* schedule, Zone* zone) : nullptr) {}
: temp_zone_(zone),
jsgraph_(jsgraph),
current_effect_(nullptr),
current_control_(nullptr),
block_updater_(new BasicBlockUpdater(schedule, jsgraph->graph(), zone)) {}
GraphAssembler::~GraphAssembler() = default; GraphAssembler::~GraphAssembler() = default;
@ -660,7 +660,15 @@ void GraphAssembler::GotoIfBasicBlock(BasicBlock* block, Node* branch,
BasicBlock* GraphAssembler::FinalizeCurrentBlock(BasicBlock* block) { BasicBlock* GraphAssembler::FinalizeCurrentBlock(BasicBlock* block) {
if (block_updater_) { if (block_updater_) {
return block_updater_->Finalize(block); block = block_updater_->Finalize(block);
if (current_control_ == jsgraph()->Dead()) {
// If the block's end is unreachable, then reset current effect and
// control to that of the block's throw control node.
DCHECK(block->control() == BasicBlock::kThrow);
Node* throw_node = block->control_input();
current_control_ = NodeProperties::GetControlInput(throw_node);
current_effect_ = NodeProperties::GetEffectInput(throw_node);
}
} }
return block; return block;
} }

View File

@ -167,11 +167,9 @@ class GraphAssemblerLabel {
class GraphAssembler { class GraphAssembler {
public: public:
// Constructs a GraphAssembler that operates on an unscheduled graph. // Constructs a GraphAssembler. If {schedule} is not null, the graph assembler
GraphAssembler(JSGraph* jsgraph, Zone* zone); // will maintain the schedule as it updates blocks.
// Constructs a GraphAssembler that operates on a scheduled graph, updating GraphAssembler(JSGraph* jsgraph, Zone* zone, Schedule* schedule = nullptr);
// the schedule in the process.
GraphAssembler(JSGraph* jsgraph, Schedule* schedule, Zone* zone);
~GraphAssembler(); ~GraphAssembler();
void Reset(BasicBlock* block); void Reset(BasicBlock* block);

View File

@ -44,13 +44,17 @@ class MemoryLowering::AllocationGroup final : public ZoneObject {
}; };
MemoryLowering::MemoryLowering(JSGraph* jsgraph, Zone* zone, MemoryLowering::MemoryLowering(JSGraph* jsgraph, Zone* zone,
GraphAssembler* graph_assembler,
PoisoningMitigationLevel poisoning_level, PoisoningMitigationLevel poisoning_level,
AllocationFolding allocation_folding, AllocationFolding allocation_folding,
WriteBarrierAssertFailedCallback callback, WriteBarrierAssertFailedCallback callback,
const char* function_debug_name) const char* function_debug_name)
: jsgraph_(jsgraph), : isolate_(jsgraph->isolate()),
zone_(zone), zone_(zone),
graph_assembler_(jsgraph, zone), graph_zone_(jsgraph->graph()->zone()),
common_(jsgraph->common()),
machine_(jsgraph->machine()),
graph_assembler_(graph_assembler),
allocation_folding_(allocation_folding), allocation_folding_(allocation_folding),
poisoning_level_(poisoning_level), poisoning_level_(poisoning_level),
write_barrier_assert_failed_(callback), write_barrier_assert_failed_(callback),
@ -195,7 +199,7 @@ Reduction MemoryLowering::ReduceAllocateRaw(
if (!allocate_operator_.is_set()) { if (!allocate_operator_.is_set()) {
auto descriptor = AllocateDescriptor{}; auto descriptor = AllocateDescriptor{};
auto call_descriptor = Linkage::GetStubCallDescriptor( auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), descriptor, descriptor.GetStackParameterCount(), graph_zone(), descriptor, descriptor.GetStackParameterCount(),
CallDescriptor::kCanUseRoots, Operator::kNoThrow); CallDescriptor::kCanUseRoots, Operator::kNoThrow);
allocate_operator_.set(common()->Call(call_descriptor)); allocate_operator_.set(common()->Call(call_descriptor));
} }
@ -256,7 +260,7 @@ Reduction MemoryLowering::ReduceAllocateRaw(
if (!allocate_operator_.is_set()) { if (!allocate_operator_.is_set()) {
auto descriptor = AllocateDescriptor{}; auto descriptor = AllocateDescriptor{};
auto call_descriptor = Linkage::GetStubCallDescriptor( auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), descriptor, descriptor.GetStackParameterCount(), graph_zone(), descriptor, descriptor.GetStackParameterCount(),
CallDescriptor::kCanUseRoots, Operator::kNoThrow); CallDescriptor::kCanUseRoots, Operator::kNoThrow);
allocate_operator_.set(common()->Call(call_descriptor)); allocate_operator_.set(common()->Call(call_descriptor));
} }
@ -275,22 +279,6 @@ Reduction MemoryLowering::ReduceAllocateRaw(
} }
} }
// Replace all effect uses of {node} with the {effect} and replace
// all value uses of {node} with the {value}.
for (Edge edge : node->use_edges()) {
if (NodeProperties::IsEffectEdge(edge)) {
edge.UpdateTo(effect);
} else if (NodeProperties::IsValueEdge(edge)) {
edge.UpdateTo(value);
} else {
DCHECK(NodeProperties::IsControlEdge(edge));
edge.UpdateTo(control);
}
}
// Kill the {node} to make sure we don't leave dangling dead uses.
node->Kill();
return Replace(value); return Replace(value);
} }
@ -318,8 +306,8 @@ Reduction MemoryLowering::ReduceLoadElement(Node* node) {
Reduction MemoryLowering::ReduceLoadField(Node* node) { Reduction MemoryLowering::ReduceLoadField(Node* node) {
DCHECK_EQ(IrOpcode::kLoadField, node->opcode()); DCHECK_EQ(IrOpcode::kLoadField, node->opcode());
FieldAccess const& access = FieldAccessOf(node->op()); FieldAccess const& access = FieldAccessOf(node->op());
Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag()); Node* offset = __ IntPtrConstant(access.offset - access.tag());
node->InsertInput(graph()->zone(), 1, offset); node->InsertInput(graph_zone(), 1, offset);
MachineType type = access.machine_type; MachineType type = access.machine_type;
if (NeedsPoisoning(access.load_sensitivity)) { if (NeedsPoisoning(access.load_sensitivity)) {
NodeProperties::ChangeOp(node, machine()->PoisonedLoad(type)); NodeProperties::ChangeOp(node, machine()->PoisonedLoad(type));
@ -367,8 +355,8 @@ Reduction MemoryLowering::ReduceStoreField(Node* node,
Node* value = node->InputAt(1); Node* value = node->InputAt(1);
WriteBarrierKind write_barrier_kind = ComputeWriteBarrierKind( WriteBarrierKind write_barrier_kind = ComputeWriteBarrierKind(
node, object, value, state, access.write_barrier_kind); node, object, value, state, access.write_barrier_kind);
Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag()); Node* offset = __ IntPtrConstant(access.offset - access.tag());
node->InsertInput(graph()->zone(), 1, offset); node->InsertInput(graph_zone(), 1, offset);
NodeProperties::ChangeOp( NodeProperties::ChangeOp(
node, machine()->Store(StoreRepresentation( node, machine()->Store(StoreRepresentation(
access.machine_type.representation(), write_barrier_kind))); access.machine_type.representation(), write_barrier_kind)));
@ -534,18 +522,6 @@ bool MemoryLowering::AllocationState::IsYoungGenerationAllocation() const {
return group() && group()->IsYoungGenerationAllocation(); return group() && group()->IsYoungGenerationAllocation();
} }
Graph* MemoryLowering::graph() const { return jsgraph()->graph(); }
Isolate* MemoryLowering::isolate() const { return jsgraph()->isolate(); }
CommonOperatorBuilder* MemoryLowering::common() const {
return jsgraph()->common();
}
MachineOperatorBuilder* MemoryLowering::machine() const {
return jsgraph()->machine();
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -71,7 +71,8 @@ class MemoryLowering final : public Reducer {
Node* node, Node* object, const char* name, Zone* temp_zone)>; Node* node, Node* object, const char* name, Zone* temp_zone)>;
MemoryLowering( MemoryLowering(
JSGraph* jsgraph, Zone* zone, PoisoningMitigationLevel poisoning_level, JSGraph* jsgraph, Zone* zone, GraphAssembler* graph_assembler,
PoisoningMitigationLevel poisoning_level,
AllocationFolding allocation_folding = AllocationFolding allocation_folding =
AllocationFolding::kDontAllocationFolding, AllocationFolding::kDontAllocationFolding,
WriteBarrierAssertFailedCallback callback = [](Node*, Node*, const char*, WriteBarrierAssertFailedCallback callback = [](Node*, Node*, const char*,
@ -110,17 +111,20 @@ class MemoryLowering final : public Reducer {
bool NeedsPoisoning(LoadSensitivity load_sensitivity) const; bool NeedsPoisoning(LoadSensitivity load_sensitivity) const;
Graph* graph() const; Graph* graph() const;
Isolate* isolate() const; Isolate* isolate() const { return isolate_; }
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
JSGraph* jsgraph() const { return jsgraph_; } Zone* graph_zone() const { return graph_zone_; }
CommonOperatorBuilder* common() const; CommonOperatorBuilder* common() const { return common_; }
MachineOperatorBuilder* machine() const; MachineOperatorBuilder* machine() const { return machine_; }
GraphAssembler* gasm() { return &graph_assembler_; } GraphAssembler* gasm() const { return graph_assembler_; }
SetOncePointer<const Operator> allocate_operator_; SetOncePointer<const Operator> allocate_operator_;
JSGraph* const jsgraph_; Isolate* isolate_;
Zone* zone_; Zone* zone_;
GraphAssembler graph_assembler_; Zone* graph_zone_;
CommonOperatorBuilder* common_;
MachineOperatorBuilder* machine_;
GraphAssembler* graph_assembler_;
AllocationFolding allocation_folding_; AllocationFolding allocation_folding_;
PoisoningMitigationLevel poisoning_level_; PoisoningMitigationLevel poisoning_level_;
WriteBarrierAssertFailedCallback write_barrier_assert_failed_; WriteBarrierAssertFailedCallback write_barrier_assert_failed_;

View File

@ -185,8 +185,10 @@ MemoryOptimizer::MemoryOptimizer(
JSGraph* jsgraph, Zone* zone, PoisoningMitigationLevel poisoning_level, JSGraph* jsgraph, Zone* zone, PoisoningMitigationLevel poisoning_level,
MemoryLowering::AllocationFolding allocation_folding, MemoryLowering::AllocationFolding allocation_folding,
const char* function_debug_name, TickCounter* tick_counter) const char* function_debug_name, TickCounter* tick_counter)
: memory_lowering_(jsgraph, zone, poisoning_level, allocation_folding, : graph_assembler_(jsgraph, zone),
WriteBarrierAssertFailed, function_debug_name), memory_lowering_(jsgraph, zone, &graph_assembler_, poisoning_level,
allocation_folding, WriteBarrierAssertFailed,
function_debug_name),
jsgraph_(jsgraph), jsgraph_(jsgraph),
empty_state_(AllocationState::Empty(zone)), empty_state_(AllocationState::Empty(zone)),
pending_(zone), pending_(zone),
@ -311,8 +313,17 @@ void MemoryOptimizer::VisitAllocateRaw(Node* node,
} }
} }
memory_lowering()->ReduceAllocateRaw( Reduction reduction = memory_lowering()->ReduceAllocateRaw(
node, allocation_type, allocation.allow_large_objects(), &state); node, allocation_type, allocation.allow_large_objects(), &state);
CHECK(reduction.Changed() && reduction.replacement() != node);
// Replace all uses of node and kill the node to make sure we don't leave
// dangling dead uses.
NodeProperties::ReplaceUses(node, reduction.replacement(),
graph_assembler_.current_effect(),
graph_assembler_.current_control());
node->Kill();
EnqueueUses(state->effect(), state); EnqueueUses(state->effect(), state);
} }

View File

@ -5,6 +5,7 @@
#ifndef V8_COMPILER_MEMORY_OPTIMIZER_H_ #ifndef V8_COMPILER_MEMORY_OPTIMIZER_H_
#define V8_COMPILER_MEMORY_OPTIMIZER_H_ #define V8_COMPILER_MEMORY_OPTIMIZER_H_
#include "src/compiler/graph-assembler.h"
#include "src/compiler/memory-lowering.h" #include "src/compiler/memory-lowering.h"
#include "src/zone/zone-containers.h" #include "src/zone/zone-containers.h"
@ -78,6 +79,7 @@ class MemoryOptimizer final {
JSGraph* jsgraph() const { return jsgraph_; } JSGraph* jsgraph() const { return jsgraph_; }
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
GraphAssembler graph_assembler_;
MemoryLowering memory_lowering_; MemoryLowering memory_lowering_;
JSGraph* jsgraph_; JSGraph* jsgraph_;
AllocationState const* const empty_state_; AllocationState const* const empty_state_;

View File

@ -65,6 +65,7 @@
#include "src/compiler/pipeline-statistics.h" #include "src/compiler/pipeline-statistics.h"
#include "src/compiler/redundancy-elimination.h" #include "src/compiler/redundancy-elimination.h"
#include "src/compiler/schedule.h" #include "src/compiler/schedule.h"
#include "src/compiler/scheduled-machine-lowering.h"
#include "src/compiler/scheduler.h" #include "src/compiler/scheduler.h"
#include "src/compiler/select-lowering.h" #include "src/compiler/select-lowering.h"
#include "src/compiler/serializer-for-background-compilation.h" #include "src/compiler/serializer-for-background-compilation.h"
@ -1645,7 +1646,7 @@ struct EffectControlLinearizationPhase {
// - introduce effect phis and rewire effects to get SSA again. // - introduce effect phis and rewire effects to get SSA again.
LinearizeEffectControl(data->jsgraph(), schedule, temp_zone, LinearizeEffectControl(data->jsgraph(), schedule, temp_zone,
data->source_positions(), data->node_origins(), data->source_positions(), data->node_origins(),
mask_array_index); mask_array_index, MaintainSchedule::kDiscard);
} }
{ {
// The {EffectControlLinearizer} might leave {Dead} nodes behind, so we // The {EffectControlLinearizer} might leave {Dead} nodes behind, so we
@ -1759,7 +1760,8 @@ struct LateOptimizationPhase {
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(), CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
data->broker(), data->common(), data->broker(), data->common(),
data->machine(), temp_zone); data->machine(), temp_zone);
SelectLowering select_lowering(data->jsgraph(), temp_zone); GraphAssembler graph_assembler(data->jsgraph(), temp_zone);
SelectLowering select_lowering(&graph_assembler, data->graph());
// TODO(v8:7703, solanes): go back to using #if guards once // TODO(v8:7703, solanes): go back to using #if guards once
// FLAG_turbo_decompression_elimination gets removed. // FLAG_turbo_decompression_elimination gets removed.
DecompressionElimination decompression_elimination( DecompressionElimination decompression_elimination(
@ -1806,20 +1808,48 @@ struct DecompressionOptimizationPhase {
} }
}; };
struct MidTierMachineLoweringPhase { struct ScheduledEffectControlLinearizationPhase {
static const char* phase_name() { return "V8.TFMidTierMachineLoweringPhase"; } static const char* phase_name() {
return "V8.TFScheduledEffectControlLinearizationPhase";
}
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
GraphReducer graph_reducer(temp_zone, data->graph(), MaskArrayIndexEnable mask_array_index =
&data->info()->tick_counter(), (data->info()->GetPoisoningMitigationLevel() !=
data->jsgraph()->Dead()); PoisoningMitigationLevel::kDontPoison)
SelectLowering select_lowering(data->jsgraph(), temp_zone); ? MaskArrayIndexEnable::kMaskArrayIndex
MemoryLowering memory_lowering(data->jsgraph(), temp_zone, : MaskArrayIndexEnable::kDoNotMaskArrayIndex;
data->info()->GetPoisoningMitigationLevel()); // Post-pass for wiring the control/effects
// - connect allocating representation changes into the control&effect
// chains and lower them,
// - get rid of the region markers,
// - introduce effect phis and rewire effects to get SSA again.
LinearizeEffectControl(data->jsgraph(), data->schedule(), temp_zone,
data->source_positions(), data->node_origins(),
mask_array_index, MaintainSchedule::kMaintain);
AddReducer(data, &graph_reducer, &memory_lowering); // TODO(rmcilroy) Avoid having to rebuild rpo_order on schedule each time.
AddReducer(data, &graph_reducer, &select_lowering); Scheduler::ComputeSpecialRPO(temp_zone, data->schedule());
graph_reducer.ReduceGraph(); TraceSchedule(data->info(), data, data->schedule(),
"effect linearization schedule");
}
};
struct ScheduledMachineLoweringPhase {
static const char* phase_name() {
return "V8.TFScheduledMachineLoweringPhase";
}
void Run(PipelineData* data, Zone* temp_zone) {
ScheduledMachineLowering machine_lowering(
data->jsgraph(), data->schedule(), temp_zone, data->source_positions(),
data->node_origins(), data->info()->GetPoisoningMitigationLevel());
machine_lowering.Run();
// TODO(rmcilroy) Avoid having to rebuild rpo_order on schedule each time.
Scheduler::ComputeSpecialRPO(temp_zone, data->schedule());
TraceSchedule(data->info(), data, data->schedule(),
"machine lowered schedule");
} }
}; };
@ -2498,19 +2528,20 @@ bool PipelineImpl::OptimizeGraphForMidTier(Linkage* linkage) {
data->BeginPhaseKind("V8.TFBlockBuilding"); data->BeginPhaseKind("V8.TFBlockBuilding");
Run<EffectControlLinearizationPhase>(); ComputeScheduledGraph();
RunPrintAndVerify(EffectControlLinearizationPhase::phase_name(), true);
Run<MidTierMachineLoweringPhase>(); Run<ScheduledEffectControlLinearizationPhase>();
RunPrintAndVerify(MidTierMachineLoweringPhase::phase_name(), true); RunPrintAndVerify(ScheduledEffectControlLinearizationPhase::phase_name(),
true);
Run<ScheduledMachineLoweringPhase>();
RunPrintAndVerify(ScheduledMachineLoweringPhase::phase_name(), true);
data->source_positions()->RemoveDecorator(); data->source_positions()->RemoveDecorator();
if (data->info()->trace_turbo_json_enabled()) { if (data->info()->trace_turbo_json_enabled()) {
data->node_origins()->RemoveDecorator(); data->node_origins()->RemoveDecorator();
} }
ComputeScheduledGraph();
return SelectInstructions(linkage); return SelectInstructions(linkage);
} }

View File

@ -0,0 +1,69 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/scheduled-machine-lowering.h"
#include "src/compiler/compiler-source-position-table.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node-origin-table.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/schedule.h"
namespace v8 {
namespace internal {
namespace compiler {
ScheduledMachineLowering::ScheduledMachineLowering(
JSGraph* js_graph, Schedule* schedule, Zone* temp_zone,
SourcePositionTable* source_positions, NodeOriginTable* node_origins,
PoisoningMitigationLevel poison_level)
: schedule_(schedule),
graph_assembler_(js_graph, temp_zone, schedule),
select_lowering_(&graph_assembler_, js_graph->graph()),
memory_lowering_(js_graph, temp_zone, &graph_assembler_, poison_level),
reducers_({&select_lowering_, &memory_lowering_}, temp_zone),
source_positions_(source_positions),
node_origins_(node_origins) {}
void ScheduledMachineLowering::Run() {
// TODO(rmcilroy) We should not depend on having rpo_order on schedule, and
// instead just do our own RPO walk here.
for (BasicBlock* block : *(schedule()->rpo_order())) {
BasicBlock::iterator instr = block->begin();
BasicBlock::iterator end_instr = block->end();
gasm()->Reset(block);
for (; instr != end_instr; instr++) {
Node* node = *instr;
Reduction reduction;
for (auto reducer : reducers_) {
reduction = reducer->Reduce(node);
if (reduction.Changed()) break;
}
if (reduction.Changed()) {
Node* replacement = reduction.replacement();
if (replacement != node) {
// Replace all uses of node and kill the node to make sure we don't
// leave dangling dead uses.
NodeProperties::ReplaceUses(node, replacement,
gasm()->current_effect(),
gasm()->current_control());
node->Kill();
} else {
gasm()->AddNode(replacement);
}
} else {
gasm()->AddNode(node);
}
}
gasm()->FinalizeCurrentBlock(block);
}
schedule_->rpo_order()->clear();
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,51 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_SCHEDULED_MACHINE_LOWERING_H_
#define V8_COMPILER_SCHEDULED_MACHINE_LOWERING_H_
#include "src/compiler/graph-assembler.h"
#include "src/compiler/memory-lowering.h"
#include "src/compiler/select-lowering.h"
namespace v8 {
namespace internal {
namespace compiler {
class NodeOriginTable;
class Schedule;
class SourcePositionTable;
// Performs machine lowering on an already scheduled graph.
class ScheduledMachineLowering final {
public:
ScheduledMachineLowering(JSGraph* js_graph, Schedule* schedule,
Zone* temp_zone,
SourcePositionTable* source_positions,
NodeOriginTable* node_origins,
PoisoningMitigationLevel poison_level);
~ScheduledMachineLowering() = default;
void Run();
private:
bool LowerNode(Node* node);
GraphAssembler* gasm() { return &graph_assembler_; }
Schedule* schedule() { return schedule_; }
Schedule* schedule_;
GraphAssembler graph_assembler_;
SelectLowering select_lowering_;
MemoryLowering memory_lowering_;
ZoneVector<Reducer*> reducers_;
SourcePositionTable* source_positions_;
NodeOriginTable* node_origins_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_SCHEDULED_MACHINE_LOWERING_H_

View File

@ -6,27 +6,28 @@
#include "src/compiler/common-operator.h" #include "src/compiler/common-operator.h"
#include "src/compiler/diamond.h" #include "src/compiler/diamond.h"
#include "src/compiler/graph-assembler.h"
#include "src/compiler/graph.h" #include "src/compiler/graph.h"
#include "src/compiler/node.h"
#include "src/compiler/node-properties.h" #include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
SelectLowering::SelectLowering(JSGraph* jsgraph, Zone* zone) SelectLowering::SelectLowering(GraphAssembler* graph_assembler, Graph* graph)
: graph_assembler_(jsgraph, zone), start_(jsgraph->graph()->start()) {} : graph_assembler_(graph_assembler), start_(graph->start()) {}
SelectLowering::~SelectLowering() = default; SelectLowering::~SelectLowering() = default;
Reduction SelectLowering::Reduce(Node* node) { Reduction SelectLowering::Reduce(Node* node) {
if (node->opcode() != IrOpcode::kSelect) return NoChange(); if (node->opcode() != IrOpcode::kSelect) return NoChange();
return Changed(LowerSelect(node)); return LowerSelect(node);
} }
#define __ gasm()-> #define __ gasm()->
Node* SelectLowering::LowerSelect(Node* node) { Reduction SelectLowering::LowerSelect(Node* node) {
SelectParameters const p = SelectParametersOf(node->op()); SelectParameters const p = SelectParametersOf(node->op());
Node* condition = node->InputAt(0); Node* condition = node->InputAt(0);
@ -41,7 +42,7 @@ Node* SelectLowering::LowerSelect(Node* node) {
__ Goto(&done, vfalse); __ Goto(&done, vfalse);
__ Bind(&done); __ Bind(&done);
return done.PhiAt(0); return Changed(done.PhiAt(0));
} }
#undef __ #undef __

View File

@ -5,30 +5,32 @@
#ifndef V8_COMPILER_SELECT_LOWERING_H_ #ifndef V8_COMPILER_SELECT_LOWERING_H_
#define V8_COMPILER_SELECT_LOWERING_H_ #define V8_COMPILER_SELECT_LOWERING_H_
#include "src/compiler/graph-assembler.h"
#include "src/compiler/graph-reducer.h" #include "src/compiler/graph-reducer.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
// Forward declarations.
class GraphAssembler;
// Lowers Select nodes to diamonds. // Lowers Select nodes to diamonds.
class SelectLowering final : public Reducer { class SelectLowering final : public Reducer {
public: public:
SelectLowering(JSGraph* jsgraph, Zone* zone); SelectLowering(GraphAssembler* graph_assembler, Graph* graph);
~SelectLowering() override; ~SelectLowering() override;
const char* reducer_name() const override { return "SelectLowering"; } const char* reducer_name() const override { return "SelectLowering"; }
Reduction Reduce(Node* node) override; Reduction Reduce(Node* node) override;
Node* LowerSelect(Node* node);
private: private:
GraphAssembler* gasm() { return &graph_assembler_; } Reduction LowerSelect(Node* node);
Node* start() { return start_; }
GraphAssembler graph_assembler_; GraphAssembler* gasm() const { return graph_assembler_; }
Node* start() const { return start_; }
GraphAssembler* graph_assembler_;
Node* start_; Node* start_;
}; };

View File

@ -85,9 +85,9 @@ TEST_F(EffectControlLinearizerTest, SimpleLoad) {
schedule.AddReturn(start, ret); schedule.AddReturn(start, ret);
// Run the state effect introducer. // Run the state effect introducer.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(), LinearizeEffectControl(
node_origins(), jsgraph(), &schedule, zone(), source_positions(), node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex); MaskArrayIndexEnable::kDoNotMaskArrayIndex, MaintainSchedule::kDiscard);
EXPECT_THAT(load, EXPECT_THAT(load,
IsLoadField(AccessBuilder::ForHeapNumberValue(), heap_number, IsLoadField(AccessBuilder::ForHeapNumberValue(), heap_number,
@ -147,9 +147,9 @@ TEST_F(EffectControlLinearizerTest, DiamondLoad) {
schedule.AddReturn(mblock, ret); schedule.AddReturn(mblock, ret);
// Run the state effect introducer. // Run the state effect introducer.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(), LinearizeEffectControl(
node_origins(), jsgraph(), &schedule, zone(), source_positions(), node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex); MaskArrayIndexEnable::kDoNotMaskArrayIndex, MaintainSchedule::kDiscard);
// The effect input to the return should be an effect phi with the // The effect input to the return should be an effect phi with the
// newly introduced effectful change operators. // newly introduced effectful change operators.
@ -214,9 +214,9 @@ TEST_F(EffectControlLinearizerTest, LoopLoad) {
schedule.AddReturn(rblock, ret); schedule.AddReturn(rblock, ret);
// Run the state effect introducer. // Run the state effect introducer.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(), LinearizeEffectControl(
node_origins(), jsgraph(), &schedule, zone(), source_positions(), node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex); MaskArrayIndexEnable::kDoNotMaskArrayIndex, MaintainSchedule::kDiscard);
ASSERT_THAT(ret, IsReturn(load, load, if_true)); ASSERT_THAT(ret, IsReturn(load, load, if_true));
EXPECT_THAT(load, IsLoadField(AccessBuilder::ForHeapNumberValue(), EXPECT_THAT(load, IsLoadField(AccessBuilder::ForHeapNumberValue(),
@ -277,9 +277,9 @@ TEST_F(EffectControlLinearizerTest, CloneBranch) {
schedule.AddNode(mblock, merge); schedule.AddNode(mblock, merge);
schedule.AddNode(mblock, graph()->end()); schedule.AddNode(mblock, graph()->end());
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(), LinearizeEffectControl(
node_origins(), jsgraph(), &schedule, zone(), source_positions(), node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex); MaskArrayIndexEnable::kDoNotMaskArrayIndex, MaintainSchedule::kDiscard);
Capture<Node *> branch1_capture, branch2_capture; Capture<Node *> branch1_capture, branch2_capture;
EXPECT_THAT( EXPECT_THAT(