summaryrefslogtreecommitdiffstats
path: root/compiler/optimizing/code_generator_arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/code_generator_arm.cc')
-rw-r--r--compiler/optimizing/code_generator_arm.cc800
1 files changed, 502 insertions, 298 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 002d9d4449..8c07b46173 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -16,6 +16,7 @@
#include "code_generator_arm.h"
+#include "arch/arm/instruction_set_features_arm.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "gc/accounting/card_table.h"
#include "mirror/array-inl.h"
@@ -36,7 +37,10 @@ static DRegister FromLowSToD(SRegister reg) {
return static_cast<DRegister>(reg / 2);
}
-static constexpr bool kExplicitStackOverflowCheck = false;
+static bool ExpectedPairLayout(Location location) {
+ // We expected this for both core and fpu register pairs.
+ return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
+}
static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7
static constexpr int kCurrentMethodStackOffset = 0;
@@ -255,8 +259,8 @@ class LoadStringSlowPathARM : public SlowPathCodeARM {
codegen->SaveLiveRegisters(locations);
InvokeRuntimeCallingConvention calling_convention;
- arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0));
- __ LoadImmediate(calling_convention.GetRegisterAt(1), instruction_->GetStringIndex());
+ arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+ __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
arm_codegen->InvokeRuntime(
QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
@@ -372,13 +376,27 @@ size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id
return kArmWordSize;
}
-CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
- : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters, kNumberOfRegisterPairs),
+size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+ __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
+ return kArmWordSize;
+}
+
+size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+ __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
+ return kArmWordSize;
+}
+
+CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
+ const ArmInstructionSetFeatures& isa_features,
+ const CompilerOptions& compiler_options)
+ : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters,
+ kNumberOfRegisterPairs, compiler_options),
block_labels_(graph->GetArena(), 0),
location_builder_(graph, this),
instruction_visitor_(graph, this),
move_resolver_(graph->GetArena(), this),
- assembler_(true) {}
+ assembler_(true),
+ isa_features_(isa_features) {}
size_t CodeGeneratorARM::FrameEntrySpillSize() const {
return kNumberOfPushedRegistersAtEntry * kArmWordSize;
@@ -499,17 +517,17 @@ void CodeGeneratorARM::GenerateFrameEntry() {
bool skip_overflow_check =
IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
if (!skip_overflow_check) {
- if (kExplicitStackOverflowCheck) {
+ if (GetCompilerOptions().GetImplicitStackOverflowChecks()) {
+ __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
+ __ LoadFromOffset(kLoadWord, IP, IP, 0);
+ RecordPcInfo(nullptr, 0);
+ } else {
SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
AddSlowPath(slow_path);
__ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
__ cmp(SP, ShifterOperand(IP));
__ b(slow_path->GetEntryLabel(), CC);
- } else {
- __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
- __ LoadFromOffset(kLoadWord, IP, IP, 0);
- RecordPcInfo(nullptr, 0);
}
}
@@ -577,11 +595,17 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type
gp_index_ += 2;
stack_index_ += 2;
if (index + 1 < calling_convention.GetNumberOfRegisters()) {
- ArmManagedRegister pair = ArmManagedRegister::FromRegisterPair(
- calling_convention.GetRegisterPairAt(index));
- return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
- } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
- return Location::QuickParameter(index, stack_index);
+ if (calling_convention.GetRegisterAt(index) == R1) {
+ // Skip R1, and use R2_R3 instead.
+ gp_index_++;
+ index++;
+ }
+ }
+ if (index + 1 < calling_convention.GetNumberOfRegisters()) {
+ DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
+ calling_convention.GetRegisterAt(index + 1));
+ return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
+ calling_convention.GetRegisterAt(index + 1));
} else {
return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
}
@@ -606,9 +630,11 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type
if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
uint32_t index = double_index_;
double_index_ += 2;
- return Location::FpuRegisterPairLocation(
+ Location result = Location::FpuRegisterPairLocation(
calling_convention.GetFpuRegisterAt(index),
calling_convention.GetFpuRegisterAt(index + 1));
+ DCHECK(ExpectedPairLayout(result));
+ return result;
} else {
return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
}
@@ -698,27 +724,11 @@ void CodeGeneratorARM::Move64(Location destination, Location source) {
Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
} else if (source.IsFpuRegister()) {
UNIMPLEMENTED(FATAL);
- } else if (source.IsQuickParameter()) {
- uint16_t register_index = source.GetQuickParameterRegisterIndex();
- uint16_t stack_index = source.GetQuickParameterStackIndex();
- InvokeDexCallingConvention calling_convention;
- EmitParallelMoves(
- Location::RegisterLocation(calling_convention.GetRegisterAt(register_index)),
- Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
- Location::StackSlot(
- calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize()),
- Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()));
} else {
- // No conflict possible, so just do the moves.
DCHECK(source.IsDoubleStackSlot());
- if (destination.AsRegisterPairLow<Register>() == R1) {
- DCHECK_EQ(destination.AsRegisterPairHigh<Register>(), R2);
- __ LoadFromOffset(kLoadWord, R1, SP, source.GetStackIndex());
- __ LoadFromOffset(kLoadWord, R2, SP, source.GetHighStackIndex(kArmWordSize));
- } else {
- __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
- SP, source.GetStackIndex());
- }
+ DCHECK(ExpectedPairLayout(destination));
+ __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
+ SP, source.GetStackIndex());
}
} else if (destination.IsFpuRegisterPair()) {
if (source.IsDoubleStackSlot()) {
@@ -728,22 +738,6 @@ void CodeGeneratorARM::Move64(Location destination, Location source) {
} else {
UNIMPLEMENTED(FATAL);
}
- } else if (destination.IsQuickParameter()) {
- InvokeDexCallingConvention calling_convention;
- uint16_t register_index = destination.GetQuickParameterRegisterIndex();
- uint16_t stack_index = destination.GetQuickParameterStackIndex();
- if (source.IsRegisterPair()) {
- UNIMPLEMENTED(FATAL);
- } else if (source.IsFpuRegister()) {
- UNIMPLEMENTED(FATAL);
- } else {
- DCHECK(source.IsDoubleStackSlot());
- EmitParallelMoves(
- Location::StackSlot(source.GetStackIndex()),
- Location::RegisterLocation(calling_convention.GetRegisterAt(register_index)),
- Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
- Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index + 1)));
- }
} else {
DCHECK(destination.IsDoubleStackSlot());
if (source.IsRegisterPair()) {
@@ -756,17 +750,6 @@ void CodeGeneratorARM::Move64(Location destination, Location source) {
__ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
SP, destination.GetStackIndex());
}
- } else if (source.IsQuickParameter()) {
- InvokeDexCallingConvention calling_convention;
- uint16_t register_index = source.GetQuickParameterRegisterIndex();
- uint16_t stack_index = source.GetQuickParameterStackIndex();
- // Just move the low part. The only time a source is a quick parameter is
- // when moving the parameter to its stack locations. And the (Java) caller
- // of this method has already done that.
- __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(register_index),
- SP, destination.GetStackIndex());
- DCHECK_EQ(calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize(),
- static_cast<size_t>(destination.GetHighStackIndex(kArmWordSize)));
} else if (source.IsFpuRegisterPair()) {
__ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
SP,
@@ -799,7 +782,8 @@ void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstr
__ LoadImmediate(IP, value);
__ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
}
- } else if (const_to_move->IsLongConstant()) {
+ } else {
+ DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
int64_t value = const_to_move->AsLongConstant()->GetValue();
if (location.IsRegisterPair()) {
__ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
@@ -951,6 +935,7 @@ void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
// Condition has not been materialized, use its inputs as the
// comparison and its condition as the branch condition.
LocationSummary* locations = cond->GetLocations();
+ DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Register left = locations->InAt(0).AsRegister<Register>();
if (locations->InAt(1).IsRegister()) {
__ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
@@ -1196,7 +1181,7 @@ void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirec
kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
// temp = temp[index_in_cache]
__ LoadFromOffset(
- kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache()));
+ kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
// LR = temp[offset_of_quick_compiled_code]
__ LoadFromOffset(kLoadWord, LR, temp,
mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
@@ -1240,6 +1225,7 @@ void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
} else {
__ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
}
+ codegen_->MaybeRecordImplicitNullCheck(invoke);
// temp = temp->GetMethodAt(method_offset);
uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
kArmWordSize).Int32Value();
@@ -1278,6 +1264,7 @@ void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke)
} else {
__ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
}
+ codegen_->MaybeRecordImplicitNullCheck(invoke);
// temp = temp->GetImtEntryAt(method_offset);
uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
kArmWordSize).Int32Value();
@@ -1296,7 +1283,9 @@ void LocationsBuilderARM::VisitNeg(HNeg* neg) {
switch (neg->GetResultType()) {
case Primitive::kPrimInt:
case Primitive::kPrimLong: {
- bool output_overlaps = (neg->GetResultType() == Primitive::kPrimLong);
+ Location::OutputOverlap output_overlaps = (neg->GetResultType() == Primitive::kPrimLong)
+ ? Location::kOutputOverlap
+ : Location::kNoOutputOverlap;
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister(), output_overlaps);
break;
@@ -1823,12 +1812,17 @@ void LocationsBuilderARM::VisitAdd(HAdd* add) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
switch (add->GetResultType()) {
- case Primitive::kPrimInt:
- case Primitive::kPrimLong: {
- bool output_overlaps = (add->GetResultType() == Primitive::kPrimLong);
+ case Primitive::kPrimInt: {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
- locations->SetOut(Location::RequiresRegister(), output_overlaps);
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ break;
+ }
+
+ case Primitive::kPrimLong: {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
break;
}
@@ -1863,7 +1857,8 @@ void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
}
break;
- case Primitive::kPrimLong:
+ case Primitive::kPrimLong: {
+ DCHECK(second.IsRegisterPair());
__ adds(out.AsRegisterPairLow<Register>(),
first.AsRegisterPairLow<Register>(),
ShifterOperand(second.AsRegisterPairLow<Register>()));
@@ -1871,6 +1866,7 @@ void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
first.AsRegisterPairHigh<Register>(),
ShifterOperand(second.AsRegisterPairHigh<Register>()));
break;
+ }
case Primitive::kPrimFloat:
__ vadds(out.AsFpuRegister<SRegister>(),
@@ -1893,12 +1889,17 @@ void LocationsBuilderARM::VisitSub(HSub* sub) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
switch (sub->GetResultType()) {
- case Primitive::kPrimInt:
- case Primitive::kPrimLong: {
- bool output_overlaps = (sub->GetResultType() == Primitive::kPrimLong);
+ case Primitive::kPrimInt: {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
- locations->SetOut(Location::RequiresRegister(), output_overlaps);
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ break;
+ }
+
+ case Primitive::kPrimLong: {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
break;
}
case Primitive::kPrimFloat:
@@ -1933,6 +1934,7 @@ void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
}
case Primitive::kPrimLong: {
+ DCHECK(second.IsRegisterPair());
__ subs(out.AsRegisterPairLow<Register>(),
first.AsRegisterPairLow<Register>(),
ShifterOperand(second.AsRegisterPairLow<Register>()));
@@ -2068,8 +2070,7 @@ void LocationsBuilderARM::VisitDiv(HDiv* div) {
calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
locations->SetInAt(1, Location::RegisterPairLocation(
calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
- // The runtime helper puts the output in R0,R2.
- locations->SetOut(Location::RegisterPairLocation(R0, R2));
+ locations->SetOut(Location::RegisterPairLocation(R0, R1));
break;
}
case Primitive::kPrimFloat:
@@ -2106,7 +2107,7 @@ void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
- DCHECK_EQ(R2, out.AsRegisterPairHigh<Register>());
+ DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc());
break;
@@ -2289,8 +2290,8 @@ void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
locations->SetInAt(0, Location::RegisterPairLocation(
calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
- // The runtime helper puts the output in R0,R2.
- locations->SetOut(Location::RegisterPairLocation(R0, R2));
+ // The runtime helper puts the output in R0,R1.
+ locations->SetOut(Location::RegisterPairLocation(R0, R1));
break;
}
default:
@@ -2344,7 +2345,7 @@ void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegister<Register>());
DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
- DCHECK_EQ(R2, out.AsRegisterPairHigh<Register>());
+ DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
int32_t entry_point_offset;
if (op->IsShl()) {
@@ -2409,14 +2410,14 @@ void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
InvokeRuntimeCallingConvention calling_convention;
locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
- locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
locations->SetOut(Location::RegisterLocation(R0));
- locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+ locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
}
void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
InvokeRuntimeCallingConvention calling_convention;
- codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+ codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
__ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
codegen_->InvokeRuntime(
QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
@@ -2556,68 +2557,172 @@ void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
LOG(FATAL) << "Unreachable";
}
-void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
+ // TODO (ported from quick): revisit Arm barrier kinds
+ DmbOptions flavour = DmbOptions::ISH; // quiet c++ warnings
+ switch (kind) {
+ case MemBarrierKind::kAnyStore:
+ case MemBarrierKind::kLoadAny:
+ case MemBarrierKind::kAnyAny: {
+ flavour = DmbOptions::ISH;
+ break;
+ }
+ case MemBarrierKind::kStoreStore: {
+ flavour = DmbOptions::ISHST;
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unexpected memory barrier " << kind;
+ }
+ __ dmb(flavour);
+}
+
+void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
+ uint32_t offset,
+ Register out_lo,
+ Register out_hi) {
+ if (offset != 0) {
+ __ LoadImmediate(out_lo, offset);
+ __ add(IP, addr, ShifterOperand(out_lo));
+ addr = IP;
+ }
+ __ ldrexd(out_lo, out_hi, addr);
+}
+
+void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
+ uint32_t offset,
+ Register value_lo,
+ Register value_hi,
+ Register temp1,
+ Register temp2,
+ HInstruction* instruction) {
+ Label fail;
+ if (offset != 0) {
+ __ LoadImmediate(temp1, offset);
+ __ add(IP, addr, ShifterOperand(temp1));
+ addr = IP;
+ }
+ __ Bind(&fail);
+ // We need a load followed by store. (The address used in a STREX instruction must
+ // be the same as the address in the most recently executed LDREX instruction.)
+ __ ldrexd(temp1, temp2, addr);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ strexd(temp1, value_lo, value_hi, addr);
+ __ cmp(temp1, ShifterOperand(0));
+ __ b(&fail, NE);
+}
+
+void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
+ DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
+
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
- bool needs_write_barrier =
- CodeGenerator::StoreNeedsWriteBarrier(instruction->GetFieldType(), instruction->GetValue());
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
+
+
+ Primitive::Type field_type = field_info.GetFieldType();
+ bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
+ bool generate_volatile = field_info.IsVolatile()
+ && is_wide
+ && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
// Temporary registers for the write barrier.
- if (needs_write_barrier) {
+ // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+ locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
+ } else if (generate_volatile) {
+ // Arm encoding have some additional constraints for ldrexd/strexd:
+ // - registers need to be consecutive
+ // - the first register should be even but not R14.
+ // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
+ // enable Arm encoding.
+ DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
+
locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ if (field_type == Primitive::kPrimDouble) {
+ // For doubles we need two more registers to copy the value.
+ locations->AddTemp(Location::RegisterLocation(R2));
+ locations->AddTemp(Location::RegisterLocation(R3));
+ }
}
}
-void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
+ const FieldInfo& field_info) {
+ DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
+
LocationSummary* locations = instruction->GetLocations();
- Register obj = locations->InAt(0).AsRegister<Register>();
- uint32_t offset = instruction->GetFieldOffset().Uint32Value();
- Primitive::Type field_type = instruction->GetFieldType();
+ Register base = locations->InAt(0).AsRegister<Register>();
+ Location value = locations->InAt(1);
+
+ bool is_volatile = field_info.IsVolatile();
+ bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
+ Primitive::Type field_type = field_info.GetFieldType();
+ uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+
+ if (is_volatile) {
+ GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
+ }
switch (field_type) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte: {
- Register value = locations->InAt(1).AsRegister<Register>();
- __ StoreToOffset(kStoreByte, value, obj, offset);
+ __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
break;
}
case Primitive::kPrimShort:
case Primitive::kPrimChar: {
- Register value = locations->InAt(1).AsRegister<Register>();
- __ StoreToOffset(kStoreHalfword, value, obj, offset);
+ __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
break;
}
case Primitive::kPrimInt:
case Primitive::kPrimNot: {
- Register value = locations->InAt(1).AsRegister<Register>();
- __ StoreToOffset(kStoreWord, value, obj, offset);
- if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
- Register temp = locations->GetTemp(0).AsRegister<Register>();
- Register card = locations->GetTemp(1).AsRegister<Register>();
- codegen_->MarkGCCard(temp, card, obj, value);
- }
+ __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
break;
}
case Primitive::kPrimLong: {
- Location value = locations->InAt(1);
- __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
+ if (is_volatile && !atomic_ldrd_strd) {
+ GenerateWideAtomicStore(base, offset,
+ value.AsRegisterPairLow<Register>(),
+ value.AsRegisterPairHigh<Register>(),
+ locations->GetTemp(0).AsRegister<Register>(),
+ locations->GetTemp(1).AsRegister<Register>(),
+ instruction);
+ } else {
+ __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ }
break;
}
case Primitive::kPrimFloat: {
- SRegister value = locations->InAt(1).AsFpuRegister<SRegister>();
- __ StoreSToOffset(value, obj, offset);
+ __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
break;
}
case Primitive::kPrimDouble: {
- DRegister value = FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>());
- __ StoreDToOffset(value, obj, offset);
+ DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
+ if (is_volatile && !atomic_ldrd_strd) {
+ Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
+ Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
+
+ __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
+
+ GenerateWideAtomicStore(base, offset,
+ value_reg_lo,
+ value_reg_hi,
+ locations->GetTemp(2).AsRegister<Register>(),
+ locations->GetTemp(3).AsRegister<Register>(),
+ instruction);
+ } else {
+ __ StoreDToOffset(value_reg, base, offset);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ }
break;
}
@@ -2625,75 +2730,160 @@ void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instr
LOG(FATAL) << "Unreachable type " << field_type;
UNREACHABLE();
}
+
+ // Longs and doubles are handled in the switch.
+ if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ }
+
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+ Register temp = locations->GetTemp(0).AsRegister<Register>();
+ Register card = locations->GetTemp(1).AsRegister<Register>();
+ codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+ }
+
+ if (is_volatile) {
+ GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
+ }
}
-void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
+ DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+
+ bool generate_volatile = field_info.IsVolatile()
+ && (field_info.GetFieldType() == Primitive::kPrimDouble)
+ && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
+ if (generate_volatile) {
+ // Arm encoding have some additional constraints for ldrexd/strexd:
+ // - registers need to be consecutive
+ // - the first register should be even but not R14.
+ // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
+ // enable Arm encoding.
+ DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
-void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
+ const FieldInfo& field_info) {
+ DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
+
LocationSummary* locations = instruction->GetLocations();
- Register obj = locations->InAt(0).AsRegister<Register>();
- uint32_t offset = instruction->GetFieldOffset().Uint32Value();
+ Register base = locations->InAt(0).AsRegister<Register>();
+ Location out = locations->Out();
+ bool is_volatile = field_info.IsVolatile();
+ bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
+ Primitive::Type field_type = field_info.GetFieldType();
+ uint32_t offset = field_info.GetFieldOffset().Uint32Value();
- switch (instruction->GetType()) {
+ switch (field_type) {
case Primitive::kPrimBoolean: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
+ __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
break;
}
case Primitive::kPrimByte: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
+ __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
break;
}
case Primitive::kPrimShort: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
+ __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
break;
}
case Primitive::kPrimChar: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
+ __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
break;
}
case Primitive::kPrimInt:
case Primitive::kPrimNot: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadWord, out, obj, offset);
+ __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
break;
}
case Primitive::kPrimLong: {
- // TODO: support volatile.
- Location out = locations->Out();
- __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
+ if (is_volatile && !atomic_ldrd_strd) {
+ GenerateWideAtomicLoad(base, offset,
+ out.AsRegisterPairLow<Register>(),
+ out.AsRegisterPairHigh<Register>());
+ } else {
+ __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
+ }
break;
}
case Primitive::kPrimFloat: {
- SRegister out = locations->Out().AsFpuRegister<SRegister>();
- __ LoadSFromOffset(out, obj, offset);
+ __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
break;
}
case Primitive::kPrimDouble: {
- DRegister out = FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>());
- __ LoadDFromOffset(out, obj, offset);
+ DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
+ if (is_volatile && !atomic_ldrd_strd) {
+ Register lo = locations->GetTemp(0).AsRegister<Register>();
+ Register hi = locations->GetTemp(1).AsRegister<Register>();
+ GenerateWideAtomicLoad(base, offset, lo, hi);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ vmovdrr(out_reg, lo, hi);
+ } else {
+ __ LoadDFromOffset(out_reg, base, offset);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ }
break;
}
case Primitive::kPrimVoid:
- LOG(FATAL) << "Unreachable type " << instruction->GetType();
+ LOG(FATAL) << "Unreachable type " << field_type;
UNREACHABLE();
}
+
+ // Doubles are handled in the switch.
+ if (field_type != Primitive::kPrimDouble) {
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ }
+
+ if (is_volatile) {
+ GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
+ }
+}
+
+void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+ HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+ HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+ HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+ HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+ HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+ HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+ HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+ HandleFieldSet(instruction, instruction->GetFieldInfo());
}
void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
@@ -2705,20 +2895,32 @@ void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
}
}
-void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
+void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
+ if (codegen_->CanMoveNullCheckToUser(instruction)) {
+ return;
+ }
+ Location obj = instruction->GetLocations()->InAt(0);
+
+ __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
+void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
codegen_->AddSlowPath(slow_path);
LocationSummary* locations = instruction->GetLocations();
Location obj = locations->InAt(0);
- if (obj.IsRegister()) {
- __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
- __ b(slow_path->GetEntryLabel(), EQ);
+ __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
+ __ b(slow_path->GetEntryLabel(), EQ);
+}
+
+void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
+ if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
+ GenerateImplicitNullCheck(instruction);
} else {
- DCHECK(obj.IsConstant()) << obj;
- DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
- __ b(slow_path->GetEntryLabel());
+ GenerateExplicitNullCheck(instruction);
}
}
@@ -2822,14 +3024,39 @@ void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
break;
}
- case Primitive::kPrimFloat:
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
- UNREACHABLE();
+ case Primitive::kPrimFloat: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
+ Location out = locations->Out();
+ DCHECK(out.IsFpuRegister());
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
+ __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimDouble: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
+ Location out = locations->Out();
+ DCHECK(out.IsFpuRegisterPair());
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+ __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
+ __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
+ }
+ break;
+ }
+
case Primitive::kPrimVoid:
LOG(FATAL) << "Unreachable type " << instruction->GetType();
UNREACHABLE();
}
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
}
void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
@@ -2913,6 +3140,7 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
__ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
__ StoreToOffset(kStoreWord, value, IP, data_offset);
}
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
if (needs_write_barrier) {
DCHECK_EQ(value_type, Primitive::kPrimNot);
Register temp = locations->GetTemp(0).AsRegister<Register>();
@@ -2942,14 +3170,44 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
break;
}
- case Primitive::kPrimFloat:
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
- UNREACHABLE();
+ case Primitive::kPrimFloat: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
+ Location value = locations->InAt(2);
+ DCHECK(value.IsFpuRegister());
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
+ __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimDouble: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
+ Location value = locations->InAt(2);
+ DCHECK(value.IsFpuRegisterPair());
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+ __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
+ __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
+ }
+
+ break;
+ }
+
case Primitive::kPrimVoid:
- LOG(FATAL) << "Unreachable type " << instruction->GetType();
+ LOG(FATAL) << "Unreachable type " << value_type;
UNREACHABLE();
}
+
+ // Ints and objects are handled in the switch.
+ if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ }
}
void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
@@ -2965,6 +3223,7 @@ void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
Register obj = locations->InAt(0).AsRegister<Register>();
Register out = locations->Out().AsRegister<Register>();
__ LoadFromOffset(kLoadWord, out, obj, offset);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
}
void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -3075,21 +3334,87 @@ void ParallelMoveResolverARM::EmitMove(size_t index) {
if (destination.IsRegister()) {
__ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
SP, source.GetStackIndex());
+ } else if (destination.IsFpuRegister()) {
+ __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
} else {
DCHECK(destination.IsStackSlot());
__ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
__ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
}
- } else {
- DCHECK(source.IsConstant());
- DCHECK(source.GetConstant()->IsIntConstant());
- int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
- if (destination.IsRegister()) {
- __ LoadImmediate(destination.AsRegister<Register>(), value);
+ } else if (source.IsFpuRegister()) {
+ if (destination.IsFpuRegister()) {
+ __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
} else {
DCHECK(destination.IsStackSlot());
- __ LoadImmediate(IP, value);
- __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+ __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
+ }
+ } else if (source.IsDoubleStackSlot()) {
+ DCHECK(destination.IsDoubleStackSlot()) << destination;
+ __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
+ __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+ __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize));
+ __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
+ } else {
+ DCHECK(source.IsConstant()) << source;
+ HInstruction* constant = source.GetConstant();
+ if (constant->IsIntConstant()) {
+ int32_t value = constant->AsIntConstant()->GetValue();
+ if (destination.IsRegister()) {
+ __ LoadImmediate(destination.AsRegister<Register>(), value);
+ } else {
+ DCHECK(destination.IsStackSlot());
+ __ LoadImmediate(IP, value);
+ __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+ }
+ } else if (constant->IsLongConstant()) {
+ int64_t value = constant->AsLongConstant()->GetValue();
+ if (destination.IsRegister()) {
+ // In the presence of long or double constants, the parallel move resolver will
+ // split the move into two, but keeps the same constant for both moves. Here,
+ // we use the low or high part depending on which register this move goes to.
+ if (destination.reg() % 2 == 0) {
+ __ LoadImmediate(destination.AsRegister<Register>(), Low32Bits(value));
+ } else {
+ __ LoadImmediate(destination.AsRegister<Register>(), High32Bits(value));
+ }
+ } else {
+ DCHECK(destination.IsDoubleStackSlot());
+ __ LoadImmediate(IP, Low32Bits(value));
+ __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+ __ LoadImmediate(IP, High32Bits(value));
+ __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
+ }
+ } else if (constant->IsDoubleConstant()) {
+ double value = constant->AsDoubleConstant()->GetValue();
+ uint64_t int_value = bit_cast<uint64_t, double>(value);
+ if (destination.IsFpuRegister()) {
+ // In the presence of long or double constants, the parallel move resolver will
+ // split the move into two, but keeps the same constant for both moves. Here,
+ // we use the low or high part depending on which register this move goes to.
+ if (destination.reg() % 2 == 0) {
+ __ LoadSImmediate(destination.AsFpuRegister<SRegister>(),
+ bit_cast<float, uint32_t>(Low32Bits(int_value)));
+ } else {
+ __ LoadSImmediate(destination.AsFpuRegister<SRegister>(),
+ bit_cast<float, uint32_t>(High32Bits(int_value)));
+ }
+ } else {
+ DCHECK(destination.IsDoubleStackSlot());
+ __ LoadImmediate(IP, Low32Bits(int_value));
+ __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+ __ LoadImmediate(IP, High32Bits(int_value));
+ __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
+ }
+ } else {
+ DCHECK(constant->IsFloatConstant()) << constant->DebugName();
+ float value = constant->AsFloatConstant()->GetValue();
+ if (destination.IsFpuRegister()) {
+ __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
+ } else {
+ DCHECK(destination.IsStackSlot());
+ __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
+ __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+ }
}
}
}
@@ -3128,8 +3453,25 @@ void ParallelMoveResolverARM::EmitSwap(size_t index) {
Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
} else if (source.IsStackSlot() && destination.IsStackSlot()) {
Exchange(source.GetStackIndex(), destination.GetStackIndex());
+ } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
+ __ vmovrs(IP, source.AsFpuRegister<SRegister>());
+ __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
+ __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
+ } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
+ SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
+ : destination.AsFpuRegister<SRegister>();
+ int mem = source.IsFpuRegister()
+ ? destination.GetStackIndex()
+ : source.GetStackIndex();
+
+ __ vmovrs(IP, reg);
+ __ LoadFromOffset(kLoadWord, IP, SP, mem);
+ __ StoreToOffset(kStoreWord, IP, SP, mem);
+ } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
+ Exchange(source.GetStackIndex(), destination.GetStackIndex());
+ Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
} else {
- LOG(FATAL) << "Unimplemented";
+ LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
}
}
@@ -3206,146 +3548,6 @@ void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
__ Bind(slow_path->GetExitLabel());
}
-void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
- LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
-}
-
-void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
- LocationSummary* locations = instruction->GetLocations();
- Register cls = locations->InAt(0).AsRegister<Register>();
- uint32_t offset = instruction->GetFieldOffset().Uint32Value();
-
- switch (instruction->GetType()) {
- case Primitive::kPrimBoolean: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadUnsignedByte, out, cls, offset);
- break;
- }
-
- case Primitive::kPrimByte: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadSignedByte, out, cls, offset);
- break;
- }
-
- case Primitive::kPrimShort: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadSignedHalfword, out, cls, offset);
- break;
- }
-
- case Primitive::kPrimChar: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadUnsignedHalfword, out, cls, offset);
- break;
- }
-
- case Primitive::kPrimInt:
- case Primitive::kPrimNot: {
- Register out = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(kLoadWord, out, cls, offset);
- break;
- }
-
- case Primitive::kPrimLong: {
- // TODO: support volatile.
- Location out = locations->Out();
- __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), cls, offset);
- break;
- }
-
- case Primitive::kPrimFloat: {
- SRegister out = locations->Out().AsFpuRegister<SRegister>();
- __ LoadSFromOffset(out, cls, offset);
- break;
- }
-
- case Primitive::kPrimDouble: {
- DRegister out = FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>());
- __ LoadDFromOffset(out, cls, offset);
- break;
- }
-
- case Primitive::kPrimVoid:
- LOG(FATAL) << "Unreachable type " << instruction->GetType();
- UNREACHABLE();
- }
-}
-
-void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
- LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
- bool needs_write_barrier =
- CodeGenerator::StoreNeedsWriteBarrier(instruction->GetFieldType(), instruction->GetValue());
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RequiresRegister());
- // Temporary registers for the write barrier.
- if (needs_write_barrier) {
- locations->AddTemp(Location::RequiresRegister());
- locations->AddTemp(Location::RequiresRegister());
- }
-}
-
-void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
- LocationSummary* locations = instruction->GetLocations();
- Register cls = locations->InAt(0).AsRegister<Register>();
- uint32_t offset = instruction->GetFieldOffset().Uint32Value();
- Primitive::Type field_type = instruction->GetFieldType();
-
- switch (field_type) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte: {
- Register value = locations->InAt(1).AsRegister<Register>();
- __ StoreToOffset(kStoreByte, value, cls, offset);
- break;
- }
-
- case Primitive::kPrimShort:
- case Primitive::kPrimChar: {
- Register value = locations->InAt(1).AsRegister<Register>();
- __ StoreToOffset(kStoreHalfword, value, cls, offset);
- break;
- }
-
- case Primitive::kPrimInt:
- case Primitive::kPrimNot: {
- Register value = locations->InAt(1).AsRegister<Register>();
- __ StoreToOffset(kStoreWord, value, cls, offset);
- if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
- Register temp = locations->GetTemp(0).AsRegister<Register>();
- Register card = locations->GetTemp(1).AsRegister<Register>();
- codegen_->MarkGCCard(temp, card, cls, value);
- }
- break;
- }
-
- case Primitive::kPrimLong: {
- Location value = locations->InAt(1);
- __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), cls, offset);
- break;
- }
-
- case Primitive::kPrimFloat: {
- SRegister value = locations->InAt(1).AsFpuRegister<SRegister>();
- __ StoreSToOffset(value, cls, offset);
- break;
- }
-
- case Primitive::kPrimDouble: {
- DRegister value = FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>());
- __ StoreDToOffset(value, cls, offset);
- break;
- }
-
- case Primitive::kPrimVoid:
- LOG(FATAL) << "Unreachable type " << field_type;
- UNREACHABLE();
- }
-}
-
void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
@@ -3495,7 +3697,9 @@ void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction)
|| instruction->GetResultType() == Primitive::kPrimLong);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
- bool output_overlaps = (instruction->GetResultType() == Primitive::kPrimLong);
+ Location::OutputOverlap output_overlaps = (instruction->GetResultType() == Primitive::kPrimLong)
+ ? Location::kOutputOverlap
+ : Location::kNoOutputOverlap;
locations->SetOut(Location::RequiresRegister(), output_overlaps);
}