diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 81 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 20 | ||||
| -rw-r--r-- | compiler/optimizing/load_store_elimination.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.cc | 29 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 3 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 4 |
6 files changed, 98 insertions, 41 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 8d9794bd79..3dc3b7fba0 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -56,6 +56,8 @@ static constexpr SRegister kFpuCalleeSaves[] = // S registers. Therefore there is no need to block it. static constexpr DRegister DTMP = D31; +static constexpr uint32_t kPackedSwitchJumpTableThreshold = 6; + #define __ down_cast<ArmAssembler*>(codegen->GetAssembler())-> #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value() @@ -513,17 +515,6 @@ void CodeGeneratorARM::Finalize(CodeAllocator* allocator) { uint32_t new_position = __ GetAdjustedPosition(old_position); stack_map_stream_.SetStackMapNativePcOffset(i, new_position); } - // Adjust native pc offsets of block labels. - for (HBasicBlock* block : *block_order_) { - // Get the label directly from block_labels_ rather than through GetLabelOf() to avoid - // FirstNonEmptyBlock() which could lead to adjusting a label more than once. - DCHECK_LT(block->GetBlockId(), GetGraph()->GetBlocks().size()); - Label* block_label = &block_labels_[block->GetBlockId()]; - DCHECK_EQ(block_label->IsBound(), !block->IsSingleJump()); - if (block_label->IsBound()) { - __ AdjustLabelPosition(block_label); - } - } // Adjust pc offsets for the disassembly information. if (disasm_info_ != nullptr) { GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval(); @@ -538,10 +529,6 @@ void CodeGeneratorARM::Finalize(CodeAllocator* allocator) { it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end); } } - // Adjust pc offsets for relative call patches. - for (MethodPatchInfo<Label>& info : relative_call_patches_) { - __ AdjustLabelPosition(&info.label); - } CodeGenerator::Finalize(allocator); } @@ -732,7 +719,8 @@ void CodeGeneratorARM::GenerateFrameExit() { } void CodeGeneratorARM::Bind(HBasicBlock* block) { - __ Bind(GetLabelOf(block)); + Label* label = GetLabelOf(block); + __ BindTrackedLabel(label); } Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const { @@ -5255,7 +5243,7 @@ void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, break; case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: relative_call_patches_.emplace_back(invoke->GetTargetMethod()); - __ Bind(&relative_call_patches_.back().label); + __ BindTrackedLabel(&relative_call_patches_.back().label); // Arbitrarily branch to the BL itself, override at link time. __ bl(&relative_call_patches_.back().label); break; @@ -5378,25 +5366,64 @@ void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall); locations->SetInAt(0, Location::RequiresRegister()); + if (switch_instr->GetNumEntries() >= kPackedSwitchJumpTableThreshold && + codegen_->GetAssembler()->IsThumb()) { + locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base. + if (switch_instr->GetStartValue() != 0) { + locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias. + } + } } void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) { int32_t lower_bound = switch_instr->GetStartValue(); - int32_t num_entries = switch_instr->GetNumEntries(); + uint32_t num_entries = switch_instr->GetNumEntries(); LocationSummary* locations = switch_instr->GetLocations(); Register value_reg = locations->InAt(0).AsRegister<Register>(); HBasicBlock* default_block = switch_instr->GetDefaultBlock(); - // Create a series of compare/jumps. - const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors(); - for (int32_t i = 0; i < num_entries; i++) { - GenerateCompareWithImmediate(value_reg, lower_bound + i); - __ b(codegen_->GetLabelOf(successors[i]), EQ); - } + if (num_entries < kPackedSwitchJumpTableThreshold || !codegen_->GetAssembler()->IsThumb()) { + // Create a series of compare/jumps. + const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors(); + for (uint32_t i = 0; i < num_entries; i++) { + GenerateCompareWithImmediate(value_reg, lower_bound + i); + __ b(codegen_->GetLabelOf(successors[i]), EQ); + } + + // And the default for any other value. + if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) { + __ b(codegen_->GetLabelOf(default_block)); + } + } else { + // Create a table lookup. + Register temp_reg = locations->GetTemp(0).AsRegister<Register>(); + + // Materialize a pointer to the switch table + std::vector<Label*> labels(num_entries); + const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors(); + for (uint32_t i = 0; i < num_entries; i++) { + labels[i] = codegen_->GetLabelOf(successors[i]); + } + JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg); + + // Remove the bias. + Register key_reg; + if (lower_bound != 0) { + key_reg = locations->GetTemp(1).AsRegister<Register>(); + __ AddConstant(key_reg, value_reg, -lower_bound); + } else { + key_reg = value_reg; + } + + // Check whether the value is in the table, jump to default block if not. + __ CmpConstant(key_reg, num_entries - 1); + __ b(codegen_->GetLabelOf(default_block), Condition::HI); + + // Load the displacement from the table. + __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2)); - // And the default for any other value. - if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) { - __ b(codegen_->GetLabelOf(default_block)); + // Dispatch is a direct add to the PC (for Thumb2). + __ EmitJumpTableDispatch(table, temp_reg); } } diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 0aaa6b3f2c..353881e47a 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -494,6 +494,26 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, << " it is in a different dex file and requires access to the dex cache"; return false; } + + if (current->IsNewInstance() && + (current->AsNewInstance()->GetEntrypoint() == kQuickAllocObjectWithAccessCheck)) { + // Allocation entrypoint does not handle inlined frames. + return false; + } + + if (current->IsNewArray() && + (current->AsNewArray()->GetEntrypoint() == kQuickAllocArrayWithAccessCheck)) { + // Allocation entrypoint does not handle inlined frames. + return false; + } + + if (current->IsUnresolvedStaticFieldGet() || + current->IsUnresolvedInstanceFieldGet() || + current->IsUnresolvedStaticFieldSet() || + current->IsUnresolvedInstanceFieldSet()) { + // Entrypoint for unresolved fields does not handle inlined frames. + return false; + } } } number_of_inlined_instructions_ += number_of_instructions; diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 90f28e511e..6fbb6823d6 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -59,7 +59,7 @@ class ReferenceInfo : public ArenaObject<kArenaAllocMisc> { (use->IsInstanceFieldSet() && (reference_ == use->InputAt(1))) || (use->IsUnresolvedInstanceFieldSet() && (reference_ == use->InputAt(1))) || (use->IsStaticFieldSet() && (reference_ == use->InputAt(1))) || - (use->IsUnresolvedStaticFieldSet() && (reference_ == use->InputAt(1))) || + (use->IsUnresolvedStaticFieldSet() && (reference_ == use->InputAt(0))) || (use->IsArraySet() && (reference_ == use->InputAt(2)))) { // reference_ is merged to a phi, passed to a callee, or stored to heap. // reference_ isn't the only name that can refer to its value anymore. diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 8b28ff91d4..68fb0acf7f 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -1652,7 +1652,8 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { // 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`. @@ -1668,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 diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 7df586692b..0f2c1cffee 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -4750,6 +4750,9 @@ class HLoadClass : public HExpression<1> { return generate_clinit_check_; } void SetMustGenerateClinitCheck(bool generate_clinit_check) { + // The entrypoint the code generator is going to call does not do + // clinit of the class. + DCHECK(!NeedsAccessCheck()); generate_clinit_check_ = generate_clinit_check; } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 6632f95ebe..8cb2cfc816 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -492,6 +492,8 @@ static void RunOptimizations(HGraph* graph, RunOptimizations(optimizations1, arraysize(optimizations1), pass_observer); + MaybeRunInliner(graph, codegen, driver, stats, dex_compilation_unit, pass_observer, handles); + // TODO: Update passes incompatible with try/catch so we have the same // pipeline for all methods. if (graph->HasTryCatch()) { @@ -507,8 +509,6 @@ static void RunOptimizations(HGraph* graph, RunOptimizations(optimizations2, arraysize(optimizations2), pass_observer); } else { - MaybeRunInliner(graph, codegen, driver, stats, dex_compilation_unit, pass_observer, handles); - HOptimization* optimizations2[] = { // BooleanSimplifier depends on the InstructionSimplifier removing // redundant suspend checks to recognize empty blocks. |