From 26a25ef62a13f409f941aa39825a51b4d6f0f047 Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Tue, 30 Sep 2014 13:54:09 +0100 Subject: [PATCH] Add a prepare for register allocation pass. - Currently the pass just changes the uses of checks to the actual values. - Also optimize array access, now that inputs can be constants. - And fix another bug in the register allocator reveiled by this change. Change-Id: I43be0dbde9330ee5c8f9d678de11361292d8bd98 --- compiler/Android.mk | 1 + compiler/optimizing/code_generator_arm.cc | 17 ++-- compiler/optimizing/code_generator_x86.cc | 99 ++++++++++++++++------ compiler/optimizing/code_generator_x86_64.cc | 78 ++++++++++++----- compiler/optimizing/graph_visualizer.cc | 2 + compiler/optimizing/locations.cc | 11 +++ compiler/optimizing/locations.h | 3 + compiler/optimizing/optimizing_compiler.cc | 2 + .../optimizing/prepare_for_register_allocation.cc | 40 +++++++++ .../optimizing/prepare_for_register_allocation.h | 44 ++++++++++ compiler/optimizing/register_allocator.cc | 15 ++-- compiler/utils/x86/assembler_x86.cc | 11 +++ compiler/utils/x86/assembler_x86.h | 2 + compiler/utils/x86_64/assembler_x86_64.cc | 13 +++ compiler/utils/x86_64/assembler_x86_64.h | 2 + 15 files changed, 280 insertions(+), 60 deletions(-) create mode 100644 compiler/optimizing/prepare_for_register_allocation.cc create mode 100644 compiler/optimizing/prepare_for_register_allocation.h diff --git a/compiler/Android.mk b/compiler/Android.mk index 133044a19..edc5bd0f5 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -100,6 +100,7 @@ LIBART_COMPILER_SRC_FILES := \ optimizing/nodes.cc \ optimizing/optimizing_compiler.cc \ optimizing/parallel_move_resolver.cc \ + optimizing/prepare_for_register_allocation.cc \ optimizing/register_allocator.cc \ optimizing/ssa_builder.cc \ optimizing/ssa_liveness_analysis.cc \ diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 2aa04d4b7..9d875df1f 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1311,8 +1311,9 @@ void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::RequiresRegister()); - // TODO: Have a normalization phase that makes this instruction never used. - locations->SetOut(Location::SameAsFirstInput()); + if (instruction->HasUses()) { + locations->SetOut(Location::SameAsFirstInput()); + } } void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { @@ -1321,12 +1322,15 @@ void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { LocationSummary* locations = instruction->GetLocations(); Location obj = locations->InAt(0); - DCHECK(obj.Equals(locations->Out())); if (obj.IsRegister()) { __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0)); + __ b(slow_path->GetEntryLabel(), EQ); + } else { + DCHECK(obj.IsConstant()) << obj; + DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); + __ b(slow_path->GetEntryLabel()); } - __ b(slow_path->GetEntryLabel(), EQ); } void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { @@ -1550,8 +1554,9 @@ void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) { new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RequiresRegister()); - // TODO: Have a normalization phase that makes this instruction never used. - locations->SetOut(Location::SameAsFirstInput()); + if (instruction->HasUses()) { + locations->SetOut(Location::SameAsFirstInput()); + } } void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 6791003bf..658aed92e 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1302,8 +1302,9 @@ void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::Any()); - // TODO: Have a normalization phase that makes this instruction never used. - locations->SetOut(Location::SameAsFirstInput()); + if (instruction->HasUses()) { + locations->SetOut(Location::SameAsFirstInput()); + } } void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) { @@ -1312,13 +1313,16 @@ void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) { LocationSummary* locations = instruction->GetLocations(); Location obj = locations->InAt(0); - DCHECK(obj.Equals(locations->Out())); if (obj.IsRegister()) { __ cmpl(obj.AsX86().AsCpuRegister(), Immediate(0)); - } else { - DCHECK(locations->InAt(0).IsStackSlot()); + } else if (obj.IsStackSlot()) { __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0)); + } else { + DCHECK(obj.IsConstant()) << obj; + DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); + __ jmp(slow_path->GetEntryLabel()); + return; } __ j(kEqual, slow_path->GetEntryLabel()); } @@ -1443,9 +1447,10 @@ void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) { 1, Location::RegisterOrConstant(instruction->InputAt(1)), dies_at_entry); if (value_type == Primitive::kPrimBoolean || value_type == Primitive::kPrimByte) { // Ensure the value is in a byte register. - locations->SetInAt(2, X86CpuLocation(EAX), dies_at_entry); + locations->SetInAt(2, Location::ByteRegisterOrConstant( + X86ManagedRegister::FromCpuRegister(EAX), instruction->InputAt(2)), dies_at_entry); } else { - locations->SetInAt(2, Location::RequiresRegister(), dies_at_entry); + locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)), dies_at_entry); } } } @@ -1454,18 +1459,29 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) { LocationSummary* locations = instruction->GetLocations(); Register obj = locations->InAt(0).AsX86().AsCpuRegister(); Location index = locations->InAt(1); + Location value = locations->InAt(2); Primitive::Type value_type = instruction->GetComponentType(); switch (value_type) { case Primitive::kPrimBoolean: case Primitive::kPrimByte: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); - ByteRegister value = locations->InAt(2).AsX86().AsByteRegister(); if (index.IsConstant()) { size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; - __ movb(Address(obj, offset), value); + if (value.IsRegister()) { + __ movb(Address(obj, offset), value.AsX86().AsByteRegister()); + } else { + __ movb(Address(obj, offset), + Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } else { - __ movb(Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset), value); + if (value.IsRegister()) { + __ movb(Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset), + value.AsX86().AsByteRegister()); + } else { + __ movb(Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset), + Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } break; } @@ -1473,24 +1489,43 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimShort: case Primitive::kPrimChar: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); - Register value = locations->InAt(2).AsX86().AsCpuRegister(); if (index.IsConstant()) { size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; - __ movw(Address(obj, offset), value); + if (value.IsRegister()) { + __ movw(Address(obj, offset), value.AsX86().AsCpuRegister()); + } else { + __ movw(Address(obj, offset), + Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } else { - __ movw(Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset), value); + if (value.IsRegister()) { + __ movw(Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset), + value.AsX86().AsCpuRegister()); + } else { + __ movw(Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset), + Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } break; } case Primitive::kPrimInt: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); - Register value = locations->InAt(2).AsX86().AsCpuRegister(); if (index.IsConstant()) { size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; - __ movl(Address(obj, offset), value); + if (value.IsRegister()) { + __ movl(Address(obj, offset), value.AsX86().AsCpuRegister()); + } else { + __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } else { - __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_4, data_offset), value); + if (value.IsRegister()) { + __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_4, data_offset), + value.AsX86().AsCpuRegister()); + } else { + __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_4, data_offset), + Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } break; } @@ -1504,16 +1539,29 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimLong: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); - X86ManagedRegister value = locations->InAt(2).AsX86(); if (index.IsConstant()) { size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; - __ movl(Address(obj, offset), value.AsRegisterPairLow()); - __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh()); + if (value.IsRegister()) { + __ movl(Address(obj, offset), value.AsX86().AsRegisterPairLow()); + __ movl(Address(obj, offset + kX86WordSize), value.AsX86().AsRegisterPairHigh()); + } else { + int64_t val = value.GetConstant()->AsLongConstant()->GetValue(); + __ movl(Address(obj, offset), Immediate(Low32Bits(val))); + __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val))); + } } else { - __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset), - value.AsRegisterPairLow()); - __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset + kX86WordSize), - value.AsRegisterPairHigh()); + if (value.IsRegister()) { + __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset), + value.AsX86().AsRegisterPairLow()); + __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset + kX86WordSize), + value.AsX86().AsRegisterPairHigh()); + } else { + int64_t val = value.GetConstant()->AsLongConstant()->GetValue(); + __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset), + Immediate(Low32Bits(val))); + __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset + kX86WordSize), + Immediate(High32Bits(val))); + } } break; } @@ -1547,8 +1595,9 @@ void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) { new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RequiresRegister()); - // TODO: Have a normalization phase that makes this instruction never used. - locations->SetOut(Location::SameAsFirstInput()); + if (instruction->HasUses()) { + locations->SetOut(Location::SameAsFirstInput()); + } } void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) { diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index e0e0c797c..a4efe4f12 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1149,8 +1149,9 @@ void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::Any()); - // TODO: Have a normalization phase that makes this instruction never used. - locations->SetOut(Location::SameAsFirstInput()); + if (instruction->HasUses()) { + locations->SetOut(Location::SameAsFirstInput()); + } } void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) { @@ -1159,13 +1160,16 @@ void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) { LocationSummary* locations = instruction->GetLocations(); Location obj = locations->InAt(0); - DCHECK(obj.Equals(locations->Out())); if (obj.IsRegister()) { __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0)); - } else { - DCHECK(locations->InAt(0).IsStackSlot()); + } else if (obj.IsStackSlot()) { __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0)); + } else { + DCHECK(obj.IsConstant()) << obj; + DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); + __ jmp(slow_path->GetEntryLabel()); + return; } __ j(kEqual, slow_path->GetEntryLabel()); } @@ -1283,6 +1287,11 @@ void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) { locations->SetInAt( 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry); + if (value_type == Primitive::kPrimLong) { + locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry); + } else { + locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)), Location::kDiesAtEntry); + } } } @@ -1290,18 +1299,28 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) { LocationSummary* locations = instruction->GetLocations(); CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister(); Location index = locations->InAt(1); + Location value = locations->InAt(2); Primitive::Type value_type = instruction->GetComponentType(); switch (value_type) { case Primitive::kPrimBoolean: case Primitive::kPrimByte: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); - CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister(); if (index.IsConstant()) { size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; - __ movb(Address(obj, offset), value); + if (value.IsRegister()) { + __ movb(Address(obj, offset), value.AsX86_64().AsCpuRegister()); + } else { + __ movb(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } else { - __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value); + if (value.IsRegister()) { + __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), + value.AsX86_64().AsCpuRegister()); + } else { + __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), + Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } break; } @@ -1309,24 +1328,42 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimShort: case Primitive::kPrimChar: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); - CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister(); if (index.IsConstant()) { size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; - __ movw(Address(obj, offset), value); + if (value.IsRegister()) { + __ movw(Address(obj, offset), value.AsX86_64().AsCpuRegister()); + } else { + __ movw(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } else { - __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value); + if (value.IsRegister()) { + __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), + value.AsX86_64().AsCpuRegister()); + } else { + __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), + Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } break; } case Primitive::kPrimInt: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); - CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister(); if (index.IsConstant()) { size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; - __ movl(Address(obj, offset), value); + if (value.IsRegister()) { + __ movl(Address(obj, offset), value.AsX86_64().AsCpuRegister()); + } else { + __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } else { - __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value); + if (value.IsRegister()) { + __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), + value.AsX86_64().AsCpuRegister()); + } else { + __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), + Immediate(value.GetConstant()->AsIntConstant()->GetValue())); + } } break; } @@ -1340,12 +1377,14 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimLong: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); - CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister(); if (index.IsConstant()) { size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; - __ movq(Address(obj, offset), value); + DCHECK(value.IsRegister()); + __ movq(Address(obj, offset), value.AsX86_64().AsCpuRegister()); } else { - __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value); + DCHECK(value.IsRegister()); + __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), + value.AsX86_64().AsCpuRegister()); } break; } @@ -1379,8 +1418,9 @@ void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) { new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RequiresRegister()); - // TODO: Have a normalization phase that makes this instruction never used. - locations->SetOut(Location::SameAsFirstInput()); + if (instruction->HasUses()) { + locations->SetOut(Location::SameAsFirstInput()); + } } void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) { diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 0fb4737db..686a0b003 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -158,6 +158,7 @@ class HGraphVisualizerPrinter : public HGraphVisitor { } } output_ << ")"; + output_ << " (liveness: " << instruction->GetLifetimePosition() << ")"; } void VisitInstruction(HInstruction* instruction) { @@ -191,6 +192,7 @@ class HGraphVisualizerPrinter : public HGraphVisitor { DumpLocation(locations->Out(), instruction->GetType()); } } + output_ << " (liveness: " << instruction->GetLifetimePosition() << ")"; } } diff --git a/compiler/optimizing/locations.cc b/compiler/optimizing/locations.cc index 114d69c4b..7b09241d1 100644 --- a/compiler/optimizing/locations.cc +++ b/compiler/optimizing/locations.cc @@ -55,4 +55,15 @@ Location Location::RegisterOrConstant(HInstruction* instruction) { : Location::RequiresRegister(); } +Location Location::ByteRegisterOrConstant(ManagedRegister reg, HInstruction* instruction) { + return instruction->IsConstant() + ? Location::ConstantLocation(instruction->AsConstant()) + : Location::RegisterLocation(reg); +} + +std::ostream& operator<<(std::ostream& os, const Location& location) { + os << location.DebugString(); + return os; +} + } // namespace art diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h index 8d0715a45..0e77deb9d 100644 --- a/compiler/optimizing/locations.h +++ b/compiler/optimizing/locations.h @@ -221,6 +221,7 @@ class Location : public ValueObject { } static Location RegisterOrConstant(HInstruction* instruction); + static Location ByteRegisterOrConstant(ManagedRegister reg, HInstruction* instruction); // The location of the first input to the instruction will be // used to replace this unallocated location. @@ -422,6 +423,8 @@ class LocationSummary : public ArenaObject { DISALLOW_COPY_AND_ASSIGN(LocationSummary); }; +std::ostream& operator<<(std::ostream& os, const Location& location); + } // namespace art #endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_ diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 65bdb1881..3cf5a0b29 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -28,6 +28,7 @@ #include "gvn.h" #include "instruction_simplifier.h" #include "nodes.h" +#include "prepare_for_register_allocation.h" #include "register_allocator.h" #include "ssa_phi_elimination.h" #include "ssa_liveness_analysis.h" @@ -265,6 +266,7 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite InstructionSimplifier(graph).Run(); GlobalValueNumberer(graph->GetArena(), graph).Run(); visualizer.DumpGraph(kGVNPassName); + PrepareForRegisterAllocation(graph).Run(); SsaLivenessAnalysis liveness(*graph, codegen); liveness.Analyze(); diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc new file mode 100644 index 000000000..bfbbab57b --- /dev/null +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "prepare_for_register_allocation.h" + +namespace art { + +void PrepareForRegisterAllocation::Run() { + // Order does not matter. + for (HReversePostOrderIterator it(*GetGraph()); !it.Done(); it.Advance()) { + HBasicBlock* block = it.Current(); + // No need to visit the phis. + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + it.Current()->Accept(this); + } + } +} + +void PrepareForRegisterAllocation::VisitNullCheck(HNullCheck* check) { + check->ReplaceWith(check->InputAt(0)); +} + +void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) { + check->ReplaceWith(check->InputAt(0)); +} + +} // namespace art diff --git a/compiler/optimizing/prepare_for_register_allocation.h b/compiler/optimizing/prepare_for_register_allocation.h new file mode 100644 index 000000000..37f28712b --- /dev/null +++ b/compiler/optimizing/prepare_for_register_allocation.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_OPTIMIZING_PREPARE_FOR_REGISTER_ALLOCATION_H_ +#define ART_COMPILER_OPTIMIZING_PREPARE_FOR_REGISTER_ALLOCATION_H_ + +#include "nodes.h" + +namespace art { + +/** + * A simplification pass over the graph before doing register allocation. + * For example it changes uses of null checks and bounds checks to the original + * objects, to avoid creating a live range for these checks. + */ +class PrepareForRegisterAllocation : public HGraphVisitor { + public: + explicit PrepareForRegisterAllocation(HGraph* graph) : HGraphVisitor(graph) {} + + void Run(); + + private: + virtual void VisitNullCheck(HNullCheck* check) OVERRIDE; + virtual void VisitBoundsCheck(HBoundsCheck* check) OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(PrepareForRegisterAllocation); +}; + +} // namespace art + +#endif // ART_COMPILER_OPTIMIZING_PREPARE_FOR_REGISTER_ALLOCATION_H_ diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index 1d1d694ad..013ab72c5 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -795,7 +795,7 @@ void RegisterAllocator::InsertParallelMoveAt(size_t position, move = at->GetNext()->AsParallelMove(); // This is a parallel move for connecting siblings in a same block. We need to // differentiate it with moves for connecting blocks, and input moves. - if (move == nullptr || move->GetLifetimePosition() != position) { + if (move == nullptr || IsInputMove(move) || move->GetLifetimePosition() > position) { move = new (allocator_) HParallelMove(allocator_); move->SetLifetimePosition(position); at->GetBlock()->InsertInstructionBefore(move, at->GetNext()); @@ -803,16 +803,11 @@ void RegisterAllocator::InsertParallelMoveAt(size_t position, } else { // Move must happen before the instruction. HInstruction* previous = at->GetPrevious(); - if (previous != nullptr && previous->IsParallelMove()) { + if (previous != nullptr && previous->IsParallelMove() && IsInputMove(previous)) { // This is a parallel move for connecting siblings in a same block. We need to - // differentiate it with moves for connecting blocks, and input moves. - if (previous->GetLifetimePosition() != position) { - // If the previous instruction of the previous instruction is not a parallel - // move, we have to insert the new parallel move before the input or connecting - // block moves. - at = previous; - previous = previous->GetPrevious(); - } + // differentiate it with input moves. + at = previous; + previous = previous->GetPrevious(); } if (previous == nullptr || !previous->IsParallelMove() diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index f888d46dd..a2cbd8bee 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -243,6 +243,17 @@ void X86Assembler::movw(const Address& dst, Register src) { } +void X86Assembler::movw(const Address& dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOperandSizeOverride(); + EmitUint8(0xC7); + EmitOperand(0, dst); + CHECK(imm.is_int16()); + EmitUint8(imm.value() & 0xFF); + EmitUint8(imm.value() >> 8); +} + + void X86Assembler::leal(Register dst, const Address& src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x8D); diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index ec983d9a5..2113c85ee 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -37,6 +37,7 @@ class Immediate { bool is_int8() const { return IsInt(8, value_); } bool is_uint8() const { return IsUint(8, value_); } + bool is_int16() const { return IsInt(16, value_); } bool is_uint16() const { return IsUint(16, value_); } private: @@ -251,6 +252,7 @@ class X86Assembler FINAL : public Assembler { void movsxw(Register dst, const Address& src); void movw(Register dst, const Address& src); void movw(const Address& dst, Register src); + void movw(const Address& dst, const Immediate& imm); void leal(Register dst, const Address& src); diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index f432e6600..ade7a1325 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -234,6 +234,7 @@ void X86_64Assembler::movb(const Address& dst, CpuRegister src) { void X86_64Assembler::movb(const Address& dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(dst); EmitUint8(0xC6); EmitOperand(Register::RAX, dst); CHECK(imm.is_int8()); @@ -291,6 +292,18 @@ void X86_64Assembler::movw(const Address& dst, CpuRegister src) { } +void X86_64Assembler::movw(const Address& dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOperandSizeOverride(); + EmitOptionalRex32(dst); + EmitUint8(0xC7); + EmitOperand(Register::RAX, dst); + CHECK(imm.is_int16()); + EmitUint8(imm.value() & 0xFF); + EmitUint8(imm.value() >> 8); +} + + void X86_64Assembler::leaq(CpuRegister dst, const Address& src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitRex64(dst, src); diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 1fd65c2c7..c3e6e3b4c 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -44,6 +44,7 @@ class Immediate { bool is_int8() const { return IsInt(8, value_); } bool is_uint8() const { return IsUint(8, value_); } + bool is_int16() const { return IsInt(16, value_); } bool is_uint16() const { return IsUint(16, value_); } bool is_int32() const { // This does not work on 32b machines: return IsInt(32, value_); @@ -295,6 +296,7 @@ class X86_64Assembler FINAL : public Assembler { void movsxw(CpuRegister dst, const Address& src); void movw(CpuRegister dst, const Address& src); void movw(const Address& dst, CpuRegister src); + void movw(const Address& dst, const Immediate& imm); void leaq(CpuRegister dst, const Address& src); -- 2.11.0