diff options
author | Nicolas Geoffray <ngeoffray@google.com> | 2014-06-09 18:40:10 +0100 |
---|---|---|
committer | Nicolas Geoffray <ngeoffray@google.com> | 2014-06-13 09:49:30 +0100 |
commit | 9cf35523764d829ae0470dae2d5dd99be469c841 (patch) | |
tree | 889459a8ecf8fdf801ea46dd58d15268dfb25af8 | |
parent | b08f63c21de64f8b74003e3638e100471bd099f3 (diff) | |
download | art-9cf35523764d829ae0470dae2d5dd99be469c841.zip art-9cf35523764d829ae0470dae2d5dd99be469c841.tar.gz art-9cf35523764d829ae0470dae2d5dd99be469c841.tar.bz2 |
Add x86_64 support to the optimizing compiler.
Change-Id: I4462d9ae15be56c4a3dc1bd4d1c0c6548c1b94be
-rw-r--r-- | compiler/Android.mk | 1 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.h | 6 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 26 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 14 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 708 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 161 | ||||
-rw-r--r-- | compiler/optimizing/codegen_test.cc | 30 | ||||
-rw-r--r-- | compiler/optimizing/locations.h | 1 |
9 files changed, 915 insertions, 35 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 4f9f312..6d2f5d1 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -84,6 +84,7 @@ LIBART_COMPILER_SRC_FILES := \ optimizing/code_generator.cc \ optimizing/code_generator_arm.cc \ optimizing/code_generator_x86.cc \ + optimizing/code_generator_x86_64.cc \ optimizing/graph_visualizer.cc \ optimizing/locations.cc \ optimizing/nodes.cc \ diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index f05cb66..b8332ad 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -18,6 +18,7 @@ #include "code_generator_arm.h" #include "code_generator_x86.h" +#include "code_generator_x86_64.h" #include "dex/verified_method.h" #include "driver/dex_compilation_unit.h" #include "gc_map_builder.h" @@ -221,7 +222,7 @@ CodeGenerator* CodeGenerator::Create(ArenaAllocator* allocator, return new (allocator) x86::CodeGeneratorX86(graph); } case kX86_64: { - return new (allocator) x86::CodeGeneratorX86(graph); + return new (allocator) x86_64::CodeGeneratorX86_64(graph); } default: return nullptr; diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 11b3a33..83621e0 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -157,10 +157,10 @@ class CallingConvention { return registers_[index]; } - uint8_t GetStackOffsetOf(size_t index, size_t word_size) const { + uint8_t GetStackOffsetOf(size_t index) const { // We still reserve the space for parameters passed by registers. - // Add word_size for the method pointer. - return index * kVRegSize + word_size; + // Add one for the method pointer. + return (index + 1) * kVRegSize; } private: diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 2aebf9a..212a6dc 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -15,14 +15,14 @@ */ #include "code_generator_arm.h" -#include "utils/assembler.h" -#include "utils/arm/assembler_arm.h" -#include "utils/arm/managed_register_arm.h" #include "entrypoints/quick/quick_entrypoints.h" #include "mirror/array.h" #include "mirror/art_method.h" #include "thread.h" +#include "utils/assembler.h" +#include "utils/arm/assembler_arm.h" +#include "utils/arm/managed_register_arm.h" #define __ reinterpret_cast<ArmAssembler*>(GetAssembler())-> @@ -165,7 +165,7 @@ int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const { uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs(); if (reg_number >= number_of_vregs - number_of_in_vregs) { // Local is a parameter of the method. It is stored in the caller's frame. - return GetFrameSize() + kArmWordSize // ART method + return GetFrameSize() + kVRegSize // ART method + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize; } else { // Local is a temporary in this method. It is stored in this method's frame. @@ -214,7 +214,7 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type if (index < calling_convention.GetNumberOfRegisters()) { return ArmCoreLocation(calling_convention.GetRegisterAt(index)); } else { - return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize)); + return Location::StackSlot(calling_convention.GetStackOffsetOf(index)); } } @@ -227,7 +227,7 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type } else if (index + 1 == calling_convention.GetNumberOfRegisters()) { return Location::QuickParameter(index); } else { - return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize)); + return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index)); } } @@ -278,7 +278,7 @@ void CodeGeneratorARM::Move64(Location destination, Location source) { __ Mov(destination.AsArm().AsRegisterPairLow(), calling_convention.GetRegisterAt(argument_index)); __ ldr(destination.AsArm().AsRegisterPairHigh(), - Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize())); + Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize())); } else { DCHECK(source.IsDoubleStackSlot()); if (destination.AsArm().AsRegisterPair() == R1_R2) { @@ -295,12 +295,12 @@ void CodeGeneratorARM::Move64(Location destination, Location source) { if (source.IsRegister()) { __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow()); __ str(source.AsArm().AsRegisterPairHigh(), - Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize))); + Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1))); } else { DCHECK(source.IsDoubleStackSlot()); __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex())); - __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize))); - __ str(IP, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize))); + __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize))); + __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1))); } } else { DCHECK(destination.IsDoubleStackSlot()); @@ -317,9 +317,9 @@ void CodeGeneratorARM::Move64(Location destination, Location source) { uint32_t argument_index = source.GetQuickParameterIndex(); __ str(calling_convention.GetRegisterAt(argument_index), Address(SP, destination.GetStackIndex())); - __ ldr(IP, - Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize())); - __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize))); + __ ldr(R0, + Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize())); + __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize))); } else { DCHECK(source.IsDoubleStackSlot()); __ ldr(IP, Address(SP, source.GetStackIndex())); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index f24af5b..342a191 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -157,7 +157,7 @@ int32_t CodeGeneratorX86::GetStackSlot(HLocal* local) const { uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs(); if (reg_number >= number_of_vregs - number_of_in_vregs) { // Local is a parameter of the method. It is stored in the caller's frame. - return GetFrameSize() + kX86WordSize // ART method + return GetFrameSize() + kVRegSize // ART method + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize; } else { // Local is a temporary in this method. It is stored in this method's frame. @@ -221,7 +221,7 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type if (index < calling_convention.GetNumberOfRegisters()) { return X86CpuLocation(calling_convention.GetRegisterAt(index)); } else { - return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kX86WordSize)); + return Location::StackSlot(calling_convention.GetStackOffsetOf(index)); } } @@ -234,7 +234,7 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type } else if (index + 1 == calling_convention.GetNumberOfRegisters()) { return Location::QuickParameter(index); } else { - return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kX86WordSize)); + return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index)); } } @@ -286,7 +286,7 @@ void CodeGeneratorX86::Move64(Location destination, Location source) { __ movl(destination.AsX86().AsRegisterPairLow(), calling_convention.GetRegisterAt(argument_index)); __ movl(destination.AsX86().AsRegisterPairHigh(), Address(ESP, - calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize) + GetFrameSize())); + calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize())); } else { DCHECK(source.IsDoubleStackSlot()); __ movl(destination.AsX86().AsRegisterPairLow(), Address(ESP, source.GetStackIndex())); @@ -298,14 +298,14 @@ void CodeGeneratorX86::Move64(Location destination, Location source) { uint32_t argument_index = destination.GetQuickParameterIndex(); if (source.IsRegister()) { __ movl(calling_convention.GetRegisterAt(argument_index), source.AsX86().AsRegisterPairLow()); - __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize)), + __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)), source.AsX86().AsRegisterPairHigh()); } else { DCHECK(source.IsDoubleStackSlot()); __ movl(calling_convention.GetRegisterAt(argument_index), Address(ESP, source.GetStackIndex())); __ pushl(Address(ESP, source.GetHighStackIndex(kX86WordSize))); - __ popl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize))); + __ popl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1))); } } else { if (source.IsRegister()) { @@ -318,7 +318,7 @@ void CodeGeneratorX86::Move64(Location destination, Location source) { __ movl(Address(ESP, destination.GetStackIndex()), calling_convention.GetRegisterAt(argument_index)); __ pushl(Address(ESP, - calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize) + GetFrameSize())); + calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize())); __ popl(Address(ESP, destination.GetHighStackIndex(kX86WordSize))); } else { DCHECK(source.IsDoubleStackSlot()); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc new file mode 100644 index 0000000..ef17ca7 --- /dev/null +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -0,0 +1,708 @@ +/* + * 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 "code_generator_x86_64.h" + +#include "entrypoints/quick/quick_entrypoints.h" +#include "mirror/array.h" +#include "mirror/art_method.h" +#include "mirror/object_reference.h" +#include "thread.h" +#include "utils/assembler.h" +#include "utils/x86_64/assembler_x86_64.h" +#include "utils/x86_64/managed_register_x86_64.h" + +#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())-> + +namespace art { + +x86_64::X86_64ManagedRegister Location::AsX86_64() const { + return reg().AsX86_64(); +} + +namespace x86_64 { + +static constexpr int kNumberOfPushedRegistersAtEntry = 1; +static constexpr int kCurrentMethodStackOffset = 0; + +void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const { + stream << X86_64ManagedRegister::FromCpuRegister(Register(reg)); +} + +void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const { + stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg)); +} + +static Location X86_64CpuLocation(Register reg) { + return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg)); +} + +CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph) + : CodeGenerator(graph, kNumberOfRegIds), + location_builder_(graph, this), + instruction_visitor_(graph, this) {} + +InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen) + : HGraphVisitor(graph), + assembler_(codegen->GetAssembler()), + codegen_(codegen) {} + +ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type, + bool* blocked_registers) const { + switch (type) { + case Primitive::kPrimLong: + case Primitive::kPrimByte: + case Primitive::kPrimBoolean: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: { + size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters); + return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg)); + } + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Unimplemented register type " << type; + + case Primitive::kPrimVoid: + LOG(FATAL) << "Unreachable type " << type; + } + + return ManagedRegister::NoRegister(); +} + +void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const { + // Stack register is always reserved. + blocked_registers[RSP] = true; + + // TODO: We currently don't use Quick's callee saved registers. + blocked_registers[RBX] = true; + blocked_registers[RBP] = true; + blocked_registers[R12] = true; + blocked_registers[R13] = true; + blocked_registers[R14] = true; + blocked_registers[R15] = true; +} + +void CodeGeneratorX86_64::ComputeFrameSize(size_t number_of_spill_slots) { + // Add the current ART method to the frame size, the return PC, and the filler. + SetFrameSize(RoundUp( + number_of_spill_slots * kVRegSize + + kVRegSize // filler + + kVRegSize // Art method + + kNumberOfPushedRegistersAtEntry * kX86_64WordSize, + kStackAlignment)); +} + +void CodeGeneratorX86_64::GenerateFrameEntry() { + // Create a fake register to mimic Quick. + static const int kFakeReturnRegister = 16; + core_spill_mask_ |= (1 << kFakeReturnRegister); + + // The return PC has already been pushed on the stack. + __ subq(CpuRegister(RSP), Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize)); + __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI)); +} + +void CodeGeneratorX86_64::GenerateFrameExit() { + __ addq(CpuRegister(RSP), + Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize)); +} + +void CodeGeneratorX86_64::Bind(Label* label) { + __ Bind(label); +} + +void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) { + __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset)); +} + +int32_t CodeGeneratorX86_64::GetStackSlot(HLocal* local) const { + uint16_t reg_number = local->GetRegNumber(); + uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); + uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs(); + if (reg_number >= number_of_vregs - number_of_in_vregs) { + // Local is a parameter of the method. It is stored in the caller's frame. + return GetFrameSize() + kVRegSize // ART method + + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize; + } else { + // Local is a temporary in this method. It is stored in this method's frame. + return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kX86_64WordSize) + - kVRegSize + - (number_of_vregs * kVRegSize) + + (reg_number * kVRegSize); + } +} + +Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const { + switch (load->GetType()) { + case Primitive::kPrimLong: + return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); + break; + + case Primitive::kPrimInt: + case Primitive::kPrimNot: + return Location::StackSlot(GetStackSlot(load->GetLocal())); + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Unimplemented type " << load->GetType(); + + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimVoid: + LOG(FATAL) << "Unexpected type " << load->GetType(); + } + + LOG(FATAL) << "Unreachable"; + return Location(); +} + +void CodeGeneratorX86_64::Move(Location destination, Location source) { + if (source.Equals(destination)) { + return; + } + if (destination.IsRegister()) { + if (source.IsRegister()) { + __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister()); + } else if (source.IsStackSlot()) { + __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex())); + } else { + DCHECK(source.IsDoubleStackSlot()); + __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex())); + } + } else if (destination.IsStackSlot()) { + if (source.IsRegister()) { + __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister()); + } else { + DCHECK(source.IsStackSlot()); + __ movl(CpuRegister(RAX), Address(CpuRegister(RSP), source.GetStackIndex())); + __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(RAX)); + } + } else { + DCHECK(destination.IsDoubleStackSlot()); + if (source.IsRegister()) { + __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister()); + } else { + DCHECK(source.IsDoubleStackSlot()); + __ movq(CpuRegister(RAX), Address(CpuRegister(RSP), source.GetStackIndex())); + __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(RAX)); + } + } +} + +void CodeGeneratorX86_64::Move(HInstruction* instruction, Location location, HInstruction* move_for) { + if (instruction->AsIntConstant() != nullptr) { + Immediate imm(instruction->AsIntConstant()->GetValue()); + if (location.IsRegister()) { + __ movq(location.AsX86_64().AsCpuRegister(), imm); + } else { + __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm); + } + } else if (instruction->AsLongConstant() != nullptr) { + int64_t value = instruction->AsLongConstant()->GetValue(); + if (location.IsRegister()) { + __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value)); + } else { + __ movq(CpuRegister(RAX), Immediate(value)); + __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(RAX)); + } + } else if (instruction->AsLoadLocal() != nullptr) { + switch (instruction->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal()))); + break; + + case Primitive::kPrimLong: + Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal()))); + break; + + default: + LOG(FATAL) << "Unimplemented local type " << instruction->GetType(); + } + } else { + // This can currently only happen when the instruction that requests the move + // is the next to be compiled. + DCHECK_EQ(instruction->GetNext(), move_for); + switch (instruction->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + case Primitive::kPrimLong: + Move(location, instruction->GetLocations()->Out()); + break; + + default: + LOG(FATAL) << "Unimplemented type " << instruction->GetType(); + } + } +} + +void LocationsBuilderX86_64::VisitGoto(HGoto* got) { + got->SetLocations(nullptr); +} + +void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) { + HBasicBlock* successor = got->GetSuccessor(); + if (GetGraph()->GetExitBlock() == successor) { + codegen_->GenerateFrameExit(); + } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { + __ jmp(codegen_->GetLabelOf(successor)); + } +} + +void LocationsBuilderX86_64::VisitExit(HExit* exit) { + exit->SetLocations(nullptr); +} + +void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) { + if (kIsDebugBuild) { + __ Comment("Unreachable"); + __ int3(); + } +} + +void LocationsBuilderX86_64::VisitIf(HIf* if_instr) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr); + locations->SetInAt(0, X86_64CpuLocation(RAX)); + if_instr->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) { + // TODO: Generate the input as a condition, instead of materializing in a register. + __ cmpl(if_instr->GetLocations()->InAt(0).AsX86_64().AsCpuRegister(), Immediate(0)); + __ j(kEqual, codegen_->GetLabelOf(if_instr->IfFalseSuccessor())); + if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) { + __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); + } +} + +void LocationsBuilderX86_64::VisitLocal(HLocal* local) { + local->SetLocations(nullptr); +} + +void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) { + DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); +} + +void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) { + local->SetLocations(nullptr); +} + +void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) { + // Nothing to do, this is driven by the code generator. +} + +void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store); + switch (store->InputAt(1)->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); + break; + + case Primitive::kPrimLong: + locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); + break; + + default: + LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType(); + } + store->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) { +} + +void LocationsBuilderX86_64::VisitEqual(HEqual* equal) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal); + locations->SetInAt(0, X86_64CpuLocation(RAX)); + locations->SetInAt(1, X86_64CpuLocation(RCX)); + locations->SetOut(X86_64CpuLocation(RAX)); + equal->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* equal) { + __ cmpq(equal->GetLocations()->InAt(0).AsX86_64().AsCpuRegister(), + equal->GetLocations()->InAt(1).AsX86_64().AsCpuRegister()); + __ setcc(kEqual, equal->GetLocations()->Out().AsX86_64().AsCpuRegister()); +} + +void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) { + // TODO: Support constant locations. + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant); + locations->SetOut(Location::RequiresRegister()); + constant->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) { + // Will be generated at use site. +} + +void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) { + // TODO: Support constant locations. + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant); + locations->SetOut(Location::RequiresRegister()); + constant->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) { + // Will be generated at use site. +} + +void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) { + ret->SetLocations(nullptr); +} + +void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) { + codegen_->GenerateFrameExit(); + __ ret(); +} + +void LocationsBuilderX86_64::VisitReturn(HReturn* ret) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret); + switch (ret->InputAt(0)->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + case Primitive::kPrimLong: + locations->SetInAt(0, X86_64CpuLocation(RAX)); + break; + + default: + LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); + } + ret->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) { + if (kIsDebugBuild) { + switch (ret->InputAt(0)->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + case Primitive::kPrimLong: + DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX); + break; + + default: + LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); + } + } + codegen_->GenerateFrameExit(); + __ ret(); +} + +static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX }; +static constexpr size_t kRuntimeParameterCoreRegistersLength = + arraysize(kRuntimeParameterCoreRegisters); + +class InvokeRuntimeCallingConvention : public CallingConvention<Register> { + public: + InvokeRuntimeCallingConvention() + : CallingConvention(kRuntimeParameterCoreRegisters, + kRuntimeParameterCoreRegistersLength) {} + + private: + DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); +}; + +Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) { + switch (type) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: { + uint32_t index = gp_index_++; + stack_index_++; + if (index < calling_convention.GetNumberOfRegisters()) { + return X86_64CpuLocation(calling_convention.GetRegisterAt(index)); + } else { + return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1)); + } + } + + case Primitive::kPrimLong: { + uint32_t index = gp_index_; + stack_index_ += 2; + if (index < calling_convention.GetNumberOfRegisters()) { + gp_index_ += 1; + return X86_64CpuLocation(calling_convention.GetRegisterAt(index)); + } else { + gp_index_ += 2; + return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2)); + } + } + + case Primitive::kPrimDouble: + case Primitive::kPrimFloat: + LOG(FATAL) << "Unimplemented parameter type " << type; + break; + + case Primitive::kPrimVoid: + LOG(FATAL) << "Unexpected parameter type " << type; + break; + } + return Location(); +} + +void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); + locations->AddTemp(X86_64CpuLocation(RDI)); + + InvokeDexCallingConventionVisitor calling_convention_visitor; + for (size_t i = 0; i < invoke->InputCount(); ++i) { + HInstruction* input = invoke->InputAt(i); + locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); + } + + switch (invoke->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + case Primitive::kPrimLong: + locations->SetOut(X86_64CpuLocation(RAX)); + break; + + case Primitive::kPrimVoid: + break; + + case Primitive::kPrimDouble: + case Primitive::kPrimFloat: + LOG(FATAL) << "Unimplemented return type " << invoke->GetType(); + break; + } + + invoke->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) { + CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister(); + uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>); + size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() + + invoke->GetIndexInDexCache() * heap_reference_size; + + // TODO: Implement all kinds of calls: + // 1) boot -> boot + // 2) app -> boot + // 3) app -> app + // + // Currently we implement the app -> app logic, which looks up in the resolve cache. + + // temp = method; + LoadCurrentMethod(temp); + // temp = temp->dex_cache_resolved_methods_; + __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue())); + // temp = temp[index_in_cache] + __ movl(temp, Address(temp, index_in_cache)); + // (temp + offset_of_quick_compiled_code)() + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue())); + + codegen_->RecordPcInfo(invoke->GetDexPc()); +} + +void LocationsBuilderX86_64::VisitAdd(HAdd* add) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add); + switch (add->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + locations->SetInAt(0, X86_64CpuLocation(RAX)); + locations->SetInAt(1, X86_64CpuLocation(RCX)); + locations->SetOut(X86_64CpuLocation(RAX)); + break; + } + + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + LOG(FATAL) << "Unexpected add type " << add->GetResultType(); + break; + + default: + LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); + } + add->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) { + LocationSummary* locations = add->GetLocations(); + switch (add->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), + locations->Out().AsX86_64().AsCpuRegister().AsRegister()); + __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(), + locations->InAt(1).AsX86_64().AsCpuRegister()); + break; + } + + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + LOG(FATAL) << "Unexpected add type " << add->GetResultType(); + break; + + default: + LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); + } +} + +void LocationsBuilderX86_64::VisitSub(HSub* sub) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub); + switch (sub->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + locations->SetInAt(0, X86_64CpuLocation(RAX)); + locations->SetInAt(1, X86_64CpuLocation(RCX)); + locations->SetOut(X86_64CpuLocation(RAX)); + break; + } + + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); + break; + + default: + LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); + } + sub->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) { + LocationSummary* locations = sub->GetLocations(); + switch (sub->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), + locations->Out().AsX86_64().AsCpuRegister().AsRegister()); + __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(), + locations->InAt(1).AsX86_64().AsCpuRegister()); + break; + } + + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); + break; + + default: + LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); + } +} + +void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); + locations->SetOut(X86_64CpuLocation(RAX)); + instruction->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) { + InvokeRuntimeCallingConvention calling_convention; + LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1))); + __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex())); + + __ gs()->call(Address::Absolute( + QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true)); + + codegen_->RecordPcInfo(instruction->GetDexPc()); +} + +void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); + Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); + if (location.IsStackSlot()) { + location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); + } else if (location.IsDoubleStackSlot()) { + location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); + } + locations->SetOut(location); + instruction->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) { + // Nothing to do, the parameter is already at its location. +} + +void LocationsBuilderX86_64::VisitNot(HNot* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); + locations->SetInAt(0, X86_64CpuLocation(RAX)); + locations->SetOut(X86_64CpuLocation(RAX)); + instruction->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) { + LocationSummary* locations = instruction->GetLocations(); + DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), + locations->Out().AsX86_64().AsCpuRegister().AsRegister()); + __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1)); +} + +void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); + for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { + locations->SetInAt(i, Location::Any()); + } + locations->SetOut(Location::Any()); + instruction->SetLocations(locations); +} + +void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) { + LOG(FATAL) << "Unimplemented"; +} + +void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) { + LOG(FATAL) << "Unimplemented"; +} + +void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) { + LOG(FATAL) << "Unimplemented"; +} + +} // namespace x86_64 +} // namespace art diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h new file mode 100644 index 0000000..ac7ee9f --- /dev/null +++ b/compiler/optimizing/code_generator_x86_64.h @@ -0,0 +1,161 @@ +/* + * 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_CODE_GENERATOR_X86_64_H_ +#define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_H_ + +#include "code_generator.h" +#include "nodes.h" +#include "utils/x86_64/assembler_x86_64.h" + +namespace art { +namespace x86_64 { + +static constexpr size_t kX86_64WordSize = 8; + +static constexpr Register kParameterCoreRegisters[] = { RSI, RDX, RCX, R8, R9 }; + +static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); + +class InvokeDexCallingConvention : public CallingConvention<Register> { + public: + InvokeDexCallingConvention() + : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {} + + private: + DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); +}; + +class InvokeDexCallingConventionVisitor { + public: + InvokeDexCallingConventionVisitor() : gp_index_(0), stack_index_(0) {} + + Location GetNextLocation(Primitive::Type type); + + private: + InvokeDexCallingConvention calling_convention; + uint32_t gp_index_; + uint32_t stack_index_; + + DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitor); +}; + +class CodeGeneratorX86_64; + +class LocationsBuilderX86_64 : public HGraphVisitor { + public: + LocationsBuilderX86_64(HGraph* graph, CodeGeneratorX86_64* codegen) + : HGraphVisitor(graph), codegen_(codegen) {} + +#define DECLARE_VISIT_INSTRUCTION(name) \ + virtual void Visit##name(H##name* instr); + + FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION) + +#undef DECLARE_VISIT_INSTRUCTION + + private: + CodeGeneratorX86_64* const codegen_; + InvokeDexCallingConventionVisitor parameter_visitor_; + + DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86_64); +}; + +class InstructionCodeGeneratorX86_64 : public HGraphVisitor { + public: + InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen); + +#define DECLARE_VISIT_INSTRUCTION(name) \ + virtual void Visit##name(H##name* instr); + + FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION) + +#undef DECLARE_VISIT_INSTRUCTION + + void LoadCurrentMethod(CpuRegister reg); + + X86_64Assembler* GetAssembler() const { return assembler_; } + + private: + X86_64Assembler* const assembler_; + CodeGeneratorX86_64* const codegen_; + + DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86_64); +}; + +class CodeGeneratorX86_64 : public CodeGenerator { + public: + explicit CodeGeneratorX86_64(HGraph* graph); + virtual ~CodeGeneratorX86_64() {} + + virtual void ComputeFrameSize(size_t number_of_spill_slots) OVERRIDE; + virtual void GenerateFrameEntry() OVERRIDE; + virtual void GenerateFrameExit() OVERRIDE; + virtual void Bind(Label* label) OVERRIDE; + virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; + + virtual size_t GetWordSize() const OVERRIDE { + return kX86_64WordSize; + } + + virtual HGraphVisitor* GetLocationBuilder() OVERRIDE { + return &location_builder_; + } + + virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE { + return &instruction_visitor_; + } + + virtual X86_64Assembler* GetAssembler() OVERRIDE { + return &assembler_; + } + + int32_t GetStackSlot(HLocal* local) const; + virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE; + + virtual size_t GetNumberOfRegisters() const OVERRIDE { + return kNumberOfRegIds; + } + + virtual size_t GetNumberOfCoreRegisters() const OVERRIDE { + return kNumberOfCpuRegisters; + } + + virtual size_t GetNumberOfFloatingPointRegisters() const OVERRIDE { + return kNumberOfFloatRegisters; + } + + virtual void SetupBlockedRegisters(bool* blocked_registers) const OVERRIDE; + virtual ManagedRegister AllocateFreeRegister( + Primitive::Type type, bool* blocked_registers) const OVERRIDE; + virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; + virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; + + private: + // Helper method to move a value between two locations. + void Move(Location destination, Location source); + + LocationsBuilderX86_64 location_builder_; + InstructionCodeGeneratorX86_64 instruction_visitor_; + X86_64Assembler assembler_; + + DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64); +}; + +} // namespace x86_64 +} // namespace art + +#endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_H_ diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index 8ee775c..3b91ca1 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -47,6 +47,15 @@ class InternalCodeAllocator : public CodeAllocator { DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator); }; +static void Run(const InternalCodeAllocator& allocator, bool has_result, int32_t expected) { + typedef int32_t (*fptr)(); + CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize()); + int32_t result = reinterpret_cast<fptr>(allocator.GetMemory())(); + if (has_result) { + CHECK_EQ(result, expected); + } +} + static void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0) { ArenaPool pool; ArenaAllocator arena(&pool); @@ -55,24 +64,23 @@ static void TestCode(const uint16_t* data, bool has_result = false, int32_t expe HGraph* graph = builder.BuildGraph(*item); ASSERT_NE(graph, nullptr); InternalCodeAllocator allocator; + CodeGenerator* codegen = CodeGenerator::Create(&arena, graph, kX86); codegen->CompileBaseline(&allocator); - typedef int32_t (*fptr)(); #if defined(__i386__) - CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize()); - int32_t result = reinterpret_cast<fptr>(allocator.GetMemory())(); - if (has_result) { - CHECK_EQ(result, expected); - } + Run(allocator, has_result, expected); #endif + codegen = CodeGenerator::Create(&arena, graph, kArm); codegen->CompileBaseline(&allocator); #if defined(__arm__) - CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize()); - int32_t result = reinterpret_cast<fptr>(allocator.GetMemory())(); - if (has_result) { - CHECK_EQ(result, expected); - } + Run(allocator, has_result, expected); +#endif + + codegen = CodeGenerator::Create(&arena, graph, kX86_64); + codegen->CompileBaseline(&allocator); +#if defined(__x86_64__) + Run(allocator, has_result, expected); #endif } diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h index 3c60d3c..40a39ad 100644 --- a/compiler/optimizing/locations.h +++ b/compiler/optimizing/locations.h @@ -150,6 +150,7 @@ class Location : public ValueObject { arm::ArmManagedRegister AsArm() const; x86::X86ManagedRegister AsX86() const; + x86_64::X86_64ManagedRegister AsX86_64() const; Kind GetKind() const { return KindField::Decode(value_); |