v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
dead-code-elimination.cc
Go to the documentation of this file.
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
6
11
12namespace v8 {
13namespace internal {
14namespace compiler {
15
18 Zone* temp_zone)
19 : AdvancedReducer(editor),
20 graph_(graph),
21 common_(common),
22 dead_(graph->NewNode(common->Dead())),
23 zone_(temp_zone) {
25}
26
27namespace {
28
29// True if we can guarantee that {node} will never actually produce a value or
30// effect.
31bool NoReturn(Node* node) {
32 return node->opcode() == IrOpcode::kDead ||
33 node->opcode() == IrOpcode::kUnreachable ||
34 node->opcode() == IrOpcode::kDeadValue ||
36}
37
38Node* FindDeadInput(Node* node) {
39 for (Node* input : node->inputs()) {
40 if (NoReturn(input)) return input;
41 }
42 return nullptr;
43}
44
45} // namespace
46
48 switch (node->opcode()) {
49 case IrOpcode::kEnd:
50 return ReduceEnd(node);
51 case IrOpcode::kLoop:
52 case IrOpcode::kMerge:
53 return ReduceLoopOrMerge(node);
54 case IrOpcode::kLoopExit:
55 return ReduceLoopExit(node);
56 case IrOpcode::kUnreachable:
57 case IrOpcode::kIfException:
59 case IrOpcode::kPhi:
60 return ReducePhi(node);
61 case IrOpcode::kEffectPhi:
62 return ReduceEffectPhi(node);
63 case IrOpcode::kDeoptimize:
64 case IrOpcode::kReturn:
65 case IrOpcode::kTerminate:
66 case IrOpcode::kTailCall:
68 case IrOpcode::kThrow:
69 return PropagateDeadControl(node);
70 case IrOpcode::kBranch:
71 case IrOpcode::kSwitch:
72 return ReduceBranchOrSwitch(node);
73 default:
74 return ReduceNode(node);
75 }
77}
78
80 DCHECK_EQ(1, node->op()->ControlInputCount());
82 if (control->opcode() == IrOpcode::kDead) return Replace(control);
83 return NoChange();
84}
85
87 DCHECK_EQ(IrOpcode::kEnd, node->opcode());
88 Node::Inputs inputs = node->inputs();
89 DCHECK_LE(1, inputs.count());
90 int live_input_count = 0;
91 for (int i = 0; i < inputs.count(); ++i) {
92 Node* const input = inputs[i];
93 // Skip dead inputs.
94 if (input->opcode() == IrOpcode::kDead) continue;
95 // Compact live inputs.
96 if (i != live_input_count) node->ReplaceInput(live_input_count, input);
97 ++live_input_count;
98 }
99 if (live_input_count == 0) {
100 return Replace(dead());
101 } else if (live_input_count < inputs.count()) {
102 node->TrimInputCount(live_input_count);
103 NodeProperties::ChangeOp(node, common()->End(live_input_count));
104 return Changed(node);
105 }
106 DCHECK_EQ(inputs.count(), live_input_count);
107 return NoChange();
108}
109
111 DCHECK(IrOpcode::IsMergeOpcode(node->opcode()));
112 Node::Inputs inputs = node->inputs();
113 DCHECK_LE(1, inputs.count());
114 // Count the number of live inputs to {node} and compact them on the fly, also
115 // compacting the inputs of the associated {Phi} and {EffectPhi} uses at the
116 // same time. We consider {Loop}s dead even if only the first control input
117 // is dead.
118 int live_input_count = 0;
119 if (node->opcode() != IrOpcode::kLoop ||
120 node->InputAt(0)->opcode() != IrOpcode::kDead) {
121 for (int i = 0; i < inputs.count(); ++i) {
122 Node* const input = inputs[i];
123 // Skip dead inputs.
124 if (input->opcode() == IrOpcode::kDead) continue;
125 // Compact live inputs.
126 if (live_input_count != i) {
127 node->ReplaceInput(live_input_count, input);
128 for (Node* const use : node->uses()) {
129 if (NodeProperties::IsPhi(use)) {
130 DCHECK_EQ(inputs.count() + 1, use->InputCount());
131 use->ReplaceInput(live_input_count, use->InputAt(i));
132 }
133 }
134 }
135 ++live_input_count;
136 }
137 }
138 if (live_input_count == 0) {
139 return Replace(dead());
140 } else if (live_input_count == 1) {
141 NodeVector loop_exits(zone_);
142 // Due to compaction above, the live input is at offset 0.
143 for (Node* const use : node->uses()) {
144 if (NodeProperties::IsPhi(use)) {
145 Replace(use, use->InputAt(0));
146 } else if (use->opcode() == IrOpcode::kLoopExit &&
147 use->InputAt(1) == node) {
148 // Remember the loop exits so that we can mark their loop input dead.
149 // This has to be done after the use list iteration so that we do
150 // not mutate the use list while it is being iterated.
151 loop_exits.push_back(use);
152 } else if (use->opcode() == IrOpcode::kTerminate) {
153 DCHECK_EQ(IrOpcode::kLoop, node->opcode());
154 Replace(use, dead());
155 }
156 }
157 for (Node* loop_exit : loop_exits) {
158 loop_exit->ReplaceInput(1, dead());
159 Revisit(loop_exit);
160 }
161 return Replace(node->InputAt(0));
162 }
163 DCHECK_LE(2, live_input_count);
164 DCHECK_LE(live_input_count, inputs.count());
165 // Trim input count for the {Merge} or {Loop} node.
166 if (live_input_count < inputs.count()) {
167 // Trim input counts for all phi uses and revisit them.
168 for (Node* const use : node->uses()) {
169 if (NodeProperties::IsPhi(use)) {
170 use->ReplaceInput(live_input_count, node);
171 TrimMergeOrPhi(use, live_input_count);
172 Revisit(use);
173 }
174 }
175 TrimMergeOrPhi(node, live_input_count);
176 return Changed(node);
177 }
178 return NoChange();
179}
180
182 DCHECK_EQ(IrOpcode::kLoopExit, node->opcode());
183 for (Node* const use : node->uses()) {
184 if (use->opcode() == IrOpcode::kLoopExitValue ||
185 use->opcode() == IrOpcode::kLoopExitEffect) {
186 Replace(use, use->InputAt(0));
187 }
188 }
189 Node* control = NodeProperties::GetControlInput(node, 0);
190 Replace(node, control);
191 return Replace(control);
192}
193
195 DCHECK(!IrOpcode::IsGraphTerminator(node->opcode()));
196 int const effect_input_count = node->op()->EffectInputCount();
197 int const control_input_count = node->op()->ControlInputCount();
198 DCHECK_LE(control_input_count, 1);
199 if (control_input_count == 1) {
200 Reduction reduction = PropagateDeadControl(node);
201 if (reduction.Changed()) return reduction;
202 }
203 if (effect_input_count == 0 &&
204 (control_input_count == 0 || node->op()->ControlOutputCount() == 0)) {
205 return ReducePureNode(node);
206 }
207 if (effect_input_count > 0) {
208 return ReduceEffectNode(node);
209 }
210 return NoChange();
211}
212
214 DCHECK_EQ(IrOpcode::kPhi, node->opcode());
215 Reduction reduction = PropagateDeadControl(node);
216 if (reduction.Changed()) return reduction;
218 if (rep == MachineRepresentation::kNone ||
220 return Replace(DeadValue(node, rep));
221 }
222 int input_count = node->op()->ValueInputCount();
223 for (int i = 0; i < input_count; ++i) {
224 Node* input = NodeProperties::GetValueInput(node, i);
225 if (input->opcode() == IrOpcode::kDeadValue &&
226 DeadValueRepresentationOf(input->op()) != rep) {
228 }
229 }
230 return NoChange();
231}
232
234 DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
235 Reduction reduction = PropagateDeadControl(node);
236 if (reduction.Changed()) return reduction;
237
239 DCHECK(merge->opcode() == IrOpcode::kMerge ||
240 merge->opcode() == IrOpcode::kLoop);
241 int input_count = node->op()->EffectInputCount();
242 for (int i = 0; i < input_count; ++i) {
243 Node* effect = NodeProperties::GetEffectInput(node, i);
244 if (effect->opcode() == IrOpcode::kUnreachable) {
245 // If Unreachable hits an effect phi, we can re-connect the effect chain
246 // to the graph end and delete the corresponding inputs from the merge and
247 // phi nodes.
248 Node* control = NodeProperties::GetControlInput(merge, i);
249 Node* throw_node = graph_->NewNode(common_->Throw(), effect, control);
250 MergeControlToEnd(graph_, common_, throw_node);
253 Revisit(merge);
254 reduction = Changed(node);
255 }
256 }
257 return reduction;
258}
259
261 DCHECK_EQ(0, node->op()->EffectInputCount());
262 if (node->opcode() == IrOpcode::kDeadValue) return NoChange();
263 if (Node* input = FindDeadInput(node)) {
264 return Replace(DeadValue(input));
265 }
266 return NoChange();
267}
268
270 DCHECK(node->opcode() == IrOpcode::kUnreachable ||
271 node->opcode() == IrOpcode::kIfException);
272 Reduction reduction = PropagateDeadControl(node);
273 if (reduction.Changed()) return reduction;
274 Node* effect = NodeProperties::GetEffectInput(node, 0);
275 if (effect->opcode() == IrOpcode::kDead) {
276 return Replace(effect);
277 }
278 if (effect->opcode() == IrOpcode::kUnreachable) {
279 return Replace(effect);
280 }
281 return NoChange();
282}
283
285 DCHECK_EQ(1, node->op()->EffectInputCount());
286 Node* effect = NodeProperties::GetEffectInput(node, 0);
287 if (effect->opcode() == IrOpcode::kDead) {
288 return Replace(effect);
289 }
290 if (Node* input = FindDeadInput(node)) {
291 if (effect->opcode() == IrOpcode::kUnreachable) {
292 RelaxEffectsAndControls(node);
293 return Replace(DeadValue(input));
294 }
295
296 Node* control = node->op()->ControlInputCount() == 1
298 : graph()->start();
299 Node* unreachable =
300 graph()->NewNode(common()->Unreachable(), effect, control);
301 NodeProperties::SetType(unreachable, Type::None());
302 ReplaceWithValue(node, DeadValue(input), node, control);
303 return Replace(unreachable);
304 }
305
306 return NoChange();
307}
308
310 Node* node) {
311 DCHECK(node->opcode() == IrOpcode::kDeoptimize ||
312 node->opcode() == IrOpcode::kReturn ||
313 node->opcode() == IrOpcode::kTerminate ||
314 node->opcode() == IrOpcode::kTailCall);
315 Reduction reduction = PropagateDeadControl(node);
316 if (reduction.Changed()) return reduction;
317 // Terminate nodes are not part of actual control flow, so they should never
318 // be replaced with Throw.
319 if (node->opcode() != IrOpcode::kTerminate &&
320 FindDeadInput(node) != nullptr) {
321 Node* effect = NodeProperties::GetEffectInput(node, 0);
322 Node* control = NodeProperties::GetControlInput(node, 0);
323 if (effect->opcode() != IrOpcode::kUnreachable) {
324 effect = graph()->NewNode(common()->Unreachable(), effect, control);
326 }
327 node->TrimInputCount(2);
328 node->ReplaceInput(0, effect);
329 node->ReplaceInput(1, control);
331 return Changed(node);
332 }
333 return NoChange();
334}
335
337 Node* control = NodeProperties::GetControlInput(node, 0);
338 Node* loop = NodeProperties::GetControlInput(node, 1);
339 if (control->opcode() == IrOpcode::kDead ||
340 loop->opcode() == IrOpcode::kDead) {
341 return RemoveLoopExit(node);
342 }
343 return NoChange();
344}
345
347 DCHECK(node->opcode() == IrOpcode::kBranch ||
348 node->opcode() == IrOpcode::kSwitch);
349 Reduction reduction = PropagateDeadControl(node);
350 if (reduction.Changed()) return reduction;
352 if (condition->opcode() == IrOpcode::kDeadValue) {
353 // Branches or switches on {DeadValue} must originate from unreachable code
354 // and cannot matter. Due to schedule freedom between the effect and the
355 // control chain, they might still appear in reachable code. Remove them by
356 // always choosing the first projection.
357 size_t const projection_cnt = node->op()->ControlOutputCount();
358 Node** projections = zone_->AllocateArray<Node*>(projection_cnt);
360 projection_cnt);
361 Replace(projections[0], NodeProperties::GetControlInput(node));
362 return Replace(dead());
363 }
364 return NoChange();
365}
366
368 const Operator* const op = common()->ResizeMergeOrPhi(node->op(), size);
369 node->TrimInputCount(OperatorProperties::GetTotalInputCount(op));
370 NodeProperties::ChangeOp(node, op);
371}
372
374 if (node->opcode() == IrOpcode::kDeadValue) {
375 if (rep == DeadValueRepresentationOf(node->op())) return node;
376 node = NodeProperties::GetValueInput(node, 0);
377 }
378 Node* dead_value = graph()->NewNode(common()->DeadValue(rep), node);
379 NodeProperties::SetType(dead_value, Type::None());
380 return dead_value;
381}
382
383} // namespace compiler
384} // namespace internal
385} // namespace v8
void push_back(const T &value)
T * AllocateArray(size_t length)
Definition zone.h:127
const Operator * ResizeMergeOrPhi(const Operator *op, int size)
Node * DeadValue(Node *none_node, MachineRepresentation rep=MachineRepresentation::kNone)
DeadCodeElimination(Editor *editor, TFGraph *graph, CommonOperatorBuilder *common, Zone *temp_zone)
static bool IsMergeOpcode(Value value)
Definition opcodes.h:1404
static bool IsGraphTerminator(Value value)
Definition opcodes.h:1415
static void ChangeOp(Node *node, const Operator *new_op)
static void ReplaceEffectInput(Node *node, Node *effect, int index=0)
static void ReplaceControlInput(Node *node, Node *control, int index=0)
static Type GetTypeOrAny(const Node *node)
static Node * GetEffectInput(Node *node, int index=0)
static void CollectControlProjections(Node *node, Node **proj, size_t count)
static Node * GetValueInput(Node *node, int index)
static void SetType(Node *node, Type type)
static void ReplaceValueInput(Node *node, Node *value, int index)
static Node * GetControlInput(Node *node, int index=0)
constexpr IrOpcode::Value opcode() const
Definition node.h:52
const Operator * op() const
Definition node.h:50
static int GetTotalInputCount(const Operator *op)
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
Zone * zone_
Node * node
MachineRepresentation PhiRepresentationOf(const Operator *const op)
MachineRepresentation DeadValueRepresentationOf(Operator const *op)
bool IsNone(Tagged< FieldType > obj)
Definition field-type.h:50
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
TFGraph * graph_