diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/builder.cc | 393 | ||||
-rw-r--r-- | compiler/optimizing/builder.h | 46 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.cc | 26 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.h | 161 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 551 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.h | 56 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 551 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.h | 55 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 152 |
9 files changed, 1681 insertions, 310 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 05548761e0..1efdd389d8 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -25,7 +25,8 @@ namespace art { -void HGraphBuilder::InitializeLocals(int count) { +void HGraphBuilder::InitializeLocals(uint16_t count) { + graph_->SetNumberOfVRegs(count); locals_.SetSize(count); for (int i = 0; i < count; i++) { HLocal* local = new (arena_) HLocal(i); @@ -34,15 +35,81 @@ void HGraphBuilder::InitializeLocals(int count) { } } +bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) { + // dex_compilation_unit_ is null only when unit testing. + if (dex_compilation_unit_ == nullptr) { + return true; + } + + graph_->SetNumberOfInVRegs(number_of_parameters); + const char* shorty = dex_compilation_unit_->GetShorty(); + int locals_index = locals_.Size() - number_of_parameters; + int parameter_index = 0; + + if (!dex_compilation_unit_->IsStatic()) { + // Add the implicit 'this' argument, not expressed in the signature. + HParameterValue* parameter = + new (arena_) HParameterValue(parameter_index++, Primitive::kPrimNot); + entry_block_->AddInstruction(parameter); + HLocal* local = GetLocalAt(locals_index++); + entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter)); + number_of_parameters--; + } + + uint32_t pos = 1; + for (int i = 0; i < number_of_parameters; i++) { + switch (shorty[pos++]) { + case 'F': + case 'D': { + return false; + } + + default: { + // integer and reference parameters. + HParameterValue* parameter = + new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos - 1])); + entry_block_->AddInstruction(parameter); + HLocal* local = GetLocalAt(locals_index++); + // Store the parameter value in the local that the dex code will use + // to reference that parameter. + entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter)); + if (parameter->GetType() == Primitive::kPrimLong) { + i++; + locals_index++; + parameter_index++; + } + break; + } + } + } + return true; +} + static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) { if (code_item.tries_size_ > 0) { return false; - } else if (code_item.ins_size_ > 0) { - return false; } return true; } +template<typename T> +void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not) { + HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt); + HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + current_block_->AddInstruction(new (arena_) T(first, second)); + if (is_not) { + current_block_->AddInstruction(new (arena_) HNot(current_block_->GetLastInstruction())); + } + current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction())); + HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset); + DCHECK(target != nullptr); + current_block_->AddSuccessor(target); + target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits()); + DCHECK(target != nullptr); + current_block_->AddSuccessor(target); + current_block_ = nullptr; +} + HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { if (!CanHandleCodeItem(code_item)) { return nullptr; @@ -66,6 +133,10 @@ HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { // start a new block, and create these blocks. ComputeBranchTargets(code_ptr, code_end); + if (!InitializeParameters(code_item.ins_size_)) { + return nullptr; + } + size_t dex_offset = 0; while (code_ptr < code_end) { // Update the current block if dex_offset starts a new block. @@ -139,6 +210,112 @@ HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const { return branch_targets_.Get(index); } +template<typename T> +void HGraphBuilder::Binop_32x(const Instruction& instruction, Primitive::Type type) { + HInstruction* first = LoadLocal(instruction.VRegB(), type); + HInstruction* second = LoadLocal(instruction.VRegC(), type); + current_block_->AddInstruction(new (arena_) T(type, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> +void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) { + HInstruction* first = LoadLocal(instruction.VRegA(), type); + HInstruction* second = LoadLocal(instruction.VRegB(), type); + current_block_->AddInstruction(new (arena_) T(type, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> +void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) { + HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + HInstruction* second = GetIntConstant(instruction.VRegC_22s()); + if (reverse) { + std::swap(first, second); + } + current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> +void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) { + HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + HInstruction* second = GetIntConstant(instruction.VRegC_22b()); + if (reverse) { + std::swap(first, second); + } + current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) { + if (type == Primitive::kPrimVoid) { + current_block_->AddInstruction(new (arena_) HReturnVoid()); + } else { + HInstruction* value = LoadLocal(instruction.VRegA(), type); + current_block_->AddInstruction(new (arena_) HReturn(value)); + } + current_block_->AddSuccessor(exit_block_); + current_block_ = nullptr; +} + +bool HGraphBuilder::BuildInvoke(const Instruction& instruction, + uint32_t dex_offset, + uint32_t method_idx, + uint32_t number_of_vreg_arguments, + bool is_range, + uint32_t* args, + uint32_t register_index) { + const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); + const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_id.proto_idx_); + const char* descriptor = dex_file_->StringDataByIdx(proto_id.shorty_idx_); + Primitive::Type return_type = Primitive::GetType(descriptor[0]); + bool is_instance_call = + instruction.Opcode() != Instruction::INVOKE_STATIC + && instruction.Opcode() != Instruction::INVOKE_STATIC_RANGE; + const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1); + + // Treat invoke-direct like static calls for now. + HInvoke* invoke = new (arena_) HInvokeStatic( + arena_, number_of_arguments, return_type, dex_offset, method_idx); + + size_t start_index = 0; + if (is_instance_call) { + HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot); + invoke->SetArgumentAt(0, arg); + start_index = 1; + } + + uint32_t descriptor_index = 1; + uint32_t argument_index = start_index; + for (size_t i = start_index; i < number_of_vreg_arguments; i++, argument_index++) { + Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]); + switch (type) { + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + return false; + + default: { + if (!is_range && type == Primitive::kPrimLong && args[i] + 1 != args[i + 1]) { + LOG(WARNING) << "Non sequential register pair in " << dex_compilation_unit_->GetSymbol() + << " at " << dex_offset; + // We do not implement non sequential register pair. + return false; + } + HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type); + invoke->SetArgumentAt(argument_index, arg); + if (type == Primitive::kPrimLong) { + i++; + } + } + } + } + + DCHECK_EQ(argument_index, number_of_arguments); + current_block_->AddInstruction(invoke); + return true; +} + bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) { if (current_block_ == nullptr) { return true; // Dead code @@ -147,30 +324,57 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ switch (instruction.Opcode()) { case Instruction::CONST_4: { int32_t register_index = instruction.VRegA(); - HIntConstant* constant = GetConstant(instruction.VRegB_11n()); + HIntConstant* constant = GetIntConstant(instruction.VRegB_11n()); + UpdateLocal(register_index, constant); + break; + } + + case Instruction::CONST_16: { + int32_t register_index = instruction.VRegA(); + HIntConstant* constant = GetIntConstant(instruction.VRegB_21s()); UpdateLocal(register_index, constant); break; } + case Instruction::CONST_WIDE_16: { + int32_t register_index = instruction.VRegA(); + HLongConstant* constant = GetLongConstant(instruction.VRegB_21s()); + UpdateLocal(register_index, constant); + break; + } + + case Instruction::CONST_WIDE_32: { + int32_t register_index = instruction.VRegA(); + HLongConstant* constant = GetLongConstant(instruction.VRegB_31i()); + UpdateLocal(register_index, constant); + break; + } + + case Instruction::CONST_WIDE: { + int32_t register_index = instruction.VRegA(); + HLongConstant* constant = GetLongConstant(instruction.VRegB_51l()); + UpdateLocal(register_index, constant); + break; + } + + case Instruction::MOVE: { + HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + UpdateLocal(instruction.VRegA(), value); + break; + } + case Instruction::RETURN_VOID: { - current_block_->AddInstruction(new (arena_) HReturnVoid()); - current_block_->AddSuccessor(exit_block_); - current_block_ = nullptr; + BuildReturn(instruction, Primitive::kPrimVoid); break; } case Instruction::IF_EQ: { - HInstruction* first = LoadLocal(instruction.VRegA()); - HInstruction* second = LoadLocal(instruction.VRegB()); - current_block_->AddInstruction(new (arena_) HEqual(first, second)); - current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction())); - HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset); - DCHECK(target != nullptr); - current_block_->AddSuccessor(target); - target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits()); - DCHECK(target != nullptr); - current_block_->AddSuccessor(target); - current_block_ = nullptr; + If_22t<HEqual>(instruction, dex_offset, false); + break; + } + + case Instruction::IF_NE: { + If_22t<HEqual>(instruction, dex_offset, true); break; } @@ -186,93 +390,112 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ } case Instruction::RETURN: { - HInstruction* value = LoadLocal(instruction.VRegA()); - current_block_->AddInstruction(new (arena_) HReturn(value)); - current_block_->AddSuccessor(exit_block_); - current_block_ = nullptr; + BuildReturn(instruction, Primitive::kPrimInt); break; } - case Instruction::INVOKE_STATIC: { - uint32_t method_idx = instruction.VRegB_35c(); - const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); - uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; - const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx); - const size_t number_of_arguments = instruction.VRegA_35c(); - - if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) { - return false; - } + case Instruction::RETURN_OBJECT: { + BuildReturn(instruction, Primitive::kPrimNot); + break; + } - HInvokeStatic* invoke = new (arena_) HInvokeStatic( - arena_, number_of_arguments, dex_offset, method_idx); + case Instruction::RETURN_WIDE: { + BuildReturn(instruction, Primitive::kPrimLong); + break; + } + case Instruction::INVOKE_STATIC: + case Instruction::INVOKE_DIRECT: { + uint32_t method_idx = instruction.VRegB_35c(); + uint32_t number_of_vreg_arguments = instruction.VRegA_35c(); uint32_t args[5]; instruction.GetArgs(args); - - for (size_t i = 0; i < number_of_arguments; i++) { - HInstruction* arg = LoadLocal(args[i]); - HInstruction* push = new (arena_) HPushArgument(arg, i); - current_block_->AddInstruction(push); - invoke->SetArgumentAt(i, push); + if (!BuildInvoke(instruction, dex_offset, method_idx, number_of_vreg_arguments, false, args, -1)) { + return false; } - - current_block_->AddInstruction(invoke); break; } - case Instruction::INVOKE_STATIC_RANGE: { + case Instruction::INVOKE_STATIC_RANGE: + case Instruction::INVOKE_DIRECT_RANGE: { uint32_t method_idx = instruction.VRegB_3rc(); - const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); - uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; - const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx); - const size_t number_of_arguments = instruction.VRegA_3rc(); - - if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) { + uint32_t number_of_vreg_arguments = instruction.VRegA_3rc(); + uint32_t register_index = instruction.VRegC(); + if (!BuildInvoke(instruction, dex_offset, method_idx, + number_of_vreg_arguments, true, nullptr, register_index)) { return false; } - - HInvokeStatic* invoke = new (arena_) HInvokeStatic( - arena_, number_of_arguments, dex_offset, method_idx); - int32_t register_index = instruction.VRegC(); - for (size_t i = 0; i < number_of_arguments; i++) { - HInstruction* arg = LoadLocal(register_index + i); - HInstruction* push = new (arena_) HPushArgument(arg, i); - current_block_->AddInstruction(push); - invoke->SetArgumentAt(i, push); - } - current_block_->AddInstruction(invoke); break; } case Instruction::ADD_INT: { - HInstruction* first = LoadLocal(instruction.VRegB()); - HInstruction* second = LoadLocal(instruction.VRegC()); - current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + Binop_32x<HAdd>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::ADD_LONG: { + Binop_32x<HAdd>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::SUB_INT: { + Binop_32x<HSub>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SUB_LONG: { + Binop_32x<HSub>(instruction, Primitive::kPrimLong); break; } case Instruction::ADD_INT_2ADDR: { - HInstruction* first = LoadLocal(instruction.VRegA()); - HInstruction* second = LoadLocal(instruction.VRegB()); - current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + Binop_12x<HAdd>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::ADD_LONG_2ADDR: { + Binop_12x<HAdd>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::SUB_INT_2ADDR: { + Binop_12x<HSub>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SUB_LONG_2ADDR: { + Binop_12x<HSub>(instruction, Primitive::kPrimLong); break; } case Instruction::ADD_INT_LIT16: { - HInstruction* first = LoadLocal(instruction.VRegB()); - HInstruction* second = GetConstant(instruction.VRegC_22s()); - current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + Binop_22s<HAdd>(instruction, false); + break; + } + + case Instruction::RSUB_INT: { + Binop_22s<HSub>(instruction, true); break; } case Instruction::ADD_INT_LIT8: { - HInstruction* first = LoadLocal(instruction.VRegB()); - HInstruction* second = GetConstant(instruction.VRegC_22b()); - current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); + Binop_22b<HAdd>(instruction, false); + break; + } + + case Instruction::RSUB_INT_LIT8: { + Binop_22b<HSub>(instruction, true); + break; + } + + case Instruction::NEW_INSTANCE: { + current_block_->AddInstruction( + new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c())); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + break; + } + + case Instruction::MOVE_RESULT_WIDE: { UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); break; } @@ -286,7 +509,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ return true; } -HIntConstant* HGraphBuilder::GetConstant0() { +HIntConstant* HGraphBuilder::GetIntConstant0() { if (constant0_ != nullptr) { return constant0_; } @@ -295,7 +518,7 @@ HIntConstant* HGraphBuilder::GetConstant0() { return constant0_; } -HIntConstant* HGraphBuilder::GetConstant1() { +HIntConstant* HGraphBuilder::GetIntConstant1() { if (constant1_ != nullptr) { return constant1_; } @@ -304,10 +527,10 @@ HIntConstant* HGraphBuilder::GetConstant1() { return constant1_; } -HIntConstant* HGraphBuilder::GetConstant(int constant) { +HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) { switch (constant) { - case 0: return GetConstant0(); - case 1: return GetConstant1(); + case 0: return GetIntConstant0(); + case 1: return GetIntConstant1(); default: { HIntConstant* instruction = new (arena_) HIntConstant(constant); entry_block_->AddInstruction(instruction); @@ -316,6 +539,12 @@ HIntConstant* HGraphBuilder::GetConstant(int constant) { } } +HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) { + HLongConstant* instruction = new (arena_) HLongConstant(constant); + entry_block_->AddInstruction(instruction); + return instruction; +} + HLocal* HGraphBuilder::GetLocalAt(int register_index) const { return locals_.Get(register_index); } @@ -325,9 +554,9 @@ void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) c current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction)); } -HInstruction* HGraphBuilder::LoadLocal(int register_index) const { +HInstruction* HGraphBuilder::LoadLocal(int register_index, Primitive::Type type) const { HLocal* local = GetLocalAt(register_index); - current_block_->AddInstruction(new (arena_) HLoadLocal(local)); + current_block_->AddInstruction(new (arena_) HLoadLocal(local, type)); return current_block_->GetLastInstruction(); } diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 46ca9aabd7..108514a632 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -19,6 +19,7 @@ #include "dex_file.h" #include "driver/dex_compilation_unit.h" +#include "primitive.h" #include "utils/allocation.h" #include "utils/growable_array.h" @@ -29,13 +30,14 @@ class Instruction; class HBasicBlock; class HGraph; class HIntConstant; +class HLongConstant; class HInstruction; class HLocal; class HGraphBuilder : public ValueObject { public: HGraphBuilder(ArenaAllocator* arena, - const DexCompilationUnit* dex_compilation_unit = nullptr, + DexCompilationUnit* dex_compilation_unit = nullptr, const DexFile* dex_file = nullptr) : arena_(arena), branch_targets_(arena, 0), @@ -63,13 +65,43 @@ class HGraphBuilder : public ValueObject { void MaybeUpdateCurrentBlock(size_t index); HBasicBlock* FindBlockStartingAt(int32_t index) const; - HIntConstant* GetConstant0(); - HIntConstant* GetConstant1(); - HIntConstant* GetConstant(int constant); - void InitializeLocals(int count); + HIntConstant* GetIntConstant0(); + HIntConstant* GetIntConstant1(); + HIntConstant* GetIntConstant(int32_t constant); + HLongConstant* GetLongConstant(int64_t constant); + void InitializeLocals(uint16_t count); HLocal* GetLocalAt(int register_index) const; void UpdateLocal(int register_index, HInstruction* instruction) const; - HInstruction* LoadLocal(int register_index) const; + HInstruction* LoadLocal(int register_index, Primitive::Type type) const; + + // Temporarily returns whether the compiler supports the parameters + // of the method. + bool InitializeParameters(uint16_t number_of_parameters); + + template<typename T> + void Binop_32x(const Instruction& instruction, Primitive::Type type); + + template<typename T> + void Binop_12x(const Instruction& instruction, Primitive::Type type); + + template<typename T> + void Binop_22b(const Instruction& instruction, bool reverse); + + template<typename T> + void Binop_22s(const Instruction& instruction, bool reverse); + + template<typename T> void If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not); + + void BuildReturn(const Instruction& instruction, Primitive::Type type); + + // Builds an invocation node and returns whether the instruction is supported. + bool BuildInvoke(const Instruction& instruction, + uint32_t dex_offset, + uint32_t method_idx, + uint32_t number_of_vreg_arguments, + bool is_range, + uint32_t* args, + uint32_t register_index); ArenaAllocator* const arena_; @@ -89,7 +121,7 @@ class HGraphBuilder : public ValueObject { HIntConstant* constant1_; const DexFile* const dex_file_; - const DexCompilationUnit* const dex_compilation_unit_; + DexCompilationUnit* const dex_compilation_unit_; DISALLOW_COPY_AND_ASSIGN(HGraphBuilder); }; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 05e5d7b8ef..7e63c69f5c 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -30,12 +30,11 @@ namespace art { void CodeGenerator::Compile(CodeAllocator* allocator) { - frame_size_ = GetGraph()->GetMaximumNumberOfOutVRegs() * kWordSize; const GrowableArray<HBasicBlock*>* blocks = GetGraph()->GetBlocks(); DCHECK(blocks->Get(0) == GetGraph()->GetEntryBlock()); DCHECK(GoesToNextBlock(GetGraph()->GetEntryBlock(), blocks->Get(1))); - CompileEntryBlock(); - for (size_t i = 1; i < blocks->Size(); i++) { + GenerateFrameEntry(); + for (size_t i = 0; i < blocks->Size(); i++) { CompileBlock(blocks->Get(i)); } size_t code_size = GetAssembler()->CodeSize(); @@ -44,32 +43,11 @@ void CodeGenerator::Compile(CodeAllocator* allocator) { GetAssembler()->FinalizeInstructions(code); } -void CodeGenerator::CompileEntryBlock() { - HGraphVisitor* location_builder = GetLocationBuilder(); - HGraphVisitor* instruction_visitor = GetInstructionVisitor(); - // The entry block contains all locals for this method. By visiting the entry block, - // we're computing the required frame size. - for (HInstructionIterator it(GetGraph()->GetEntryBlock()); !it.Done(); it.Advance()) { - HInstruction* current = it.Current(); - // Instructions in the entry block should not generate code. - if (kIsDebugBuild) { - current->Accept(location_builder); - DCHECK(current->GetLocations() == nullptr); - } - current->Accept(instruction_visitor); - } - GenerateFrameEntry(); -} - void CodeGenerator::CompileBlock(HBasicBlock* block) { Bind(GetLabelOf(block)); HGraphVisitor* location_builder = GetLocationBuilder(); HGraphVisitor* instruction_visitor = GetInstructionVisitor(); for (HInstructionIterator it(block); !it.Done(); it.Advance()) { - // For each instruction, we emulate a stack-based machine, where the inputs are popped from - // the runtime stack, and the result is pushed on the stack. We currently can do this because - // we do not perform any code motion, and the Dex format does not reference individual - // instructions but uses registers instead (our equivalent of HLocal). HInstruction* current = it.Current(); current->Accept(location_builder); InitLocations(current); diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 01bbcc0bb6..5c7cac1e5c 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -17,6 +17,7 @@ #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_ #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_ +#include "base/bit_field.h" #include "globals.h" #include "instruction_set.h" #include "memory_region.h" @@ -25,6 +26,8 @@ namespace art { +static size_t constexpr kVRegSize = 4; + class DexCompilationUnit; class CodeAllocator { @@ -49,30 +52,149 @@ struct PcInfo { */ class Location : public ValueObject { public: - template<typename T> - T reg() const { return static_cast<T>(reg_); } + enum Kind { + kInvalid = 0, + kStackSlot = 1, // Word size slot. + kDoubleStackSlot = 2, // 64bit stack slot. + kRegister = 3, + // On 32bits architectures, quick can pass a long where the + // low bits are in the last parameter register, and the high + // bits are in a stack slot. The kQuickParameter kind is for + // handling this special case. + kQuickParameter = 4, + }; + + Location() : value_(kInvalid) { + DCHECK(!IsValid()); + } + + Location(const Location& other) : ValueObject(), value_(other.value_) {} + + Location& operator=(const Location& other) { + value_ = other.value_; + return *this; + } - Location() : reg_(kInvalid) { } - explicit Location(uword reg) : reg_(reg) { } + bool IsValid() const { + return value_ != kInvalid; + } - static Location RegisterLocation(uword reg) { - return Location(reg); + // Register locations. + static Location RegisterLocation(ManagedRegister reg) { + return Location(kRegister, reg.RegId()); } - bool IsValid() const { return reg_ != kInvalid; } + bool IsRegister() const { + return GetKind() == kRegister; + } - Location(const Location& other) : reg_(other.reg_) { } + ManagedRegister reg() const { + DCHECK(IsRegister()); + return static_cast<ManagedRegister>(GetPayload()); + } - Location& operator=(const Location& other) { - reg_ = other.reg_; - return *this; + static uword EncodeStackIndex(intptr_t stack_index) { + DCHECK(-kStackIndexBias <= stack_index); + DCHECK(stack_index < kStackIndexBias); + return static_cast<uword>(kStackIndexBias + stack_index); + } + + static Location StackSlot(intptr_t stack_index) { + uword payload = EncodeStackIndex(stack_index); + Location loc(kStackSlot, payload); + // Ensure that sign is preserved. + DCHECK_EQ(loc.GetStackIndex(), stack_index); + return loc; + } + + bool IsStackSlot() const { + return GetKind() == kStackSlot; + } + + static Location DoubleStackSlot(intptr_t stack_index) { + uword payload = EncodeStackIndex(stack_index); + Location loc(kDoubleStackSlot, payload); + // Ensure that sign is preserved. + DCHECK_EQ(loc.GetStackIndex(), stack_index); + return loc; + } + + bool IsDoubleStackSlot() const { + return GetKind() == kDoubleStackSlot; + } + + intptr_t GetStackIndex() const { + DCHECK(IsStackSlot() || IsDoubleStackSlot()); + // Decode stack index manually to preserve sign. + return GetPayload() - kStackIndexBias; + } + + intptr_t GetHighStackIndex(uintptr_t word_size) const { + DCHECK(IsDoubleStackSlot()); + // Decode stack index manually to preserve sign. + return GetPayload() - kStackIndexBias + word_size; + } + + static Location QuickParameter(uint32_t parameter_index) { + return Location(kQuickParameter, parameter_index); + } + + uint32_t GetQuickParameterIndex() const { + DCHECK(IsQuickParameter()); + return GetPayload(); + } + + bool IsQuickParameter() const { + return GetKind() == kQuickParameter; + } + + arm::ArmManagedRegister AsArm() const; + x86::X86ManagedRegister AsX86() const; + + Kind GetKind() const { + return KindField::Decode(value_); + } + + bool Equals(Location other) const { + return value_ == other.value_; + } + + const char* DebugString() const { + switch (GetKind()) { + case kInvalid: return "?"; + case kRegister: return "R"; + case kStackSlot: return "S"; + case kDoubleStackSlot: return "DS"; + case kQuickParameter: return "Q"; + } + return "?"; } private: - // The target register for that location. - // TODO: Support stack location. - uword reg_; - static const uword kInvalid = -1; + // Number of bits required to encode Kind value. + static constexpr uint32_t kBitsForKind = 4; + static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind; + + explicit Location(uword value) : value_(value) {} + + Location(Kind kind, uword payload) + : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {} + + uword GetPayload() const { + return PayloadField::Decode(value_); + } + + typedef BitField<Kind, 0, kBitsForKind> KindField; + typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField; + + // Layout for stack slots. + static const intptr_t kStackIndexBias = + static_cast<intptr_t>(1) << (kBitsForPayload - 1); + + // Location either contains kind and payload fields or a tagged handle for + // a constant locations. Values of enumeration Kind are selected in such a + // way that none of them can be interpreted as a kConstant tag. + uword value_; }; /** @@ -145,6 +267,7 @@ class CodeGenerator : public ArenaObject { virtual HGraphVisitor* GetLocationBuilder() = 0; virtual HGraphVisitor* GetInstructionVisitor() = 0; virtual Assembler* GetAssembler() = 0; + virtual size_t GetWordSize() const = 0; uint32_t GetFrameSize() const { return frame_size_; } void SetFrameSize(uint32_t size) { frame_size_ = size; } @@ -179,7 +302,6 @@ class CodeGenerator : public ArenaObject { private: void InitLocations(HInstruction* instruction); void CompileBlock(HBasicBlock* block); - void CompileEntryBlock(); HGraph* const graph_; @@ -203,11 +325,10 @@ class CallingConvention { return registers_[index]; } - uint8_t GetStackOffsetOf(size_t index) const { - DCHECK_GE(index, number_of_registers_); + uint8_t GetStackOffsetOf(size_t index, size_t word_size) const { // We still reserve the space for parameters passed by registers. - // Add kWordSize for the method pointer. - return index * kWordSize + kWordSize; + // Add word_size for the method pointer. + return index * kVRegSize + word_size; } private: diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 09d6f7b36a..27691ac080 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -17,6 +17,7 @@ #include "code_generator_arm.h" #include "utils/assembler.h" #include "utils/arm/assembler_arm.h" +#include "utils/arm/managed_register_arm.h" #include "mirror/array.h" #include "mirror/art_method.h" @@ -24,11 +25,20 @@ #define __ reinterpret_cast<ArmAssembler*>(GetAssembler())-> namespace art { + +arm::ArmManagedRegister Location::AsArm() const { + return reg().AsArm(); +} + namespace arm { static constexpr int kNumberOfPushedRegistersAtEntry = 1; static constexpr int kCurrentMethodStackOffset = 0; +static Location ArmCoreLocation(Register reg) { + return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg)); +} + InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen) : HGraphVisitor(graph), assembler_(codegen->GetAssembler()), @@ -38,15 +48,19 @@ void CodeGeneratorARM::GenerateFrameEntry() { core_spill_mask_ |= (1 << LR); __ PushList((1 << LR)); - // Add the current ART method to the frame size and the return PC. - SetFrameSize(RoundUp(GetFrameSize() + 2 * kWordSize, kStackAlignment)); - // The retrn PC has already been pushed on the stack. - __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kWordSize)); + SetFrameSize(RoundUp( + (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize + + kVRegSize // filler + + kArmWordSize // Art method + + kNumberOfPushedRegistersAtEntry * kArmWordSize, + kStackAlignment)); + // The return PC has already been pushed on the stack. + __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize)); __ str(R0, Address(SP, 0)); } void CodeGeneratorARM::GenerateFrameExit() { - __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kWordSize); + __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize); __ PopList((1 << PC)); } @@ -55,21 +69,210 @@ void CodeGeneratorARM::Bind(Label* label) { } int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const { - return (GetGraph()->GetMaximumNumberOfOutVRegs() + local->GetRegNumber()) * kWordSize; + 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() + kArmWordSize // 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 * kArmWordSize) + - kVRegSize // filler. + - (number_of_vregs * kVRegSize) + + (reg_number * kVRegSize); + } +} + +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_++; + if (index < calling_convention.GetNumberOfRegisters()) { + return ArmCoreLocation(calling_convention.GetRegisterAt(index)); + } else { + return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize)); + } + } + + case Primitive::kPrimLong: { + uint32_t index = gp_index_; + gp_index_ += 2; + if (index + 1 < calling_convention.GetNumberOfRegisters()) { + return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair( + calling_convention.GetRegisterPairAt(index))); + } else if (index + 1 == calling_convention.GetNumberOfRegisters()) { + return Location::QuickParameter(index); + } else { + return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize)); + } + } + + 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 CodeGeneratorARM::Move32(Location destination, Location source) { + if (source.Equals(destination)) { + return; + } + if (destination.IsRegister()) { + if (source.IsRegister()) { + __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister()); + } else { + __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex())); + } + } else { + DCHECK(destination.IsStackSlot()); + if (source.IsRegister()) { + __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex())); + } else { + __ ldr(R0, Address(SP, source.GetStackIndex())); + __ str(R0, Address(SP, destination.GetStackIndex())); + } + } +} + +void CodeGeneratorARM::Move64(Location destination, Location source) { + if (source.Equals(destination)) { + return; + } + if (destination.IsRegister()) { + if (source.IsRegister()) { + __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow()); + __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh()); + } else if (source.IsQuickParameter()) { + uint32_t argument_index = source.GetQuickParameterIndex(); + InvokeDexCallingConvention calling_convention; + __ Mov(destination.AsArm().AsRegisterPairLow(), + calling_convention.GetRegisterAt(argument_index)); + __ ldr(destination.AsArm().AsRegisterPairHigh(), + Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize())); + } else { + DCHECK(source.IsDoubleStackSlot()); + if (destination.AsArm().AsRegisterPair() == R1_R2) { + __ ldr(R1, Address(SP, source.GetStackIndex())); + __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize))); + } else { + __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(), + SP, source.GetStackIndex()); + } + } + } else if (destination.IsQuickParameter()) { + InvokeDexCallingConvention calling_convention; + uint32_t argument_index = destination.GetQuickParameterIndex(); + 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))); + } else { + DCHECK(source.IsDoubleStackSlot()); + __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex())); + __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize))); + __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize))); + } + } else { + DCHECK(destination.IsDoubleStackSlot()); + if (source.IsRegister()) { + if (source.AsArm().AsRegisterPair() == R1_R2) { + __ str(R1, Address(SP, destination.GetStackIndex())); + __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize))); + } else { + __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(), + SP, destination.GetStackIndex()); + } + } else if (source.IsQuickParameter()) { + InvokeDexCallingConvention calling_convention; + uint32_t argument_index = source.GetQuickParameterIndex(); + __ str(calling_convention.GetRegisterAt(argument_index), + Address(SP, destination.GetStackIndex())); + __ ldr(R0, + Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize())); + __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize))); + } else { + DCHECK(source.IsDoubleStackSlot()); + __ ldr(R0, Address(SP, source.GetStackIndex())); + __ str(R0, Address(SP, destination.GetStackIndex())); + __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize))); + __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize))); + } + } } void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) { if (instruction->AsIntConstant() != nullptr) { - __ LoadImmediate(location.reg<Register>(), instruction->AsIntConstant()->GetValue()); + int32_t value = instruction->AsIntConstant()->GetValue(); + if (location.IsRegister()) { + __ LoadImmediate(location.AsArm().AsCoreRegister(), value); + } else { + __ LoadImmediate(R0, value); + __ str(R0, Address(SP, location.GetStackIndex())); + } + } else if (instruction->AsLongConstant() != nullptr) { + int64_t value = instruction->AsLongConstant()->GetValue(); + if (location.IsRegister()) { + __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value)); + __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value)); + } else { + __ LoadImmediate(R0, Low32Bits(value)); + __ str(R0, Address(SP, location.GetStackIndex())); + __ LoadImmediate(R0, High32Bits(value)); + __ str(R0, Address(SP, location.GetHighStackIndex(kArmWordSize))); + } } else if (instruction->AsLoadLocal() != nullptr) { - __ LoadFromOffset(kLoadWord, location.reg<Register>(), - SP, GetStackSlot(instruction->AsLoadLocal()->GetLocal())); + uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); + switch (instruction->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + Move32(location, Location::StackSlot(stack_slot)); + break; + + case Primitive::kPrimLong: + Move64(location, Location::DoubleStackSlot(stack_slot)); + break; + + default: + LOG(FATAL) << "Unimplemented 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); - __ mov(location.reg<Register>(), - ShifterOperand(instruction->GetLocations()->Out().reg<Register>())); + switch (instruction->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimNot: + case Primitive::kPrimInt: + Move32(location, instruction->GetLocations()->Out()); + break; + + case Primitive::kPrimLong: + Move64(location, instruction->GetLocations()->Out()); + break; + + default: + LOG(FATAL) << "Unimplemented type " << instruction->GetType(); + } } } @@ -99,13 +302,13 @@ void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { void LocationsBuilderARM::VisitIf(HIf* if_instr) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr); - locations->SetInAt(0, Location(R0)); + locations->SetInAt(0, ArmCoreLocation(R0)); if_instr->SetLocations(locations); } void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { // TODO: Generate the input as a condition, instead of materializing in a register. - __ cmp(if_instr->GetLocations()->InAt(0).reg<Register>(), ShifterOperand(0)); + __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0)); __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ); if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) { __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); @@ -114,18 +317,18 @@ void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { void LocationsBuilderARM::VisitEqual(HEqual* equal) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal); - locations->SetInAt(0, Location(R0)); - locations->SetInAt(1, Location(R1)); - locations->SetOut(Location(R0)); + locations->SetInAt(0, ArmCoreLocation(R0)); + locations->SetInAt(1, ArmCoreLocation(R1)); + locations->SetOut(ArmCoreLocation(R0)); equal->SetLocations(locations); } void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) { LocationSummary* locations = equal->GetLocations(); - __ teq(locations->InAt(0).reg<Register>(), - ShifterOperand(locations->InAt(1).reg<Register>())); - __ mov(locations->Out().reg<Register>(), ShifterOperand(1), EQ); - __ mov(locations->Out().reg<Register>(), ShifterOperand(0), NE); + __ teq(locations->InAt(0).AsArm().AsCoreRegister(), + ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); + __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), EQ); + __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), NE); } void LocationsBuilderARM::VisitLocal(HLocal* local) { @@ -134,7 +337,6 @@ void LocationsBuilderARM::VisitLocal(HLocal* local) { void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); - codegen_->SetFrameSize(codegen_->GetFrameSize() + kWordSize); } void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { @@ -147,14 +349,27 @@ void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store); - locations->SetInAt(1, Location(R0)); + 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 InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { - LocationSummary* locations = store->GetLocations(); - __ StoreToOffset(kStoreWord, locations->InAt(1).reg<Register>(), - SP, codegen_->GetStackSlot(store->GetLocal())); } void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { @@ -165,6 +380,14 @@ void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { // Will be generated at use site. } +void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) { + constant->SetLocations(nullptr); +} + +void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) { + // Will be generated at use site. +} + void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { ret->SetLocations(nullptr); } @@ -175,56 +398,83 @@ void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { void LocationsBuilderARM::VisitReturn(HReturn* ret) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret); - locations->SetInAt(0, Location(R0)); + switch (ret->InputAt(0)->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + locations->SetInAt(0, ArmCoreLocation(R0)); + break; + + case Primitive::kPrimLong: + locations->SetInAt(0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); + break; + + default: + LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); + } + ret->SetLocations(locations); } void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { - DCHECK_EQ(ret->GetLocations()->InAt(0).reg<Register>(), R0); + 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: + DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0); + break; + + case Primitive::kPrimLong: + DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1); + break; + + default: + LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); + } + } codegen_->GenerateFrameExit(); } -static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 }; -static constexpr int kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); +void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); + locations->AddTemp(ArmCoreLocation(R0)); -class InvokeStaticCallingConvention : public CallingConvention<Register> { - public: - InvokeStaticCallingConvention() - : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {} + InvokeDexCallingConventionVisitor calling_convention_visitor; + for (int i = 0; i < invoke->InputCount(); i++) { + HInstruction* input = invoke->InputAt(i); + locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); + } - private: - DISALLOW_COPY_AND_ASSIGN(InvokeStaticCallingConvention); -}; + switch (invoke->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + locations->SetOut(ArmCoreLocation(R0)); + break; -void LocationsBuilderARM::VisitPushArgument(HPushArgument* argument) { - LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument); - InvokeStaticCallingConvention calling_convention; - if (argument->GetArgumentIndex() < calling_convention.GetNumberOfRegisters()) { - Location location = Location(calling_convention.GetRegisterAt(argument->GetArgumentIndex())); - locations->SetInAt(0, location); - locations->SetOut(location); - } else { - locations->SetInAt(0, Location(R0)); - } - argument->SetLocations(locations); -} + case Primitive::kPrimLong: + locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); + break; -void InstructionCodeGeneratorARM::VisitPushArgument(HPushArgument* argument) { - uint8_t argument_index = argument->GetArgumentIndex(); - InvokeStaticCallingConvention calling_convention; - size_t parameter_registers = calling_convention.GetNumberOfRegisters(); - LocationSummary* locations = argument->GetLocations(); - if (argument_index >= parameter_registers) { - uint8_t offset = calling_convention.GetStackOffsetOf(argument_index); - __ StoreToOffset(kStoreWord, locations->InAt(0).reg<Register>(), SP, offset); - } else { - DCHECK_EQ(locations->Out().reg<Register>(), locations->InAt(0).reg<Register>()); + case Primitive::kPrimVoid: + break; + + case Primitive::kPrimDouble: + case Primitive::kPrimFloat: + LOG(FATAL) << "Unimplemented return type " << invoke->GetType(); + break; } -} -void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { - LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); - locations->AddTemp(Location(R0)); invoke->SetLocations(locations); } @@ -233,9 +483,9 @@ void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) { } void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { - Register temp = invoke->GetLocations()->GetTemp(0).reg<Register>(); + Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister(); size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + - invoke->GetIndexInDexCache() * kWordSize; + invoke->GetIndexInDexCache() * kArmWordSize; // TODO: Implement all kinds of calls: // 1) boot -> boot @@ -263,13 +513,30 @@ void LocationsBuilderARM::VisitAdd(HAdd* add) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add); switch (add->GetResultType()) { case Primitive::kPrimInt: { - locations->SetInAt(0, Location(R0)); - locations->SetInAt(1, Location(R1)); - locations->SetOut(Location(R0)); + locations->SetInAt(0, ArmCoreLocation(R0)); + locations->SetInAt(1, ArmCoreLocation(R1)); + locations->SetOut(ArmCoreLocation(R0)); + break; + } + + case Primitive::kPrimLong: { + locations->SetInAt( + 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); + locations->SetInAt( + 1, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R2_R3))); + locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); 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"; + LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); } add->SetLocations(locations); } @@ -278,13 +545,153 @@ void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { LocationSummary* locations = add->GetLocations(); switch (add->GetResultType()) { case Primitive::kPrimInt: - __ add(locations->Out().reg<Register>(), - locations->InAt(0).reg<Register>(), - ShifterOperand(locations->InAt(1).reg<Register>())); + __ add(locations->Out().AsArm().AsCoreRegister(), + locations->InAt(0).AsArm().AsCoreRegister(), + ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); + break; + + case Primitive::kPrimLong: + __ adds(locations->Out().AsArm().AsRegisterPairLow(), + locations->InAt(0).AsArm().AsRegisterPairLow(), + ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); + __ adc(locations->Out().AsArm().AsRegisterPairHigh(), + locations->InAt(0).AsArm().AsRegisterPairHigh(), + ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); + 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 LocationsBuilderARM::VisitSub(HSub* sub) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub); + switch (sub->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, ArmCoreLocation(R0)); + locations->SetInAt(1, ArmCoreLocation(R1)); + locations->SetOut(ArmCoreLocation(R0)); + break; + } + + case Primitive::kPrimLong: { + locations->SetInAt( + 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); + locations->SetInAt( + 1, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R2_R3))); + locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); + 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 InstructionCodeGeneratorARM::VisitSub(HSub* sub) { + LocationSummary* locations = sub->GetLocations(); + switch (sub->GetResultType()) { + case Primitive::kPrimInt: + __ sub(locations->Out().AsArm().AsCoreRegister(), + locations->InAt(0).AsArm().AsCoreRegister(), + ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); + break; + + case Primitive::kPrimLong: + __ subs(locations->Out().AsArm().AsRegisterPairLow(), + locations->InAt(0).AsArm().AsRegisterPairLow(), + ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); + __ sbc(locations->Out().AsArm().AsRegisterPairHigh(), + locations->InAt(0).AsArm().AsRegisterPairHigh(), + ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); 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"; + LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); + } +} + +static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 }; +static constexpr size_t kRuntimeParameterCoreRegistersLength = + arraysize(kRuntimeParameterCoreRegisters); + +class InvokeRuntimeCallingConvention : public CallingConvention<Register> { + public: + InvokeRuntimeCallingConvention() + : CallingConvention(kRuntimeParameterCoreRegisters, + kRuntimeParameterCoreRegistersLength) {} + + private: + DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); +}; + +void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); + locations->SetOut(ArmCoreLocation(R0)); + instruction->SetLocations(locations); +} + +void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { + InvokeRuntimeCallingConvention calling_convention; + LoadCurrentMethod(calling_convention.GetRegisterAt(1)); + __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); + + int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value(); + __ ldr(LR, Address(TR, offset)); + __ blx(LR); + + codegen_->RecordPcInfo(instruction->GetDexPc()); +} + +void LocationsBuilderARM::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 InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { + // Nothing to do, the parameter is already at its location. +} + +void LocationsBuilderARM::VisitNot(HNot* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); + locations->SetInAt(0, ArmCoreLocation(R0)); + locations->SetOut(ArmCoreLocation(R0)); + instruction->SetLocations(locations); +} + +void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) { + LocationSummary* locations = instruction->GetLocations(); + __ eor(locations->Out().AsArm().AsCoreRegister(), + locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1)); } } // namespace arm diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 52d6b2e641..ed35f94e2b 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -22,15 +22,47 @@ #include "utils/arm/assembler_arm.h" namespace art { +namespace arm { + +class CodeGeneratorARM; -class Assembler; -class Label; +static constexpr size_t kArmWordSize = 4; -namespace arm { +static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 }; +static constexpr RegisterPair kParameterCorePairRegisters[] = { R1_R2, R2_R3 }; +static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); + +class InvokeDexCallingConvention : public CallingConvention<Register> { + public: + InvokeDexCallingConvention() + : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {} + + RegisterPair GetRegisterPairAt(size_t argument_index) { + DCHECK_LT(argument_index + 1, GetNumberOfRegisters()); + return kParameterCorePairRegisters[argument_index]; + } + + private: + DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); +}; + +class InvokeDexCallingConventionVisitor { + public: + InvokeDexCallingConventionVisitor() : gp_index_(0) {} + + Location GetNextLocation(Primitive::Type type); + + private: + InvokeDexCallingConvention calling_convention; + uint32_t gp_index_; + + DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitor); +}; class LocationsBuilderARM : public HGraphVisitor { public: - explicit LocationsBuilderARM(HGraph* graph) : HGraphVisitor(graph) { } + explicit LocationsBuilderARM(HGraph* graph, CodeGeneratorARM* codegen) + : HGraphVisitor(graph), codegen_(codegen) {} #define DECLARE_VISIT_INSTRUCTION(name) \ virtual void Visit##name(H##name* instr); @@ -40,11 +72,12 @@ class LocationsBuilderARM : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION private: + CodeGeneratorARM* const codegen_; + InvokeDexCallingConventionVisitor parameter_visitor_; + DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM); }; -class CodeGeneratorARM; - class InstructionCodeGeneratorARM : public HGraphVisitor { public: InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen); @@ -70,7 +103,7 @@ class CodeGeneratorARM : public CodeGenerator { public: explicit CodeGeneratorARM(HGraph* graph) : CodeGenerator(graph), - location_builder_(graph), + location_builder_(graph, this), instruction_visitor_(graph, this) { } virtual ~CodeGeneratorARM() { } @@ -79,6 +112,10 @@ class CodeGeneratorARM : public CodeGenerator { virtual void Bind(Label* label) OVERRIDE; virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; + virtual size_t GetWordSize() const OVERRIDE { + return kArmWordSize; + } + virtual HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } @@ -94,6 +131,11 @@ class CodeGeneratorARM : public CodeGenerator { int32_t GetStackSlot(HLocal* local) const; private: + // Helper method to move a 32bits value between two locations. + void Move32(Location destination, Location source); + // Helper method to move a 64bits value between two locations. + void Move64(Location destination, Location source); + LocationsBuilderARM location_builder_; InstructionCodeGeneratorARM instruction_visitor_; ArmAssembler assembler_; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 7b0a087356..114263161d 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -17,6 +17,7 @@ #include "code_generator_x86.h" #include "utils/assembler.h" #include "utils/x86/assembler_x86.h" +#include "utils/x86/managed_register_x86.h" #include "mirror/array.h" #include "mirror/art_method.h" @@ -24,11 +25,20 @@ #define __ reinterpret_cast<X86Assembler*>(GetAssembler())-> namespace art { + +x86::X86ManagedRegister Location::AsX86() const { + return reg().AsX86(); +} + namespace x86 { static constexpr int kNumberOfPushedRegistersAtEntry = 1; static constexpr int kCurrentMethodStackOffset = 0; +static Location X86CpuLocation(Register reg) { + return Location::RegisterLocation(X86ManagedRegister::FromCpuRegister(reg)); +} + InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen) : HGraphVisitor(graph), assembler_(codegen->GetAssembler()), @@ -39,15 +49,20 @@ void CodeGeneratorX86::GenerateFrameEntry() { static const int kFakeReturnRegister = 8; core_spill_mask_ |= (1 << kFakeReturnRegister); - // Add the current ART method to the frame size and the return PC. - SetFrameSize(RoundUp(GetFrameSize() + 2 * kWordSize, kStackAlignment)); + SetFrameSize(RoundUp( + (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize + + kVRegSize // filler + + kX86WordSize // Art method + + kNumberOfPushedRegistersAtEntry * kX86WordSize, + kStackAlignment)); + // The return PC has already been pushed on the stack. - __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kWordSize)); - __ movl(Address(ESP, 0), EAX); + __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize)); + __ movl(Address(ESP, kCurrentMethodStackOffset), EAX); } void CodeGeneratorX86::GenerateFrameExit() { - __ addl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kWordSize)); + __ addl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize)); } void CodeGeneratorX86::Bind(Label* label) { @@ -59,21 +74,214 @@ void InstructionCodeGeneratorX86::LoadCurrentMethod(Register reg) { } int32_t CodeGeneratorX86::GetStackSlot(HLocal* local) const { - return (GetGraph()->GetMaximumNumberOfOutVRegs() + local->GetRegNumber()) * kWordSize; + 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() + kX86WordSize // 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 * kX86WordSize) + - kVRegSize // filler. + - (number_of_vregs * kVRegSize) + + (reg_number * kVRegSize); + } +} + +static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX }; +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_++; + if (index < calling_convention.GetNumberOfRegisters()) { + return X86CpuLocation(calling_convention.GetRegisterAt(index)); + } else { + return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kX86WordSize)); + } + } + + case Primitive::kPrimLong: { + uint32_t index = gp_index_; + gp_index_ += 2; + if (index + 1 < calling_convention.GetNumberOfRegisters()) { + return Location::RegisterLocation(X86ManagedRegister::FromRegisterPair( + calling_convention.GetRegisterPairAt(index))); + } else if (index + 1 == calling_convention.GetNumberOfRegisters()) { + return Location::QuickParameter(index); + } else { + return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kX86WordSize)); + } + } + + 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 CodeGeneratorX86::Move32(Location destination, Location source) { + if (source.Equals(destination)) { + return; + } + if (destination.IsRegister()) { + if (source.IsRegister()) { + __ movl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister()); + } else { + DCHECK(source.IsStackSlot()); + __ movl(destination.AsX86().AsCpuRegister(), Address(ESP, source.GetStackIndex())); + } + } else { + if (source.IsRegister()) { + __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister()); + } else { + DCHECK(source.IsStackSlot()); + __ movl(EAX, Address(ESP, source.GetStackIndex())); + __ movl(Address(ESP, destination.GetStackIndex()), EAX); + } + } +} + +void CodeGeneratorX86::Move64(Location destination, Location source) { + if (source.Equals(destination)) { + return; + } + if (destination.IsRegister()) { + if (source.IsRegister()) { + __ movl(destination.AsX86().AsRegisterPairLow(), source.AsX86().AsRegisterPairLow()); + __ movl(destination.AsX86().AsRegisterPairHigh(), source.AsX86().AsRegisterPairHigh()); + } else if (source.IsQuickParameter()) { + uint32_t argument_index = source.GetQuickParameterIndex(); + InvokeDexCallingConvention calling_convention; + __ movl(destination.AsX86().AsRegisterPairLow(), + calling_convention.GetRegisterAt(argument_index)); + __ movl(destination.AsX86().AsRegisterPairHigh(), Address(ESP, + calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize) + GetFrameSize())); + } else { + DCHECK(source.IsDoubleStackSlot()); + __ movl(destination.AsX86().AsRegisterPairLow(), Address(ESP, source.GetStackIndex())); + __ movl(destination.AsX86().AsRegisterPairHigh(), + Address(ESP, source.GetHighStackIndex(kX86WordSize))); + } + } else if (destination.IsQuickParameter()) { + InvokeDexCallingConvention calling_convention; + 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)), + source.AsX86().AsRegisterPairHigh()); + } else { + DCHECK(source.IsDoubleStackSlot()); + __ movl(calling_convention.GetRegisterAt(argument_index), + Address(ESP, source.GetStackIndex())); + __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize))); + __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize)), EAX); + } + } else { + if (source.IsRegister()) { + __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsRegisterPairLow()); + __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), + source.AsX86().AsRegisterPairHigh()); + } else if (source.IsQuickParameter()) { + InvokeDexCallingConvention calling_convention; + uint32_t argument_index = source.GetQuickParameterIndex(); + __ movl(Address(ESP, destination.GetStackIndex()), + calling_convention.GetRegisterAt(argument_index)); + __ movl(EAX, Address(ESP, + calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize) + GetFrameSize())); + __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX); + } else { + DCHECK(source.IsDoubleStackSlot()); + __ movl(EAX, Address(ESP, source.GetStackIndex())); + __ movl(Address(ESP, destination.GetStackIndex()), EAX); + __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize))); + __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX); + } + } } void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) { if (instruction->AsIntConstant() != nullptr) { - __ movl(location.reg<Register>(), Immediate(instruction->AsIntConstant()->GetValue())); + Immediate imm(instruction->AsIntConstant()->GetValue()); + if (location.IsRegister()) { + __ movl(location.AsX86().AsCpuRegister(), imm); + } else { + __ movl(Address(ESP, location.GetStackIndex()), imm); + } + } else if (instruction->AsLongConstant() != nullptr) { + int64_t value = instruction->AsLongConstant()->GetValue(); + if (location.IsRegister()) { + __ movl(location.AsX86().AsRegisterPairLow(), Immediate(Low32Bits(value))); + __ movl(location.AsX86().AsRegisterPairHigh(), Immediate(High32Bits(value))); + } else { + __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value))); + __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value))); + } } else if (instruction->AsLoadLocal() != nullptr) { - __ movl(location.reg<Register>(), - Address(ESP, GetStackSlot(instruction->AsLoadLocal()->GetLocal()))); + switch (instruction->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + Move32(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal()))); + break; + + case Primitive::kPrimLong: + Move64(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); - __ movl(location.reg<Register>(), - instruction->GetLocations()->Out().reg<Register>()); + switch (instruction->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + Move32(location, instruction->GetLocations()->Out()); + break; + + case Primitive::kPrimLong: + Move64(location, instruction->GetLocations()->Out()); + break; + + default: + LOG(FATAL) << "Unimplemented type " << instruction->GetType(); + } } } @@ -103,13 +311,13 @@ void InstructionCodeGeneratorX86::VisitExit(HExit* exit) { void LocationsBuilderX86::VisitIf(HIf* if_instr) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr); - locations->SetInAt(0, Location(EAX)); + locations->SetInAt(0, X86CpuLocation(EAX)); if_instr->SetLocations(locations); } void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) { // TODO: Generate the input as a condition, instead of materializing in a register. - __ cmpl(if_instr->GetLocations()->InAt(0).reg<Register>(), Immediate(0)); + __ cmpl(if_instr->GetLocations()->InAt(0).AsX86().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())); @@ -122,7 +330,6 @@ void LocationsBuilderX86::VisitLocal(HLocal* local) { void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) { DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); - codegen_->SetFrameSize(codegen_->GetFrameSize() + kWordSize); } void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) { @@ -133,29 +340,43 @@ void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) { // Nothing to do, this is driven by the code generator. } -void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* local) { - LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(local); - locations->SetInAt(1, Location(EAX)); - local->SetLocations(locations); +void LocationsBuilderX86::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::VisitStoreLocal(HStoreLocal* store) { - __ movl(Address(ESP, codegen_->GetStackSlot(store->GetLocal())), - store->GetLocations()->InAt(1).reg<Register>()); } void LocationsBuilderX86::VisitEqual(HEqual* equal) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal); - locations->SetInAt(0, Location(EAX)); - locations->SetInAt(1, Location(ECX)); - locations->SetOut(Location(EAX)); + locations->SetInAt(0, X86CpuLocation(EAX)); + locations->SetInAt(1, X86CpuLocation(ECX)); + locations->SetOut(X86CpuLocation(EAX)); equal->SetLocations(locations); } void InstructionCodeGeneratorX86::VisitEqual(HEqual* equal) { - __ cmpl(equal->GetLocations()->InAt(0).reg<Register>(), - equal->GetLocations()->InAt(1).reg<Register>()); - __ setb(kEqual, equal->GetLocations()->Out().reg<Register>()); + __ cmpl(equal->GetLocations()->InAt(0).AsX86().AsCpuRegister(), + equal->GetLocations()->InAt(1).AsX86().AsCpuRegister()); + __ setb(kEqual, equal->GetLocations()->Out().AsX86().AsCpuRegister()); } void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) { @@ -166,6 +387,14 @@ void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) { // Will be generated at use site. } +void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) { + constant->SetLocations(nullptr); +} + +void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) { + // Will be generated at use site. +} + void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) { ret->SetLocations(nullptr); } @@ -177,66 +406,91 @@ void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) { void LocationsBuilderX86::VisitReturn(HReturn* ret) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret); - locations->SetInAt(0, Location(EAX)); + switch (ret->InputAt(0)->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + locations->SetInAt(0, X86CpuLocation(EAX)); + break; + + case Primitive::kPrimLong: + locations->SetInAt( + 0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX))); + break; + + default: + LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); + } ret->SetLocations(locations); } void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) { - DCHECK_EQ(ret->GetLocations()->InAt(0).reg<Register>(), EAX); + 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: + DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsCpuRegister(), EAX); + break; + + case Primitive::kPrimLong: + DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsRegisterPair(), EAX_EDX); + break; + + default: + LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); + } + } codegen_->GenerateFrameExit(); __ ret(); } -static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX }; -static constexpr int kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); +void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); + locations->AddTemp(X86CpuLocation(EAX)); -class InvokeStaticCallingConvention : public CallingConvention<Register> { - public: - InvokeStaticCallingConvention() - : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {} + InvokeDexCallingConventionVisitor calling_convention_visitor; + for (int i = 0; i < invoke->InputCount(); i++) { + HInstruction* input = invoke->InputAt(i); + locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); + } - private: - DISALLOW_COPY_AND_ASSIGN(InvokeStaticCallingConvention); -}; + switch (invoke->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + locations->SetOut(X86CpuLocation(EAX)); + break; -void LocationsBuilderX86::VisitPushArgument(HPushArgument* argument) { - LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument); - InvokeStaticCallingConvention calling_convention; - if (argument->GetArgumentIndex() < calling_convention.GetNumberOfRegisters()) { - Location location = Location(calling_convention.GetRegisterAt(argument->GetArgumentIndex())); - locations->SetInAt(0, location); - locations->SetOut(location); - } else { - locations->SetInAt(0, Location(EAX)); - } - argument->SetLocations(locations); -} + case Primitive::kPrimLong: + locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX))); + break; -void InstructionCodeGeneratorX86::VisitPushArgument(HPushArgument* argument) { - uint8_t argument_index = argument->GetArgumentIndex(); - InvokeStaticCallingConvention calling_convention; - size_t parameter_registers = calling_convention.GetNumberOfRegisters(); - if (argument_index >= parameter_registers) { - uint8_t offset = calling_convention.GetStackOffsetOf(argument_index); - __ movl(Address(ESP, offset), - argument->GetLocations()->InAt(0).reg<Register>()); + case Primitive::kPrimVoid: + break; - } else { - DCHECK_EQ(argument->GetLocations()->Out().reg<Register>(), - argument->GetLocations()->InAt(0).reg<Register>()); + case Primitive::kPrimDouble: + case Primitive::kPrimFloat: + LOG(FATAL) << "Unimplemented return type " << invoke->GetType(); + break; } -} -void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) { - LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); - locations->AddTemp(Location(EAX)); invoke->SetLocations(locations); } void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) { - Register temp = invoke->GetLocations()->GetTemp(0).reg<Register>(); + Register temp = invoke->GetLocations()->GetTemp(0).AsX86().AsCpuRegister(); size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + - invoke->GetIndexInDexCache() * kWordSize; + invoke->GetIndexInDexCache() * kX86WordSize; // TODO: Implement all kinds of calls: // 1) boot -> boot @@ -261,13 +515,29 @@ void LocationsBuilderX86::VisitAdd(HAdd* add) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add); switch (add->GetResultType()) { case Primitive::kPrimInt: { - locations->SetInAt(0, Location(EAX)); - locations->SetInAt(1, Location(ECX)); - locations->SetOut(Location(EAX)); + locations->SetInAt(0, X86CpuLocation(EAX)); + locations->SetInAt(1, X86CpuLocation(ECX)); + locations->SetOut(X86CpuLocation(EAX)); + break; + } + case Primitive::kPrimLong: { + locations->SetInAt( + 0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX))); + locations->SetInAt( + 1, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(ECX_EBX))); + locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX))); 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"; + LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); } add->SetLocations(locations); } @@ -275,13 +545,146 @@ void LocationsBuilderX86::VisitAdd(HAdd* add) { void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { LocationSummary* locations = add->GetLocations(); switch (add->GetResultType()) { - case Primitive::kPrimInt: - DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>()); - __ addl(locations->InAt(0).reg<Register>(), locations->InAt(1).reg<Register>()); + case Primitive::kPrimInt: { + DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(), + locations->Out().AsX86().AsCpuRegister()); + __ addl(locations->InAt(0).AsX86().AsCpuRegister(), + locations->InAt(1).AsX86().AsCpuRegister()); + break; + } + + case Primitive::kPrimLong: { + DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(), + locations->Out().AsX86().AsRegisterPair()); + __ addl(locations->InAt(0).AsX86().AsRegisterPairLow(), + locations->InAt(1).AsX86().AsRegisterPairLow()); + __ adcl(locations->InAt(0).AsX86().AsRegisterPairHigh(), + locations->InAt(1).AsX86().AsRegisterPairHigh()); + 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::VisitSub(HSub* sub) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub); + switch (sub->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, X86CpuLocation(EAX)); + locations->SetInAt(1, X86CpuLocation(ECX)); + locations->SetOut(X86CpuLocation(EAX)); break; + } + + case Primitive::kPrimLong: { + locations->SetInAt( + 0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX))); + locations->SetInAt( + 1, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(ECX_EBX))); + locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX))); + 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"; + LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); } + sub->SetLocations(locations); +} + +void InstructionCodeGeneratorX86::VisitSub(HSub* sub) { + LocationSummary* locations = sub->GetLocations(); + switch (sub->GetResultType()) { + case Primitive::kPrimInt: { + DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(), + locations->Out().AsX86().AsCpuRegister()); + __ subl(locations->InAt(0).AsX86().AsCpuRegister(), + locations->InAt(1).AsX86().AsCpuRegister()); + break; + } + + case Primitive::kPrimLong: { + DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(), + locations->Out().AsX86().AsRegisterPair()); + __ subl(locations->InAt(0).AsX86().AsRegisterPairLow(), + locations->InAt(1).AsX86().AsRegisterPairLow()); + __ sbbl(locations->InAt(0).AsX86().AsRegisterPairHigh(), + locations->InAt(1).AsX86().AsRegisterPairHigh()); + 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::VisitNewInstance(HNewInstance* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); + locations->SetOut(X86CpuLocation(EAX)); + instruction->SetLocations(locations); +} + +void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) { + InvokeRuntimeCallingConvention calling_convention; + LoadCurrentMethod(calling_convention.GetRegisterAt(1)); + __ movl(calling_convention.GetRegisterAt(0), + Immediate(instruction->GetTypeIndex())); + + __ fs()->call( + Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocObjectWithAccessCheck))); + + codegen_->RecordPcInfo(instruction->GetDexPc()); +} + +void LocationsBuilderX86::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::VisitParameterValue(HParameterValue* instruction) { + // Nothing to do, the parameter is already at its location. +} + +void LocationsBuilderX86::VisitNot(HNot* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); + locations->SetInAt(0, X86CpuLocation(EAX)); + locations->SetOut(X86CpuLocation(EAX)); + instruction->SetLocations(locations); +} + +void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) { + LocationSummary* locations = instruction->GetLocations(); + DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(), locations->Out().AsX86().AsCpuRegister()); + __ xorl(locations->Out().AsX86().AsCpuRegister(), Immediate(1)); } } // namespace x86 diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index dd5044f4dc..f22890e708 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -22,12 +22,47 @@ #include "utils/x86/assembler_x86.h" namespace art { - namespace x86 { +static constexpr size_t kX86WordSize = 4; + +class CodeGeneratorX86; + +static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX }; +static constexpr RegisterPair kParameterCorePairRegisters[] = { ECX_EDX, EDX_EBX }; +static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); + +class InvokeDexCallingConvention : public CallingConvention<Register> { + public: + InvokeDexCallingConvention() + : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {} + + RegisterPair GetRegisterPairAt(size_t argument_index) { + DCHECK_LT(argument_index + 1, GetNumberOfRegisters()); + return kParameterCorePairRegisters[argument_index]; + } + + private: + DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); +}; + +class InvokeDexCallingConventionVisitor { + public: + InvokeDexCallingConventionVisitor() : gp_index_(0) {} + + Location GetNextLocation(Primitive::Type type); + + private: + InvokeDexCallingConvention calling_convention; + uint32_t gp_index_; + + DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitor); +}; + class LocationsBuilderX86 : public HGraphVisitor { public: - explicit LocationsBuilderX86(HGraph* graph) : HGraphVisitor(graph) { } + LocationsBuilderX86(HGraph* graph, CodeGeneratorX86* codegen) + : HGraphVisitor(graph), codegen_(codegen) {} #define DECLARE_VISIT_INSTRUCTION(name) \ virtual void Visit##name(H##name* instr); @@ -37,11 +72,12 @@ class LocationsBuilderX86 : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION private: + CodeGeneratorX86* const codegen_; + InvokeDexCallingConventionVisitor parameter_visitor_; + DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86); }; -class CodeGeneratorX86; - class InstructionCodeGeneratorX86 : public HGraphVisitor { public: InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen); @@ -68,7 +104,7 @@ class CodeGeneratorX86 : public CodeGenerator { public: explicit CodeGeneratorX86(HGraph* graph) : CodeGenerator(graph), - location_builder_(graph), + location_builder_(graph, this), instruction_visitor_(graph, this) { } virtual ~CodeGeneratorX86() { } @@ -77,6 +113,10 @@ class CodeGeneratorX86 : public CodeGenerator { virtual void Bind(Label* label) OVERRIDE; virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; + virtual size_t GetWordSize() const OVERRIDE { + return kX86WordSize; + } + virtual HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } @@ -92,6 +132,11 @@ class CodeGeneratorX86 : public CodeGenerator { int32_t GetStackSlot(HLocal* local) const; private: + // Helper method to move a 32bits value between two locations. + void Move32(Location destination, Location source); + // Helper method to move a 64bits value between two locations. + void Move64(Location destination, Location source); + LocationsBuilderX86 location_builder_; InstructionCodeGeneratorX86 instruction_visitor_; X86Assembler assembler_; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 2b21905224..3da9ed9461 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -42,6 +42,8 @@ class HGraph : public ArenaObject { blocks_(arena, kDefaultNumberOfBlocks), dominator_order_(arena, kDefaultNumberOfBlocks), maximum_number_of_out_vregs_(0), + number_of_vregs_(0), + number_of_in_vregs_(0), current_instruction_id_(0) { } ArenaAllocator* GetArena() const { return arena_; } @@ -68,6 +70,23 @@ class HGraph : public ArenaObject { maximum_number_of_out_vregs_ = std::max(new_value, maximum_number_of_out_vregs_); } + void SetNumberOfVRegs(uint16_t number_of_vregs) { + number_of_vregs_ = number_of_vregs; + } + + uint16_t GetNumberOfVRegs() const { + return number_of_vregs_; + } + + void SetNumberOfInVRegs(uint16_t value) { + number_of_in_vregs_ = value; + } + + uint16_t GetNumberOfInVRegs() const { + return number_of_in_vregs_; + } + + private: HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const; void VisitBlockForDominatorTree(HBasicBlock* block, @@ -90,9 +109,15 @@ class HGraph : public ArenaObject { HBasicBlock* entry_block_; HBasicBlock* exit_block_; - // The maximum number of arguments passed to a HInvoke in this graph. + // The maximum number of virtual registers arguments passed to a HInvoke in this graph. uint16_t maximum_number_of_out_vregs_; + // The number of virtual registers in this method. Contains the parameters. + uint16_t number_of_vregs_; + + // The number of virtual registers used by parameters of this method. + uint16_t number_of_in_vregs_; + // The current id to assign to a newly added instruction. See HInstruction.id_. int current_instruction_id_; @@ -201,10 +226,14 @@ class HBasicBlock : public ArenaObject { M(InvokeStatic) \ M(LoadLocal) \ M(Local) \ - M(PushArgument) \ + M(LongConstant) \ + M(NewInstance) \ + M(Not) \ + M(ParameterValue) \ M(Return) \ M(ReturnVoid) \ M(StoreLocal) \ + M(Sub) \ #define FORWARD_DECLARATION(type) class H##type; FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) @@ -254,6 +283,8 @@ class HInstruction : public ArenaObject { virtual void Accept(HGraphVisitor* visitor) = 0; virtual const char* DebugName() const = 0; + virtual Primitive::Type GetType() const { return Primitive::kPrimVoid; } + void AddUse(HInstruction* user) { uses_ = new (block_->GetGraph()->GetArena()) HUseListNode(user, uses_); } @@ -505,6 +536,7 @@ class HBinaryOperation : public HTemplateInstruction<2> { Primitive::Type GetResultType() const { return result_type_; } virtual bool IsCommutative() { return false; } + virtual Primitive::Type GetType() const { return GetResultType(); } private: const Primitive::Type result_type_; @@ -521,6 +553,8 @@ class HEqual : public HBinaryOperation { virtual bool IsCommutative() { return true; } + virtual Primitive::Type GetType() const { return Primitive::kPrimBoolean; } + DECLARE_INSTRUCTION(Equal) private: @@ -546,15 +580,19 @@ class HLocal : public HTemplateInstruction<0> { // Load a given local. The local is an input of this instruction. class HLoadLocal : public HTemplateInstruction<1> { public: - explicit HLoadLocal(HLocal* local) { + explicit HLoadLocal(HLocal* local, Primitive::Type type) : type_(type) { SetRawInputAt(0, local); } + virtual Primitive::Type GetType() const { return type_; } + HLocal* GetLocal() const { return reinterpret_cast<HLocal*>(InputAt(0)); } DECLARE_INSTRUCTION(LoadLocal) private: + const Primitive::Type type_; + DISALLOW_COPY_AND_ASSIGN(HLoadLocal); }; @@ -582,6 +620,7 @@ class HIntConstant : public HTemplateInstruction<0> { explicit HIntConstant(int32_t value) : value_(value) { } int32_t GetValue() const { return value_; } + virtual Primitive::Type GetType() const { return Primitive::kPrimInt; } DECLARE_INSTRUCTION(IntConstant) @@ -591,10 +630,30 @@ class HIntConstant : public HTemplateInstruction<0> { DISALLOW_COPY_AND_ASSIGN(HIntConstant); }; +class HLongConstant : public HTemplateInstruction<0> { + public: + explicit HLongConstant(int64_t value) : value_(value) { } + + int64_t GetValue() const { return value_; } + + virtual Primitive::Type GetType() const { return Primitive::kPrimLong; } + + DECLARE_INSTRUCTION(LongConstant) + + private: + const int64_t value_; + + DISALLOW_COPY_AND_ASSIGN(HLongConstant); +}; + class HInvoke : public HInstruction { public: - HInvoke(ArenaAllocator* arena, uint32_t number_of_arguments, int32_t dex_pc) + HInvoke(ArenaAllocator* arena, + uint32_t number_of_arguments, + Primitive::Type return_type, + uint32_t dex_pc) : inputs_(arena, number_of_arguments), + return_type_(return_type), dex_pc_(dex_pc) { inputs_.SetSize(number_of_arguments); } @@ -606,11 +665,14 @@ class HInvoke : public HInstruction { inputs_.Put(index, argument); } - int32_t GetDexPc() const { return dex_pc_; } + virtual Primitive::Type GetType() const { return return_type_; } + + uint32_t GetDexPc() const { return dex_pc_; } protected: GrowableArray<HInstruction*> inputs_; - const int32_t dex_pc_; + const Primitive::Type return_type_; + const uint32_t dex_pc_; private: DISALLOW_COPY_AND_ASSIGN(HInvoke); @@ -620,9 +682,11 @@ class HInvokeStatic : public HInvoke { public: HInvokeStatic(ArenaAllocator* arena, uint32_t number_of_arguments, - int32_t dex_pc, - int32_t index_in_dex_cache) - : HInvoke(arena, number_of_arguments, dex_pc), index_in_dex_cache_(index_in_dex_cache) {} + Primitive::Type return_type, + uint32_t dex_pc, + uint32_t index_in_dex_cache) + : HInvoke(arena, number_of_arguments, return_type, dex_pc), + index_in_dex_cache_(index_in_dex_cache) {} uint32_t GetIndexInDexCache() const { return index_in_dex_cache_; } @@ -634,22 +698,22 @@ class HInvokeStatic : public HInvoke { DISALLOW_COPY_AND_ASSIGN(HInvokeStatic); }; -// HPushArgument nodes are inserted after the evaluation of an argument -// of a call. Their mere purpose is to ease the code generator's work. -class HPushArgument : public HTemplateInstruction<1> { +class HNewInstance : public HTemplateInstruction<0> { public: - HPushArgument(HInstruction* argument, uint8_t argument_index) : argument_index_(argument_index) { - SetRawInputAt(0, argument); - } + HNewInstance(uint32_t dex_pc, uint16_t type_index) : dex_pc_(dex_pc), type_index_(type_index) {} + + uint32_t GetDexPc() const { return dex_pc_; } + uint16_t GetTypeIndex() const { return type_index_; } - uint8_t GetArgumentIndex() const { return argument_index_; } + virtual Primitive::Type GetType() const { return Primitive::kPrimNot; } - DECLARE_INSTRUCTION(PushArgument) + DECLARE_INSTRUCTION(NewInstance) private: - const uint8_t argument_index_; + const uint32_t dex_pc_; + const uint16_t type_index_; - DISALLOW_COPY_AND_ASSIGN(HPushArgument); + DISALLOW_COPY_AND_ASSIGN(HNewInstance); }; class HAdd : public HBinaryOperation { @@ -665,6 +729,56 @@ class HAdd : public HBinaryOperation { DISALLOW_COPY_AND_ASSIGN(HAdd); }; +class HSub : public HBinaryOperation { + public: + HSub(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + virtual bool IsCommutative() { return false; } + + DECLARE_INSTRUCTION(Sub); + + private: + DISALLOW_COPY_AND_ASSIGN(HSub); +}; + +// The value of a parameter in this method. Its location depends on +// the calling convention. +class HParameterValue : public HTemplateInstruction<0> { + public: + HParameterValue(uint8_t index, Primitive::Type parameter_type) + : index_(index), parameter_type_(parameter_type) {} + + uint8_t GetIndex() const { return index_; } + + virtual Primitive::Type GetType() const { return parameter_type_; } + + DECLARE_INSTRUCTION(ParameterValue); + + private: + // The index of this parameter in the parameters list. Must be less + // than HGraph::number_of_in_vregs_; + const uint8_t index_; + + const Primitive::Type parameter_type_; + + DISALLOW_COPY_AND_ASSIGN(HParameterValue); +}; + +class HNot : public HTemplateInstruction<1> { + public: + explicit HNot(HInstruction* input) { + SetRawInputAt(0, input); + } + + virtual Primitive::Type GetType() const { return Primitive::kPrimBoolean; } + + DECLARE_INSTRUCTION(Not); + + private: + DISALLOW_COPY_AND_ASSIGN(HNot); +}; + class HGraphVisitor : public ValueObject { public: explicit HGraphVisitor(HGraph* graph) : graph_(graph) { } |