Reland "[turbofan] add value input to DeadValue"

DeadValue was a constant node of type None. This is unsound in the
presence of re-scheduling. This CL adds a value input to DeadValue,
which preserves the dependency on the original node of type None.

This reland addresses the bug that the EffectControlLinearizer could destroy dependencies of DeadValue by attaching DeadValue nodes to the effect chain in the EffectControlLinearizer.

Bug: chromium:796041 chromium:798938
Change-Id: If47b54a7986d257eb63b437f855769b503679ff5
Reviewed-on: https://chromium-review.googlesource.com/850392
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50360}
This commit is contained in:
Tobias Tebbi 2018-01-04 13:45:56 +01:00 committed by Commit Bot
parent 6b050c0324
commit 6328c56570
17 changed files with 183 additions and 81 deletions

View File

@ -348,8 +348,7 @@ 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, 1, 1, 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) \
@ -1286,6 +1285,11 @@ uint32_t ObjectIdOf(Operator const* op) {
} }
} }
MachineRepresentation DeadValueRepresentationOf(Operator const* op) {
DCHECK_EQ(IrOpcode::kDeadValue, op->opcode());
return OpParameter<MachineRepresentation>(op);
}
const Operator* CommonOperatorBuilder::FrameState( const Operator* CommonOperatorBuilder::FrameState(
BailoutId bailout_id, OutputFrameStateCombine state_combine, BailoutId bailout_id, OutputFrameStateCombine state_combine,
const FrameStateFunctionInfo* function_info) { const FrameStateFunctionInfo* function_info) {
@ -1401,6 +1405,14 @@ CommonOperatorBuilder::CreateFrameStateFunctionInfo(
FrameStateFunctionInfo(type, parameter_count, local_count, shared_info); FrameStateFunctionInfo(type, parameter_count, local_count, shared_info);
} }
const Operator* CommonOperatorBuilder::DeadValue(MachineRepresentation rep) {
return new (zone()) Operator1<MachineRepresentation>( // --
IrOpcode::kDeadValue, Operator::kPure, // opcode
"DeadValue", // name
1, 0, 0, 1, 0, 0, // counts
rep); // parameter
}
#undef COMMON_CACHED_OP_LIST #undef COMMON_CACHED_OP_LIST
#undef CACHED_RETURN_LIST #undef CACHED_RETURN_LIST
#undef CACHED_END_LIST #undef CACHED_END_LIST

View File

@ -342,6 +342,8 @@ ArgumentsStateType ArgumentsStateTypeOf(Operator const*) WARN_UNUSED_RESULT;
uint32_t ObjectIdOf(Operator const*); uint32_t ObjectIdOf(Operator const*);
MachineRepresentation DeadValueRepresentationOf(Operator const*);
// Interface for building common operators that can be used at any level of IR, // Interface for building common operators that can be used at any level of IR,
// including JavaScript, mid-level, and low-level. // including JavaScript, mid-level, and low-level.
class V8_EXPORT_PRIVATE CommonOperatorBuilder final class V8_EXPORT_PRIVATE CommonOperatorBuilder final
@ -350,7 +352,7 @@ 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* DeadValue(MachineRepresentation rep);
const Operator* Unreachable(); 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);

View File

@ -21,10 +21,8 @@ DeadCodeElimination::DeadCodeElimination(Editor* editor, Graph* graph,
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) { zone_(temp_zone) {
NodeProperties::SetType(dead_, Type::None()); NodeProperties::SetType(dead_, Type::None());
NodeProperties::SetType(dead_value_, Type::None());
} }
namespace { namespace {
@ -38,11 +36,11 @@ bool NoReturn(Node* node) {
NodeProperties::GetTypeOrAny(node)->IsNone(); NodeProperties::GetTypeOrAny(node)->IsNone();
} }
bool HasDeadInput(Node* node) { Node* FindDeadInput(Node* node) {
for (Node* input : node->inputs()) { for (Node* input : node->inputs()) {
if (NoReturn(input)) return true; if (NoReturn(input)) return input;
} }
return false; return nullptr;
} }
} // namespace } // namespace
@ -209,17 +207,27 @@ Reduction DeadCodeElimination::ReducePhi(Node* node) {
DCHECK_EQ(IrOpcode::kPhi, node->opcode()); DCHECK_EQ(IrOpcode::kPhi, node->opcode());
Reduction reduction = PropagateDeadControl(node); Reduction reduction = PropagateDeadControl(node);
if (reduction.Changed()) return reduction; if (reduction.Changed()) return reduction;
if (PhiRepresentationOf(node->op()) == MachineRepresentation::kNone || MachineRepresentation rep = PhiRepresentationOf(node->op());
if (rep == MachineRepresentation::kNone ||
NodeProperties::GetTypeOrAny(node)->IsNone()) { NodeProperties::GetTypeOrAny(node)->IsNone()) {
return Replace(dead_value()); return Replace(DeadValue(node, rep));
}
int input_count = node->op()->ValueInputCount();
for (int i = 0; i < input_count; ++i) {
Node* input = NodeProperties::GetValueInput(node, i);
if (input->opcode() == IrOpcode::kDeadValue &&
DeadValueRepresentationOf(input->op()) != rep) {
NodeProperties::ReplaceValueInput(node, DeadValue(input, rep), i);
}
} }
return NoChange(); return NoChange();
} }
Reduction DeadCodeElimination::ReducePureNode(Node* node) { Reduction DeadCodeElimination::ReducePureNode(Node* node) {
DCHECK_EQ(0, node->op()->EffectInputCount()); DCHECK_EQ(0, node->op()->EffectInputCount());
if (HasDeadInput(node)) { if (node->opcode() == IrOpcode::kDeadValue) return NoChange();
return Replace(dead_value()); if (Node* input = FindDeadInput(node)) {
return Replace(DeadValue(input));
} }
return NoChange(); return NoChange();
} }
@ -234,8 +242,7 @@ Reduction DeadCodeElimination::ReduceUnreachableOrIfException(Node* node) {
return Replace(effect); return Replace(effect);
} }
if (effect->opcode() == IrOpcode::kUnreachable) { if (effect->opcode() == IrOpcode::kUnreachable) {
RelaxEffectsAndControls(node); return Replace(effect);
return Replace(dead_value());
} }
return NoChange(); return NoChange();
} }
@ -246,10 +253,10 @@ Reduction DeadCodeElimination::ReduceEffectNode(Node* node) {
if (effect->opcode() == IrOpcode::kDead) { if (effect->opcode() == IrOpcode::kDead) {
return Replace(effect); return Replace(effect);
} }
if (HasDeadInput(node)) { if (Node* input = FindDeadInput(node)) {
if (effect->opcode() == IrOpcode::kUnreachable) { if (effect->opcode() == IrOpcode::kUnreachable) {
RelaxEffectsAndControls(node); RelaxEffectsAndControls(node);
return Replace(dead_value()); return Replace(DeadValue(input));
} }
Node* control = node->op()->ControlInputCount() == 1 Node* control = node->op()->ControlInputCount() == 1
@ -257,7 +264,8 @@ Reduction DeadCodeElimination::ReduceEffectNode(Node* node) {
: graph()->start(); : graph()->start();
Node* unreachable = Node* unreachable =
graph()->NewNode(common()->Unreachable(), effect, control); graph()->NewNode(common()->Unreachable(), effect, control);
ReplaceWithValue(node, dead_value(), node, control); NodeProperties::SetType(unreachable, Type::None());
ReplaceWithValue(node, DeadValue(input), node, control);
return Replace(unreachable); return Replace(unreachable);
} }
@ -270,11 +278,12 @@ Reduction DeadCodeElimination::ReduceDeoptimizeOrReturnOrTerminate(Node* node) {
node->opcode() == IrOpcode::kTerminate); node->opcode() == IrOpcode::kTerminate);
Reduction reduction = PropagateDeadControl(node); Reduction reduction = PropagateDeadControl(node);
if (reduction.Changed()) return reduction; if (reduction.Changed()) return reduction;
if (HasDeadInput(node)) { if (FindDeadInput(node) != nullptr) {
Node* effect = NodeProperties::GetEffectInput(node, 0); Node* effect = NodeProperties::GetEffectInput(node, 0);
Node* control = NodeProperties::GetControlInput(node, 0); Node* control = NodeProperties::GetControlInput(node, 0);
if (effect->opcode() != IrOpcode::kUnreachable) { if (effect->opcode() != IrOpcode::kUnreachable) {
effect = graph()->NewNode(common()->Unreachable(), effect, control); effect = graph()->NewNode(common()->Unreachable(), effect, control);
NodeProperties::SetType(effect, Type::None());
} }
node->TrimInputCount(2); node->TrimInputCount(2);
node->ReplaceInput(0, effect); node->ReplaceInput(0, effect);
@ -322,6 +331,16 @@ void DeadCodeElimination::TrimMergeOrPhi(Node* node, int size) {
NodeProperties::ChangeOp(node, op); NodeProperties::ChangeOp(node, op);
} }
Node* DeadCodeElimination::DeadValue(Node* node, MachineRepresentation rep) {
if (node->opcode() == IrOpcode::kDeadValue) {
if (rep == DeadValueRepresentationOf(node->op())) return node;
node = NodeProperties::GetValueInput(node, 0);
}
Node* dead_value = graph()->NewNode(common()->DeadValue(rep), node);
NodeProperties::SetType(dead_value, Type::None());
return dead_value;
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -8,6 +8,7 @@
#include "src/base/compiler-specific.h" #include "src/base/compiler-specific.h"
#include "src/compiler/graph-reducer.h" #include "src/compiler/graph-reducer.h"
#include "src/globals.h" #include "src/globals.h"
#include "src/machine-type.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
@ -17,13 +18,23 @@ namespace compiler {
class CommonOperatorBuilder; class CommonOperatorBuilder;
// Propagates {Dead} control and {DeadValue} values through the graph and // Propagates {Dead} control and {DeadValue} values through the graph and
// thereby removes dead code. When {DeadValue} hits the effect chain, a crashing // thereby removes dead code.
// {Unreachable} node is inserted and the rest of the effect chain is collapsed. // We detect dead values based on types, replacing uses of nodes with
// We wait for the {EffectControlLinearizer} to connect {Unreachable} nodes to // {Type::None()} with {DeadValue}. A pure node (other than a phi) using
// the graph end, since this is much easier if there is no floating control. // {DeadValue} is replaced by {DeadValue}. When {DeadValue} hits the effect
// We detect dead values based on types, pruning uses of DeadValue except for // chain, a crashing {Unreachable} node is inserted and the rest of the effect
// uses by phi. These remaining uses are eliminated in the // chain is collapsed. We wait for the {EffectControlLinearizer} to connect
// {EffectControlLinearizer}, where they are replaced with dummy values. // {Unreachable} nodes to the graph end, since this is much easier if there is
// no floating control.
// {DeadValue} has an input, which has to have {Type::None()}. This input is
// important to maintain the dependency on the cause of the unreachable code.
// {Unreachable} has a value output and {Type::None()} so it can be used by
// {DeadValue}.
// {DeadValue} nodes track a {MachineRepresentation} so they can be lowered to a
// value-producing node. {DeadValue} has the runtime semantics of crashing and
// behaves like a constant of its representation so it can be used in gap moves.
// Since phi nodes are the only remaining use of {DeadValue}, this
// representation is only adjusted for uses by phi nodes.
// In contrast to {DeadValue}, {Dead} can never remain in the graph. // 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) {
@ -53,15 +64,16 @@ class V8_EXPORT_PRIVATE DeadCodeElimination final
void TrimMergeOrPhi(Node* node, int size); void TrimMergeOrPhi(Node* node, int size);
Node* DeadValue(Node* none_node,
MachineRepresentation rep = MachineRepresentation::kNone);
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_; Zone* zone_;
DISALLOW_COPY_AND_ASSIGN(DeadCodeElimination); DISALLOW_COPY_AND_ASSIGN(DeadCodeElimination);

View File

@ -318,28 +318,6 @@ void TryCloneBranch(Node* node, BasicBlock* block, Zone* temp_zone,
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() {
@ -369,7 +347,6 @@ void EffectControlLinearizer::Run() {
// Iterate over the phis and update the effect phis. // Iterate over the phis and update the effect phis.
Node* effect_phi = 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.
@ -380,19 +357,7 @@ void EffectControlLinearizer::Run() {
DCHECK_NE(IrOpcode::kIfException, control->opcode()); DCHECK_NE(IrOpcode::kIfException, control->opcode());
effect_phi = node; effect_phi = node;
} else if (node->opcode() == IrOpcode::kPhi) { } else if (node->opcode() == IrOpcode::kPhi) {
DCHECK_EQ(predecessor_count, node->op()->ValueInputCount()); // Just skip phis.
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;
@ -856,6 +821,8 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kSameValue: case IrOpcode::kSameValue:
result = LowerSameValue(node); result = LowerSameValue(node);
break; break;
case IrOpcode::kDeadValue:
result = LowerDeadValue(node);
case IrOpcode::kStringFromCharCode: case IrOpcode::kStringFromCharCode:
result = LowerStringFromCharCode(node); result = LowerStringFromCharCode(node);
break; break;
@ -2666,6 +2633,15 @@ Node* EffectControlLinearizer::LowerSameValue(Node* node) {
__ NoContextConstant()); __ NoContextConstant());
} }
Node* EffectControlLinearizer::LowerDeadValue(Node* node) {
Node* input = NodeProperties::GetValueInput(node, 0);
if (input->opcode() != IrOpcode::kUnreachable) {
Node* unreachable = __ Unreachable();
NodeProperties::ReplaceValueInput(node, unreachable, 0);
}
return node;
}
Node* EffectControlLinearizer::LowerStringToNumber(Node* node) { Node* EffectControlLinearizer::LowerStringToNumber(Node* node) {
Node* string = node->InputAt(0); Node* string = node->InputAt(0);

View File

@ -113,6 +113,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerNewConsString(Node* node); Node* LowerNewConsString(Node* node);
Node* LowerArrayBufferWasNeutered(Node* node); Node* LowerArrayBufferWasNeutered(Node* node);
Node* LowerSameValue(Node* node); Node* LowerSameValue(Node* node);
Node* LowerDeadValue(Node* node);
Node* LowerStringToNumber(Node* node); Node* LowerStringToNumber(Node* node);
Node* LowerStringCharAt(Node* node); Node* LowerStringCharAt(Node* node);
Node* LowerStringCharCodeAt(Node* node); Node* LowerStringCharCodeAt(Node* node);

View File

@ -134,6 +134,11 @@ Node* GraphAssembler::DebugBreak() {
current_effect_, current_control_); current_effect_, current_control_);
} }
Node* GraphAssembler::Unreachable() {
return current_effect_ = graph()->NewNode(common()->Unreachable(),
current_effect_, current_control_);
}
Node* GraphAssembler::Store(StoreRepresentation rep, Node* object, Node* offset, Node* GraphAssembler::Store(StoreRepresentation rep, Node* object, Node* offset,
Node* value) { Node* value) {
return current_effect_ = return current_effect_ =

View File

@ -194,6 +194,8 @@ class GraphAssembler {
// Debugging // Debugging
Node* DebugBreak(); Node* DebugBreak();
Node* Unreachable();
Node* Float64RoundDown(Node* value); Node* Float64RoundDown(Node* value);
Node* ToNumber(Node* value); Node* ToNumber(Node* value);

View File

@ -251,6 +251,23 @@ class OperandGenerator {
return Constant(OpParameter<ExternalReference>(node)); return Constant(OpParameter<ExternalReference>(node));
case IrOpcode::kHeapConstant: case IrOpcode::kHeapConstant:
return Constant(OpParameter<Handle<HeapObject>>(node)); return Constant(OpParameter<Handle<HeapObject>>(node));
case IrOpcode::kDeadValue: {
switch (DeadValueRepresentationOf(node->op())) {
case MachineRepresentation::kBit:
case MachineRepresentation::kWord32:
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedSigned:
case MachineRepresentation::kTaggedPointer:
return Constant(static_cast<int32_t>(0));
case MachineRepresentation::kFloat64:
return Constant(static_cast<double>(0));
case MachineRepresentation::kFloat32:
return Constant(static_cast<float>(0));
default:
UNREACHABLE();
}
break;
}
default: default:
break; break;
} }

View File

@ -1147,6 +1147,9 @@ void InstructionSelector::VisitNode(Node* node) {
case IrOpcode::kUnreachable: case IrOpcode::kUnreachable:
VisitUnreachable(node); VisitUnreachable(node);
return; return;
case IrOpcode::kDeadValue:
VisitDeadValue(node);
return;
case IrOpcode::kComment: case IrOpcode::kComment:
VisitComment(node); VisitComment(node);
return; return;
@ -2620,6 +2623,12 @@ void InstructionSelector::VisitUnreachable(Node* node) {
Emit(kArchDebugBreak, g.NoOutput()); Emit(kArchDebugBreak, g.NoOutput());
} }
void InstructionSelector::VisitDeadValue(Node* node) {
OperandGenerator g(this);
MarkAsRepresentation(DeadValueRepresentationOf(node->op()), node);
Emit(kArchDebugBreak, g.DefineAsConstant(node));
}
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));

View File

@ -352,6 +352,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void VisitThrow(Node* node); void VisitThrow(Node* node);
void VisitRetain(Node* node); void VisitRetain(Node* node);
void VisitUnreachable(Node* node); void VisitUnreachable(Node* node);
void VisitDeadValue(Node* node);
void EmitPrepareArguments(ZoneVector<compiler::PushParameter>* arguments, void EmitPrepareArguments(ZoneVector<compiler::PushParameter>* arguments,
const CallDescriptor* descriptor, Node* node); const CallDescriptor* descriptor, Node* node);

View File

@ -305,10 +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);
for (size_t i = 0; i < arraysize(cached_nodes_); i++) { for (size_t i = 0; i < arraysize(cached_nodes_); i++) {

View File

@ -155,9 +155,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_; }
@ -199,7 +196,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.
}; };

View File

@ -216,7 +216,9 @@ 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(); return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kTaggedSigned),
node);
} 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,7 +338,9 @@ 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(); return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kTaggedPointer),
node);
} else if (output_rep == MachineRepresentation::kBit) { } else if (output_rep == MachineRepresentation::kBit) {
if (output_type->Is(Type::Boolean())) { if (output_type->Is(Type::Boolean())) {
op = simplified()->ChangeBitToTagged(); op = simplified()->ChangeBitToTagged();
@ -413,7 +417,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(); return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kTagged), node);
} 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();
@ -491,7 +496,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(); return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kFloat32), node);
} 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
@ -551,7 +557,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(); return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kFloat64), node);
} 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();
@ -628,7 +635,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(); return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kWord32), node);
} 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) {
@ -767,7 +775,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(); return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kBit), node);
} 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())) {
@ -812,7 +821,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(); return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kWord32), node);
} else if (output_rep == MachineRepresentation::kBit) { } else if (output_rep == MachineRepresentation::kBit) {
return node; // Sloppy comparison -> word64 return node; // Sloppy comparison -> word64
} }

View File

@ -965,7 +965,7 @@ Type* Typer::Visitor::TypeDead(Node* node) { return Type::None(); }
Type* Typer::Visitor::TypeDeadValue(Node* node) { return Type::None(); } Type* Typer::Visitor::TypeDeadValue(Node* node) { return Type::None(); }
Type* Typer::Visitor::TypeUnreachable(Node* node) { UNREACHABLE(); } Type* Typer::Visitor::TypeUnreachable(Node* node) { return Type::None(); }
// JS comparison operators. // JS comparison operators.

View File

@ -236,10 +236,19 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
// Dead is never connected to the graph. // Dead is never connected to the graph.
UNREACHABLE(); UNREACHABLE();
case IrOpcode::kDeadValue: case IrOpcode::kDeadValue:
CheckValueInputIs(node, 0, Type::None());
CheckTypeIs(node, Type::None()); CheckTypeIs(node, Type::None());
break; break;
case IrOpcode::kUnreachable: case IrOpcode::kUnreachable:
CheckNotTyped(node); CheckTypeIs(node, Type::None());
for (Edge edge : node->use_edges()) {
Node* use = edge.from();
if (NodeProperties::IsValueEdge(edge) && all.IsLive(use)) {
// {Unreachable} nodes can only be used by {DeadValue}, because they
// don't actually produce a value.
CHECK_EQ(IrOpcode::kDeadValue, use->opcode());
}
}
break; break;
case IrOpcode::kBranch: { case IrOpcode::kBranch: {
// Branch uses are IfTrue and IfFalse. // Branch uses are IfTrue and IfFalse.

View File

@ -0,0 +1,35 @@
// Copyright 2018 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';
function f(abort, n, a, b) {
if (abort) return;
var x = a ? true : "" + a;
if (!a) {
var dead = n + 1 + 1;
if(!b) {
x = dead;
}
if (x) {
x = false;
}
if (b) {
x = false;
}
}
return x + 1;
}
f(false, 5); f(false, 6); f(false, 7); f(false, 8);
function g(abort, a, b) {
return f(abort, "abc", a, b);
}
g(true); g(true); g(true); g(true);
%OptimizeFunctionOnNextCall(g);
g(false);