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