[turbofan] Add proper conversions in RedundancyElimination
Change-Id: Ia832abb79894dfde290a8127534b161d6fcc8178 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4197350 Reviewed-by: Darius Mercadier <dmercadier@chromium.org> Commit-Queue: Nico Hartmann <nicohartmann@chromium.org> Cr-Commit-Position: refs/heads/main@{#85504}
This commit is contained in:
parent
919166e9ef
commit
f4900cf92b
@ -1805,7 +1805,8 @@ struct EarlyOptimizationPhase {
|
|||||||
SimplifiedOperatorReducer simple_reducer(&graph_reducer, data->jsgraph(),
|
SimplifiedOperatorReducer simple_reducer(&graph_reducer, data->jsgraph(),
|
||||||
data->broker(),
|
data->broker(),
|
||||||
BranchSemantics::kMachine);
|
BranchSemantics::kMachine);
|
||||||
RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone);
|
RedundancyElimination redundancy_elimination(&graph_reducer,
|
||||||
|
data->jsgraph(), temp_zone);
|
||||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||||
MachineOperatorReducer machine_reducer(
|
MachineOperatorReducer machine_reducer(
|
||||||
&graph_reducer, data->jsgraph(),
|
&graph_reducer, data->jsgraph(),
|
||||||
@ -1920,7 +1921,8 @@ struct LoadEliminationPhase {
|
|||||||
&graph_reducer, data->jsgraph(), temp_zone, BranchElimination::kEARLY);
|
&graph_reducer, data->jsgraph(), temp_zone, BranchElimination::kEARLY);
|
||||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||||
data->common(), temp_zone);
|
data->common(), temp_zone);
|
||||||
RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone);
|
RedundancyElimination redundancy_elimination(&graph_reducer,
|
||||||
|
data->jsgraph(), temp_zone);
|
||||||
LoadElimination load_elimination(&graph_reducer, data->jsgraph(),
|
LoadElimination load_elimination(&graph_reducer, data->jsgraph(),
|
||||||
temp_zone);
|
temp_zone);
|
||||||
CheckpointElimination checkpoint_elimination(&graph_reducer);
|
CheckpointElimination checkpoint_elimination(&graph_reducer);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "src/compiler/redundancy-elimination.h"
|
#include "src/compiler/redundancy-elimination.h"
|
||||||
|
|
||||||
|
#include "src/compiler/js-graph.h"
|
||||||
#include "src/compiler/node-properties.h"
|
#include "src/compiler/node-properties.h"
|
||||||
#include "src/compiler/simplified-operator.h"
|
#include "src/compiler/simplified-operator.h"
|
||||||
|
|
||||||
@ -11,8 +12,12 @@ namespace v8 {
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
namespace compiler {
|
namespace compiler {
|
||||||
|
|
||||||
RedundancyElimination::RedundancyElimination(Editor* editor, Zone* zone)
|
RedundancyElimination::RedundancyElimination(Editor* editor, JSGraph* jsgraph,
|
||||||
: AdvancedReducer(editor), node_checks_(zone), zone_(zone) {}
|
Zone* zone)
|
||||||
|
: AdvancedReducer(editor),
|
||||||
|
node_checks_(zone),
|
||||||
|
jsgraph_(jsgraph),
|
||||||
|
zone_(zone) {}
|
||||||
|
|
||||||
RedundancyElimination::~RedundancyElimination() = default;
|
RedundancyElimination::~RedundancyElimination() = default;
|
||||||
|
|
||||||
@ -133,8 +138,43 @@ RedundancyElimination::EffectPathChecks::AddCheck(Zone* zone,
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
struct Subsumption {
|
||||||
|
enum class Kind {
|
||||||
|
kNone,
|
||||||
|
kImplicit,
|
||||||
|
kWithConversion,
|
||||||
|
};
|
||||||
|
|
||||||
|
static Subsumption None() { return Subsumption(Kind::kNone, nullptr); }
|
||||||
|
static Subsumption Implicit() {
|
||||||
|
return Subsumption(Kind::kImplicit, nullptr);
|
||||||
|
}
|
||||||
|
static Subsumption WithConversion(const Operator* conversion_op) {
|
||||||
|
return Subsumption(Kind::kWithConversion, conversion_op);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsNone() const { return kind_ == Kind::kNone; }
|
||||||
|
bool IsImplicit() const { return kind_ == Kind::kImplicit; }
|
||||||
|
bool IsWithConversion() const { return kind_ == Kind::kWithConversion; }
|
||||||
|
const Operator* conversion_operator() const {
|
||||||
|
DCHECK(IsWithConversion());
|
||||||
|
return conversion_op_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Subsumption(Kind kind, const Operator* conversion_op)
|
||||||
|
: kind_(kind), conversion_op_(conversion_op) {
|
||||||
|
DCHECK_EQ(kind_ == Kind::kWithConversion, conversion_op_ != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Kind kind_;
|
||||||
|
const Operator* conversion_op_;
|
||||||
|
};
|
||||||
|
|
||||||
// Does check {a} subsume check {b}?
|
// Does check {a} subsume check {b}?
|
||||||
bool CheckSubsumes(Node const* a, Node const* b) {
|
Subsumption CheckSubsumes(Node const* a, Node const* b,
|
||||||
|
MachineOperatorBuilder* machine) {
|
||||||
|
Subsumption subsumption = Subsumption::Implicit();
|
||||||
if (a->op() != b->op()) {
|
if (a->op() != b->op()) {
|
||||||
if (a->opcode() == IrOpcode::kCheckInternalizedString &&
|
if (a->opcode() == IrOpcode::kCheckInternalizedString &&
|
||||||
b->opcode() == IrOpcode::kCheckString) {
|
b->opcode() == IrOpcode::kCheckString) {
|
||||||
@ -149,14 +189,24 @@ bool CheckSubsumes(Node const* a, Node const* b) {
|
|||||||
b->opcode() == IrOpcode::kCheckedTaggedToArrayIndex) {
|
b->opcode() == IrOpcode::kCheckedTaggedToArrayIndex) {
|
||||||
// CheckedTaggedSignedToInt32(node) implies
|
// CheckedTaggedSignedToInt32(node) implies
|
||||||
// CheckedTaggedToArrayIndex(node)
|
// CheckedTaggedToArrayIndex(node)
|
||||||
|
if (machine->Is64()) {
|
||||||
|
// On 64 bit architectures, ArrayIndex is 64 bit.
|
||||||
|
subsumption =
|
||||||
|
Subsumption::WithConversion(machine->ChangeInt32ToInt64());
|
||||||
|
}
|
||||||
} else if (a->opcode() == IrOpcode::kCheckedTaggedToInt32 &&
|
} else if (a->opcode() == IrOpcode::kCheckedTaggedToInt32 &&
|
||||||
b->opcode() == IrOpcode::kCheckedTaggedToArrayIndex) {
|
b->opcode() == IrOpcode::kCheckedTaggedToArrayIndex) {
|
||||||
// CheckedTaggedToInt32(node) implies CheckedTaggedToArrayIndex(node)
|
// CheckedTaggedToInt32(node) implies CheckedTaggedToArrayIndex(node)
|
||||||
|
if (machine->Is64()) {
|
||||||
|
// On 64 bit architectures, ArrayIndex is 64 bit.
|
||||||
|
subsumption =
|
||||||
|
Subsumption::WithConversion(machine->ChangeInt32ToInt64());
|
||||||
|
}
|
||||||
} else if (a->opcode() == IrOpcode::kCheckReceiver &&
|
} else if (a->opcode() == IrOpcode::kCheckReceiver &&
|
||||||
b->opcode() == IrOpcode::kCheckReceiverOrNullOrUndefined) {
|
b->opcode() == IrOpcode::kCheckReceiverOrNullOrUndefined) {
|
||||||
// CheckReceiver(node) implies CheckReceiverOrNullOrUndefined(node)
|
// CheckReceiver(node) implies CheckReceiverOrNullOrUndefined(node)
|
||||||
} else if (a->opcode() != b->opcode()) {
|
} else if (a->opcode() != b->opcode()) {
|
||||||
return false;
|
return Subsumption::None();
|
||||||
} else {
|
} else {
|
||||||
switch (a->opcode()) {
|
switch (a->opcode()) {
|
||||||
case IrOpcode::kCheckBounds:
|
case IrOpcode::kCheckBounds:
|
||||||
@ -189,7 +239,7 @@ bool CheckSubsumes(Node const* a, Node const* b) {
|
|||||||
const CheckMinusZeroParameters& bp =
|
const CheckMinusZeroParameters& bp =
|
||||||
CheckMinusZeroParametersOf(b->op());
|
CheckMinusZeroParametersOf(b->op());
|
||||||
if (ap.mode() != bp.mode()) {
|
if (ap.mode() != bp.mode()) {
|
||||||
return false;
|
return Subsumption::None();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -203,20 +253,20 @@ bool CheckSubsumes(Node const* a, Node const* b) {
|
|||||||
// for Number, in which case {b} will be subsumed no matter what.
|
// for Number, in which case {b} will be subsumed no matter what.
|
||||||
if (ap.mode() != bp.mode() &&
|
if (ap.mode() != bp.mode() &&
|
||||||
ap.mode() != CheckTaggedInputMode::kNumber) {
|
ap.mode() != CheckTaggedInputMode::kNumber) {
|
||||||
return false;
|
return Subsumption::None();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
DCHECK(!IsCheckedWithFeedback(a->op()));
|
DCHECK(!IsCheckedWithFeedback(a->op()));
|
||||||
return false;
|
return Subsumption::None();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = a->op()->ValueInputCount(); --i >= 0;) {
|
for (int i = a->op()->ValueInputCount(); --i >= 0;) {
|
||||||
if (a->InputAt(i) != b->InputAt(i)) return false;
|
if (a->InputAt(i) != b->InputAt(i)) return Subsumption::None();
|
||||||
}
|
}
|
||||||
return true;
|
return subsumption;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeSubsumes(Node* node, Node* replacement) {
|
bool TypeSubsumes(Node* node, Node* replacement) {
|
||||||
@ -232,11 +282,19 @@ bool TypeSubsumes(Node* node, Node* replacement) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Node* RedundancyElimination::EffectPathChecks::LookupCheck(Node* node) const {
|
Node* RedundancyElimination::EffectPathChecks::LookupCheck(
|
||||||
|
Node* node, JSGraph* jsgraph) const {
|
||||||
for (Check const* check = head_; check != nullptr; check = check->next) {
|
for (Check const* check = head_; check != nullptr; check = check->next) {
|
||||||
if (CheckSubsumes(check->node, node) && TypeSubsumes(node, check->node)) {
|
Subsumption subsumption =
|
||||||
|
CheckSubsumes(check->node, node, jsgraph->machine());
|
||||||
|
if (!subsumption.IsNone() && TypeSubsumes(node, check->node)) {
|
||||||
DCHECK(!check->node->IsDead());
|
DCHECK(!check->node->IsDead());
|
||||||
return check->node;
|
Node* result = check->node;
|
||||||
|
if (subsumption.IsWithConversion()) {
|
||||||
|
result = jsgraph->graph()->NewNode(subsumption.conversion_operator(),
|
||||||
|
result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -276,7 +334,7 @@ Reduction RedundancyElimination::ReduceCheckNode(Node* node) {
|
|||||||
// because we will have to recompute anyway once we compute the predecessor.
|
// because we will have to recompute anyway once we compute the predecessor.
|
||||||
if (checks == nullptr) return NoChange();
|
if (checks == nullptr) return NoChange();
|
||||||
// See if we have another check that dominates us.
|
// See if we have another check that dominates us.
|
||||||
if (Node* check = checks->LookupCheck(node)) {
|
if (Node* check = checks->LookupCheck(node, jsgraph_)) {
|
||||||
ReplaceWithValue(node, check);
|
ReplaceWithValue(node, check);
|
||||||
return Replace(check);
|
return Replace(check);
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,17 @@
|
|||||||
#define V8_COMPILER_REDUNDANCY_ELIMINATION_H_
|
#define V8_COMPILER_REDUNDANCY_ELIMINATION_H_
|
||||||
|
|
||||||
#include "src/compiler/graph-reducer.h"
|
#include "src/compiler/graph-reducer.h"
|
||||||
|
#include "src/compiler/machine-operator.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
namespace compiler {
|
namespace compiler {
|
||||||
|
|
||||||
|
class JSGraph;
|
||||||
|
|
||||||
class V8_EXPORT_PRIVATE RedundancyElimination final : public AdvancedReducer {
|
class V8_EXPORT_PRIVATE RedundancyElimination final : public AdvancedReducer {
|
||||||
public:
|
public:
|
||||||
RedundancyElimination(Editor* editor, Zone* zone);
|
RedundancyElimination(Editor* editor, JSGraph* jsgraph, Zone* zone);
|
||||||
~RedundancyElimination() final;
|
~RedundancyElimination() final;
|
||||||
RedundancyElimination(const RedundancyElimination&) = delete;
|
RedundancyElimination(const RedundancyElimination&) = delete;
|
||||||
RedundancyElimination& operator=(const RedundancyElimination&) = delete;
|
RedundancyElimination& operator=(const RedundancyElimination&) = delete;
|
||||||
@ -37,7 +40,7 @@ class V8_EXPORT_PRIVATE RedundancyElimination final : public AdvancedReducer {
|
|||||||
void Merge(EffectPathChecks const* that);
|
void Merge(EffectPathChecks const* that);
|
||||||
|
|
||||||
EffectPathChecks const* AddCheck(Zone* zone, Node* node) const;
|
EffectPathChecks const* AddCheck(Zone* zone, Node* node) const;
|
||||||
Node* LookupCheck(Node* node) const;
|
Node* LookupCheck(Node* node, JSGraph* jsgraph) const;
|
||||||
Node* LookupBoundsCheckFor(Node* node) const;
|
Node* LookupBoundsCheckFor(Node* node) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -74,6 +77,7 @@ class V8_EXPORT_PRIVATE RedundancyElimination final : public AdvancedReducer {
|
|||||||
Zone* zone() const { return zone_; }
|
Zone* zone() const { return zone_; }
|
||||||
|
|
||||||
PathChecksForEffectNodes node_checks_;
|
PathChecksForEffectNodes node_checks_;
|
||||||
|
JSGraph* jsgraph_;
|
||||||
Zone* const zone_;
|
Zone* const zone_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "src/codegen/tick-counter.h"
|
#include "src/codegen/tick-counter.h"
|
||||||
#include "src/compiler/feedback-source.h"
|
#include "src/compiler/feedback-source.h"
|
||||||
|
#include "src/compiler/js-graph.h"
|
||||||
#include "test/unittests/compiler/graph-reducer-unittest.h"
|
#include "test/unittests/compiler/graph-reducer-unittest.h"
|
||||||
#include "test/unittests/compiler/graph-unittest.h"
|
#include "test/unittests/compiler/graph-unittest.h"
|
||||||
#include "test/unittests/compiler/node-test-utils.h"
|
#include "test/unittests/compiler/node-test-utils.h"
|
||||||
@ -22,8 +23,12 @@ class RedundancyEliminationTest : public GraphTest {
|
|||||||
public:
|
public:
|
||||||
explicit RedundancyEliminationTest(int num_parameters = 4)
|
explicit RedundancyEliminationTest(int num_parameters = 4)
|
||||||
: GraphTest(num_parameters),
|
: GraphTest(num_parameters),
|
||||||
reducer_(&editor_, zone()),
|
javascript_(zone()),
|
||||||
simplified_(zone()) {
|
simplified_(zone()),
|
||||||
|
machine_(zone()),
|
||||||
|
jsgraph_(isolate(), graph(), common(), &javascript_, &simplified_,
|
||||||
|
&machine_),
|
||||||
|
reducer_(&editor_, &jsgraph_, zone()) {
|
||||||
// Initialize the {reducer_} state for the Start node.
|
// Initialize the {reducer_} state for the Start node.
|
||||||
reducer_.Reduce(graph()->start());
|
reducer_.Reduce(graph()->start());
|
||||||
|
|
||||||
@ -51,8 +56,11 @@ class RedundancyEliminationTest : public GraphTest {
|
|||||||
NiceMock<MockAdvancedReducerEditor> editor_;
|
NiceMock<MockAdvancedReducerEditor> editor_;
|
||||||
std::vector<FeedbackSource> vector_slot_pairs_;
|
std::vector<FeedbackSource> vector_slot_pairs_;
|
||||||
FeedbackSource feedback2_;
|
FeedbackSource feedback2_;
|
||||||
RedundancyElimination reducer_;
|
JSOperatorBuilder javascript_;
|
||||||
SimplifiedOperatorBuilder simplified_;
|
SimplifiedOperatorBuilder simplified_;
|
||||||
|
MachineOperatorBuilder machine_;
|
||||||
|
JSGraph jsgraph_;
|
||||||
|
RedundancyElimination reducer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
Loading…
Reference in New Issue
Block a user