diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/code_generator.h | 9 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 67 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 94 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 92 | ||||
| -rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 12 | ||||
| -rw-r--r-- | compiler/optimizing/instruction_simplifier.h | 1 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 27 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 1 |
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); |