Reland^2 [compiler] Simplify "==0" branches in MachineOperatorReducer
This is a reland of6b690a6b48
. The previous version of this CL was a bit too aggressive in the duplication of branch conditions. This caused an increase in register pressure in some cases, thus reducing performance. In fact, duplicating branch conditions that require an "== 0" to be added provides no benefits. We are thus now a bit less aggressive, and only duplicate comparisons. Original change's description: > Reland [compiler] Simplify "==0" branches in MachineOperatorReducer > > This is a reland of48b443f692
. > > While fixing the initial CL, we stumbled upon a few bugs that > we had to fix: > > - CommonOperatorReducer and SimplifiedOperatorReducer were applied > before and after SimplifiedLowering, but always assumed that it > was before SimplifiedLowering, and thus had the wrong semantics > for branches in some cases. They now have an added parameter to > know which semantics of branch they should use. > > - The lowering of StaticAssert was wrong and could leave kHeapConstant > in the assert (instead of machine Booleans). > > Original change's description: > > [compiler] Simplify "==0" branches in MachineOperatorReducer > > > > Bug: v8:12484 > > Change-Id: I0667c7464c0dd71338bc199a24a69248a7a0a525 > > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3497303 > > Reviewed-by: Tobias Tebbi <tebbi@chromium.org> > > Owners-Override: Tobias Tebbi <tebbi@chromium.org> > > Commit-Queue: Darius Mercadier <dmercadier@chromium.org> > > Cr-Commit-Position: refs/heads/main@{#79379} > > Bug: v8:12484 > Change-Id: Ibbf5df96fce5ccb04868dc517539479bf69f5703 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3516869 > Reviewed-by: Tobias Tebbi <tebbi@chromium.org> > Commit-Queue: Darius Mercadier <dmercadier@chromium.org> > Cr-Commit-Position: refs/heads/main@{#79528} Bug: v8:12484 Change-Id: I31f575a59811a83c7c1acb4c14bf5ded63a8f536 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3540102 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Commit-Queue: Darius Mercadier <dmercadier@chromium.org> Cr-Commit-Position: refs/heads/main@{#79560}
This commit is contained in:
parent
7ecaee95e3
commit
0719ace66e
@ -2610,6 +2610,8 @@ filegroup(
|
||||
"src/compiler/backend/unwinding-info-writer.h",
|
||||
"src/compiler/basic-block-instrumentor.cc",
|
||||
"src/compiler/basic-block-instrumentor.h",
|
||||
"src/compiler/branch-condition-duplicator.cc",
|
||||
"src/compiler/branch-condition-duplicator.h",
|
||||
"src/compiler/branch-elimination.cc",
|
||||
"src/compiler/branch-elimination.h",
|
||||
"src/compiler/bytecode-analysis.cc",
|
||||
|
2
BUILD.gn
2
BUILD.gn
@ -2778,6 +2778,7 @@ v8_header_set("v8_internal_headers") {
|
||||
"src/compiler/backend/spill-placer.h",
|
||||
"src/compiler/backend/unwinding-info-writer.h",
|
||||
"src/compiler/basic-block-instrumentor.h",
|
||||
"src/compiler/branch-condition-duplicator.h",
|
||||
"src/compiler/branch-elimination.h",
|
||||
"src/compiler/bytecode-analysis.h",
|
||||
"src/compiler/bytecode-graph-builder.h",
|
||||
@ -3890,6 +3891,7 @@ v8_compiler_sources = [
|
||||
"src/compiler/backend/register-allocator.cc",
|
||||
"src/compiler/backend/spill-placer.cc",
|
||||
"src/compiler/basic-block-instrumentor.cc",
|
||||
"src/compiler/branch-condition-duplicator.cc",
|
||||
"src/compiler/branch-elimination.cc",
|
||||
"src/compiler/bytecode-analysis.cc",
|
||||
"src/compiler/bytecode-graph-builder.cc",
|
||||
|
95
src/compiler/branch-condition-duplicator.cc
Normal file
95
src/compiler/branch-condition-duplicator.cc
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
#include "src/compiler/branch-condition-duplicator.h"
|
||||
|
||||
#include "src/compiler/backend/instruction-codes.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
#include "src/compiler/opcodes.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsBranch(Node* node) { return node->opcode() == IrOpcode::kBranch; }
|
||||
|
||||
bool CanDuplicate(Node* node) {
|
||||
// We only allow duplication of comparisons. Duplicating other nodes makes
|
||||
// little sense, because a "== 0" need to be inserted in branches anyways
|
||||
// (except for some binops, but duplicating binops might increase the live
|
||||
// range of the operands, thus increasing register pressure).
|
||||
switch (node->opcode()) {
|
||||
#define BRANCH_CASE(op) \
|
||||
case IrOpcode::k##op: \
|
||||
break;
|
||||
MACHINE_COMPARE_BINOP_LIST(BRANCH_CASE)
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// We do not duplicate nodes if all their inputs are used a single time,
|
||||
// because this would keep those inputs alive, thus increasing register
|
||||
// pressure.
|
||||
int all_inputs_have_only_a_single_use = true;
|
||||
for (Node* input : node->inputs()) {
|
||||
if (input->UseCount() > 1) {
|
||||
all_inputs_have_only_a_single_use = false;
|
||||
}
|
||||
}
|
||||
if (all_inputs_have_only_a_single_use) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Node* BranchConditionDuplicator::DuplicateNode(Node* node) {
|
||||
return graph_->CloneNode(node);
|
||||
}
|
||||
|
||||
void BranchConditionDuplicator::DuplicateConditionIfNeeded(Node* node) {
|
||||
if (!IsBranch(node)) return;
|
||||
|
||||
Node* condNode = node->InputAt(0);
|
||||
if (condNode->UseCount() > 1 && CanDuplicate(condNode)) {
|
||||
node->ReplaceInput(0, DuplicateNode(condNode));
|
||||
}
|
||||
}
|
||||
|
||||
void BranchConditionDuplicator::Enqueue(Node* node) {
|
||||
if (seen_.Get(node)) return;
|
||||
seen_.Set(node, true);
|
||||
to_visit_.push(node);
|
||||
}
|
||||
|
||||
void BranchConditionDuplicator::VisitNode(Node* node) {
|
||||
DuplicateConditionIfNeeded(node);
|
||||
|
||||
for (int i = 0; i < node->op()->ControlInputCount(); i++) {
|
||||
Enqueue(NodeProperties::GetControlInput(node, i));
|
||||
}
|
||||
}
|
||||
|
||||
void BranchConditionDuplicator::ProcessGraph() {
|
||||
Enqueue(graph_->end());
|
||||
while (!to_visit_.empty()) {
|
||||
Node* node = to_visit_.front();
|
||||
to_visit_.pop();
|
||||
VisitNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
BranchConditionDuplicator::BranchConditionDuplicator(Zone* zone, Graph* graph)
|
||||
: graph_(graph), to_visit_(zone), seen_(graph, 2) {}
|
||||
|
||||
void BranchConditionDuplicator::Reduce() { ProcessGraph(); }
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
85
src/compiler/branch-condition-duplicator.h
Normal file
85
src/compiler/branch-condition-duplicator.h
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
#ifndef V8_COMPILER_BRANCH_CONDITION_DUPLICATOR_H_
|
||||
#define V8_COMPILER_BRANCH_CONDITION_DUPLICATOR_H_
|
||||
|
||||
#include "src/base/macros.h"
|
||||
#include "src/compiler/node-marker.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/zone/zone.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
// Forward declare.
|
||||
class Graph;
|
||||
|
||||
// BranchConditionDuplicator makes sure that the condition nodes of branches are
|
||||
// used only once. When it finds a branch node whose condition has multiples
|
||||
// uses, this condition is duplicated.
|
||||
//
|
||||
// Doing this enables the InstructionSelector to generate more efficient code
|
||||
// for branches. For instance, consider this code:
|
||||
//
|
||||
// if (a + b == 0) { /* some code */ }
|
||||
// if (a + b == 0) { /* more code */ }
|
||||
//
|
||||
// Then the generated code will be something like (using registers "ra" for "a"
|
||||
// and "rb" for "b", and "rt" a temporary register):
|
||||
//
|
||||
// add ra, rb ; a + b
|
||||
// cmp ra, 0 ; (a + b) == 0
|
||||
// sete rt ; rt = (a + b) == 0
|
||||
// cmp rt, 0 ; rt == 0
|
||||
// jz
|
||||
// ...
|
||||
// cmp rt, 0 ; rt == 0
|
||||
// jz
|
||||
//
|
||||
// As you can see, TurboFan materialized the == bit into a temporary register.
|
||||
// However, since the "add" instruction sets the ZF flag (on x64), it can be
|
||||
// used to determine wether the jump should be taken or not. The code we'd like
|
||||
// to generate instead if thus:
|
||||
//
|
||||
// add ra, rb
|
||||
// jnz
|
||||
// ...
|
||||
// add ra, rb
|
||||
// jnz
|
||||
//
|
||||
// However, this requires to generate twice the instruction "add ra, rb". Due to
|
||||
// how virtual registers are assigned in TurboFan (there is a map from node ID
|
||||
// to virtual registers), both "add" instructions will use the same virtual
|
||||
// register as output, which will break SSA.
|
||||
//
|
||||
// In order to overcome this issue, BranchConditionDuplicator duplicates branch
|
||||
// conditions that are used more than once, so that they can be generated right
|
||||
// before each branch without worrying about breaking SSA.
|
||||
|
||||
class V8_EXPORT_PRIVATE BranchConditionDuplicator final {
|
||||
public:
|
||||
BranchConditionDuplicator(Zone* zone, Graph* graph);
|
||||
~BranchConditionDuplicator() = default;
|
||||
|
||||
void Reduce();
|
||||
|
||||
Node* DuplicateNode(Node* node);
|
||||
void DuplicateConditionIfNeeded(Node* node);
|
||||
void Enqueue(Node* node);
|
||||
void VisitNode(Node* node);
|
||||
void ProcessGraph();
|
||||
|
||||
private:
|
||||
Graph* const graph_;
|
||||
ZoneQueue<Node*> to_visit_;
|
||||
NodeMarker<bool> seen_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_BRANCH_CONDITION_DUPLICATOR_H_
|
@ -13,45 +13,26 @@
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/compiler/opcodes.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
namespace {
|
||||
|
||||
Decision DecideCondition(JSHeapBroker* broker, Node* const cond) {
|
||||
Node* unwrapped = SkipValueIdentities(cond);
|
||||
switch (unwrapped->opcode()) {
|
||||
case IrOpcode::kInt32Constant: {
|
||||
Int32Matcher m(unwrapped);
|
||||
return m.ResolvedValue() ? Decision::kTrue : Decision::kFalse;
|
||||
}
|
||||
case IrOpcode::kHeapConstant: {
|
||||
HeapObjectMatcher m(unwrapped);
|
||||
base::Optional<bool> maybe_result = m.Ref(broker).TryGetBooleanValue();
|
||||
if (!maybe_result.has_value()) return Decision::kUnknown;
|
||||
return *maybe_result ? Decision::kTrue : Decision::kFalse;
|
||||
}
|
||||
default:
|
||||
return Decision::kUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CommonOperatorReducer::CommonOperatorReducer(Editor* editor, Graph* graph,
|
||||
JSHeapBroker* broker,
|
||||
CommonOperatorBuilder* common,
|
||||
MachineOperatorBuilder* machine,
|
||||
Zone* temp_zone)
|
||||
Zone* temp_zone,
|
||||
BranchSemantics branch_semantics)
|
||||
: AdvancedReducer(editor),
|
||||
graph_(graph),
|
||||
broker_(broker),
|
||||
common_(common),
|
||||
machine_(machine),
|
||||
dead_(graph->NewNode(common->Dead())),
|
||||
zone_(temp_zone) {
|
||||
zone_(temp_zone),
|
||||
branch_semantics_(branch_semantics) {
|
||||
NodeProperties::SetType(dead_, Type::None());
|
||||
}
|
||||
|
||||
@ -86,6 +67,27 @@ Reduction CommonOperatorReducer::Reduce(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Decision CommonOperatorReducer::DecideCondition(Node* const cond) {
|
||||
Node* unwrapped = SkipValueIdentities(cond);
|
||||
switch (unwrapped->opcode()) {
|
||||
case IrOpcode::kInt32Constant: {
|
||||
DCHECK_EQ(branch_semantics_, BranchSemantics::kMachine);
|
||||
Int32Matcher m(unwrapped);
|
||||
return m.ResolvedValue() ? Decision::kTrue : Decision::kFalse;
|
||||
}
|
||||
case IrOpcode::kHeapConstant: {
|
||||
if (branch_semantics_ == BranchSemantics::kMachine) {
|
||||
return Decision::kTrue;
|
||||
}
|
||||
HeapObjectMatcher m(unwrapped);
|
||||
base::Optional<bool> maybe_result = m.Ref(broker_).TryGetBooleanValue();
|
||||
if (!maybe_result.has_value()) return Decision::kUnknown;
|
||||
return *maybe_result ? Decision::kTrue : Decision::kFalse;
|
||||
}
|
||||
default:
|
||||
return Decision::kUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
Reduction CommonOperatorReducer::ReduceBranch(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kBranch, node->opcode());
|
||||
@ -97,8 +99,8 @@ Reduction CommonOperatorReducer::ReduceBranch(Node* node) {
|
||||
// not (i.e. true being returned in the false case and vice versa).
|
||||
if (cond->opcode() == IrOpcode::kBooleanNot ||
|
||||
(cond->opcode() == IrOpcode::kSelect &&
|
||||
DecideCondition(broker(), cond->InputAt(1)) == Decision::kFalse &&
|
||||
DecideCondition(broker(), cond->InputAt(2)) == Decision::kTrue)) {
|
||||
DecideCondition(cond->InputAt(1)) == Decision::kFalse &&
|
||||
DecideCondition(cond->InputAt(2)) == Decision::kTrue)) {
|
||||
for (Node* const use : node->uses()) {
|
||||
switch (use->opcode()) {
|
||||
case IrOpcode::kIfTrue:
|
||||
@ -120,7 +122,7 @@ Reduction CommonOperatorReducer::ReduceBranch(Node* node) {
|
||||
node, common()->Branch(NegateBranchHint(BranchHintOf(node->op()))));
|
||||
return Changed(node);
|
||||
}
|
||||
Decision const decision = DecideCondition(broker(), cond);
|
||||
Decision const decision = DecideCondition(cond);
|
||||
if (decision == Decision::kUnknown) return NoChange();
|
||||
Node* const control = node->InputAt(1);
|
||||
for (Node* const use : node->uses()) {
|
||||
@ -160,7 +162,7 @@ Reduction CommonOperatorReducer::ReduceDeoptimizeConditional(Node* node) {
|
||||
: common()->DeoptimizeUnless(p.kind(), p.reason(), p.feedback()));
|
||||
return Changed(node);
|
||||
}
|
||||
Decision const decision = DecideCondition(broker(), condition);
|
||||
Decision const decision = DecideCondition(condition);
|
||||
if (decision == Decision::kUnknown) return NoChange();
|
||||
if (condition_is_true == (decision == Decision::kTrue)) {
|
||||
ReplaceWithValue(node, dead(), effect, control);
|
||||
@ -392,7 +394,7 @@ Reduction CommonOperatorReducer::ReduceSelect(Node* node) {
|
||||
Node* const vtrue = node->InputAt(1);
|
||||
Node* const vfalse = node->InputAt(2);
|
||||
if (vtrue == vfalse) return Replace(vtrue);
|
||||
switch (DecideCondition(broker(), cond)) {
|
||||
switch (DecideCondition(cond)) {
|
||||
case Decision::kTrue:
|
||||
return Replace(vtrue);
|
||||
case Decision::kFalse:
|
||||
@ -469,7 +471,7 @@ Reduction CommonOperatorReducer::ReduceSwitch(Node* node) {
|
||||
Reduction CommonOperatorReducer::ReduceStaticAssert(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kStaticAssert, node->opcode());
|
||||
Node* const cond = node->InputAt(0);
|
||||
Decision decision = DecideCondition(broker(), cond);
|
||||
Decision decision = DecideCondition(cond);
|
||||
if (decision == Decision::kTrue) {
|
||||
RelaxEffectsAndControls(node);
|
||||
return Changed(node);
|
||||
@ -483,7 +485,7 @@ Reduction CommonOperatorReducer::ReduceTrapConditional(Node* trap) {
|
||||
trap->opcode() == IrOpcode::kTrapUnless);
|
||||
bool trapping_condition = trap->opcode() == IrOpcode::kTrapIf;
|
||||
Node* const cond = trap->InputAt(0);
|
||||
Decision decision = DecideCondition(broker(), cond);
|
||||
Decision decision = DecideCondition(cond);
|
||||
|
||||
if (decision == Decision::kUnknown) {
|
||||
return NoChange();
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "src/base/compiler-specific.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -26,7 +27,8 @@ class V8_EXPORT_PRIVATE CommonOperatorReducer final
|
||||
public:
|
||||
CommonOperatorReducer(Editor* editor, Graph* graph, JSHeapBroker* broker,
|
||||
CommonOperatorBuilder* common,
|
||||
MachineOperatorBuilder* machine, Zone* temp_zone);
|
||||
MachineOperatorBuilder* machine, Zone* temp_zone,
|
||||
BranchSemantics branch_semantics);
|
||||
~CommonOperatorReducer() final = default;
|
||||
|
||||
const char* reducer_name() const override { return "CommonOperatorReducer"; }
|
||||
@ -48,6 +50,9 @@ class V8_EXPORT_PRIVATE CommonOperatorReducer final
|
||||
Reduction Change(Node* node, Operator const* op, Node* a);
|
||||
Reduction Change(Node* node, Operator const* op, Node* a, Node* b);
|
||||
|
||||
// Helper to determine if conditions are true or false.
|
||||
Decision DecideCondition(Node* const cond);
|
||||
|
||||
Graph* graph() const { return graph_; }
|
||||
JSHeapBroker* broker() const { return broker_; }
|
||||
CommonOperatorBuilder* common() const { return common_; }
|
||||
@ -60,6 +65,7 @@ class V8_EXPORT_PRIVATE CommonOperatorReducer final
|
||||
MachineOperatorBuilder* const machine_;
|
||||
Node* const dead_;
|
||||
Zone* zone_;
|
||||
BranchSemantics branch_semantics_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -32,6 +32,13 @@ class Operator;
|
||||
class Type;
|
||||
class Node;
|
||||
|
||||
// The semantics of IrOpcode::kBranch changes throughout the pipeline, and in
|
||||
// particular is not the same before SimplifiedLowering (JS semantics) and after
|
||||
// (machine branch semantics). Some passes are applied both before and after
|
||||
// SimplifiedLowering, and use the BranchSemantics enum to know how branches
|
||||
// should be treated.
|
||||
enum class BranchSemantics { kJS, kMachine };
|
||||
|
||||
// Prediction hint for branches.
|
||||
enum class BranchHint : uint8_t { kNone, kTrue, kFalse };
|
||||
|
||||
|
@ -3,15 +3,19 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/machine-operator-reducer.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/division-by-constant.h"
|
||||
#include "src/base/ieee754.h"
|
||||
#include "src/base/logging.h"
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "src/codegen/tnode.h"
|
||||
#include "src/compiler/diamond.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/js-operator.h"
|
||||
#include "src/compiler/machine-graph.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
@ -2187,6 +2191,124 @@ Reduction MachineOperatorReducer::ReduceFloat64RoundDown(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns true if |node| is a constant whose value is 0.
|
||||
bool IsZero(Node* node) {
|
||||
switch (node->opcode()) {
|
||||
#define CASE_IS_ZERO(opcode, matcher) \
|
||||
case IrOpcode::opcode: { \
|
||||
matcher m(node); \
|
||||
return m.Is(0); \
|
||||
}
|
||||
CASE_IS_ZERO(kInt32Constant, Int32Matcher)
|
||||
CASE_IS_ZERO(kInt64Constant, Int64Matcher)
|
||||
#undef CASE_IS_ZERO
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// If |node| is of the form "x == 0", then return "x" (in order to remove the
|
||||
// "== 0" part).
|
||||
base::Optional<Node*> TryGetInvertedCondition(Node* cond) {
|
||||
if (cond->opcode() == IrOpcode::kWord32Equal) {
|
||||
Int32BinopMatcher m(cond);
|
||||
if (IsZero(m.right().node())) {
|
||||
return m.left().node();
|
||||
}
|
||||
}
|
||||
return base::nullopt;
|
||||
}
|
||||
|
||||
struct SimplifiedCondition {
|
||||
Node* condition;
|
||||
bool is_inverted;
|
||||
};
|
||||
|
||||
// Tries to simplifies |cond| by removing all top-level "== 0". Everytime such a
|
||||
// construction is removed, the meaning of the comparison is inverted. This is
|
||||
// recorded by the variable |is_inverted| throughout this function, and returned
|
||||
// at the end. If |is_inverted| is true at the end, the caller should invert the
|
||||
// if/else branches following the comparison.
|
||||
base::Optional<SimplifiedCondition> TrySimplifyCompareZero(Node* cond) {
|
||||
bool is_inverted = false;
|
||||
bool changed = false;
|
||||
base::Optional<Node*> new_cond;
|
||||
while ((new_cond = TryGetInvertedCondition(cond)).has_value()) {
|
||||
cond = *new_cond;
|
||||
is_inverted = !is_inverted;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
return SimplifiedCondition{cond, is_inverted};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void MachineOperatorReducer::SwapBranches(Node* node) {
|
||||
DCHECK_EQ(node->opcode(), IrOpcode::kBranch);
|
||||
for (Node* const use : node->uses()) {
|
||||
switch (use->opcode()) {
|
||||
case IrOpcode::kIfTrue:
|
||||
NodeProperties::ChangeOp(use, common()->IfFalse());
|
||||
break;
|
||||
case IrOpcode::kIfFalse:
|
||||
NodeProperties::ChangeOp(use, common()->IfTrue());
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
NodeProperties::ChangeOp(
|
||||
node, common()->Branch(NegateBranchHint(BranchHintOf(node->op()))));
|
||||
}
|
||||
|
||||
// If |node| is a branch, removes all top-level 32-bit "== 0" from |node|.
|
||||
Reduction MachineOperatorReducer::SimplifyBranch(Node* node) {
|
||||
Node* cond = node->InputAt(0);
|
||||
if (auto simplified = TrySimplifyCompareZero(cond)) {
|
||||
node->ReplaceInput(0, simplified->condition);
|
||||
if (simplified->is_inverted) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kBranch:
|
||||
SwapBranches(node);
|
||||
break;
|
||||
case IrOpcode::kTrapIf:
|
||||
NodeProperties::ChangeOp(node,
|
||||
common()->TrapUnless(TrapIdOf(node->op())));
|
||||
break;
|
||||
case IrOpcode::kTrapUnless:
|
||||
NodeProperties::ChangeOp(node,
|
||||
common()->TrapIf(TrapIdOf(node->op())));
|
||||
break;
|
||||
case IrOpcode::kDeoptimizeIf: {
|
||||
DeoptimizeParameters p = DeoptimizeParametersOf(node->op());
|
||||
NodeProperties::ChangeOp(
|
||||
node,
|
||||
common()->DeoptimizeUnless(p.kind(), p.reason(), p.feedback()));
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kDeoptimizeUnless: {
|
||||
DeoptimizeParameters p = DeoptimizeParametersOf(node->op());
|
||||
NodeProperties::ChangeOp(
|
||||
node, common()->DeoptimizeIf(p.kind(), p.reason(), p.feedback()));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
return Changed(node);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction MachineOperatorReducer::ReduceConditional(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kBranch ||
|
||||
node->opcode() == IrOpcode::kDeoptimizeIf ||
|
||||
@ -2197,17 +2319,18 @@ Reduction MachineOperatorReducer::ReduceConditional(Node* node) {
|
||||
// Reductions involving control flow happen elsewhere. Non-zero inputs are
|
||||
// considered true in all conditional ops.
|
||||
NodeMatcher condition(NodeProperties::GetValueInput(node, 0));
|
||||
Reduction reduction = NoChange();
|
||||
if (condition.IsTruncateInt64ToInt32()) {
|
||||
if (auto replacement =
|
||||
ReduceConditionalN<Word64Adapter>(condition.node())) {
|
||||
NodeProperties::ReplaceValueInput(node, *replacement, 0);
|
||||
return Changed(node);
|
||||
reduction = Changed(node);
|
||||
}
|
||||
} else if (auto replacement = ReduceConditionalN<Word32Adapter>(node)) {
|
||||
NodeProperties::ReplaceValueInput(node, *replacement, 0);
|
||||
return Changed(node);
|
||||
reduction = Changed(node);
|
||||
}
|
||||
return NoChange();
|
||||
return reduction.FollowedBy(SimplifyBranch(node));
|
||||
}
|
||||
|
||||
template <typename WordNAdapter>
|
||||
|
@ -131,6 +131,12 @@ class V8_EXPORT_PRIVATE MachineOperatorReducer final
|
||||
template <typename WordNAdapter>
|
||||
Reduction ReduceWordNXor(Node* node);
|
||||
|
||||
// Tries to simplify "if(x == 0)" by removing the "== 0" and inverting
|
||||
// branches.
|
||||
Reduction SimplifyBranch(Node* node);
|
||||
// Helper for SimplifyBranch; swaps the if/else of a branch.
|
||||
void SwapBranches(Node* node);
|
||||
|
||||
// Helper for ReduceConditional. Does not perform the actual reduction; just
|
||||
// returns a new Node that could be used as the input to the condition.
|
||||
template <typename WordNAdapter>
|
||||
|
@ -28,10 +28,12 @@
|
||||
#include "src/compiler/backend/register-allocator-verifier.h"
|
||||
#include "src/compiler/backend/register-allocator.h"
|
||||
#include "src/compiler/basic-block-instrumentor.h"
|
||||
#include "src/compiler/branch-condition-duplicator.h"
|
||||
#include "src/compiler/branch-elimination.h"
|
||||
#include "src/compiler/bytecode-graph-builder.h"
|
||||
#include "src/compiler/checkpoint-elimination.h"
|
||||
#include "src/compiler/common-operator-reducer.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/compilation-dependencies.h"
|
||||
#include "src/compiler/compiler-source-position-table.h"
|
||||
#include "src/compiler/constant-folding-reducer.h"
|
||||
@ -1337,9 +1339,9 @@ struct InliningPhase {
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
CheckpointElimination checkpoint_elimination(&graph_reducer);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kJS);
|
||||
JSCallReducer::Flags call_reducer_flags = JSCallReducer::kNoFlags;
|
||||
if (data->info()->bailout_on_uninitialized()) {
|
||||
call_reducer_flags |= JSCallReducer::kBailoutOnUninitialized;
|
||||
@ -1403,9 +1405,9 @@ struct JSWasmInliningPhase {
|
||||
data->broker(), data->jsgraph()->Dead());
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kMachine);
|
||||
JSInliningHeuristic inlining(&graph_reducer, temp_zone, data->info(),
|
||||
data->jsgraph(), data->broker(),
|
||||
data->source_positions(),
|
||||
@ -1508,12 +1510,12 @@ struct TypedLoweringPhase {
|
||||
&graph_reducer, data->jsgraph(), data->broker());
|
||||
TypedOptimization typed_optimization(&graph_reducer, data->dependencies(),
|
||||
data->jsgraph(), data->broker());
|
||||
SimplifiedOperatorReducer simple_reducer(&graph_reducer, data->jsgraph(),
|
||||
data->broker());
|
||||
SimplifiedOperatorReducer simple_reducer(
|
||||
&graph_reducer, data->jsgraph(), data->broker(), BranchSemantics::kJS);
|
||||
CheckpointElimination checkpoint_elimination(&graph_reducer);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kJS);
|
||||
AddReducer(data, &graph_reducer, &dead_code_elimination);
|
||||
|
||||
AddReducer(data, &graph_reducer, &create_lowering);
|
||||
@ -1737,13 +1739,14 @@ struct EarlyOptimizationPhase {
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
SimplifiedOperatorReducer simple_reducer(&graph_reducer, data->jsgraph(),
|
||||
data->broker());
|
||||
data->broker(),
|
||||
BranchSemantics::kMachine);
|
||||
RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone);
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
MachineOperatorReducer machine_reducer(&graph_reducer, data->jsgraph());
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kMachine);
|
||||
AddReducer(data, &graph_reducer, &dead_code_elimination);
|
||||
AddReducer(data, &graph_reducer, &simple_reducer);
|
||||
AddReducer(data, &graph_reducer, &redundancy_elimination);
|
||||
@ -1811,9 +1814,9 @@ struct EffectControlLinearizationPhase {
|
||||
data->observe_node_manager());
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kMachine);
|
||||
AddReducer(data, &graph_reducer, &dead_code_elimination);
|
||||
AddReducer(data, &graph_reducer, &common_reducer);
|
||||
graph_reducer.ReduceGraph();
|
||||
@ -1855,9 +1858,9 @@ struct LoadEliminationPhase {
|
||||
temp_zone);
|
||||
CheckpointElimination checkpoint_elimination(&graph_reducer);
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kJS);
|
||||
TypedOptimization typed_optimization(&graph_reducer, data->dependencies(),
|
||||
data->jsgraph(), data->broker());
|
||||
ConstantFoldingReducer constant_folding_reducer(
|
||||
@ -1920,9 +1923,9 @@ struct LateOptimizationPhase {
|
||||
data->common(), temp_zone);
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
MachineOperatorReducer machine_reducer(&graph_reducer, data->jsgraph());
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kMachine);
|
||||
JSGraphAssembler graph_assembler(data->jsgraph(), temp_zone);
|
||||
SelectLowering select_lowering(&graph_assembler, data->graph());
|
||||
AddReducer(data, &graph_reducer, &branch_condition_elimination);
|
||||
@ -1976,6 +1979,16 @@ struct DecompressionOptimizationPhase {
|
||||
}
|
||||
};
|
||||
|
||||
struct BranchConditionDuplicationPhase {
|
||||
DECL_PIPELINE_PHASE_CONSTANTS(BranchConditionDuplication)
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
BranchConditionDuplicator compare_zero_branch_optimizer(temp_zone,
|
||||
data->graph());
|
||||
compare_zero_branch_optimizer.Reduce();
|
||||
}
|
||||
};
|
||||
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
struct WasmOptimizationPhase {
|
||||
DECL_PIPELINE_PHASE_CONSTANTS(WasmOptimization)
|
||||
@ -1994,9 +2007,9 @@ struct WasmOptimizationPhase {
|
||||
allow_signalling_nan);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kMachine);
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
CsaLoadElimination load_elimination(&graph_reducer, data->jsgraph(),
|
||||
temp_zone);
|
||||
@ -2020,9 +2033,9 @@ struct WasmOptimizationPhase {
|
||||
allow_signalling_nan);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kMachine);
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
BranchElimination branch_condition_elimination(
|
||||
&graph_reducer, data->jsgraph(), temp_zone, data->source_positions());
|
||||
@ -2053,9 +2066,9 @@ struct CsaEarlyOptimizationPhase {
|
||||
true);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kMachine);
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
CsaLoadElimination load_elimination(&graph_reducer, data->jsgraph(),
|
||||
temp_zone);
|
||||
@ -2075,9 +2088,9 @@ struct CsaEarlyOptimizationPhase {
|
||||
true);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kMachine);
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
BranchElimination branch_condition_elimination(
|
||||
&graph_reducer, data->jsgraph(), temp_zone, data->source_positions());
|
||||
@ -2104,9 +2117,9 @@ struct CsaOptimizationPhase {
|
||||
data->common(), temp_zone);
|
||||
MachineOperatorReducer machine_reducer(&graph_reducer, data->jsgraph(),
|
||||
allow_signalling_nan);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->broker(), data->common(),
|
||||
data->machine(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(
|
||||
&graph_reducer, data->graph(), data->broker(), data->common(),
|
||||
data->machine(), temp_zone, BranchSemantics::kMachine);
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
AddReducer(data, &graph_reducer, &branch_condition_elimination);
|
||||
AddReducer(data, &graph_reducer, &dead_code_elimination);
|
||||
@ -2787,6 +2800,9 @@ bool PipelineImpl::OptimizeGraph(Linkage* linkage) {
|
||||
Run<DecompressionOptimizationPhase>();
|
||||
RunPrintAndVerify(DecompressionOptimizationPhase::phase_name(), true);
|
||||
|
||||
Run<BranchConditionDuplicationPhase>();
|
||||
RunPrintAndVerify(BranchConditionDuplicationPhase::phase_name(), true);
|
||||
|
||||
data->source_positions()->RemoveDecorator();
|
||||
if (data->info()->trace_turbo_json()) {
|
||||
data->node_origins()->RemoveDecorator();
|
||||
|
@ -4025,7 +4025,8 @@ class RepresentationSelector {
|
||||
ProcessInput<T>(node, 0, UseInfo::Any());
|
||||
return SetOutput<T>(node, MachineRepresentation::kNone);
|
||||
case IrOpcode::kStaticAssert:
|
||||
return VisitUnop<T>(node, UseInfo::Any(),
|
||||
DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
|
||||
return VisitUnop<T>(node, UseInfo::Bool(),
|
||||
MachineRepresentation::kTagged);
|
||||
case IrOpcode::kAssertType:
|
||||
return VisitUnop<T>(node, UseInfo::AnyTagged(),
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
#include "src/compiler/simplified-operator-reducer.h"
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/js-graph.h"
|
||||
#include "src/compiler/js-heap-broker.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/opcodes.h"
|
||||
#include "src/compiler/operator-properties.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
#include "src/compiler/type-cache.h"
|
||||
@ -33,10 +35,13 @@ Decision DecideObjectIsSmi(Node* const input) {
|
||||
|
||||
} // namespace
|
||||
|
||||
SimplifiedOperatorReducer::SimplifiedOperatorReducer(Editor* editor,
|
||||
JSGraph* jsgraph,
|
||||
JSHeapBroker* broker)
|
||||
: AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
|
||||
SimplifiedOperatorReducer::SimplifiedOperatorReducer(
|
||||
Editor* editor, JSGraph* jsgraph, JSHeapBroker* broker,
|
||||
BranchSemantics branch_semantics)
|
||||
: AdvancedReducer(editor),
|
||||
jsgraph_(jsgraph),
|
||||
broker_(broker),
|
||||
branch_semantics_(branch_semantics) {}
|
||||
|
||||
SimplifiedOperatorReducer::~SimplifiedOperatorReducer() = default;
|
||||
|
||||
@ -277,7 +282,11 @@ Reduction SimplifiedOperatorReducer::Change(Node* node, const Operator* op,
|
||||
}
|
||||
|
||||
Reduction SimplifiedOperatorReducer::ReplaceBoolean(bool value) {
|
||||
return Replace(jsgraph()->BooleanConstant(value));
|
||||
if (branch_semantics_ == BranchSemantics::kJS) {
|
||||
return Replace(jsgraph()->BooleanConstant(value));
|
||||
} else {
|
||||
return ReplaceInt32(value);
|
||||
}
|
||||
}
|
||||
|
||||
Reduction SimplifiedOperatorReducer::ReplaceFloat64(double value) {
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "src/base/compiler-specific.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -27,7 +28,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorReducer final
|
||||
: public NON_EXPORTED_BASE(AdvancedReducer) {
|
||||
public:
|
||||
SimplifiedOperatorReducer(Editor* editor, JSGraph* jsgraph,
|
||||
JSHeapBroker* broker);
|
||||
JSHeapBroker* broker,
|
||||
BranchSemantics branch_semantics);
|
||||
~SimplifiedOperatorReducer() final;
|
||||
SimplifiedOperatorReducer(const SimplifiedOperatorReducer&) = delete;
|
||||
SimplifiedOperatorReducer& operator=(const SimplifiedOperatorReducer&) =
|
||||
@ -60,6 +62,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorReducer final
|
||||
|
||||
JSGraph* const jsgraph_;
|
||||
JSHeapBroker* const broker_;
|
||||
BranchSemantics branch_semantics_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -322,6 +322,7 @@ class RuntimeCallTimer final {
|
||||
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AllocateGeneralRegisters) \
|
||||
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AssembleCode) \
|
||||
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AssignSpillSlots) \
|
||||
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BranchConditionDuplication) \
|
||||
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildLiveRangeBundles) \
|
||||
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildLiveRanges) \
|
||||
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BytecodeGraphBuilder) \
|
||||
|
@ -28,19 +28,21 @@ class CommonOperatorReducerTest : public GraphTest {
|
||||
protected:
|
||||
Reduction Reduce(
|
||||
AdvancedReducer::Editor* editor, Node* node,
|
||||
BranchSemantics branch_semantics,
|
||||
MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags) {
|
||||
JSHeapBroker broker(isolate(), zone());
|
||||
MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(),
|
||||
flags);
|
||||
CommonOperatorReducer reducer(editor, graph(), &broker, common(), &machine,
|
||||
zone());
|
||||
zone(), branch_semantics);
|
||||
return reducer.Reduce(node);
|
||||
}
|
||||
|
||||
Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
|
||||
MachineOperatorBuilder::kNoFlags) {
|
||||
Reduction Reduce(
|
||||
Node* node, BranchSemantics branch_semantics,
|
||||
MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags) {
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
return Reduce(&editor, node, flags);
|
||||
return Reduce(&editor, node, branch_semantics, flags);
|
||||
}
|
||||
|
||||
MachineOperatorBuilder* machine() { return &machine_; }
|
||||
@ -84,7 +86,7 @@ TEST_F(CommonOperatorReducerTest, BranchWithInt32ZeroConstant) {
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Replace(if_true, IsDead()));
|
||||
EXPECT_CALL(editor, Replace(if_false, control));
|
||||
Reduction const r = Reduce(&editor, branch);
|
||||
Reduction const r = Reduce(&editor, branch, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsDead());
|
||||
}
|
||||
@ -101,7 +103,7 @@ TEST_F(CommonOperatorReducerTest, BranchWithInt32OneConstant) {
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Replace(if_true, control));
|
||||
EXPECT_CALL(editor, Replace(if_false, IsDead()));
|
||||
Reduction const r = Reduce(&editor, branch);
|
||||
Reduction const r = Reduce(&editor, branch, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsDead());
|
||||
}
|
||||
@ -118,7 +120,7 @@ TEST_F(CommonOperatorReducerTest, BranchWithFalseConstant) {
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Replace(if_true, IsDead()));
|
||||
EXPECT_CALL(editor, Replace(if_false, control));
|
||||
Reduction const r = Reduce(&editor, branch);
|
||||
Reduction const r = Reduce(&editor, branch, BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsDead());
|
||||
}
|
||||
@ -135,7 +137,7 @@ TEST_F(CommonOperatorReducerTest, BranchWithTrueConstant) {
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Replace(if_true, control));
|
||||
EXPECT_CALL(editor, Replace(if_false, IsDead()));
|
||||
Reduction const r = Reduce(&editor, branch);
|
||||
Reduction const r = Reduce(&editor, branch, BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsDead());
|
||||
}
|
||||
@ -151,7 +153,7 @@ TEST_F(CommonOperatorReducerTest, BranchWithBooleanNot) {
|
||||
graph()->NewNode(simplified()->BooleanNot(), value), control);
|
||||
Node* const if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||
Node* const if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
Reduction const r = Reduce(branch);
|
||||
Reduction const r = Reduce(branch, BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(branch, r.replacement());
|
||||
EXPECT_THAT(branch, IsBranch(value, control));
|
||||
@ -172,7 +174,7 @@ TEST_F(CommonOperatorReducerTest, BranchWithSelect) {
|
||||
control);
|
||||
Node* const if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||
Node* const if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
Reduction const r = Reduce(branch);
|
||||
Reduction const r = Reduce(branch, BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(branch, r.replacement());
|
||||
EXPECT_THAT(branch, IsBranch(value, control));
|
||||
@ -193,7 +195,8 @@ TEST_F(CommonOperatorReducerTest, MergeOfUnusedDiamond0) {
|
||||
Node* const if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||
Node* const if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
Reduction const r =
|
||||
Reduce(graph()->NewNode(common()->Merge(2), if_true, if_false));
|
||||
Reduce(graph()->NewNode(common()->Merge(2), if_true, if_false),
|
||||
BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(control, r.replacement());
|
||||
EXPECT_THAT(branch, IsDead());
|
||||
@ -207,7 +210,8 @@ TEST_F(CommonOperatorReducerTest, MergeOfUnusedDiamond1) {
|
||||
Node* const if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||
Node* const if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
Reduction const r =
|
||||
Reduce(graph()->NewNode(common()->Merge(2), if_false, if_true));
|
||||
Reduce(graph()->NewNode(common()->Merge(2), if_false, if_true),
|
||||
BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(control, r.replacement());
|
||||
EXPECT_THAT(branch, IsDead());
|
||||
@ -236,8 +240,10 @@ TEST_F(CommonOperatorReducerTest, EffectPhiWithMerge) {
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Revisit(merge));
|
||||
Reduction r =
|
||||
Reduce(&editor, graph()->NewNode(common()->EffectPhi(value_input_count),
|
||||
input_count, inputs));
|
||||
Reduce(&editor,
|
||||
graph()->NewNode(common()->EffectPhi(value_input_count),
|
||||
input_count, inputs),
|
||||
BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(input, r.replacement());
|
||||
}
|
||||
@ -253,7 +259,7 @@ TEST_F(CommonOperatorReducerTest, EffectPhiWithLoop) {
|
||||
ephi->ReplaceInput(1, ephi);
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Revisit(loop));
|
||||
Reduction const r = Reduce(&editor, ephi);
|
||||
Reduction const r = Reduce(&editor, ephi, BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(e0, r.replacement());
|
||||
}
|
||||
@ -281,9 +287,11 @@ TEST_F(CommonOperatorReducerTest, PhiWithMerge) {
|
||||
inputs[value_input_count] = merge;
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Revisit(merge));
|
||||
Reduction r = Reduce(
|
||||
&editor, graph()->NewNode(common()->Phi(rep, value_input_count),
|
||||
input_count, inputs));
|
||||
Reduction r =
|
||||
Reduce(&editor,
|
||||
graph()->NewNode(common()->Phi(rep, value_input_count),
|
||||
input_count, inputs),
|
||||
BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(input, r.replacement());
|
||||
}
|
||||
@ -301,7 +309,7 @@ TEST_F(CommonOperatorReducerTest, PhiWithLoop) {
|
||||
phi->ReplaceInput(1, phi);
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Revisit(loop));
|
||||
Reduction const r = Reduce(&editor, phi);
|
||||
Reduction const r = Reduce(&editor, phi, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(p0, r.replacement());
|
||||
}
|
||||
@ -321,7 +329,7 @@ TEST_F(CommonOperatorReducerTest, PhiToFloat32Abs) {
|
||||
common()->Phi(MachineRepresentation::kFloat32, 2), vtrue, vfalse, merge);
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Revisit(merge));
|
||||
Reduction r = Reduce(&editor, phi);
|
||||
Reduction r = Reduce(&editor, phi, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFloat32Abs(p0));
|
||||
}
|
||||
@ -341,7 +349,7 @@ TEST_F(CommonOperatorReducerTest, PhiToFloat64Abs) {
|
||||
common()->Phi(MachineRepresentation::kFloat64, 2), vtrue, vfalse, merge);
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Revisit(merge));
|
||||
Reduction r = Reduce(&editor, phi);
|
||||
Reduction r = Reduce(&editor, phi, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFloat64Abs(p0));
|
||||
}
|
||||
@ -370,7 +378,7 @@ TEST_F(CommonOperatorReducerTest, ReturnWithPhiAndEffectPhiAndMerge) {
|
||||
graph()->SetEnd(graph()->NewNode(common()->End(1), ret));
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Replace(merge, IsDead()));
|
||||
Reduction const r = Reduce(&editor, ret);
|
||||
Reduction const r = Reduce(&editor, ret, BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsDead());
|
||||
EXPECT_THAT(graph()->end(), IsEnd(ret, IsReturn(vtrue, etrue, if_true),
|
||||
@ -400,7 +408,7 @@ TEST_F(CommonOperatorReducerTest, MultiReturnWithPhiAndEffectPhiAndMerge) {
|
||||
graph()->NewNode(common()->Return(2), zero, phi1, phi2, ephi, merge);
|
||||
graph()->SetEnd(graph()->NewNode(common()->End(1), ret));
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
Reduction const r = Reduce(&editor, ret);
|
||||
Reduction const r = Reduce(&editor, ret, BranchSemantics::kJS);
|
||||
// For now a return with multiple return values should not be reduced.
|
||||
ASSERT_TRUE(!r.Changed());
|
||||
}
|
||||
@ -414,7 +422,8 @@ TEST_F(CommonOperatorReducerTest, SelectWithSameThenAndElse) {
|
||||
TRACED_FOREACH(BranchHint, hint, kBranchHints) {
|
||||
TRACED_FOREACH(MachineRepresentation, rep, kMachineRepresentations) {
|
||||
Reduction r = Reduce(
|
||||
graph()->NewNode(common()->Select(rep, hint), input, input, input));
|
||||
graph()->NewNode(common()->Select(rep, hint), input, input, input),
|
||||
BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(input, r.replacement());
|
||||
}
|
||||
@ -428,7 +437,7 @@ TEST_F(CommonOperatorReducerTest, SelectWithInt32ZeroConstant) {
|
||||
Node* select =
|
||||
graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
|
||||
Int32Constant(0), p0, p1);
|
||||
Reduction r = Reduce(select);
|
||||
Reduction r = Reduce(select, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(p1, r.replacement());
|
||||
}
|
||||
@ -440,7 +449,7 @@ TEST_F(CommonOperatorReducerTest, SelectWithInt32OneConstant) {
|
||||
Node* select =
|
||||
graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
|
||||
Int32Constant(1), p0, p1);
|
||||
Reduction r = Reduce(select);
|
||||
Reduction r = Reduce(select, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(p0, r.replacement());
|
||||
}
|
||||
@ -452,7 +461,7 @@ TEST_F(CommonOperatorReducerTest, SelectWithFalseConstant) {
|
||||
Node* select =
|
||||
graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
|
||||
FalseConstant(), p0, p1);
|
||||
Reduction r = Reduce(select);
|
||||
Reduction r = Reduce(select, BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(p1, r.replacement());
|
||||
}
|
||||
@ -463,7 +472,7 @@ TEST_F(CommonOperatorReducerTest, SelectWithTrueConstant) {
|
||||
Node* p1 = Parameter(1);
|
||||
Node* select = graph()->NewNode(
|
||||
common()->Select(MachineRepresentation::kTagged), TrueConstant(), p0, p1);
|
||||
Reduction r = Reduce(select);
|
||||
Reduction r = Reduce(select, BranchSemantics::kJS);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(p0, r.replacement());
|
||||
}
|
||||
@ -476,7 +485,7 @@ TEST_F(CommonOperatorReducerTest, SelectToFloat32Abs) {
|
||||
Node* select =
|
||||
graph()->NewNode(common()->Select(MachineRepresentation::kFloat32), check,
|
||||
p0, graph()->NewNode(machine()->Float32Sub(), c0, p0));
|
||||
Reduction r = Reduce(select);
|
||||
Reduction r = Reduce(select, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFloat32Abs(p0));
|
||||
}
|
||||
@ -489,7 +498,7 @@ TEST_F(CommonOperatorReducerTest, SelectToFloat64Abs) {
|
||||
Node* select =
|
||||
graph()->NewNode(common()->Select(MachineRepresentation::kFloat64), check,
|
||||
p0, graph()->NewNode(machine()->Float64Sub(), c0, p0));
|
||||
Reduction r = Reduce(select);
|
||||
Reduction r = Reduce(select, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFloat64Abs(p0));
|
||||
}
|
||||
@ -506,7 +515,7 @@ TEST_F(CommonOperatorReducerTest, SwitchInputMatchesCaseWithDefault) {
|
||||
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Replace(if_1, control));
|
||||
Reduction r = Reduce(&editor, sw);
|
||||
Reduction r = Reduce(&editor, sw, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsDead());
|
||||
}
|
||||
@ -520,7 +529,7 @@ TEST_F(CommonOperatorReducerTest, SwitchInputMatchesDefaultWithCase) {
|
||||
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Replace(if_default, control));
|
||||
Reduction r = Reduce(&editor, sw);
|
||||
Reduction r = Reduce(&editor, sw, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsDead());
|
||||
}
|
||||
@ -535,7 +544,7 @@ TEST_F(CommonOperatorReducerTest, SwitchInputMatchesCaseExtraCaseWithDefault) {
|
||||
|
||||
StrictMock<MockAdvancedReducerEditor> editor;
|
||||
EXPECT_CALL(editor, Replace(if_0, control));
|
||||
Reduction r = Reduce(&editor, sw);
|
||||
Reduction r = Reduce(&editor, sw, BranchSemantics::kMachine);
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsDead());
|
||||
}
|
||||
|
@ -35,7 +35,8 @@ class SimplifiedOperatorReducerTest : public GraphTest {
|
||||
JSGraph jsgraph(isolate(), graph(), common(), &javascript, simplified(),
|
||||
&machine);
|
||||
GraphReducer graph_reducer(zone(), graph(), tick_counter(), broker());
|
||||
SimplifiedOperatorReducer reducer(&graph_reducer, &jsgraph, broker());
|
||||
SimplifiedOperatorReducer reducer(&graph_reducer, &jsgraph, broker(),
|
||||
BranchSemantics::kJS);
|
||||
return reducer.Reduce(node);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user