diff options
Diffstat (limited to 'compiler/optimizing')
28 files changed, 1842 insertions, 544 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index b51b6e7d25..be8631ad42 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -568,12 +568,13 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, return true; } -void HGraphBuilder::BuildCheckedDiv(uint16_t out_vreg, - uint16_t first_vreg, - int64_t second_vreg_or_constant, - uint32_t dex_pc, - Primitive::Type type, - bool second_is_constant) { +void HGraphBuilder::BuildCheckedDivRem(uint16_t out_vreg, + uint16_t first_vreg, + int64_t second_vreg_or_constant, + uint32_t dex_pc, + Primitive::Type type, + bool second_is_constant, + bool isDiv) { DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong); HInstruction* first = LoadLocal(first_vreg, type); @@ -597,7 +598,11 @@ void HGraphBuilder::BuildCheckedDiv(uint16_t out_vreg, temps.Add(current_block_->GetLastInstruction()); } - current_block_->AddInstruction(new (arena_) HDiv(type, first, second, dex_pc)); + if (isDiv) { + current_block_->AddInstruction(new (arena_) HDiv(type, first, second, dex_pc)); + } else { + current_block_->AddInstruction(new (arena_) HRem(type, first, second, dex_pc)); + } UpdateLocal(out_vreg, current_block_->GetLastInstruction()); } @@ -997,6 +1002,16 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::INT_TO_FLOAT: { + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimFloat); + break; + } + + case Instruction::INT_TO_DOUBLE: { + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimDouble); + break; + } + case Instruction::LONG_TO_INT: { Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimInt); break; @@ -1007,6 +1022,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::INT_TO_SHORT: { + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimShort); + break; + } + case Instruction::INT_TO_CHAR: { Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimChar); break; @@ -1078,14 +1098,14 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::DIV_INT: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), - dex_pc, Primitive::kPrimInt, false); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimInt, false, true); break; } case Instruction::DIV_LONG: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), - dex_pc, Primitive::kPrimLong, false); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimLong, false, true); break; } @@ -1099,6 +1119,18 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::REM_INT: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimInt, false, false); + break; + } + + case Instruction::REM_LONG: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimLong, false, false); + break; + } + case Instruction::AND_INT: { Binop_23x<HAnd>(instruction, Primitive::kPrimInt); break; @@ -1185,14 +1217,26 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::DIV_INT_2ADDR: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), - dex_pc, Primitive::kPrimInt, false); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), + dex_pc, Primitive::kPrimInt, false, true); break; } case Instruction::DIV_LONG_2ADDR: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), - dex_pc, Primitive::kPrimLong, false); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), + dex_pc, Primitive::kPrimLong, false, true); + break; + } + + case Instruction::REM_INT_2ADDR: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), + dex_pc, Primitive::kPrimInt, false, false); + break; + } + + case Instruction::REM_LONG_2ADDR: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), + dex_pc, Primitive::kPrimLong, false, false); break; } @@ -1298,8 +1342,15 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::DIV_INT_LIT16: case Instruction::DIV_INT_LIT8: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), - dex_pc, Primitive::kPrimInt, true); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimInt, true, true); + break; + } + + case Instruction::REM_INT_LIT16: + case Instruction::REM_INT_LIT8: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimInt, true, false); break; } diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 799e628a78..897bcece7b 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -123,12 +123,13 @@ class HGraphBuilder : public ValueObject { Primitive::Type input_type, Primitive::Type result_type); - void BuildCheckedDiv(uint16_t out_reg, - uint16_t first_reg, - int64_t second_reg_or_constant, - uint32_t dex_pc, - Primitive::Type type, - bool second_is_lit); + void BuildCheckedDivRem(uint16_t out_reg, + uint16_t first_reg, + int64_t second_reg_or_constant, + uint32_t dex_pc, + Primitive::Type type, + bool second_is_lit, + bool is_div); void BuildReturn(const Instruction& instruction, Primitive::Type type); diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 4d71cb780a..0b593275c7 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -589,12 +589,14 @@ void CodeGenerator::SaveLiveRegisters(LocationSummary* locations) { if (locations->RegisterContainsObject(i)) { locations->SetStackBit(stack_offset / kVRegSize); } + DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize()); stack_offset += SaveCoreRegister(stack_offset, i); } } for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) { if (register_set->ContainsFloatingPointRegister(i)) { + DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize()); stack_offset += SaveFloatingPointRegister(stack_offset, i); } } @@ -605,12 +607,14 @@ void CodeGenerator::RestoreLiveRegisters(LocationSummary* locations) { size_t stack_offset = first_register_slot_in_slow_path_; for (size_t i = 0, e = GetNumberOfCoreRegisters(); i < e; ++i) { if (register_set->ContainsCoreRegister(i)) { + DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize()); stack_offset += RestoreCoreRegister(stack_offset, i); } } for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) { if (register_set->ContainsFloatingPointRegister(i)) { + DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize()); stack_offset += RestoreFloatingPointRegister(stack_offset, i); } } 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 09e1b97570..1701ef5f0a 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -80,7 +80,7 @@ class NullCheckSlowPathARM : public SlowPathCodeARM { public: explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {} - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); __ Bind(GetEntryLabel()); arm_codegen->InvokeRuntime( @@ -96,7 +96,7 @@ class DivZeroCheckSlowPathARM : public SlowPathCodeARM { public: explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {} - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); __ Bind(GetEntryLabel()); arm_codegen->InvokeRuntime( @@ -112,7 +112,7 @@ class StackOverflowCheckSlowPathARM : public SlowPathCodeARM { public: StackOverflowCheckSlowPathARM() {} - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { __ Bind(GetEntryLabel()); __ LoadFromOffset(kLoadWord, PC, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value()); @@ -124,10 +124,10 @@ class StackOverflowCheckSlowPathARM : public SlowPathCodeARM { class SuspendCheckSlowPathARM : public SlowPathCodeARM { public: - explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor) + SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor) : instruction_(instruction), successor_(successor) {} - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); __ Bind(GetEntryLabel()); codegen->SaveLiveRegisters(instruction_->GetLocations()); @@ -166,7 +166,7 @@ class BoundsCheckSlowPathARM : public SlowPathCodeARM { index_location_(index_location), length_location_(length_location) {} - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); __ Bind(GetEntryLabel()); // We're moving two locations to locations that could overlap, so we need a parallel @@ -199,7 +199,7 @@ class LoadClassSlowPathARM : public SlowPathCodeARM { DCHECK(at->IsLoadClass() || at->IsClinitCheck()); } - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = at_->GetLocations(); CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); @@ -245,7 +245,7 @@ class LoadStringSlowPathARM : public SlowPathCodeARM { public: explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {} - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); @@ -281,7 +281,7 @@ class TypeCheckSlowPathARM : public SlowPathCodeARM { object_class_(object_class), dex_pc_(dex_pc) {} - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); DCHECK(instruction_->IsCheckCast() || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); @@ -1188,7 +1188,8 @@ void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache())); // LR = temp[offset_of_quick_compiled_code] __ LoadFromOffset(kLoadWord, LR, temp, - mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()); + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kArmWordSize).Int32Value()); // LR() __ blx(LR); @@ -1229,7 +1230,8 @@ void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset); } // temp = temp->GetMethodAt(method_offset); - uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); + uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kArmWordSize).Int32Value(); __ LoadFromOffset(kLoadWord, temp, temp, method_offset); // LR = temp->GetEntryPoint(); __ LoadFromOffset(kLoadWord, LR, temp, entry_point); @@ -1265,7 +1267,8 @@ void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset); } // temp = temp->GetImtEntryAt(method_offset); - uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); + uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kArmWordSize).Int32Value(); __ LoadFromOffset(kLoadWord, temp, temp, method_offset); // LR = temp->GetEntryPoint(); __ LoadFromOffset(kLoadWord, LR, temp, entry_point); @@ -1367,6 +1370,22 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { } break; + case Primitive::kPrimShort: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-short' instruction. + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: @@ -1428,9 +1447,49 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-float' instruction. + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresFpuRegister()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; + break; + case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-double' instruction. + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresFpuRegister()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; break; default: @@ -1461,6 +1520,21 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio } break; + case Primitive::kPrimShort: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-short' instruction. + __ sbfx(out.As<Register>(), in.As<Register>(), 0, 16); + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: @@ -1535,9 +1609,52 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio break; case Primitive::kPrimFloat: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: { + // Processing a Dex `int-to-float' instruction. + __ vmovsr(out.As<SRegister>(), in.As<Register>()); + __ vcvtsi(out.As<SRegister>(), out.As<SRegister>()); + break; + } + + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; + break; + case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: { + // Processing a Dex `int-to-double' instruction. + __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.As<Register>()); + __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), + out.AsFpuRegisterPairLow<SRegister>()); + break; + } + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; break; default: @@ -1842,6 +1959,86 @@ void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) { } } +void LocationsBuilderARM::VisitRem(HRem* rem) { + LocationSummary::CallKind call_kind = rem->GetResultType() == Primitive::kPrimLong + ? LocationSummary::kCall + : LocationSummary::kNoCall; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); + + switch (rem->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + locations->AddTemp(Location::RequiresRegister()); + break; + } + case Primitive::kPrimLong: { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterPairLocation( + 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 R2,R3. + locations->SetOut(Location::RegisterPairLocation(R2, R3)); + break; + } + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + +void InstructionCodeGeneratorARM::VisitRem(HRem* rem) { + LocationSummary* locations = rem->GetLocations(); + Location out = locations->Out(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + + switch (rem->GetResultType()) { + case Primitive::kPrimInt: { + Register reg1 = first.As<Register>(); + Register reg2 = second.As<Register>(); + Register temp = locations->GetTemp(0).As<Register>(); + + // temp = reg1 / reg2 (integer division) + // temp = temp * reg2 + // dest = reg1 - temp + __ sdiv(temp, reg1, reg2); + __ mul(temp, temp, reg2); + __ sub(out.As<Register>(), reg1, ShifterOperand(temp)); + break; + } + + case Primitive::kPrimLong: { + InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); + DCHECK_EQ(R2, out.AsRegisterPairLow<Register>()); + DCHECK_EQ(R3, out.AsRegisterPairHigh<Register>()); + + codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc()); + break; + } + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); @@ -2034,11 +2231,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()); } @@ -2069,7 +2267,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); @@ -2302,10 +2500,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))); @@ -2314,6 +2516,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()); + } } } @@ -2322,6 +2530,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: @@ -2352,24 +2563,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); @@ -2718,11 +2937,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()); } @@ -2753,7 +2973,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_arm.h b/compiler/optimizing/code_generator_arm.h index acc3fd6a25..c00fac1a37 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -28,7 +28,8 @@ namespace arm { class CodeGeneratorARM; class SlowPathCodeARM; -static constexpr size_t kArmWordSize = 4; +// Use a local definition to prevent copying mistakes. +static constexpr size_t kArmWordSize = kArmPointerSize; static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 }; static constexpr RegisterPair kParameterCorePairRegisters[] = { R1_R2, R2_R3 }; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 887a4efa19..82dced5e4f 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -48,18 +48,28 @@ bool IsFPType(Primitive::Type type) { return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble; } +bool IsIntegralType(Primitive::Type type) { + switch (type) { + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimLong: + return true; + default: + return false; + } +} + bool Is64BitType(Primitive::Type type) { return type == Primitive::kPrimLong || type == Primitive::kPrimDouble; } // Convenience helpers to ease conversion to and from VIXL operands. +static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32), + "Unexpected values for register codes."); int VIXLRegCodeFromART(int code) { - // TODO: static check? - DCHECK_EQ(SP, 31); - DCHECK_EQ(WSP, 31); - DCHECK_EQ(XZR, 32); - DCHECK_EQ(WZR, 32); if (code == SP) { return vixl::kSPRegInternalCode; } @@ -70,11 +80,6 @@ int VIXLRegCodeFromART(int code) { } int ARTRegCodeFromVIXL(int code) { - // TODO: static check? - DCHECK_EQ(SP, 31); - DCHECK_EQ(WSP, 31); - DCHECK_EQ(XZR, 32); - DCHECK_EQ(WZR, 32); if (code == vixl::kSPRegInternalCode) { return SP; } @@ -128,6 +133,17 @@ FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) { instr->InputAt(input_index)->GetType()); } +CPURegister OutputCPURegister(HInstruction* instr) { + return IsFPType(instr->GetType()) ? static_cast<CPURegister>(OutputFPRegister(instr)) + : static_cast<CPURegister>(OutputRegister(instr)); +} + +CPURegister InputCPURegisterAt(HInstruction* instr, int index) { + return IsFPType(instr->InputAt(index)->GetType()) + ? static_cast<CPURegister>(InputFPRegisterAt(instr, index)) + : static_cast<CPURegister>(InputRegisterAt(instr, index)); +} + int64_t Int64ConstantFrom(Location location) { HConstant* instr = location.GetConstant(); return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue() @@ -151,14 +167,18 @@ MemOperand StackOperandFrom(Location location) { return MemOperand(sp, location.GetStackIndex()); } -MemOperand HeapOperand(const Register& base, Offset offset) { +MemOperand HeapOperand(const Register& base, size_t offset) { // A heap reference must be 32bit, so fit in a W register. DCHECK(base.IsW()); - return MemOperand(base.X(), offset.SizeValue()); + return MemOperand(base.X(), offset); } -MemOperand HeapOperandFrom(Location location, Primitive::Type type, Offset offset) { - return HeapOperand(RegisterFrom(location, type), offset); +MemOperand HeapOperand(const Register& base, Offset offset) { + return HeapOperand(base, offset.SizeValue()); +} + +MemOperand HeapOperandFrom(Location location, Offset offset) { + return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset); } Location LocationFrom(const Register& reg) { @@ -227,7 +247,8 @@ Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type retur return ARM64ReturnLocation(return_type); } -#define __ reinterpret_cast<Arm64Assembler*>(codegen->GetAssembler())->vixl_masm_-> +#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()-> +#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value() class SlowPathCodeARM64 : public SlowPathCode { public: @@ -245,45 +266,125 @@ class SlowPathCodeARM64 : public SlowPathCode { class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 { public: - explicit BoundsCheckSlowPathARM64(HBoundsCheck* instruction, - Location index_location, - Location length_location) - : instruction_(instruction), - index_location_(index_location), - length_location_(length_location) {} - - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { - CodeGeneratorARM64* arm64_codegen = reinterpret_cast<CodeGeneratorARM64*>(codegen); + BoundsCheckSlowPathARM64() {} + + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { __ Bind(GetEntryLabel()); + __ Brk(__LINE__); // TODO: Unimplemented BoundsCheckSlowPathARM64. + } + + private: + DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64); +}; + +class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 { + public: + explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {} + + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); + __ Bind(GetEntryLabel()); + arm64_codegen->InvokeRuntime( + QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc()); + } + + private: + HDivZeroCheck* const instruction_; + DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64); +}; + +class LoadClassSlowPathARM64 : public SlowPathCodeARM64 { + public: + LoadClassSlowPathARM64(HLoadClass* cls, + HInstruction* at, + uint32_t dex_pc, + bool do_clinit) + : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { + DCHECK(at->IsLoadClass() || at->IsClinitCheck()); + } + + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + LocationSummary* locations = at_->GetLocations(); + CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); + + __ Bind(GetEntryLabel()); + codegen->SaveLiveRegisters(locations); + InvokeRuntimeCallingConvention calling_convention; - arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(0)), - index_location_, Primitive::kPrimInt); - arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(1)), - length_location_, Primitive::kPrimInt); - size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowArrayBounds).SizeValue(); - __ Ldr(lr, MemOperand(tr, offset)); - __ Blr(lr); - codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); + __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex()); + arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W()); + int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage) + : QUICK_ENTRY_POINT(pInitializeType); + arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_); + + // Move the class to the desired location. + Location out = locations->Out(); + if (out.IsValid()) { + DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg())); + Primitive::Type type = at_->GetType(); + arm64_codegen->MoveHelper(out, calling_convention.GetReturnLocation(type), type); + } + + codegen->RestoreLiveRegisters(locations); + __ B(GetExitLabel()); } private: - HBoundsCheck* const instruction_; - const Location index_location_; - const Location length_location_; + // The class this slow path will load. + HLoadClass* const cls_; - DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64); + // The instruction where this slow path is happening. + // (Might be the load class or an initialization check). + HInstruction* const at_; + + // The dex PC of `at_`. + const uint32_t dex_pc_; + + // Whether to initialize the class. + const bool do_clinit_; + + DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64); +}; + +class LoadStringSlowPathARM64 : public SlowPathCodeARM64 { + public: + explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {} + + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + LocationSummary* locations = instruction_->GetLocations(); + DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); + + __ Bind(GetEntryLabel()); + codegen->SaveLiveRegisters(locations); + + InvokeRuntimeCallingConvention calling_convention; + arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0).W()); + __ Mov(calling_convention.GetRegisterAt(1).W(), instruction_->GetStringIndex()); + arm64_codegen->InvokeRuntime( + QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc()); + Primitive::Type type = instruction_->GetType(); + arm64_codegen->MoveHelper(locations->Out(), calling_convention.GetReturnLocation(type), type); + + codegen->RestoreLiveRegisters(locations); + __ B(GetExitLabel()); + } + + private: + HLoadString* const instruction_; + + DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64); }; class NullCheckSlowPathARM64 : public SlowPathCodeARM64 { public: explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {} - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); __ Bind(GetEntryLabel()); - int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowNullPointer).Int32Value(); - __ Ldr(lr, MemOperand(tr, offset)); - __ Blr(lr); - codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); + arm64_codegen->InvokeRuntime( + QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc()); } private: @@ -298,13 +399,18 @@ class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 { HBasicBlock* successor) : instruction_(instruction), successor_(successor) {} - virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { - size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pTestSuspend).SizeValue(); + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); __ Bind(GetEntryLabel()); - __ Ldr(lr, MemOperand(tr, offset)); - __ Blr(lr); - codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); - __ B(GetReturnLabel()); + codegen->SaveLiveRegisters(instruction_->GetLocations()); + arm64_codegen->InvokeRuntime( + QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc()); + codegen->RestoreLiveRegisters(instruction_->GetLocations()); + if (successor_ == nullptr) { + __ B(GetReturnLabel()); + } else { + __ B(arm64_codegen->GetLabelOf(successor_)); + } } vixl::Label* GetReturnLabel() { @@ -324,6 +430,20 @@ class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 { DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64); }; +class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 { + public: + TypeCheckSlowPathARM64() {} + + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + __ Bind(GetEntryLabel()); + __ Brk(__LINE__); // TODO: Unimplemented TypeCheckSlowPathARM64. + __ b(GetExitLabel()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64); +}; + #undef __ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) { @@ -356,11 +476,12 @@ CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph) location_builder_(graph, this), instruction_visitor_(graph, this) {} -#define __ reinterpret_cast<Arm64Assembler*>(GetAssembler())->vixl_masm_-> +#undef __ +#define __ GetVIXLAssembler()-> void CodeGeneratorARM64::GenerateFrameEntry() { // TODO: Add proper support for the stack overflow check. - UseScratchRegisterScope temps(assembler_.vixl_masm_); + UseScratchRegisterScope temps(GetVIXLAssembler()); Register temp = temps.AcquireX(); __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64))); __ Ldr(temp, MemOperand(temp, 0)); @@ -378,7 +499,7 @@ void CodeGeneratorARM64::GenerateFrameEntry() { // ... : other preserved registers. // sp[frame_size - regs_size]: first preserved register. // ... : reserved frame space. - // sp[0] : context pointer. + // sp[0] : current method. } void CodeGeneratorARM64::GenerateFrameExit() { @@ -413,7 +534,7 @@ void CodeGeneratorARM64::Move(HInstruction* instruction, __ Mov(dst, value); } else { DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot()); - UseScratchRegisterScope temps(assembler_.vixl_masm_); + UseScratchRegisterScope temps(GetVIXLAssembler()); Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX(); __ Mov(temp, value); __ Str(temp, StackOperandFrom(location)); @@ -465,7 +586,7 @@ Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const { } void CodeGeneratorARM64::MarkGCCard(Register object, Register value) { - UseScratchRegisterScope temps(assembler_.vixl_masm_); + UseScratchRegisterScope temps(GetVIXLAssembler()); Register card = temps.AcquireX(); Register temp = temps.AcquireX(); vixl::Label done; @@ -522,6 +643,19 @@ void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg stream << Arm64ManagedRegister::FromDRegister(DRegister(reg)); } +void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) { + if (constant->IsIntConstant() || constant->IsLongConstant()) { + __ Mov(Register(destination), + constant->IsIntConstant() ? constant->AsIntConstant()->GetValue() + : constant->AsLongConstant()->GetValue()); + } else if (constant->IsFloatConstant()) { + __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue()); + } else { + DCHECK(constant->IsDoubleConstant()); + __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue()); + } +} + void CodeGeneratorARM64::MoveHelper(Location destination, Location source, Primitive::Type type) { @@ -544,13 +678,7 @@ void CodeGeneratorARM64::MoveHelper(Location destination, } else if (source.IsFpuRegister()) { __ Fmov(dst, FPRegisterFrom(source, type)); } else { - HConstant* cst = source.GetConstant(); - if (cst->IsFloatConstant()) { - __ Fmov(dst, cst->AsFloatConstant()->GetValue()); - } else { - DCHECK(cst->IsDoubleConstant()); - __ Fmov(dst, cst->AsDoubleConstant()->GetValue()); - } + MoveConstant(dst, source.GetConstant()); } } else { DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot()); @@ -558,8 +686,21 @@ void CodeGeneratorARM64::MoveHelper(Location destination, __ Str(RegisterFrom(source, type), StackOperandFrom(destination)); } else if (source.IsFpuRegister()) { __ Str(FPRegisterFrom(source, type), StackOperandFrom(destination)); + } else if (source.IsConstant()) { + UseScratchRegisterScope temps(GetVIXLAssembler()); + HConstant* cst = source.GetConstant(); + CPURegister temp; + if (cst->IsIntConstant() || cst->IsLongConstant()) { + temp = cst->IsIntConstant() ? temps.AcquireW() : temps.AcquireX(); + } else { + DCHECK(cst->IsFloatConstant() || cst->IsDoubleConstant()); + temp = cst->IsFloatConstant() ? temps.AcquireS() : temps.AcquireD(); + } + MoveConstant(temp, cst); + __ Str(temp, StackOperandFrom(destination)); } else { - UseScratchRegisterScope temps(assembler_.vixl_masm_); + DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot()); + UseScratchRegisterScope temps(GetVIXLAssembler()); Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW(); __ Ldr(temp, StackOperandFrom(source)); __ Str(temp, StackOperandFrom(destination)); @@ -568,61 +709,89 @@ void CodeGeneratorARM64::MoveHelper(Location destination, } void CodeGeneratorARM64::Load(Primitive::Type type, - vixl::Register dst, + vixl::CPURegister dst, const vixl::MemOperand& src) { switch (type) { case Primitive::kPrimBoolean: - __ Ldrb(dst, src); + __ Ldrb(Register(dst), src); break; case Primitive::kPrimByte: - __ Ldrsb(dst, src); + __ Ldrsb(Register(dst), src); break; case Primitive::kPrimShort: - __ Ldrsh(dst, src); + __ Ldrsh(Register(dst), src); break; case Primitive::kPrimChar: - __ Ldrh(dst, src); + __ Ldrh(Register(dst), src); break; case Primitive::kPrimInt: case Primitive::kPrimNot: case Primitive::kPrimLong: - DCHECK(dst.Is64Bits() == (type == Primitive::kPrimLong)); - __ Ldr(dst, src); - break; case Primitive::kPrimFloat: case Primitive::kPrimDouble: + DCHECK(dst.Is64Bits() == Is64BitType(type)); + __ Ldr(dst, src); + break; case Primitive::kPrimVoid: LOG(FATAL) << "Unreachable type " << type; } } void CodeGeneratorARM64::Store(Primitive::Type type, - vixl::Register rt, + vixl::CPURegister rt, const vixl::MemOperand& dst) { switch (type) { case Primitive::kPrimBoolean: case Primitive::kPrimByte: - __ Strb(rt, dst); + __ Strb(Register(rt), dst); break; case Primitive::kPrimChar: case Primitive::kPrimShort: - __ Strh(rt, dst); + __ Strh(Register(rt), dst); break; case Primitive::kPrimInt: case Primitive::kPrimNot: case Primitive::kPrimLong: - DCHECK(rt.Is64Bits() == (type == Primitive::kPrimLong)); - __ Str(rt, dst); - break; case Primitive::kPrimFloat: case Primitive::kPrimDouble: + DCHECK(rt.Is64Bits() == Is64BitType(type)); + __ Str(rt, dst); + break; case Primitive::kPrimVoid: LOG(FATAL) << "Unreachable type " << type; } } -#undef __ -#define __ GetAssembler()->vixl_masm_-> +void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) { + DCHECK(current_method.IsW()); + __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset)); +} + +void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset, + HInstruction* instruction, + uint32_t dex_pc) { + __ Ldr(lr, MemOperand(tr, entry_point_offset)); + __ Blr(lr); + RecordPcInfo(instruction, dex_pc); + DCHECK(instruction->IsSuspendCheck() + || instruction->IsBoundsCheck() + || instruction->IsNullCheck() + || instruction->IsDivZeroCheck() + || !IsLeafMethod()); +} + +void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path, + vixl::Register class_reg) { + UseScratchRegisterScope temps(GetVIXLAssembler()); + Register temp = temps.AcquireW(); + __ Ldr(temp, HeapOperand(class_reg, mirror::Class::StatusOffset())); + __ Cmp(temp, mirror::Class::kStatusInitialized); + __ B(lt, slow_path->GetEntryLabel()); + // Even if the initialized flag is set, we may be in a situation where caches are not synced + // properly. Therefore, we do a memory fence. + __ Dmb(InnerShareable, BarrierAll); + __ Bind(slow_path->GetExitLabel()); +} InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, CodeGeneratorARM64* codegen) @@ -631,27 +800,14 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, codegen_(codegen) {} #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ - M(And) \ - M(CheckCast) \ - M(ClinitCheck) \ - M(DivZeroCheck) \ - M(InstanceOf) \ - M(InvokeInterface) \ - M(LoadClass) \ - M(LoadException) \ - M(LoadString) \ - M(MonitorOperation) \ - M(Or) \ M(ParallelMove) \ - M(StaticFieldGet) \ - M(StaticFieldSet) \ - M(Throw) \ - M(TypeConversion) \ - M(Xor) \ + M(Rem) #define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode enum UnimplementedInstructionBreakCode { + // Using a base helps identify when we hit such breakpoints. + UnimplementedInstructionBreakCodeBaseCode = 0x900, #define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name), FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION) #undef ENUM_UNIMPLEMENTED_INSTRUCTION @@ -670,9 +826,9 @@ enum UnimplementedInstructionBreakCode { #undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS #undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE +#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION -void LocationsBuilderARM64::HandleAddSub(HBinaryOperation* instr) { - DCHECK(instr->IsAdd() || instr->IsSub()); +void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) { DCHECK_EQ(instr->InputCount(), 2U); LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); Primitive::Type type = instr->GetResultType(); @@ -688,7 +844,7 @@ void LocationsBuilderARM64::HandleAddSub(HBinaryOperation* instr) { case Primitive::kPrimDouble: locations->SetInAt(0, Location::RequiresFpuRegister()); locations->SetInAt(1, Location::RequiresFpuRegister()); - locations->SetOut(Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); break; default: @@ -696,9 +852,7 @@ void LocationsBuilderARM64::HandleAddSub(HBinaryOperation* instr) { } } -void InstructionCodeGeneratorARM64::HandleAddSub(HBinaryOperation* instr) { - DCHECK(instr->IsAdd() || instr->IsSub()); - +void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) { Primitive::Type type = instr->GetType(); switch (type) { @@ -709,8 +863,15 @@ void InstructionCodeGeneratorARM64::HandleAddSub(HBinaryOperation* instr) { Operand rhs = InputOperandAt(instr, 1); if (instr->IsAdd()) { __ Add(dst, lhs, rhs); - } else { + } else if (instr->IsAnd()) { + __ And(dst, lhs, rhs); + } else if (instr->IsOr()) { + __ Orr(dst, lhs, rhs); + } else if (instr->IsSub()) { __ Sub(dst, lhs, rhs); + } else { + DCHECK(instr->IsXor()); + __ Eor(dst, lhs, rhs); } break; } @@ -721,22 +882,32 @@ void InstructionCodeGeneratorARM64::HandleAddSub(HBinaryOperation* instr) { FPRegister rhs = InputFPRegisterAt(instr, 1); if (instr->IsAdd()) { __ Fadd(dst, lhs, rhs); - } else { + } else if (instr->IsSub()) { __ Fsub(dst, lhs, rhs); + } else { + LOG(FATAL) << "Unexpected floating-point binary operation"; } break; } default: - LOG(FATAL) << "Unexpected add/sub type " << type; + LOG(FATAL) << "Unexpected binary operation type " << type; } } void LocationsBuilderARM64::VisitAdd(HAdd* instruction) { - HandleAddSub(instruction); + HandleBinaryOp(instruction); } void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) { - HandleAddSub(instruction); + HandleBinaryOp(instruction); +} + +void LocationsBuilderARM64::VisitAnd(HAnd* instruction) { + HandleBinaryOp(instruction); +} + +void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) { + HandleBinaryOp(instruction); } void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) { @@ -751,11 +922,10 @@ void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) { LocationSummary* locations = instruction->GetLocations(); Primitive::Type type = instruction->GetType(); Register obj = InputRegisterAt(instruction, 0); - Register out = OutputRegister(instruction); Location index = locations->InAt(1); size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value(); MemOperand source(obj); - UseScratchRegisterScope temps(GetAssembler()->vixl_masm_); + UseScratchRegisterScope temps(GetVIXLAssembler()); if (index.IsConstant()) { offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type); @@ -767,7 +937,7 @@ void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) { source = MemOperand(temp, offset); } - codegen_->Load(type, out, source); + codegen_->Load(type, OutputCPURegister(instruction), source); } void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) { @@ -801,18 +971,16 @@ void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) { void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) { Primitive::Type value_type = instruction->GetComponentType(); if (value_type == Primitive::kPrimNot) { - __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAputObject).Int32Value())); - __ Blr(lr); - codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); - DCHECK(!codegen_->IsLeafMethod()); + codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc()); + } else { LocationSummary* locations = instruction->GetLocations(); Register obj = InputRegisterAt(instruction, 0); - Register value = InputRegisterAt(instruction, 2); + CPURegister value = InputCPURegisterAt(instruction, 2); Location index = locations->InAt(1); size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value(); MemOperand destination(obj); - UseScratchRegisterScope temps(GetAssembler()->vixl_masm_); + UseScratchRegisterScope temps(GetVIXLAssembler()); if (index.IsConstant()) { offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type); @@ -828,6 +996,66 @@ void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) { } } +void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + if (instruction->HasUses()) { + locations->SetOut(Location::SameAsFirstInput()); + } +} + +void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) { + BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(); + codegen_->AddSlowPath(slow_path); + + __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1)); + __ B(slow_path->GetEntryLabel(), hs); +} + +void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( + instruction, LocationSummary::kCallOnSlowPath); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); +} + +void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { + UseScratchRegisterScope temps(GetVIXLAssembler()); + Register obj = InputRegisterAt(instruction, 0);; + Register cls = InputRegisterAt(instruction, 1);; + Register temp = temps.AcquireW(); + + SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(); + codegen_->AddSlowPath(slow_path); + + // TODO: avoid this check if we know obj is not null. + __ Cbz(obj, slow_path->GetExitLabel()); + // Compare the class of `obj` with `cls`. + __ Ldr(temp, HeapOperand(obj, mirror::Object::ClassOffset())); + __ Cmp(temp, cls); + __ B(ne, slow_path->GetEntryLabel()); + __ Bind(slow_path->GetExitLabel()); +} + +void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath); + locations->SetInAt(0, Location::RequiresRegister()); + if (check->HasUses()) { + locations->SetOut(Location::SameAsFirstInput()); + } +} + +void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) { + // We assume the class is not null. + SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64( + check->GetLoadClass(), check, check->GetDexPc(), true); + codegen_->AddSlowPath(slow_path); + GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0)); +} + void LocationsBuilderARM64::VisitCompare(HCompare* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); @@ -846,7 +1074,7 @@ void InstructionCodeGeneratorARM64::VisitCompare(HCompare* instruction) { Register result = OutputRegister(instruction); Register left = InputRegisterAt(instruction, 0); Operand right = InputOperandAt(instruction, 1); - __ Subs(result, left, right); + __ Subs(result.X(), left, right); __ B(eq, &done); __ Mov(result, 1); __ Cneg(result, result, le); @@ -893,6 +1121,7 @@ void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) { void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } \ void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS) +#undef DEFINE_CONDITION_VISITORS #undef FOR_EACH_CONDITION_INSTRUCTION void LocationsBuilderARM64::VisitDiv(HDiv* div) { @@ -936,6 +1165,33 @@ void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) { } } +void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); + if (instruction->HasUses()) { + locations->SetOut(Location::SameAsFirstInput()); + } +} + +void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) { + SlowPathCodeARM64* slow_path = + new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction); + codegen_->AddSlowPath(slow_path); + Location value = instruction->GetLocations()->InAt(0); + + if (value.IsConstant()) { + int64_t divisor = Int64ConstantFrom(value); + if (divisor == 0) { + __ B(slow_path->GetEntryLabel()); + } else { + LOG(FATAL) << "Divisions by non-null constants should have been optimized away."; + } + } else { + __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel()); + } +} + void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); @@ -955,7 +1211,7 @@ void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) { UNUSED(exit); if (kIsDebugBuild) { down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable"); - __ Brk(0); // TODO: Introduce special markers for such code locations. + __ Brk(__LINE__); // TODO: Introduce special markers for such code locations. } } @@ -1038,7 +1294,7 @@ void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { MemOperand field = MemOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset().Uint32Value()); - codegen_->Load(instruction->GetType(), OutputRegister(instruction), field); + codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field); } void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { @@ -1049,12 +1305,54 @@ void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { Primitive::Type field_type = instruction->GetFieldType(); - Register value = InputRegisterAt(instruction, 1); + CPURegister value = InputCPURegisterAt(instruction, 1); Register obj = InputRegisterAt(instruction, 0); codegen_->Store(field_type, value, MemOperand(obj, instruction->GetFieldOffset().Uint32Value())); if (field_type == Primitive::kPrimNot) { - codegen_->MarkGCCard(obj, value); + codegen_->MarkGCCard(obj, Register(value)); + } +} + +void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) { + LocationSummary::CallKind call_kind = + instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), true); // The output does overlap inputs. +} + +void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Register obj = InputRegisterAt(instruction, 0);; + Register cls = InputRegisterAt(instruction, 1);; + Register out = OutputRegister(instruction); + + vixl::Label done; + + // Return 0 if `obj` is null. + // TODO: Avoid this check if we know `obj` is not null. + __ Mov(out, 0); + __ Cbz(obj, &done); + + // Compare the class of `obj` with `cls`. + __ Ldr(out, MemOperand(obj, mirror::Object::ClassOffset().Int32Value())); + __ Cmp(out, cls); + if (instruction->IsClassFinal()) { + // Classes must be equal for the instanceof to succeed. + __ Cset(out, eq); + } else { + // If the classes are not equal, we go into a slow path. + DCHECK(locations->OnlyCallsOnSlowPath()); + SlowPathCodeARM64* slow_path = + new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(); + codegen_->AddSlowPath(slow_path); + __ B(ne, slow_path->GetEntryLabel()); + __ Mov(out, 1); + __ Bind(slow_path->GetExitLabel()); } + + __ Bind(&done); } void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) { @@ -1067,14 +1365,6 @@ void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) { UNUSED(constant); } -void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) { - HandleInvoke(invoke); -} - -void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { - HandleInvoke(invoke); -} - void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); @@ -1092,6 +1382,50 @@ void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) { } } +void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) { + HandleInvoke(invoke); +} + +void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) { + // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. + Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0)); + uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + + (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); + Location receiver = invoke->GetLocations()->InAt(0); + Offset class_offset = mirror::Object::ClassOffset(); + Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize); + + // The register ip1 is required to be used for the hidden argument in + // art_quick_imt_conflict_trampoline, so prevent VIXL from using it. + UseScratchRegisterScope scratch_scope(GetVIXLAssembler()); + scratch_scope.Exclude(ip1); + __ Mov(ip1, invoke->GetDexMethodIndex()); + + // temp = object->GetClass(); + if (receiver.IsStackSlot()) { + __ Ldr(temp, StackOperandFrom(receiver)); + __ Ldr(temp, HeapOperand(temp, class_offset)); + } else { + __ Ldr(temp, HeapOperandFrom(receiver, class_offset)); + } + // temp = temp->GetImtEntryAt(method_offset); + __ Ldr(temp, HeapOperand(temp, method_offset)); + // lr = temp->GetEntryPoint(); + __ Ldr(lr, HeapOperand(temp, entry_point)); + // lr(); + __ Blr(lr); + DCHECK(!codegen_->IsLeafMethod()); + codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); +} + +void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { + HandleInvoke(invoke); +} + +void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) { + HandleInvoke(invoke); +} + void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) { Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0)); // Make sure that ArtMethod* is passed in W0 as per the calling convention @@ -1107,7 +1441,7 @@ void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) { // Currently we implement the app -> app logic, which looks up in the resolve cache. // temp = method; - __ Ldr(temp, MemOperand(sp, kCurrentMethodStackOffset)); + codegen_->LoadCurrentMethod(temp); // temp = temp->dex_cache_resolved_methods_; __ Ldr(temp, MemOperand(temp.X(), mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue())); @@ -1115,7 +1449,8 @@ void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) { __ Ldr(temp, MemOperand(temp.X(), index_in_cache)); // lr = temp->entry_point_from_quick_compiled_code_; __ Ldr(lr, MemOperand(temp.X(), - mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue())); + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kArm64WordSize).SizeValue())); // lr(); __ Blr(lr); @@ -1130,7 +1465,7 @@ void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() + invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry); Offset class_offset = mirror::Object::ClassOffset(); - Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(); + Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize); // temp = object->GetClass(); if (receiver.IsStackSlot()) { @@ -1138,8 +1473,7 @@ void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { __ Ldr(temp.W(), MemOperand(temp, class_offset.SizeValue())); } else { DCHECK(receiver.IsRegister()); - __ Ldr(temp.W(), HeapOperandFrom(receiver, Primitive::kPrimNot, - class_offset)); + __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset)); } // temp = temp->GetMethodAt(method_offset); __ Ldr(temp.W(), MemOperand(temp, method_offset)); @@ -1151,6 +1485,50 @@ void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) { + LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath + : LocationSummary::kNoCall; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); + locations->SetOut(Location::RequiresRegister()); +} + +void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { + Register out = OutputRegister(cls); + if (cls->IsReferrersClass()) { + DCHECK(!cls->CanCallRuntime()); + DCHECK(!cls->MustGenerateClinitCheck()); + codegen_->LoadCurrentMethod(out); + __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset())); + } else { + DCHECK(cls->CanCallRuntime()); + codegen_->LoadCurrentMethod(out); + __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset())); + __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); + + SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64( + cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); + codegen_->AddSlowPath(slow_path); + __ Cbz(out, slow_path->GetEntryLabel()); + if (cls->MustGenerateClinitCheck()) { + GenerateClassInitializationCheck(slow_path, out); + } else { + __ Bind(slow_path->GetExitLabel()); + } + } +} + +void LocationsBuilderARM64::VisitLoadException(HLoadException* load) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall); + locations->SetOut(Location::RequiresRegister()); +} + +void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) { + MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value()); + __ Ldr(OutputRegister(instruction), exception); + __ Str(wzr, exception); +} + void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) { load->SetLocations(nullptr); } @@ -1160,6 +1538,24 @@ void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) { UNUSED(load); } +void LocationsBuilderARM64::VisitLoadString(HLoadString* load) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath); + locations->SetOut(Location::RequiresRegister()); +} + +void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) { + SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load); + codegen_->AddSlowPath(slow_path); + + Register out = OutputRegister(load); + codegen_->LoadCurrentMethod(out); + __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheStringsOffset())); + __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(load->GetStringIndex()))); + __ Cbz(out, slow_path->GetEntryLabel()); + __ Bind(slow_path->GetExitLabel()); +} + void LocationsBuilderARM64::VisitLocal(HLocal* local) { local->SetLocations(nullptr); } @@ -1178,6 +1574,20 @@ void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) { UNUSED(constant); } +void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); +} + +void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) { + codegen_->InvokeRuntime(instruction->IsEnter() + ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject), + instruction, + instruction->GetDexPc()); +} + void LocationsBuilderARM64::VisitMul(HMul* mul) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall); @@ -1193,7 +1603,7 @@ void LocationsBuilderARM64::VisitMul(HMul* mul) { case Primitive::kPrimDouble: locations->SetInAt(0, Location::RequiresFpuRegister()); locations->SetInAt(1, Location::RequiresFpuRegister()); - locations->SetOut(Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); break; default: @@ -1223,15 +1633,15 @@ void LocationsBuilderARM64::VisitNeg(HNeg* neg) { new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); switch (neg->GetResultType()) { case Primitive::kPrimInt: - case Primitive::kPrimLong: { + case Primitive::kPrimLong: locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0))); - locations->SetOut(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; - } case Primitive::kPrimFloat: case Primitive::kPrimDouble: - LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); break; default: @@ -1248,7 +1658,7 @@ void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: - LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0)); break; default: @@ -1273,14 +1683,10 @@ void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) { DCHECK(type_index.Is(w0)); Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot); DCHECK(current_method.Is(w1)); - __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset)); + codegen_->LoadCurrentMethod(current_method); __ Mov(type_index, instruction->GetTypeIndex()); - int32_t quick_entrypoint_offset = - QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocArrayWithAccessCheck).Int32Value(); - __ Ldr(lr, MemOperand(tr, quick_entrypoint_offset)); - __ Blr(lr); - codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); - DCHECK(!codegen_->IsLeafMethod()); + codegen_->InvokeRuntime( + QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc()); } void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) { @@ -1298,14 +1704,10 @@ void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) DCHECK(type_index.Is(w0)); Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot); DCHECK(current_method.Is(w1)); - __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset)); + codegen_->LoadCurrentMethod(current_method); __ Mov(type_index, instruction->GetTypeIndex()); - int32_t quick_entrypoint_offset = - QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocObjectWithAccessCheck).Int32Value(); - __ Ldr(lr, MemOperand(tr, quick_entrypoint_offset)); - __ Blr(lr); - codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); - DCHECK(!codegen_->IsLeafMethod()); + codegen_->InvokeRuntime( + QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc()); } void LocationsBuilderARM64::VisitNot(HNot* instruction) { @@ -1354,6 +1756,14 @@ void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) { } } +void LocationsBuilderARM64::VisitOr(HOr* instruction) { + HandleBinaryOp(instruction); +} + +void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) { + HandleBinaryOp(instruction); +} + void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); @@ -1434,31 +1844,43 @@ void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) { } void LocationsBuilderARM64::VisitSub(HSub* instruction) { - HandleAddSub(instruction); + HandleBinaryOp(instruction); } void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) { - HandleAddSub(instruction); + HandleBinaryOp(instruction); } -void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) { +void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) { + Register cls = InputRegisterAt(instruction, 0); + uint32_t offset = instruction->GetFieldOffset().Uint32Value(); + codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), MemOperand(cls, offset)); +} + +void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RequiresRegister()); - if (instruction->HasUses()) { - locations->SetOut(Location::SameAsFirstInput()); - } } -void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) { - LocationSummary* locations = instruction->GetLocations(); - BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64( - instruction, locations->InAt(0), locations->InAt(1)); - codegen_->AddSlowPath(slow_path); +void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) { + CPURegister value = InputCPURegisterAt(instruction, 1); + Register cls = InputRegisterAt(instruction, 0); + uint32_t offset = instruction->GetFieldOffset().Uint32Value(); + Primitive::Type field_type = instruction->GetFieldType(); - __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1)); - __ B(slow_path->GetEntryLabel(), hs); + codegen_->Store(field_type, value, MemOperand(cls, offset)); + if (field_type == Primitive::kPrimNot) { + codegen_->MarkGCCard(cls, Register(value)); + } } void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) { @@ -1485,5 +1907,74 @@ void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) { UNUSED(temp); } +void LocationsBuilderARM64::VisitThrow(HThrow* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); +} + +void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) { + codegen_->InvokeRuntime( + QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc()); +} + +void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall); + Primitive::Type input_type = conversion->GetInputType(); + Primitive::Type result_type = conversion->GetResultType(); + if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) || + (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) { + LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type; + } + + if (IsFPType(input_type)) { + locations->SetInAt(0, Location::RequiresFpuRegister()); + } else { + locations->SetInAt(0, Location::RequiresRegister()); + } + + if (IsFPType(result_type)) { + locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); + } else { + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + } +} + +void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) { + Primitive::Type result_type = conversion->GetResultType(); + Primitive::Type input_type = conversion->GetInputType(); + + DCHECK_NE(input_type, result_type); + + if (IsIntegralType(result_type) && IsIntegralType(input_type)) { + int result_size = Primitive::ComponentSize(result_type); + int input_size = Primitive::ComponentSize(input_type); + int min_size = kBitsPerByte * std::min(result_size, input_size); + if ((result_type == Primitive::kPrimChar) || + ((input_type == Primitive::kPrimChar) && (result_size > input_size))) { + __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size); + } else { + __ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size); + } + return; + } + + LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type + << " to " << result_type; +} + +void LocationsBuilderARM64::VisitXor(HXor* instruction) { + HandleBinaryOp(instruction); +} + +void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) { + HandleBinaryOp(instruction); +} + +#undef __ +#undef QUICK_ENTRY_POINT + } // namespace arm64 } // namespace art diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 54e87f4d9c..a40f27fafa 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -29,8 +29,11 @@ namespace art { namespace arm64 { class CodeGeneratorARM64; +class SlowPathCodeARM64; + +// Use a local definition to prevent copying mistakes. +static constexpr size_t kArm64WordSize = kArm64PointerSize; -static constexpr size_t kArm64WordSize = 8; static const vixl::Register kParameterCoreRegisters[] = { vixl::x1, vixl::x2, vixl::x3, vixl::x4, vixl::x5, vixl::x6, vixl::x7 }; @@ -103,9 +106,11 @@ class InstructionCodeGeneratorARM64 : public HGraphVisitor { void LoadCurrentMethod(XRegister reg); Arm64Assembler* GetAssembler() const { return assembler_; } + vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; } private: - void HandleAddSub(HBinaryOperation* instr); + void GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path, vixl::Register class_reg); + void HandleBinaryOp(HBinaryOperation* instr); Arm64Assembler* const assembler_; CodeGeneratorARM64* const codegen_; @@ -124,7 +129,7 @@ class LocationsBuilderARM64 : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION private: - void HandleAddSub(HBinaryOperation* instr); + void HandleBinaryOp(HBinaryOperation* instr); void HandleInvoke(HInvoke* instr); CodeGeneratorARM64* const codegen_; @@ -162,9 +167,10 @@ class CodeGeneratorARM64 : public CodeGenerator { return kArm64WordSize; } - uintptr_t GetAddressOf(HBasicBlock* block ATTRIBUTE_UNUSED) const OVERRIDE { - UNIMPLEMENTED(INFO) << "TODO: GetAddressOf"; - return 0u; + uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE { + vixl::Label* block_entry_label = GetLabelOf(block); + DCHECK(block_entry_label->IsBound()); + return block_entry_label->location(); } size_t FrameEntrySpillSize() const OVERRIDE; @@ -172,6 +178,7 @@ class CodeGeneratorARM64 : public CodeGenerator { HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; } Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; } + vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; } // Emit a write barrier. void MarkGCCard(vixl::Register object, vixl::Register value); @@ -185,18 +192,18 @@ class CodeGeneratorARM64 : public CodeGenerator { Location GetStackLocation(HLoadLocal* load) const OVERRIDE; - size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE { + size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) { UNUSED(stack_index); UNUSED(reg_id); - UNIMPLEMENTED(INFO) << "TODO: SaveCoreRegister"; - return 0; + LOG(INFO) << "CodeGeneratorARM64::SaveCoreRegister()"; + return kArm64WordSize; } - size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE { + size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) { UNUSED(stack_index); UNUSED(reg_id); - UNIMPLEMENTED(INFO) << "TODO: RestoreCoreRegister"; - return 0; + LOG(INFO) << "CodeGeneratorARM64::RestoreCoreRegister()"; + return kArm64WordSize; } // The number of registers that can be allocated. The register allocator may @@ -226,9 +233,14 @@ class CodeGeneratorARM64 : public CodeGenerator { } // Code generation helpers. + void MoveConstant(vixl::CPURegister destination, HConstant* constant); void MoveHelper(Location destination, Location source, Primitive::Type type); - void Load(Primitive::Type type, vixl::Register dst, const vixl::MemOperand& src); - void Store(Primitive::Type type, vixl::Register rt, const vixl::MemOperand& dst); + void Load(Primitive::Type type, vixl::CPURegister dst, const vixl::MemOperand& src); + void Store(Primitive::Type type, vixl::CPURegister rt, const vixl::MemOperand& dst); + void LoadCurrentMethod(vixl::Register current_method); + + // Generate code to invoke a runtime entry point. + void InvokeRuntime(int32_t offset, HInstruction* instruction, uint32_t dex_pc); ParallelMoveResolver* GetMoveResolver() OVERRIDE { UNIMPLEMENTED(INFO) << "TODO: MoveResolver"; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 8a8fec2609..3c53cea0bf 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() @@ -100,19 +103,24 @@ class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 { DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86); }; -class DivMinusOneSlowPathX86 : public SlowPathCodeX86 { +class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 { public: - explicit DivMinusOneSlowPathX86(Register reg) : reg_(reg) {} + explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {} virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { __ Bind(GetEntryLabel()); - __ negl(reg_); + if (is_div_) { + __ negl(reg_); + } else { + __ movl(reg_, Immediate(0)); + } __ jmp(GetExitLabel()); } private: Register reg_; - DISALLOW_COPY_AND_ASSIGN(DivMinusOneSlowPathX86); + bool is_div_; + DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86); }; class StackOverflowCheckSlowPathX86 : public SlowPathCodeX86 { @@ -427,6 +435,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; @@ -1111,7 +1120,8 @@ void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) { // temp = temp[index_in_cache] __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache()))); // (temp + offset_of_quick_compiled_code)() - __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); + __ call(Address( + temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value())); DCHECK(!codegen_->IsLeafMethod()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); @@ -1175,7 +1185,8 @@ void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { // temp = temp->GetMethodAt(method_offset); __ movl(temp, Address(temp, method_offset)); // call temp->GetEntryPoint(); - __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); + __ call(Address( + temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value())); DCHECK(!codegen_->IsLeafMethod()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); @@ -1210,7 +1221,8 @@ void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) // temp = temp->GetImtEntryAt(method_offset); __ movl(temp, Address(temp, method_offset)); // call temp->GetEntryPoint(); - __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kX86WordSize).Int32Value())); DCHECK(!codegen_->IsLeafMethod()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); @@ -1306,6 +1318,22 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { } break; + case Primitive::kPrimShort: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-short' instruction. + locations->SetInAt(0, Location::Any()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: @@ -1367,9 +1395,49 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-float' instruction. + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresFpuRegister()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; + break; + case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-double' instruction. + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresFpuRegister()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } break; default: @@ -1408,6 +1476,29 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio } break; + case Primitive::kPrimShort: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-short' instruction. + if (in.IsRegister()) { + __ movsxw(out.As<Register>(), in.As<Register>()); + } else if (in.IsStackSlot()) { + __ movsxw(out.As<Register>(), Address(ESP, in.GetStackIndex())); + } else { + DCHECK(in.GetConstant()->IsIntConstant()); + int32_t value = in.GetConstant()->AsIntConstant()->GetValue(); + __ movl(out.As<Register>(), Immediate(static_cast<int16_t>(value))); + } + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: @@ -1486,9 +1577,47 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio break; case Primitive::kPrimFloat: + switch (input_type) { + // Processing a Dex `int-to-float' instruction. + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + __ cvtsi2ss(out.As<XmmRegister>(), in.As<Register>()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; + break; + case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + switch (input_type) { + // Processing a Dex `int-to-double' instruction. + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + __ cvtsi2sd(out.As<XmmRegister>(), in.As<Register>()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; break; default: @@ -1753,6 +1882,68 @@ void InstructionCodeGeneratorX86::VisitMul(HMul* mul) { } } +void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + + LocationSummary* locations = instruction->GetLocations(); + Location out = locations->Out(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + bool is_div = instruction->IsDiv(); + + switch (instruction->GetResultType()) { + case Primitive::kPrimInt: { + Register second_reg = second.As<Register>(); + DCHECK_EQ(EAX, first.As<Register>()); + DCHECK_EQ(is_div ? EAX : EDX, out.As<Register>()); + + SlowPathCodeX86* slow_path = + new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.As<Register>(), is_div); + codegen_->AddSlowPath(slow_path); + + // 0x80000000/-1 triggers an arithmetic exception! + // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so + // it's safe to just use negl instead of more complex comparisons. + + __ cmpl(second_reg, Immediate(-1)); + __ j(kEqual, slow_path->GetEntryLabel()); + + // edx:eax <- sign-extended of eax + __ cdq(); + // eax = quotient, edx = remainder + __ idivl(second_reg); + + __ Bind(slow_path->GetExitLabel()); + break; + } + + case Primitive::kPrimLong: { + InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); + DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>()); + DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>()); + + if (is_div) { + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv))); + } else { + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod))); + } + uint32_t dex_pc = is_div + ? instruction->AsDiv()->GetDexPc() + : instruction->AsRem()->GetDexPc(); + codegen_->RecordPcInfo(instruction, dex_pc); + + break; + } + + default: + LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType(); + } +} + void LocationsBuilderX86::VisitDiv(HDiv* div) { LocationSummary::CallKind call_kind = div->GetResultType() == Primitive::kPrimLong ? LocationSummary::kCall @@ -1798,45 +1989,9 @@ void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) { Location second = locations->InAt(1); switch (div->GetResultType()) { - case Primitive::kPrimInt: { - DCHECK(first.Equals(out)); - Register first_reg = first.As<Register>(); - Register second_reg = second.As<Register>(); - DCHECK_EQ(EAX, first_reg); - DCHECK_EQ(EDX, locations->GetTemp(0).As<Register>()); - - SlowPathCodeX86* slow_path = - new (GetGraph()->GetArena()) DivMinusOneSlowPathX86(first_reg); - codegen_->AddSlowPath(slow_path); - - // 0x80000000/-1 triggers an arithmetic exception! - // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so - // it's safe to just use negl instead of more complex comparisons. - - __ cmpl(second_reg, Immediate(-1)); - __ j(kEqual, slow_path->GetEntryLabel()); - - // edx:eax <- sign-extended of eax - __ cdq(); - // eax = quotient, edx = remainder - __ idivl(second_reg); - - __ Bind(slow_path->GetExitLabel()); - break; - } - + case Primitive::kPrimInt: case Primitive::kPrimLong: { - InvokeRuntimeCallingConvention calling_convention; - DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); - DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); - DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); - DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); - DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>()); - DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>()); - - __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv))); - codegen_->RecordPcInfo(div, div->GetDexPc()); - + GenerateDivRemIntegral(div); break; } @@ -1857,6 +2012,58 @@ void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) { } } +void LocationsBuilderX86::VisitRem(HRem* rem) { + LocationSummary::CallKind call_kind = rem->GetResultType() == Primitive::kPrimLong + ? LocationSummary::kCall + : LocationSummary::kNoCall; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); + + switch (rem->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, Location::RegisterLocation(EAX)); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RegisterLocation(EDX)); + break; + } + case Primitive::kPrimLong: { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); + locations->SetInAt(1, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); + // Runtime helper puts the result in EAX, EDX. + locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); + break; + } + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + +void InstructionCodeGeneratorX86::VisitRem(HRem* rem) { + Primitive::Type type = rem->GetResultType(); + switch (type) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + GenerateDivRemIntegral(rem); + break; + } + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << type; + break; + } + default: + LOG(FATAL) << "Unexpected rem type " << type; + } +} + void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); @@ -2081,7 +2288,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 @@ -2093,7 +2302,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)); @@ -2126,7 +2335,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); @@ -2372,11 +2581,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))); @@ -2395,6 +2613,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)); + } } } @@ -2404,6 +2628,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: @@ -2452,34 +2679,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()) { @@ -2844,7 +3082,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 @@ -2856,7 +3095,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)); @@ -2889,7 +3128,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.h b/compiler/optimizing/code_generator_x86.h index 841b28b158..0aff6cc493 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -25,7 +25,8 @@ namespace art { namespace x86 { -static constexpr size_t kX86WordSize = 4; +// Use a local definition to prevent copying mistakes. +static constexpr size_t kX86WordSize = kX86PointerSize; class CodeGeneratorX86; class SlowPathCodeX86; @@ -130,6 +131,7 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeX86* slow_path, Register class_reg); void HandleBitwiseOperation(HBinaryOperation* instruction); + void GenerateDivRemIntegral(HBinaryOperation* instruction); X86Assembler* const assembler_; CodeGeneratorX86* const codegen_; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 5aa1c4a6c8..97f5e5c7ac 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -106,26 +106,36 @@ class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 { DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64); }; -class DivMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 { +class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 { public: - explicit DivMinusOneSlowPathX86_64(Register reg, Primitive::Type type) - : reg_(reg), type_(type) {} + explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div) + : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {} virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { __ Bind(GetEntryLabel()); if (type_ == Primitive::kPrimInt) { - __ negl(CpuRegister(reg_)); + if (is_div_) { + __ negl(cpu_reg_); + } else { + __ movl(cpu_reg_, Immediate(0)); + } + } else { DCHECK_EQ(Primitive::kPrimLong, type_); - __ negq(CpuRegister(reg_)); + if (is_div_) { + __ negq(cpu_reg_); + } else { + __ movq(cpu_reg_, Immediate(0)); + } } __ jmp(GetExitLabel()); } private: - const Register reg_; + const CpuRegister cpu_reg_; const Primitive::Type type_; - DISALLOW_COPY_AND_ASSIGN(DivMinusOneSlowPathX86_64); + const bool is_div_; + DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64); }; class StackOverflowCheckSlowPathX86_64 : public SlowPathCodeX86_64 { @@ -1102,7 +1112,8 @@ void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) { // temp = temp[index_in_cache] __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache()))); // (temp + offset_of_quick_compiled_code)() - __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue())); + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kX86_64WordSize).SizeValue())); DCHECK(!codegen_->IsLeafMethod()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); @@ -1161,7 +1172,8 @@ void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) // temp = temp->GetMethodAt(method_offset); __ movl(temp, Address(temp, method_offset)); // call temp->GetEntryPoint(); - __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue())); + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kX86_64WordSize).SizeValue())); DCHECK(!codegen_->IsLeafMethod()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); @@ -1196,7 +1208,8 @@ void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invo // temp = temp->GetImtEntryAt(method_offset); __ movl(temp, Address(temp, method_offset)); // call temp->GetEntryPoint(); - __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue())); + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kX86_64WordSize).SizeValue())); DCHECK(!codegen_->IsLeafMethod()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); @@ -1304,6 +1317,22 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { } break; + case Primitive::kPrimShort: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-short' instruction. + locations->SetInAt(0, Location::Any()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: @@ -1367,9 +1396,49 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-float' instruction. + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresFpuRegister()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; + break; + case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-double' instruction. + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresFpuRegister()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } break; default: @@ -1409,6 +1478,30 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } break; + case Primitive::kPrimShort: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-short' instruction. + if (in.IsRegister()) { + __ movsxw(out.As<CpuRegister>(), in.As<CpuRegister>()); + } else if (in.IsStackSlot()) { + __ movsxw(out.As<CpuRegister>(), + Address(CpuRegister(RSP), in.GetStackIndex())); + } else { + DCHECK(in.GetConstant()->IsIntConstant()); + __ movl(out.As<CpuRegister>(), + Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue()))); + } + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: @@ -1488,9 +1581,47 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver break; case Primitive::kPrimFloat: + switch (input_type) { + // Processing a Dex `int-to-float' instruction. + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + __ cvtsi2ss(out.As<XmmRegister>(), in.As<CpuRegister>()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; + break; + case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + switch (input_type) { + // Processing a Dex `int-to-double' instruction. + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + __ cvtsi2sd(out.As<XmmRegister>(), in.As<CpuRegister>()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + LOG(FATAL) << "Type conversion from " << input_type + << " to " << result_type << " not yet implemented"; + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + }; break; default: @@ -1701,6 +1832,47 @@ void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) { } } +void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + Primitive::Type type = instruction->GetResultType(); + DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong); + + bool is_div = instruction->IsDiv(); + LocationSummary* locations = instruction->GetLocations(); + + CpuRegister out_reg = locations->Out().As<CpuRegister>(); + CpuRegister second_reg = locations->InAt(1).As<CpuRegister>(); + + DCHECK_EQ(RAX, locations->InAt(0).As<CpuRegister>().AsRegister()); + DCHECK_EQ(is_div ? RAX : RDX, out_reg.AsRegister()); + + SlowPathCodeX86_64* slow_path = + new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64( + out_reg.AsRegister(), type, is_div); + codegen_->AddSlowPath(slow_path); + + // 0x80000000(00000000)/-1 triggers an arithmetic exception! + // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000) + // so it's safe to just use negl instead of more complex comparisons. + + __ cmpl(second_reg, Immediate(-1)); + __ j(kEqual, slow_path->GetEntryLabel()); + + if (type == Primitive::kPrimInt) { + // edx:eax <- sign-extended of eax + __ cdq(); + // eax = quotient, edx = remainder + __ idivl(second_reg); + } else { + // rdx:rax <- sign-extended of rax + __ cqo(); + // rax = quotient, rdx = remainder + __ idivq(second_reg); + } + + __ Bind(slow_path->GetExitLabel()); +} + void LocationsBuilderX86_64::VisitDiv(HDiv* div) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall); @@ -1738,35 +1910,7 @@ void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) { switch (type) { case Primitive::kPrimInt: case Primitive::kPrimLong: { - CpuRegister first_reg = first.As<CpuRegister>(); - CpuRegister second_reg = second.As<CpuRegister>(); - DCHECK_EQ(RAX, first_reg.AsRegister()); - DCHECK_EQ(RDX, locations->GetTemp(0).As<CpuRegister>().AsRegister()); - - SlowPathCodeX86_64* slow_path = - new (GetGraph()->GetArena()) DivMinusOneSlowPathX86_64(first_reg.AsRegister(), type); - codegen_->AddSlowPath(slow_path); - - // 0x80000000(00000000)/-1 triggers an arithmetic exception! - // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000) - // so it's safe to just use negl instead of more complex comparisons. - - __ cmpl(second_reg, Immediate(-1)); - __ j(kEqual, slow_path->GetEntryLabel()); - - if (type == Primitive::kPrimInt) { - // edx:eax <- sign-extended of eax - __ cdq(); - // eax = quotient, edx = remainder - __ idivl(second_reg); - } else { - // rdx:rax <- sign-extended of rax - __ cqo(); - // rax = quotient, rdx = remainder - __ idivq(second_reg); - } - - __ Bind(slow_path->GetExitLabel()); + GenerateDivRemIntegral(div); break; } @@ -1785,6 +1929,50 @@ void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) { } } +void LocationsBuilderX86_64::VisitRem(HRem* rem) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall); + switch (rem->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + locations->SetInAt(0, Location::RegisterLocation(RAX)); + locations->SetInAt(1, Location::RequiresRegister()); + // Intel uses rdx:rax as the dividend and puts the remainder in rdx + locations->SetOut(Location::RegisterLocation(RDX)); + break; + } + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + +void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) { + Primitive::Type type = rem->GetResultType(); + switch (type) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + GenerateDivRemIntegral(rem); + break; + } + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); @@ -1946,10 +2134,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()); @@ -1981,7 +2170,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); @@ -2231,10 +2420,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))); @@ -2251,6 +2444,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()); + } } } @@ -2260,6 +2459,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: @@ -2292,13 +2494,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())); } @@ -2306,35 +2511,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()) { @@ -2813,10 +3030,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()); @@ -2848,7 +3066,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/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 4c6e4750d7..29c679d8f1 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -25,7 +25,8 @@ namespace art { namespace x86_64 { -static constexpr size_t kX86_64WordSize = 8; +// Use a local definition to prevent copying mistakes. +static constexpr size_t kX86_64WordSize = kX86_64PointerSize; static constexpr Register kParameterCoreRegisters[] = { RSI, RDX, RCX, R8, R9 }; static constexpr FloatRegister kParameterFloatRegisters[] = @@ -134,6 +135,7 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor { void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg); void HandleBitwiseOperation(HBinaryOperation* operation); + void GenerateDivRemIntegral(HBinaryOperation* instruction); X86_64Assembler* const assembler_; CodeGeneratorX86_64* const codegen_; diff --git a/compiler/optimizing/constant_folding.h b/compiler/optimizing/constant_folding.h index d2acfa6973..ac00824e33 100644 --- a/compiler/optimizing/constant_folding.h +++ b/compiler/optimizing/constant_folding.h @@ -32,10 +32,10 @@ namespace art { */ class HConstantFolding : public HOptimization { public: - HConstantFolding(HGraph* graph, const HGraphVisualizer& visualizer) - : HOptimization(graph, true, kConstantFoldingPassName, visualizer) {} + explicit HConstantFolding(HGraph* graph) + : HOptimization(graph, true, kConstantFoldingPassName) {} - virtual void Run() OVERRIDE; + void Run() OVERRIDE; static constexpr const char* kConstantFoldingPassName = "constant_folding"; diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc index 856c5165a3..a56b9d9a12 100644 --- a/compiler/optimizing/constant_folding_test.cc +++ b/compiler/optimizing/constant_folding_test.cc @@ -47,8 +47,7 @@ static void TestCode(const uint16_t* data, ASSERT_EQ(expected_before, actual_before); x86::CodeGeneratorX86 codegen(graph); - HGraphVisualizer visualizer(nullptr, graph, codegen, ""); - HConstantFolding(graph, visualizer).Run(); + HConstantFolding(graph).Run(); SSAChecker ssa_checker(&allocator, graph); ssa_checker.Run(); ASSERT_TRUE(ssa_checker.IsValid()); @@ -60,7 +59,7 @@ static void TestCode(const uint16_t* data, check_after_cf(graph); - HDeadCodeElimination(graph, visualizer).Run(); + HDeadCodeElimination(graph).Run(); ssa_checker.Run(); ASSERT_TRUE(ssa_checker.IsValid()); diff --git a/compiler/optimizing/dead_code_elimination.h b/compiler/optimizing/dead_code_elimination.h index a4446ae04d..3db2c3ff3f 100644 --- a/compiler/optimizing/dead_code_elimination.h +++ b/compiler/optimizing/dead_code_elimination.h @@ -28,10 +28,10 @@ namespace art { */ class HDeadCodeElimination : public HOptimization { public: - HDeadCodeElimination(HGraph* graph, const HGraphVisualizer& visualizer) - : HOptimization(graph, true, kDeadCodeEliminationPassName, visualizer) {} + explicit HDeadCodeElimination(HGraph* graph) + : HOptimization(graph, true, kDeadCodeEliminationPassName) {} - virtual void Run() OVERRIDE; + void Run() OVERRIDE; static constexpr const char* kDeadCodeEliminationPassName = "dead_code_elimination"; diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc index 0c6807482a..5d4b9cb024 100644 --- a/compiler/optimizing/dead_code_elimination_test.cc +++ b/compiler/optimizing/dead_code_elimination_test.cc @@ -41,8 +41,7 @@ static void TestCode(const uint16_t* data, ASSERT_EQ(actual_before, expected_before); x86::CodeGeneratorX86 codegen(graph); - HGraphVisualizer visualizer(nullptr, graph, codegen, ""); - HDeadCodeElimination(graph, visualizer).Run(); + HDeadCodeElimination(graph).Run(); SSAChecker ssa_checker(&allocator, graph); ssa_checker.Run(); ASSERT_TRUE(ssa_checker.IsValid()); diff --git a/compiler/optimizing/gvn.h b/compiler/optimizing/gvn.h index 8d2c77475c..a841d5f65a 100644 --- a/compiler/optimizing/gvn.h +++ b/compiler/optimizing/gvn.h @@ -18,6 +18,7 @@ #define ART_COMPILER_OPTIMIZING_GVN_H_ #include "nodes.h" +#include "optimization.h" namespace art { @@ -165,11 +166,11 @@ class ValueSet : public ArenaObject<kArenaAllocMisc> { /** * Optimization phase that removes redundant instruction. */ -class GlobalValueNumberer : public ValueObject { +class GlobalValueNumberer : public HOptimization { public: GlobalValueNumberer(ArenaAllocator* allocator, HGraph* graph) - : allocator_(allocator), - graph_(graph), + : HOptimization(graph, true, "GVN"), + allocator_(allocator), block_effects_(allocator, graph->GetBlocks().Size()), loop_effects_(allocator, graph->GetBlocks().Size()), sets_(allocator, graph->GetBlocks().Size()), @@ -186,7 +187,7 @@ class GlobalValueNumberer : public ValueObject { } } - void Run(); + void Run() OVERRIDE; private: // Per-block GVN. Will also update the ValueSet of the dominated and @@ -202,7 +203,6 @@ class GlobalValueNumberer : public ValueObject { SideEffects GetBlockEffects(HBasicBlock* block) const; ArenaAllocator* const allocator_; - HGraph* const graph_; // Side effects of individual blocks, that is the union of the side effects // of the instructions in the block. diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 29eabe7e29..3d65e9a0a4 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -18,11 +18,22 @@ namespace art { +class InstructionSimplifierVisitor : public HGraphVisitor { + public: + explicit InstructionSimplifierVisitor(HGraph* graph) : HGraphVisitor(graph) {} + + private: + void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE; + void VisitEqual(HEqual* equal) OVERRIDE; + void VisitArraySet(HArraySet* equal) OVERRIDE; +}; + void InstructionSimplifier::Run() { - VisitInsertionOrder(); + InstructionSimplifierVisitor visitor(graph_); + visitor.VisitInsertionOrder(); } -void InstructionSimplifier::VisitSuspendCheck(HSuspendCheck* check) { +void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) { HBasicBlock* block = check->GetBlock(); // Currently always keep the suspend check at entry. if (block->IsEntryBlock()) return; @@ -38,7 +49,7 @@ void InstructionSimplifier::VisitSuspendCheck(HSuspendCheck* check) { block->RemoveInstruction(check); } -void InstructionSimplifier::VisitEqual(HEqual* equal) { +void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) { HInstruction* input1 = equal->InputAt(0); HInstruction* input2 = equal->InputAt(1); if (input1->GetType() == Primitive::kPrimBoolean && input2->IsIntConstant()) { @@ -55,4 +66,16 @@ void InstructionSimplifier::VisitEqual(HEqual* equal) { } } +void InstructionSimplifierVisitor::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..7068c7fc10 100644 --- a/compiler/optimizing/instruction_simplifier.h +++ b/compiler/optimizing/instruction_simplifier.h @@ -18,21 +18,19 @@ #define ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_H_ #include "nodes.h" +#include "optimization.h" namespace art { /** * Implements optimizations specific to each instruction. */ -class InstructionSimplifier : public HGraphVisitor { +class InstructionSimplifier : public HOptimization { public: - explicit InstructionSimplifier(HGraph* graph) : HGraphVisitor(graph) {} + explicit InstructionSimplifier(HGraph* graph) + : HOptimization(graph, true, "instruction_simplifier") {} - void Run(); - - private: - virtual void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE; - virtual void VisitEqual(HEqual* equal) OVERRIDE; + void Run() OVERRIDE; }; } // namespace art diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h index d1555d4e11..e1c8e8ed6e 100644 --- a/compiler/optimizing/locations.h +++ b/compiler/optimizing/locations.h @@ -391,6 +391,10 @@ class RegisterSet : public ValueObject { return (register_set & (1 << reg)) != 0; } + size_t GetNumberOfRegisters() const { + return __builtin_popcount(core_registers_) + __builtin_popcount(floating_point_registers_); + } + private: uint32_t core_registers_; uint32_t floating_point_registers_; @@ -503,6 +507,10 @@ class LocationSummary : public ArenaObject<kArenaAllocMisc> { return &live_registers_; } + size_t GetNumberOfLiveRegisters() const { + return live_registers_.GetNumberOfRegisters(); + } + bool InputOverlapsWithOutputOrTemp(uint32_t input_index, bool is_environment) const { if (is_environment) return true; if ((input_index == 0) diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 5af3cdd2d6..7d52d7d221 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -521,6 +521,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(ParallelMove, Instruction) \ M(ParameterValue, Instruction) \ M(Phi, Instruction) \ + M(Rem, BinaryOperation) \ M(Return, Instruction) \ M(ReturnVoid, Instruction) \ M(StaticFieldGet, Instruction) \ @@ -1756,10 +1757,15 @@ class HDiv : public HBinaryOperation { virtual int32_t Evaluate(int32_t x, int32_t y) const { // Our graph structure ensures we never have 0 for `y` during constant folding. DCHECK_NE(y, 0); - // Special case -1 to avoid getting a SIGFPE on x86. + // Special case -1 to avoid getting a SIGFPE on x86(_64). + return (y == -1) ? -x : x / y; + } + + virtual int64_t Evaluate(int64_t x, int64_t y) const { + DCHECK_NE(y, 0); + // Special case -1 to avoid getting a SIGFPE on x86(_64). return (y == -1) ? -x : x / y; } - virtual int64_t Evaluate(int64_t x, int64_t y) const { return x / y; } uint32_t GetDexPc() const { return dex_pc_; } @@ -1771,6 +1777,33 @@ class HDiv : public HBinaryOperation { DISALLOW_COPY_AND_ASSIGN(HDiv); }; +class HRem : public HBinaryOperation { + public: + HRem(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc) + : HBinaryOperation(result_type, left, right), dex_pc_(dex_pc) {} + + virtual int32_t Evaluate(int32_t x, int32_t y) const { + DCHECK_NE(y, 0); + // Special case -1 to avoid getting a SIGFPE on x86(_64). + return (y == -1) ? 0 : x % y; + } + + virtual int64_t Evaluate(int64_t x, int64_t y) const { + DCHECK_NE(y, 0); + // Special case -1 to avoid getting a SIGFPE on x86(_64). + return (y == -1) ? 0 : x % y; + } + + uint32_t GetDexPc() const { return dex_pc_; } + + DECLARE_INSTRUCTION(Rem); + + private: + const uint32_t dex_pc_; + + DISALLOW_COPY_AND_ASSIGN(HRem); +}; + class HDivZeroCheck : public HExpression<1> { public: HDivZeroCheck(HInstruction* value, uint32_t dex_pc) @@ -2034,6 +2067,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 +2085,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 +2110,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 +2151,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 +2420,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/optimization.cc b/compiler/optimizing/optimization.cc index ea98186d11..d1178d5798 100644 --- a/compiler/optimizing/optimization.cc +++ b/compiler/optimizing/optimization.cc @@ -21,12 +21,6 @@ namespace art { -void HOptimization::Execute() { - Run(); - visualizer_.DumpGraph(pass_name_); - Check(); -} - void HOptimization::Check() { if (kIsDebugBuild) { if (is_in_ssa_form_) { diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h index 59683e2075..d281248f4a 100644 --- a/compiler/optimizing/optimization.h +++ b/compiler/optimizing/optimization.h @@ -29,25 +29,19 @@ class HOptimization : public ValueObject { public: HOptimization(HGraph* graph, bool is_in_ssa_form, - const char* pass_name, - const HGraphVisualizer& visualizer) + const char* pass_name) : graph_(graph), is_in_ssa_form_(is_in_ssa_form), - pass_name_(pass_name), - visualizer_(visualizer) {} + pass_name_(pass_name) {} virtual ~HOptimization() {} - // Execute the optimization pass. - void Execute(); - // Return the name of the pass. const char* GetPassName() const { return pass_name_; } // Peform the analysis itself. virtual void Run() = 0; - private: // Verify the graph; abort if it is not valid. void Check(); @@ -59,9 +53,6 @@ class HOptimization : public ValueObject { const bool is_in_ssa_form_; // Optimization pass name. const char* pass_name_; - // A graph visualiser invoked after the execution of the optimization - // pass if enabled. - const HGraphVisualizer& visualizer_; DISALLOW_COPY_AND_ASSIGN(HOptimization); }; diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 6e3653a359..42ac77d1d8 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -26,9 +26,12 @@ #include "dead_code_elimination.h" #include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" +#include "elf_writer_quick.h" #include "graph_visualizer.h" #include "gvn.h" #include "instruction_simplifier.h" +#include "jni/quick/jni_compiler.h" +#include "mirror/art_method-inl.h" #include "nodes.h" #include "prepare_for_register_allocation.h" #include "register_allocator.h" @@ -88,15 +91,6 @@ class OptimizingCompiler FINAL : public Compiler { jobject class_loader, const DexFile& dex_file) const OVERRIDE; - CompiledMethod* TryCompile(const DexFile::CodeItem* code_item, - uint32_t access_flags, - InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const DexFile& dex_file) const; - - // For the following methods we will use the fallback. This is a delegation pattern. CompiledMethod* JniCompile(uint32_t access_flags, uint32_t method_idx, const DexFile& dex_file) const OVERRIDE; @@ -110,13 +104,16 @@ class OptimizingCompiler FINAL : public Compiler { const std::string& android_root, bool is_host) const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const OVERRIDE; + Backend* GetCodeGenerator(CompilationUnit* cu ATTRIBUTE_UNUSED, + void* compilation_unit ATTRIBUTE_UNUSED) const OVERRIDE { + return nullptr; + } - void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE; + void InitCompilationUnit(CompilationUnit& cu ATTRIBUTE_UNUSED) const OVERRIDE {} - void Init() const OVERRIDE; + void Init() const OVERRIDE {} - void UnInit() const OVERRIDE; + void UnInit() const OVERRIDE {} private: // Whether we should run any optimization or register allocation. If false, will @@ -128,10 +125,6 @@ class OptimizingCompiler FINAL : public Compiler { std::unique_ptr<std::ostream> visualizer_output_; - // Delegate to another compiler in case the optimizing compiler cannot compile a method. - // Currently the fallback is the quick compiler. - std::unique_ptr<Compiler> delegate_; - DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler); }; @@ -143,21 +136,12 @@ OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) driver->GetCompilerOptions().GetCompilerFilter() != CompilerOptions::kTime), total_compiled_methods_(0), unoptimized_compiled_methods_(0), - optimized_compiled_methods_(0), - delegate_(Create(driver, Compiler::Kind::kQuick)) { + optimized_compiled_methods_(0) { if (kIsVisualizerEnabled) { visualizer_output_.reset(new std::ofstream("art.cfg")); } } -void OptimizingCompiler::Init() const { - delegate_->Init(); -} - -void OptimizingCompiler::UnInit() const { - delegate_->UnInit(); -} - OptimizingCompiler::~OptimizingCompiler() { if (total_compiled_methods_ == 0) { LOG(INFO) << "Did not compile any method."; @@ -170,33 +154,28 @@ OptimizingCompiler::~OptimizingCompiler() { } } -bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, - CompilationUnit* cu) const { - return delegate_->CanCompileMethod(method_idx, dex_file, cu); +bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx ATTRIBUTE_UNUSED, + const DexFile& dex_file ATTRIBUTE_UNUSED, + CompilationUnit* cu ATTRIBUTE_UNUSED) const { + return true; } CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags, uint32_t method_idx, const DexFile& dex_file) const { - return delegate_->JniCompile(access_flags, method_idx, dex_file); + return ArtQuickJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file); } uintptr_t OptimizingCompiler::GetEntryPointOf(mirror::ArtMethod* method) const { - return delegate_->GetEntryPointOf(method); + return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCodePtrSize( + InstructionSetPointerSize(GetCompilerDriver()->GetInstructionSet()))); } bool OptimizingCompiler::WriteElf(art::File* file, OatWriter* oat_writer, const std::vector<const art::DexFile*>& dex_files, const std::string& android_root, bool is_host) const { - return delegate_->WriteElf(file, oat_writer, dex_files, android_root, is_host); -} - -Backend* OptimizingCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const { - return delegate_->GetCodeGenerator(cu, compilation_unit); -} - -void OptimizingCompiler::InitCompilationUnit(CompilationUnit& cu) const { - delegate_->InitCompilationUnit(cu); + return art::ElfWriterQuick32::Create(file, oat_writer, dex_files, android_root, is_host, + *GetCompilerDriver()); } static bool IsInstructionSetSupported(InstructionSet instruction_set) { @@ -211,13 +190,32 @@ static bool CanOptimize(const DexFile::CodeItem& code_item) { return code_item.tries_size_ == 0; } -CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item, - uint32_t access_flags, - InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const DexFile& dex_file) const { +static void RunOptimizations(HGraph* graph, const HGraphVisualizer& visualizer) { + HDeadCodeElimination opt1(graph); + HConstantFolding opt2(graph); + SsaRedundantPhiElimination opt3(graph); + SsaDeadPhiElimination opt4(graph); + InstructionSimplifier opt5(graph); + GlobalValueNumberer opt6(graph->GetArena(), graph); + InstructionSimplifier opt7(graph); + + HOptimization* optimizations[] = { &opt1, &opt2, &opt3, &opt4, &opt5, &opt6, &opt7 }; + + for (size_t i = 0; i < arraysize(optimizations); ++i) { + HOptimization* optimization = optimizations[i]; + optimization->Run(); + optimization->Check(); + visualizer.DumpGraph(optimization->GetPassName()); + } +} + +CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, + uint32_t access_flags, + InvokeType invoke_type, + uint16_t class_def_idx, + uint32_t method_idx, + jobject class_loader, + const DexFile& dex_file) const { UNUSED(invoke_type); total_compiled_methods_++; InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet(); @@ -278,16 +276,9 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite visualizer.DumpGraph("ssa"); graph->FindNaturalLoops(); - HDeadCodeElimination(graph, visualizer).Execute(); - HConstantFolding(graph, visualizer).Execute(); + RunOptimizations(graph, visualizer); - SsaRedundantPhiElimination(graph).Run(); - SsaDeadPhiElimination(graph).Run(); - InstructionSimplifier(graph).Run(); - GlobalValueNumberer(graph->GetArena(), graph).Run(); - visualizer.DumpGraph(kGVNPassName); PrepareForRegisterAllocation(graph).Run(); - SsaLivenessAnalysis liveness(*graph, codegen); liveness.Analyze(); visualizer.DumpGraph(kLivenessPassName); @@ -360,23 +351,6 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite } } -CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, - uint32_t access_flags, - InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const DexFile& dex_file) const { - CompiledMethod* method = TryCompile(code_item, access_flags, invoke_type, class_def_idx, - method_idx, class_loader, dex_file); - if (method != nullptr) { - return method; - } - - return delegate_->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx, - class_loader, dex_file); -} - Compiler* CreateOptimizingCompiler(CompilerDriver* driver) { return new OptimizingCompiler(driver); } diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index 4d6e66413d..2948496e15 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -215,9 +215,16 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { // By adding the following interval in the algorithm, we can compute this // maximum before updating locations. LiveInterval* interval = LiveInterval::MakeSlowPathInterval(allocator_, instruction); - interval->AddRange(position, position + 1); - unhandled_core_intervals_.Add(interval); - unhandled_fp_intervals_.Add(interval); + // The start of the interval must be after the position of the safepoint, so that + // we can just check the number of active registers at that position. Note that this + // will include the current interval in the computation of + // `maximum_number_of_live_registers`, so we need a better strategy if this becomes + // a problem. + // TODO: We could put the logic in AddSorted, to ensure the safepoint range is + // after all other intervals starting at that same position. + interval->AddRange(position + 1, position + 2); + AddSorted(&unhandled_core_intervals_, interval); + AddSorted(&unhandled_fp_intervals_, interval); } } @@ -250,6 +257,7 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { : unhandled_fp_intervals_; DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek())); + // Some instructions define their output in fixed register/stack slot. We need // to ensure we know these locations before doing register allocation. For a // given register, we create an interval that covers these locations. The register @@ -475,6 +483,17 @@ void RegisterAllocator::LinearScan() { LiveInterval* current = unhandled_->Pop(); DCHECK(!current->IsFixed() && !current->HasSpillSlot()); DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() >= current->GetStart()); + + if (current->IsSlowPathSafepoint()) { + // Synthesized interval to record the maximum number of live registers + // at safepoints. No need to allocate a register for it. + // We know that current actives are all live at the safepoint (modulo + // the one created by the safepoint). + maximum_number_of_live_registers_ = + std::max(maximum_number_of_live_registers_, active_.Size()); + continue; + } + size_t position = current->GetStart(); // Remember the inactive_ size here since the ones moved to inactive_ from @@ -515,14 +534,6 @@ void RegisterAllocator::LinearScan() { } } - if (current->IsSlowPathSafepoint()) { - // Synthesized interval to record the maximum number of live registers - // at safepoints. No need to allocate a register for it. - maximum_number_of_live_registers_ = - std::max(maximum_number_of_live_registers_, active_.Size()); - continue; - } - // (4) Try to find an available register. bool success = TryAllocateFreeReg(current); @@ -1062,6 +1073,7 @@ void RegisterAllocator::ConnectSiblings(LiveInterval* interval) { switch (source.GetKind()) { case Location::kRegister: { locations->AddLiveRegister(source); + DCHECK_LE(locations->GetNumberOfLiveRegisters(), maximum_number_of_live_registers_); if (current->GetType() == Primitive::kPrimNot) { locations->SetRegisterBit(source.reg()); } diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index fec40f93c7..b2cc11996e 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -183,8 +183,7 @@ static HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant) { static HPhi* GetFloatOrDoubleEquivalentOfPhi(HPhi* phi, Primitive::Type type) { // We place the floating point phi next to this phi. HInstruction* next = phi->GetNext(); - if (next == nullptr - || (next->GetType() != Primitive::kPrimDouble && next->GetType() != Primitive::kPrimFloat)) { + if (next == nullptr || (next->AsPhi()->GetRegNumber() != phi->GetRegNumber())) { ArenaAllocator* allocator = phi->GetBlock()->GetGraph()->GetArena(); HPhi* new_phi = new (allocator) HPhi(allocator, phi->GetRegNumber(), phi->InputCount(), type); for (size_t i = 0, e = phi->InputCount(); i < e; ++i) { @@ -195,9 +194,7 @@ static HPhi* GetFloatOrDoubleEquivalentOfPhi(HPhi* phi, Primitive::Type type) { phi->GetBlock()->InsertPhiAfter(new_phi, phi); return new_phi; } else { - // If there is already a phi with the expected type, we know it is the floating - // point equivalent of this phi. - DCHECK_EQ(next->AsPhi()->GetRegNumber(), phi->GetRegNumber()); + DCHECK_EQ(next->GetType(), type); return next->AsPhi(); } } diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h index 5274f09f3f..b7899712d6 100644 --- a/compiler/optimizing/ssa_phi_elimination.h +++ b/compiler/optimizing/ssa_phi_elimination.h @@ -18,6 +18,7 @@ #define ART_COMPILER_OPTIMIZING_SSA_PHI_ELIMINATION_H_ #include "nodes.h" +#include "optimization.h" namespace art { @@ -25,15 +26,15 @@ namespace art { * Optimization phase that removes dead phis from the graph. Dead phis are unused * phis, or phis only used by other phis. */ -class SsaDeadPhiElimination : public ValueObject { +class SsaDeadPhiElimination : public HOptimization { public: explicit SsaDeadPhiElimination(HGraph* graph) - : graph_(graph), worklist_(graph->GetArena(), kDefaultWorklistSize) {} + : HOptimization(graph, true, "dead_phi_elimination"), + worklist_(graph->GetArena(), kDefaultWorklistSize) {} - void Run(); + void Run() OVERRIDE; private: - HGraph* const graph_; GrowableArray<HPhi*> worklist_; static constexpr size_t kDefaultWorklistSize = 8; @@ -47,15 +48,15 @@ class SsaDeadPhiElimination : public ValueObject { * registers might be updated with the same value, or not updated at all. We can just * replace the phi with the value when entering the loop. */ -class SsaRedundantPhiElimination : public ValueObject { +class SsaRedundantPhiElimination : public HOptimization { public: explicit SsaRedundantPhiElimination(HGraph* graph) - : graph_(graph), worklist_(graph->GetArena(), kDefaultWorklistSize) {} + : HOptimization(graph, true, "redundant_phi_elimination"), + worklist_(graph->GetArena(), kDefaultWorklistSize) {} - void Run(); + void Run() OVERRIDE; private: - HGraph* const graph_; GrowableArray<HPhi*> worklist_; static constexpr size_t kDefaultWorklistSize = 8; diff --git a/compiler/optimizing/ssa_type_propagation.cc b/compiler/optimizing/ssa_type_propagation.cc index 3828142ed2..cb5ce20c46 100644 --- a/compiler/optimizing/ssa_type_propagation.cc +++ b/compiler/optimizing/ssa_type_propagation.cc @@ -90,10 +90,12 @@ void SsaTypePropagation::VisitBasicBlock(HBasicBlock* block) { } } else { for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { - HPhi* phi = it.Current()->AsPhi(); - if (UpdateType(phi)) { - AddDependentInstructionsToWorklist(phi); - } + // Eagerly compute the type of the phi, for quicker convergence. Note + // that we don't need to add users to the worklist because we are + // doing a reverse post-order visit, therefore either the phi users are + // non-loop phi and will be visited later in the visit, or are loop-phis, + // and they are already in the work list. + UpdateType(it.Current()->AsPhi()); } } } |