Line data Source code
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/dead-code-elimination.h"
6 :
7 : #include "src/compiler/common-operator.h"
8 : #include "src/compiler/graph.h"
9 : #include "src/compiler/js-operator.h"
10 : #include "src/compiler/node-properties.h"
11 : #include "src/compiler/operator-properties.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 : namespace compiler {
16 :
17 2860714 : DeadCodeElimination::DeadCodeElimination(Editor* editor, Graph* graph,
18 : CommonOperatorBuilder* common,
19 : Zone* temp_zone)
20 : : AdvancedReducer(editor),
21 : graph_(graph),
22 : common_(common),
23 2860714 : dead_(graph->NewNode(common->Dead())),
24 5721435 : zone_(temp_zone) {
25 : NodeProperties::SetType(dead_, Type::None());
26 2860721 : }
27 :
28 : namespace {
29 :
30 : // True if we can guarantee that {node} will never actually produce a value or
31 : // effect.
32 773218413 : bool NoReturn(Node* node) {
33 773167409 : return node->opcode() == IrOpcode::kDead ||
34 773165823 : node->opcode() == IrOpcode::kUnreachable ||
35 1546328540 : node->opcode() == IrOpcode::kDeadValue ||
36 1546328540 : NodeProperties::GetTypeOrAny(node).IsNone();
37 : }
38 :
39 247817412 : Node* FindDeadInput(Node* node) {
40 1020927028 : for (Node* input : node->inputs()) {
41 773217608 : if (NoReturn(input)) return input;
42 : }
43 : return nullptr;
44 : }
45 :
46 : } // namespace
47 :
48 303398221 : Reduction DeadCodeElimination::Reduce(Node* node) {
49 : DisallowHeapAccess no_heap_access;
50 303398221 : switch (node->opcode()) {
51 : case IrOpcode::kEnd:
52 3052049 : return ReduceEnd(node);
53 : case IrOpcode::kLoop:
54 : case IrOpcode::kMerge:
55 7513000 : return ReduceLoopOrMerge(node);
56 : case IrOpcode::kLoopExit:
57 355651 : return ReduceLoopExit(node);
58 : case IrOpcode::kUnreachable:
59 : case IrOpcode::kIfException:
60 2298937 : return ReduceUnreachableOrIfException(node);
61 : case IrOpcode::kPhi:
62 3960265 : return ReducePhi(node);
63 : case IrOpcode::kEffectPhi:
64 : return PropagateDeadControl(node);
65 : case IrOpcode::kDeoptimize:
66 : case IrOpcode::kReturn:
67 : case IrOpcode::kTerminate:
68 : case IrOpcode::kTailCall:
69 4589139 : return ReduceDeoptimizeOrReturnOrTerminateOrTailCall(node);
70 : case IrOpcode::kThrow:
71 : return PropagateDeadControl(node);
72 : case IrOpcode::kBranch:
73 : case IrOpcode::kSwitch:
74 9621336 : return ReduceBranchOrSwitch(node);
75 : default:
76 263526279 : return ReduceNode(node);
77 : }
78 : UNREACHABLE();
79 : }
80 :
81 0 : Reduction DeadCodeElimination::PropagateDeadControl(Node* node) {
82 : DCHECK_EQ(1, node->op()->ControlInputCount());
83 153834332 : Node* control = NodeProperties::GetControlInput(node);
84 153820005 : if (control->opcode() == IrOpcode::kDead) return Replace(control);
85 : return NoChange();
86 : }
87 :
88 3052050 : Reduction DeadCodeElimination::ReduceEnd(Node* node) {
89 : DCHECK_EQ(IrOpcode::kEnd, node->opcode());
90 : Node::Inputs inputs = node->inputs();
91 : DCHECK_LE(1, inputs.count());
92 : int live_input_count = 0;
93 23240362 : for (int i = 0; i < inputs.count(); ++i) {
94 : Node* const input = inputs[i];
95 : // Skip dead inputs.
96 10094147 : if (input->opcode() == IrOpcode::kDead) continue;
97 : // Compact live inputs.
98 9926239 : if (i != live_input_count) node->ReplaceInput(live_input_count, input);
99 9926248 : ++live_input_count;
100 : }
101 3052059 : if (live_input_count == 0) {
102 : return Replace(dead());
103 3052044 : } else if (live_input_count < inputs.count()) {
104 94344 : node->TrimInputCount(live_input_count);
105 94343 : NodeProperties::ChangeOp(node, common()->End(live_input_count));
106 : return Changed(node);
107 : }
108 : DCHECK_EQ(inputs.count(), live_input_count);
109 : return NoChange();
110 : }
111 :
112 :
113 7513016 : Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) {
114 : DCHECK(IrOpcode::IsMergeOpcode(node->opcode()));
115 : Node::Inputs inputs = node->inputs();
116 : DCHECK_LE(1, inputs.count());
117 : // Count the number of live inputs to {node} and compact them on the fly, also
118 : // compacting the inputs of the associated {Phi} and {EffectPhi} uses at the
119 : // same time. We consider {Loop}s dead even if only the first control input
120 : // is dead.
121 : int live_input_count = 0;
122 8154167 : if (node->opcode() != IrOpcode::kLoop ||
123 : node->InputAt(0)->opcode() != IrOpcode::kDead) {
124 60434134 : for (int i = 0; i < inputs.count(); ++i) {
125 : Node* const input = inputs[i];
126 : // Skip dead inputs.
127 26461334 : if (input->opcode() == IrOpcode::kDead) continue;
128 : // Compact live inputs.
129 26068017 : if (live_input_count != i) {
130 418668 : node->ReplaceInput(live_input_count, input);
131 1806133 : for (Node* const use : node->uses()) {
132 1387465 : if (NodeProperties::IsPhi(use)) {
133 : DCHECK_EQ(inputs.count() + 1, use->InputCount());
134 697121 : use->ReplaceInput(live_input_count, use->InputAt(i));
135 : }
136 : }
137 : }
138 26068017 : ++live_input_count;
139 : }
140 : }
141 7513016 : if (live_input_count == 0) {
142 : return Replace(dead());
143 7499595 : } else if (live_input_count == 1) {
144 519671 : NodeVector loop_exits(zone_);
145 : // Due to compaction above, the live input is at offset 0.
146 6310509 : for (Node* const use : node->uses()) {
147 2895419 : if (NodeProperties::IsPhi(use)) {
148 : Replace(use, use->InputAt(0));
149 2551482 : } else if (use->opcode() == IrOpcode::kLoopExit &&
150 : use->InputAt(1) == node) {
151 : // Remember the loop exits so that we can mark their loop input dead.
152 : // This has to be done after the use list iteration so that we do
153 : // not mutate the use list while it is being iterated.
154 2172 : loop_exits.push_back(use);
155 2545721 : } else if (use->opcode() == IrOpcode::kTerminate) {
156 : DCHECK_EQ(IrOpcode::kLoop, node->opcode());
157 : Replace(use, dead());
158 : }
159 : }
160 521843 : for (Node* loop_exit : loop_exits) {
161 2172 : loop_exit->ReplaceInput(1, dead());
162 : Revisit(loop_exit);
163 : }
164 : return Replace(node->InputAt(0));
165 : }
166 : DCHECK_LE(2, live_input_count);
167 : DCHECK_LE(live_input_count, inputs.count());
168 : // Trim input count for the {Merge} or {Loop} node.
169 6979924 : if (live_input_count < inputs.count()) {
170 : // Trim input counts for all phi uses and revisit them.
171 424220 : for (Node* const use : node->uses()) {
172 319209 : if (NodeProperties::IsPhi(use)) {
173 143757 : use->ReplaceInput(live_input_count, node);
174 143757 : TrimMergeOrPhi(use, live_input_count);
175 : Revisit(use);
176 : }
177 : }
178 105011 : TrimMergeOrPhi(node, live_input_count);
179 : return Changed(node);
180 : }
181 : return NoChange();
182 : }
183 :
184 14860 : Reduction DeadCodeElimination::RemoveLoopExit(Node* node) {
185 : DCHECK_EQ(IrOpcode::kLoopExit, node->opcode());
186 70761 : for (Node* const use : node->uses()) {
187 55901 : if (use->opcode() == IrOpcode::kLoopExitValue ||
188 : use->opcode() == IrOpcode::kLoopExitEffect) {
189 : Replace(use, use->InputAt(0));
190 : }
191 : }
192 14860 : Node* control = NodeProperties::GetControlInput(node, 0);
193 : Replace(node, control);
194 14860 : return Replace(control);
195 : }
196 :
197 263589537 : Reduction DeadCodeElimination::ReduceNode(Node* node) {
198 : DCHECK(!IrOpcode::IsGraphTerminator(node->opcode()));
199 : int const effect_input_count = node->op()->EffectInputCount();
200 : int const control_input_count = node->op()->ControlInputCount();
201 : DCHECK_LE(control_input_count, 1);
202 263589537 : if (control_input_count == 1) {
203 : Reduction reduction = PropagateDeadControl(node);
204 124869810 : if (reduction.Changed()) return reduction;
205 : }
206 526639090 : if (effect_input_count == 0 &&
207 21392516 : (control_input_count == 0 || node->op()->ControlOutputCount() == 0)) {
208 134796580 : return ReducePureNode(node);
209 : }
210 128522965 : if (effect_input_count > 0) {
211 108585653 : return ReduceEffectNode(node);
212 : }
213 : return NoChange();
214 : }
215 :
216 3960107 : Reduction DeadCodeElimination::ReducePhi(Node* node) {
217 : DCHECK_EQ(IrOpcode::kPhi, node->opcode());
218 : Reduction reduction = PropagateDeadControl(node);
219 3959510 : if (reduction.Changed()) return reduction;
220 3879140 : MachineRepresentation rep = PhiRepresentationOf(node->op());
221 7756554 : if (rep == MachineRepresentation::kNone ||
222 3878960 : NodeProperties::GetTypeOrAny(node).IsNone()) {
223 64 : return Replace(DeadValue(node, rep));
224 : }
225 : int input_count = node->op()->ValueInputCount();
226 37234770 : for (int i = 0; i < input_count; ++i) {
227 16678841 : Node* input = NodeProperties::GetValueInput(node, i);
228 16681113 : if (input->opcode() == IrOpcode::kDeadValue &&
229 2449 : DeadValueRepresentationOf(input->op()) != rep) {
230 803 : NodeProperties::ReplaceValueInput(node, DeadValue(input, rep), i);
231 : }
232 : }
233 : return NoChange();
234 : }
235 :
236 134796265 : Reduction DeadCodeElimination::ReducePureNode(Node* node) {
237 : DCHECK_EQ(0, node->op()->EffectInputCount());
238 134796265 : if (node->opcode() == IrOpcode::kDeadValue) return NoChange();
239 134734405 : if (Node* input = FindDeadInput(node)) {
240 105754 : return Replace(DeadValue(input));
241 : }
242 : return NoChange();
243 : }
244 :
245 2298935 : Reduction DeadCodeElimination::ReduceUnreachableOrIfException(Node* node) {
246 : DCHECK(node->opcode() == IrOpcode::kUnreachable ||
247 : node->opcode() == IrOpcode::kIfException);
248 : Reduction reduction = PropagateDeadControl(node);
249 2298929 : if (reduction.Changed()) return reduction;
250 2253905 : Node* effect = NodeProperties::GetEffectInput(node, 0);
251 2253901 : if (effect->opcode() == IrOpcode::kDead) {
252 : return Replace(effect);
253 : }
254 2253792 : if (effect->opcode() == IrOpcode::kUnreachable) {
255 : return Replace(effect);
256 : }
257 : return NoChange();
258 : }
259 :
260 108584527 : Reduction DeadCodeElimination::ReduceEffectNode(Node* node) {
261 : DCHECK_EQ(1, node->op()->EffectInputCount());
262 108584527 : Node* effect = NodeProperties::GetEffectInput(node, 0);
263 108580764 : if (effect->opcode() == IrOpcode::kDead) {
264 : return Replace(effect);
265 : }
266 108572031 : if (Node* input = FindDeadInput(node)) {
267 8876 : if (effect->opcode() == IrOpcode::kUnreachable) {
268 : RelaxEffectsAndControls(node);
269 7257 : return Replace(DeadValue(input));
270 : }
271 :
272 : Node* control = node->op()->ControlInputCount() == 1
273 : ? NodeProperties::GetControlInput(node, 0)
274 1619 : : graph()->start();
275 : Node* unreachable =
276 1619 : graph()->NewNode(common()->Unreachable(), effect, control);
277 : NodeProperties::SetType(unreachable, Type::None());
278 : ReplaceWithValue(node, DeadValue(input), node, control);
279 : return Replace(unreachable);
280 : }
281 :
282 : return NoChange();
283 : }
284 :
285 4589135 : Reduction DeadCodeElimination::ReduceDeoptimizeOrReturnOrTerminateOrTailCall(
286 : Node* node) {
287 : DCHECK(node->opcode() == IrOpcode::kDeoptimize ||
288 : node->opcode() == IrOpcode::kReturn ||
289 : node->opcode() == IrOpcode::kTerminate ||
290 : node->opcode() == IrOpcode::kTailCall);
291 : Reduction reduction = PropagateDeadControl(node);
292 4589139 : if (reduction.Changed()) return reduction;
293 4556553 : if (FindDeadInput(node) != nullptr) {
294 296 : Node* effect = NodeProperties::GetEffectInput(node, 0);
295 296 : Node* control = NodeProperties::GetControlInput(node, 0);
296 296 : if (effect->opcode() != IrOpcode::kUnreachable) {
297 76 : effect = graph()->NewNode(common()->Unreachable(), effect, control);
298 : NodeProperties::SetType(effect, Type::None());
299 : }
300 296 : node->TrimInputCount(2);
301 296 : node->ReplaceInput(0, effect);
302 296 : node->ReplaceInput(1, control);
303 296 : NodeProperties::ChangeOp(node, common()->Throw());
304 : return Changed(node);
305 : }
306 : return NoChange();
307 : }
308 :
309 355651 : Reduction DeadCodeElimination::ReduceLoopExit(Node* node) {
310 355651 : Node* control = NodeProperties::GetControlInput(node, 0);
311 355651 : Node* loop = NodeProperties::GetControlInput(node, 1);
312 698451 : if (control->opcode() == IrOpcode::kDead ||
313 : loop->opcode() == IrOpcode::kDead) {
314 14860 : return RemoveLoopExit(node);
315 : }
316 : return NoChange();
317 : }
318 :
319 9621292 : Reduction DeadCodeElimination::ReduceBranchOrSwitch(Node* node) {
320 : DCHECK(node->opcode() == IrOpcode::kBranch ||
321 : node->opcode() == IrOpcode::kSwitch);
322 : Reduction reduction = PropagateDeadControl(node);
323 9621168 : if (reduction.Changed()) return reduction;
324 9595093 : Node* condition = NodeProperties::GetValueInput(node, 0);
325 9595081 : if (condition->opcode() == IrOpcode::kDeadValue) {
326 : // Branches or switches on {DeadValue} must originate from unreachable code
327 : // and cannot matter. Due to schedule freedom between the effect and the
328 : // control chain, they might still appear in reachable code. Remove them by
329 : // always choosing the first projection.
330 701 : size_t const projection_cnt = node->op()->ControlOutputCount();
331 701 : Node** projections = zone_->NewArray<Node*>(projection_cnt);
332 : NodeProperties::CollectControlProjections(node, projections,
333 701 : projection_cnt);
334 701 : Replace(projections[0], NodeProperties::GetControlInput(node));
335 : return Replace(dead());
336 : }
337 : return NoChange();
338 : }
339 :
340 248768 : void DeadCodeElimination::TrimMergeOrPhi(Node* node, int size) {
341 248768 : const Operator* const op = common()->ResizeMergeOrPhi(node->op(), size);
342 248768 : node->TrimInputCount(OperatorProperties::GetTotalInputCount(op));
343 248768 : NodeProperties::ChangeOp(node, op);
344 248768 : }
345 :
346 115497 : Node* DeadCodeElimination::DeadValue(Node* node, MachineRepresentation rep) {
347 115497 : if (node->opcode() == IrOpcode::kDeadValue) {
348 57342 : if (rep == DeadValueRepresentationOf(node->op())) return node;
349 913 : node = NodeProperties::GetValueInput(node, 0);
350 : }
351 59068 : Node* dead_value = graph()->NewNode(common()->DeadValue(rep), node);
352 : NodeProperties::SetType(dead_value, Type::None());
353 59068 : return dead_value;
354 : }
355 :
356 : } // namespace compiler
357 : } // namespace internal
358 122004 : } // namespace v8
|