diff options
-rw-r--r-- | build/Android.gtest.mk | 1 | ||||
-rw-r--r-- | compiler/optimizing/builder.cc | 260 | ||||
-rw-r--r-- | compiler/optimizing/builder.h | 42 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.h | 151 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 497 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.h | 16 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 503 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.h | 16 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 53 | ||||
-rw-r--r-- | compiler/utils/managed_register.h | 4 | ||||
-rw-r--r-- | compiler/utils/x86/managed_register_x86.cc | 3 | ||||
-rw-r--r-- | compiler/utils/x86/managed_register_x86.h | 9 | ||||
-rw-r--r-- | runtime/base/bit_field.h | 82 | ||||
-rw-r--r-- | runtime/base/bit_field_test.cc | 37 | ||||
-rw-r--r-- | test/403-optimizing-long/expected.txt | 1 | ||||
-rw-r--r-- | test/403-optimizing-long/info.txt | 1 | ||||
-rw-r--r-- | test/403-optimizing-long/src/Main.java | 115 |
17 files changed, 1505 insertions, 286 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index ef5819d..1f8f799 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -18,6 +18,7 @@ LOCAL_PATH := art RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/barrier_test.cc \ + runtime/base/bit_field_test.cc \ runtime/base/bit_vector_test.cc \ runtime/base/hex_dump_test.cc \ runtime/base/histogram_test.cc \ diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index beccf01..637cf17 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -48,7 +48,8 @@ bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) { if (!dex_compilation_unit_->IsStatic()) { // Add the implicit 'this' argument, not expressed in the signature. - HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++); + 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)); @@ -59,19 +60,24 @@ bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) { for (int i = 0; i < number_of_parameters; i++) { switch (shorty[pos++]) { case 'F': - case 'D': - case 'J': { + case 'D': { return false; } default: { // integer and reference parameters. - HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++); + 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; } } @@ -88,8 +94,8 @@ static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) { template<typename T> void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not) { - HInstruction* first = LoadLocal(instruction.VRegA()); - HInstruction* second = LoadLocal(instruction.VRegB()); + 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())); @@ -205,25 +211,25 @@ HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const { } template<typename T> -void HGraphBuilder::Binop_32x(const Instruction& instruction) { - HInstruction* first = LoadLocal(instruction.VRegB()); - HInstruction* second = LoadLocal(instruction.VRegC()); - current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second)); +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) { - HInstruction* first = LoadLocal(instruction.VRegA()); - HInstruction* second = LoadLocal(instruction.VRegB()); - current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second)); +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()); - HInstruction* second = GetConstant(instruction.VRegC_22s()); + HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + HInstruction* second = GetIntConstant(instruction.VRegC_22s()); if (reverse) { std::swap(first, second); } @@ -233,8 +239,8 @@ void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) { template<typename T> void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) { - HInstruction* first = LoadLocal(instruction.VRegB()); - HInstruction* second = GetConstant(instruction.VRegC_22b()); + HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + HInstruction* second = GetIntConstant(instruction.VRegC_22b()); if (reverse) { std::swap(first, second); } @@ -242,6 +248,78 @@ void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) { 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); + HInstruction* push = new (arena_) HPushArgument(arg, 0); + current_block_->AddInstruction(push); + invoke->SetArgumentAt(0, push); + 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); + HInstruction* push = new (arena_) HPushArgument(arg, i); + current_block_->AddInstruction(push); + invoke->SetArgumentAt(argument_index, push); + 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 @@ -250,28 +328,47 @@ 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 = GetConstant(instruction.VRegB_21s()); + 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()); + 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; } @@ -296,88 +393,82 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ break; } - case Instruction::RETURN: + case Instruction::RETURN: { + BuildReturn(instruction, Primitive::kPrimInt); + break; + } + case Instruction::RETURN_OBJECT: { - HInstruction* value = LoadLocal(instruction.VRegA()); - current_block_->AddInstruction(new (arena_) HReturn(value)); - current_block_->AddSuccessor(exit_block_); - current_block_ = nullptr; + BuildReturn(instruction, Primitive::kPrimNot); + break; + } + + case Instruction::RETURN_WIDE: { + BuildReturn(instruction, Primitive::kPrimLong); break; } case Instruction::INVOKE_STATIC: case Instruction::INVOKE_DIRECT: { 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; - } - - // Treat invoke-direct like static calls for now. - HInvokeStatic* invoke = new (arena_) HInvokeStatic( - arena_, number_of_arguments, dex_offset, method_idx); - + 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_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; } - - // Treat invoke-direct like static calls for now. - 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: { - Binop_32x<HAdd>(instruction); + 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); + Binop_32x<HSub>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SUB_LONG: { + Binop_32x<HSub>(instruction, Primitive::kPrimLong); break; } case Instruction::ADD_INT_2ADDR: { - Binop_12x<HAdd>(instruction); + 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); + Binop_12x<HSub>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SUB_LONG_2ADDR: { + Binop_12x<HSub>(instruction, Primitive::kPrimLong); break; } @@ -408,6 +499,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ break; } + case Instruction::MOVE_RESULT_WIDE: { + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + break; + } + case Instruction::NOP: break; @@ -417,7 +513,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ return true; } -HIntConstant* HGraphBuilder::GetConstant0() { +HIntConstant* HGraphBuilder::GetIntConstant0() { if (constant0_ != nullptr) { return constant0_; } @@ -426,7 +522,7 @@ HIntConstant* HGraphBuilder::GetConstant0() { return constant0_; } -HIntConstant* HGraphBuilder::GetConstant1() { +HIntConstant* HGraphBuilder::GetIntConstant1() { if (constant1_ != nullptr) { return constant1_; } @@ -435,10 +531,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); @@ -447,6 +543,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); } @@ -456,9 +558,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 60d9982..108514a 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,24 +65,44 @@ class HGraphBuilder : public ValueObject { void MaybeUpdateCurrentBlock(size_t index); HBasicBlock* FindBlockStartingAt(int32_t index) const; - HIntConstant* GetConstant0(); - HIntConstant* GetConstant1(); - HIntConstant* GetConstant(int constant); + 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); - template<typename T> void Binop_12x(const Instruction& instruction); - 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 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_; // A list of the size of the dex code holding block information for @@ -99,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.h b/compiler/optimizing/code_generator.h index 6648598..d459dd5 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" @@ -49,30 +50,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() : reg_(kInvalid) { } - explicit Location(uword reg) : reg_(reg) { } + Location(const Location& other) : ValueObject(), value_(other.value_) {} - static Location RegisterLocation(uword reg) { - return Location(reg); + Location& operator=(const Location& other) { + value_ = other.value_; + return *this; } - bool IsValid() const { return reg_ != kInvalid; } + bool IsValid() const { + return value_ != kInvalid; + } - Location(const Location& other) : reg_(other.reg_) { } + // Register locations. + static Location RegisterLocation(ManagedRegister reg) { + return Location(kRegister, reg.RegId()); + } - Location& operator=(const Location& other) { - reg_ = other.reg_; - return *this; + bool IsRegister() const { + return GetKind() == kRegister; + } + + ManagedRegister reg() const { + DCHECK(IsRegister()); + return static_cast<ManagedRegister>(GetPayload()); + } + + 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_; }; /** @@ -204,7 +324,6 @@ class CallingConvention { } uint8_t GetStackOffsetOf(size_t index) const { - DCHECK_GE(index, number_of_registers_); // We still reserve the space for parameters passed by registers. // Add kWordSize for the method pointer. return index * kWordSize + kWordSize; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 4e88765..fe61333 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()), @@ -73,18 +83,171 @@ int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const { } } +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); +}; + +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) + 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))); + } 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))); + } + } 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) + 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(); + } } } @@ -114,13 +277,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())); @@ -129,18 +292,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) { @@ -161,14 +324,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) { @@ -179,6 +355,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); } @@ -189,56 +373,118 @@ 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 size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); - -class InvokeDexCallingConvention : public CallingConvention<Register> { - public: - InvokeDexCallingConvention() - : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {} - - private: - DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); -}; - void LocationsBuilderARM::VisitPushArgument(HPushArgument* argument) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument); InvokeDexCallingConvention 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)); + uint32_t argument_index = argument->GetArgumentIndex(); + switch (argument->InputAt(0)->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: { + if (argument_index < calling_convention.GetNumberOfRegisters()) { + locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(argument_index))); + } else { + locations->SetInAt( + 0, Location::StackSlot(calling_convention.GetStackOffsetOf(argument_index))); + } + break; + } + case Primitive::kPrimLong: { + if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) { + Location location = Location::RegisterLocation(ArmManagedRegister::FromRegisterPair( + calling_convention.GetRegisterPairAt(argument_index))); + locations->SetInAt(0, location); + } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) { + locations->SetInAt(0, Location::QuickParameter(argument_index)); + } else { + locations->SetInAt( + 0, Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(argument_index))); + } + break; + } + default: + LOG(FATAL) << "Unimplemented argument type " << argument->InputAt(0)->GetType(); } argument->SetLocations(locations); } void InstructionCodeGeneratorARM::VisitPushArgument(HPushArgument* argument) { - uint8_t argument_index = argument->GetArgumentIndex(); - InvokeDexCallingConvention 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>()); - } + // Nothing to do. } void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); - locations->AddTemp(Location(R0)); + locations->AddTemp(ArmCoreLocation(R0)); + 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; + + case Primitive::kPrimLong: + locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); + break; + + case Primitive::kPrimVoid: + break; + + case Primitive::kPrimDouble: + case Primitive::kPrimFloat: + LOG(FATAL) << "Unimplemented return type " << invoke->GetType(); + break; + } + invoke->SetLocations(locations); } @@ -247,7 +493,7 @@ 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() * kArmWordSize; @@ -277,13 +523,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); } @@ -292,12 +555,29 @@ 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"; + LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); } } @@ -305,13 +585,30 @@ void LocationsBuilderARM::VisitSub(HSub* sub) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub); switch (sub->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 sub type " << sub->GetResultType(); + break; + default: - LOG(FATAL) << "Unimplemented"; + LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); } sub->SetLocations(locations); } @@ -320,12 +617,29 @@ void InstructionCodeGeneratorARM::VisitSub(HSub* sub) { LocationSummary* locations = sub->GetLocations(); switch (sub->GetResultType()) { case Primitive::kPrimInt: - __ sub(locations->Out().reg<Register>(), - locations->InAt(0).reg<Register>(), - ShifterOperand(locations->InAt(1).reg<Register>())); + __ 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(); } } @@ -345,7 +659,7 @@ class InvokeRuntimeCallingConvention : public CallingConvention<Register> { void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); - locations->SetOut(Location(R0)); + locations->SetOut(ArmCoreLocation(R0)); instruction->SetLocations(locations); } @@ -365,34 +679,55 @@ void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); InvokeDexCallingConvention calling_convention; uint32_t argument_index = instruction->GetIndex(); - if (argument_index < calling_convention.GetNumberOfRegisters()) { - locations->SetOut(Location(calling_convention.GetRegisterAt(argument_index))); - } else { - locations->SetOut(Location(R0)); + switch (instruction->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + if (argument_index < calling_convention.GetNumberOfRegisters()) { + locations->SetOut(ArmCoreLocation(calling_convention.GetRegisterAt(argument_index))); + } else { + locations->SetOut(Location::StackSlot( + calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize())); + } + break; + + case Primitive::kPrimLong: + if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) { + locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair( + (calling_convention.GetRegisterPairAt(argument_index))))); + } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) { + // Spanning a register and a stack slot. Use the quick parameter kind. + locations->SetOut(Location::QuickParameter(argument_index)); + } else { + locations->SetOut(Location::DoubleStackSlot( + calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize())); + } + break; + + default: + LOG(FATAL) << "Unimplemented parameter type " << instruction->GetType(); } instruction->SetLocations(locations); } void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { - LocationSummary* locations = instruction->GetLocations(); - InvokeDexCallingConvention calling_convention; - uint8_t argument_index = instruction->GetIndex(); - if (argument_index >= calling_convention.GetNumberOfRegisters()) { - uint8_t offset = calling_convention.GetStackOffsetOf(argument_index); - __ ldr(locations->Out().reg<Register>(), Address(SP, offset + codegen_->GetFrameSize())); - } + // 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, Location(R0)); - locations->SetOut(Location(R0)); + locations->SetInAt(0, ArmCoreLocation(R0)); + locations->SetOut(ArmCoreLocation(R0)); instruction->SetLocations(locations); } void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) { LocationSummary* locations = instruction->GetLocations(); - __ eor(locations->Out().reg<Register>(), locations->InAt(0).reg<Register>(), ShifterOperand(1)); + __ 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 a51d85e..3fbe631 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -24,11 +24,14 @@ namespace art { namespace arm { +class CodeGeneratorARM; + static constexpr size_t kArmWordSize = 4; 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); @@ -38,11 +41,11 @@ class LocationsBuilderARM : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION private: + CodeGeneratorARM* const codegen_; + DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM); }; -class CodeGeneratorARM; - class InstructionCodeGeneratorARM : public HGraphVisitor { public: InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen); @@ -68,7 +71,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() { } @@ -96,6 +99,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 88198dc..7507ee7 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()), @@ -77,18 +87,163 @@ int32_t CodeGeneratorX86::GetStackSlot(HLocal* local) const { } } +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); +}; + +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) + 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)), + 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)), 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) + 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(); + } } } @@ -118,13 +273,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())); @@ -147,29 +302,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) { @@ -180,6 +349,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); } @@ -191,28 +368,51 @@ 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 size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); - -class InvokeDexCallingConvention : public CallingConvention<Register> { - public: - InvokeDexCallingConvention() - : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {} - - private: - DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); -}; - static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX }; static constexpr size_t kRuntimeParameterCoreRegistersLength = arraysize(kRuntimeParameterCoreRegisters); @@ -230,39 +430,78 @@ class InvokeRuntimeCallingConvention : public CallingConvention<Register> { void LocationsBuilderX86::VisitPushArgument(HPushArgument* argument) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument); InvokeDexCallingConvention 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)); + uint32_t argument_index = argument->GetArgumentIndex(); + switch (argument->InputAt(0)->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: { + if (argument_index < calling_convention.GetNumberOfRegisters()) { + locations->SetInAt( + 0, X86CpuLocation(calling_convention.GetRegisterAt(argument->GetArgumentIndex()))); + } else { + locations->SetInAt( + 0, Location::StackSlot(calling_convention.GetStackOffsetOf(argument_index))); + } + break; + } + case Primitive::kPrimLong: { + if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) { + Location location = Location::RegisterLocation(X86ManagedRegister::FromRegisterPair( + calling_convention.GetRegisterPairAt(argument_index))); + locations->SetInAt(0, location); + } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) { + locations->SetInAt(0, Location::QuickParameter(argument_index)); + } else { + locations->SetInAt( + 0, Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(argument_index))); + } + break; + } + default: + LOG(FATAL) << "Unimplemented argument type " << argument->InputAt(0)->GetType(); } + argument->SetLocations(locations); } void InstructionCodeGeneratorX86::VisitPushArgument(HPushArgument* argument) { - uint8_t argument_index = argument->GetArgumentIndex(); - InvokeDexCallingConvention 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>()); - - } else { - DCHECK_EQ(argument->GetLocations()->Out().reg<Register>(), - argument->GetLocations()->InAt(0).reg<Register>()); - } + // Nothing to do. } void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); - locations->AddTemp(Location(EAX)); + locations->AddTemp(X86CpuLocation(EAX)); + 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; + + case Primitive::kPrimLong: + locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX))); + break; + + case Primitive::kPrimVoid: + break; + + case Primitive::kPrimDouble: + case Primitive::kPrimFloat: + LOG(FATAL) << "Unimplemented return type " << invoke->GetType(); + break; + } + 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() * kX86WordSize; @@ -289,13 +528,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); } @@ -303,12 +558,33 @@ 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"; + LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); } } @@ -316,13 +592,30 @@ void LocationsBuilderX86::VisitSub(HSub* sub) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub); switch (sub->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 sub type " << sub->GetResultType(); + break; + default: - LOG(FATAL) << "Unimplemented"; + LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); } sub->SetLocations(locations); } @@ -330,18 +623,39 @@ void LocationsBuilderX86::VisitSub(HSub* sub) { void InstructionCodeGeneratorX86::VisitSub(HSub* sub) { LocationSummary* locations = sub->GetLocations(); switch (sub->GetResultType()) { - case Primitive::kPrimInt: - DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>()); - __ subl(locations->InAt(0).reg<Register>(), locations->InAt(1).reg<Register>()); + 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"; + LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); } } void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); - locations->SetOut(Location(EAX)); + locations->SetOut(X86CpuLocation(EAX)); instruction->SetLocations(locations); } @@ -361,35 +675,54 @@ void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); InvokeDexCallingConvention calling_convention; uint32_t argument_index = instruction->GetIndex(); - if (argument_index < calling_convention.GetNumberOfRegisters()) { - locations->SetOut(Location(calling_convention.GetRegisterAt(argument_index))); - } else { - locations->SetOut(Location(EAX)); + switch (instruction->GetType()) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: + if (argument_index < calling_convention.GetNumberOfRegisters()) { + locations->SetOut(X86CpuLocation(calling_convention.GetRegisterAt(argument_index))); + } else { + locations->SetOut(Location::StackSlot( + calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize())); + } + break; + + case Primitive::kPrimLong: + if (argument_index + 1 < calling_convention.GetNumberOfRegisters()) { + locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair( + (calling_convention.GetRegisterPairAt(argument_index))))); + } else if (argument_index + 1 == calling_convention.GetNumberOfRegisters()) { + locations->SetOut(Location::QuickParameter(argument_index)); + } else { + locations->SetOut(Location::DoubleStackSlot( + calling_convention.GetStackOffsetOf(argument_index) + codegen_->GetFrameSize())); + } + break; + + default: + LOG(FATAL) << "Unimplemented parameter type " << instruction->GetType(); } instruction->SetLocations(locations); } void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) { - LocationSummary* locations = instruction->GetLocations(); - InvokeDexCallingConvention calling_convention; - uint32_t argument_index = instruction->GetIndex(); - if (argument_index >= calling_convention.GetNumberOfRegisters()) { - uint8_t offset = calling_convention.GetStackOffsetOf(argument_index); - __ movl(locations->Out().reg<Register>(), Address(ESP, offset + codegen_->GetFrameSize())); - } + // 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, Location(EAX)); - locations->SetOut(Location(EAX)); + 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).reg<Register>(), locations->Out().reg<Register>()); - __ xorl(locations->Out().reg<Register>(), Immediate(1)); + 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 bba81c0..9108f80 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -26,9 +26,12 @@ namespace x86 { static constexpr size_t kX86WordSize = 4; +class CodeGeneratorX86; + 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); @@ -38,11 +41,11 @@ class LocationsBuilderX86 : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION private: + CodeGeneratorX86* const codegen_; + DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86); }; -class CodeGeneratorX86; - class InstructionCodeGeneratorX86 : public HGraphVisitor { public: InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen); @@ -69,7 +72,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() { } @@ -97,6 +100,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 adea0ba..d7e74f8 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -226,6 +226,7 @@ class HBasicBlock : public ArenaObject { M(InvokeStatic) \ M(LoadLocal) \ M(Local) \ + M(LongConstant) \ M(NewInstance) \ M(Not) \ M(ParameterValue) \ @@ -283,6 +284,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_); } @@ -534,6 +537,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_; @@ -550,6 +554,8 @@ class HEqual : public HBinaryOperation { virtual bool IsCommutative() { return true; } + virtual Primitive::Type GetType() const { return Primitive::kPrimBoolean; } + DECLARE_INSTRUCTION(Equal) private: @@ -575,15 +581,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); }; @@ -611,6 +621,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) @@ -620,10 +631,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, uint32_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); } @@ -635,10 +666,13 @@ class HInvoke : public HInstruction { inputs_.Put(index, argument); } + virtual Primitive::Type GetType() const { return return_type_; } + uint32_t GetDexPc() const { return dex_pc_; } protected: GrowableArray<HInstruction*> inputs_; + const Primitive::Type return_type_; const uint32_t dex_pc_; private: @@ -649,9 +683,11 @@ class HInvokeStatic : public HInvoke { public: HInvokeStatic(ArenaAllocator* arena, uint32_t number_of_arguments, + Primitive::Type return_type, uint32_t dex_pc, uint32_t index_in_dex_cache) - : HInvoke(arena, number_of_arguments, dex_pc), index_in_dex_cache_(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_; } @@ -670,6 +706,8 @@ class HNewInstance : public HTemplateInstruction<0> { uint32_t GetDexPc() const { return dex_pc_; } uint16_t GetTypeIndex() const { return type_index_; } + virtual Primitive::Type GetType() const { return Primitive::kPrimNot; } + DECLARE_INSTRUCTION(NewInstance) private: @@ -727,10 +765,13 @@ class HSub : public HBinaryOperation { // the calling convention. class HParameterValue : public HTemplateInstruction<0> { public: - explicit HParameterValue(uint8_t index) : index_(index) {} + 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: @@ -738,6 +779,8 @@ class HParameterValue : public HTemplateInstruction<0> { // than HGraph::number_of_in_vregs_; const uint8_t index_; + const Primitive::Type parameter_type_; + DISALLOW_COPY_AND_ASSIGN(HParameterValue); }; @@ -747,6 +790,8 @@ class HNot : public HTemplateInstruction<1> { SetRawInputAt(0, input); } + virtual Primitive::Type GetType() const { return Primitive::kPrimBoolean; } + DECLARE_INSTRUCTION(Not); private: diff --git a/compiler/utils/managed_register.h b/compiler/utils/managed_register.h index f007d28..0d31322 100644 --- a/compiler/utils/managed_register.h +++ b/compiler/utils/managed_register.h @@ -70,11 +70,13 @@ class ManagedRegister { return ManagedRegister(); } + int RegId() const { return id_; } + explicit ManagedRegister(int reg_id) : id_(reg_id) { } + protected: static const int kNoRegister = -1; ManagedRegister() : id_(kNoRegister) { } - explicit ManagedRegister(int reg_id) : id_(reg_id) { } int id_; }; diff --git a/compiler/utils/x86/managed_register_x86.cc b/compiler/utils/x86/managed_register_x86.cc index 7fae7a8..034a795 100644 --- a/compiler/utils/x86/managed_register_x86.cc +++ b/compiler/utils/x86/managed_register_x86.cc @@ -33,7 +33,8 @@ namespace x86 { P(EDX, EDI) \ P(ECX, EBX) \ P(ECX, EDI) \ - P(EBX, EDI) + P(EBX, EDI) \ + P(ECX, EDX) struct RegisterPairDescriptor { diff --git a/compiler/utils/x86/managed_register_x86.h b/compiler/utils/x86/managed_register_x86.h index 0201a96..09d2b49 100644 --- a/compiler/utils/x86/managed_register_x86.h +++ b/compiler/utils/x86/managed_register_x86.h @@ -37,7 +37,8 @@ enum RegisterPair { ECX_EBX = 7, ECX_EDI = 8, EBX_EDI = 9, - kNumberOfRegisterPairs = 10, + ECX_EDX = 10, // Dalvik style passing + kNumberOfRegisterPairs = 11, kNoRegisterPair = -1, }; @@ -121,6 +122,12 @@ class X86ManagedRegister : public ManagedRegister { return FromRegId(AllocIdHigh()).AsCpuRegister(); } + RegisterPair AsRegisterPair() const { + CHECK(IsRegisterPair()); + return static_cast<RegisterPair>(id_ - + (kNumberOfCpuRegIds + kNumberOfXmmRegIds + kNumberOfX87RegIds)); + } + bool IsCpuRegister() const { CHECK(IsValidManagedRegister()); return (0 <= id_) && (id_ < kNumberOfCpuRegIds); diff --git a/runtime/base/bit_field.h b/runtime/base/bit_field.h new file mode 100644 index 0000000..e041bd0 --- /dev/null +++ b/runtime/base/bit_field.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_BASE_BIT_FIELD_H_ +#define ART_RUNTIME_BASE_BIT_FIELD_H_ + +#include "globals.h" +#include "logging.h" + +namespace art { + +static const uword kUwordOne = 1U; + +// BitField is a template for encoding and decoding a bit field inside +// an unsigned machine word. +template<typename T, int position, int size> +class BitField { + public: + // Tells whether the provided value fits into the bit field. + static bool IsValid(T value) { + return (static_cast<uword>(value) & ~((kUwordOne << size) - 1)) == 0; + } + + // Returns a uword mask of the bit field. + static uword Mask() { + return (kUwordOne << size) - 1; + } + + // Returns a uword mask of the bit field which can be applied directly to + // the raw unshifted bits. + static uword MaskInPlace() { + return ((kUwordOne << size) - 1) << position; + } + + // Returns the shift count needed to right-shift the bit field to + // the least-significant bits. + static int Shift() { + return position; + } + + // Returns the size of the bit field. + static int BitSize() { + return size; + } + + // Returns a uword with the bit field value encoded. + static uword Encode(T value) { + DCHECK(IsValid(value)); + return static_cast<uword>(value) << position; + } + + // Extracts the bit field from the value. + static T Decode(uword value) { + return static_cast<T>((value >> position) & ((kUwordOne << size) - 1)); + } + + // Returns a uword with the bit field value encoded based on the + // original value. Only the bits corresponding to this bit field + // will be changed. + static uword Update(T value, uword original) { + DCHECK(IsValid(value)); + return (static_cast<uword>(value) << position) | + (~MaskInPlace() & original); + } +}; + +} // namespace art + +#endif // ART_RUNTIME_BASE_BIT_FIELD_H_ diff --git a/runtime/base/bit_field_test.cc b/runtime/base/bit_field_test.cc new file mode 100644 index 0000000..afeb2c4 --- /dev/null +++ b/runtime/base/bit_field_test.cc @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bit_field.h" +#include "globals.h" + +#include "gtest/gtest.h" + +namespace art { + +TEST(BitFields, Test1) { + class TestBitFields : public BitField<int32_t, 1, 8> {}; + ASSERT_TRUE(TestBitFields::IsValid(16)); + ASSERT_TRUE(!TestBitFields::IsValid(256)); + ASSERT_EQ(0x00ffU, TestBitFields::Mask()); + ASSERT_EQ(0x001feU, TestBitFields::MaskInPlace()); + ASSERT_EQ(1, TestBitFields::Shift()); + ASSERT_EQ(8, TestBitFields::BitSize()); + ASSERT_EQ(32U, TestBitFields::Encode(16)); + ASSERT_EQ(16, TestBitFields::Decode(32)); + ASSERT_EQ(2U, TestBitFields::Update(1, 16)); +} + +} // namespace art diff --git a/test/403-optimizing-long/expected.txt b/test/403-optimizing-long/expected.txt new file mode 100644 index 0000000..dff83cf --- /dev/null +++ b/test/403-optimizing-long/expected.txt @@ -0,0 +1 @@ +Long: 42 diff --git a/test/403-optimizing-long/info.txt b/test/403-optimizing-long/info.txt new file mode 100644 index 0000000..dc2d668 --- /dev/null +++ b/test/403-optimizing-long/info.txt @@ -0,0 +1 @@ +Tests long support on optimizing compiler. diff --git a/test/403-optimizing-long/src/Main.java b/test/403-optimizing-long/src/Main.java new file mode 100644 index 0000000..21af4e1 --- /dev/null +++ b/test/403-optimizing-long/src/Main.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Note that $opt$ is a marker for the optimizing compiler to ensure +// it does compile the method. + +public class Main { + public static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void main(String[] args) { + long l = $opt$ReturnLong(); + expectEquals(42, l); + System.out.println("Long: " + l); + + l = $opt$TakeOneLong1(42); + expectEquals(42, l); + + l = $opt$TakeOneLong2(0, 42); + expectEquals(42, l); + + l = $opt$TakeOneLong3(0, 1, 42); + expectEquals(42, l); + + l = $opt$TakeOneLong4(0, 1, 2, 42); + expectEquals(42, l); + + l = $opt$AddTwoLongs(42, 41); + expectEquals(83, l); + + l = $opt$SubTwoLongs(42, 41); + expectEquals(1, l); + + l = $opt$MakeCallsWithLongs1(); + expectEquals(57, l); + + l = $opt$MakeCallsWithLongs2(); + expectEquals(900000000006L, l); + + l = $opt$SubTwoLongs(-600000000006L, -200000000002L); + expectEquals(-400000000004L, l); + + l = $opt$AddTwoLongs(-600000000006L, -200000000002L); + expectEquals(-800000000008L, l); + } + + static long $opt$MakeCallsWithLongs1() { + long l = $opt$SubTwoLongs(-600000000006L, -200000000002L); + expectEquals(-400000000004L, l); + + l = $opt$AddTwoLongs(-600000000006L, -200000000002L); + expectEquals(-800000000008L, l); + + return $opt$ReturnLong() + $opt$TakeOneLong1(1) + $opt$TakeOneLong2(0, 2) + + $opt$TakeOneLong3(0, 0, 3) + $opt$TakeOneLong4(0, 0, 0, 4) + // Test invoke-range. + + $opt$TakeOneLong5(0, 0, 0, 0, 5); + } + + static long $opt$MakeCallsWithLongs2() { + return $opt$AddThreeLongs(400000000003L, 200000000002L, 300000000001L); + } + + static long $opt$ReturnLong() { + return 42; + } + + static long $opt$TakeOneLong1(long l) { + return l; + } + + static long $opt$TakeOneLong2(int a, long l) { + return l; + } + + static long $opt$TakeOneLong3(int a, int b, long l) { + return l; + } + + static long $opt$TakeOneLong4(int a, int b, int c, long l) { + return l; + } + + static long $opt$TakeOneLong5(int a, int b, int c,int d, long l) { + return l; + } + + static long $opt$AddTwoLongs(long a, long b) { + return a + b; + } + + static long $opt$AddThreeLongs(long a, long b, long c) { + return a + b + c; + } + + static long $opt$SubTwoLongs(long a, long b) { + return a - b; + } +} |