Commit ac0661b3 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

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: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49188}
parent 6bb1d47e
...@@ -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)->IsInhabited();
}
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)->IsInhabited()) {
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;
...@@ -2764,6 +2767,11 @@ void InstructionSelector::VisitDebugBreak(Node* node) { ...@@ -2764,6 +2767,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.
}; };
......
...@@ -100,6 +100,7 @@ void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state) { ...@@ -100,6 +100,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(), schedule); if (FLAG_turbo_verify) ScheduleVerifier::Run(schedule);
TraceSchedule(data->info(), 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);
......
...@@ -217,8 +217,7 @@ Node* RepresentationChanger::GetTaggedSignedRepresentationFor( ...@@ -217,8 +217,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();
...@@ -336,8 +335,7 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor( ...@@ -336,8 +335,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();
...@@ -414,8 +412,7 @@ Node* RepresentationChanger::GetTaggedRepresentationFor( ...@@ -414,8 +412,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();
...@@ -493,8 +490,7 @@ Node* RepresentationChanger::GetFloat32RepresentationFor( ...@@ -493,8 +490,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
...@@ -554,8 +550,7 @@ Node* RepresentationChanger::GetFloat64RepresentationFor( ...@@ -554,8 +550,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();
...@@ -632,8 +627,7 @@ Node* RepresentationChanger::GetWord32RepresentationFor( ...@@ -632,8 +627,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) {
...@@ -769,8 +763,7 @@ Node* RepresentationChanger::GetBitRepresentationFor( ...@@ -769,8 +763,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())) {
...@@ -815,8 +808,7 @@ Node* RepresentationChanger::GetWord64RepresentationFor( ...@@ -815,8 +808,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
} }
......
...@@ -3027,6 +3027,7 @@ class RepresentationSelector { ...@@ -3027,6 +3027,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:
...@@ -3043,7 +3044,8 @@ class RepresentationSelector { ...@@ -3043,7 +3044,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__,
......
...@@ -895,6 +895,10 @@ Type* Typer::Visitor::TypeTypeGuard(Node* node) { ...@@ -895,6 +895,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.
...@@ -1859,7 +1864,8 @@ void Verifier::VerifyNode(Node* node) { ...@@ -1859,7 +1864,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++) {
...@@ -1884,7 +1890,9 @@ void Verifier::VerifyEdgeInputReplacement(const Edge& edge, ...@@ -1884,7 +1890,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