summaryrefslogtreecommitdiff
path: root/compiler/optimizing/nodes.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/nodes.cc')
-rw-r--r--compiler/optimizing/nodes.cc175
1 files changed, 121 insertions, 54 deletions
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 989970fb49..68fb0acf7f 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -21,6 +21,7 @@
#include "base/bit_vector-inl.h"
#include "base/bit_utils.h"
#include "base/stl_util.h"
+#include "intrinsics.h"
#include "mirror/class-inl.h"
#include "scoped_thread_state_change.h"
@@ -54,7 +55,6 @@ void HGraph::FindBackEdges(ArenaBitVector* visited) {
visiting.ClearBit(current_id);
worklist.pop_back();
} else {
- DCHECK_LT(successors_visited[current_id], current->GetSuccessors().size());
HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
uint32_t successor_id = successor->GetBlockId();
if (visiting.IsBitSet(successor_id)) {
@@ -88,7 +88,7 @@ static void RemoveAsUser(HInstruction* instruction) {
void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const {
for (size_t i = 0; i < blocks_.size(); ++i) {
if (!visited.IsBitSet(i)) {
- HBasicBlock* block = GetBlock(i);
+ HBasicBlock* block = blocks_[i];
DCHECK(block->GetPhis().IsEmpty()) << "Phis are not inserted at this stage";
for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
RemoveAsUser(it.Current());
@@ -100,7 +100,7 @@ void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visit
void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) {
for (size_t i = 0; i < blocks_.size(); ++i) {
if (!visited.IsBitSet(i)) {
- HBasicBlock* block = GetBlock(i);
+ HBasicBlock* block = blocks_[i];
// We only need to update the successor, which might be live.
for (HBasicBlock* successor : block->GetSuccessors()) {
successor->RemovePredecessor(block);
@@ -174,7 +174,6 @@ void HGraph::ComputeDominanceInformation() {
if (successors_visited[current_id] == current->GetSuccessors().size()) {
worklist.pop_back();
} else {
- DCHECK_LT(successors_visited[current_id], current->GetSuccessors().size());
HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
if (successor->GetDominator() == nullptr) {
@@ -185,7 +184,6 @@ void HGraph::ComputeDominanceInformation() {
// Once all the forward edges have been visited, we know the immediate
// dominator of the block. We can then start visiting its successors.
- DCHECK_LT(successor->GetBlockId(), visits.size());
if (++visits[successor->GetBlockId()] ==
successor->GetPredecessors().size() - successor->NumberOfBackEdges()) {
successor->GetDominator()->AddDominatedBlock(successor);
@@ -257,7 +255,7 @@ void HGraph::SimplifyLoop(HBasicBlock* header) {
pre_header->AddInstruction(new (arena_) HGoto(header->GetDexPc()));
for (size_t pred = 0; pred < header->GetPredecessors().size(); ++pred) {
- HBasicBlock* predecessor = header->GetPredecessor(pred);
+ HBasicBlock* predecessor = header->GetPredecessors()[pred];
if (!info->IsBackEdge(*predecessor)) {
predecessor->ReplaceSuccessor(header, pre_header);
pred--;
@@ -267,10 +265,10 @@ void HGraph::SimplifyLoop(HBasicBlock* header) {
}
// Make sure the first predecessor of a loop header is the incoming block.
- if (info->IsBackEdge(*header->GetPredecessor(0))) {
- HBasicBlock* to_swap = header->GetPredecessor(0);
+ if (info->IsBackEdge(*header->GetPredecessors()[0])) {
+ HBasicBlock* to_swap = header->GetPredecessors()[0];
for (size_t pred = 1, e = header->GetPredecessors().size(); pred < e; ++pred) {
- HBasicBlock* predecessor = header->GetPredecessor(pred);
+ HBasicBlock* predecessor = header->GetPredecessors()[pred];
if (!info->IsBackEdge(*predecessor)) {
header->predecessors_[pred] = to_swap;
header->predecessors_[0] = predecessor;
@@ -293,7 +291,7 @@ void HGraph::SimplifyLoop(HBasicBlock* header) {
}
static bool CheckIfPredecessorAtIsExceptional(const HBasicBlock& block, size_t pred_idx) {
- HBasicBlock* predecessor = block.GetPredecessor(pred_idx);
+ HBasicBlock* predecessor = block.GetPredecessors()[pred_idx];
if (!predecessor->EndsWithTryBoundary()) {
// Only edges from HTryBoundary can be exceptional.
return false;
@@ -343,7 +341,7 @@ void HGraph::SimplifyCatchBlocks() {
HBasicBlock* normal_block = catch_block->SplitBefore(catch_block->GetFirstInstruction());
for (size_t j = 0; j < catch_block->GetPredecessors().size(); ++j) {
if (!CheckIfPredecessorAtIsExceptional(*catch_block, j)) {
- catch_block->GetPredecessor(j)->ReplaceSuccessor(catch_block, normal_block);
+ catch_block->GetPredecessors()[j]->ReplaceSuccessor(catch_block, normal_block);
--j;
}
}
@@ -365,7 +363,7 @@ void HGraph::ComputeTryBlockInformation() {
// Infer try membership from the first predecessor. Having simplified loops,
// the first predecessor can never be a back edge and therefore it must have
// been visited already and had its try membership set.
- HBasicBlock* first_predecessor = block->GetPredecessor(0);
+ HBasicBlock* first_predecessor = block->GetPredecessors()[0];
DCHECK(!block->IsLoopHeader() || !block->GetLoopInformation()->IsBackEdge(*first_predecessor));
const HTryBoundary* try_entry = first_predecessor->ComputeTryEntryOfSuccessors();
if (try_entry != nullptr) {
@@ -385,7 +383,7 @@ void HGraph::SimplifyCFG() {
if (block == nullptr) continue;
if (block->NumberOfNormalSuccessors() > 1) {
for (size_t j = 0; j < block->GetSuccessors().size(); ++j) {
- HBasicBlock* successor = block->GetSuccessor(j);
+ HBasicBlock* successor = block->GetSuccessors()[j];
DCHECK(!successor->IsCatchBlock());
if (successor->GetPredecessors().size() > 1) {
SplitCriticalEdge(block, successor);
@@ -534,7 +532,7 @@ bool HLoopInformation::Populate() {
void HLoopInformation::Update() {
HGraph* graph = header_->GetGraph();
for (uint32_t id : blocks_.Indexes()) {
- HBasicBlock* block = graph->GetBlock(id);
+ HBasicBlock* block = graph->GetBlocks()[id];
// Reset loop information of non-header blocks inside the loop, except
// members of inner nested loops because those should already have been
// updated by their own LoopInformation.
@@ -576,6 +574,17 @@ bool HLoopInformation::IsIn(const HLoopInformation& other) const {
return other.blocks_.IsBitSet(header_->GetBlockId());
}
+bool HLoopInformation::IsLoopInvariant(HInstruction* instruction, bool must_dominate) const {
+ HLoopInformation* other_loop = instruction->GetBlock()->GetLoopInformation();
+ if (other_loop != this && (other_loop == nullptr || !other_loop->IsIn(*this))) {
+ if (must_dominate) {
+ return instruction->GetBlock()->Dominates(GetHeader());
+ }
+ return true;
+ }
+ return false;
+}
+
size_t HLoopInformation::GetLifetimeEnd() const {
size_t last_position = 0;
for (HBasicBlock* back_edge : GetBackEdges()) {
@@ -608,8 +617,23 @@ static void UpdateInputsUsers(HInstruction* instruction) {
void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
HInstruction* replacement) {
DCHECK(initial->GetBlock() == this);
- InsertInstructionBefore(replacement, initial);
- initial->ReplaceWith(replacement);
+ if (initial->IsControlFlow()) {
+ // We can only replace a control flow instruction with another control flow instruction.
+ DCHECK(replacement->IsControlFlow());
+ DCHECK_EQ(replacement->GetId(), -1);
+ DCHECK_EQ(replacement->GetType(), Primitive::kPrimVoid);
+ DCHECK_EQ(initial->GetBlock(), this);
+ DCHECK_EQ(initial->GetType(), Primitive::kPrimVoid);
+ DCHECK(initial->GetUses().IsEmpty());
+ DCHECK(initial->GetEnvUses().IsEmpty());
+ replacement->SetBlock(this);
+ replacement->SetId(GetGraph()->GetNextInstructionId());
+ instructions_.InsertInstructionBefore(replacement, initial);
+ UpdateInputsUsers(replacement);
+ } else {
+ InsertInstructionBefore(replacement, initial);
+ initial->ReplaceWith(replacement);
+ }
RemoveInstruction(initial);
}
@@ -743,7 +767,6 @@ void HEnvironment::CopyFromWithLoopPhiAdjustment(HEnvironment* env,
}
void HEnvironment::RemoveAsUserOfInput(size_t index) const {
- DCHECK_LT(index, Size());
const HUserRecord<HEnvironment*>& user_record = vregs_[index];
user_record.GetInstruction()->RemoveEnvironmentUser(user_record.GetUseNode());
}
@@ -1435,7 +1458,7 @@ void HBasicBlock::MergeWith(HBasicBlock* other) {
// Update links to the successors of `other`.
successors_.clear();
while (!other->successors_.empty()) {
- HBasicBlock* successor = other->GetSuccessor(0);
+ HBasicBlock* successor = other->GetSuccessors()[0];
successor->ReplacePredecessor(other, this);
}
@@ -1472,7 +1495,7 @@ void HBasicBlock::MergeWithInlined(HBasicBlock* other) {
// Update links to the successors of `other`.
successors_.clear();
while (!other->successors_.empty()) {
- HBasicBlock* successor = other->GetSuccessor(0);
+ HBasicBlock* successor = other->GetSuccessors()[0];
successor->ReplacePredecessor(other, this);
}
@@ -1488,11 +1511,11 @@ void HBasicBlock::MergeWithInlined(HBasicBlock* other) {
void HBasicBlock::ReplaceWith(HBasicBlock* other) {
while (!GetPredecessors().empty()) {
- HBasicBlock* predecessor = GetPredecessor(0);
+ HBasicBlock* predecessor = GetPredecessors()[0];
predecessor->ReplaceSuccessor(this, other);
}
while (!GetSuccessors().empty()) {
- HBasicBlock* successor = GetSuccessor(0);
+ HBasicBlock* successor = GetSuccessors()[0];
successor->ReplacePredecessor(this, other);
}
for (HBasicBlock* dominated : GetDominatedBlocks()) {
@@ -1567,9 +1590,9 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
if (GetBlocks().size() == 3) {
// Simple case of an entry block, a body block, and an exit block.
// Put the body block's instruction into `invoke`'s block.
- HBasicBlock* body = GetBlock(1);
- DCHECK(GetBlock(0)->IsEntryBlock());
- DCHECK(GetBlock(2)->IsExitBlock());
+ HBasicBlock* body = GetBlocks()[1];
+ DCHECK(GetBlocks()[0]->IsEntryBlock());
+ DCHECK(GetBlocks()[2]->IsExitBlock());
DCHECK(!body->IsExitBlock());
HInstruction* last = body->GetLastInstruction();
@@ -1579,7 +1602,6 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
// Replace the invoke with the return value of the inlined graph.
if (last->IsReturn()) {
return_value = last->InputAt(0);
- invoke->ReplaceWith(return_value);
} else {
DCHECK(last->IsReturnVoid());
}
@@ -1594,16 +1616,16 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
HBasicBlock* at = invoke->GetBlock();
HBasicBlock* to = at->SplitAfter(invoke);
- HBasicBlock* first = entry_block_->GetSuccessor(0);
+ HBasicBlock* first = entry_block_->GetSuccessors()[0];
DCHECK(!first->IsInLoop());
at->MergeWithInlined(first);
exit_block_->ReplaceWith(to);
// Update all predecessors of the exit block (now the `to` block)
// to not `HReturn` but `HGoto` instead.
- bool returns_void = to->GetPredecessor(0)->GetLastInstruction()->IsReturnVoid();
+ bool returns_void = to->GetPredecessors()[0]->GetLastInstruction()->IsReturnVoid();
if (to->GetPredecessors().size() == 1) {
- HBasicBlock* predecessor = to->GetPredecessor(0);
+ HBasicBlock* predecessor = to->GetPredecessors()[0];
HInstruction* last = predecessor->GetLastInstruction();
if (!returns_void) {
return_value = last->InputAt(0);
@@ -1627,14 +1649,11 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
}
}
- if (return_value != nullptr) {
- invoke->ReplaceWith(return_value);
- }
-
// Update the meta information surrounding blocks:
// (1) the graph they are now in,
// (2) the reverse post order of that graph,
- // (3) the potential loop information they are now in.
+ // (3) the potential loop information they are now in,
+ // (4) try block membership.
// We don't add the entry block, the exit block, and the first block, which
// has been merged with `at`.
@@ -1650,41 +1669,47 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
size_t index_of_at = IndexOfElement(outer_graph->reverse_post_order_, at);
MakeRoomFor(&outer_graph->reverse_post_order_, blocks_added, index_of_at);
- // Do a reverse post order of the blocks in the callee and do (1), (2),
- // and (3) to the blocks that apply.
- HLoopInformation* info = at->GetLoopInformation();
+ HLoopInformation* loop_info = at->GetLoopInformation();
+ // Copy TryCatchInformation if `at` is a try block, not if it is a catch block.
+ TryCatchInformation* try_catch_info = at->IsTryBlock() ? at->GetTryCatchInformation() : nullptr;
+
+ // Do a reverse post order of the blocks in the callee and do (1), (2), (3)
+ // and (4) to the blocks that apply.
for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
HBasicBlock* current = it.Current();
if (current != exit_block_ && current != entry_block_ && current != first) {
DCHECK(!current->IsInLoop());
+ DCHECK(current->GetTryCatchInformation() == nullptr);
DCHECK(current->GetGraph() == this);
current->SetGraph(outer_graph);
outer_graph->AddBlock(current);
outer_graph->reverse_post_order_[++index_of_at] = current;
- if (info != nullptr) {
- current->SetLoopInformation(info);
+ if (loop_info != nullptr) {
+ current->SetLoopInformation(loop_info);
for (HLoopInformationOutwardIterator loop_it(*at); !loop_it.Done(); loop_it.Advance()) {
loop_it.Current()->Add(current);
}
}
+ current->SetTryCatchInformation(try_catch_info);
}
}
- // Do (1), (2), and (3) to `to`.
+ // Do (1), (2), (3) and (4) to `to`.
to->SetGraph(outer_graph);
outer_graph->AddBlock(to);
outer_graph->reverse_post_order_[++index_of_at] = to;
- if (info != nullptr) {
- to->SetLoopInformation(info);
+ if (loop_info != nullptr) {
+ to->SetLoopInformation(loop_info);
for (HLoopInformationOutwardIterator loop_it(*at); !loop_it.Done(); loop_it.Advance()) {
loop_it.Current()->Add(to);
}
- if (info->IsBackEdge(*at)) {
+ if (loop_info->IsBackEdge(*at)) {
// Only `to` can become a back edge, as the inlined blocks
// are predecessors of `to`.
- info->ReplaceBackEdge(at, to);
+ loop_info->ReplaceBackEdge(at, to);
}
}
+ to->SetTryCatchInformation(try_catch_info);
}
// Update the next instruction id of the outer graph, so that instructions
@@ -1700,20 +1725,21 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
size_t parameter_index = 0;
for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
HInstruction* current = it.Current();
+ HInstruction* replacement = nullptr;
if (current->IsNullConstant()) {
- current->ReplaceWith(outer_graph->GetNullConstant(current->GetDexPc()));
+ replacement = outer_graph->GetNullConstant(current->GetDexPc());
} else if (current->IsIntConstant()) {
- current->ReplaceWith(outer_graph->GetIntConstant(
- current->AsIntConstant()->GetValue(), current->GetDexPc()));
+ replacement = outer_graph->GetIntConstant(
+ current->AsIntConstant()->GetValue(), current->GetDexPc());
} else if (current->IsLongConstant()) {
- current->ReplaceWith(outer_graph->GetLongConstant(
- current->AsLongConstant()->GetValue(), current->GetDexPc()));
+ replacement = outer_graph->GetLongConstant(
+ current->AsLongConstant()->GetValue(), current->GetDexPc());
} else if (current->IsFloatConstant()) {
- current->ReplaceWith(outer_graph->GetFloatConstant(
- current->AsFloatConstant()->GetValue(), current->GetDexPc()));
+ replacement = outer_graph->GetFloatConstant(
+ current->AsFloatConstant()->GetValue(), current->GetDexPc());
} else if (current->IsDoubleConstant()) {
- current->ReplaceWith(outer_graph->GetDoubleConstant(
- current->AsDoubleConstant()->GetValue(), current->GetDexPc()));
+ replacement = outer_graph->GetDoubleConstant(
+ current->AsDoubleConstant()->GetValue(), current->GetDexPc());
} else if (current->IsParameterValue()) {
if (kIsDebugBuild
&& invoke->IsInvokeStaticOrDirect()
@@ -1723,13 +1749,25 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
size_t last_input_index = invoke->InputCount() - 1;
DCHECK(parameter_index != last_input_index);
}
- current->ReplaceWith(invoke->InputAt(parameter_index++));
+ replacement = invoke->InputAt(parameter_index++);
} else if (current->IsCurrentMethod()) {
- current->ReplaceWith(outer_graph->GetCurrentMethod());
+ replacement = outer_graph->GetCurrentMethod();
} else {
DCHECK(current->IsGoto() || current->IsSuspendCheck());
entry_block_->RemoveInstruction(current);
}
+ if (replacement != nullptr) {
+ current->ReplaceWith(replacement);
+ // If the current is the return value then we need to update the latter.
+ if (current == return_value) {
+ DCHECK_EQ(entry_block_, return_value->GetBlock());
+ return_value = replacement;
+ }
+ }
+ }
+
+ if (return_value != nullptr) {
+ invoke->ReplaceWith(return_value);
}
// Finally remove the invoke from the caller.
@@ -1873,6 +1911,35 @@ bool HInstruction::HasAnyEnvironmentUseBefore(HInstruction* other) {
return false;
}
+void HInvoke::SetIntrinsic(Intrinsics intrinsic,
+ IntrinsicNeedsEnvironmentOrCache needs_env_or_cache) {
+ intrinsic_ = intrinsic;
+ IntrinsicOptimizations opt(this);
+ if (needs_env_or_cache == kNoEnvironmentOrCache) {
+ opt.SetDoesNotNeedDexCache();
+ opt.SetDoesNotNeedEnvironment();
+ }
+}
+
+bool HInvoke::NeedsEnvironment() const {
+ if (!IsIntrinsic()) {
+ return true;
+ }
+ IntrinsicOptimizations opt(*this);
+ return !opt.GetDoesNotNeedEnvironment();
+}
+
+bool HInvokeStaticOrDirect::NeedsDexCacheOfDeclaringClass() const {
+ if (GetMethodLoadKind() != MethodLoadKind::kDexCacheViaMethod) {
+ return false;
+ }
+ if (!IsIntrinsic()) {
+ return true;
+ }
+ IntrinsicOptimizations opt(*this);
+ return !opt.GetDoesNotNeedDexCache();
+}
+
void HInstruction::RemoveEnvironmentUsers() {
for (HUseIterator<HEnvironment*> use_it(GetEnvUses()); !use_it.Done(); use_it.Advance()) {
HUseListNode<HEnvironment*>* user_node = use_it.Current();