Opt compiler: Add arm64 support for a few more IRs.
Change-Id: I781ddcbc61eb2b04ae80b1c7697e1ed5694bd5b9
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index c57c68c..4dc836f 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -392,51 +392,6 @@
__ Bind(GetLabelOf(block));
}
-void CodeGeneratorARM64::MoveHelper(Location destination,
- Location source,
- Primitive::Type type) {
- if (source.Equals(destination)) {
- return;
- }
- if (destination.IsRegister()) {
- Register dst = RegisterFrom(destination, type);
- if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
- DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
- __ Ldr(dst, StackOperandFrom(source));
- } else {
- __ Mov(dst, OperandFrom(source, type));
- }
- } else if (destination.IsFpuRegister()) {
- FPRegister dst = FPRegisterFrom(destination, type);
- if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
- DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
- __ Ldr(dst, StackOperandFrom(source));
- } else if (source.IsFpuRegister()) {
- __ Fmov(dst, FPRegisterFrom(source, type));
- } else {
- HConstant* cst = source.GetConstant();
- if (cst->IsFloatConstant()) {
- __ Fmov(dst, cst->AsFloatConstant()->GetValue());
- } else {
- DCHECK(cst->IsDoubleConstant());
- __ Fmov(dst, cst->AsDoubleConstant()->GetValue());
- }
- }
- } else {
- DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
- if (source.IsRegister()) {
- __ Str(RegisterFrom(source, type), StackOperandFrom(destination));
- } else if (source.IsFpuRegister()) {
- __ Str(FPRegisterFrom(source, type), StackOperandFrom(destination));
- } else {
- UseScratchRegisterScope temps(assembler_.vixl_masm_);
- Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW();
- __ Ldr(temp, StackOperandFrom(source));
- __ Str(temp, StackOperandFrom(destination));
- }
- }
-}
-
void CodeGeneratorARM64::Move(HInstruction* instruction,
Location location,
HInstruction* move_for) {
@@ -567,8 +522,107 @@
stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
}
+void CodeGeneratorARM64::MoveHelper(Location destination,
+ Location source,
+ Primitive::Type type) {
+ if (source.Equals(destination)) {
+ return;
+ }
+ if (destination.IsRegister()) {
+ Register dst = RegisterFrom(destination, type);
+ if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
+ DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
+ __ Ldr(dst, StackOperandFrom(source));
+ } else {
+ __ Mov(dst, OperandFrom(source, type));
+ }
+ } else if (destination.IsFpuRegister()) {
+ FPRegister dst = FPRegisterFrom(destination, type);
+ if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
+ DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
+ __ Ldr(dst, StackOperandFrom(source));
+ } else if (source.IsFpuRegister()) {
+ __ Fmov(dst, FPRegisterFrom(source, type));
+ } else {
+ HConstant* cst = source.GetConstant();
+ if (cst->IsFloatConstant()) {
+ __ Fmov(dst, cst->AsFloatConstant()->GetValue());
+ } else {
+ DCHECK(cst->IsDoubleConstant());
+ __ Fmov(dst, cst->AsDoubleConstant()->GetValue());
+ }
+ }
+ } else {
+ DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
+ if (source.IsRegister()) {
+ __ Str(RegisterFrom(source, type), StackOperandFrom(destination));
+ } else if (source.IsFpuRegister()) {
+ __ Str(FPRegisterFrom(source, type), StackOperandFrom(destination));
+ } else {
+ UseScratchRegisterScope temps(assembler_.vixl_masm_);
+ Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW();
+ __ Ldr(temp, StackOperandFrom(source));
+ __ Str(temp, StackOperandFrom(destination));
+ }
+ }
+}
+
+void CodeGeneratorARM64::Load(Primitive::Type type,
+ vixl::Register dst,
+ const vixl::MemOperand& src) {
+ switch (type) {
+ case Primitive::kPrimBoolean:
+ __ Ldrb(dst, src);
+ break;
+ case Primitive::kPrimByte:
+ __ Ldrsb(dst, src);
+ break;
+ case Primitive::kPrimShort:
+ __ Ldrsh(dst, src);
+ break;
+ case Primitive::kPrimChar:
+ __ Ldrh(dst, src);
+ break;
+ case Primitive::kPrimInt:
+ case Primitive::kPrimNot:
+ case Primitive::kPrimLong:
+ DCHECK(dst.Is64Bits() == (type == Primitive::kPrimLong));
+ __ Ldr(dst, src);
+ break;
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable type " << type;
+ }
+}
+
+void CodeGeneratorARM64::Store(Primitive::Type type,
+ vixl::Register rt,
+ const vixl::MemOperand& dst) {
+ switch (type) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ __ Strb(rt, dst);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ __ Strh(rt, dst);
+ break;
+ case Primitive::kPrimInt:
+ case Primitive::kPrimNot:
+ case Primitive::kPrimLong:
+ DCHECK(rt.Is64Bits() == (type == Primitive::kPrimLong));
+ __ Str(rt, dst);
+ break;
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable type " << type;
+ }
+}
+
#undef __
-#define __ assembler_->vixl_masm_->
+#define __ GetAssembler()->vixl_masm_->
InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
CodeGeneratorARM64* codegen)
@@ -577,17 +631,12 @@
codegen_(codegen) {}
#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
- M(ArrayGet) \
- M(ArraySet) \
M(ClinitCheck) \
- M(Div) \
M(DivZeroCheck) \
M(InvokeInterface) \
M(LoadClass) \
M(LoadException) \
M(LoadString) \
- M(Neg) \
- M(NewArray) \
M(ParallelMove) \
M(StaticFieldGet) \
M(StaticFieldSet) \
@@ -685,6 +734,37 @@
HandleAddSub(instruction);
}
+void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Primitive::Type type = instruction->GetType();
+ Register obj = InputRegisterAt(instruction, 0);
+ Register out = OutputRegister(instruction);
+ Location index = locations->InAt(1);
+ size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
+ MemOperand source(obj);
+ UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
+
+ if (index.IsConstant()) {
+ offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
+ source = MemOperand(obj, offset);
+ } else {
+ Register temp = temps.AcquireSameSizeAs(obj);
+ Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
+ __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
+ source = MemOperand(temp, offset);
+ }
+
+ codegen_->Load(type, out, source);
+}
+
void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
locations->SetInAt(0, Location::RequiresRegister());
@@ -696,6 +776,53 @@
HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
}
+void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
+ Primitive::Type value_type = instruction->GetComponentType();
+ bool is_object = value_type == Primitive::kPrimNot;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+ instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
+ if (is_object) {
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
+ locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
+ locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
+ } else {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ locations->SetInAt(2, Location::RequiresRegister());
+ }
+}
+
+void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
+ Primitive::Type value_type = instruction->GetComponentType();
+ if (value_type == Primitive::kPrimNot) {
+ __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAputObject).Int32Value()));
+ __ Blr(lr);
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+ DCHECK(!codegen_->IsLeafMethod());
+ } else {
+ LocationSummary* locations = instruction->GetLocations();
+ Register obj = InputRegisterAt(instruction, 0);
+ Register value = InputRegisterAt(instruction, 2);
+ Location index = locations->InAt(1);
+ size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
+ MemOperand destination(obj);
+ UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
+
+ if (index.IsConstant()) {
+ offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
+ destination = MemOperand(obj, offset);
+ } else {
+ Register temp = temps.AcquireSameSizeAs(obj);
+ Register index_reg = InputRegisterAt(instruction, 1);
+ __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
+ destination = MemOperand(temp, offset);
+ }
+
+ codegen_->Store(value_type, value, destination);
+ }
+}
+
void LocationsBuilderARM64::VisitCompare(HCompare* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
@@ -763,6 +890,47 @@
FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
#undef FOR_EACH_CONDITION_INSTRUCTION
+void LocationsBuilderARM64::VisitDiv(HDiv* div) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
+ switch (div->GetResultType()) {
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ break;
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected div type " << div->GetResultType();
+ }
+}
+
+void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
+ Primitive::Type type = div->GetResultType();
+ switch (type) {
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
+ break;
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected div type " << type;
+ }
+}
+
void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
@@ -863,44 +1031,9 @@
}
void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
- Primitive::Type res_type = instruction->GetType();
- Register res = OutputRegister(instruction);
- Register obj = InputRegisterAt(instruction, 0);
- uint32_t offset = instruction->GetFieldOffset().Uint32Value();
-
- switch (res_type) {
- case Primitive::kPrimBoolean: {
- __ Ldrb(res, MemOperand(obj, offset));
- break;
- }
- case Primitive::kPrimByte: {
- __ Ldrsb(res, MemOperand(obj, offset));
- break;
- }
- case Primitive::kPrimShort: {
- __ Ldrsh(res, MemOperand(obj, offset));
- break;
- }
- case Primitive::kPrimChar: {
- __ Ldrh(res, MemOperand(obj, offset));
- break;
- }
- case Primitive::kPrimInt:
- case Primitive::kPrimNot:
- case Primitive::kPrimLong: { // TODO: support volatile.
- DCHECK(res.IsX() == (res_type == Primitive::kPrimLong));
- __ Ldr(res, MemOperand(obj, offset));
- break;
- }
-
- case Primitive::kPrimFloat:
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Unimplemented register res_type " << res_type;
- break;
-
- case Primitive::kPrimVoid:
- LOG(FATAL) << "Unreachable res_type " << res_type;
- }
+ MemOperand field = MemOperand(InputRegisterAt(instruction, 0),
+ instruction->GetFieldOffset().Uint32Value());
+ codegen_->Load(instruction->GetType(), OutputRegister(instruction), field);
}
void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
@@ -910,43 +1043,12 @@
}
void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
- Register obj = InputRegisterAt(instruction, 0);
+ Primitive::Type field_type = instruction->GetFieldType();
Register value = InputRegisterAt(instruction, 1);
- Primitive::Type field_type = instruction->InputAt(1)->GetType();
- uint32_t offset = instruction->GetFieldOffset().Uint32Value();
-
- switch (field_type) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte: {
- __ Strb(value, MemOperand(obj, offset));
- break;
- }
-
- case Primitive::kPrimShort:
- case Primitive::kPrimChar: {
- __ Strh(value, MemOperand(obj, offset));
- break;
- }
-
- case Primitive::kPrimInt:
- case Primitive::kPrimNot:
- case Primitive::kPrimLong: {
- DCHECK(value.IsX() == (field_type == Primitive::kPrimLong));
- __ Str(value, MemOperand(obj, offset));
-
- if (field_type == Primitive::kPrimNot) {
- codegen_->MarkGCCard(obj, value);
- }
- break;
- }
-
- case Primitive::kPrimFloat:
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Unimplemented register type " << field_type;
- break;
-
- case Primitive::kPrimVoid:
- LOG(FATAL) << "Unreachable type " << field_type;
+ Register obj = InputRegisterAt(instruction, 0);
+ codegen_->Store(field_type, value, MemOperand(obj, instruction->GetFieldOffset().Uint32Value()));
+ if (field_type == Primitive::kPrimNot) {
+ codegen_->MarkGCCard(obj, value);
}
}
@@ -1002,11 +1104,13 @@
// temp = method;
__ Ldr(temp, MemOperand(sp, kCurrentMethodStackOffset));
// temp = temp->dex_cache_resolved_methods_;
- __ Ldr(temp, MemOperand(temp.X(), mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
+ __ Ldr(temp, MemOperand(temp.X(),
+ mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
// temp = temp[index_in_cache];
__ Ldr(temp, MemOperand(temp.X(), index_in_cache));
// lr = temp->entry_point_from_quick_compiled_code_;
- __ Ldr(lr, MemOperand(temp.X(), mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
+ __ Ldr(lr, MemOperand(temp.X(),
+ mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
// lr();
__ Blr(lr);
@@ -1109,6 +1213,71 @@
}
}
+void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
+ switch (neg->GetResultType()) {
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong: {
+ locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
+ locations->SetOut(Location::RequiresRegister());
+ break;
+ }
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+ }
+}
+
+void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
+ switch (neg->GetResultType()) {
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
+ break;
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+ }
+}
+
+void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
+ locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
+ locations->SetOut(LocationFrom(x0));
+ locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(2)));
+}
+
+void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ InvokeRuntimeCallingConvention calling_convention;
+ Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
+ DCHECK(type_index.Is(w0));
+ Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
+ DCHECK(current_method.Is(w1));
+ __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
+ __ Mov(type_index, instruction->GetTypeIndex());
+ int32_t quick_entrypoint_offset =
+ QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocArrayWithAccessCheck).Int32Value();
+ __ Ldr(lr, MemOperand(tr, quick_entrypoint_offset));
+ __ Blr(lr);
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+ DCHECK(!codegen_->IsLeafMethod());
+}
+
void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
@@ -1126,7 +1295,9 @@
DCHECK(current_method.Is(w1));
__ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
__ Mov(type_index, instruction->GetTypeIndex());
- __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocObjectWithAccessCheck).Int32Value()));
+ int32_t quick_entrypoint_offset =
+ QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocObjectWithAccessCheck).Int32Value();
+ __ Ldr(lr, MemOperand(tr, quick_entrypoint_offset));
__ Blr(lr);
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
DCHECK(!codegen_->IsLeafMethod());
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index ad1f221..f2ead21 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -216,8 +216,6 @@
return InstructionSet::kArm64;
}
- void MoveHelper(Location destination, Location source, Primitive::Type type);
-
void Initialize() OVERRIDE {
HGraph* graph = GetGraph();
int length = graph->GetBlocks().Size();
@@ -227,6 +225,11 @@
}
}
+ // Code generation helpers.
+ void MoveHelper(Location destination, Location source, Primitive::Type type);
+ void Load(Primitive::Type type, vixl::Register dst, const vixl::MemOperand& src);
+ void Store(Primitive::Type type, vixl::Register rt, const vixl::MemOperand& dst);
+
private:
// Labels for each block that will be compiled.
vixl::Label* block_labels_;