Revert "[turbofan] add value input to DeadValue" and "[turbofan] add regression test for chromium:796041"

This reverts
https://chromium-review.googlesource.com/c/v8/v8/+/848995
and
https://chromium-review.googlesource.com/c/v8/v8/+/847011

Bug: chromium:798938
Change-Id: I4be8e5bca77037a278fd9882f0d76de1ae12c23f
TBR: jarin@chromium.org
Reviewed-on: https://chromium-review.googlesource.com/849995
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50356}
This commit is contained in:
Tobias Tebbi 2018-01-04 11:54:22 +01:00 committed by Commit Bot
parent 4b107b9ec9
commit 9e2d001e86
14 changed files with 81 additions and 164 deletions

View File

@ -348,7 +348,8 @@ ZoneVector<MachineType> const* MachineTypesOf(Operator const* op) {
#define COMMON_CACHED_OP_LIST(V) \
V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \
V(Unreachable, Operator::kFoldable, 0, 1, 1, 1, 1, 0) \
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(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
@ -1285,11 +1286,6 @@ 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(
BailoutId bailout_id, OutputFrameStateCombine state_combine,
const FrameStateFunctionInfo* function_info) {
@ -1405,14 +1401,6 @@ CommonOperatorBuilder::CreateFrameStateFunctionInfo(
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 CACHED_RETURN_LIST
#undef CACHED_END_LIST

View File

@ -342,8 +342,6 @@ ArgumentsStateType ArgumentsStateTypeOf(Operator const*) WARN_UNUSED_RESULT;
uint32_t ObjectIdOf(Operator const*);
MachineRepresentation DeadValueRepresentationOf(Operator const*);
// Interface for building common operators that can be used at any level of IR,
// including JavaScript, mid-level, and low-level.
class V8_EXPORT_PRIVATE CommonOperatorBuilder final
@ -352,7 +350,7 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
explicit CommonOperatorBuilder(Zone* zone);
const Operator* Dead();
const Operator* DeadValue(MachineRepresentation rep);
const Operator* DeadValue();
const Operator* Unreachable();
const Operator* End(size_t control_input_count);
const Operator* Branch(BranchHint = BranchHint::kNone);

View File

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

View File

@ -8,7 +8,6 @@
#include "src/base/compiler-specific.h"
#include "src/compiler/graph-reducer.h"
#include "src/globals.h"
#include "src/machine-type.h"
namespace v8 {
namespace internal {
@ -18,23 +17,13 @@ namespace compiler {
class CommonOperatorBuilder;
// Propagates {Dead} control and {DeadValue} values through the graph and
// thereby removes dead code.
// We detect dead values based on types, replacing uses of nodes with
// {Type::None()} with {DeadValue}. A pure node (other than a phi) using
// {DeadValue} is replaced by {DeadValue}. When {DeadValue} hits the effect
// chain, a crashing {Unreachable} node is inserted and the rest of the effect
// chain is collapsed. We wait for the {EffectControlLinearizer} to connect
// {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.
// thereby removes dead code. When {DeadValue} hits the effect chain, a crashing
// {Unreachable} node is inserted and the rest of the effect chain is collapsed.
// 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
: public NON_EXPORTED_BASE(AdvancedReducer) {
@ -64,16 +53,15 @@ class V8_EXPORT_PRIVATE DeadCodeElimination final
void TrimMergeOrPhi(Node* node, int size);
Node* DeadValue(Node* none_node,
MachineRepresentation rep = MachineRepresentation::kNone);
Graph* graph() const { return graph_; }
CommonOperatorBuilder* common() const { return common_; }
Node* dead() const { return dead_; }
Node* dead_value() const { return dead_value_; }
Graph* const graph_;
CommonOperatorBuilder* const common_;
Node* const dead_;
Node* const dead_value_;
Zone* zone_;
DISALLOW_COPY_AND_ASSIGN(DeadCodeElimination);

View File

@ -318,6 +318,28 @@ void TryCloneBranch(Node* node, BasicBlock* block, Zone* temp_zone,
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
void EffectControlLinearizer::Run() {
@ -347,6 +369,7 @@ void EffectControlLinearizer::Run() {
// Iterate over the phis and update the effect phis.
Node* effect_phi = nullptr;
Node* terminate = nullptr;
int predecessor_count = static_cast<int>(block->PredecessorCount());
for (; instr < block->NodeCount(); instr++) {
Node* node = block->NodeAt(instr);
// Only go through the phis and effect phis.
@ -357,7 +380,19 @@ void EffectControlLinearizer::Run() {
DCHECK_NE(IrOpcode::kIfException, control->opcode());
effect_phi = node;
} 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) {
DCHECK_NULL(terminate);
terminate = node;

View File

@ -251,23 +251,6 @@ class OperandGenerator {
return Constant(OpParameter<ExternalReference>(node));
case IrOpcode::kHeapConstant:
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:
break;
}

View File

@ -1147,9 +1147,6 @@ void InstructionSelector::VisitNode(Node* node) {
case IrOpcode::kUnreachable:
VisitUnreachable(node);
return;
case IrOpcode::kDeadValue:
VisitDeadValue(node);
return;
case IrOpcode::kComment:
VisitComment(node);
return;
@ -2623,12 +2620,6 @@ void InstructionSelector::VisitUnreachable(Node* node) {
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) {
OperandGenerator g(this);
InstructionOperand operand(g.UseImmediate(node));

View File

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

View File

@ -305,6 +305,10 @@ Node* JSGraph::Dead() {
return CACHED(kDead, graph()->NewNode(common()->Dead()));
}
Node* JSGraph::DeadValue() {
return CACHED(kDeadValue, graph()->NewNode(common()->DeadValue()));
}
void JSGraph::GetCachedNodes(NodeVector* nodes) {
cache_.GetCachedNodes(nodes);
for (size_t i = 0; i < arraysize(cached_nodes_); i++) {

View File

@ -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.
Node* Dead();
// Sentinel for a value resulting from unreachable computations.
Node* DeadValue();
CommonOperatorBuilder* common() const { return common_; }
JSOperatorBuilder* javascript() const { return javascript_; }
SimplifiedOperatorBuilder* simplified() const { return simplified_; }
@ -196,6 +199,7 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
kEmptyStateValues,
kSingleDeadTypedStateValues,
kDead,
kDeadValue,
kNumCachedNodes // Must remain last.
};

View File

@ -216,9 +216,7 @@ Node* RepresentationChanger::GetTaggedSignedRepresentationFor(
const Operator* op;
if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime.
return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kTaggedSigned),
node);
return jsgraph()->DeadValue();
} else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed31())) {
op = simplified()->ChangeInt31ToTaggedSigned();
@ -338,9 +336,7 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
Operator const* op;
if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime.
return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kTaggedPointer),
node);
return jsgraph()->DeadValue();
} else if (output_rep == MachineRepresentation::kBit) {
if (output_type->Is(Type::Boolean())) {
op = simplified()->ChangeBitToTagged();
@ -417,8 +413,7 @@ Node* RepresentationChanger::GetTaggedRepresentationFor(
const Operator* op;
if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime.
return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kTagged), node);
return jsgraph()->DeadValue();
} else if (output_rep == MachineRepresentation::kBit) {
if (output_type->Is(Type::Boolean())) {
op = simplified()->ChangeBitToTagged();
@ -496,8 +491,7 @@ Node* RepresentationChanger::GetFloat32RepresentationFor(
const Operator* op = nullptr;
if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime.
return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kFloat32), node);
return jsgraph()->DeadValue();
} else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) {
// int32 -> float64 -> float32
@ -557,8 +551,7 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
const Operator* op = nullptr;
if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime.
return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kFloat64), node);
return jsgraph()->DeadValue();
} else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) {
op = machine()->ChangeInt32ToFloat64();
@ -635,8 +628,7 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
const Operator* op = nullptr;
if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime.
return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kWord32), node);
return jsgraph()->DeadValue();
} else if (output_rep == MachineRepresentation::kBit) {
return node; // Sloppy comparison -> word32
} else if (output_rep == MachineRepresentation::kFloat64) {
@ -775,8 +767,7 @@ Node* RepresentationChanger::GetBitRepresentationFor(
const Operator* op;
if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime.
return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kBit), node);
return jsgraph()->DeadValue();
} else if (output_rep == MachineRepresentation::kTagged ||
output_rep == MachineRepresentation::kTaggedPointer) {
if (output_type->Is(Type::BooleanOrNullOrUndefined())) {
@ -821,8 +812,7 @@ Node* RepresentationChanger::GetWord64RepresentationFor(
Node* node, MachineRepresentation output_rep, Type* output_type) {
if (output_type->Is(Type::None())) {
// This is an impossible value; it should not be used at runtime.
return jsgraph()->graph()->NewNode(
jsgraph()->common()->DeadValue(MachineRepresentation::kWord32), node);
return jsgraph()->DeadValue();
} else if (output_rep == MachineRepresentation::kBit) {
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::TypeUnreachable(Node* node) { return Type::None(); }
Type* Typer::Visitor::TypeUnreachable(Node* node) { UNREACHABLE(); }
// JS comparison operators.

View File

@ -236,19 +236,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
// Dead is never connected to the graph.
UNREACHABLE();
case IrOpcode::kDeadValue:
CheckValueInputIs(node, 0, Type::None());
CheckTypeIs(node, Type::None());
break;
case IrOpcode::kUnreachable:
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());
}
}
CheckNotTyped(node);
break;
case IrOpcode::kBranch: {
// Branch uses are IfTrue and IfFalse.

View File

@ -1,35 +0,0 @@
// 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);