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 2859137 : DeadCodeElimination::DeadCodeElimination(Editor* editor, Graph* graph,
18 : CommonOperatorBuilder* common,
19 : Zone* temp_zone)
20 : : AdvancedReducer(editor),
21 : graph_(graph),
22 : common_(common),
23 2859137 : dead_(graph->NewNode(common->Dead())),
24 5718284 : zone_(temp_zone) {
25 : NodeProperties::SetType(dead_, Type::None());
26 2859147 : }
27 :
28 : namespace {
29 :
30 : // True if we can guarantee that {node} will never actually produce a value or
31 : // effect.
32 771887933 : bool NoReturn(Node* node) {
33 771836409 : return node->opcode() == IrOpcode::kDead ||
34 771834813 : node->opcode() == IrOpcode::kUnreachable ||
35 1543667729 : node->opcode() == IrOpcode::kDeadValue ||
36 1543667729 : NodeProperties::GetTypeOrAny(node).IsNone();
37 : }
38 :
39 247383452 : Node* FindDeadInput(Node* node) {
40 1019162856 : for (Node* input : node->inputs()) {
41 771887334 : if (NoReturn(input)) return input;
42 : }
43 : return nullptr;
44 : }
45 :
46 : } // namespace
47 :
48 302805077 : Reduction DeadCodeElimination::Reduce(Node* node) {
49 : DisallowHeapAccess no_heap_access;
50 302805077 : switch (node->opcode()) {
51 : case IrOpcode::kEnd:
52 3049682 : return ReduceEnd(node);
53 : case IrOpcode::kLoop:
54 : case IrOpcode::kMerge:
55 7498504 : return ReduceLoopOrMerge(node);
56 : case IrOpcode::kLoopExit:
57 352429 : return ReduceLoopExit(node);
58 : case IrOpcode::kUnreachable:
59 : case IrOpcode::kIfException:
60 2279238 : return ReduceUnreachableOrIfException(node);
61 : case IrOpcode::kPhi:
62 3952453 : 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 4575698 : return ReduceDeoptimizeOrReturnOrTerminateOrTailCall(node);
70 : case IrOpcode::kThrow:
71 : return PropagateDeadControl(node);
72 : case IrOpcode::kBranch:
73 : case IrOpcode::kSwitch:
74 9600579 : return ReduceBranchOrSwitch(node);
75 : default:
76 263045955 : return ReduceNode(node);
77 : }
78 : UNREACHABLE();
79 : }
80 :
81 0 : Reduction DeadCodeElimination::PropagateDeadControl(Node* node) {
82 : DCHECK_EQ(1, node->op()->ControlInputCount());
83 153428260 : Node* control = NodeProperties::GetControlInput(node);
84 153417927 : if (control->opcode() == IrOpcode::kDead) return Replace(control);
85 : return NoChange();
86 : }
87 :
88 3049678 : 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 23182728 : for (int i = 0; i < inputs.count(); ++i) {
94 : Node* const input = inputs[i];
95 : // Skip dead inputs.
96 10066522 : if (input->opcode() == IrOpcode::kDead) continue;
97 : // Compact live inputs.
98 9898626 : if (i != live_input_count) node->ReplaceInput(live_input_count, input);
99 9898629 : ++live_input_count;
100 : }
101 3049681 : if (live_input_count == 0) {
102 : return Replace(dead());
103 3049666 : } else if (live_input_count < inputs.count()) {
104 94236 : node->TrimInputCount(live_input_count);
105 94236 : 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 7498480 : 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 8134349 : if (node->opcode() != IrOpcode::kLoop ||
123 : node->InputAt(0)->opcode() != IrOpcode::kDead) {
124 60213073 : for (int i = 0; i < inputs.count(); ++i) {
125 : Node* const input = inputs[i];
126 : // Skip dead inputs.
127 26358054 : if (input->opcode() == IrOpcode::kDead) continue;
128 : // Compact live inputs.
129 25967709 : if (live_input_count != i) {
130 415252 : node->ReplaceInput(live_input_count, input);
131 1786358 : for (Node* const use : node->uses()) {
132 1371106 : if (NodeProperties::IsPhi(use)) {
133 : DCHECK_EQ(inputs.count() + 1, use->InputCount());
134 685519 : use->ReplaceInput(live_input_count, use->InputAt(i));
135 : }
136 : }
137 : }
138 25967709 : ++live_input_count;
139 : }
140 : }
141 7498480 : if (live_input_count == 0) {
142 : return Replace(dead());
143 7485131 : } else if (live_input_count == 1) {
144 515892 : NodeVector loop_exits(zone_);
145 : // Due to compaction above, the live input is at offset 0.
146 6287086 : for (Node* const use : node->uses()) {
147 2885597 : if (NodeProperties::IsPhi(use)) {
148 : Replace(use, use->InputAt(0));
149 2542968 : } 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 2081 : loop_exits.push_back(use);
155 2537470 : } else if (use->opcode() == IrOpcode::kTerminate) {
156 : DCHECK_EQ(IrOpcode::kLoop, node->opcode());
157 : Replace(use, dead());
158 : }
159 : }
160 517973 : for (Node* loop_exit : loop_exits) {
161 2081 : 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 6969239 : if (live_input_count < inputs.count()) {
170 : // Trim input counts for all phi uses and revisit them.
171 421952 : for (Node* const use : node->uses()) {
172 317439 : if (NodeProperties::IsPhi(use)) {
173 142805 : use->ReplaceInput(live_input_count, node);
174 142805 : TrimMergeOrPhi(use, live_input_count);
175 : Revisit(use);
176 : }
177 : }
178 104513 : TrimMergeOrPhi(node, live_input_count);
179 : return Changed(node);
180 : }
181 : return NoChange();
182 : }
183 :
184 14241 : Reduction DeadCodeElimination::RemoveLoopExit(Node* node) {
185 : DCHECK_EQ(IrOpcode::kLoopExit, node->opcode());
186 67478 : for (Node* const use : node->uses()) {
187 53237 : if (use->opcode() == IrOpcode::kLoopExitValue ||
188 : use->opcode() == IrOpcode::kLoopExitEffect) {
189 : Replace(use, use->InputAt(0));
190 : }
191 : }
192 14241 : Node* control = NodeProperties::GetControlInput(node, 0);
193 : Replace(node, control);
194 14241 : return Replace(control);
195 : }
196 :
197 263096832 : 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 263096832 : if (control_input_count == 1) {
203 : Reduction reduction = PropagateDeadControl(node);
204 124560247 : if (reduction.Changed()) return reduction;
205 : }
206 525662346 : if (effect_input_count == 0 &&
207 21325953 : (control_input_count == 0 || node->op()->ControlOutputCount() == 0)) {
208 134627304 : return ReducePureNode(node);
209 : }
210 128203869 : if (effect_input_count > 0) {
211 108326240 : return ReduceEffectNode(node);
212 : }
213 : return NoChange();
214 : }
215 :
216 3952301 : Reduction DeadCodeElimination::ReducePhi(Node* node) {
217 : DCHECK_EQ(IrOpcode::kPhi, node->opcode());
218 : Reduction reduction = PropagateDeadControl(node);
219 3951836 : if (reduction.Changed()) return reduction;
220 3871502 : MachineRepresentation rep = PhiRepresentationOf(node->op());
221 7741513 : if (rep == MachineRepresentation::kNone ||
222 3871380 : NodeProperties::GetTypeOrAny(node).IsNone()) {
223 64 : return Replace(DeadValue(node, rep));
224 : }
225 : int input_count = node->op()->ValueInputCount();
226 37043053 : for (int i = 0; i < input_count; ++i) {
227 16586620 : Node* input = NodeProperties::GetValueInput(node, i);
228 16588755 : if (input->opcode() == IrOpcode::kDeadValue &&
229 2257 : DeadValueRepresentationOf(input->op()) != rep) {
230 743 : NodeProperties::ReplaceValueInput(node, DeadValue(input, rep), i);
231 : }
232 : }
233 : return NoChange();
234 : }
235 :
236 134627185 : Reduction DeadCodeElimination::ReducePureNode(Node* node) {
237 : DCHECK_EQ(0, node->op()->EffectInputCount());
238 134627185 : if (node->opcode() == IrOpcode::kDeadValue) return NoChange();
239 134565745 : if (Node* input = FindDeadInput(node)) {
240 105358 : return Replace(DeadValue(input));
241 : }
242 : return NoChange();
243 : }
244 :
245 2279238 : Reduction DeadCodeElimination::ReduceUnreachableOrIfException(Node* node) {
246 : DCHECK(node->opcode() == IrOpcode::kUnreachable ||
247 : node->opcode() == IrOpcode::kIfException);
248 : Reduction reduction = PropagateDeadControl(node);
249 2279228 : if (reduction.Changed()) return reduction;
250 2235851 : Node* effect = NodeProperties::GetEffectInput(node, 0);
251 2235851 : if (effect->opcode() == IrOpcode::kDead) {
252 : return Replace(effect);
253 : }
254 2235742 : if (effect->opcode() == IrOpcode::kUnreachable) {
255 : return Replace(effect);
256 : }
257 : return NoChange();
258 : }
259 :
260 108324942 : Reduction DeadCodeElimination::ReduceEffectNode(Node* node) {
261 : DCHECK_EQ(1, node->op()->EffectInputCount());
262 108324942 : Node* effect = NodeProperties::GetEffectInput(node, 0);
263 108321894 : if (effect->opcode() == IrOpcode::kDead) {
264 : return Replace(effect);
265 : }
266 108313149 : if (Node* input = FindDeadInput(node)) {
267 8051 : if (effect->opcode() == IrOpcode::kUnreachable) {
268 : RelaxEffectsAndControls(node);
269 6466 : return Replace(DeadValue(input));
270 : }
271 :
272 : Node* control = node->op()->ControlInputCount() == 1
273 : ? NodeProperties::GetControlInput(node, 0)
274 1585 : : graph()->start();
275 : Node* unreachable =
276 1585 : 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 4575689 : 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 4575698 : if (reduction.Changed()) return reduction;
293 4543099 : if (FindDeadInput(node) != nullptr) {
294 273 : Node* effect = NodeProperties::GetEffectInput(node, 0);
295 273 : Node* control = NodeProperties::GetControlInput(node, 0);
296 273 : if (effect->opcode() != IrOpcode::kUnreachable) {
297 68 : effect = graph()->NewNode(common()->Unreachable(), effect, control);
298 : NodeProperties::SetType(effect, Type::None());
299 : }
300 273 : node->TrimInputCount(2);
301 273 : node->ReplaceInput(0, effect);
302 273 : node->ReplaceInput(1, control);
303 273 : NodeProperties::ChangeOp(node, common()->Throw());
304 : return Changed(node);
305 : }
306 : return NoChange();
307 : }
308 :
309 352429 : Reduction DeadCodeElimination::ReduceLoopExit(Node* node) {
310 352429 : Node* control = NodeProperties::GetControlInput(node, 0);
311 352429 : Node* loop = NodeProperties::GetControlInput(node, 1);
312 692547 : if (control->opcode() == IrOpcode::kDead ||
313 : loop->opcode() == IrOpcode::kDead) {
314 14241 : return RemoveLoopExit(node);
315 : }
316 : return NoChange();
317 : }
318 :
319 9600540 : Reduction DeadCodeElimination::ReduceBranchOrSwitch(Node* node) {
320 : DCHECK(node->opcode() == IrOpcode::kBranch ||
321 : node->opcode() == IrOpcode::kSwitch);
322 : Reduction reduction = PropagateDeadControl(node);
323 9600475 : if (reduction.Changed()) return reduction;
324 9574490 : Node* condition = NodeProperties::GetValueInput(node, 0);
325 9574457 : 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 709 : size_t const projection_cnt = node->op()->ControlOutputCount();
331 709 : Node** projections = zone_->NewArray<Node*>(projection_cnt);
332 : NodeProperties::CollectControlProjections(node, projections,
333 709 : projection_cnt);
334 709 : Replace(projections[0], NodeProperties::GetControlInput(node));
335 : return Replace(dead());
336 : }
337 : return NoChange();
338 : }
339 :
340 247318 : void DeadCodeElimination::TrimMergeOrPhi(Node* node, int size) {
341 247318 : const Operator* const op = common()->ResizeMergeOrPhi(node->op(), size);
342 247318 : node->TrimInputCount(OperatorProperties::GetTotalInputCount(op));
343 247318 : NodeProperties::ChangeOp(node, op);
344 247318 : }
345 :
346 114216 : Node* DeadCodeElimination::DeadValue(Node* node, MachineRepresentation rep) {
347 114216 : if (node->opcode() == IrOpcode::kDeadValue) {
348 56297 : if (rep == DeadValueRepresentationOf(node->op())) return node;
349 851 : node = NodeProperties::GetValueInput(node, 0);
350 : }
351 58770 : Node* dead_value = graph()->NewNode(common()->DeadValue(rep), node);
352 : NodeProperties::SetType(dead_value, Type::None());
353 58770 : return dead_value;
354 : }
355 :
356 : } // namespace compiler
357 : } // namespace internal
358 122036 : } // namespace v8
|