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 2858340 : DeadCodeElimination::DeadCodeElimination(Editor* editor, Graph* graph,
18 : CommonOperatorBuilder* common,
19 : Zone* temp_zone)
20 : : AdvancedReducer(editor),
21 : graph_(graph),
22 : common_(common),
23 2858340 : dead_(graph->NewNode(common->Dead())),
24 5716715 : zone_(temp_zone) {
25 : NodeProperties::SetType(dead_, Type::None());
26 2858375 : }
27 :
28 : namespace {
29 :
30 : // True if we can guarantee that {node} will never actually produce a value or
31 : // effect.
32 820010048 : bool NoReturn(Node* node) {
33 819957484 : return node->opcode() == IrOpcode::kDead ||
34 819955814 : node->opcode() == IrOpcode::kUnreachable ||
35 1639910237 : node->opcode() == IrOpcode::kDeadValue ||
36 1639910237 : NodeProperties::GetTypeOrAny(node).IsNone();
37 : }
38 :
39 260769382 : Node* FindDeadInput(Node* node) {
40 1080668831 : for (Node* input : node->inputs()) {
41 820009430 : if (NoReturn(input)) return input;
42 : }
43 : return nullptr;
44 : }
45 :
46 : } // namespace
47 :
48 318153445 : Reduction DeadCodeElimination::Reduce(Node* node) {
49 : DisallowHeapAccess no_heap_access;
50 318153445 : switch (node->opcode()) {
51 : case IrOpcode::kEnd:
52 3057784 : return ReduceEnd(node);
53 : case IrOpcode::kLoop:
54 : case IrOpcode::kMerge:
55 7807607 : return ReduceLoopOrMerge(node);
56 : case IrOpcode::kLoopExit:
57 343443 : return ReduceLoopExit(node);
58 : case IrOpcode::kUnreachable:
59 : case IrOpcode::kIfException:
60 2216345 : return ReduceUnreachableOrIfException(node);
61 : case IrOpcode::kPhi:
62 4187213 : 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 4643776 : return ReduceDeoptimizeOrReturnOrTerminateOrTailCall(node);
70 : case IrOpcode::kThrow:
71 : return PropagateDeadControl(node);
72 : case IrOpcode::kBranch:
73 : case IrOpcode::kSwitch:
74 10021130 : return ReduceBranchOrSwitch(node);
75 : default:
76 277189206 : return ReduceNode(node);
77 : }
78 : UNREACHABLE();
79 : }
80 :
81 0 : Reduction DeadCodeElimination::PropagateDeadControl(Node* node) {
82 : DCHECK_EQ(1, node->op()->ControlInputCount());
83 160585585 : Node* control = NodeProperties::GetControlInput(node);
84 160575726 : if (control->opcode() == IrOpcode::kDead) return Replace(control);
85 : return NoChange();
86 : }
87 :
88 3057778 : 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 24117884 : for (int i = 0; i < inputs.count(); ++i) {
94 : Node* const input = inputs[i];
95 : // Skip dead inputs.
96 10530045 : if (input->opcode() == IrOpcode::kDead) continue;
97 : // Compact live inputs.
98 10347324 : if (i != live_input_count) node->ReplaceInput(live_input_count, input);
99 10347332 : ++live_input_count;
100 : }
101 3057786 : if (live_input_count == 0) {
102 : return Replace(dead());
103 3057771 : } else if (live_input_count < inputs.count()) {
104 106742 : node->TrimInputCount(live_input_count);
105 106741 : 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 7807599 : 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 8445737 : if (node->opcode() != IrOpcode::kLoop ||
123 : node->InputAt(0)->opcode() != IrOpcode::kDead) {
124 62730716 : for (int i = 0; i < inputs.count(); ++i) {
125 : Node* const input = inputs[i];
126 : // Skip dead inputs.
127 27462263 : if (input->opcode() == IrOpcode::kDead) continue;
128 : // Compact live inputs.
129 27072740 : if (live_input_count != i) {
130 413649 : node->ReplaceInput(live_input_count, input);
131 1789589 : for (Node* const use : node->uses()) {
132 1375940 : if (NodeProperties::IsPhi(use)) {
133 : DCHECK_EQ(inputs.count() + 1, use->InputCount());
134 691359 : use->ReplaceInput(live_input_count, use->InputAt(i));
135 : }
136 : }
137 : }
138 27072740 : ++live_input_count;
139 : }
140 : }
141 7807599 : if (live_input_count == 0) {
142 : return Replace(dead());
143 7793828 : } else if (live_input_count == 1) {
144 517200 : NodeVector loop_exits(zone_);
145 : // Due to compaction above, the live input is at offset 0.
146 4610253 : for (Node* const use : node->uses()) {
147 2046528 : if (NodeProperties::IsPhi(use)) {
148 : Replace(use, use->InputAt(0));
149 1706308 : } 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 2133 : loop_exits.push_back(use);
155 1700669 : } else if (use->opcode() == IrOpcode::kTerminate) {
156 : DCHECK_EQ(IrOpcode::kLoop, node->opcode());
157 : Replace(use, dead());
158 : }
159 : }
160 519330 : for (Node* loop_exit : loop_exits) {
161 2133 : 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 7276628 : if (live_input_count < inputs.count()) {
170 : // Trim input counts for all phi uses and revisit them.
171 419274 : for (Node* const use : node->uses()) {
172 315714 : if (NodeProperties::IsPhi(use)) {
173 142101 : use->ReplaceInput(live_input_count, node);
174 142101 : TrimMergeOrPhi(use, live_input_count);
175 : Revisit(use);
176 : }
177 : }
178 103560 : TrimMergeOrPhi(node, live_input_count);
179 : return Changed(node);
180 : }
181 : return NoChange();
182 : }
183 :
184 14719 : Reduction DeadCodeElimination::RemoveLoopExit(Node* node) {
185 : DCHECK_EQ(IrOpcode::kLoopExit, node->opcode());
186 69850 : for (Node* const use : node->uses()) {
187 55132 : if (use->opcode() == IrOpcode::kLoopExitValue ||
188 : use->opcode() == IrOpcode::kLoopExitEffect) {
189 : Replace(use, use->InputAt(0));
190 : }
191 : }
192 14718 : Node* control = NodeProperties::GetControlInput(node, 0);
193 : Replace(node, control);
194 14718 : return Replace(control);
195 : }
196 :
197 277232206 : 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 277232206 : if (control_input_count == 1) {
203 : Reduction reduction = PropagateDeadControl(node);
204 130821028 : if (reduction.Changed()) return reduction;
205 : }
206 553926010 : if (effect_input_count == 0 &&
207 22630702 : (control_input_count == 0 || node->op()->ControlOutputCount() == 0)) {
208 143005515 : return ReducePureNode(node);
209 : }
210 133957490 : if (effect_input_count > 0) {
211 113263195 : return ReduceEffectNode(node);
212 : }
213 : return NoChange();
214 : }
215 :
216 4187062 : Reduction DeadCodeElimination::ReducePhi(Node* node) {
217 : DCHECK_EQ(IrOpcode::kPhi, node->opcode());
218 : Reduction reduction = PropagateDeadControl(node);
219 4186684 : if (reduction.Changed()) return reduction;
220 4092108 : MachineRepresentation rep = PhiRepresentationOf(node->op());
221 8182957 : if (rep == MachineRepresentation::kNone ||
222 4092018 : NodeProperties::GetTypeOrAny(node).IsNone()) {
223 56 : return Replace(DeadValue(node, rep));
224 : }
225 : int input_count = node->op()->ValueInputCount();
226 37662635 : for (int i = 0; i < input_count; ++i) {
227 16785962 : Node* input = NodeProperties::GetValueInput(node, i);
228 16788208 : if (input->opcode() == IrOpcode::kDeadValue &&
229 2365 : DeadValueRepresentationOf(input->op()) != rep) {
230 765 : NodeProperties::ReplaceValueInput(node, DeadValue(input, rep), i);
231 : }
232 : }
233 : return NoChange();
234 : }
235 :
236 143005352 : Reduction DeadCodeElimination::ReducePureNode(Node* node) {
237 : DCHECK_EQ(0, node->op()->EffectInputCount());
238 143005352 : if (node->opcode() == IrOpcode::kDeadValue) return NoChange();
239 142942822 : if (Node* input = FindDeadInput(node)) {
240 106690 : return Replace(DeadValue(input));
241 : }
242 : return NoChange();
243 : }
244 :
245 2216346 : Reduction DeadCodeElimination::ReduceUnreachableOrIfException(Node* node) {
246 : DCHECK(node->opcode() == IrOpcode::kUnreachable ||
247 : node->opcode() == IrOpcode::kIfException);
248 : Reduction reduction = PropagateDeadControl(node);
249 2216340 : if (reduction.Changed()) return reduction;
250 2171451 : Node* effect = NodeProperties::GetEffectInput(node, 0);
251 2171443 : if (effect->opcode() == IrOpcode::kDead) {
252 : return Replace(effect);
253 : }
254 2171366 : if (effect->opcode() == IrOpcode::kUnreachable) {
255 : return Replace(effect);
256 : }
257 : return NoChange();
258 : }
259 :
260 113262188 : Reduction DeadCodeElimination::ReduceEffectNode(Node* node) {
261 : DCHECK_EQ(1, node->op()->EffectInputCount());
262 113262188 : Node* effect = NodeProperties::GetEffectInput(node, 0);
263 113259687 : if (effect->opcode() == IrOpcode::kDead) {
264 : return Replace(effect);
265 : }
266 113251124 : if (Node* input = FindDeadInput(node)) {
267 8485 : if (effect->opcode() == IrOpcode::kUnreachable) {
268 : RelaxEffectsAndControls(node);
269 6937 : return Replace(DeadValue(input));
270 : }
271 :
272 : Node* control = node->op()->ControlInputCount() == 1
273 : ? NodeProperties::GetControlInput(node, 0)
274 1548 : : graph()->start();
275 : Node* unreachable =
276 1548 : graph()->NewNode(common()->Unreachable(), effect, control);
277 : NodeProperties::SetType(unreachable, Type::None());
278 1548 : ReplaceWithValue(node, DeadValue(input), node, control);
279 : return Replace(unreachable);
280 : }
281 :
282 : return NoChange();
283 : }
284 :
285 4643768 : 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 4643775 : if (reduction.Changed()) return reduction;
293 4611250 : if (FindDeadInput(node) != nullptr) {
294 245 : Node* effect = NodeProperties::GetEffectInput(node, 0);
295 245 : Node* control = NodeProperties::GetControlInput(node, 0);
296 245 : if (effect->opcode() != IrOpcode::kUnreachable) {
297 44 : effect = graph()->NewNode(common()->Unreachable(), effect, control);
298 : NodeProperties::SetType(effect, Type::None());
299 : }
300 245 : node->TrimInputCount(2);
301 245 : node->ReplaceInput(0, effect);
302 245 : node->ReplaceInput(1, control);
303 245 : NodeProperties::ChangeOp(node, common()->Throw());
304 : return Changed(node);
305 : }
306 : return NoChange();
307 : }
308 :
309 343443 : Reduction DeadCodeElimination::ReduceLoopExit(Node* node) {
310 343443 : Node* control = NodeProperties::GetControlInput(node, 0);
311 343443 : Node* loop = NodeProperties::GetControlInput(node, 1);
312 674104 : if (control->opcode() == IrOpcode::kDead ||
313 : loop->opcode() == IrOpcode::kDead) {
314 14718 : return RemoveLoopExit(node);
315 : }
316 : return NoChange();
317 : }
318 :
319 10021103 : Reduction DeadCodeElimination::ReduceBranchOrSwitch(Node* node) {
320 : DCHECK(node->opcode() == IrOpcode::kBranch ||
321 : node->opcode() == IrOpcode::kSwitch);
322 : Reduction reduction = PropagateDeadControl(node);
323 10021041 : if (reduction.Changed()) return reduction;
324 9994606 : Node* condition = NodeProperties::GetValueInput(node, 0);
325 9994581 : 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 698 : size_t const projection_cnt = node->op()->ControlOutputCount();
331 698 : Node** projections = zone_->NewArray<Node*>(projection_cnt);
332 : NodeProperties::CollectControlProjections(node, projections,
333 698 : projection_cnt);
334 698 : Replace(projections[0], NodeProperties::GetControlInput(node));
335 : return Replace(dead());
336 : }
337 : return NoChange();
338 : }
339 :
340 245661 : void DeadCodeElimination::TrimMergeOrPhi(Node* node, int size) {
341 245661 : const Operator* const op = common()->ResizeMergeOrPhi(node->op(), size);
342 245661 : node->TrimInputCount(OperatorProperties::GetTotalInputCount(op));
343 245661 : NodeProperties::ChangeOp(node, op);
344 245661 : }
345 :
346 115996 : Node* DeadCodeElimination::DeadValue(Node* node, MachineRepresentation rep) {
347 115996 : if (node->opcode() == IrOpcode::kDeadValue) {
348 57039 : if (rep == DeadValueRepresentationOf(node->op())) return node;
349 864 : node = NodeProperties::GetValueInput(node, 0);
350 : }
351 59821 : Node* dead_value = graph()->NewNode(common()->DeadValue(rep), node);
352 : NodeProperties::SetType(dead_value, Type::None());
353 59821 : return dead_value;
354 : }
355 :
356 : } // namespace compiler
357 : } // namespace internal
358 120216 : } // namespace v8
|