[Turboprop] Remove ScheduledMachineLowering and replace with inline reductions.

Instead of running a second pass of the scheduled graph after
effect control linearization to do machine lowering, integrate
the machine lowering reducers (MemoryLowering and SelectLowering)
into the graph assembler used by the effect control linearization.
This saves running through the graph and re-maintaining the schedule
for the second time, reducing overhead in Turboprop.

BUG=v8:9684

Change-Id: Ib0fed19089287c8e801a063333cb8404181411db
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2848474
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74178}
This commit is contained in:
Ross McIlroy 2021-04-26 10:10:51 +01:00 committed by Commit Bot
parent 4982b98f3c
commit 12aa090ee6
10 changed files with 156 additions and 206 deletions

View File

@ -2508,7 +2508,6 @@ v8_header_set("v8_internal_headers") {
"src/compiler/refs-map.h",
"src/compiler/representation-change.h",
"src/compiler/schedule.h",
"src/compiler/scheduled-machine-lowering.h",
"src/compiler/scheduler.h",
"src/compiler/select-lowering.h",
"src/compiler/serializer-for-background-compilation.h",
@ -3493,7 +3492,6 @@ v8_compiler_sources = [
"src/compiler/refs-map.cc",
"src/compiler/representation-change.cc",
"src/compiler/schedule.cc",
"src/compiler/scheduled-machine-lowering.cc",
"src/compiler/scheduler.cc",
"src/compiler/select-lowering.cc",
"src/compiler/serializer-for-background-compilation.cc",

View File

@ -17,11 +17,13 @@
#include "src/compiler/js-graph.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/linkage.h"
#include "src/compiler/memory-lowering.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-origin-table.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
#include "src/compiler/schedule.h"
#include "src/compiler/select-lowering.h"
#include "src/execution/frames.h"
#include "src/heap/factory-inl.h"
#include "src/objects/heap-number.h"
@ -32,10 +34,13 @@ namespace v8 {
namespace internal {
namespace compiler {
enum class MaintainSchedule { kMaintain, kDiscard };
enum class MaskArrayIndexEnable { kDoNotMaskArrayIndex, kMaskArrayIndex };
class EffectControlLinearizer {
public:
EffectControlLinearizer(JSGraph* js_graph, Schedule* schedule,
Zone* temp_zone,
JSGraphAssembler* graph_assembler, Zone* temp_zone,
SourcePositionTable* source_positions,
NodeOriginTable* node_origins,
MaskArrayIndexEnable mask_array_index,
@ -49,8 +54,7 @@ class EffectControlLinearizer {
source_positions_(source_positions),
node_origins_(node_origins),
broker_(broker),
graph_assembler_(js_graph, temp_zone, base::nullopt,
should_maintain_schedule() ? schedule : nullptr),
graph_assembler_(graph_assembler),
frame_state_zapper_(nullptr) {}
void Run();
@ -308,7 +312,7 @@ class EffectControlLinearizer {
return js_graph_->simplified();
}
MachineOperatorBuilder* machine() const { return js_graph_->machine(); }
JSGraphAssembler* gasm() { return &graph_assembler_; }
JSGraphAssembler* gasm() const { return graph_assembler_; }
JSHeapBroker* broker() const { return broker_; }
JSGraph* js_graph_;
@ -320,7 +324,7 @@ class EffectControlLinearizer {
SourcePositionTable* source_positions_;
NodeOriginTable* node_origins_;
JSHeapBroker* broker_;
JSGraphAssembler graph_assembler_;
JSGraphAssembler* graph_assembler_;
Node* frame_state_zapper_; // For tracking down compiler::Node::New crashes.
};
@ -6467,15 +6471,47 @@ Node* EffectControlLinearizer::BuildIsClearedWeakReference(Node* maybe_object) {
#undef __
namespace {
MaskArrayIndexEnable MaskArrayForPoisonLevel(
PoisoningMitigationLevel poison_level) {
return (poison_level != PoisoningMitigationLevel::kDontPoison)
? MaskArrayIndexEnable::kMaskArrayIndex
: MaskArrayIndexEnable::kDoNotMaskArrayIndex;
}
} // namespace
void LinearizeEffectControl(JSGraph* graph, Schedule* schedule, Zone* temp_zone,
SourcePositionTable* source_positions,
NodeOriginTable* node_origins,
MaskArrayIndexEnable mask_array_index,
MaintainSchedule maintain_schedule,
PoisoningMitigationLevel poison_level,
JSHeapBroker* broker) {
EffectControlLinearizer linearizer(
graph, schedule, temp_zone, source_positions, node_origins,
mask_array_index, maintain_schedule, broker);
JSGraphAssembler graph_assembler_(graph, temp_zone, base::nullopt, nullptr);
EffectControlLinearizer linearizer(graph, schedule, &graph_assembler_,
temp_zone, source_positions, node_origins,
MaskArrayForPoisonLevel(poison_level),
MaintainSchedule::kDiscard, broker);
linearizer.Run();
}
void LowerToMachineSchedule(JSGraph* js_graph, Schedule* schedule,
Zone* temp_zone,
SourcePositionTable* source_positions,
NodeOriginTable* node_origins,
PoisoningMitigationLevel poison_level,
JSHeapBroker* broker) {
JSGraphAssembler graph_assembler(js_graph, temp_zone, base::nullopt,
schedule);
EffectControlLinearizer linearizer(js_graph, schedule, &graph_assembler,
temp_zone, source_positions, node_origins,
MaskArrayForPoisonLevel(poison_level),
MaintainSchedule::kMaintain, broker);
MemoryLowering memory_lowering(js_graph, temp_zone, &graph_assembler,
poison_level);
SelectLowering select_lowering(&graph_assembler, js_graph->graph());
graph_assembler.AddInlineReducer(&memory_lowering);
graph_assembler.AddInlineReducer(&select_lowering);
linearizer.Run();
}

View File

@ -23,15 +23,18 @@ class Schedule;
class SourcePositionTable;
class JSHeapBroker;
enum class MaskArrayIndexEnable { kDoNotMaskArrayIndex, kMaskArrayIndex };
enum class MaintainSchedule { kMaintain, kDiscard };
V8_EXPORT_PRIVATE void LinearizeEffectControl(
JSGraph* graph, Schedule* schedule, Zone* temp_zone,
SourcePositionTable* source_positions, NodeOriginTable* node_origins,
MaskArrayIndexEnable mask_array_index, MaintainSchedule maintain_schedule,
JSHeapBroker* broker);
PoisoningMitigationLevel poison_level, JSHeapBroker* broker);
// Performs effect control linearization lowering in addition to machine
// lowering, producing a scheduled graph that is ready for instruction
// selection.
V8_EXPORT_PRIVATE void LowerToMachineSchedule(
JSGraph* graph, Schedule* schedule, Zone* temp_zone,
SourcePositionTable* source_positions, NodeOriginTable* node_origins,
PoisoningMitigationLevel poison_level, JSHeapBroker* broker);
} // namespace compiler
} // namespace internal

View File

@ -6,6 +6,7 @@
#include "src/codegen/code-factory.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/linkage.h"
#include "src/compiler/schedule.h"
// For TNode types.
@ -330,6 +331,21 @@ BasicBlock* GraphAssembler::BasicBlockUpdater::Finalize(BasicBlock* original) {
return block;
}
class V8_NODISCARD GraphAssembler::BlockInlineReduction {
public:
explicit BlockInlineReduction(GraphAssembler* gasm) : gasm_(gasm) {
DCHECK(!gasm_->inline_reductions_blocked_);
gasm_->inline_reductions_blocked_ = true;
}
~BlockInlineReduction() {
DCHECK(gasm_->inline_reductions_blocked_);
gasm_->inline_reductions_blocked_ = false;
}
private:
GraphAssembler* gasm_;
};
GraphAssembler::GraphAssembler(
MachineGraph* mcgraph, Zone* zone,
base::Optional<NodeChangedCallback> node_changed_callback,
@ -343,6 +359,8 @@ GraphAssembler::GraphAssembler(
? new BasicBlockUpdater(schedule, mcgraph->graph(),
mcgraph->common(), zone)
: nullptr),
inline_reducers_(zone),
inline_reductions_blocked_(false),
loop_headers_(zone),
mark_loop_exits_(mark_loop_exits) {}
@ -994,6 +1012,28 @@ Node* GraphAssembler::AddClonedNode(Node* node) {
}
Node* GraphAssembler::AddNode(Node* node) {
if (!inline_reducers_.empty() && !inline_reductions_blocked_) {
// Reducers may add new nodes to the graph using this graph assembler,
// however they should never introduce nodes that need further reduction,
// so block reduction
BlockInlineReduction scope(this);
Reduction reduction;
for (auto reducer : inline_reducers_) {
reduction = reducer->Reduce(node, nullptr);
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, effect(), control());
node->Kill();
return replacement;
}
}
}
if (block_updater_) {
block_updater_->AddNode(node);
}

View File

@ -27,6 +27,7 @@ namespace compiler {
class Schedule;
class BasicBlock;
class Reducer;
#define PURE_ASSEMBLER_MACH_UNOP_LIST(V) \
V(BitcastFloat32ToInt32) \
@ -442,6 +443,16 @@ class V8_EXPORT_PRIVATE GraphAssembler {
void ConnectUnreachableToEnd();
// Add an inline reducers such that nodes added to the graph will be run
// through the reducers and possibly further lowered. Each reducer should
// operate on independent node types since once a reducer changes a node we
// no longer run any other reducers on that node. The reducers should also
// only generate new nodes that wouldn't be further reduced, as new nodes
// generated by a reducer won't be passed through the reducers again.
void AddInlineReducer(Reducer* reducer) {
inline_reducers_.push_back(reducer);
}
Control control() const { return Control(control_); }
Effect effect() const { return Effect(effect_); }
@ -538,6 +549,8 @@ class V8_EXPORT_PRIVATE GraphAssembler {
};
private:
class BlockInlineReduction;
template <typename... Vars>
void BranchImpl(Node* condition,
GraphAssemblerLabel<sizeof...(Vars)>* if_true,
@ -557,6 +570,11 @@ class V8_EXPORT_PRIVATE GraphAssembler {
base::Optional<NodeChangedCallback> node_changed_callback_;
std::unique_ptr<BasicBlockUpdater> block_updater_;
// Inline reducers enable reductions to be performed to nodes as they are
// added to the graph with the graph assembler.
ZoneVector<Reducer*> inline_reducers_;
bool inline_reductions_blocked_;
// Track loop information in order to properly mark loop exits with
// {LoopExit,LoopExitEffect,LoopExitValue} nodes. The outermost level has
// a nesting level of 0. See also GraphAssembler::LoopScope.

View File

@ -67,7 +67,6 @@
#include "src/compiler/pipeline-statistics.h"
#include "src/compiler/redundancy-elimination.h"
#include "src/compiler/schedule.h"
#include "src/compiler/scheduled-machine-lowering.h"
#include "src/compiler/scheduler.h"
#include "src/compiler/select-lowering.h"
#include "src/compiler/serializer-for-background-compilation.h"
@ -1814,11 +1813,6 @@ struct EffectControlLinearizationPhase {
TraceScheduleAndVerify(data->info(), data, schedule,
"effect linearization schedule");
MaskArrayIndexEnable mask_array_index =
(data->info()->GetPoisoningMitigationLevel() !=
PoisoningMitigationLevel::kDontPoison)
? MaskArrayIndexEnable::kMaskArrayIndex
: MaskArrayIndexEnable::kDoNotMaskArrayIndex;
// Post-pass for wiring the control/effects
// - connect allocating representation changes into the control&effect
// chains and lower them,
@ -1826,7 +1820,7 @@ struct EffectControlLinearizationPhase {
// - introduce effect phis and rewire effects to get SSA again.
LinearizeEffectControl(data->jsgraph(), schedule, temp_zone,
data->source_positions(), data->node_origins(),
mask_array_index, MaintainSchedule::kDiscard,
data->info()->GetPoisoningMitigationLevel(),
data->broker());
}
{
@ -2013,43 +2007,22 @@ struct ScheduledEffectControlLinearizationPhase {
DECL_PIPELINE_PHASE_CONSTANTS(ScheduledEffectControlLinearization)
void Run(PipelineData* data, Zone* temp_zone) {
MaskArrayIndexEnable mask_array_index =
(data->info()->GetPoisoningMitigationLevel() !=
PoisoningMitigationLevel::kDontPoison)
? MaskArrayIndexEnable::kMaskArrayIndex
: MaskArrayIndexEnable::kDoNotMaskArrayIndex;
// 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,
// - introduce effect phis and rewire effects to get SSA again,
// - lower simplified memory and select nodes to machine level nodes.
LowerToMachineSchedule(data->jsgraph(), data->schedule(), temp_zone,
data->source_positions(), data->node_origins(),
mask_array_index, MaintainSchedule::kMaintain,
data->info()->GetPoisoningMitigationLevel(),
data->broker());
// TODO(rmcilroy) Avoid having to rebuild rpo_order on schedule each time.
Scheduler::ComputeSpecialRPO(temp_zone, data->schedule());
if (FLAG_turbo_verify) Scheduler::GenerateDominatorTree(data->schedule());
TraceScheduleAndVerify(data->info(), data, data->schedule(),
"effect linearization schedule");
}
};
struct ScheduledMachineLoweringPhase {
DECL_PIPELINE_PHASE_CONSTANTS(ScheduledMachineLowering)
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());
Scheduler::GenerateDominatorTree(data->schedule());
TraceScheduleAndVerify(data->info(), data, data->schedule(),
"machine lowered schedule");
"effect linearization schedule");
}
};
@ -2877,9 +2850,6 @@ bool PipelineImpl::OptimizeGraphForMidTier(Linkage* linkage) {
RunPrintAndVerify(ScheduledEffectControlLinearizationPhase::phase_name(),
true);
Run<ScheduledMachineLoweringPhase>();
RunPrintAndVerify(ScheduledMachineLoweringPhase::phase_name(), true);
data->source_positions()->RemoveDecorator();
if (data->info()->trace_turbo_json()) {
data->node_origins()->RemoveDecorator();

View File

@ -1,68 +0,0 @@
// 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, base::nullopt, 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, nullptr);
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()->effect(),
gasm()->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

@ -1,51 +0,0 @@
// 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);
JSGraphAssembler* gasm() { return &graph_assembler_; }
Schedule* schedule() { return schedule_; }
Schedule* schedule_;
JSGraphAssembler 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

@ -34,7 +34,11 @@ Reduction SelectLowering::LowerSelect(Node* node) {
Node* vtrue = node->InputAt(1);
Node* vfalse = node->InputAt(2);
bool reset_gasm = false;
if (gasm()->control() == nullptr) {
gasm()->InitializeEffectControl(start(), start());
reset_gasm = true;
}
auto done = __ MakeLabel(p.representation());
@ -42,6 +46,10 @@ Reduction SelectLowering::LowerSelect(Node* node) {
__ Goto(&done, vfalse);
__ Bind(&done);
if (reset_gasm) {
gasm()->Reset(nullptr);
}
return Changed(done.PhiAt(0));
}

View File

@ -86,9 +86,8 @@ TEST_F(EffectControlLinearizerTest, SimpleLoad) {
// Run the state effect introducer.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(),
node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex,
MaintainSchedule::kDiscard, broker());
node_origins(), PoisoningMitigationLevel::kDontPoison,
broker());
EXPECT_THAT(load,
IsLoadField(AccessBuilder::ForHeapNumberValue(), heap_number,
@ -149,9 +148,8 @@ TEST_F(EffectControlLinearizerTest, DiamondLoad) {
// Run the state effect introducer.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(),
node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex,
MaintainSchedule::kDiscard, broker());
node_origins(), PoisoningMitigationLevel::kDontPoison,
broker());
// The effect input to the return should be an effect phi with the
// newly introduced effectful change operators.
@ -217,9 +215,8 @@ TEST_F(EffectControlLinearizerTest, LoopLoad) {
// Run the state effect introducer.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(),
node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex,
MaintainSchedule::kDiscard, broker());
node_origins(), PoisoningMitigationLevel::kDontPoison,
broker());
ASSERT_THAT(ret, IsReturn(load, load, if_true));
EXPECT_THAT(load, IsLoadField(AccessBuilder::ForHeapNumberValue(),
@ -281,9 +278,8 @@ TEST_F(EffectControlLinearizerTest, CloneBranch) {
schedule.AddNode(mblock, graph()->end());
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(),
node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex,
MaintainSchedule::kDiscard, broker());
node_origins(), PoisoningMitigationLevel::kDontPoison,
broker());
Capture<Node *> branch1_capture, branch2_capture;
EXPECT_THAT(
@ -338,11 +334,11 @@ TEST_F(EffectControlLinearizerTest, UnreachableThenBranch) {
ASSERT_THAT(end(), IsEnd(IsThrow(), IsThrow()));
ASSERT_THAT(end()->op()->ControlInputCount(), 2);
// Run the state effect linearizer, maintaining the schedule.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(),
node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex,
MaintainSchedule::kMaintain, broker());
// Run the state effect linearizer and machine lowering, maintaining the
// schedule.
LowerToMachineSchedule(jsgraph(), &schedule, zone(), source_positions(),
node_origins(), PoisoningMitigationLevel::kDontPoison,
broker());
ASSERT_THAT(end(), IsEnd(IsThrow()));
}
@ -391,11 +387,11 @@ TEST_F(EffectControlLinearizerTest, UnreachableThenDiamond) {
ASSERT_THAT(end(), IsEnd(IsThrow()));
ASSERT_THAT(end()->op()->ControlInputCount(), 1);
// Run the state effect linearizer, maintaining the schedule.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(),
node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex,
MaintainSchedule::kMaintain, broker());
// Run the state effect linearizer and machine lowering, maintaining the
// schedule.
LowerToMachineSchedule(jsgraph(), &schedule, zone(), source_positions(),
node_origins(), PoisoningMitigationLevel::kDontPoison,
broker());
ASSERT_THAT(end(), IsEnd(IsThrow()));
}
@ -449,11 +445,11 @@ TEST_F(EffectControlLinearizerTest, UnreachableThenLoop) {
ASSERT_THAT(end(), IsEnd(IsThrow()));
ASSERT_THAT(end()->op()->ControlInputCount(), 1);
// Run the state effect linearizer, maintaining the schedule.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(),
node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex,
MaintainSchedule::kMaintain, broker());
// Run the state effect linearizer and machine lowering, maintaining the
// schedule.
LowerToMachineSchedule(jsgraph(), &schedule, zone(), source_positions(),
node_origins(), PoisoningMitigationLevel::kDontPoison,
broker());
ASSERT_THAT(end(), IsEnd(IsThrow()));
}
@ -503,11 +499,11 @@ TEST_F(EffectControlLinearizerTest, UnreachableInChangedBlockThenBranch) {
ASSERT_THAT(end(), IsEnd(IsThrow(), IsThrow()));
ASSERT_THAT(end()->op()->ControlInputCount(), 2);
// Run the state effect linearizer, maintaining the schedule.
LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(),
node_origins(),
MaskArrayIndexEnable::kDoNotMaskArrayIndex,
MaintainSchedule::kMaintain, broker());
// Run the state effect linearizer and machine lowering, maintaining the
// schedule.
LowerToMachineSchedule(jsgraph(), &schedule, zone(), source_positions(),
node_origins(), PoisoningMitigationLevel::kDontPoison,
broker());
ASSERT_THAT(end(), IsEnd(IsThrow()));
}