| Index: src/compiler/common-operator-reducer.cc
|
| diff --git a/src/compiler/common-operator-reducer.cc b/src/compiler/common-operator-reducer.cc
|
| index 23b2fc16a8bc5b87d7e050c70bb4fb6e534e0b8f..35f405bf3d82f4de9e1c9ef4ceb34e3b1cf4fb40 100644
|
| --- a/src/compiler/common-operator-reducer.cc
|
| +++ b/src/compiler/common-operator-reducer.cc
|
| @@ -16,8 +16,39 @@ namespace v8 {
|
| namespace internal {
|
| namespace compiler {
|
|
|
| +namespace {
|
| +
|
| +enum class Decision { kUnknown, kTrue, kFalse };
|
| +
|
| +Decision DecideCondition(Node* const cond) {
|
| + switch (cond->opcode()) {
|
| + case IrOpcode::kInt32Constant: {
|
| + Int32Matcher mcond(cond);
|
| + return mcond.Value() ? Decision::kTrue : Decision::kFalse;
|
| + }
|
| + case IrOpcode::kInt64Constant: {
|
| + Int64Matcher mcond(cond);
|
| + return mcond.Value() ? Decision::kTrue : Decision::kFalse;
|
| + }
|
| + case IrOpcode::kHeapConstant: {
|
| + HeapObjectMatcher<HeapObject> mcond(cond);
|
| + return mcond.Value().handle()->BooleanValue() ? Decision::kTrue
|
| + : Decision::kFalse;
|
| + }
|
| + default:
|
| + return Decision::kUnknown;
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +
|
| Reduction CommonOperatorReducer::Reduce(Node* node) {
|
| switch (node->opcode()) {
|
| + case IrOpcode::kBranch:
|
| + return ReduceBranch(node);
|
| + case IrOpcode::kMerge:
|
| + return ReduceMerge(node);
|
| case IrOpcode::kEffectPhi:
|
| return ReduceEffectPhi(node);
|
| case IrOpcode::kPhi:
|
| @@ -31,6 +62,66 @@ Reduction CommonOperatorReducer::Reduce(Node* node) {
|
| }
|
|
|
|
|
| +Reduction CommonOperatorReducer::ReduceBranch(Node* node) {
|
| + DCHECK_EQ(IrOpcode::kBranch, node->opcode());
|
| + Node* const cond = node->InputAt(0);
|
| + Decision const decision = DecideCondition(cond);
|
| + if (decision == Decision::kUnknown) return NoChange();
|
| + Node* const control = node->InputAt(1);
|
| + node->set_op(common()->Dead());
|
| + node->TrimInputCount(0);
|
| + for (Node* const use : node->uses()) {
|
| + switch (use->opcode()) {
|
| + case IrOpcode::kIfTrue:
|
| + Replace(use, (decision == Decision::kTrue) ? control : node);
|
| + break;
|
| + case IrOpcode::kIfFalse:
|
| + Replace(use, (decision == Decision::kFalse) ? control : node);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + }
|
| + return Changed(node);
|
| +}
|
| +
|
| +
|
| +Reduction CommonOperatorReducer::ReduceMerge(Node* node) {
|
| + DCHECK_EQ(IrOpcode::kMerge, node->opcode());
|
| + //
|
| + // Check if this is a merge that belongs to an unused diamond, which means
|
| + // that:
|
| + //
|
| + // a) the {Merge} has no {Phi} or {EffectPhi} uses, and
|
| + // b) the {Merge} has two inputs, one {IfTrue} and one {IfFalse}, which are
|
| + // both owned by the Merge, and
|
| + // c) and the {IfTrue} and {IfFalse} nodes point to the same {Branch}.
|
| + //
|
| + if (node->InputCount() == 2) {
|
| + for (Node* const use : node->uses()) {
|
| + if (IrOpcode::IsPhiOpcode(use->opcode())) return NoChange();
|
| + }
|
| + Node* if_true = node->InputAt(0);
|
| + Node* if_false = node->InputAt(1);
|
| + if (if_true->opcode() != IrOpcode::kIfTrue) std::swap(if_true, if_false);
|
| + if (if_true->opcode() == IrOpcode::kIfTrue &&
|
| + if_false->opcode() == IrOpcode::kIfFalse &&
|
| + if_true->InputAt(0) == if_false->InputAt(0) && if_true->OwnedBy(node) &&
|
| + if_false->OwnedBy(node)) {
|
| + Node* const branch = if_true->InputAt(0);
|
| + DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
|
| + DCHECK(branch->OwnedBy(if_true, if_false));
|
| + Node* const control = branch->InputAt(1);
|
| + // Mark the {branch} as {Dead}.
|
| + branch->set_op(common()->Dead());
|
| + branch->TrimInputCount(0);
|
| + return Replace(control);
|
| + }
|
| + }
|
| + return NoChange();
|
| +}
|
| +
|
| +
|
| Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) {
|
| DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
|
| int const input_count = node->InputCount() - 1;
|
| @@ -146,11 +237,15 @@ 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(cond)) {
|
| + case Decision::kTrue:
|
| + return Replace(vtrue);
|
| + case Decision::kFalse:
|
| + return Replace(vfalse);
|
| + case Decision::kUnknown:
|
| + break;
|
| + }
|
| switch (cond->opcode()) {
|
| - case IrOpcode::kHeapConstant: {
|
| - HeapObjectMatcher<HeapObject> mcond(cond);
|
| - return Replace(mcond.Value().handle()->BooleanValue() ? vtrue : vfalse);
|
| - }
|
| case IrOpcode::kFloat32LessThan: {
|
| Float32BinopMatcher mcond(cond);
|
| if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
|
|
|