Commit 19ac10e5 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

Reland^6 "[turbofan] eagerly prune None types and deadness from the graph"

Reland of https://chromium-review.googlesource.com/c/v8/v8/+/727893
The crashes should be fixed by https://chromium-review.googlesource.com/c/v8/v8/+/763531

Original change's description:
> Revert "Reland^5 "[turbofan] eagerly prune None types and deadness from the graph""
> 
> This reverts commit ac0661b3.
> 
> Reason for revert: Clusterfuzz unhappy: chromium:783019 chromium:783035
> 
> Original change's description:
> > Reland^5 "[turbofan] eagerly prune None types and deadness from the graph"
> >
> > This gives up on earlier attempts to interpret DeadValue as a signal of
> > unreachable code. This does not work because free-floating dead value
> > nodes, and even pure branch nodes that use them, can get scheduled so
> > early that they get reachable. Instead, we now eagerly remove branches
> > that use DeadValue in DeadCodeElimination and replace DeadValue inputs
> > to value phi nodes with dummy values.
> >
> > Reland of https://chromium-review.googlesource.com/715716
> >
> > Bug: chromium:741225 chromium:776256
> > Change-Id: I251efd507c967d4a8882ad8fd2fd96c4185781fe
> > Reviewed-on: https://chromium-review.googlesource.com/727893
> > Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
> > Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#49188}
> 
> TBR=jarin@chromium.org,tebbi@chromium.org
> 
> Bug: chromium:741225 chromium:776256 chromium:783019 chromium:783035
> Change-Id: I6a8fa3a08ce2824a858ae01817688e63ed1f442e
> Reviewed-on: https://chromium-review.googlesource.com/758770
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#49262}

TBR=jarin@chromium.org,tebbi@chromium.org

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: chromium:741225 chromium:776256 chromium:783019 chromium:783035
Change-Id: I6c02b4beb02997ec34015ed2f6791a93c70f5e36
Reviewed-on: https://chromium-review.googlesource.com/772150
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49429}
parent b8092f43
...@@ -18,9 +18,7 @@ BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph, ...@@ -18,9 +18,7 @@ BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph,
jsgraph_(js_graph), jsgraph_(js_graph),
node_conditions_(zone, js_graph->graph()->NodeCount()), node_conditions_(zone, js_graph->graph()->NodeCount()),
zone_(zone), zone_(zone),
dead_(js_graph->graph()->NewNode(js_graph->common()->Dead())) { dead_(js_graph->Dead()) {}
NodeProperties::SetType(dead_, Type::None());
}
BranchElimination::~BranchElimination() {} BranchElimination::~BranchElimination() {}
......
...@@ -343,6 +343,8 @@ ZoneVector<MachineType> const* MachineTypesOf(Operator const* op) { ...@@ -343,6 +343,8 @@ ZoneVector<MachineType> const* MachineTypesOf(Operator const* op) {
#define COMMON_CACHED_OP_LIST(V) \ #define COMMON_CACHED_OP_LIST(V) \
V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \ V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \
V(DeadValue, Operator::kFoldable, 0, 0, 0, 1, 0, 0) \
V(Unreachable, Operator::kFoldable, 0, 1, 1, 0, 1, 0) \
V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
......
...@@ -346,6 +346,8 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final ...@@ -346,6 +346,8 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
explicit CommonOperatorBuilder(Zone* zone); explicit CommonOperatorBuilder(Zone* zone);
const Operator* Dead(); const Operator* Dead();
const Operator* DeadValue();
const Operator* Unreachable();
const Operator* End(size_t control_input_count); const Operator* End(size_t control_input_count);
const Operator* Branch(BranchHint = BranchHint::kNone); const Operator* Branch(BranchHint = BranchHint::kNone);
const Operator* IfTrue(); const Operator* IfTrue();
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "src/compiler/common-operator.h" #include "src/compiler/common-operator.h"
#include "src/compiler/graph.h" #include "src/compiler/graph.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/node-properties.h" #include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h" #include "src/compiler/operator-properties.h"
...@@ -14,14 +15,38 @@ namespace internal { ...@@ -14,14 +15,38 @@ namespace internal {
namespace compiler { namespace compiler {
DeadCodeElimination::DeadCodeElimination(Editor* editor, Graph* graph, DeadCodeElimination::DeadCodeElimination(Editor* editor, Graph* graph,
CommonOperatorBuilder* common) CommonOperatorBuilder* common,
Zone* temp_zone)
: AdvancedReducer(editor), : AdvancedReducer(editor),
graph_(graph), graph_(graph),
common_(common), common_(common),
dead_(graph->NewNode(common->Dead())) { dead_(graph->NewNode(common->Dead())),
dead_value_(graph->NewNode(common->DeadValue())),
zone_(temp_zone) {
NodeProperties::SetType(dead_, Type::None()); NodeProperties::SetType(dead_, Type::None());
NodeProperties::SetType(dead_value_, Type::None());
} }
namespace {
// True if we can guarantee that {node} will never actually produce a value or
// effect.
bool NoReturn(Node* node) {
return node->opcode() == IrOpcode::kDead ||
node->opcode() == IrOpcode::kUnreachable ||
node->opcode() == IrOpcode::kDeadValue ||
NodeProperties::GetTypeOrAny(node)->IsNone();
}
bool HasDeadInput(Node* node) {
for (Node* input : node->inputs()) {
if (NoReturn(input)) return true;
}
return false;
}
} // namespace
Reduction DeadCodeElimination::Reduce(Node* node) { Reduction DeadCodeElimination::Reduce(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kEnd: case IrOpcode::kEnd:
...@@ -31,12 +56,34 @@ Reduction DeadCodeElimination::Reduce(Node* node) { ...@@ -31,12 +56,34 @@ Reduction DeadCodeElimination::Reduce(Node* node) {
return ReduceLoopOrMerge(node); return ReduceLoopOrMerge(node);
case IrOpcode::kLoopExit: case IrOpcode::kLoopExit:
return ReduceLoopExit(node); return ReduceLoopExit(node);
case IrOpcode::kUnreachable:
case IrOpcode::kIfException:
return ReduceUnreachableOrIfException(node);
case IrOpcode::kPhi:
return ReducePhi(node);
case IrOpcode::kEffectPhi:
return PropagateDeadControl(node);
case IrOpcode::kDeoptimize:
case IrOpcode::kReturn:
case IrOpcode::kTerminate:
return ReduceDeoptimizeOrReturnOrTerminate(node);
case IrOpcode::kThrow:
return PropagateDeadControl(node);
case IrOpcode::kBranch:
case IrOpcode::kSwitch:
return ReduceBranchOrSwitch(node);
default: default:
return ReduceNode(node); return ReduceNode(node);
} }
UNREACHABLE(); UNREACHABLE();
} }
Reduction DeadCodeElimination::PropagateDeadControl(Node* node) {
DCHECK_EQ(1, node->op()->ControlInputCount());
Node* control = NodeProperties::GetControlInput(node);
if (control->opcode() == IrOpcode::kDead) return Replace(control);
return NoChange();
}
Reduction DeadCodeElimination::ReduceEnd(Node* node) { Reduction DeadCodeElimination::ReduceEnd(Node* node) {
DCHECK_EQ(IrOpcode::kEnd, node->opcode()); DCHECK_EQ(IrOpcode::kEnd, node->opcode());
...@@ -140,13 +187,105 @@ Reduction DeadCodeElimination::RemoveLoopExit(Node* node) { ...@@ -140,13 +187,105 @@ Reduction DeadCodeElimination::RemoveLoopExit(Node* node) {
} }
Reduction DeadCodeElimination::ReduceNode(Node* node) { Reduction DeadCodeElimination::ReduceNode(Node* node) {
// If {node} has exactly one control input and this is {Dead}, DCHECK(!IrOpcode::IsGraphTerminator(node->opcode()));
// replace {node} with {Dead}. int const effect_input_count = node->op()->EffectInputCount();
int const control_input_count = node->op()->ControlInputCount(); int const control_input_count = node->op()->ControlInputCount();
if (control_input_count == 0) return NoChange(); DCHECK_LE(control_input_count, 1);
DCHECK_EQ(1, control_input_count); if (control_input_count == 1) {
Node* control = NodeProperties::GetControlInput(node); Reduction reduction = PropagateDeadControl(node);
if (control->opcode() == IrOpcode::kDead) return Replace(control); if (reduction.Changed()) return reduction;
}
if (effect_input_count == 0 &&
(control_input_count == 0 || node->op()->ControlOutputCount() == 0)) {
return ReducePureNode(node);
}
if (effect_input_count > 0) {
return ReduceEffectNode(node);
}
return NoChange();
}
Reduction DeadCodeElimination::ReducePhi(Node* node) {
DCHECK_EQ(IrOpcode::kPhi, node->opcode());
Reduction reduction = PropagateDeadControl(node);
if (reduction.Changed()) return reduction;
if (PhiRepresentationOf(node->op()) == MachineRepresentation::kNone ||
NodeProperties::GetTypeOrAny(node)->IsNone()) {
return Replace(dead_value());
}
return NoChange();
}
Reduction DeadCodeElimination::ReducePureNode(Node* node) {
DCHECK_EQ(0, node->op()->EffectInputCount());
int input_count = node->op()->ValueInputCount();
for (int i = 0; i < input_count; ++i) {
Node* input = NodeProperties::GetValueInput(node, i);
if (NoReturn(input)) {
return Replace(dead_value());
}
}
return NoChange();
}
Reduction DeadCodeElimination::ReduceUnreachableOrIfException(Node* node) {
DCHECK(node->opcode() == IrOpcode::kUnreachable ||
node->opcode() == IrOpcode::kIfException);
Reduction reduction = PropagateDeadControl(node);
if (reduction.Changed()) return reduction;
Node* effect = NodeProperties::GetEffectInput(node, 0);
if (effect->opcode() == IrOpcode::kDead) {
return Replace(effect);
}
if (effect->opcode() == IrOpcode::kUnreachable) {
RelaxEffectsAndControls(node);
return Replace(dead_value());
}
return NoChange();
}
Reduction DeadCodeElimination::ReduceEffectNode(Node* node) {
DCHECK_EQ(1, node->op()->EffectInputCount());
Node* effect = NodeProperties::GetEffectInput(node, 0);
if (effect->opcode() == IrOpcode::kDead) {
return Replace(effect);
}
if (HasDeadInput(node)) {
if (effect->opcode() == IrOpcode::kUnreachable) {
RelaxEffectsAndControls(node);
return Replace(dead_value());
}
Node* control = node->op()->ControlInputCount() == 1
? NodeProperties::GetControlInput(node, 0)
: graph()->start();
Node* unreachable =
graph()->NewNode(common()->Unreachable(), effect, control);
ReplaceWithValue(node, dead_value(), node, control);
return Replace(unreachable);
}
return NoChange();
}
Reduction DeadCodeElimination::ReduceDeoptimizeOrReturnOrTerminate(Node* node) {
DCHECK(node->opcode() == IrOpcode::kDeoptimize ||
node->opcode() == IrOpcode::kReturn ||
node->opcode() == IrOpcode::kTerminate);
Reduction reduction = PropagateDeadControl(node);
if (reduction.Changed()) return reduction;
if (HasDeadInput(node)) {
Node* effect = NodeProperties::GetEffectInput(node, 0);
Node* control = NodeProperties::GetControlInput(node, 0);
if (effect->opcode() != IrOpcode::kUnreachable) {
effect = graph()->NewNode(common()->Unreachable(), effect, control);
}
node->TrimInputCount(2);
node->ReplaceInput(0, effect);
node->ReplaceInput(1, control);
NodeProperties::ChangeOp(node, common()->Throw());
return Changed(node);
}
return NoChange(); return NoChange();
} }
...@@ -160,6 +299,27 @@ Reduction DeadCodeElimination::ReduceLoopExit(Node* node) { ...@@ -160,6 +299,27 @@ Reduction DeadCodeElimination::ReduceLoopExit(Node* node) {
return NoChange(); return NoChange();
} }
Reduction DeadCodeElimination::ReduceBranchOrSwitch(Node* node) {
DCHECK(node->opcode() == IrOpcode::kBranch ||
node->opcode() == IrOpcode::kSwitch);
Reduction reduction = PropagateDeadControl(node);
if (reduction.Changed()) return reduction;
Node* condition = NodeProperties::GetValueInput(node, 0);
if (condition->opcode() == IrOpcode::kDeadValue) {
// Branches or switches on {DeadValue} must originate from unreachable code
// and cannot matter. Due to schedule freedom between the effect and the
// control chain, they might still appear in reachable code. Remove them by
// always choosing the first projection.
size_t const projection_cnt = node->op()->ControlOutputCount();
Node** projections = zone_->NewArray<Node*>(projection_cnt);
NodeProperties::CollectControlProjections(node, projections,
projection_cnt);
Replace(projections[0], NodeProperties::GetControlInput(node));
return Replace(dead());
}
return NoChange();
}
void DeadCodeElimination::TrimMergeOrPhi(Node* node, int size) { void DeadCodeElimination::TrimMergeOrPhi(Node* node, int size) {
const Operator* const op = common()->ResizeMergeOrPhi(node->op(), size); const Operator* const op = common()->ResizeMergeOrPhi(node->op(), size);
node->TrimInputCount(OperatorProperties::GetTotalInputCount(op)); node->TrimInputCount(OperatorProperties::GetTotalInputCount(op));
......
...@@ -16,15 +16,20 @@ namespace compiler { ...@@ -16,15 +16,20 @@ namespace compiler {
// Forward declarations. // Forward declarations.
class CommonOperatorBuilder; class CommonOperatorBuilder;
// Propagates {Dead} control through the graph and thereby removes dead code. // Propagates {Dead} control and {DeadValue} values through the graph and
// Note that this does not include trimming dead uses from the graph, and it // thereby removes dead code. When {DeadValue} hits the effect chain, a crashing
// also does not include detecting dead code by any other means than seeing a // {Unreachable} node is inserted and the rest of the effect chain is collapsed.
// {Dead} control input; that is left to other reducers. // We wait for the {EffectControlLinearizer} to connect {Unreachable} nodes to
// the graph end, since this is much easier if there is no floating control.
// We detect dead values based on types, pruning uses of DeadValue except for
// uses by phi. These remaining uses are eliminated in the
// {EffectControlLinearizer}, where they are replaced with dummy values.
// In contrast to {DeadValue}, {Dead} can never remain in the graph.
class V8_EXPORT_PRIVATE DeadCodeElimination final class V8_EXPORT_PRIVATE DeadCodeElimination final
: public NON_EXPORTED_BASE(AdvancedReducer) { : public NON_EXPORTED_BASE(AdvancedReducer) {
public: public:
DeadCodeElimination(Editor* editor, Graph* graph, DeadCodeElimination(Editor* editor, Graph* graph,
CommonOperatorBuilder* common); CommonOperatorBuilder* common, Zone* temp_zone);
~DeadCodeElimination() final {} ~DeadCodeElimination() final {}
const char* reducer_name() const override { return "DeadCodeElimination"; } const char* reducer_name() const override { return "DeadCodeElimination"; }
...@@ -36,18 +41,28 @@ class V8_EXPORT_PRIVATE DeadCodeElimination final ...@@ -36,18 +41,28 @@ class V8_EXPORT_PRIVATE DeadCodeElimination final
Reduction ReduceLoopOrMerge(Node* node); Reduction ReduceLoopOrMerge(Node* node);
Reduction ReduceLoopExit(Node* node); Reduction ReduceLoopExit(Node* node);
Reduction ReduceNode(Node* node); Reduction ReduceNode(Node* node);
Reduction ReducePhi(Node* node);
Reduction ReducePureNode(Node* node);
Reduction ReduceUnreachableOrIfException(Node* node);
Reduction ReduceEffectNode(Node* node);
Reduction ReduceDeoptimizeOrReturnOrTerminate(Node* node);
Reduction ReduceBranchOrSwitch(Node* node);
Reduction RemoveLoopExit(Node* node); Reduction RemoveLoopExit(Node* node);
Reduction PropagateDeadControl(Node* node);
void TrimMergeOrPhi(Node* node, int size); void TrimMergeOrPhi(Node* node, int size);
Graph* graph() const { return graph_; } Graph* graph() const { return graph_; }
CommonOperatorBuilder* common() const { return common_; } CommonOperatorBuilder* common() const { return common_; }
Node* dead() const { return dead_; } Node* dead() const { return dead_; }
Node* dead_value() const { return dead_value_; }
Graph* const graph_; Graph* const graph_;
CommonOperatorBuilder* const common_; CommonOperatorBuilder* const common_;
Node* const dead_; Node* const dead_;
Node* const dead_value_;
Zone* zone_;
DISALLOW_COPY_AND_ASSIGN(DeadCodeElimination); DISALLOW_COPY_AND_ASSIGN(DeadCodeElimination);
}; };
......
...@@ -76,8 +76,19 @@ struct PendingEffectPhi { ...@@ -76,8 +76,19 @@ struct PendingEffectPhi {
: effect_phi(effect_phi), block(block) {} : effect_phi(effect_phi), block(block) {}
}; };
void ConnectUnreachableToEnd(Node* effect, Node* control, JSGraph* jsgraph) {
Graph* graph = jsgraph->graph();
CommonOperatorBuilder* common = jsgraph->common();
if (effect->opcode() == IrOpcode::kDead) return;
if (effect->opcode() != IrOpcode::kUnreachable) {
effect = graph->NewNode(common->Unreachable(), effect, control);
}
Node* throw_node = graph->NewNode(common->Throw(), effect, control);
NodeProperties::MergeControlToEnd(graph, common, throw_node);
}
void UpdateEffectPhi(Node* node, BasicBlock* block, void UpdateEffectPhi(Node* node, BasicBlock* block,
BlockEffectControlMap* block_effects) { BlockEffectControlMap* block_effects, JSGraph* jsgraph) {
// Update all inputs to an effect phi with the effects from the given // Update all inputs to an effect phi with the effects from the given
// block->effect map. // block->effect map.
DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
...@@ -88,8 +99,9 @@ void UpdateEffectPhi(Node* node, BasicBlock* block, ...@@ -88,8 +99,9 @@ void UpdateEffectPhi(Node* node, BasicBlock* block,
BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i));
const BlockEffectControlData& block_effect = const BlockEffectControlData& block_effect =
block_effects->For(predecessor, block); block_effects->For(predecessor, block);
if (input != block_effect.current_effect) { Node* effect = block_effect.current_effect;
node->ReplaceInput(i, block_effect.current_effect); if (input != effect) {
node->ReplaceInput(i, effect);
} }
} }
} }
...@@ -303,6 +315,29 @@ void TryCloneBranch(Node* node, BasicBlock* block, Zone* temp_zone, ...@@ -303,6 +315,29 @@ void TryCloneBranch(Node* node, BasicBlock* block, Zone* temp_zone,
cond->Kill(); cond->Kill();
merge->Kill(); merge->Kill();
} }
Node* DummyValue(JSGraph* jsgraph, MachineRepresentation rep) {
switch (rep) {
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedSigned:
return jsgraph->SmiConstant(0xdead);
case MachineRepresentation::kTaggedPointer:
return jsgraph->TheHoleConstant();
case MachineRepresentation::kWord64:
return jsgraph->Int64Constant(0xdead);
case MachineRepresentation::kWord32:
return jsgraph->Int32Constant(0xdead);
case MachineRepresentation::kFloat64:
return jsgraph->Float64Constant(0xdead);
case MachineRepresentation::kFloat32:
return jsgraph->Float32Constant(0xdead);
case MachineRepresentation::kBit:
return jsgraph->Int32Constant(0);
default:
UNREACHABLE();
}
}
} // namespace } // namespace
void EffectControlLinearizer::Run() { void EffectControlLinearizer::Run() {
...@@ -330,29 +365,32 @@ void EffectControlLinearizer::Run() { ...@@ -330,29 +365,32 @@ void EffectControlLinearizer::Run() {
instr++; instr++;
// Iterate over the phis and update the effect phis. // Iterate over the phis and update the effect phis.
Node* effect = nullptr; Node* effect_phi = nullptr;
Node* terminate = nullptr; Node* terminate = nullptr;
int predecessor_count = static_cast<int>(block->PredecessorCount());
for (; instr < block->NodeCount(); instr++) { for (; instr < block->NodeCount(); instr++) {
Node* node = block->NodeAt(instr); Node* node = block->NodeAt(instr);
// Only go through the phis and effect phis. // Only go through the phis and effect phis.
if (node->opcode() == IrOpcode::kEffectPhi) { if (node->opcode() == IrOpcode::kEffectPhi) {
// There should be at most one effect phi in a block. // There should be at most one effect phi in a block.
DCHECK_NULL(effect); DCHECK_NULL(effect_phi);
// IfException blocks should not have effect phis. // IfException blocks should not have effect phis.
DCHECK_NE(IrOpcode::kIfException, control->opcode()); DCHECK_NE(IrOpcode::kIfException, control->opcode());
effect = node; effect_phi = node;
// Make sure we update the inputs to the incoming blocks' effects.
if (HasIncomingBackEdges(block)) {
// In case of loops, we do not update the effect phi immediately
// because the back predecessor has not been handled yet. We just
// record the effect phi for later processing.
pending_effect_phis.push_back(PendingEffectPhi(node, block));
} else {
UpdateEffectPhi(node, block, &block_effects);
}
} else if (node->opcode() == IrOpcode::kPhi) { } else if (node->opcode() == IrOpcode::kPhi) {
// Just skip phis. DCHECK_EQ(predecessor_count, node->op()->ValueInputCount());
for (int i = 0; i < predecessor_count; ++i) {
if (NodeProperties::GetValueInput(node, i)->opcode() ==
IrOpcode::kDeadValue) {
// Phi uses of {DeadValue} must originate from unreachable code. Due
// to schedule freedom between the effect and the control chain,
// they might still appear in reachable code. So we replace them
// with a dummy value.
NodeProperties::ReplaceValueInput(
node, DummyValue(jsgraph(), PhiRepresentationOf(node->op())),
i);
}
}
} else if (node->opcode() == IrOpcode::kTerminate) { } else if (node->opcode() == IrOpcode::kTerminate) {
DCHECK_NULL(terminate); DCHECK_NULL(terminate);
terminate = node; terminate = node;
...@@ -361,9 +399,28 @@ void EffectControlLinearizer::Run() { ...@@ -361,9 +399,28 @@ void EffectControlLinearizer::Run() {
} }
} }
if (effect_phi) {
// Make sure we update the inputs to the incoming blocks' effects.
if (HasIncomingBackEdges(block)) {
// In case of loops, we do not update the effect phi immediately
// because the back predecessor has not been handled yet. We just
// record the effect phi for later processing.
pending_effect_phis.push_back(PendingEffectPhi(effect_phi, block));
} else {
UpdateEffectPhi(effect_phi, block, &block_effects, jsgraph());
}
}
Node* effect = effect_phi;
if (effect == nullptr) { if (effect == nullptr) {
// There was no effect phi. // There was no effect phi.
DCHECK(!HasIncomingBackEdges(block));
// Since a loop should have at least a StackCheck, only loops in
// unreachable code can have no effect phi.
DCHECK_IMPLIES(
HasIncomingBackEdges(block),
block_effects.For(block->PredecessorAt(0), block)
.current_effect->opcode() == IrOpcode::kUnreachable);
if (block == schedule()->start()) { if (block == schedule()->start()) {
// Start block => effect is start. // Start block => effect is start.
DCHECK_EQ(graph()->start(), control); DCHECK_EQ(graph()->start(), control);
...@@ -376,11 +433,11 @@ void EffectControlLinearizer::Run() { ...@@ -376,11 +433,11 @@ void EffectControlLinearizer::Run() {
} else { } else {
// If all the predecessors have the same effect, we can use it as our // If all the predecessors have the same effect, we can use it as our
// current effect. // current effect.
effect = for (size_t i = 0; i < block->PredecessorCount(); ++i) {
block_effects.For(block->PredecessorAt(0), block).current_effect; const BlockEffectControlData& data =
for (size_t i = 1; i < block->PredecessorCount(); ++i) { block_effects.For(block->PredecessorAt(i), block);
if (block_effects.For(block->PredecessorAt(i), block) if (!effect) effect = data.current_effect;
.current_effect != effect) { if (data.current_effect != effect) {
effect = nullptr; effect = nullptr;
break; break;
} }
...@@ -399,7 +456,7 @@ void EffectControlLinearizer::Run() { ...@@ -399,7 +456,7 @@ void EffectControlLinearizer::Run() {
if (control->opcode() == IrOpcode::kLoop) { if (control->opcode() == IrOpcode::kLoop) {
pending_effect_phis.push_back(PendingEffectPhi(effect, block)); pending_effect_phis.push_back(PendingEffectPhi(effect, block));
} else { } else {
UpdateEffectPhi(effect, block, &block_effects); UpdateEffectPhi(effect, block, &block_effects, jsgraph());
} }
} else if (control->opcode() == IrOpcode::kIfException) { } else if (control->opcode() == IrOpcode::kIfException) {
// The IfException is connected into the effect chain, so we need // The IfException is connected into the effect chain, so we need
...@@ -476,14 +533,14 @@ void EffectControlLinearizer::Run() { ...@@ -476,14 +533,14 @@ void EffectControlLinearizer::Run() {
} }
} }
for (BasicBlock* pending_block_control : pending_block_controls) {
UpdateBlockControl(pending_block_control, &block_effects);
}
// Update the incoming edges of the effect phis that could not be processed // Update the incoming edges of the effect phis that could not be processed
// during the first pass (because they could have incoming back edges). // during the first pass (because they could have incoming back edges).
for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) { for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) {
UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block,
&block_effects); &block_effects, jsgraph());
}
for (BasicBlock* pending_block_control : pending_block_controls) {
UpdateBlockControl(pending_block_control, &block_effects);
} }
} }
...@@ -569,6 +626,13 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state, ...@@ -569,6 +626,13 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state,
if (node->op()->ControlOutputCount() > 0) { if (node->op()->ControlOutputCount() > 0) {
*control = node; *control = node;
} }
// Break the effect chain on {Unreachable} and reconnect to the graph end.
// Mark the following code for deletion by connecting to the {Dead} node.
if (node->opcode() == IrOpcode::kUnreachable) {
ConnectUnreachableToEnd(*effect, *control, jsgraph());
*effect = *control = jsgraph()->Dead();
}
} }
bool EffectControlLinearizer::TryWireInStateEffect(Node* node, bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
......
...@@ -1120,6 +1120,9 @@ void InstructionSelector::VisitNode(Node* node) { ...@@ -1120,6 +1120,9 @@ void InstructionSelector::VisitNode(Node* node) {
case IrOpcode::kDebugBreak: case IrOpcode::kDebugBreak:
VisitDebugBreak(node); VisitDebugBreak(node);
return; return;
case IrOpcode::kUnreachable:
VisitUnreachable(node);
return;
case IrOpcode::kComment: case IrOpcode::kComment:
VisitComment(node); VisitComment(node);
return; return;
...@@ -2765,6 +2768,11 @@ void InstructionSelector::VisitDebugBreak(Node* node) { ...@@ -2765,6 +2768,11 @@ void InstructionSelector::VisitDebugBreak(Node* node) {
Emit(kArchDebugBreak, g.NoOutput()); Emit(kArchDebugBreak, g.NoOutput());
} }
void InstructionSelector::VisitUnreachable(Node* node) {
OperandGenerator g(this);
Emit(kArchDebugBreak, g.NoOutput());
}
void InstructionSelector::VisitComment(Node* node) { void InstructionSelector::VisitComment(Node* node) {
OperandGenerator g(this); OperandGenerator g(this);
InstructionOperand operand(g.UseImmediate(node)); InstructionOperand operand(g.UseImmediate(node));
......
...@@ -348,6 +348,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final { ...@@ -348,6 +348,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void VisitReturn(Node* ret); void VisitReturn(Node* ret);
void VisitThrow(Node* node); void VisitThrow(Node* node);
void VisitRetain(Node* node); void VisitRetain(Node* node);
void VisitUnreachable(Node* node);
void EmitPrepareArguments(ZoneVector<compiler::PushParameter>* arguments, void EmitPrepareArguments(ZoneVector<compiler::PushParameter>* arguments,
const CallDescriptor* descriptor, Node* node); const CallDescriptor* descriptor, Node* node);
......
...@@ -305,6 +305,9 @@ Node* JSGraph::Dead() { ...@@ -305,6 +305,9 @@ Node* JSGraph::Dead() {
return CACHED(kDead, graph()->NewNode(common()->Dead())); return CACHED(kDead, graph()->NewNode(common()->Dead()));
} }
Node* JSGraph::DeadValue() {
return CACHED(kDeadValue, graph()->NewNode(common()->DeadValue()));
}
void JSGraph::GetCachedNodes(NodeVector* nodes) { void JSGraph::GetCachedNodes(NodeVector* nodes) {
cache_.GetCachedNodes(nodes); cache_.GetCachedNodes(nodes);
......
...@@ -155,6 +155,9 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -155,6 +155,9 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
// Create a control node that serves as dependency for dead nodes. // Create a control node that serves as dependency for dead nodes.
Node* Dead(); Node* Dead();
// Sentinel for a value resulting from unreachable computations.
Node* DeadValue();
CommonOperatorBuilder* common() const { return common_; } CommonOperatorBuilder* common() const { return common_; }
JSOperatorBuilder* javascript() const { return javascript_; } JSOperatorBuilder* javascript() const { return javascript_; }
SimplifiedOperatorBuilder* simplified() const { return simplified_; } SimplifiedOperatorBuilder* simplified() const { return simplified_; }
...@@ -196,6 +199,7 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -196,6 +199,7 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
kEmptyStateValues, kEmptyStateValues,
kSingleDeadTypedStateValues, kSingleDeadTypedStateValues,
kDead, kDead,
kDeadValue,
kNumCachedNodes // Must remain last. kNumCachedNodes // Must remain last.
}; };
......
...@@ -104,6 +104,7 @@ void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state) { ...@@ -104,6 +104,7 @@ void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state) {
case IrOpcode::kRetain: case IrOpcode::kRetain:
case IrOpcode::kUnsafePointerAdd: case IrOpcode::kUnsafePointerAdd:
case IrOpcode::kDebugBreak: case IrOpcode::kDebugBreak:
case IrOpcode::kUnreachable:
return VisitOtherEffect(node, state); return VisitOtherEffect(node, state);
default: default:
break; break;
......
...@@ -79,6 +79,8 @@ ...@@ -79,6 +79,8 @@
#define COMMON_OP_LIST(V) \ #define COMMON_OP_LIST(V) \
CONSTANT_OP_LIST(V) \ CONSTANT_OP_LIST(V) \
INNER_OP_LIST(V) \ INNER_OP_LIST(V) \
V(Unreachable) \
V(DeadValue) \
V(Dead) V(Dead)
// Opcodes for JavaScript operators. // Opcodes for JavaScript operators.
......
...@@ -947,7 +947,7 @@ PipelineWasmCompilationJob::ExecuteJobImpl() { ...@@ -947,7 +947,7 @@ PipelineWasmCompilationJob::ExecuteJobImpl() {
PipelineRunScope scope(data, "Wasm optimization"); PipelineRunScope scope(data, "Wasm optimization");
JSGraphReducer graph_reducer(data->jsgraph(), scope.zone()); JSGraphReducer graph_reducer(data->jsgraph(), scope.zone());
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common()); data->common(), scope.zone());
ValueNumberingReducer value_numbering(scope.zone(), data->graph()->zone()); ValueNumberingReducer value_numbering(scope.zone(), data->graph()->zone());
MachineOperatorReducer machine_reducer(data->jsgraph(), asmjs_origin_); MachineOperatorReducer machine_reducer(data->jsgraph(), asmjs_origin_);
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(), CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
...@@ -1091,7 +1091,7 @@ struct InliningPhase { ...@@ -1091,7 +1091,7 @@ struct InliningPhase {
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone); JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common()); data->common(), temp_zone);
CheckpointElimination checkpoint_elimination(&graph_reducer); CheckpointElimination checkpoint_elimination(&graph_reducer);
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(), CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
data->common(), data->machine()); data->common(), data->machine());
...@@ -1185,7 +1185,7 @@ struct TypedLoweringPhase { ...@@ -1185,7 +1185,7 @@ struct TypedLoweringPhase {
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone); JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common()); data->common(), temp_zone);
JSBuiltinReducer builtin_reducer( JSBuiltinReducer builtin_reducer(
&graph_reducer, data->jsgraph(), &graph_reducer, data->jsgraph(),
data->info()->dependencies(), data->native_context()); data->info()->dependencies(), data->native_context());
...@@ -1298,7 +1298,7 @@ struct EarlyOptimizationPhase { ...@@ -1298,7 +1298,7 @@ struct EarlyOptimizationPhase {
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone); JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common()); data->common(), temp_zone);
SimplifiedOperatorReducer simple_reducer(&graph_reducer, data->jsgraph()); SimplifiedOperatorReducer simple_reducer(&graph_reducer, data->jsgraph());
RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone); RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone);
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone()); ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
...@@ -1329,50 +1329,48 @@ struct EffectControlLinearizationPhase { ...@@ -1329,50 +1329,48 @@ struct EffectControlLinearizationPhase {
static const char* phase_name() { return "effect linearization"; } static const char* phase_name() { return "effect linearization"; }
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
// The scheduler requires the graphs to be trimmed, so trim now. {
// TODO(jarin) Remove the trimming once the scheduler can handle untrimmed // The scheduler requires the graphs to be trimmed, so trim now.
// graphs. // TODO(jarin) Remove the trimming once the scheduler can handle untrimmed
GraphTrimmer trimmer(temp_zone, data->graph()); // graphs.
NodeVector roots(temp_zone); GraphTrimmer trimmer(temp_zone, data->graph());
data->jsgraph()->GetCachedNodes(&roots); NodeVector roots(temp_zone);
trimmer.TrimGraph(roots.begin(), roots.end()); data->jsgraph()->GetCachedNodes(&roots);
trimmer.TrimGraph(roots.begin(), roots.end());
// Schedule the graph without node splitting so that we can
// fix the effect and control flow for nodes with low-level side // Schedule the graph without node splitting so that we can
// effects (such as changing representation to tagged or // fix the effect and control flow for nodes with low-level side
// 'floating' allocation regions.) // effects (such as changing representation to tagged or
Schedule* schedule = Scheduler::ComputeSchedule(temp_zone, data->graph(), // 'floating' allocation regions.)
Scheduler::kTempSchedule); Schedule* schedule = Scheduler::ComputeSchedule(temp_zone, data->graph(),
if (FLAG_turbo_verify) ScheduleVerifier::Run(schedule); Scheduler::kTempSchedule);
TraceSchedule(data->info(), data->isolate(), schedule); if (FLAG_turbo_verify) ScheduleVerifier::Run(schedule);
TraceSchedule(data->info(), data->isolate(), schedule);
// Post-pass for wiring the control/effects
// - connect allocating representation changes into the control&effect // Post-pass for wiring the control/effects
// chains and lower them, // - connect allocating representation changes into the control&effect
// - get rid of the region markers, // chains and lower them,
// - introduce effect phis and rewire effects to get SSA again. // - get rid of the region markers,
EffectControlLinearizer linearizer(data->jsgraph(), schedule, temp_zone, // - introduce effect phis and rewire effects to get SSA again.
data->source_positions()); EffectControlLinearizer linearizer(data->jsgraph(), schedule, temp_zone,
linearizer.Run(); data->source_positions());
} linearizer.Run();
}; }
{
// The store-store elimination greatly benefits from doing a common operator // The {EffectControlLinearizer} might leave {Dead} nodes behind, so we
// reducer and dead code elimination just before it, to eliminate conditional // run {DeadCodeElimination} to prune these parts of the graph.
// deopts with a constant condition. // Also, the following store-store elimination phase greatly benefits from
// doing a common operator reducer and dead code elimination just before
struct DeadCodeEliminationPhase { // it, to eliminate conditional deopts with a constant condition.
static const char* phase_name() { return "dead code elimination"; } JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
void Run(PipelineData* data, Zone* temp_zone) { data->common(), temp_zone);
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone); CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), data->common(), data->machine());
data->common()); AddReducer(data, &graph_reducer, &dead_code_elimination);
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(), AddReducer(data, &graph_reducer, &common_reducer);
data->common(), data->machine()); graph_reducer.ReduceGraph();
AddReducer(data, &graph_reducer, &dead_code_elimination); }
AddReducer(data, &graph_reducer, &common_reducer);
graph_reducer.ReduceGraph();
} }
}; };
...@@ -1397,7 +1395,7 @@ struct LoadEliminationPhase { ...@@ -1397,7 +1395,7 @@ struct LoadEliminationPhase {
BranchElimination branch_condition_elimination(&graph_reducer, BranchElimination branch_condition_elimination(&graph_reducer,
data->jsgraph(), temp_zone); data->jsgraph(), temp_zone);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common()); data->common(), temp_zone);
RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone); RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone);
LoadElimination load_elimination(&graph_reducer, data->jsgraph(), LoadElimination load_elimination(&graph_reducer, data->jsgraph(),
temp_zone); temp_zone);
...@@ -1440,7 +1438,7 @@ struct LateOptimizationPhase { ...@@ -1440,7 +1438,7 @@ struct LateOptimizationPhase {
BranchElimination branch_condition_elimination(&graph_reducer, BranchElimination branch_condition_elimination(&graph_reducer,
data->jsgraph(), temp_zone); data->jsgraph(), temp_zone);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common()); data->common(), temp_zone);
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone()); ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
MachineOperatorReducer machine_reducer(data->jsgraph()); MachineOperatorReducer machine_reducer(data->jsgraph());
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(), CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
...@@ -1895,9 +1893,6 @@ bool PipelineImpl::OptimizeGraph(Linkage* linkage) { ...@@ -1895,9 +1893,6 @@ bool PipelineImpl::OptimizeGraph(Linkage* linkage) {
Run<EffectControlLinearizationPhase>(); Run<EffectControlLinearizationPhase>();
RunPrintAndVerify("Effect and control linearized", true); RunPrintAndVerify("Effect and control linearized", true);
Run<DeadCodeEliminationPhase>();
RunPrintAndVerify("Dead code elimination", true);
if (FLAG_turbo_store_elimination) { if (FLAG_turbo_store_elimination) {
Run<StoreStoreEliminationPhase>(); Run<StoreStoreEliminationPhase>();
RunPrintAndVerify("Store-store elimination", true); RunPrintAndVerify("Store-store elimination", true);
......
...@@ -216,8 +216,7 @@ Node* RepresentationChanger::GetTaggedSignedRepresentationFor( ...@@ -216,8 +216,7 @@ Node* RepresentationChanger::GetTaggedSignedRepresentationFor(
const Operator* op; const Operator* op;
if (output_type->Is(Type::None())) { if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime. // This is an impossible value; it should not be used at runtime.
// We just provide a dummy value here. return jsgraph()->DeadValue();
return jsgraph()->Constant(0);
} else if (IsWord(output_rep)) { } else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed31())) { if (output_type->Is(Type::Signed31())) {
op = simplified()->ChangeInt31ToTaggedSigned(); op = simplified()->ChangeInt31ToTaggedSigned();
...@@ -335,8 +334,7 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor( ...@@ -335,8 +334,7 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
Operator const* op; Operator const* op;
if (output_type->Is(Type::None())) { if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime. // This is an impossible value; it should not be used at runtime.
// We just provide a dummy value here. return jsgraph()->DeadValue();
return jsgraph()->TheHoleConstant();
} else if (output_rep == MachineRepresentation::kBit) { } else if (output_rep == MachineRepresentation::kBit) {
if (output_type->Is(Type::Boolean())) { if (output_type->Is(Type::Boolean())) {
op = simplified()->ChangeBitToTagged(); op = simplified()->ChangeBitToTagged();
...@@ -413,8 +411,7 @@ Node* RepresentationChanger::GetTaggedRepresentationFor( ...@@ -413,8 +411,7 @@ Node* RepresentationChanger::GetTaggedRepresentationFor(
const Operator* op; const Operator* op;
if (output_type->Is(Type::None())) { if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime. // This is an impossible value; it should not be used at runtime.
// We just provide a dummy value here. return jsgraph()->DeadValue();
return jsgraph()->TheHoleConstant();
} else if (output_rep == MachineRepresentation::kBit) { } else if (output_rep == MachineRepresentation::kBit) {
if (output_type->Is(Type::Boolean())) { if (output_type->Is(Type::Boolean())) {
op = simplified()->ChangeBitToTagged(); op = simplified()->ChangeBitToTagged();
...@@ -492,8 +489,7 @@ Node* RepresentationChanger::GetFloat32RepresentationFor( ...@@ -492,8 +489,7 @@ Node* RepresentationChanger::GetFloat32RepresentationFor(
const Operator* op = nullptr; const Operator* op = nullptr;
if (output_type->Is(Type::None())) { if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime. // This is an impossible value; it should not be used at runtime.
// We just provide a dummy value here. return jsgraph()->DeadValue();
return jsgraph()->Float32Constant(0.0f);
} else if (IsWord(output_rep)) { } else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) { if (output_type->Is(Type::Signed32())) {
// int32 -> float64 -> float32 // int32 -> float64 -> float32
...@@ -553,8 +549,7 @@ Node* RepresentationChanger::GetFloat64RepresentationFor( ...@@ -553,8 +549,7 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
const Operator* op = nullptr; const Operator* op = nullptr;
if (output_type->Is(Type::None())) { if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime. // This is an impossible value; it should not be used at runtime.
// We just provide a dummy value here. return jsgraph()->DeadValue();
return jsgraph()->Float64Constant(0.0);
} else if (IsWord(output_rep)) { } else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) { if (output_type->Is(Type::Signed32())) {
op = machine()->ChangeInt32ToFloat64(); op = machine()->ChangeInt32ToFloat64();
...@@ -631,8 +626,7 @@ Node* RepresentationChanger::GetWord32RepresentationFor( ...@@ -631,8 +626,7 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
const Operator* op = nullptr; const Operator* op = nullptr;
if (output_type->Is(Type::None())) { if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime. // This is an impossible value; it should not be used at runtime.
// We just provide a dummy value here. return jsgraph()->DeadValue();
return jsgraph()->Int32Constant(0);
} else if (output_rep == MachineRepresentation::kBit) { } else if (output_rep == MachineRepresentation::kBit) {
return node; // Sloppy comparison -> word32 return node; // Sloppy comparison -> word32
} else if (output_rep == MachineRepresentation::kFloat64) { } else if (output_rep == MachineRepresentation::kFloat64) {
...@@ -768,8 +762,7 @@ Node* RepresentationChanger::GetBitRepresentationFor( ...@@ -768,8 +762,7 @@ Node* RepresentationChanger::GetBitRepresentationFor(
const Operator* op; const Operator* op;
if (output_type->Is(Type::None())) { if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime. // This is an impossible value; it should not be used at runtime.
// We just provide a dummy value here. return jsgraph()->DeadValue();
return jsgraph()->Int32Constant(0);
} else if (output_rep == MachineRepresentation::kTagged || } else if (output_rep == MachineRepresentation::kTagged ||
output_rep == MachineRepresentation::kTaggedPointer) { output_rep == MachineRepresentation::kTaggedPointer) {
if (output_type->Is(Type::BooleanOrNullOrUndefined())) { if (output_type->Is(Type::BooleanOrNullOrUndefined())) {
...@@ -814,8 +807,7 @@ Node* RepresentationChanger::GetWord64RepresentationFor( ...@@ -814,8 +807,7 @@ Node* RepresentationChanger::GetWord64RepresentationFor(
Node* node, MachineRepresentation output_rep, Type* output_type) { Node* node, MachineRepresentation output_rep, Type* output_type) {
if (output_type->Is(Type::None())) { if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime. // This is an impossible value; it should not be used at runtime.
// We just provide a dummy value here. return jsgraph()->DeadValue();
return jsgraph()->Int64Constant(0);
} else if (output_rep == MachineRepresentation::kBit) { } else if (output_rep == MachineRepresentation::kBit) {
return node; // Sloppy comparison -> word64 return node; // Sloppy comparison -> word64
} }
......
...@@ -3033,6 +3033,7 @@ class RepresentationSelector { ...@@ -3033,6 +3033,7 @@ class RepresentationSelector {
case IrOpcode::kOsrValue: case IrOpcode::kOsrValue:
case IrOpcode::kArgumentsElementsState: case IrOpcode::kArgumentsElementsState:
case IrOpcode::kArgumentsLengthState: case IrOpcode::kArgumentsLengthState:
case IrOpcode::kUnreachable:
case IrOpcode::kRuntimeAbort: case IrOpcode::kRuntimeAbort:
// All JavaScript operators except JSToNumber have uniform handling. // All JavaScript operators except JSToNumber have uniform handling.
#define OPCODE_CASE(name) case IrOpcode::k##name: #define OPCODE_CASE(name) case IrOpcode::k##name:
...@@ -3049,7 +3050,8 @@ class RepresentationSelector { ...@@ -3049,7 +3050,8 @@ class RepresentationSelector {
VisitInputs(node); VisitInputs(node);
// Assume the output is tagged. // Assume the output is tagged.
return SetOutput(node, MachineRepresentation::kTagged); return SetOutput(node, MachineRepresentation::kTagged);
case IrOpcode::kDeadValue:
return SetOutput(node, MachineRepresentation::kNone);
default: default:
V8_Fatal( V8_Fatal(
__FILE__, __LINE__, __FILE__, __LINE__,
......
...@@ -903,6 +903,10 @@ Type* Typer::Visitor::TypeTypeGuard(Node* node) { ...@@ -903,6 +903,10 @@ Type* Typer::Visitor::TypeTypeGuard(Node* node) {
Type* Typer::Visitor::TypeDead(Node* node) { return Type::None(); } Type* Typer::Visitor::TypeDead(Node* node) { return Type::None(); }
Type* Typer::Visitor::TypeDeadValue(Node* node) { return Type::None(); }
Type* Typer::Visitor::TypeUnreachable(Node* node) { UNREACHABLE(); }
// JS comparison operators. // JS comparison operators.
......
...@@ -236,6 +236,11 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -236,6 +236,11 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kDead: case IrOpcode::kDead:
// Dead is never connected to the graph. // Dead is never connected to the graph.
UNREACHABLE(); UNREACHABLE();
case IrOpcode::kDeadValue:
CheckTypeIs(node, Type::None());
break;
case IrOpcode::kUnreachable:
CheckNotTyped(node);
break; break;
case IrOpcode::kBranch: { case IrOpcode::kBranch: {
// Branch uses are IfTrue and IfFalse. // Branch uses are IfTrue and IfFalse.
...@@ -1878,7 +1883,8 @@ void Verifier::VerifyNode(Node* node) { ...@@ -1878,7 +1883,8 @@ void Verifier::VerifyNode(Node* node) {
Node* input = NodeProperties::GetFrameStateInput(node); Node* input = NodeProperties::GetFrameStateInput(node);
DCHECK(input->opcode() == IrOpcode::kFrameState || DCHECK(input->opcode() == IrOpcode::kFrameState ||
input->opcode() == IrOpcode::kStart || input->opcode() == IrOpcode::kStart ||
input->opcode() == IrOpcode::kDead); input->opcode() == IrOpcode::kDead ||
input->opcode() == IrOpcode::kDeadValue);
} }
// Effect inputs should be effect-producing nodes (or sentinels). // Effect inputs should be effect-producing nodes (or sentinels).
for (int i = 0; i < node->op()->EffectInputCount(); i++) { for (int i = 0; i < node->op()->EffectInputCount(); i++) {
...@@ -1903,7 +1909,9 @@ void Verifier::VerifyEdgeInputReplacement(const Edge& edge, ...@@ -1903,7 +1909,9 @@ void Verifier::VerifyEdgeInputReplacement(const Edge& edge,
DCHECK(!NodeProperties::IsEffectEdge(edge) || DCHECK(!NodeProperties::IsEffectEdge(edge) ||
replacement->op()->EffectOutputCount() > 0); replacement->op()->EffectOutputCount() > 0);
DCHECK(!NodeProperties::IsFrameStateEdge(edge) || DCHECK(!NodeProperties::IsFrameStateEdge(edge) ||
replacement->opcode() == IrOpcode::kFrameState); replacement->opcode() == IrOpcode::kFrameState ||
replacement->opcode() == IrOpcode::kDead ||
replacement->opcode() == IrOpcode::kDeadValue);
} }
#endif // DEBUG #endif // DEBUG
......
// Copyright 2017 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.
// Flags: --allow-natives-syntax
function f() {
for (var x = 10; x > 5; x -= 16) {}
}
f();
f();
%OptimizeFunctionOnNextCall(f);
f();
// Copyright 2017 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.
// Flags: --allow-natives-syntax
'use strict';
var a = { x:0 };
var b = {};
Object.defineProperty(b, "x", {get: function () {}});
function f(o) {
return 5 + o.x++;
}
try {
f(a);
f(b);
} catch (e) {}
%OptimizeFunctionOnNextCall(f);
f(a);
...@@ -24,7 +24,7 @@ class DeadCodeEliminationTest : public GraphTest { ...@@ -24,7 +24,7 @@ class DeadCodeEliminationTest : public GraphTest {
protected: protected:
Reduction Reduce(AdvancedReducer::Editor* editor, Node* node) { Reduction Reduce(AdvancedReducer::Editor* editor, Node* node) {
DeadCodeElimination reducer(editor, graph(), common()); DeadCodeElimination reducer(editor, graph(), common(), zone());
return reducer.Reduce(node); return reducer.Reduce(node);
} }
......
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