Opt compiler: Add support for more IRs on arm64.
Change-Id: I4b6425135d1af74912a206411288081d2516f8bf
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 1debaa5..39543a2 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -80,7 +80,7 @@
public:
explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
__ Bind(GetEntryLabel());
arm_codegen->InvokeRuntime(
@@ -96,7 +96,7 @@
public:
explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
__ Bind(GetEntryLabel());
arm_codegen->InvokeRuntime(
@@ -112,7 +112,7 @@
public:
StackOverflowCheckSlowPathARM() {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
__ Bind(GetEntryLabel());
__ LoadFromOffset(kLoadWord, PC, TR,
QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
@@ -124,10 +124,10 @@
class SuspendCheckSlowPathARM : public SlowPathCodeARM {
public:
- explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
+ SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
: instruction_(instruction), successor_(successor) {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
__ Bind(GetEntryLabel());
codegen->SaveLiveRegisters(instruction_->GetLocations());
@@ -166,7 +166,7 @@
index_location_(index_location),
length_location_(length_location) {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
__ Bind(GetEntryLabel());
// We're moving two locations to locations that could overlap, so we need a parallel
@@ -199,7 +199,7 @@
DCHECK(at->IsLoadClass() || at->IsClinitCheck());
}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
LocationSummary* locations = at_->GetLocations();
CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
@@ -245,7 +245,7 @@
public:
explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
LocationSummary* locations = instruction_->GetLocations();
DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
@@ -281,7 +281,7 @@
object_class_(object_class),
dex_pc_(dex_pc) {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
LocationSummary* locations = instruction_->GetLocations();
DCHECK(instruction_->IsCheckCast()
|| !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 5432882..fc9bdba 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -48,18 +48,28 @@
return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble;
}
+bool IsIntegralType(Primitive::Type type) {
+ switch (type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool Is64BitType(Primitive::Type type) {
return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
}
// Convenience helpers to ease conversion to and from VIXL operands.
+static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32),
+ "Unexpected values for register codes.");
int VIXLRegCodeFromART(int code) {
- // TODO: static check?
- DCHECK_EQ(SP, 31);
- DCHECK_EQ(WSP, 31);
- DCHECK_EQ(XZR, 32);
- DCHECK_EQ(WZR, 32);
if (code == SP) {
return vixl::kSPRegInternalCode;
}
@@ -70,11 +80,6 @@
}
int ARTRegCodeFromVIXL(int code) {
- // TODO: static check?
- DCHECK_EQ(SP, 31);
- DCHECK_EQ(WSP, 31);
- DCHECK_EQ(XZR, 32);
- DCHECK_EQ(WZR, 32);
if (code == vixl::kSPRegInternalCode) {
return SP;
}
@@ -128,6 +133,17 @@
instr->InputAt(input_index)->GetType());
}
+CPURegister OutputCPURegister(HInstruction* instr) {
+ return IsFPType(instr->GetType()) ? static_cast<CPURegister>(OutputFPRegister(instr))
+ : static_cast<CPURegister>(OutputRegister(instr));
+}
+
+CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
+ return IsFPType(instr->InputAt(index)->GetType())
+ ? static_cast<CPURegister>(InputFPRegisterAt(instr, index))
+ : static_cast<CPURegister>(InputRegisterAt(instr, index));
+}
+
int64_t Int64ConstantFrom(Location location) {
HConstant* instr = location.GetConstant();
return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue()
@@ -151,14 +167,18 @@
return MemOperand(sp, location.GetStackIndex());
}
-MemOperand HeapOperand(const Register& base, Offset offset) {
+MemOperand HeapOperand(const Register& base, size_t offset) {
// A heap reference must be 32bit, so fit in a W register.
DCHECK(base.IsW());
- return MemOperand(base.X(), offset.SizeValue());
+ return MemOperand(base.X(), offset);
}
-MemOperand HeapOperandFrom(Location location, Primitive::Type type, Offset offset) {
- return HeapOperand(RegisterFrom(location, type), offset);
+MemOperand HeapOperand(const Register& base, Offset offset) {
+ return HeapOperand(base, offset.SizeValue());
+}
+
+MemOperand HeapOperandFrom(Location location, Offset offset) {
+ return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset);
}
Location LocationFrom(const Register& reg) {
@@ -227,7 +247,8 @@
return ARM64ReturnLocation(return_type);
}
-#define __ reinterpret_cast<Arm64Assembler*>(codegen->GetAssembler())->vixl_masm_->
+#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
+#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
class SlowPathCodeARM64 : public SlowPathCode {
public:
@@ -245,45 +266,125 @@
class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
public:
- explicit BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
- Location index_location,
- Location length_location)
- : instruction_(instruction),
- index_location_(index_location),
- length_location_(length_location) {}
+ BoundsCheckSlowPathARM64() {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
- CodeGeneratorARM64* arm64_codegen = reinterpret_cast<CodeGeneratorARM64*>(codegen);
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
__ Bind(GetEntryLabel());
- InvokeRuntimeCallingConvention calling_convention;
- arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(0)),
- index_location_, Primitive::kPrimInt);
- arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(1)),
- length_location_, Primitive::kPrimInt);
- size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowArrayBounds).SizeValue();
- __ Ldr(lr, MemOperand(tr, offset));
- __ Blr(lr);
- codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+ __ Brk(__LINE__); // TODO: Unimplemented BoundsCheckSlowPathARM64.
}
private:
- HBoundsCheck* const instruction_;
- const Location index_location_;
- const Location length_location_;
-
DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
};
+class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+ explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+ __ Bind(GetEntryLabel());
+ arm64_codegen->InvokeRuntime(
+ QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
+ }
+
+ private:
+ HDivZeroCheck* const instruction_;
+ DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
+};
+
+class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+ LoadClassSlowPathARM64(HLoadClass* cls,
+ HInstruction* at,
+ uint32_t dex_pc,
+ bool do_clinit)
+ : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+ DCHECK(at->IsLoadClass() || at->IsClinitCheck());
+ }
+
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ LocationSummary* locations = at_->GetLocations();
+ CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+
+ __ Bind(GetEntryLabel());
+ codegen->SaveLiveRegisters(locations);
+
+ InvokeRuntimeCallingConvention calling_convention;
+ __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
+ arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
+ int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
+ : QUICK_ENTRY_POINT(pInitializeType);
+ arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
+
+ // Move the class to the desired location.
+ Location out = locations->Out();
+ if (out.IsValid()) {
+ DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
+ Primitive::Type type = at_->GetType();
+ arm64_codegen->MoveHelper(out, calling_convention.GetReturnLocation(type), type);
+ }
+
+ codegen->RestoreLiveRegisters(locations);
+ __ B(GetExitLabel());
+ }
+
+ private:
+ // The class this slow path will load.
+ HLoadClass* const cls_;
+
+ // The instruction where this slow path is happening.
+ // (Might be the load class or an initialization check).
+ HInstruction* const at_;
+
+ // The dex PC of `at_`.
+ const uint32_t dex_pc_;
+
+ // Whether to initialize the class.
+ const bool do_clinit_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
+};
+
+class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+ explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {}
+
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ LocationSummary* locations = instruction_->GetLocations();
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+ CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+
+ __ Bind(GetEntryLabel());
+ codegen->SaveLiveRegisters(locations);
+
+ InvokeRuntimeCallingConvention calling_convention;
+ arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0).W());
+ __ Mov(calling_convention.GetRegisterAt(1).W(), instruction_->GetStringIndex());
+ arm64_codegen->InvokeRuntime(
+ QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
+ Primitive::Type type = instruction_->GetType();
+ arm64_codegen->MoveHelper(locations->Out(), calling_convention.GetReturnLocation(type), type);
+
+ codegen->RestoreLiveRegisters(locations);
+ __ B(GetExitLabel());
+ }
+
+ private:
+ HLoadString* const instruction_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
+};
+
class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
public:
explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
__ Bind(GetEntryLabel());
- int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowNullPointer).Int32Value();
- __ Ldr(lr, MemOperand(tr, offset));
- __ Blr(lr);
- codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+ arm64_codegen->InvokeRuntime(
+ QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
}
private:
@@ -298,13 +399,18 @@
HBasicBlock* successor)
: instruction_(instruction), successor_(successor) {}
- virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
- size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pTestSuspend).SizeValue();
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
__ Bind(GetEntryLabel());
- __ Ldr(lr, MemOperand(tr, offset));
- __ Blr(lr);
- codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
- __ B(GetReturnLabel());
+ codegen->SaveLiveRegisters(instruction_->GetLocations());
+ arm64_codegen->InvokeRuntime(
+ QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
+ codegen->RestoreLiveRegisters(instruction_->GetLocations());
+ if (successor_ == nullptr) {
+ __ B(GetReturnLabel());
+ } else {
+ __ B(arm64_codegen->GetLabelOf(successor_));
+ }
}
vixl::Label* GetReturnLabel() {
@@ -324,6 +430,20 @@
DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
};
+class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+ TypeCheckSlowPathARM64() {}
+
+ void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ __ Bind(GetEntryLabel());
+ __ Brk(__LINE__); // TODO: Unimplemented TypeCheckSlowPathARM64.
+ __ b(GetExitLabel());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
+};
+
#undef __
Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
@@ -356,11 +476,12 @@
location_builder_(graph, this),
instruction_visitor_(graph, this) {}
-#define __ reinterpret_cast<Arm64Assembler*>(GetAssembler())->vixl_masm_->
+#undef __
+#define __ GetVIXLAssembler()->
void CodeGeneratorARM64::GenerateFrameEntry() {
// TODO: Add proper support for the stack overflow check.
- UseScratchRegisterScope temps(assembler_.vixl_masm_);
+ UseScratchRegisterScope temps(GetVIXLAssembler());
Register temp = temps.AcquireX();
__ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
__ Ldr(temp, MemOperand(temp, 0));
@@ -378,7 +499,7 @@
// ... : other preserved registers.
// sp[frame_size - regs_size]: first preserved register.
// ... : reserved frame space.
- // sp[0] : context pointer.
+ // sp[0] : current method.
}
void CodeGeneratorARM64::GenerateFrameExit() {
@@ -413,7 +534,7 @@
__ Mov(dst, value);
} else {
DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
- UseScratchRegisterScope temps(assembler_.vixl_masm_);
+ UseScratchRegisterScope temps(GetVIXLAssembler());
Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
__ Mov(temp, value);
__ Str(temp, StackOperandFrom(location));
@@ -465,7 +586,7 @@
}
void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
- UseScratchRegisterScope temps(assembler_.vixl_masm_);
+ UseScratchRegisterScope temps(GetVIXLAssembler());
Register card = temps.AcquireX();
Register temp = temps.AcquireX();
vixl::Label done;
@@ -522,6 +643,19 @@
stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
}
+void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
+ if (constant->IsIntConstant() || constant->IsLongConstant()) {
+ __ Mov(Register(destination),
+ constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
+ : constant->AsLongConstant()->GetValue());
+ } else if (constant->IsFloatConstant()) {
+ __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
+ } else {
+ DCHECK(constant->IsDoubleConstant());
+ __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue());
+ }
+}
+
void CodeGeneratorARM64::MoveHelper(Location destination,
Location source,
Primitive::Type type) {
@@ -544,13 +678,7 @@
} 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());
- }
+ MoveConstant(dst, source.GetConstant());
}
} else {
DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
@@ -558,8 +686,21 @@
__ Str(RegisterFrom(source, type), StackOperandFrom(destination));
} else if (source.IsFpuRegister()) {
__ Str(FPRegisterFrom(source, type), StackOperandFrom(destination));
+ } else if (source.IsConstant()) {
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ HConstant* cst = source.GetConstant();
+ CPURegister temp;
+ if (cst->IsIntConstant() || cst->IsLongConstant()) {
+ temp = cst->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
+ } else {
+ DCHECK(cst->IsFloatConstant() || cst->IsDoubleConstant());
+ temp = cst->IsFloatConstant() ? temps.AcquireS() : temps.AcquireD();
+ }
+ MoveConstant(temp, cst);
+ __ Str(temp, StackOperandFrom(destination));
} else {
- UseScratchRegisterScope temps(assembler_.vixl_masm_);
+ DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
+ UseScratchRegisterScope temps(GetVIXLAssembler());
Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW();
__ Ldr(temp, StackOperandFrom(source));
__ Str(temp, StackOperandFrom(destination));
@@ -568,61 +709,89 @@
}
void CodeGeneratorARM64::Load(Primitive::Type type,
- vixl::Register dst,
+ vixl::CPURegister dst,
const vixl::MemOperand& src) {
switch (type) {
case Primitive::kPrimBoolean:
- __ Ldrb(dst, src);
+ __ Ldrb(Register(dst), src);
break;
case Primitive::kPrimByte:
- __ Ldrsb(dst, src);
+ __ Ldrsb(Register(dst), src);
break;
case Primitive::kPrimShort:
- __ Ldrsh(dst, src);
+ __ Ldrsh(Register(dst), src);
break;
case Primitive::kPrimChar:
- __ Ldrh(dst, src);
+ __ Ldrh(Register(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:
+ DCHECK(dst.Is64Bits() == Is64BitType(type));
+ __ Ldr(dst, src);
+ break;
case Primitive::kPrimVoid:
LOG(FATAL) << "Unreachable type " << type;
}
}
void CodeGeneratorARM64::Store(Primitive::Type type,
- vixl::Register rt,
+ vixl::CPURegister rt,
const vixl::MemOperand& dst) {
switch (type) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
- __ Strb(rt, dst);
+ __ Strb(Register(rt), dst);
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- __ Strh(rt, dst);
+ __ Strh(Register(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:
+ DCHECK(rt.Is64Bits() == Is64BitType(type));
+ __ Str(rt, dst);
+ break;
case Primitive::kPrimVoid:
LOG(FATAL) << "Unreachable type " << type;
}
}
-#undef __
-#define __ GetAssembler()->vixl_masm_->
+void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
+ DCHECK(current_method.IsW());
+ __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
+}
+
+void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
+ HInstruction* instruction,
+ uint32_t dex_pc) {
+ __ Ldr(lr, MemOperand(tr, entry_point_offset));
+ __ Blr(lr);
+ RecordPcInfo(instruction, dex_pc);
+ DCHECK(instruction->IsSuspendCheck()
+ || instruction->IsBoundsCheck()
+ || instruction->IsNullCheck()
+ || instruction->IsDivZeroCheck()
+ || !IsLeafMethod());
+}
+
+void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
+ vixl::Register class_reg) {
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ Register temp = temps.AcquireW();
+ __ Ldr(temp, HeapOperand(class_reg, mirror::Class::StatusOffset()));
+ __ Cmp(temp, mirror::Class::kStatusInitialized);
+ __ B(lt, slow_path->GetEntryLabel());
+ // Even if the initialized flag is set, we may be in a situation where caches are not synced
+ // properly. Therefore, we do a memory fence.
+ __ Dmb(InnerShareable, BarrierAll);
+ __ Bind(slow_path->GetExitLabel());
+}
InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
CodeGeneratorARM64* codegen)
@@ -631,28 +800,14 @@
codegen_(codegen) {}
#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
- M(And) \
- M(CheckCast) \
- M(ClinitCheck) \
- M(DivZeroCheck) \
- M(InstanceOf) \
- M(InvokeInterface) \
- M(LoadClass) \
- M(LoadException) \
- M(LoadString) \
- M(MonitorOperation) \
- M(Or) \
M(ParallelMove) \
- M(Rem) \
- M(StaticFieldGet) \
- M(StaticFieldSet) \
- M(Throw) \
- M(TypeConversion) \
- M(Xor) \
+ M(Rem)
#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
enum UnimplementedInstructionBreakCode {
+ // Using a base helps identify when we hit such breakpoints.
+ UnimplementedInstructionBreakCodeBaseCode = 0x900,
#define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
#undef ENUM_UNIMPLEMENTED_INSTRUCTION
@@ -671,9 +826,9 @@
#undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
#undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
+#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION
-void LocationsBuilderARM64::HandleAddSub(HBinaryOperation* instr) {
- DCHECK(instr->IsAdd() || instr->IsSub());
+void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
DCHECK_EQ(instr->InputCount(), 2U);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
Primitive::Type type = instr->GetResultType();
@@ -689,7 +844,7 @@
case Primitive::kPrimDouble:
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetInAt(1, Location::RequiresFpuRegister());
- locations->SetOut(Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
default:
@@ -697,9 +852,7 @@
}
}
-void InstructionCodeGeneratorARM64::HandleAddSub(HBinaryOperation* instr) {
- DCHECK(instr->IsAdd() || instr->IsSub());
-
+void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
Primitive::Type type = instr->GetType();
switch (type) {
@@ -710,8 +863,15 @@
Operand rhs = InputOperandAt(instr, 1);
if (instr->IsAdd()) {
__ Add(dst, lhs, rhs);
- } else {
+ } else if (instr->IsAnd()) {
+ __ And(dst, lhs, rhs);
+ } else if (instr->IsOr()) {
+ __ Orr(dst, lhs, rhs);
+ } else if (instr->IsSub()) {
__ Sub(dst, lhs, rhs);
+ } else {
+ DCHECK(instr->IsXor());
+ __ Eor(dst, lhs, rhs);
}
break;
}
@@ -722,22 +882,32 @@
FPRegister rhs = InputFPRegisterAt(instr, 1);
if (instr->IsAdd()) {
__ Fadd(dst, lhs, rhs);
- } else {
+ } else if (instr->IsSub()) {
__ Fsub(dst, lhs, rhs);
+ } else {
+ LOG(FATAL) << "Unexpected floating-point binary operation";
}
break;
}
default:
- LOG(FATAL) << "Unexpected add/sub type " << type;
+ LOG(FATAL) << "Unexpected binary operation type " << type;
}
}
void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
- HandleAddSub(instruction);
+ HandleBinaryOp(instruction);
}
void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
- HandleAddSub(instruction);
+ HandleBinaryOp(instruction);
+}
+
+void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
+ HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
+ HandleBinaryOp(instruction);
}
void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
@@ -752,11 +922,10 @@
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_);
+ UseScratchRegisterScope temps(GetVIXLAssembler());
if (index.IsConstant()) {
offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
@@ -768,7 +937,7 @@
source = MemOperand(temp, offset);
}
- codegen_->Load(type, out, source);
+ codegen_->Load(type, OutputCPURegister(instruction), source);
}
void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
@@ -802,18 +971,16 @@
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());
+ codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
+
} else {
LocationSummary* locations = instruction->GetLocations();
Register obj = InputRegisterAt(instruction, 0);
- Register value = InputRegisterAt(instruction, 2);
+ CPURegister value = InputCPURegisterAt(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_);
+ UseScratchRegisterScope temps(GetVIXLAssembler());
if (index.IsConstant()) {
offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
@@ -829,6 +996,66 @@
}
}
+void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ if (instruction->HasUses()) {
+ locations->SetOut(Location::SameAsFirstInput());
+ }
+}
+
+void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
+ BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64();
+ codegen_->AddSlowPath(slow_path);
+
+ __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
+ __ B(slow_path->GetEntryLabel(), hs);
+}
+
+void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+ instruction, LocationSummary::kCallOnSlowPath);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ Register obj = InputRegisterAt(instruction, 0);;
+ Register cls = InputRegisterAt(instruction, 1);;
+ Register temp = temps.AcquireW();
+
+ SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64();
+ codegen_->AddSlowPath(slow_path);
+
+ // TODO: avoid this check if we know obj is not null.
+ __ Cbz(obj, slow_path->GetExitLabel());
+ // Compare the class of `obj` with `cls`.
+ __ Ldr(temp, HeapOperand(obj, mirror::Object::ClassOffset()));
+ __ Cmp(temp, cls);
+ __ B(ne, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
+ locations->SetInAt(0, Location::RequiresRegister());
+ if (check->HasUses()) {
+ locations->SetOut(Location::SameAsFirstInput());
+ }
+}
+
+void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
+ // We assume the class is not null.
+ SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
+ check->GetLoadClass(), check, check->GetDexPc(), true);
+ codegen_->AddSlowPath(slow_path);
+ GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
+}
+
void LocationsBuilderARM64::VisitCompare(HCompare* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
@@ -847,7 +1074,7 @@
Register result = OutputRegister(instruction);
Register left = InputRegisterAt(instruction, 0);
Operand right = InputOperandAt(instruction, 1);
- __ Subs(result, left, right);
+ __ Subs(result.X(), left, right);
__ B(eq, &done);
__ Mov(result, 1);
__ Cneg(result, result, le);
@@ -894,6 +1121,7 @@
void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } \
void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
+#undef DEFINE_CONDITION_VISITORS
#undef FOR_EACH_CONDITION_INSTRUCTION
void LocationsBuilderARM64::VisitDiv(HDiv* div) {
@@ -937,6 +1165,33 @@
}
}
+void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
+ if (instruction->HasUses()) {
+ locations->SetOut(Location::SameAsFirstInput());
+ }
+}
+
+void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ SlowPathCodeARM64* slow_path =
+ new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction);
+ codegen_->AddSlowPath(slow_path);
+ Location value = instruction->GetLocations()->InAt(0);
+
+ if (value.IsConstant()) {
+ int64_t divisor = Int64ConstantFrom(value);
+ if (divisor == 0) {
+ __ B(slow_path->GetEntryLabel());
+ } else {
+ LOG(FATAL) << "Divisions by non-null constants should have been optimized away.";
+ }
+ } else {
+ __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
+ }
+}
+
void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
@@ -956,7 +1211,7 @@
UNUSED(exit);
if (kIsDebugBuild) {
down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
- __ Brk(0); // TODO: Introduce special markers for such code locations.
+ __ Brk(__LINE__); // TODO: Introduce special markers for such code locations.
}
}
@@ -1039,7 +1294,7 @@
void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
MemOperand field = MemOperand(InputRegisterAt(instruction, 0),
instruction->GetFieldOffset().Uint32Value());
- codegen_->Load(instruction->GetType(), OutputRegister(instruction), field);
+ codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
}
void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
@@ -1050,14 +1305,56 @@
void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Primitive::Type field_type = instruction->GetFieldType();
- Register value = InputRegisterAt(instruction, 1);
+ CPURegister value = InputCPURegisterAt(instruction, 1);
Register obj = InputRegisterAt(instruction, 0);
codegen_->Store(field_type, value, MemOperand(obj, instruction->GetFieldOffset().Uint32Value()));
if (field_type == Primitive::kPrimNot) {
- codegen_->MarkGCCard(obj, value);
+ codegen_->MarkGCCard(obj, Register(value));
}
}
+void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
+ LocationSummary::CallKind call_kind =
+ instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), true); // The output does overlap inputs.
+}
+
+void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Register obj = InputRegisterAt(instruction, 0);;
+ Register cls = InputRegisterAt(instruction, 1);;
+ Register out = OutputRegister(instruction);
+
+ vixl::Label done;
+
+ // Return 0 if `obj` is null.
+ // TODO: Avoid this check if we know `obj` is not null.
+ __ Mov(out, 0);
+ __ Cbz(obj, &done);
+
+ // Compare the class of `obj` with `cls`.
+ __ Ldr(out, MemOperand(obj, mirror::Object::ClassOffset().Int32Value()));
+ __ Cmp(out, cls);
+ if (instruction->IsClassFinal()) {
+ // Classes must be equal for the instanceof to succeed.
+ __ Cset(out, eq);
+ } else {
+ // If the classes are not equal, we go into a slow path.
+ DCHECK(locations->OnlyCallsOnSlowPath());
+ SlowPathCodeARM64* slow_path =
+ new (GetGraph()->GetArena()) TypeCheckSlowPathARM64();
+ codegen_->AddSlowPath(slow_path);
+ __ B(ne, slow_path->GetEntryLabel());
+ __ Mov(out, 1);
+ __ Bind(slow_path->GetExitLabel());
+ }
+
+ __ Bind(&done);
+}
+
void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
locations->SetOut(Location::ConstantLocation(constant));
@@ -1068,14 +1365,6 @@
UNUSED(constant);
}
-void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
- HandleInvoke(invoke);
-}
-
-void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
- HandleInvoke(invoke);
-}
-
void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
@@ -1093,6 +1382,50 @@
}
}
+void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
+ HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
+ // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
+ Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
+ uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
+ (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
+ Location receiver = invoke->GetLocations()->InAt(0);
+ Offset class_offset = mirror::Object::ClassOffset();
+ Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset();
+
+ // The register ip1 is required to be used for the hidden argument in
+ // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
+ UseScratchRegisterScope scratch_scope(GetVIXLAssembler());
+ scratch_scope.Exclude(ip1);
+ __ Mov(ip1, invoke->GetDexMethodIndex());
+
+ // temp = object->GetClass();
+ if (receiver.IsStackSlot()) {
+ __ Ldr(temp, StackOperandFrom(receiver));
+ __ Ldr(temp, HeapOperand(temp, class_offset));
+ } else {
+ __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
+ }
+ // temp = temp->GetImtEntryAt(method_offset);
+ __ Ldr(temp, HeapOperand(temp, method_offset));
+ // lr = temp->GetEntryPoint();
+ __ Ldr(lr, HeapOperand(temp, entry_point));
+ // lr();
+ __ Blr(lr);
+ DCHECK(!codegen_->IsLeafMethod());
+ codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+ HandleInvoke(invoke);
+}
+
+void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
+ HandleInvoke(invoke);
+}
+
void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
// Make sure that ArtMethod* is passed in W0 as per the calling convention
@@ -1108,7 +1441,7 @@
// Currently we implement the app -> app logic, which looks up in the resolve cache.
// temp = method;
- __ Ldr(temp, MemOperand(sp, kCurrentMethodStackOffset));
+ codegen_->LoadCurrentMethod(temp);
// temp = temp->dex_cache_resolved_methods_;
__ Ldr(temp, MemOperand(temp.X(),
mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
@@ -1139,8 +1472,7 @@
__ Ldr(temp.W(), MemOperand(temp, class_offset.SizeValue()));
} else {
DCHECK(receiver.IsRegister());
- __ Ldr(temp.W(), HeapOperandFrom(receiver, Primitive::kPrimNot,
- class_offset));
+ __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
}
// temp = temp->GetMethodAt(method_offset);
__ Ldr(temp.W(), MemOperand(temp, method_offset));
@@ -1152,6 +1484,50 @@
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
+void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
+ LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
+ Register out = OutputRegister(cls);
+ if (cls->IsReferrersClass()) {
+ DCHECK(!cls->CanCallRuntime());
+ DCHECK(!cls->MustGenerateClinitCheck());
+ codegen_->LoadCurrentMethod(out);
+ __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
+ } else {
+ DCHECK(cls->CanCallRuntime());
+ codegen_->LoadCurrentMethod(out);
+ __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset()));
+ __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+
+ SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
+ cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+ codegen_->AddSlowPath(slow_path);
+ __ Cbz(out, slow_path->GetEntryLabel());
+ if (cls->MustGenerateClinitCheck()) {
+ GenerateClassInitializationCheck(slow_path, out);
+ } else {
+ __ Bind(slow_path->GetExitLabel());
+ }
+ }
+}
+
+void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
+ MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
+ __ Ldr(OutputRegister(instruction), exception);
+ __ Str(wzr, exception);
+}
+
void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
load->SetLocations(nullptr);
}
@@ -1161,6 +1537,24 @@
UNUSED(load);
}
+void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
+ SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
+ codegen_->AddSlowPath(slow_path);
+
+ Register out = OutputRegister(load);
+ codegen_->LoadCurrentMethod(out);
+ __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheStringsOffset()));
+ __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(load->GetStringIndex())));
+ __ Cbz(out, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+}
+
void LocationsBuilderARM64::VisitLocal(HLocal* local) {
local->SetLocations(nullptr);
}
@@ -1179,6 +1573,20 @@
UNUSED(constant);
}
+void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
+ codegen_->InvokeRuntime(instruction->IsEnter()
+ ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
+ instruction,
+ instruction->GetDexPc());
+}
+
void LocationsBuilderARM64::VisitMul(HMul* mul) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
@@ -1194,7 +1602,7 @@
case Primitive::kPrimDouble:
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetInAt(1, Location::RequiresFpuRegister());
- locations->SetOut(Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
default:
@@ -1224,15 +1632,15 @@
new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
switch (neg->GetResultType()) {
case Primitive::kPrimInt:
- case Primitive::kPrimLong: {
+ case Primitive::kPrimLong:
locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
- locations->SetOut(Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
- }
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
default:
@@ -1249,7 +1657,7 @@
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
break;
default:
@@ -1274,14 +1682,10 @@
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));
+ codegen_->LoadCurrentMethod(current_method);
__ 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());
+ codegen_->InvokeRuntime(
+ QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
}
void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
@@ -1299,14 +1703,10 @@
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));
+ codegen_->LoadCurrentMethod(current_method);
__ Mov(type_index, instruction->GetTypeIndex());
- 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());
+ codegen_->InvokeRuntime(
+ QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
}
void LocationsBuilderARM64::VisitNot(HNot* instruction) {
@@ -1355,6 +1755,14 @@
}
}
+void LocationsBuilderARM64::VisitOr(HOr* instruction) {
+ HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
+ HandleBinaryOp(instruction);
+}
+
void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
@@ -1435,31 +1843,43 @@
}
void LocationsBuilderARM64::VisitSub(HSub* instruction) {
- HandleAddSub(instruction);
+ HandleBinaryOp(instruction);
}
void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
- HandleAddSub(instruction);
+ HandleBinaryOp(instruction);
}
-void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
+void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+ Register cls = InputRegisterAt(instruction, 0);
+ uint32_t offset = instruction->GetFieldOffset().Uint32Value();
+ codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), MemOperand(cls, offset));
+}
+
+void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
- if (instruction->HasUses()) {
- locations->SetOut(Location::SameAsFirstInput());
- }
}
-void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
- LocationSummary* locations = instruction->GetLocations();
- BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(
- instruction, locations->InAt(0), locations->InAt(1));
- codegen_->AddSlowPath(slow_path);
+void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+ CPURegister value = InputCPURegisterAt(instruction, 1);
+ Register cls = InputRegisterAt(instruction, 0);
+ uint32_t offset = instruction->GetFieldOffset().Uint32Value();
+ Primitive::Type field_type = instruction->GetFieldType();
- __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
- __ B(slow_path->GetEntryLabel(), hs);
+ codegen_->Store(field_type, value, MemOperand(cls, offset));
+ if (field_type == Primitive::kPrimNot) {
+ codegen_->MarkGCCard(cls, Register(value));
+ }
}
void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
@@ -1486,5 +1906,74 @@
UNUSED(temp);
}
+void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
+ codegen_->InvokeRuntime(
+ QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
+}
+
+void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+ Primitive::Type input_type = conversion->GetInputType();
+ Primitive::Type result_type = conversion->GetResultType();
+ if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
+ (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
+ LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
+ }
+
+ if (IsFPType(input_type)) {
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ } else {
+ locations->SetInAt(0, Location::RequiresRegister());
+ }
+
+ if (IsFPType(result_type)) {
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+ } else {
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ }
+}
+
+void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
+ Primitive::Type result_type = conversion->GetResultType();
+ Primitive::Type input_type = conversion->GetInputType();
+
+ DCHECK_NE(input_type, result_type);
+
+ if (IsIntegralType(result_type) && IsIntegralType(input_type)) {
+ int result_size = Primitive::ComponentSize(result_type);
+ int input_size = Primitive::ComponentSize(input_type);
+ int min_size = kBitsPerByte * std::min(result_size, input_size);
+ if ((result_type == Primitive::kPrimChar) ||
+ ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
+ __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size);
+ } else {
+ __ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size);
+ }
+ return;
+ }
+
+ LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
+ << " to " << result_type;
+}
+
+void LocationsBuilderARM64::VisitXor(HXor* instruction) {
+ HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
+ HandleBinaryOp(instruction);
+}
+
+#undef __
+#undef QUICK_ENTRY_POINT
+
} // namespace arm64
} // namespace art
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 54e87f4..6b71b94 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -29,6 +29,7 @@
namespace arm64 {
class CodeGeneratorARM64;
+class SlowPathCodeARM64;
static constexpr size_t kArm64WordSize = 8;
static const vixl::Register kParameterCoreRegisters[] = {
@@ -103,9 +104,11 @@
void LoadCurrentMethod(XRegister reg);
Arm64Assembler* GetAssembler() const { return assembler_; }
+ vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
private:
- void HandleAddSub(HBinaryOperation* instr);
+ void GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path, vixl::Register class_reg);
+ void HandleBinaryOp(HBinaryOperation* instr);
Arm64Assembler* const assembler_;
CodeGeneratorARM64* const codegen_;
@@ -124,7 +127,7 @@
#undef DECLARE_VISIT_INSTRUCTION
private:
- void HandleAddSub(HBinaryOperation* instr);
+ void HandleBinaryOp(HBinaryOperation* instr);
void HandleInvoke(HInvoke* instr);
CodeGeneratorARM64* const codegen_;
@@ -162,9 +165,10 @@
return kArm64WordSize;
}
- uintptr_t GetAddressOf(HBasicBlock* block ATTRIBUTE_UNUSED) const OVERRIDE {
- UNIMPLEMENTED(INFO) << "TODO: GetAddressOf";
- return 0u;
+ uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+ vixl::Label* block_entry_label = GetLabelOf(block);
+ DCHECK(block_entry_label->IsBound());
+ return block_entry_label->location();
}
size_t FrameEntrySpillSize() const OVERRIDE;
@@ -172,6 +176,7 @@
HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
+ vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
// Emit a write barrier.
void MarkGCCard(vixl::Register object, vixl::Register value);
@@ -185,18 +190,18 @@
Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
UNUSED(stack_index);
UNUSED(reg_id);
- UNIMPLEMENTED(INFO) << "TODO: SaveCoreRegister";
- return 0;
+ LOG(INFO) << "CodeGeneratorARM64::SaveCoreRegister()";
+ return kArm64WordSize;
}
- size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
UNUSED(stack_index);
UNUSED(reg_id);
- UNIMPLEMENTED(INFO) << "TODO: RestoreCoreRegister";
- return 0;
+ LOG(INFO) << "CodeGeneratorARM64::RestoreCoreRegister()";
+ return kArm64WordSize;
}
// The number of registers that can be allocated. The register allocator may
@@ -226,9 +231,14 @@
}
// Code generation helpers.
+ void MoveConstant(vixl::CPURegister destination, HConstant* constant);
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);
+ void Load(Primitive::Type type, vixl::CPURegister dst, const vixl::MemOperand& src);
+ void Store(Primitive::Type type, vixl::CPURegister rt, const vixl::MemOperand& dst);
+ void LoadCurrentMethod(vixl::Register current_method);
+
+ // Generate code to invoke a runtime entry point.
+ void InvokeRuntime(int32_t offset, HInstruction* instruction, uint32_t dex_pc);
ParallelMoveResolver* GetMoveResolver() OVERRIDE {
UNIMPLEMENTED(INFO) << "TODO: MoveResolver";
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 0f58234..8749f41 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -307,164 +307,38 @@
# Known broken tests for the arm64 optimizing compiler backend.
TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \
- 001-HelloWorld \
- 002-sleep \
003-omnibus-opcodes \
- 004-InterfaceTest \
- 004-JniTest \
004-NativeAllocations \
004-ReferenceMap \
- 004-SignalTest \
- 004-StackWalk \
- 004-UnsafeTest \
005-annotations \
- 006-args \
- 007-count10 \
- 008-exceptions \
009-instanceof \
010-instance \
- 011-array-copy \
- 013-math2 \
- 014-math3 \
- 016-intern \
- 017-float \
- 018-stack-overflow \
- 019-wrong-array-type \
- 020-string \
- 021-string2 \
- 022-interface \
+ 012-math \
023-many-interfaces \
- 024-illegal-access \
- 025-access-controller \
- 026-access \
- 028-array-write \
- 029-assert \
- 030-bad-finalizer \
- 031-class-attributes \
- 032-concrete-sub \
- 033-class-init-deadlock \
- 034-call-null \
- 035-enum \
- 036-finalizer \
037-inherit \
- 038-inner-null \
- 039-join-main \
- 040-miranda \
- 042-new-instance \
- 043-privates \
+ 047-inherit \
044-proxy \
045-reflect-array \
046-reflect \
047-returns \
- 049-show-object \
- 050-sync-test \
- 051-thread \
- 052-verifier-fun \
- 054-uncaught \
- 055-enum-performance \
- 056-const-string-jumbo \
- 058-enum-order \
- 061-out-of-memory \
062-character-encodings \
063-process-manager \
- 064-field-access \
- 065-mismatched-implements \
- 066-mismatched-super \
- 067-preemptive-unpark \
068-classloader \
069-field-type \
- 070-nio-buffer \
071-dexfile \
- 072-precise-gc \
- 074-gc-thrash \
- 075-verification-error \
- 076-boolean-put \
- 077-method-override \
- 078-polymorphic-virtual \
- 079-phantom \
- 080-oom-throw \
- 081-hot-exceptions \
- 082-inline-execute \
083-compiler-regressions \
- 084-class-init \
- 085-old-style-inner-class \
- 086-null-super \
- 087-gc-after-link \
- 088-monitor-verification \
- 090-loop-formation \
- 092-locale \
- 093-serialization \
- 094-pattern \
- 096-array-copy-concurrent-gc \
- 097-duplicate-method \
- 098-ddmc \
- 100-reflect2 \
- 101-fibonacci \
- 102-concurrent-gc \
- 103-string-append \
- 104-growth-limit \
- 105-invoke \
106-exceptions2 \
107-int-math2 \
- 108-check-cast \
- 109-suspend-check \
- 110-field-access \
- 111-unresolvable-exception \
- 112-double-math \
- 113-multidex \
114-ParallelGC \
- 117-nopatchoat \
- 118-noimage-dex2oat \
- 119-noimage-patchoat \
- 120-hashcode \
- 121-modifiers \
- 121-simple-suspend-check \
- 122-npe \
- 123-compiler-regressions-mt \
- 124-missing-classes \
- 125-gc-and-classloading \
- 126-miranda-multidex \
201-built-in-exception-detail-messages \
- 202-thread-oome \
- 300-package-override \
- 301-abstract-protected \
- 303-verification-stress \
- 304-method-tracing \
- 401-optimizing-compiler \
- 402-optimizing-control-flow \
- 403-optimizing-long \
- 404-optimizing-allocator \
- 405-optimizing-long-allocator \
- 406-fields \
407-arrays \
- 409-materialized-condition \
- 410-floats \
- 411-optimizing-arith \
412-new-array \
- 413-regalloc-regression \
- 414-optimizing-arith-sub \
- 414-static-fields \
- 415-optimizing-arith-neg \
- 416-optimizing-arith-not \
- 417-optimizing-arith-div \
- 418-const-string \
- 419-long-parameter \
- 420-const-class \
- 421-exceptions \
- 421-large-frame \
422-instanceof \
422-type-conversion \
- 423-invoke-interface \
424-checkcast \
- 426-monitor \
- 427-bitwise \
427-bounds \
428-optimizing-arith-rem \
- 700-LoadArgRegs \
701-easy-div-rem \
- 702-LargeBranchOffset \
- 703-floating-point-div \
- 800-smali
ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \