diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/builder.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/common_arm64.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/parallel_move_resolver.cc | 58 | ||||
| -rw-r--r-- | compiler/optimizing/parallel_move_test.cc | 27 | ||||
| -rw-r--r-- | compiler/optimizing/register_allocator.cc | 54 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.cc | 32 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.h | 25 |
12 files changed, 145 insertions, 72 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 62bd86af98..a912d4ccc4 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -23,6 +23,7 @@ #include "dex_instruction.h" #include "dex_instruction-inl.h" #include "driver/compiler_driver-inl.h" +#include "driver/compiler_options.h" #include "mirror/art_field.h" #include "mirror/art_field-inl.h" #include "mirror/class_loader.h" diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 32ada3837e..03d344555f 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -394,6 +394,10 @@ CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, isa_features_(isa_features) { // Save the link register (containing the return address) to mimic Quick. AddAllocatedRegister(LocationFrom(lr)); + + // Workaround for valgrind undefined recommended_checkpoint_. + // This won't do anything, as the literal pool is empty, but initialize the field. + GetVIXLAssembler()->EmitLiteralPool(LiteralPool::EmitOption::kNoBranchRequired); } #undef __ diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 2c624d2926..f555de50e5 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -23,8 +23,8 @@ #include "nodes.h" #include "parallel_move_resolver.h" #include "utils/arm64/assembler_arm64.h" -#include "a64/disasm-a64.h" -#include "a64/macro-assembler-a64.h" +#include "vixl/a64/disasm-a64.h" +#include "vixl/a64/macro-assembler-a64.h" #include "arch/arm64/quick_method_frame_info_arm64.h" namespace art { diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 8d0ca0beb9..0d5fe49c1d 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -3146,7 +3146,7 @@ void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruct Location obj = locations->InAt(0); if (obj.IsRegister()) { - __ cmpl(obj.AsRegister<Register>(), Immediate(0)); + __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>()); } else if (obj.IsStackSlot()) { __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0)); } else { diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h index fd8c0c6242..966165bf4c 100644 --- a/compiler/optimizing/common_arm64.h +++ b/compiler/optimizing/common_arm64.h @@ -20,8 +20,8 @@ #include "locations.h" #include "nodes.h" #include "utils/arm64/assembler_arm64.h" -#include "a64/disasm-a64.h" -#include "a64/macro-assembler-a64.h" +#include "vixl/a64/disasm-a64.h" +#include "vixl/a64/macro-assembler-a64.h" namespace art { namespace arm64 { diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 72d303c870..d1176c460f 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -28,8 +28,8 @@ #include "utils/arm64/assembler_arm64.h" #include "utils/arm64/constants_arm64.h" -#include "a64/disasm-a64.h" -#include "a64/macro-assembler-a64.h" +#include "vixl/a64/disasm-a64.h" +#include "vixl/a64/macro-assembler-a64.h" using namespace vixl; // NOLINT(build/namespaces) diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index b2f9c65153..e474c49121 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -26,11 +26,13 @@ #include "bounds_check_elimination.h" #include "builder.h" #include "code_generator.h" +#include "compiled_method.h" #include "compiler.h" #include "constant_folding.h" #include "dead_code_elimination.h" #include "dex/quick/dex_file_to_method_inliner_map.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" #include "elf_writer_quick.h" #include "graph_visualizer.h" diff --git a/compiler/optimizing/parallel_move_resolver.cc b/compiler/optimizing/parallel_move_resolver.cc index 7d0641ec13..9df8f5640d 100644 --- a/compiler/optimizing/parallel_move_resolver.cc +++ b/compiler/optimizing/parallel_move_resolver.cc @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include <iostream> #include "parallel_move_resolver.h" #include "nodes.h" @@ -63,39 +64,42 @@ void ParallelMoveResolver::BuildInitialMoveList(HParallelMove* parallel_move) { } } +Location LowOf(Location location) { + if (location.IsRegisterPair()) { + return Location::RegisterLocation(location.low()); + } else if (location.IsFpuRegisterPair()) { + return Location::FpuRegisterLocation(location.low()); + } else if (location.IsDoubleStackSlot()) { + return Location::StackSlot(location.GetStackIndex()); + } else { + return Location::NoLocation(); + } +} + +Location HighOf(Location location) { + if (location.IsRegisterPair()) { + return Location::RegisterLocation(location.high()); + } else if (location.IsFpuRegisterPair()) { + return Location::FpuRegisterLocation(location.high()); + } else if (location.IsDoubleStackSlot()) { + return Location::StackSlot(location.GetHighStackIndex(4)); + } else { + return Location::NoLocation(); + } +} + // Update the source of `move`, knowing that `updated_location` has been swapped // with `new_source`. Note that `updated_location` can be a pair, therefore if // `move` is non-pair, we need to extract which register to use. static void UpdateSourceOf(MoveOperands* move, Location updated_location, Location new_source) { Location source = move->GetSource(); - if (new_source.GetKind() == source.GetKind()) { - DCHECK(updated_location.Equals(source)); - move->SetSource(new_source); - } else if (new_source.IsStackSlot() - || new_source.IsDoubleStackSlot() - || source.IsStackSlot() - || source.IsDoubleStackSlot()) { - // Stack slots never take part of a pair/non-pair swap. - DCHECK(updated_location.Equals(source)); + if (LowOf(updated_location).Equals(source)) { + move->SetSource(LowOf(new_source)); + } else if (HighOf(updated_location).Equals(source)) { + move->SetSource(HighOf(new_source)); + } else { + DCHECK(updated_location.Equals(source)) << updated_location << " " << source; move->SetSource(new_source); - } else if (source.IsRegister()) { - DCHECK(new_source.IsRegisterPair()) << new_source; - DCHECK(updated_location.IsRegisterPair()) << updated_location; - if (updated_location.low() == source.reg()) { - move->SetSource(Location::RegisterLocation(new_source.low())); - } else { - DCHECK_EQ(updated_location.high(), source.reg()); - move->SetSource(Location::RegisterLocation(new_source.high())); - } - } else if (source.IsFpuRegister()) { - DCHECK(new_source.IsFpuRegisterPair()) << new_source; - DCHECK(updated_location.IsFpuRegisterPair()) << updated_location; - if (updated_location.low() == source.reg()) { - move->SetSource(Location::FpuRegisterLocation(new_source.low())); - } else { - DCHECK_EQ(updated_location.high(), source.reg()); - move->SetSource(Location::FpuRegisterLocation(new_source.high())); - } } } diff --git a/compiler/optimizing/parallel_move_test.cc b/compiler/optimizing/parallel_move_test.cc index 817a44b184..5c502f7ef4 100644 --- a/compiler/optimizing/parallel_move_test.cc +++ b/compiler/optimizing/parallel_move_test.cc @@ -31,8 +31,13 @@ class TestParallelMoveResolver : public ParallelMoveResolver { message_ << "C"; } else if (location.IsPair()) { message_ << location.low() << "," << location.high(); - } else { + } else if (location.IsRegister()) { message_ << location.reg(); + } else if (location.IsStackSlot()) { + message_ << location.GetStackIndex() << "(sp)"; + } else { + message_ << "2x" << location.GetStackIndex() << "(sp)"; + DCHECK(location.IsDoubleStackSlot()) << location; } } @@ -279,6 +284,26 @@ TEST(ParallelMoveTest, Pairs) { resolver.EmitNativeCode(moves); ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str()); } + + { + // Test involving registers used in single context and pair context. + TestParallelMoveResolver resolver(&allocator); + HParallelMove* moves = new (&allocator) HParallelMove(&allocator); + moves->AddMove( + Location::RegisterLocation(10), + Location::RegisterLocation(5), + nullptr); + moves->AddMove( + Location::RegisterPairLocation(4, 5), + Location::DoubleStackSlot(32), + nullptr); + moves->AddMove( + Location::DoubleStackSlot(32), + Location::RegisterPairLocation(10, 11), + nullptr); + resolver.EmitNativeCode(moves); + ASSERT_STREQ("(2x32(sp) <-> 10,11) (4,5 <-> 2x32(sp)) (4 -> 5)", resolver.GetMessage().c_str()); + } } } // namespace art diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index cf38bd3f8c..4bca43499f 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -1408,26 +1408,36 @@ void RegisterAllocator::ConnectSiblings(LiveInterval* interval) { // Walk over all uses covered by this interval, and update the location // information. - while (use != nullptr && use->GetPosition() <= current->GetEnd()) { - LocationSummary* locations = use->GetUser()->GetLocations(); - if (use->GetIsEnvironment()) { - locations->SetEnvironmentAt(use->GetInputIndex(), source); - } else { - Location expected_location = locations->InAt(use->GetInputIndex()); - // The expected (actual) location may be invalid in case the input is unused. Currently - // this only happens for intrinsics. - if (expected_location.IsValid()) { - if (expected_location.IsUnallocated()) { - locations->SetInAt(use->GetInputIndex(), source); - } else if (!expected_location.IsConstant()) { - AddInputMoveFor(interval->GetDefinedBy(), use->GetUser(), source, expected_location); - } + + LiveRange* range = current->GetFirstRange(); + while (range != nullptr) { + while (use != nullptr && use->GetPosition() < range->GetStart()) { + DCHECK(use->GetIsEnvironment()); + use = use->GetNext(); + } + while (use != nullptr && use->GetPosition() <= range->GetEnd()) { + DCHECK(current->Covers(use->GetPosition()) || (use->GetPosition() == range->GetEnd())); + LocationSummary* locations = use->GetUser()->GetLocations(); + if (use->GetIsEnvironment()) { + locations->SetEnvironmentAt(use->GetInputIndex(), source); } else { - DCHECK(use->GetUser()->IsInvoke()); - DCHECK(use->GetUser()->AsInvoke()->GetIntrinsic() != Intrinsics::kNone); + Location expected_location = locations->InAt(use->GetInputIndex()); + // The expected (actual) location may be invalid in case the input is unused. Currently + // this only happens for intrinsics. + if (expected_location.IsValid()) { + if (expected_location.IsUnallocated()) { + locations->SetInAt(use->GetInputIndex(), source); + } else if (!expected_location.IsConstant()) { + AddInputMoveFor(interval->GetDefinedBy(), use->GetUser(), source, expected_location); + } + } else { + DCHECK(use->GetUser()->IsInvoke()); + DCHECK(use->GetUser()->AsInvoke()->GetIntrinsic() != Intrinsics::kNone); + } } + use = use->GetNext(); } - use = use->GetNext(); + range = range->GetNext(); } // If the next interval starts just after this one, and has a register, @@ -1503,7 +1513,15 @@ void RegisterAllocator::ConnectSiblings(LiveInterval* interval) { } current = next_sibling; } while (current != nullptr); - DCHECK(use == nullptr); + + if (kIsDebugBuild) { + // Following uses can only be environment uses. The location for + // these environments will be none. + while (use != nullptr) { + DCHECK(use->GetIsEnvironment()); + use = use->GetNext(); + } + } } void RegisterAllocator::ConnectSplitSiblings(LiveInterval* interval, diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc index 0f3973e5fb..95da6ef551 100644 --- a/compiler/optimizing/ssa_liveness_analysis.cc +++ b/compiler/optimizing/ssa_liveness_analysis.cc @@ -218,28 +218,34 @@ void SsaLivenessAnalysis::ComputeLiveRanges() { current->GetLiveInterval()->SetFrom(current->GetLifetimePosition()); } - // All inputs of an instruction must be live. - for (size_t i = 0, e = current->InputCount(); i < e; ++i) { - HInstruction* input = current->InputAt(i); - // Some instructions 'inline' their inputs, that is they do not need - // to be materialized. - if (input->HasSsaIndex()) { - live_in->SetBit(input->GetSsaIndex()); - input->GetLiveInterval()->AddUse(current, i, false); - } - } - + // Process the environment first, because we know their uses come after + // or at the same liveness position of inputs. if (current->HasEnvironment()) { // Handle environment uses. See statements (b) and (c) of the // SsaLivenessAnalysis. HEnvironment* environment = current->GetEnvironment(); for (size_t i = 0, e = environment->Size(); i < e; ++i) { HInstruction* instruction = environment->GetInstructionAt(i); - if (ShouldBeLiveForEnvironment(instruction)) { + bool should_be_live = ShouldBeLiveForEnvironment(instruction); + if (should_be_live) { DCHECK(instruction->HasSsaIndex()); live_in->SetBit(instruction->GetSsaIndex()); - instruction->GetLiveInterval()->AddUse(current, i, true); } + if (instruction != nullptr) { + instruction->GetLiveInterval()->AddUse( + current, i, /* is_environment */ true, should_be_live); + } + } + } + + // All inputs of an instruction must be live. + for (size_t i = 0, e = current->InputCount(); i < e; ++i) { + HInstruction* input = current->InputAt(i); + // Some instructions 'inline' their inputs, that is they do not need + // to be materialized. + if (input->HasSsaIndex()) { + live_in->SetBit(input->GetSsaIndex()); + input->GetLiveInterval()->AddUse(current, i, /* is_environment */ false); } } } diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h index bc78dc2e76..d2da84c0c0 100644 --- a/compiler/optimizing/ssa_liveness_analysis.h +++ b/compiler/optimizing/ssa_liveness_analysis.h @@ -189,7 +189,10 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { AddRange(position, position + 1); } - void AddUse(HInstruction* instruction, size_t input_index, bool is_environment) { + void AddUse(HInstruction* instruction, + size_t input_index, + bool is_environment, + bool keep_alive = false) { // Set the use within the instruction. size_t position = instruction->GetLifetimePosition() + 1; LocationSummary* locations = instruction->GetLocations(); @@ -211,6 +214,7 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { && (first_use_->GetPosition() < position)) { // The user uses the instruction multiple times, and one use dies before the other. // We update the use list so that the latter is first. + DCHECK(!is_environment); UsePosition* cursor = first_use_; while ((cursor->GetNext() != nullptr) && (cursor->GetNext()->GetPosition() < position)) { cursor = cursor->GetNext(); @@ -225,6 +229,15 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { return; } + first_use_ = new (allocator_) UsePosition( + instruction, input_index, is_environment, position, first_use_); + + if (is_environment && !keep_alive) { + // If this environment use does not keep the instruction live, it does not + // affect the live range of that instruction. + return; + } + size_t start_block_position = instruction->GetBlock()->GetLifetimeStart(); if (first_range_ == nullptr) { // First time we see a use of that interval. @@ -246,8 +259,6 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { // and the check line 205 would succeed. first_range_ = new (allocator_) LiveRange(start_block_position, position, first_range_); } - first_use_ = new (allocator_) UsePosition( - instruction, input_index, is_environment, position, first_use_); } void AddPhiUse(HInstruction* instruction, size_t input_index, HBasicBlock* block) { @@ -425,9 +436,11 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { UsePosition* use = first_use_; size_t end = GetEnd(); while (use != nullptr && use->GetPosition() <= end) { - size_t use_position = use->GetPosition(); - if (use_position > position) { - return use_position; + if (!use->GetIsEnvironment()) { + size_t use_position = use->GetPosition(); + if (use_position > position) { + return use_position; + } } use = use->GetNext(); } |