| // Copyright 2015 the V8 project authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "src/compiler/dead-code-elimination.h" | 
 |  | 
 | #include "src/compiler/common-operator.h" | 
 | #include "src/compiler/graph.h" | 
 | #include "src/compiler/node-properties.h" | 
 | #include "src/compiler/operator-properties.h" | 
 |  | 
 | namespace v8 { | 
 | namespace internal { | 
 | namespace compiler { | 
 |  | 
 | DeadCodeElimination::DeadCodeElimination(Editor* editor, Graph* graph, | 
 |                                          CommonOperatorBuilder* common) | 
 |     : AdvancedReducer(editor), | 
 |       graph_(graph), | 
 |       common_(common), | 
 |       dead_(graph->NewNode(common->Dead())) {} | 
 |  | 
 |  | 
 | Reduction DeadCodeElimination::Reduce(Node* node) { | 
 |   switch (node->opcode()) { | 
 |     case IrOpcode::kEnd: | 
 |       return ReduceEnd(node); | 
 |     case IrOpcode::kLoop: | 
 |     case IrOpcode::kMerge: | 
 |       return ReduceLoopOrMerge(node); | 
 |     default: | 
 |       return ReduceNode(node); | 
 |   } | 
 |   UNREACHABLE(); | 
 |   return NoChange(); | 
 | } | 
 |  | 
 |  | 
 | Reduction DeadCodeElimination::ReduceEnd(Node* node) { | 
 |   DCHECK_EQ(IrOpcode::kEnd, node->opcode()); | 
 |   int const input_count = node->InputCount(); | 
 |   DCHECK_LE(1, input_count); | 
 |   int live_input_count = 0; | 
 |   for (int i = 0; i < input_count; ++i) { | 
 |     Node* const input = node->InputAt(i); | 
 |     // Skip dead inputs. | 
 |     if (input->opcode() == IrOpcode::kDead) continue; | 
 |     // Compact live inputs. | 
 |     if (i != live_input_count) node->ReplaceInput(live_input_count, input); | 
 |     ++live_input_count; | 
 |   } | 
 |   if (live_input_count == 0) { | 
 |     return Replace(dead()); | 
 |   } else if (live_input_count < input_count) { | 
 |     node->TrimInputCount(live_input_count); | 
 |     NodeProperties::ChangeOp(node, common()->End(live_input_count)); | 
 |     return Changed(node); | 
 |   } | 
 |   DCHECK_EQ(input_count, live_input_count); | 
 |   return NoChange(); | 
 | } | 
 |  | 
 |  | 
 | Reduction DeadCodeElimination::ReduceLoopOrMerge(Node* node) { | 
 |   DCHECK(IrOpcode::IsMergeOpcode(node->opcode())); | 
 |   int const input_count = node->InputCount(); | 
 |   DCHECK_LE(1, input_count); | 
 |   // Count the number of live inputs to {node} and compact them on the fly, also | 
 |   // compacting the inputs of the associated {Phi} and {EffectPhi} uses at the | 
 |   // same time.  We consider {Loop}s dead even if only the first control input | 
 |   // is dead. | 
 |   int live_input_count = 0; | 
 |   if (node->opcode() != IrOpcode::kLoop || | 
 |       node->InputAt(0)->opcode() != IrOpcode::kDead) { | 
 |     for (int i = 0; i < input_count; ++i) { | 
 |       Node* const input = node->InputAt(i); | 
 |       // Skip dead inputs. | 
 |       if (input->opcode() == IrOpcode::kDead) continue; | 
 |       // Compact live inputs. | 
 |       if (live_input_count != i) { | 
 |         node->ReplaceInput(live_input_count, input); | 
 |         for (Node* const use : node->uses()) { | 
 |           if (NodeProperties::IsPhi(use)) { | 
 |             DCHECK_EQ(input_count + 1, use->InputCount()); | 
 |             use->ReplaceInput(live_input_count, use->InputAt(i)); | 
 |           } | 
 |         } | 
 |       } | 
 |       ++live_input_count; | 
 |     } | 
 |   } | 
 |   if (live_input_count == 0) { | 
 |     return Replace(dead()); | 
 |   } else if (live_input_count == 1) { | 
 |     // Due to compaction above, the live input is at offset 0. | 
 |     for (Node* const use : node->uses()) { | 
 |       if (NodeProperties::IsPhi(use)) { | 
 |         Replace(use, use->InputAt(0)); | 
 |       } else if (use->opcode() == IrOpcode::kTerminate) { | 
 |         DCHECK_EQ(IrOpcode::kLoop, node->opcode()); | 
 |         Replace(use, dead()); | 
 |       } | 
 |     } | 
 |     return Replace(node->InputAt(0)); | 
 |   } | 
 |   DCHECK_LE(2, live_input_count); | 
 |   DCHECK_LE(live_input_count, input_count); | 
 |   // Trim input count for the {Merge} or {Loop} node. | 
 |   if (live_input_count < input_count) { | 
 |     // Trim input counts for all phi uses and revisit them. | 
 |     for (Node* const use : node->uses()) { | 
 |       if (NodeProperties::IsPhi(use)) { | 
 |         use->ReplaceInput(live_input_count, node); | 
 |         TrimMergeOrPhi(use, live_input_count); | 
 |         Revisit(use); | 
 |       } | 
 |     } | 
 |     TrimMergeOrPhi(node, live_input_count); | 
 |     return Changed(node); | 
 |   } | 
 |   return NoChange(); | 
 | } | 
 |  | 
 |  | 
 | Reduction DeadCodeElimination::ReduceNode(Node* node) { | 
 |   // If {node} has exactly one control input and this is {Dead}, | 
 |   // replace {node} with {Dead}. | 
 |   int const control_input_count = node->op()->ControlInputCount(); | 
 |   if (control_input_count == 0) return NoChange(); | 
 |   DCHECK_EQ(1, control_input_count); | 
 |   Node* control = NodeProperties::GetControlInput(node); | 
 |   if (control->opcode() == IrOpcode::kDead) return Replace(control); | 
 |   return NoChange(); | 
 | } | 
 |  | 
 |  | 
 | void DeadCodeElimination::TrimMergeOrPhi(Node* node, int size) { | 
 |   const Operator* const op = common()->ResizeMergeOrPhi(node->op(), size); | 
 |   node->TrimInputCount(OperatorProperties::GetTotalInputCount(op)); | 
 |   NodeProperties::ChangeOp(node, op); | 
 | } | 
 |  | 
 | }  // namespace compiler | 
 | }  // namespace internal | 
 | }  // namespace v8 |