diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/optimizing/bounds_check_elimination.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/bounds_check_elimination_test.cc | 18 | ||||
| -rw-r--r-- | compiler/optimizing/builder.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 8 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 8 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 46 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 46 | ||||
| -rw-r--r-- | compiler/optimizing/graph_checker.cc | 12 | ||||
| -rw-r--r-- | compiler/optimizing/graph_checker.h | 3 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 25 | ||||
| -rw-r--r-- | compiler/optimizing/prepare_for_register_allocation.cc | 2 |
12 files changed, 126 insertions, 52 deletions
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc index 6511120794..3645f19f09 100644 --- a/compiler/optimizing/bounds_check_elimination.cc +++ b/compiler/optimizing/bounds_check_elimination.cc @@ -1064,7 +1064,7 @@ class BCEVisitor : public HGraphVisitor { }; void BoundsCheckElimination::Run() { - if (!graph_->HasArrayAccesses()) { + if (!graph_->HasBoundsChecks()) { return; } diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc index 75cf1cf063..97be778dbd 100644 --- a/compiler/optimizing/bounds_check_elimination_test.cc +++ b/compiler/optimizing/bounds_check_elimination_test.cc @@ -43,7 +43,7 @@ TEST(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) { ArenaAllocator allocator(&pool); HGraph* graph = new (&allocator) HGraph(&allocator); - graph->SetHasArrayAccesses(true); + graph->SetHasBoundsChecks(true); HBasicBlock* entry = new (&allocator) HBasicBlock(graph); graph->AddBlock(entry); @@ -148,7 +148,7 @@ TEST(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) { ArenaAllocator allocator(&pool); HGraph* graph = new (&allocator) HGraph(&allocator); - graph->SetHasArrayAccesses(true); + graph->SetHasBoundsChecks(true); HBasicBlock* entry = new (&allocator) HBasicBlock(graph); graph->AddBlock(entry); @@ -220,7 +220,7 @@ TEST(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) { ArenaAllocator allocator(&pool); HGraph* graph = new (&allocator) HGraph(&allocator); - graph->SetHasArrayAccesses(true); + graph->SetHasBoundsChecks(true); HBasicBlock* entry = new (&allocator) HBasicBlock(graph); graph->AddBlock(entry); @@ -292,7 +292,7 @@ TEST(BoundsCheckEliminationTest, ConstantArrayBoundsElimination) { ArenaAllocator allocator(&pool); HGraph* graph = new (&allocator) HGraph(&allocator); - graph->SetHasArrayAccesses(true); + graph->SetHasBoundsChecks(true); HBasicBlock* entry = new (&allocator) HBasicBlock(graph); graph->AddBlock(entry); @@ -365,7 +365,7 @@ static HGraph* BuildSSAGraph1(ArenaAllocator* allocator, int increment, IfCondition cond = kCondGE) { HGraph* graph = new (allocator) HGraph(allocator); - graph->SetHasArrayAccesses(true); + graph->SetHasBoundsChecks(true); HBasicBlock* entry = new (allocator) HBasicBlock(graph); graph->AddBlock(entry); @@ -502,7 +502,7 @@ static HGraph* BuildSSAGraph2(ArenaAllocator* allocator, int increment = -1, IfCondition cond = kCondLE) { HGraph* graph = new (allocator) HGraph(allocator); - graph->SetHasArrayAccesses(true); + graph->SetHasBoundsChecks(true); HBasicBlock* entry = new (allocator) HBasicBlock(graph); graph->AddBlock(entry); @@ -633,7 +633,7 @@ static HGraph* BuildSSAGraph3(ArenaAllocator* allocator, int increment, IfCondition cond) { HGraph* graph = new (allocator) HGraph(allocator); - graph->SetHasArrayAccesses(true); + graph->SetHasBoundsChecks(true); HBasicBlock* entry = new (allocator) HBasicBlock(graph); graph->AddBlock(entry); @@ -744,7 +744,7 @@ static HGraph* BuildSSAGraph4(ArenaAllocator* allocator, int initial, IfCondition cond = kCondGE) { HGraph* graph = new (allocator) HGraph(allocator); - graph->SetHasArrayAccesses(true); + graph->SetHasBoundsChecks(true); HBasicBlock* entry = new (allocator) HBasicBlock(graph); graph->AddBlock(entry); @@ -869,7 +869,7 @@ TEST(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) { ArenaAllocator allocator(&pool); HGraph* graph = new (&allocator) HGraph(&allocator); - graph->SetHasArrayAccesses(true); + graph->SetHasBoundsChecks(true); HBasicBlock* entry = new (&allocator) HBasicBlock(graph); graph->AddBlock(entry); diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index ebd8243c2b..96e08fd24c 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -963,7 +963,7 @@ void HGraphBuilder::BuildArrayAccess(const Instruction& instruction, current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type)); UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction()); } - graph_->SetHasArrayAccesses(true); + graph_->SetHasBoundsChecks(true); } void HGraphBuilder::BuildFilledNewArray(uint32_t dex_pc, @@ -1065,7 +1065,7 @@ void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t default: LOG(FATAL) << "Unknown element width for " << payload->element_width; } - graph_->SetHasArrayAccesses(true); + graph_->SetHasBoundsChecks(true); } void HGraphBuilder::BuildFillWideArrayData(HInstruction* object, diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index d1c318c05e..01748a9f5c 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1242,8 +1242,12 @@ void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation. - DCHECK(!invoke->IsStaticWithExplicitClinitCheck()); + // pruned by art::PrepareForRegisterAllocation, but this step is not + // run in baseline. So we remove them manually here if we find them. + // TODO: Instead of this local workaround, address this properly. + if (invoke->IsStaticWithExplicitClinitCheck()) { + invoke->RemoveClinitCheckOrLoadClassAsLastInput(); + } IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(), codegen_->GetInstructionSetFeatures()); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 7beda96857..dada4ce5bd 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -1969,8 +1969,12 @@ void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { void LocationsBuilderARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation. - DCHECK(!invoke->IsStaticWithExplicitClinitCheck()); + // pruned by art::PrepareForRegisterAllocation, but this step is not + // run in baseline. So we remove them manually here if we find them. + // TODO: Instead of this local workaround, address this properly. + if (invoke->IsStaticWithExplicitClinitCheck()) { + invoke->RemoveClinitCheckOrLoadClassAsLastInput(); + } IntrinsicLocationsBuilderARM64 intrinsic(GetGraph()->GetArena()); if (intrinsic.TryDispatch(invoke)) { diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 70e4440e7a..04999bedb0 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1195,8 +1195,12 @@ void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) { void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation. - DCHECK(!invoke->IsStaticWithExplicitClinitCheck()); + // pruned by art::PrepareForRegisterAllocation, but this step is not + // run in baseline. So we remove them manually here if we find them. + // TODO: Instead of this local workaround, address this properly. + if (invoke->IsStaticWithExplicitClinitCheck()) { + invoke->RemoveClinitCheckOrLoadClassAsLastInput(); + } IntrinsicLocationsBuilderX86 intrinsic(codegen_); if (intrinsic.TryDispatch(invoke)) { @@ -3815,7 +3819,7 @@ void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); - locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); if (instruction->HasUses()) { locations->SetOut(Location::SameAsFirstInput()); } @@ -3827,16 +3831,38 @@ void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) { Location length_loc = locations->InAt(1); SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction, index_loc, length_loc); - codegen_->AddSlowPath(slow_path); - Register length = length_loc.AsRegister<Register>(); - if (index_loc.IsConstant()) { - int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant()); - __ cmpl(length, Immediate(value)); + if (length_loc.IsConstant()) { + int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant()); + if (index_loc.IsConstant()) { + // BCE will remove the bounds check if we are guarenteed to pass. + int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant()); + if (index < 0 || index >= length) { + codegen_->AddSlowPath(slow_path); + __ jmp(slow_path->GetEntryLabel()); + } else { + // Some optimization after BCE may have generated this, and we should not + // generate a bounds check if it is a valid range. + } + return; + } + + // We have to reverse the jump condition because the length is the constant. + Register index_reg = index_loc.AsRegister<Register>(); + __ cmpl(index_reg, Immediate(length)); + codegen_->AddSlowPath(slow_path); + __ j(kAboveEqual, slow_path->GetEntryLabel()); } else { - __ cmpl(length, index_loc.AsRegister<Register>()); + Register length = length_loc.AsRegister<Register>(); + if (index_loc.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant()); + __ cmpl(length, Immediate(value)); + } else { + __ cmpl(length, index_loc.AsRegister<Register>()); + } + codegen_->AddSlowPath(slow_path); + __ j(kBelowEqual, slow_path->GetEntryLabel()); } - __ j(kBelowEqual, slow_path->GetEntryLabel()); } void LocationsBuilderX86::VisitTemporary(HTemporary* temp) { diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 9cf5c218d4..5ce932928b 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1290,8 +1290,12 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation. - DCHECK(!invoke->IsStaticWithExplicitClinitCheck()); + // pruned by art::PrepareForRegisterAllocation, but this step is not + // run in baseline. So we remove them manually here if we find them. + // TODO: Instead of this local workaround, address this properly. + if (invoke->IsStaticWithExplicitClinitCheck()) { + invoke->RemoveClinitCheckOrLoadClassAsLastInput(); + } IntrinsicLocationsBuilderX86_64 intrinsic(codegen_); if (intrinsic.TryDispatch(invoke)) { @@ -3756,7 +3760,7 @@ void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); - locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); if (instruction->HasUses()) { locations->SetOut(Location::SameAsFirstInput()); } @@ -3768,16 +3772,38 @@ void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) Location length_loc = locations->InAt(1); SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc); - codegen_->AddSlowPath(slow_path); - CpuRegister length = length_loc.AsRegister<CpuRegister>(); - if (index_loc.IsConstant()) { - int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant()); - __ cmpl(length, Immediate(value)); + if (length_loc.IsConstant()) { + int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant()); + if (index_loc.IsConstant()) { + // BCE will remove the bounds check if we are guarenteed to pass. + int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant()); + if (index < 0 || index >= length) { + codegen_->AddSlowPath(slow_path); + __ jmp(slow_path->GetEntryLabel()); + } else { + // Some optimization after BCE may have generated this, and we should not + // generate a bounds check if it is a valid range. + } + return; + } + + // We have to reverse the jump condition because the length is the constant. + CpuRegister index_reg = index_loc.AsRegister<CpuRegister>(); + __ cmpl(index_reg, Immediate(length)); + codegen_->AddSlowPath(slow_path); + __ j(kAboveEqual, slow_path->GetEntryLabel()); } else { - __ cmpl(length, index_loc.AsRegister<CpuRegister>()); + CpuRegister length = length_loc.AsRegister<CpuRegister>(); + if (index_loc.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant()); + __ cmpl(length, Immediate(value)); + } else { + __ cmpl(length, index_loc.AsRegister<CpuRegister>()); + } + codegen_->AddSlowPath(slow_path); + __ j(kBelowEqual, slow_path->GetEntryLabel()); } - __ j(kBelowEqual, slow_path->GetEntryLabel()); } void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp, diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index 890676467f..dc3124b35f 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -121,6 +121,18 @@ void GraphChecker::VisitBasicBlock(HBasicBlock* block) { } } +void GraphChecker::VisitBoundsCheck(HBoundsCheck* check) { + if (!GetGraph()->HasBoundsChecks()) { + AddError(StringPrintf("Instruction %s:%d is a HBoundsCheck, " + "but HasBoundsChecks() returns false", + check->DebugName(), + check->GetId())); + } + + // Perform the instruction base checks too. + VisitInstruction(check); +} + void GraphChecker::VisitInstruction(HInstruction* instruction) { if (seen_ids_.IsBitSet(instruction->GetId())) { AddError(StringPrintf("Instruction id %d is duplicate in graph.", diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h index 45e8804edb..b4314da03b 100644 --- a/compiler/optimizing/graph_checker.h +++ b/compiler/optimizing/graph_checker.h @@ -45,6 +45,9 @@ class GraphChecker : public HGraphDelegateVisitor { // Perform control-flow graph checks on instruction. void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE; + // Check that the HasBoundsChecks() flag is set for bounds checks. + void VisitBoundsCheck(HBoundsCheck* check) OVERRIDE; + // Was the last visit of the graph valid? bool IsValid() const { return errors_.empty(); diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 37b57533c1..ada32db047 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -268,8 +268,8 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, callee_graph->InlineInto(graph_, invoke_instruction); - if (callee_graph->HasArrayAccesses()) { - graph_->SetHasArrayAccesses(true); + if (callee_graph->HasBoundsChecks()) { + graph_->SetHasBoundsChecks(true); } return true; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 6b9d72ddf6..938d6fcd64 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -127,7 +127,7 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { number_of_vregs_(0), number_of_in_vregs_(0), temporaries_vreg_slots_(0), - has_array_accesses_(false), + has_bounds_checks_(false), debuggable_(debuggable), current_instruction_id_(start_instruction_id), cached_null_constant_(nullptr), @@ -230,12 +230,12 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { return linear_order_; } - bool HasArrayAccesses() const { - return has_array_accesses_; + bool HasBoundsChecks() const { + return has_bounds_checks_; } - void SetHasArrayAccesses(bool value) { - has_array_accesses_ = value; + void SetHasBoundsChecks(bool value) { + has_bounds_checks_ = value; } bool IsDebuggable() const { return debuggable_; } @@ -295,8 +295,8 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { // Number of vreg size slots that the temporaries use (used in baseline compiler). size_t temporaries_vreg_slots_; - // Has array accesses. We can totally skip BCE if it's false. - bool has_array_accesses_; + // Has bounds checks. We can totally skip BCE if it's false. + bool has_bounds_checks_; // Indicates whether the graph should be compiled in a way that // ensures full debuggability. If false, we can apply more @@ -2262,16 +2262,15 @@ class HInvokeStaticOrDirect : public HInvoke { return GetInvokeType() == kStatic; } - // Remove the art::HLoadClass instruction set as last input by - // art::PrepareForRegisterAllocation::VisitClinitCheck in lieu of - // the initial art::HClinitCheck instruction (only relevant for - // static calls with explicit clinit check). - void RemoveLoadClassAsLastInput() { + // Remove the art::HClinitCheck or art::HLoadClass instruction as + // last input (only relevant for static calls with explicit clinit + // check). + void RemoveClinitCheckOrLoadClassAsLastInput() { DCHECK(IsStaticWithExplicitClinitCheck()); size_t last_input_index = InputCount() - 1; HInstruction* last_input = InputAt(last_input_index); DCHECK(last_input != nullptr); - DCHECK(last_input->IsLoadClass()) << last_input->DebugName(); + DCHECK(last_input->IsClinitCheck() || last_input->IsLoadClass()) << last_input->DebugName(); RemoveAsUserOfInput(last_input_index); inputs_.DeleteAt(last_input_index); clinit_check_requirement_ = ClinitCheckRequirement::kImplicit; diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc index 78d11857c3..fa6b3c292c 100644 --- a/compiler/optimizing/prepare_for_register_allocation.cc +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -91,7 +91,7 @@ void PrepareForRegisterAllocation::VisitInvokeStaticOrDirect(HInvokeStaticOrDire // previously) by the graph builder during the creation of the // static invoke instruction, but is no longer required at this // stage (i.e., after inlining has been performed). - invoke->RemoveLoadClassAsLastInput(); + invoke->RemoveClinitCheckOrLoadClassAsLastInput(); // If the load class instruction is no longer used, remove it from // the graph. |