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