#include "src/compiler/machine-operator.h"
#include "src/compiler/node.h"
#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
} // namespace
+CommonOperatorReducer::CommonOperatorReducer(Editor* editor, Graph* graph,
+ CommonOperatorBuilder* common,
+ MachineOperatorBuilder* machine)
+ : AdvancedReducer(editor),
+ graph_(graph),
+ common_(common),
+ machine_(machine),
+ dead_(graph->NewNode(common->Dead())) {}
+
+
Reduction CommonOperatorReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kBranch:
return ReduceEffectPhi(node);
case IrOpcode::kPhi:
return ReducePhi(node);
+ case IrOpcode::kReturn:
+ return ReduceReturn(node);
case IrOpcode::kSelect:
return ReduceSelect(node);
default:
Decision const decision = DecideCondition(cond);
if (decision == Decision::kUnknown) return NoChange();
Node* const control = node->InputAt(1);
- if (!dead_.is_set()) dead_.set(graph()->NewNode(common()->Dead()));
for (Node* const use : node->uses()) {
switch (use->opcode()) {
case IrOpcode::kIfTrue:
- Replace(use, (decision == Decision::kTrue) ? control : dead_.get());
+ Replace(use, (decision == Decision::kTrue) ? control : dead());
break;
case IrOpcode::kIfFalse:
- Replace(use, (decision == Decision::kFalse) ? control : dead_.get());
+ Replace(use, (decision == Decision::kFalse) ? control : dead());
break;
default:
UNREACHABLE();
}
}
- return Replace(dead_.get());
+ return Replace(dead());
}
}
+Reduction CommonOperatorReducer::ReduceReturn(Node* node) {
+ DCHECK_EQ(IrOpcode::kReturn, node->opcode());
+ Node* const value = node->InputAt(0);
+ Node* const effect = node->InputAt(1);
+ Node* const control = node->InputAt(2);
+ if (value->opcode() == IrOpcode::kPhi &&
+ NodeProperties::GetControlInput(value) == control &&
+ effect->opcode() == IrOpcode::kEffectPhi &&
+ NodeProperties::GetControlInput(effect) == control &&
+ control->opcode() == IrOpcode::kMerge) {
+ int const control_input_count = control->InputCount();
+ DCHECK_NE(0, control_input_count);
+ DCHECK_EQ(control_input_count, value->InputCount() - 1);
+ DCHECK_EQ(control_input_count, effect->InputCount() - 1);
+ Node* const end = graph()->end();
+ DCHECK_EQ(IrOpcode::kEnd, end->opcode());
+ DCHECK_NE(0, end->InputCount());
+ for (int i = 0; i < control_input_count; ++i) {
+ // Create a new {Return} and connect it to {end}. We don't need to mark
+ // {end} as revisit, because we mark {node} as {Dead} below, which was
+ // previously connected to {end}, so we know for sure that at some point
+ // the reducer logic will visit {end} again.
+ Node* ret = graph()->NewNode(common()->Return(), value->InputAt(i),
+ effect->InputAt(i), control->InputAt(i));
+ end->set_op(common()->End(end->InputCount() + 1));
+ end->AppendInput(graph()->zone(), ret);
+ }
+ // Mark the merge {control} and return {node} as {dead}.
+ Replace(control, dead());
+ return Replace(dead());
+ }
+ return NoChange();
+}
+
+
Reduction CommonOperatorReducer::ReduceSelect(Node* node) {
DCHECK_EQ(IrOpcode::kSelect, node->opcode());
Node* const cond = node->InputAt(0);
public:
CommonOperatorReducer(Editor* editor, Graph* graph,
CommonOperatorBuilder* common,
- MachineOperatorBuilder* machine)
- : AdvancedReducer(editor),
- graph_(graph),
- common_(common),
- machine_(machine) {}
+ MachineOperatorBuilder* machine);
~CommonOperatorReducer() final {}
Reduction Reduce(Node* node) final;
Reduction ReduceMerge(Node* node);
Reduction ReduceEffectPhi(Node* node);
Reduction ReducePhi(Node* node);
+ Reduction ReduceReturn(Node* node);
Reduction ReduceSelect(Node* node);
Reduction Change(Node* node, Operator const* op, Node* a);
Graph* graph() const { return graph_; }
CommonOperatorBuilder* common() const { return common_; }
MachineOperatorBuilder* machine() const { return machine_; }
+ Node* dead() const { return dead_; }
Graph* const graph_;
CommonOperatorBuilder* const common_;
MachineOperatorBuilder* const machine_;
- SetOncePointer<Node> dead_;
+ Node* const dead_;
};
} // namespace compiler
// -----------------------------------------------------------------------------
+// Return
+
+
+TEST_F(CommonOperatorReducerTest, ReturnWithPhiAndEffectPhiAndMerge) {
+ Node* cond = Parameter(2);
+ Node* branch = graph()->NewNode(common()->Branch(), cond, graph()->start());
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* etrue = graph()->start();
+ Node* vtrue = Parameter(0);
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Node* efalse = graph()->start();
+ Node* vfalse = Parameter(1);
+ Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
+ Node* phi =
+ graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse, merge);
+ Node* ret = graph()->NewNode(common()->Return(), phi, ephi, merge);
+ graph()->SetEnd(graph()->NewNode(common()->End(1), ret));
+ StrictMock<MockAdvancedReducerEditor> editor;
+ EXPECT_CALL(editor, Replace(merge, IsDead()));
+ Reduction const r = Reduce(&editor, ret);
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsDead());
+ EXPECT_THAT(graph()->end(), IsEnd(ret, IsReturn(vtrue, etrue, if_true),
+ IsReturn(vfalse, efalse, if_false)));
+}
+
+
+// -----------------------------------------------------------------------------
// Select
}
+Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher,
+ const Matcher<Node*>& control1_matcher,
+ const Matcher<Node*>& control2_matcher) {
+ return MakeMatcher(new IsControl3Matcher(IrOpcode::kEnd, control0_matcher,
+ control1_matcher, control2_matcher));
+}
+
+
Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& control_matcher) {
return MakeMatcher(new IsBranchMatcher(value_matcher, control_matcher));
Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher);
Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher);
+Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher,
+ const Matcher<Node*>& control1_matcher,
+ const Matcher<Node*>& control2_matcher);
Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,