Revert "Reland^3 "[turbofan] eagerly prune None types and deadness from the graph""
This reverts commit4cf476458f
. Reason for revert: Broken effect chains detected by Clusterfuzz. Playing it safe for the 63 branch. Original change's description: > Reland^3 "[turbofan] eagerly prune None types and deadness from the graph" > > This fixes the issues > https://bugs.chromium.org/p/chromium/issues/detail?id=772873 > and https://bugs.chromium.org/p/chromium/issues/detail?id=772872. > > One problem was that mutating an effect node into Unreachable confused > the LoadElimination sidetables, so I just always create a new node now. > > The other problem was that UpdateBlockControl() was executed after > UpdateEffectPhi() in the lazy case. This reverted the update to the Merge input. > So now I make sure that UpdateEffectPhi() is always executed last. > > This is a reland of6ddb5e7da7
> Original change's description: > > Reland^2 "[turbofan] eagerly prune None types and deadness from the graph" > > > > Now, the EffectControlLinearizer connects all occurrences of Unreachable to the > > graph end. This fixes issues with later phases running DeadCodeElimination and > > introducing new DeadValue nodes when processing uses of Unreachable. > > > > This is a reland of3c4bc27f13
> > Original change's description: > > > Reland "[turbofan] eagerly prune None types and deadness from the graph" > > > > > > This is a reland ofe1cdda2512
> > > Original change's description: > > > > [turbofan] eagerly prune None types and deadness from the graph > > > > > > > > In addition to using the {Dead} node to prune dead control nodes and nodes that > > > > depend on them, we introduce a {DeadValue} node representing an impossible value > > > > that can occur at any position in the graph. The extended {DeadCodeElimination} > > > > prunes {DeadValue} and its uses, inserting a crashing {Unreachable} node into > > > > the effect chain when possible. The remaining uses of {DeadValue} are handled > > > > in {EffectControlLinearizer}, where we always have access to the effect chain. > > > > In addition to explicitly introduced {DeadValue} nodes, we consider any value use > > > > of a node with type {None} as dead. > > > > > > > > Bug: chromium:741225 > > > > Change-Id: Icc4b636d1d018c452ba1a2fa7cd3e00e522f1655 > > > > Reviewed-on: https://chromium-review.googlesource.com/641250 > > > > Commit-Queue: Tobias Tebbi <tebbi@chromium.org> > > > > Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> > > > > Cr-Commit-Position: refs/heads/master@{#48208} > > > > > > Bug: chromium:741225 > > > Change-Id: I21316913dae02864f7a6d7c9269405a79f054138 > > > Reviewed-on: https://chromium-review.googlesource.com/692034 > > > Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> > > > Commit-Queue: Tobias Tebbi <tebbi@chromium.org> > > > Cr-Commit-Position: refs/heads/master@{#48232} > > > > Bug: chromium:741225 > > Change-Id: I5702ec34856c075717162153adc765774453c45f > > Reviewed-on: https://chromium-review.googlesource.com/702264 > > Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> > > Commit-Queue: Tobias Tebbi <tebbi@chromium.org> > > Cr-Commit-Position: refs/heads/master@{#48366} > > Bug: chromium:741225 > Change-Id: I4054a694d2521c2e1f0c4a3ad0f3cf100b5c536f > Reviewed-on: https://chromium-review.googlesource.com/709214 > Commit-Queue: Tobias Tebbi <tebbi@chromium.org> > Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> > Cr-Commit-Position: refs/heads/master@{#48469} TBR=jarin@chromium.org,tebbi@chromium.org Change-Id: Icf6a6af4feaafd4bde28cb7b996735ff91bb3810 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: chromium:741225 Reviewed-on: https://chromium-review.googlesource.com/715096 Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#48482}
This commit is contained in:
parent
840e92c5dd
commit
e29fd74c08
@ -18,7 +18,9 @@ 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->Dead()) {}
|
dead_(js_graph->graph()->NewNode(js_graph->common()->Dead())) {
|
||||||
|
NodeProperties::SetType(dead_, Type::None());
|
||||||
|
}
|
||||||
|
|
||||||
BranchElimination::~BranchElimination() {}
|
BranchElimination::~BranchElimination() {}
|
||||||
|
|
||||||
|
@ -348,8 +348,6 @@ 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) \
|
||||||
|
@ -348,8 +348,6 @@ 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,7 +6,6 @@
|
|||||||
|
|
||||||
#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"
|
||||||
|
|
||||||
@ -19,32 +18,10 @@ DeadCodeElimination::DeadCodeElimination(Editor* editor, Graph* graph,
|
|||||||
: 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())) {
|
|
||||||
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:
|
||||||
@ -163,89 +140,13 @@ Reduction DeadCodeElimination::RemoveLoopExit(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Reduction DeadCodeElimination::ReduceNode(Node* node) {
|
Reduction DeadCodeElimination::ReduceNode(Node* node) {
|
||||||
int const effect_input_count = node->op()->EffectInputCount();
|
|
||||||
int const control_input_count = node->op()->ControlInputCount();
|
|
||||||
if (control_input_count == 0 && effect_input_count == 0) {
|
|
||||||
return ReducePureNode(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (control_input_count == 1) {
|
|
||||||
// If {node} has exactly one control input and this is {Dead},
|
// If {node} has exactly one control input and this is {Dead},
|
||||||
// replace {node} with {Dead}.
|
// replace {node} with {Dead}.
|
||||||
|
int const control_input_count = node->op()->ControlInputCount();
|
||||||
|
if (control_input_count == 0) return NoChange();
|
||||||
|
DCHECK_EQ(1, control_input_count);
|
||||||
Node* control = NodeProperties::GetControlInput(node);
|
Node* control = NodeProperties::GetControlInput(node);
|
||||||
if (control->opcode() == IrOpcode::kDead) return Replace(control);
|
if (control->opcode() == IrOpcode::kDead) return Replace(control);
|
||||||
|
|
||||||
if (node->opcode() == IrOpcode::kPhi &&
|
|
||||||
(PhiRepresentationOf(node->op()) == MachineRepresentation::kNone ||
|
|
||||||
!NodeProperties::GetTypeOrAny(node)->IsInhabited())) {
|
|
||||||
return Replace(dead_value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effect_input_count > 0 && !NodeProperties::IsPhi(node))
|
|
||||||
return ReduceEffectNode(node);
|
|
||||||
|
|
||||||
return NoChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
Reduction DeadCodeElimination::ReducePureNode(Node* node) {
|
|
||||||
DCHECK_EQ(0, node->op()->EffectInputCount());
|
|
||||||
DCHECK_EQ(0, node->op()->ControlInputCount());
|
|
||||||
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::ReduceEffectNode(Node* node) {
|
|
||||||
if (IrOpcode::IsGraphTerminator(node->opcode())) {
|
|
||||||
return ReduceGraphTerminator(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
DCHECK_EQ(1, node->op()->EffectInputCount());
|
|
||||||
Node* effect = NodeProperties::GetEffectInput(node, 0);
|
|
||||||
if (effect->opcode() == IrOpcode::kDead) {
|
|
||||||
return Replace(effect);
|
|
||||||
}
|
|
||||||
if (HasDeadInput(node) && node->opcode() != IrOpcode::kIfException) {
|
|
||||||
if (effect->opcode() == IrOpcode::kUnreachable) {
|
|
||||||
RelaxEffectsAndControls(node);
|
|
||||||
return Replace(dead_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->opcode() == IrOpcode::kUnreachable) return NoChange();
|
|
||||||
|
|
||||||
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::ReduceGraphTerminator(Node* node) {
|
|
||||||
DCHECK(IrOpcode::IsGraphTerminator(node->opcode()));
|
|
||||||
if (node->opcode() == IrOpcode::kThrow) return NoChange();
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,15 +16,11 @@ namespace compiler {
|
|||||||
// Forward declarations.
|
// Forward declarations.
|
||||||
class CommonOperatorBuilder;
|
class CommonOperatorBuilder;
|
||||||
|
|
||||||
// Propagates {Dead} control and {DeadValue} values through the graph and
|
|
||||||
// thereby removes dead code. When {DeadValue} hits the effect chain, a crashing
|
// Propagates {Dead} control through the graph and thereby removes dead code.
|
||||||
// {Unreachable} node is inserted and the rest of the effect chain is collapsed.
|
// Note that this does not include trimming dead uses from the graph, and it
|
||||||
// We detect dead values based on types, pruning uses of DeadValue except for
|
// also does not include detecting dead code by any other means than seeing a
|
||||||
// uses by phi and control nodes without effect input. These remaining uses of
|
// {Dead} control input; that is left to other reducers.
|
||||||
// {DeadValue} are eliminated in the {EffectControlLinearizer}, when the effect
|
|
||||||
// chain is readily available to insert an {Unreachable} and connect it to the
|
|
||||||
// {End} node directly. In contrast to this, {Dead} must not 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:
|
||||||
@ -41,9 +37,6 @@ 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 ReducePureNode(Node* node);
|
|
||||||
Reduction ReduceEffectNode(Node* node);
|
|
||||||
Reduction ReduceGraphTerminator(Node* node);
|
|
||||||
|
|
||||||
Reduction RemoveLoopExit(Node* node);
|
Reduction RemoveLoopExit(Node* node);
|
||||||
|
|
||||||
@ -52,12 +45,10 @@ class V8_EXPORT_PRIVATE DeadCodeElimination final
|
|||||||
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_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(DeadCodeElimination);
|
DISALLOW_COPY_AND_ASSIGN(DeadCodeElimination);
|
||||||
};
|
};
|
||||||
|
@ -46,7 +46,6 @@ struct BlockEffectControlData {
|
|||||||
Node* current_effect = nullptr; // New effect.
|
Node* current_effect = nullptr; // New effect.
|
||||||
Node* current_control = nullptr; // New control.
|
Node* current_control = nullptr; // New control.
|
||||||
Node* current_frame_state = nullptr; // New frame state.
|
Node* current_frame_state = nullptr; // New frame state.
|
||||||
bool dead = false; // This control edge can never be taken.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlockEffectControlMap {
|
class BlockEffectControlMap {
|
||||||
@ -77,25 +76,8 @@ struct PendingEffectPhi {
|
|||||||
: effect_phi(effect_phi), block(block) {}
|
: effect_phi(effect_phi), block(block) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
void ConnectUnreachableToEnd(Node* effect, Node* control, JSGraph* jsgraph) {
|
void UpdateEffectPhi(Node* node, BasicBlock* block,
|
||||||
Graph* graph = jsgraph->graph();
|
BlockEffectControlMap* block_effects) {
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a value phi has a {DeadValue} input, this function connects the
|
|
||||||
// corresponding control to {End} and replaces is with the {Dead} node. For
|
|
||||||
// this, it is important that UpdateEffectPhiAndReconnectDeadControl() is only
|
|
||||||
// executed after the control inputs and the value phis of the current block
|
|
||||||
// have been processed.
|
|
||||||
void UpdateEffectPhiAndReconnectDeadControl(
|
|
||||||
Node* node, BasicBlock* block, 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());
|
||||||
@ -106,15 +88,8 @@ void UpdateEffectPhiAndReconnectDeadControl(
|
|||||||
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);
|
||||||
Node* effect = block_effect.current_effect;
|
if (input != block_effect.current_effect) {
|
||||||
if (block_effect.dead) {
|
node->ReplaceInput(i, block_effect.current_effect);
|
||||||
ConnectUnreachableToEnd(effect, block_effect.current_control, jsgraph);
|
|
||||||
effect = jsgraph->Dead();
|
|
||||||
Node* merge = NodeProperties::GetControlInput(node);
|
|
||||||
NodeProperties::ReplaceControlInput(merge, jsgraph->Dead(), i);
|
|
||||||
}
|
|
||||||
if (input != effect) {
|
|
||||||
node->ReplaceInput(i, effect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,7 +303,6 @@ void TryCloneBranch(Node* node, BasicBlock* block, Zone* temp_zone,
|
|||||||
cond->Kill();
|
cond->Kill();
|
||||||
merge->Kill();
|
merge->Kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void EffectControlLinearizer::Run() {
|
void EffectControlLinearizer::Run() {
|
||||||
@ -356,30 +330,29 @@ 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_phi = nullptr;
|
Node* effect = 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_phi);
|
DCHECK_NULL(effect);
|
||||||
// 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_phi = node;
|
effect = 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) {
|
||||||
DCHECK_EQ(predecessor_count, node->op()->ValueInputCount());
|
// Just skip phis.
|
||||||
// If a value input of a phi node is {DeadValue}, then the
|
|
||||||
// corresponding control edge is dead.
|
|
||||||
for (int i = 0; i < predecessor_count; ++i) {
|
|
||||||
if (NodeProperties::GetValueInput(node, i)->opcode() ==
|
|
||||||
IrOpcode::kDeadValue) {
|
|
||||||
BlockEffectControlData* data =
|
|
||||||
&block_effects.For(block->predecessors()[i], block);
|
|
||||||
data->dead = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (node->opcode() == IrOpcode::kTerminate) {
|
} else if (node->opcode() == IrOpcode::kTerminate) {
|
||||||
DCHECK_NULL(terminate);
|
DCHECK_NULL(terminate);
|
||||||
terminate = node;
|
terminate = node;
|
||||||
@ -388,29 +361,9 @@ 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 {
|
|
||||||
UpdateEffectPhiAndReconnectDeadControl(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);
|
||||||
@ -422,14 +375,12 @@ void EffectControlLinearizer::Run() {
|
|||||||
effect = nullptr;
|
effect = nullptr;
|
||||||
} 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. If there are dead incoming control paths, we always
|
// current effect.
|
||||||
// insert an effect phi to break the effect chain there later in
|
effect =
|
||||||
// UpdateEffectPhiAndReconnectDeadControl().
|
block_effects.For(block->PredecessorAt(0), block).current_effect;
|
||||||
for (size_t i = 0; i < block->PredecessorCount(); ++i) {
|
for (size_t i = 1; i < block->PredecessorCount(); ++i) {
|
||||||
const BlockEffectControlData& data =
|
if (block_effects.For(block->PredecessorAt(i), block)
|
||||||
block_effects.For(block->PredecessorAt(i), block);
|
.current_effect != effect) {
|
||||||
if (!effect) effect = data.current_effect;
|
|
||||||
if (data.current_effect != effect || data.dead) {
|
|
||||||
effect = nullptr;
|
effect = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -448,8 +399,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 {
|
||||||
UpdateEffectPhiAndReconnectDeadControl(effect, block,
|
UpdateEffectPhi(effect, block, &block_effects);
|
||||||
&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
|
||||||
@ -526,15 +476,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) {
|
||||||
UpdateEffectPhiAndReconnectDeadControl(pending_effect_phi.effect_phi,
|
UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block,
|
||||||
pending_effect_phi.block,
|
&block_effects);
|
||||||
&block_effects, jsgraph());
|
}
|
||||||
|
for (BasicBlock* pending_block_control : pending_block_controls) {
|
||||||
|
UpdateBlockControl(pending_block_control, &block_effects);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,24 +498,6 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// {Branch} and {Switch} nodes can have a {DeadValue} condition not pruned in
|
|
||||||
// {DeadCodeElimination}. Now we have the effect chain at hand to insert
|
|
||||||
// {Unreachable} and break the current effect/control chain, connecting it to
|
|
||||||
// the graph end.
|
|
||||||
if (((node->opcode() == IrOpcode::kBranch ||
|
|
||||||
node->opcode() == IrOpcode::kSwitch) &&
|
|
||||||
NodeProperties::GetValueInput(node, 0)->opcode() ==
|
|
||||||
IrOpcode::kDeadValue) ||
|
|
||||||
node->opcode() == IrOpcode::kUnreachable) {
|
|
||||||
if (node->opcode() == IrOpcode::kUnreachable) {
|
|
||||||
NodeProperties::ReplaceControlInput(node, *control);
|
|
||||||
*effect = node;
|
|
||||||
}
|
|
||||||
ConnectUnreachableToEnd(*effect, *control, jsgraph());
|
|
||||||
*effect = *control = jsgraph()->Dead();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the node has a visible effect, then there must be a checkpoint in the
|
// If the node has a visible effect, then there must be a checkpoint in the
|
||||||
// effect chain before we are allowed to place another eager deoptimization
|
// effect chain before we are allowed to place another eager deoptimization
|
||||||
// point. We zap the frame state to ensure this invariant is maintained.
|
// point. We zap the frame state to ensure this invariant is maintained.
|
||||||
|
@ -1120,9 +1120,6 @@ 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;
|
||||||
@ -2767,11 +2764,6 @@ 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,7 +348,6 @@ 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,9 +305,6 @@ 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);
|
||||||
|
@ -152,9 +152,6 @@ 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,7 +193,6 @@ 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,7 +100,6 @@ 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,8 +79,6 @@
|
|||||||
#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.
|
||||||
|
@ -1167,7 +1167,6 @@ 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.
|
// The scheduler requires the graphs to be trimmed, so trim now.
|
||||||
// TODO(jarin) Remove the trimming once the scheduler can handle untrimmed
|
// TODO(jarin) Remove the trimming once the scheduler can handle untrimmed
|
||||||
// graphs.
|
// graphs.
|
||||||
@ -1194,12 +1193,16 @@ struct EffectControlLinearizationPhase {
|
|||||||
data->source_positions());
|
data->source_positions());
|
||||||
linearizer.Run();
|
linearizer.Run();
|
||||||
}
|
}
|
||||||
{
|
};
|
||||||
// The {EffectControlLinearizer} might leave {Dead} nodes behind, so we
|
|
||||||
// run {DeadCodeElimination} to prune these parts of the graph.
|
// The store-store elimination greatly benefits from doing a common operator
|
||||||
// Also, the following store-store elimination phase greatly benefits from
|
// reducer and dead code elimination just before it, to eliminate conditional
|
||||||
// doing a common operator reducer and dead code elimination just before
|
// deopts with a constant condition.
|
||||||
// it, to eliminate conditional deopts with a constant condition.
|
|
||||||
|
struct DeadCodeEliminationPhase {
|
||||||
|
static const char* phase_name() { return "dead code elimination"; }
|
||||||
|
|
||||||
|
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());
|
||||||
@ -1209,7 +1212,6 @@ struct EffectControlLinearizationPhase {
|
|||||||
AddReducer(data, &graph_reducer, &common_reducer);
|
AddReducer(data, &graph_reducer, &common_reducer);
|
||||||
graph_reducer.ReduceGraph();
|
graph_reducer.ReduceGraph();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StoreStoreEliminationPhase {
|
struct StoreStoreEliminationPhase {
|
||||||
@ -1718,6 +1720,9 @@ 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,7 +217,8 @@ 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.
|
||||||
return jsgraph()->DeadValue();
|
// We just provide a dummy value here.
|
||||||
|
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,7 +336,8 @@ 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.
|
||||||
return jsgraph()->DeadValue();
|
// We just provide a dummy value here.
|
||||||
|
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();
|
||||||
@ -412,7 +414,8 @@ 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.
|
||||||
return jsgraph()->DeadValue();
|
// We just provide a dummy value here.
|
||||||
|
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();
|
||||||
@ -490,7 +493,8 @@ 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.
|
||||||
return jsgraph()->DeadValue();
|
// We just provide a dummy value here.
|
||||||
|
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
|
||||||
@ -550,7 +554,8 @@ 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.
|
||||||
return jsgraph()->DeadValue();
|
// We just provide a dummy value here.
|
||||||
|
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();
|
||||||
@ -627,7 +632,8 @@ 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.
|
||||||
return jsgraph()->DeadValue();
|
// We just provide a dummy value here.
|
||||||
|
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) {
|
||||||
@ -763,7 +769,8 @@ 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.
|
||||||
return jsgraph()->DeadValue();
|
// We just provide a dummy value here.
|
||||||
|
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())) {
|
||||||
@ -808,7 +815,8 @@ 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.
|
||||||
return jsgraph()->DeadValue();
|
// We just provide a dummy value here.
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
@ -2965,7 +2965,6 @@ 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:
|
||||||
@ -2983,8 +2982,7 @@ 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__,
|
||||||
|
@ -887,10 +887,6 @@ 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.
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,11 +218,6 @@ 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.
|
||||||
@ -1805,8 +1800,7 @@ 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++) {
|
||||||
@ -1831,9 +1825,7 @@ 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
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
// 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();
|
|
Loading…
Reference in New Issue
Block a user