summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/code_generator.h9
-rw-r--r--compiler/optimizing/code_generator_arm.cc67
-rw-r--r--compiler/optimizing/code_generator_x86.cc94
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc92
-rw-r--r--compiler/optimizing/instruction_simplifier.cc12
-rw-r--r--compiler/optimizing/instruction_simplifier.h1
-rw-r--r--compiler/optimizing/nodes.h27
-rw-r--r--compiler/optimizing/optimizing_compiler.cc1
8 files changed, 216 insertions, 87 deletions
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 63bf96ca5a..f906eb8c05 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -168,6 +168,15 @@ class CodeGenerator : public ArenaObject<kArenaAllocMisc> {
void EmitParallelMoves(Location from1, Location to1, Location from2, Location to2);
+ static bool StoreNeedsWriteBarrier(Primitive::Type type, HInstruction* value) {
+ if (kIsDebugBuild) {
+ if (type == Primitive::kPrimNot && value->IsIntConstant()) {
+ CHECK_EQ(value->AsIntConstant()->GetValue(), 0);
+ }
+ }
+ return type == Primitive::kPrimNot && !value->IsIntConstant();
+ }
+
protected:
CodeGenerator(HGraph* graph,
size_t number_of_core_registers,
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index da51a37497..c17142d7c9 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2065,11 +2065,12 @@ void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
- bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
+ 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 (is_object_type) {
+ if (needs_write_barrier) {
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
}
@@ -2100,7 +2101,7 @@ void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instr
case Primitive::kPrimNot: {
Register value = locations->InAt(1).As<Register>();
__ StoreToOffset(kStoreWord, value, obj, offset);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
Register temp = locations->GetTemp(0).As<Register>();
Register card = locations->GetTemp(1).As<Register>();
codegen_->MarkGCCard(temp, card, obj, value);
@@ -2333,10 +2334,14 @@ void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Primitive::Type value_type = instruction->GetComponentType();
- bool is_object = value_type == Primitive::kPrimNot;
+
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+ bool needs_runtime_call = instruction->NeedsTypeCheck();
+
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
- instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
- if (is_object) {
+ instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+ if (needs_runtime_call) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
@@ -2345,6 +2350,12 @@ void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
locations->SetInAt(2, Location::RequiresRegister());
+
+ if (needs_write_barrier) {
+ // Temporary registers for the write barrier.
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
}
@@ -2353,6 +2364,9 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
Register obj = locations->InAt(0).As<Register>();
Location index = locations->InAt(1);
Primitive::Type value_type = instruction->GetComponentType();
+ bool needs_runtime_call = locations->WillCall();
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
switch (value_type) {
case Primitive::kPrimBoolean:
@@ -2383,24 +2397,32 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
break;
}
- case Primitive::kPrimInt: {
- uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
- Register value = locations->InAt(2).As<Register>();
- if (index.IsConstant()) {
- size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ StoreToOffset(kStoreWord, value, obj, offset);
+ case Primitive::kPrimInt:
+ case Primitive::kPrimNot: {
+ if (!needs_runtime_call) {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ Register value = locations->InAt(2).As<Register>();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ __ StoreToOffset(kStoreWord, value, obj, offset);
+ } else {
+ DCHECK(index.IsRegister()) << index;
+ __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
+ __ StoreToOffset(kStoreWord, value, IP, data_offset);
+ }
+ if (needs_write_barrier) {
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ Register temp = locations->GetTemp(0).As<Register>();
+ Register card = locations->GetTemp(1).As<Register>();
+ codegen_->MarkGCCard(temp, card, obj, value);
+ }
} else {
- __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
- __ StoreToOffset(kStoreWord, value, IP, data_offset);
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
}
break;
}
- case Primitive::kPrimNot: {
- codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
- break;
- }
-
case Primitive::kPrimLong: {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Location value = locations->InAt(2);
@@ -2749,11 +2771,12 @@ void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instructi
void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
- bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
+ 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 (is_object_type) {
+ if (needs_write_barrier) {
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
}
@@ -2784,7 +2807,7 @@ void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instructi
case Primitive::kPrimNot: {
Register value = locations->InAt(1).As<Register>();
__ StoreToOffset(kStoreWord, value, cls, offset);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
Register temp = locations->GetTemp(0).As<Register>();
Register card = locations->GetTemp(1).As<Register>();
codegen_->MarkGCCard(temp, card, cls, value);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index b6549b21c3..c486580216 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -42,6 +42,9 @@ static constexpr size_t kRuntimeParameterCoreRegistersLength =
static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { };
static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
+// Marker for places that can be updated once we don't follow the quick ABI.
+static constexpr bool kFollowsQuickABI = true;
+
class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> {
public:
InvokeRuntimeCallingConvention()
@@ -427,6 +430,7 @@ void CodeGeneratorX86::SetupBlockedRegisters() const {
blocked_core_registers_[ESP] = true;
// TODO: We currently don't use Quick's callee saved registers.
+ DCHECK(kFollowsQuickABI);
blocked_core_registers_[EBP] = true;
blocked_core_registers_[ESI] = true;
blocked_core_registers_[EDI] = true;
@@ -2120,7 +2124,9 @@ void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction)
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
Primitive::Type field_type = instruction->GetFieldType();
- bool is_object_type = field_type == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
+
bool is_byte_type = (field_type == Primitive::kPrimBoolean)
|| (field_type == Primitive::kPrimByte);
// The register allocator does not support multiple
@@ -2132,7 +2138,7 @@ void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction)
locations->SetInAt(1, Location::RequiresRegister());
}
// Temporary registers for the write barrier.
- if (is_object_type) {
+ if (needs_write_barrier) {
locations->AddTemp(Location::RequiresRegister());
// Ensure the card is in a byte register.
locations->AddTemp(Location::RegisterLocation(ECX));
@@ -2165,7 +2171,7 @@ void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instr
Register value = locations->InAt(1).As<Register>();
__ movl(Address(obj, offset), value);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Register temp = locations->GetTemp(0).As<Register>();
Register card = locations->GetTemp(1).As<Register>();
codegen_->MarkGCCard(temp, card, obj, value);
@@ -2411,11 +2417,20 @@ void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Primitive::Type value_type = instruction->GetComponentType();
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+
+ DCHECK(kFollowsQuickABI);
+ bool not_enough_registers = needs_write_barrier
+ && !instruction->GetValue()->IsConstant()
+ && !instruction->GetIndex()->IsConstant();
+ bool needs_runtime_call = instruction->NeedsTypeCheck() || not_enough_registers;
+
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
instruction,
- value_type == Primitive::kPrimNot ? LocationSummary::kCall : LocationSummary::kNoCall);
+ needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
- if (value_type == Primitive::kPrimNot) {
+ if (needs_runtime_call) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
@@ -2434,6 +2449,12 @@ void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
} else {
locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
}
+ // Temporary registers for the write barrier.
+ if (needs_write_barrier) {
+ locations->AddTemp(Location::RequiresRegister());
+ // Ensure the card is in a byte register.
+ locations->AddTemp(Location::RegisterLocation(ECX));
+ }
}
}
@@ -2443,6 +2464,9 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
Location index = locations->InAt(1);
Location value = locations->InAt(2);
Primitive::Type value_type = instruction->GetComponentType();
+ bool needs_runtime_call = locations->WillCall();
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
switch (value_type) {
case Primitive::kPrimBoolean:
@@ -2491,34 +2515,45 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
break;
}
- case Primitive::kPrimInt: {
- uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
- if (index.IsConstant()) {
- size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- if (value.IsRegister()) {
- __ movl(Address(obj, offset), value.As<Register>());
+ case Primitive::kPrimInt:
+ case Primitive::kPrimNot: {
+ if (!needs_runtime_call) {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ if (value.IsRegister()) {
+ __ movl(Address(obj, offset), value.As<Register>());
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ __ movl(Address(obj, offset),
+ Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ }
} else {
- __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ DCHECK(index.IsRegister()) << index;
+ if (value.IsRegister()) {
+ __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
+ value.As<Register>());
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
+ Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ }
}
- } else {
- if (value.IsRegister()) {
- __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
- value.As<Register>());
- } else {
- __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
- Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+
+ if (needs_write_barrier) {
+ Register temp = locations->GetTemp(0).As<Register>();
+ Register card = locations->GetTemp(1).As<Register>();
+ codegen_->MarkGCCard(temp, card, obj, value.As<Register>());
}
+ } else {
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ DCHECK(!codegen_->IsLeafMethod());
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
}
break;
}
- case Primitive::kPrimNot: {
- DCHECK(!codegen_->IsLeafMethod());
- __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
- codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
- break;
- }
-
case Primitive::kPrimLong: {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
if (index.IsConstant()) {
@@ -2883,7 +2918,8 @@ void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
Primitive::Type field_type = instruction->GetFieldType();
- bool is_object_type = field_type == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
bool is_byte_type = (field_type == Primitive::kPrimBoolean)
|| (field_type == Primitive::kPrimByte);
// The register allocator does not support multiple
@@ -2895,7 +2931,7 @@ void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
locations->SetInAt(1, Location::RequiresRegister());
}
// Temporary registers for the write barrier.
- if (is_object_type) {
+ if (needs_write_barrier) {
locations->AddTemp(Location::RequiresRegister());
// Ensure the card is in a byte register.
locations->AddTemp(Location::RegisterLocation(ECX));
@@ -2928,7 +2964,7 @@ void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instructi
Register value = locations->InAt(1).As<Register>();
__ movl(Address(cls, offset), value);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Register temp = locations->GetTemp(0).As<Register>();
Register card = locations->GetTemp(1).As<Register>();
codegen_->MarkGCCard(temp, card, cls, value);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index f7cdee9c68..735addba4b 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1986,10 +1986,11 @@ void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instructio
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Primitive::Type field_type = instruction->GetFieldType();
- bool is_object_type = field_type == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue());
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
- if (is_object_type) {
+ if (needs_write_barrier) {
// Temporary registers for the write barrier.
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
@@ -2021,7 +2022,7 @@ void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* in
case Primitive::kPrimNot: {
CpuRegister value = locations->InAt(1).As<CpuRegister>();
__ movl(Address(obj, offset), value);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
codegen_->MarkGCCard(temp, card, obj, value);
@@ -2271,10 +2272,14 @@ void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Primitive::Type value_type = instruction->GetComponentType();
- bool is_object = value_type == Primitive::kPrimNot;
+
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+ bool needs_runtime_call = instruction->NeedsTypeCheck();
+
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
- instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
- if (is_object) {
+ instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+ if (needs_runtime_call) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
@@ -2291,6 +2296,12 @@ void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
} else {
locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
}
+
+ if (needs_write_barrier) {
+ // Temporary registers for the write barrier.
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
}
@@ -2300,6 +2311,9 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
Location index = locations->InAt(1);
Location value = locations->InAt(2);
Primitive::Type value_type = instruction->GetComponentType();
+ bool needs_runtime_call = locations->WillCall();
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
switch (value_type) {
case Primitive::kPrimBoolean:
@@ -2332,13 +2346,16 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
if (value.IsRegister()) {
__ movw(Address(obj, offset), value.As<CpuRegister>());
} else {
+ DCHECK(value.IsConstant()) << value;
__ movw(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
}
} else {
+ DCHECK(index.IsRegister()) << index;
if (value.IsRegister()) {
__ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
value.As<CpuRegister>());
} else {
+ DCHECK(value.IsConstant()) << value;
__ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
}
@@ -2346,35 +2363,47 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
break;
}
- case Primitive::kPrimInt: {
- uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
- if (index.IsConstant()) {
- size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- if (value.IsRegister()) {
- __ movl(Address(obj, offset), value.As<CpuRegister>());
+ case Primitive::kPrimInt:
+ case Primitive::kPrimNot: {
+ if (!needs_runtime_call) {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ if (index.IsConstant()) {
+ size_t offset =
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ if (value.IsRegister()) {
+ __ movl(Address(obj, offset), value.As<CpuRegister>());
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ __ movl(Address(obj, offset),
+ Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ }
} else {
- __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ DCHECK(index.IsRegister()) << index;
+ if (value.IsRegister()) {
+ __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
+ value.As<CpuRegister>());
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
+ Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ }
}
- } else {
- if (value.IsRegister()) {
- __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
- value.As<CpuRegister>());
- } else {
- DCHECK(value.IsConstant()) << value;
- __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
- Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+
+ if (needs_write_barrier) {
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
+ CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
+ codegen_->MarkGCCard(temp, card, obj, value.As<CpuRegister>());
}
+ } else {
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
+ DCHECK(!codegen_->IsLeafMethod());
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
}
break;
}
- case Primitive::kPrimNot: {
- __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
- DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
- break;
- }
-
case Primitive::kPrimLong: {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
if (index.IsConstant()) {
@@ -2853,10 +2882,11 @@ void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Primitive::Type field_type = instruction->GetFieldType();
- bool is_object_type = field_type == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue());
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
- if (is_object_type) {
+ if (needs_write_barrier) {
// Temporary registers for the write barrier.
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
@@ -2888,7 +2918,7 @@ void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instru
case Primitive::kPrimNot: {
CpuRegister value = locations->InAt(1).As<CpuRegister>();
__ movl(Address(cls, offset), value);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
codegen_->MarkGCCard(temp, card, cls, value);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 29eabe7e29..3e8361eca1 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -55,4 +55,16 @@ void InstructionSimplifier::VisitEqual(HEqual* equal) {
}
}
+void InstructionSimplifier::VisitArraySet(HArraySet* instruction) {
+ HInstruction* value = instruction->GetValue();
+ if (value->GetType() != Primitive::kPrimNot) return;
+
+ if (value->IsArrayGet()) {
+ if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
+ // If the code is just swapping elements in the array, no need for a type check.
+ instruction->ClearNeedsTypeCheck();
+ }
+ }
+}
+
} // namespace art
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index d74b624518..3844d57439 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -33,6 +33,7 @@ class InstructionSimplifier : public HGraphVisitor {
private:
virtual void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
virtual void VisitEqual(HEqual* equal) OVERRIDE;
+ virtual void VisitArraySet(HArraySet* equal) OVERRIDE;
};
} // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 5af3cdd2d6..c1884828a8 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2034,6 +2034,8 @@ class HInstanceFieldSet : public HTemplateInstruction<2> {
MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+ HInstruction* GetValue() const { return InputAt(1); }
+
DECLARE_INSTRUCTION(InstanceFieldSet);
private:
@@ -2050,13 +2052,16 @@ class HArrayGet : public HExpression<2> {
SetRawInputAt(1, index);
}
- virtual bool CanBeMoved() const { return true; }
- virtual bool InstructionDataEquals(HInstruction* other) const {
+ bool CanBeMoved() const OVERRIDE { return true; }
+ bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
UNUSED(other);
return true;
}
void SetType(Primitive::Type type) { type_ = type; }
+ HInstruction* GetArray() const { return InputAt(0); }
+ HInstruction* GetIndex() const { return InputAt(1); }
+
DECLARE_INSTRUCTION(ArrayGet);
private:
@@ -2072,20 +2077,29 @@ class HArraySet : public HTemplateInstruction<3> {
uint32_t dex_pc)
: HTemplateInstruction(SideEffects::ChangesSomething()),
dex_pc_(dex_pc),
- expected_component_type_(expected_component_type) {
+ expected_component_type_(expected_component_type),
+ needs_type_check_(value->GetType() == Primitive::kPrimNot) {
SetRawInputAt(0, array);
SetRawInputAt(1, index);
SetRawInputAt(2, value);
}
- virtual bool NeedsEnvironment() const {
+ bool NeedsEnvironment() const {
// We currently always call a runtime method to catch array store
// exceptions.
- return InputAt(2)->GetType() == Primitive::kPrimNot;
+ return needs_type_check_;
+ }
+
+ void ClearNeedsTypeCheck() {
+ needs_type_check_ = false;
}
+ bool NeedsTypeCheck() const { return needs_type_check_; }
+
uint32_t GetDexPc() const { return dex_pc_; }
+ HInstruction* GetArray() const { return InputAt(0); }
+ HInstruction* GetIndex() const { return InputAt(1); }
HInstruction* GetValue() const { return InputAt(2); }
Primitive::Type GetComponentType() const {
@@ -2104,6 +2118,7 @@ class HArraySet : public HTemplateInstruction<3> {
private:
const uint32_t dex_pc_;
const Primitive::Type expected_component_type_;
+ bool needs_type_check_;
DISALLOW_COPY_AND_ASSIGN(HArraySet);
};
@@ -2372,6 +2387,8 @@ class HStaticFieldSet : public HTemplateInstruction<2> {
MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+ HInstruction* GetValue() const { return InputAt(1); }
+
DECLARE_INSTRUCTION(StaticFieldSet);
private:
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 6e3653a359..ee92e89ff5 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -286,6 +286,7 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite
InstructionSimplifier(graph).Run();
GlobalValueNumberer(graph->GetArena(), graph).Run();
visualizer.DumpGraph(kGVNPassName);
+ InstructionSimplifier(graph).Run();
PrepareForRegisterAllocation(graph).Run();
SsaLivenessAnalysis liveness(*graph, codegen);