diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/bounds_check_elimination.cc | 33 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 13 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm.cc | 7 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 7 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_mips64.cc | 11 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 6 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 6 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.cc | 61 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 1 |
9 files changed, 100 insertions, 45 deletions
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc index a7a1c0f2c4..f2929bcc18 100644 --- a/compiler/optimizing/bounds_check_elimination.cc +++ b/compiler/optimizing/bounds_check_elimination.cc @@ -533,6 +533,8 @@ class BCEVisitor : public HGraphVisitor { first_index_bounds_check_map_( std::less<int>(), graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)), + dynamic_bce_standby_( + graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)), early_exit_loop_( std::less<uint32_t>(), graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)), @@ -553,6 +555,13 @@ class BCEVisitor : public HGraphVisitor { } void Finish() { + // Retry dynamic bce candidates on standby that are still in the graph. + for (HBoundsCheck* bounds_check : dynamic_bce_standby_) { + if (bounds_check->IsInBlock()) { + TryDynamicBCE(bounds_check); + } + } + // Preserve SSA structure which may have been broken by adding one or more // new taken-test structures (see TransformLoopForDeoptimizationIfNeeded()). InsertPhiNodes(); @@ -561,6 +570,7 @@ class BCEVisitor : public HGraphVisitor { early_exit_loop_.clear(); taken_test_loop_.clear(); finite_loop_.clear(); + dynamic_bce_standby_.clear(); } private: @@ -1301,7 +1311,7 @@ class BCEVisitor : public HGraphVisitor { if (DynamicBCESeemsProfitable(loop, instruction->GetBlock()) && induction_range_.CanGenerateCode( instruction, index, &needs_finite_test, &needs_taken_test) && - CanHandleInfiniteLoop(loop, index, needs_finite_test) && + CanHandleInfiniteLoop(loop, instruction, index, needs_finite_test) && CanHandleLength(loop, length, needs_taken_test)) { // do this test last (may code gen) HInstruction* lower = nullptr; HInstruction* upper = nullptr; @@ -1433,7 +1443,7 @@ class BCEVisitor : public HGraphVisitor { * ensure the loop is finite. */ bool CanHandleInfiniteLoop( - HLoopInformation* loop, HInstruction* index, bool needs_infinite_test) { + HLoopInformation* loop, HBoundsCheck* check, HInstruction* index, bool needs_infinite_test) { if (needs_infinite_test) { // If we already forced the loop to be finite, allow directly. const uint32_t loop_id = loop->GetHeader()->GetBlockId(); @@ -1455,6 +1465,9 @@ class BCEVisitor : public HGraphVisitor { } } } + // If bounds check made it this far, it is worthwhile to check later if + // the loop was forced finite by another candidate. + dynamic_bce_standby_.push_back(check); return false; } return true; @@ -1676,6 +1689,9 @@ class BCEVisitor : public HGraphVisitor { // in a block that checks an index against that HArrayLength. ArenaSafeMap<int, HBoundsCheck*> first_index_bounds_check_map_; + // Stand by list for dynamic bce. + ArenaVector<HBoundsCheck*> dynamic_bce_standby_; + // Early-exit loop bookkeeping. ArenaSafeMap<uint32_t, bool> early_exit_loop_; @@ -1711,21 +1727,18 @@ void BoundsCheckElimination::Run() { // that value dominated by that instruction fits in that range. Range of that // value can be narrowed further down in the dominator tree. BCEVisitor visitor(graph_, side_effects_, induction_analysis_); - HBasicBlock* last_visited_block = nullptr; for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) { HBasicBlock* current = it.Current(); - if (current == last_visited_block) { - // We may insert blocks into the reverse post order list when processing - // a loop header. Don't process it again. - DCHECK(current->IsLoopHeader()); - continue; - } if (visitor.IsAddedBlock(current)) { // Skip added blocks. Their effects are already taken care of. continue; } visitor.VisitBasicBlock(current); - last_visited_block = current; + // Skip forward to the current block in case new basic blocks were inserted + // (which always appear earlier in reverse post order) to avoid visiting the + // same basic block twice. + for ( ; !it.Done() && it.Current() != current; it.Advance()) { + } } // Perform cleanup. diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 3f67e481f9..3e3719e6ea 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1010,6 +1010,8 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, // at runtime, we change this call as if it was a virtual call. invoke_type = kVirtual; } + + const int32_t caller_instruction_counter = graph_->GetCurrentInstructionId(); HGraph* callee_graph = new (graph_->GetArena()) HGraph( graph_->GetArena(), callee_dex_file, @@ -1019,7 +1021,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, invoke_type, graph_->IsDebuggable(), /* osr */ false, - graph_->GetCurrentInstructionId()); + caller_instruction_counter); callee_graph->SetArtMethod(resolved_method); OptimizingCompilerStats inline_stats; @@ -1219,7 +1221,16 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, } number_of_inlined_instructions_ += number_of_instructions; + DCHECK_EQ(caller_instruction_counter, graph_->GetCurrentInstructionId()) + << "No instructions can be added to the outer graph while inner graph is being built"; + + const int32_t callee_instruction_counter = callee_graph->GetCurrentInstructionId(); + graph_->SetCurrentInstructionId(callee_instruction_counter); *return_replacement = callee_graph->InlineInto(graph_, invoke_instruction); + + DCHECK_EQ(callee_instruction_counter, callee_graph->GetCurrentInstructionId()) + << "No instructions can be added to the inner graph during inlining into the outer graph"; + return true; } diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 4ce919ee39..276085ef30 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -1151,6 +1151,7 @@ static void GenerateVisitStringIndexOf(HInvoke* invoke, __ LoadFromOffset(kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pIndexOf).Int32Value()); + CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>(); __ blx(LR); if (slow_path != nullptr) { @@ -1242,6 +1243,12 @@ void IntrinsicLocationsBuilderARM::VisitStringNewStringFromChars(HInvoke* invoke void IntrinsicCodeGeneratorARM::VisitStringNewStringFromChars(HInvoke* invoke) { ArmAssembler* assembler = GetAssembler(); + // No need to emit code checking whether `locations->InAt(2)` is a null + // pointer, as callers of the native method + // + // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data) + // + // all include a null check on `data` before calling that method. __ LoadFromOffset( kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromChars).Int32Value()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 4be1695a94..9f9d8c493f 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -1301,6 +1301,7 @@ static void GenerateVisitStringIndexOf(HInvoke* invoke, } __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pIndexOf).Int32Value())); + CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>(); __ Blr(lr); if (slow_path != nullptr) { @@ -1392,6 +1393,12 @@ void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromChars(HInvoke* invo void IntrinsicCodeGeneratorARM64::VisitStringNewStringFromChars(HInvoke* invoke) { vixl::MacroAssembler* masm = GetVIXLAssembler(); + // No need to emit code checking whether `locations->InAt(2)` is a null + // pointer, as callers of the native method + // + // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data) + // + // all include a null check on `data` before calling that method. __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocStringFromChars).Int32Value())); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index ca2652b74a..a7a2560043 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -1636,6 +1636,7 @@ static void GenerateStringIndexOf(HInvoke* invoke, TMP, TR, QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pIndexOf).Int32Value()); + CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>(); __ Jalr(TMP); __ Nop(); @@ -1685,7 +1686,7 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) { invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false); } -// java.lang.String.String(byte[] bytes) +// java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount) void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke) { LocationSummary* locations = new (arena_) LocationSummary(invoke, LocationSummary::kCall, @@ -1719,7 +1720,7 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke __ Bind(slow_path->GetExitLabel()); } -// java.lang.String.String(char[] value) +// java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data) void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromChars(HInvoke* invoke) { LocationSummary* locations = new (arena_) LocationSummary(invoke, LocationSummary::kCall, @@ -1735,6 +1736,12 @@ void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromChars(HInvoke* inv void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromChars(HInvoke* invoke) { Mips64Assembler* assembler = GetAssembler(); + // No need to emit code checking whether `locations->InAt(2)` is a null + // pointer, as callers of the native method + // + // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data) + // + // all include a null check on `data` before calling that method. __ LoadFromOffset(kLoadDoubleword, TMP, TR, diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 0df4553f56..bfa4e374f7 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -1564,6 +1564,12 @@ void IntrinsicLocationsBuilderX86::VisitStringNewStringFromChars(HInvoke* invoke void IntrinsicCodeGeneratorX86::VisitStringNewStringFromChars(HInvoke* invoke) { X86Assembler* assembler = GetAssembler(); + // No need to emit code checking whether `locations->InAt(2)` is a null + // pointer, as callers of the native method + // + // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data) + // + // all include a null check on `data` before calling that method. __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocStringFromChars))); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 2a9e684d11..15c399712d 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -1659,6 +1659,12 @@ void IntrinsicLocationsBuilderX86_64::VisitStringNewStringFromChars(HInvoke* inv void IntrinsicCodeGeneratorX86_64::VisitStringNewStringFromChars(HInvoke* invoke) { X86_64Assembler* assembler = GetAssembler(); + // No need to emit code checking whether `locations->InAt(2)` is a null + // pointer, as callers of the native method + // + // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data) + // + // all include a null check on `data` before calling that method. __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocStringFromChars), /* no_rip */ true)); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 87b9c022df..0e0b83e4b4 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -1976,34 +1976,6 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { 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->GetPredecessors()[0]->GetLastInstruction()->IsReturnVoid(); - if (to->GetPredecessors().size() == 1) { - HBasicBlock* predecessor = to->GetPredecessors()[0]; - HInstruction* last = predecessor->GetLastInstruction(); - if (!returns_void) { - return_value = last->InputAt(0); - } - predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc())); - predecessor->RemoveInstruction(last); - } else { - if (!returns_void) { - // There will be multiple returns. - return_value = new (allocator) HPhi( - allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()), to->GetDexPc()); - to->AddPhi(return_value->AsPhi()); - } - for (HBasicBlock* predecessor : to->GetPredecessors()) { - HInstruction* last = predecessor->GetLastInstruction(); - if (!returns_void) { - return_value->AsPhi()->AddInput(last->InputAt(0)); - } - predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc())); - predecessor->RemoveInstruction(last); - } - } - // Update the meta information surrounding blocks: // (1) the graph they are now in, // (2) the reverse post order of that graph, @@ -2048,11 +2020,36 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { // Only `to` can become a back edge, as the inlined blocks // are predecessors of `to`. UpdateLoopAndTryInformationOfNewBlock(to, at, /* replace_if_back_edge */ true); - } - // Update the next instruction id of the outer graph, so that instructions - // added later get bigger ids than those in the inner graph. - outer_graph->SetCurrentInstructionId(GetNextInstructionId()); + // Update all predecessors of the exit block (now the `to` block) + // to not `HReturn` but `HGoto` instead. + bool returns_void = to->GetPredecessors()[0]->GetLastInstruction()->IsReturnVoid(); + if (to->GetPredecessors().size() == 1) { + HBasicBlock* predecessor = to->GetPredecessors()[0]; + HInstruction* last = predecessor->GetLastInstruction(); + if (!returns_void) { + return_value = last->InputAt(0); + } + predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc())); + predecessor->RemoveInstruction(last); + } else { + if (!returns_void) { + // There will be multiple returns. + return_value = new (allocator) HPhi( + allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()), to->GetDexPc()); + to->AddPhi(return_value->AsPhi()); + } + for (HBasicBlock* predecessor : to->GetPredecessors()) { + HInstruction* last = predecessor->GetLastInstruction(); + if (!returns_void) { + DCHECK(last->IsReturn()); + return_value->AsPhi()->AddInput(last->InputAt(0)); + } + predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc())); + predecessor->RemoveInstruction(last); + } + } + } // Walk over the entry block and: // - Move constants from the entry block to the outer_graph's entry block, diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index e3dbe16547..b684cc697f 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -387,6 +387,7 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { } void SetCurrentInstructionId(int32_t id) { + DCHECK_GE(id, current_instruction_id_); current_instruction_id_ = id; } |