summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Geoffray <ngeoffray@google.com>2014-04-11 17:43:50 +0100
committerNicolas Geoffray <ngeoffray@google.com>2014-04-16 14:21:12 +0100
commit01bc96d007b67fdb7fe349232a83e4b354ce3d08 (patch)
tree1ed36c2d7c0fb204e6f276bd9853153d9350ad1d
parent2be6fc74bce10ac68d3d1b39a5019f520ad170ea (diff)
downloadart-01bc96d007b67fdb7fe349232a83e4b354ce3d08.zip
art-01bc96d007b67fdb7fe349232a83e4b354ce3d08.tar.gz
art-01bc96d007b67fdb7fe349232a83e4b354ce3d08.tar.bz2
Long support in optimizing compiler.
- Add stack locations to the Location class. - Change logic of parameter passing/setup by setting the location of such instructions the ones for the calling convention. Change-Id: I4730ad58732813dcb9c238f44f55dfc0baa18799
-rw-r--r--build/Android.gtest.mk1
-rw-r--r--compiler/optimizing/builder.cc260
-rw-r--r--compiler/optimizing/builder.h42
-rw-r--r--compiler/optimizing/code_generator.h151
-rw-r--r--compiler/optimizing/code_generator_arm.cc497
-rw-r--r--compiler/optimizing/code_generator_arm.h16
-rw-r--r--compiler/optimizing/code_generator_x86.cc503
-rw-r--r--compiler/optimizing/code_generator_x86.h16
-rw-r--r--compiler/optimizing/nodes.h53
-rw-r--r--compiler/utils/managed_register.h4
-rw-r--r--compiler/utils/x86/managed_register_x86.cc3
-rw-r--r--compiler/utils/x86/managed_register_x86.h9
-rw-r--r--runtime/base/bit_field.h82
-rw-r--r--runtime/base/bit_field_test.cc37
-rw-r--r--test/403-optimizing-long/expected.txt1
-rw-r--r--test/403-optimizing-long/info.txt1
-rw-r--r--test/403-optimizing-long/src/Main.java115
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;
+ }
+}