Commit fa7c3476 authored by titzer's avatar titzer Committed by Commit bot

[turbofan] Improve branch folding over phis and ranges.

R=mstarzinger@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1057843002

Cr-Commit-Position: refs/heads/master@{#27591}
parent 260ab451
......@@ -433,7 +433,7 @@ class ControlReducerImpl {
}
// Try to statically fold a condition.
Decision DecideCondition(Node* cond) {
Decision DecideCondition(Node* cond, bool recurse = true) {
switch (cond->opcode()) {
case IrOpcode::kInt32Constant:
return Int32Matcher(cond).Is(0) ? kFalse : kTrue;
......@@ -444,14 +444,29 @@ class ControlReducerImpl {
case IrOpcode::kHeapConstant: {
Handle<Object> object =
HeapObjectMatcher<Object>(cond).Value().handle();
if (object->IsTrue()) return kTrue;
if (object->IsFalse()) return kFalse;
// TODO(turbofan): decide more conditions for heap constants.
break;
return object->BooleanValue() ? kTrue : kFalse;
}
case IrOpcode::kPhi: {
if (!recurse) return kUnknown; // Only go one level deep checking phis.
Decision result = kUnknown;
// Check if all inputs to a phi result in the same decision.
for (int i = cond->op()->ValueInputCount() - 1; i >= 0; i--) {
// Recurse only one level, since phis can be involved in cycles.
Decision decision = DecideCondition(cond->InputAt(i), false);
if (decision == kUnknown) return kUnknown;
if (result == kUnknown) result = decision;
if (result != decision) return kUnknown;
}
return result;
}
default:
break;
}
if (NodeProperties::IsTyped(cond)) {
// If the node has a range type, check whether the range excludes 0.
Type* type = NodeProperties::GetBounds(cond).upper;
if (type->IsRange() && (type->Min() > 0 || type->Max() < 0)) return kTrue;
}
return kUnknown;
}
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "src/compiler/control-reducer.h"
#include "src/compiler/graph-visualizer.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/machine-operator.h"
......@@ -20,14 +21,34 @@ namespace v8 {
namespace internal {
namespace compiler {
class ControlReducerTest : public GraphTest {
class ControlReducerTest : public TypedGraphTest {
public:
ControlReducerTest()
: TypedGraphTest(1),
machine_(zone()),
javascript_(zone()),
jsgraph_(isolate(), graph(), common(), &javascript_, &machine_) {}
protected:
MachineOperatorBuilder machine_;
JSOperatorBuilder javascript_;
JSGraph jsgraph_;
void ReduceGraph() {
JSOperatorBuilder javascript(zone());
MachineOperatorBuilder machine(zone());
JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine);
ControlReducer::ReduceGraph(zone(), &jsgraph, common());
if (FLAG_trace_turbo_graph) {
OFStream os(stdout);
os << "-- Graph before control reduction" << std::endl;
os << AsRPO(*graph());
}
ControlReducer::ReduceGraph(zone(), jsgraph(), common());
if (FLAG_trace_turbo_graph) {
OFStream os(stdout);
os << "-- Graph after control reduction" << std::endl;
os << AsRPO(*graph());
}
}
JSGraph* jsgraph() { return &jsgraph_; }
};
......@@ -119,6 +140,145 @@ TEST_F(ControlReducerTest, NonTerminatingLoopWithDeadEnd) {
IsIfTrue(CaptureEq(&branch))))))))));
}
TEST_F(ControlReducerTest, PhiAsInputToBranch_true) {
Node* p0 = Parameter(0);
Node* branch1 = graph()->NewNode(common()->Branch(), p0, graph()->start());
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* merge1 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
Node* phi1 = graph()->NewNode(common()->Phi(kMachInt32, 2),
jsgraph()->Int32Constant(1),
jsgraph()->Int32Constant(2), merge1);
Node* branch2 = graph()->NewNode(common()->Branch(), phi1, merge1);
Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
Node* merge2 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
Node* result = graph()->NewNode(common()->Phi(kMachInt32, 2),
jsgraph()->Int32Constant(11),
jsgraph()->Int32Constant(22), merge2);
Node* ret =
graph()->NewNode(common()->Return(), result, graph()->start(), merge2);
graph()->end()->ReplaceInput(0, ret);
ReduceGraph();
// First diamond is not reduced.
EXPECT_THAT(merge1, IsMerge(IsIfTrue(branch1), IsIfFalse(branch1)));
// Second diamond should be folded away.
EXPECT_THAT(graph()->end(),
IsEnd(IsReturn(IsInt32Constant(11), graph()->start(), merge1)));
}
TEST_F(ControlReducerTest, PhiAsInputToBranch_false) {
Node* p0 = Parameter(0);
Node* branch1 = graph()->NewNode(common()->Branch(), p0, graph()->start());
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* merge1 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
Node* phi1 = graph()->NewNode(common()->Phi(kMachInt32, 2),
jsgraph()->Int32Constant(0),
jsgraph()->BooleanConstant(false), merge1);
Node* branch2 = graph()->NewNode(common()->Branch(), phi1, merge1);
Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
Node* merge2 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
Node* result = graph()->NewNode(common()->Phi(kMachInt32, 2),
jsgraph()->Int32Constant(11),
jsgraph()->Int32Constant(22), merge2);
Node* ret =
graph()->NewNode(common()->Return(), result, graph()->start(), merge2);
graph()->end()->ReplaceInput(0, ret);
ReduceGraph();
// First diamond is not reduced.
EXPECT_THAT(merge1, IsMerge(IsIfTrue(branch1), IsIfFalse(branch1)));
// Second diamond should be folded away.
EXPECT_THAT(graph()->end(),
IsEnd(IsReturn(IsInt32Constant(22), graph()->start(), merge1)));
}
TEST_F(ControlReducerTest, PhiAsInputToBranch_unknown_true) {
Node* p0 = Parameter(0);
Node* phi0 = graph()->NewNode(common()->Phi(kMachInt32, 2), p0,
jsgraph()->Int32Constant(1), graph()->start());
Node* branch1 = graph()->NewNode(common()->Branch(), phi0, graph()->start());
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* merge1 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
Node* phi1 = graph()->NewNode(common()->Phi(kMachInt32, 2),
jsgraph()->Int32Constant(111),
jsgraph()->Int32Constant(222), merge1);
Node* ret =
graph()->NewNode(common()->Return(), phi1, graph()->start(), merge1);
graph()->end()->ReplaceInput(0, ret);
ReduceGraph();
// Branch should not be folded.
EXPECT_THAT(phi1,
IsPhi(kMachInt32, IsInt32Constant(111), IsInt32Constant(222),
IsMerge(IsIfTrue(branch1), IsIfFalse(branch1))));
EXPECT_THAT(graph()->end(), IsEnd(IsReturn(phi1, graph()->start(), merge1)));
}
TEST_F(ControlReducerTest, RangeAsInputToBranch_true1) {
Node* p0 = Parameter(Type::Range(1, 2, zone()), 0);
Node* branch1 = graph()->NewNode(common()->Branch(), p0, graph()->start());
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* merge1 = graph()->NewNode(common()->Merge(1), if_true1, if_false1);
Node* result = graph()->NewNode(common()->Phi(kMachInt32, 2),
jsgraph()->Int32Constant(11),
jsgraph()->Int32Constant(44), merge1);
Node* ret =
graph()->NewNode(common()->Return(), result, graph()->start(), merge1);
graph()->end()->ReplaceInput(0, ret);
ReduceGraph();
// Diamond should be folded away.
EXPECT_THAT(
graph()->end(),
IsEnd(IsReturn(IsInt32Constant(11), graph()->start(), graph()->start())));
}
TEST_F(ControlReducerTest, RangeAsInputToBranch_true2) {
Node* p0 = Parameter(Type::Range(-2, -1, zone()), 0);
Node* branch1 = graph()->NewNode(common()->Branch(), p0, graph()->start());
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* merge1 = graph()->NewNode(common()->Merge(1), if_true1, if_false1);
Node* result = graph()->NewNode(common()->Phi(kMachInt32, 2),
jsgraph()->Int32Constant(11),
jsgraph()->Int32Constant(44), merge1);
Node* ret =
graph()->NewNode(common()->Return(), result, graph()->start(), merge1);
graph()->end()->ReplaceInput(0, ret);
ReduceGraph();
// Diamond should be folded away.
EXPECT_THAT(
graph()->end(),
IsEnd(IsReturn(IsInt32Constant(11), graph()->start(), graph()->start())));
}
} // namespace compiler
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment