1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/control-flow-optimizer.h"
6
7 #include "src/codegen/tick-counter.h"
8 #include "src/compiler/common-operator.h"
9 #include "src/compiler/graph.h"
10 #include "src/compiler/node-matchers.h"
11 #include "src/compiler/node-properties.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16
ControlFlowOptimizer(Graph * graph,CommonOperatorBuilder * common,MachineOperatorBuilder * machine,TickCounter * tick_counter,Zone * zone)17 ControlFlowOptimizer::ControlFlowOptimizer(Graph* graph,
18 CommonOperatorBuilder* common,
19 MachineOperatorBuilder* machine,
20 TickCounter* tick_counter,
21 Zone* zone)
22 : graph_(graph),
23 common_(common),
24 machine_(machine),
25 queue_(zone),
26 queued_(graph, 2),
27 zone_(zone),
28 tick_counter_(tick_counter) {}
29
Optimize()30 void ControlFlowOptimizer::Optimize() {
31 Enqueue(graph()->start());
32 while (!queue_.empty()) {
33 tick_counter_->TickAndMaybeEnterSafepoint();
34 Node* node = queue_.front();
35 queue_.pop();
36 if (node->IsDead()) continue;
37 switch (node->opcode()) {
38 case IrOpcode::kBranch:
39 VisitBranch(node);
40 break;
41 default:
42 VisitNode(node);
43 break;
44 }
45 }
46 }
47
48
Enqueue(Node * node)49 void ControlFlowOptimizer::Enqueue(Node* node) {
50 DCHECK_NOT_NULL(node);
51 if (node->IsDead() || queued_.Get(node)) return;
52 queued_.Set(node, true);
53 queue_.push(node);
54 }
55
56
VisitNode(Node * node)57 void ControlFlowOptimizer::VisitNode(Node* node) {
58 for (Edge edge : node->use_edges()) {
59 if (NodeProperties::IsControlEdge(edge)) {
60 Enqueue(edge.from());
61 }
62 }
63 }
64
65
VisitBranch(Node * node)66 void ControlFlowOptimizer::VisitBranch(Node* node) {
67 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
68 if (TryBuildSwitch(node)) return;
69 VisitNode(node);
70 }
71
72
TryBuildSwitch(Node * node)73 bool ControlFlowOptimizer::TryBuildSwitch(Node* node) {
74 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
75
76 Node* branch = node;
77 if (BranchHintOf(branch->op()) != BranchHint::kNone) return false;
78 Node* cond = NodeProperties::GetValueInput(branch, 0);
79 if (cond->opcode() != IrOpcode::kWord32Equal) return false;
80 Int32BinopMatcher m(cond);
81 Node* index = m.left().node();
82 if (!m.right().HasResolvedValue()) return false;
83 int32_t value = m.right().ResolvedValue();
84 ZoneSet<int32_t> values(zone());
85 values.insert(value);
86
87 Node* if_false;
88 Node* if_true;
89 int32_t order = 1;
90 while (true) {
91 BranchMatcher matcher(branch);
92 DCHECK(matcher.Matched());
93
94 if_true = matcher.IfTrue();
95 if_false = matcher.IfFalse();
96
97 auto it = if_false->uses().begin();
98 if (it == if_false->uses().end()) break;
99 Node* branch1 = *it++;
100 if (branch1->opcode() != IrOpcode::kBranch) break;
101 if (BranchHintOf(branch1->op()) != BranchHint::kNone) break;
102 if (it != if_false->uses().end()) break;
103 Node* cond1 = branch1->InputAt(0);
104 if (cond1->opcode() != IrOpcode::kWord32Equal) break;
105 Int32BinopMatcher m1(cond1);
106 if (m1.left().node() != index) break;
107 if (!m1.right().HasResolvedValue()) break;
108 int32_t value1 = m1.right().ResolvedValue();
109 if (values.find(value1) != values.end()) break;
110 DCHECK_NE(value, value1);
111
112 if (branch != node) {
113 branch->NullAllInputs();
114 if_true->ReplaceInput(0, node);
115 }
116 NodeProperties::ChangeOp(if_true, common()->IfValue(value, order++));
117 if_false->NullAllInputs();
118 Enqueue(if_true);
119
120 branch = branch1;
121 value = value1;
122 values.insert(value);
123 }
124
125 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
126 DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
127 if (branch == node) {
128 DCHECK_EQ(1u, values.size());
129 return false;
130 }
131 DCHECK_LT(1u, values.size());
132 node->ReplaceInput(0, index);
133 NodeProperties::ChangeOp(node, common()->Switch(values.size() + 1));
134 if_true->ReplaceInput(0, node);
135 NodeProperties::ChangeOp(if_true, common()->IfValue(value, order++));
136 Enqueue(if_true);
137 if_false->ReplaceInput(0, node);
138 NodeProperties::ChangeOp(if_false, common()->IfDefault());
139 Enqueue(if_false);
140 branch->NullAllInputs();
141 return true;
142 }
143
144 } // namespace compiler
145 } // namespace internal
146 } // namespace v8
147