Inlining support in optimizing.

Currently only inlines simple things that don't require an
environment, such as:
- Returning a constant.
- Returning a parameter.
- Returning an arithmetic operation.

Change-Id: Ie844950cb44f69e104774a3cf7a8dea66bc85661
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index ba4dccf..fb941b5 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -167,7 +167,7 @@
   }
 }
 
-void HGraph::TransformToSSA() {
+void HGraph::TransformToSsa() {
   DCHECK(!reverse_post_order_.IsEmpty());
   SsaBuilder ssa_builder(this);
   ssa_builder.BuildSsa();
@@ -682,4 +682,81 @@
   return os;
 }
 
+void HInstruction::InsertBefore(HInstruction* cursor) {
+  next_->previous_ = previous_;
+  if (previous_ != nullptr) {
+    previous_->next_ = next_;
+  }
+  if (block_->instructions_.first_instruction_ == this) {
+    block_->instructions_.first_instruction_ = next_;
+  }
+
+  previous_ = cursor->previous_;
+  if (previous_ != nullptr) {
+    previous_->next_ = this;
+  }
+  next_ = cursor;
+  cursor->previous_ = this;
+  block_ = cursor->block_;
+}
+
+void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
+  // We currently only support graphs with one entry block, one body block, and one exit block.
+  DCHECK_EQ(GetBlocks().Size(), 3u);
+
+  // Walk over the entry block and:
+  // - Move constants from the entry block to the outer_graph's entry block,
+  // - Replace HParameterValue instructions with their real value.
+  // - Remove suspend checks, that hold an environment.
+  int parameter_index = 0;
+  for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
+    HInstruction* current = it.Current();
+    if (current->IsConstant()) {
+      current->InsertBefore(outer_graph->GetEntryBlock()->GetLastInstruction());
+    } else if (current->IsParameterValue()) {
+      current->ReplaceWith(invoke->InputAt(parameter_index++));
+    } else {
+      DCHECK(current->IsGoto() || current->IsSuspendCheck());
+      entry_block_->RemoveInstruction(current);
+    }
+  }
+
+  // Insert the body's instructions except the last, just after the `invoke`
+  // instruction.
+  HBasicBlock* body = GetBlocks().Get(1);
+  DCHECK(!body->IsExitBlock());
+  HInstruction* last = body->GetLastInstruction();
+  HInstruction* first = body->GetFirstInstruction();
+
+  if (first != last) {
+    HInstruction* antelast = last->GetPrevious();
+
+    // Update the instruction list of the body to only contain the last
+    // instruction.
+    last->previous_ = nullptr;
+    body->instructions_.first_instruction_ = last;
+    body->instructions_.last_instruction_ = last;
+
+    // Update the instruction list of the `invoke`'s block to now contain the
+    // body's instructions.
+    antelast->next_ = invoke->GetNext();
+    antelast->next_->previous_ = antelast;
+    first->previous_ = invoke;
+    invoke->next_ = first;
+
+    // Update the block pointer of all instructions.
+    for (HInstruction* current = antelast; current != invoke; current = current->GetPrevious()) {
+      current->SetBlock(invoke->GetBlock());
+    }
+  }
+
+  // Finally, replace the invoke with the return value of the inlined graph.
+  if (last->IsReturn()) {
+    invoke->ReplaceWith(last->InputAt(0));
+    body->RemoveInstruction(last);
+  } else {
+    DCHECK(last->IsReturnVoid());
+  }
+}
+
 }  // namespace art