diff options
Diffstat (limited to 'compiler')
22 files changed, 1686 insertions, 342 deletions
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index b35d51c46e..a0ad2133be 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -771,11 +771,11 @@ void MIRGraph::CombineBlocks(class BasicBlock* bb) { if ((df_attributes & DF_IFIELD) != 0) { // Combine only if fast, otherwise weird things can happen. const MirIFieldLoweringInfo& field_info = GetIFieldLoweringInfo(throw_insn); - ok = (df_attributes & DF_DA) ? field_info.FastPut() : field_info.FastGet(); + ok = (df_attributes & DF_DA) ? field_info.FastGet() : field_info.FastPut(); } else if ((df_attributes & DF_SFIELD) != 0) { // Combine only if fast, otherwise weird things can happen. const MirSFieldLoweringInfo& field_info = GetSFieldLoweringInfo(throw_insn); - bool fast = ((df_attributes & DF_DA) ? field_info.FastPut() : field_info.FastGet()); + bool fast = ((df_attributes & DF_DA) ? field_info.FastGet() : field_info.FastPut()); // Don't combine if the SGET/SPUT can call <clinit>(). bool clinit = !field_info.IsClassInitialized() && (throw_insn->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0; diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index ccaa167d6a..92ef70db7e 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -417,10 +417,10 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list RegLocation rl_src[3]; RegLocation rl_dest = mir_graph_->GetBadLoc(); RegLocation rl_result = mir_graph_->GetBadLoc(); - Instruction::Code opcode = mir->dalvikInsn.opcode; - int opt_flags = mir->optimization_flags; - uint32_t vB = mir->dalvikInsn.vB; - uint32_t vC = mir->dalvikInsn.vC; + const Instruction::Code opcode = mir->dalvikInsn.opcode; + const int opt_flags = mir->optimization_flags; + const uint32_t vB = mir->dalvikInsn.vB; + const uint32_t vC = mir->dalvikInsn.vC; DCHECK(CheckCorePoolSanity()) << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " @ 0x:" << std::hex << current_dalvik_offset_; @@ -572,7 +572,7 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list GenThrow(rl_src[0]); break; - case Instruction::ARRAY_LENGTH: + case Instruction::ARRAY_LENGTH: { int len_offset; len_offset = mirror::Array::LengthOffset().Int32Value(); rl_src[0] = LoadValue(rl_src[0], kRefReg); @@ -582,7 +582,7 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list MarkPossibleNullPointerException(opt_flags); StoreValue(rl_dest, rl_result); break; - + } case Instruction::CONST_STRING: case Instruction::CONST_STRING_JUMBO: GenConstString(vB, rl_dest); @@ -666,8 +666,7 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list GenCompareAndBranch(opcode, rl_src[0], rl_src[1], taken); } break; - } - + } case Instruction::IF_EQZ: case Instruction::IF_NEZ: case Instruction::IF_LTZ: @@ -693,7 +692,7 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list GenCompareZeroAndBranch(opcode, rl_src[0], taken); } break; - } + } case Instruction::AGET_WIDE: GenArrayGet(opt_flags, k64, rl_src[0], rl_src[1], rl_dest, 3); diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 3d492cde05..d3ac4e02cf 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -374,21 +374,34 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1); HInvoke* invoke = nullptr; - if (invoke_type == kVirtual) { + if (invoke_type == kVirtual || invoke_type == kInterface || invoke_type == kSuper) { MethodReference target_method(dex_file_, method_idx); uintptr_t direct_code; uintptr_t direct_method; - int vtable_index; - // TODO: Add devirtualization support. + int table_index; + InvokeType optimized_invoke_type = invoke_type; compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_offset, true, true, - &invoke_type, &target_method, &vtable_index, + &optimized_invoke_type, &target_method, &table_index, &direct_code, &direct_method); - if (vtable_index == -1) { + if (table_index == -1) { return false; } - invoke = new (arena_) HInvokeVirtual( - arena_, number_of_arguments, return_type, dex_offset, vtable_index); + + if (optimized_invoke_type == kVirtual) { + invoke = new (arena_) HInvokeVirtual( + arena_, number_of_arguments, return_type, dex_offset, table_index); + } else if (optimized_invoke_type == kInterface) { + invoke = new (arena_) HInvokeInterface( + arena_, number_of_arguments, return_type, dex_offset, method_idx, table_index); + } else if (optimized_invoke_type == kDirect) { + // For this compiler, sharpening only works if we compile PIC. + DCHECK(compiler_driver_->GetCompilerOptions().GetCompilePic()); + // Treat invoke-direct like static calls for now. + invoke = new (arena_) HInvokeStatic( + arena_, number_of_arguments, return_type, dex_offset, target_method.dex_method_index); + } } else { + DCHECK(invoke_type == kDirect || invoke_type == kStatic); // Treat invoke-direct like static calls for now. invoke = new (arena_) HInvokeStatic( arena_, number_of_arguments, return_type, dex_offset, method_idx); @@ -696,6 +709,38 @@ void HGraphBuilder::BuildFillWideArrayData(HInstruction* object, } } +bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction, + uint8_t destination, + uint8_t reference, + uint16_t type_index, + uint32_t dex_offset) { + bool type_known_final; + bool type_known_abstract; + bool is_referrers_class; + bool can_access = compiler_driver_->CanAccessTypeWithoutChecks( + dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index, + &type_known_final, &type_known_abstract, &is_referrers_class); + if (!can_access) { + return false; + } + HInstruction* object = LoadLocal(reference, Primitive::kPrimNot); + HLoadClass* cls = new (arena_) HLoadClass(type_index, is_referrers_class, dex_offset); + current_block_->AddInstruction(cls); + // The class needs a temporary before being used by the type check. + Temporaries temps(graph_, 1); + temps.Add(cls); + if (instruction.Opcode() == Instruction::INSTANCE_OF) { + current_block_->AddInstruction( + new (arena_) HInstanceOf(object, cls, type_known_final, dex_offset)); + UpdateLocal(destination, current_block_->GetLastInstruction()); + } else { + DCHECK_EQ(instruction.Opcode(), Instruction::CHECK_CAST); + current_block_->AddInstruction( + new (arena_) HCheckCast(object, cls, type_known_final, dex_offset)); + } + return true; +} + void HGraphBuilder::PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_offset) { if (target_offset <= 0) { // Unconditionnally add a suspend check to backward branches. We can remove @@ -850,8 +895,10 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } - case Instruction::INVOKE_STATIC: case Instruction::INVOKE_DIRECT: + case Instruction::INVOKE_INTERFACE: + case Instruction::INVOKE_STATIC: + case Instruction::INVOKE_SUPER: case Instruction::INVOKE_VIRTUAL: { uint32_t method_idx = instruction.VRegB_35c(); uint32_t number_of_vreg_arguments = instruction.VRegA_35c(); @@ -864,8 +911,10 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } - case Instruction::INVOKE_STATIC_RANGE: case Instruction::INVOKE_DIRECT_RANGE: + case Instruction::INVOKE_INTERFACE_RANGE: + case Instruction::INVOKE_STATIC_RANGE: + case Instruction::INVOKE_SUPER_RANGE: case Instruction::INVOKE_VIRTUAL_RANGE: { uint32_t method_idx = instruction.VRegB_3rc(); uint32_t number_of_vreg_arguments = instruction.VRegA_3rc(); @@ -912,6 +961,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::LONG_TO_INT: { + Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimInt); + break; + } + case Instruction::ADD_INT: { Binop_23x<HAdd>(instruction, Primitive::kPrimInt); break; @@ -993,6 +1047,36 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::AND_INT: { + Binop_23x<HAnd>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::AND_LONG: { + Binop_23x<HAnd>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::OR_INT: { + Binop_23x<HOr>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::OR_LONG: { + Binop_23x<HOr>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::XOR_INT: { + Binop_23x<HXor>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::XOR_LONG: { + Binop_23x<HXor>(instruction, Primitive::kPrimLong); + break; + } + case Instruction::ADD_LONG_2ADDR: { Binop_12x<HAdd>(instruction, Primitive::kPrimLong); break; @@ -1064,11 +1148,56 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::AND_INT_2ADDR: { + Binop_12x<HAnd>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::AND_LONG_2ADDR: { + Binop_12x<HAnd>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::OR_INT_2ADDR: { + Binop_12x<HOr>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::OR_LONG_2ADDR: { + Binop_12x<HOr>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::XOR_INT_2ADDR: { + Binop_12x<HXor>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::XOR_LONG_2ADDR: { + Binop_12x<HXor>(instruction, Primitive::kPrimLong); + break; + } + case Instruction::ADD_INT_LIT16: { Binop_22s<HAdd>(instruction, false); break; } + case Instruction::AND_INT_LIT16: { + Binop_22s<HAnd>(instruction, false); + break; + } + + case Instruction::OR_INT_LIT16: { + Binop_22s<HOr>(instruction, false); + break; + } + + case Instruction::XOR_INT_LIT16: { + Binop_22s<HXor>(instruction, false); + break; + } + case Instruction::RSUB_INT: { Binop_22s<HSub>(instruction, true); break; @@ -1084,6 +1213,21 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::AND_INT_LIT8: { + Binop_22b<HAnd>(instruction, false); + break; + } + + case Instruction::OR_INT_LIT8: { + Binop_22b<HOr>(instruction, false); + break; + } + + case Instruction::XOR_INT_LIT8: { + Binop_22b<HXor>(instruction, false); + break; + } + case Instruction::RSUB_INT_LIT8: { Binop_22b<HSub>(instruction, true); break; @@ -1282,25 +1426,37 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::INSTANCE_OF: { + uint8_t destination = instruction.VRegA_22c(); + uint8_t reference = instruction.VRegB_22c(); uint16_t type_index = instruction.VRegC_22c(); - bool type_known_final; - bool type_known_abstract; - bool is_referrers_class; - bool can_access = compiler_driver_->CanAccessTypeWithoutChecks( - dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index, - &type_known_final, &type_known_abstract, &is_referrers_class); - if (!can_access) { + if (!BuildTypeCheck(instruction, destination, reference, type_index, dex_offset)) { return false; } - HInstruction* object = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimNot); - HLoadClass* cls = new (arena_) HLoadClass(type_index, is_referrers_class, dex_offset); - current_block_->AddInstruction(cls); - // The class needs a temporary before being used by the type check. - Temporaries temps(graph_, 1); - temps.Add(cls); - current_block_->AddInstruction( - new (arena_) HTypeCheck(object, cls, type_known_final, dex_offset)); - UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction()); + break; + } + + case Instruction::CHECK_CAST: { + uint8_t reference = instruction.VRegA_21c(); + uint16_t type_index = instruction.VRegB_21c(); + if (!BuildTypeCheck(instruction, -1, reference, type_index, dex_offset)) { + return false; + } + break; + } + + case Instruction::MONITOR_ENTER: { + current_block_->AddInstruction(new (arena_) HMonitorOperation( + LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot), + HMonitorOperation::kEnter, + dex_offset)); + break; + } + + case Instruction::MONITOR_EXIT: { + current_block_->AddInstruction(new (arena_) HMonitorOperation( + LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot), + HMonitorOperation::kExit, + dex_offset)); break; } diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 09c9a51260..9cf83055b2 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -173,6 +173,14 @@ class HGraphBuilder : public ValueObject { uint32_t element_count, uint32_t dex_offset); + // Builds a `HInstanceOf`, or a `HCheckCast` instruction. + // Returns whether we succeeded in building the instruction. + bool BuildTypeCheck(const Instruction& instruction, + uint8_t destination, + uint8_t reference, + uint16_t type_index, + uint32_t dex_offset); + ArenaAllocator* const arena_; // A list of the size of the dex code holding block information for diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 0dfbad25f5..9d172638e1 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -216,10 +216,14 @@ void CodeGenerator::AllocateRegistersLocally(HInstruction* instruction) const { for (size_t i = 0, e = locations->GetTempCount(); i < e; ++i) { Location loc = locations->GetTemp(i); + // The DCHECKS below check that a register is not specified twice in + // the summary. if (loc.IsRegister()) { - // Check that a register is not specified twice in the summary. DCHECK(!blocked_core_registers_[loc.reg()]); blocked_core_registers_[loc.reg()] = true; + } else if (loc.IsFpuRegister()) { + DCHECK(!blocked_fpu_registers_[loc.reg()]); + blocked_fpu_registers_[loc.reg()] = true; } else { DCHECK_EQ(loc.GetPolicy(), Location::kRequiresRegister); } diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 8e6f8ea5eb..56546c2901 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -22,9 +22,9 @@ #include "mirror/art_method.h" #include "mirror/class.h" #include "thread.h" -#include "utils/assembler.h" #include "utils/arm/assembler_arm.h" #include "utils/arm/managed_register_arm.h" +#include "utils/assembler.h" #include "utils/stack_checks.h" namespace art { @@ -269,13 +269,19 @@ class LoadStringSlowPathARM : public SlowPathCodeARM { class TypeCheckSlowPathARM : public SlowPathCodeARM { public: - explicit TypeCheckSlowPathARM(HTypeCheck* instruction, Location object_class) + TypeCheckSlowPathARM(HInstruction* instruction, + Location class_to_check, + Location object_class, + uint32_t dex_pc) : instruction_(instruction), - object_class_(object_class) {} + class_to_check_(class_to_check), + object_class_(object_class), + dex_pc_(dex_pc) {} virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + DCHECK(instruction_->IsCheckCast() + || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); __ Bind(GetEntryLabel()); @@ -284,7 +290,7 @@ class TypeCheckSlowPathARM : public SlowPathCodeARM { // We're moving two locations to locations that could overlap, so we need a parallel // move resolver. InvokeRuntimeCallingConvention calling_convention; - MoveOperands move1(locations->InAt(1), + MoveOperands move1(class_to_check_, Location::RegisterLocation(calling_convention.GetRegisterAt(0)), nullptr); MoveOperands move2(object_class_, @@ -295,17 +301,23 @@ class TypeCheckSlowPathARM : public SlowPathCodeARM { parallel_move.AddMove(&move2); arm_codegen->GetMoveResolver()->EmitNativeCode(¶llel_move); - arm_codegen->InvokeRuntime( - QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, instruction_->GetDexPc()); - arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); + if (instruction_->IsInstanceOf()) { + arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_); + arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); + } else { + DCHECK(instruction_->IsCheckCast()); + arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_); + } codegen->RestoreLiveRegisters(locations); __ b(GetExitLabel()); } private: - HTypeCheck* const instruction_; + HInstruction* const instruction_; + const Location class_to_check_; const Location object_class_; + uint32_t dex_pc_; DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM); }; @@ -1178,10 +1190,6 @@ void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { DCHECK(!codegen_->IsLeafMethod()); } -void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { - HandleInvoke(invoke); -} - void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); @@ -1196,6 +1204,9 @@ void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType())); } +void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { + HandleInvoke(invoke); +} void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); @@ -1222,6 +1233,42 @@ void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) { + HandleInvoke(invoke); + // Add the hidden argument. + invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12)); +} + +void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) { + // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. + Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); + uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + + (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); + uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + + // Set the hidden argument. + __ LoadImmediate(invoke->GetLocations()->GetTemp(1).As<Register>(), invoke->GetDexMethodIndex()); + + // temp = object->GetClass(); + if (receiver.IsStackSlot()) { + __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex()); + __ LoadFromOffset(kLoadWord, temp, temp, class_offset); + } else { + __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset); + } + // temp = temp->GetImtEntryAt(method_offset); + uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); + __ LoadFromOffset(kLoadWord, temp, temp, method_offset); + // LR = temp->GetEntryPoint(); + __ LoadFromOffset(kLoadWord, LR, temp, entry_point); + // LR(); + __ blx(LR); + DCHECK(!codegen_->IsLeafMethod()); + codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); +} + void LocationsBuilderARM::VisitNeg(HNeg* neg) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); @@ -1298,11 +1345,32 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); switch (result_type) { + case Primitive::kPrimInt: + switch (input_type) { + case Primitive::kPrimLong: + // long-to-int conversion. + locations->SetInAt(0, Location::Any()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + case Primitive::kPrimFloat: + 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::kPrimLong: switch (input_type) { case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: + case Primitive::kPrimChar: // int-to-long conversion. locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); @@ -1320,7 +1388,6 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { } break; - case Primitive::kPrimInt: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1340,11 +1407,41 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); switch (result_type) { + case Primitive::kPrimInt: + switch (input_type) { + case Primitive::kPrimLong: + // long-to-int conversion. + DCHECK(out.IsRegister()); + if (in.IsRegisterPair()) { + __ Mov(out.As<Register>(), in.AsRegisterPairLow<Register>()); + } else if (in.IsDoubleStackSlot()) { + __ LoadFromOffset(kLoadWord, out.As<Register>(), SP, in.GetStackIndex()); + } else { + DCHECK(in.IsConstant()); + DCHECK(in.GetConstant()->IsLongConstant()); + int64_t value = in.GetConstant()->AsLongConstant()->GetValue(); + __ LoadImmediate(out.As<Register>(), static_cast<int32_t>(value)); + } + break; + + case Primitive::kPrimFloat: + 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::kPrimLong: switch (input_type) { case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: + case Primitive::kPrimChar: // int-to-long conversion. DCHECK(out.IsRegisterPair()); DCHECK(in.IsRegister()); @@ -1367,7 +1464,6 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio } break; - case Primitive::kPrimInt: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -2621,7 +2717,7 @@ void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) { QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc()); } -void LocationsBuilderARM::VisitTypeCheck(HTypeCheck* instruction) { +void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) { LocationSummary::CallKind call_kind = instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath; @@ -2631,7 +2727,7 @@ void LocationsBuilderARM::VisitTypeCheck(HTypeCheck* instruction) { locations->SetOut(Location::RequiresRegister()); } -void InstructionCodeGeneratorARM::VisitTypeCheck(HTypeCheck* instruction) { +void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { LocationSummary* locations = instruction->GetLocations(); Register obj = locations->InAt(0).As<Register>(); Register cls = locations->InAt(1).As<Register>(); @@ -2656,7 +2752,7 @@ void InstructionCodeGeneratorARM::VisitTypeCheck(HTypeCheck* instruction) { // If the classes are not equal, we go into a slow path. DCHECK(locations->OnlyCallsOnSlowPath()); slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( - instruction, Location::RegisterLocation(out)); + instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc()); codegen_->AddSlowPath(slow_path); __ b(slow_path->GetEntryLabel(), NE); __ LoadImmediate(out, 1); @@ -2670,5 +2766,121 @@ void InstructionCodeGeneratorARM::VisitTypeCheck(HTypeCheck* instruction) { __ Bind(&done); } +void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( + instruction, LocationSummary::kCallOnSlowPath); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); +} + +void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Register obj = locations->InAt(0).As<Register>(); + Register cls = locations->InAt(1).As<Register>(); + Register temp = locations->GetTemp(0).As<Register>(); + uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( + instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc()); + codegen_->AddSlowPath(slow_path); + + // TODO: avoid this check if we know obj is not null. + __ cmp(obj, ShifterOperand(0)); + __ b(slow_path->GetExitLabel(), EQ); + // Compare the class of `obj` with `cls`. + __ LoadFromOffset(kLoadWord, temp, obj, class_offset); + __ cmp(temp, ShifterOperand(cls)); + __ b(slow_path->GetEntryLabel(), NE); + __ Bind(slow_path->GetExitLabel()); +} + +void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); +} + +void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) { + codegen_->InvokeRuntime(instruction->IsEnter() + ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject), + instruction, + instruction->GetDexPc()); +} + +void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } + +void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt + || instruction->GetResultType() == Primitive::kPrimLong); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + bool output_overlaps = (instruction->GetResultType() == Primitive::kPrimLong); + locations->SetOut(Location::RequiresRegister(), output_overlaps); +} + +void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = instruction->GetLocations(); + + if (instruction->GetResultType() == Primitive::kPrimInt) { + Register first = locations->InAt(0).As<Register>(); + Register second = locations->InAt(1).As<Register>(); + Register out = locations->Out().As<Register>(); + if (instruction->IsAnd()) { + __ and_(out, first, ShifterOperand(second)); + } else if (instruction->IsOr()) { + __ orr(out, first, ShifterOperand(second)); + } else { + DCHECK(instruction->IsXor()); + __ eor(out, first, ShifterOperand(second)); + } + } else { + DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + Location out = locations->Out(); + if (instruction->IsAnd()) { + __ and_(out.AsRegisterPairLow<Register>(), + first.AsRegisterPairLow<Register>(), + ShifterOperand(second.AsRegisterPairLow<Register>())); + __ and_(out.AsRegisterPairHigh<Register>(), + first.AsRegisterPairHigh<Register>(), + ShifterOperand(second.AsRegisterPairHigh<Register>())); + } else if (instruction->IsOr()) { + __ orr(out.AsRegisterPairLow<Register>(), + first.AsRegisterPairLow<Register>(), + ShifterOperand(second.AsRegisterPairLow<Register>())); + __ orr(out.AsRegisterPairHigh<Register>(), + first.AsRegisterPairHigh<Register>(), + ShifterOperand(second.AsRegisterPairHigh<Register>())); + } else { + DCHECK(instruction->IsXor()); + __ eor(out.AsRegisterPairLow<Register>(), + first.AsRegisterPairLow<Register>(), + ShifterOperand(second.AsRegisterPairLow<Register>())); + __ eor(out.AsRegisterPairHigh<Register>(), + first.AsRegisterPairHigh<Register>(), + ShifterOperand(second.AsRegisterPairHigh<Register>())); + } + } +} + } // namespace arm } // namespace art diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 5d519937f4..d69531002d 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -105,9 +105,10 @@ class LocationsBuilderARM : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION + private: void HandleInvoke(HInvoke* invoke); + void HandleBitwiseOperation(HBinaryOperation* operation); - private: CodeGeneratorARM* const codegen_; InvokeDexCallingConventionVisitor parameter_visitor_; @@ -133,6 +134,7 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { // the suspend call. void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg); + void HandleBitwiseOperation(HBinaryOperation* operation); ArmAssembler* const assembler_; CodeGeneratorARM* const codegen_; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index f37c5db0b7..887a4efa19 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -38,15 +38,20 @@ namespace art { namespace arm64 { -static bool IsFPType(Primitive::Type type) { - return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble; -} - // TODO: clean-up some of the constant definitions. static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>); static constexpr int kCurrentMethodStackOffset = 0; namespace { + +bool IsFPType(Primitive::Type type) { + return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble; +} + +bool Is64BitType(Primitive::Type type) { + return type == Primitive::kPrimLong || type == Primitive::kPrimDouble; +} + // Convenience helpers to ease conversion to and from VIXL operands. int VIXLRegCodeFromART(int code) { @@ -101,6 +106,28 @@ Register InputRegisterAt(HInstruction* instr, int input_index) { instr->InputAt(input_index)->GetType()); } +FPRegister DRegisterFrom(Location location) { + return FPRegister::DRegFromCode(location.reg()); +} + +FPRegister SRegisterFrom(Location location) { + return FPRegister::SRegFromCode(location.reg()); +} + +FPRegister FPRegisterFrom(Location location, Primitive::Type type) { + DCHECK(IsFPType(type)); + return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location); +} + +FPRegister OutputFPRegister(HInstruction* instr) { + return FPRegisterFrom(instr->GetLocations()->Out(), instr->GetType()); +} + +FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) { + return FPRegisterFrom(instr->GetLocations()->InAt(input_index), + instr->InputAt(input_index)->GetType()); +} + int64_t Int64ConstantFrom(Location location) { HConstant* instr = location.GetConstant(); return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue() @@ -138,6 +165,10 @@ Location LocationFrom(const Register& reg) { return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.code())); } +Location LocationFrom(const FPRegister& fpreg) { + return Location::FpuRegisterLocation(fpreg.code()); +} + } // namespace inline Condition ARM64Condition(IfCondition cond) { @@ -154,6 +185,22 @@ inline Condition ARM64Condition(IfCondition cond) { return nv; // Unreachable. } +Location ARM64ReturnLocation(Primitive::Type return_type) { + DCHECK_NE(return_type, Primitive::kPrimVoid); + // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the + // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`, + // but we use the exact registers for clarity. + if (return_type == Primitive::kPrimFloat) { + return LocationFrom(s0); + } else if (return_type == Primitive::kPrimDouble) { + return LocationFrom(d0); + } else if (return_type == Primitive::kPrimLong) { + return LocationFrom(x0); + } else { + return LocationFrom(w0); + } +} + static const Register kRuntimeParameterCoreRegisters[] = { x0, x1, x2, x3, x4, x5, x6, x7 }; static constexpr size_t kRuntimeParameterCoreRegistersLength = arraysize(kRuntimeParameterCoreRegisters); @@ -177,11 +224,7 @@ class InvokeRuntimeCallingConvention : public CallingConvention<Register, FPRegi }; Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) { - DCHECK_NE(return_type, Primitive::kPrimVoid); - if (return_type == Primitive::kPrimFloat || return_type == Primitive::kPrimDouble) { - LOG(FATAL) << "Unimplemented return type " << return_type; - } - return LocationFrom(x0); + return ARM64ReturnLocation(return_type); } #define __ reinterpret_cast<Arm64Assembler*>(codegen->GetAssembler())->vixl_masm_-> @@ -289,35 +332,25 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type LOG(FATAL) << "Unreachable type " << type; } - if (type == Primitive::kPrimFloat || type == Primitive::kPrimDouble) { - LOG(FATAL) << "Unimplemented type " << type; + if (IsFPType(type) && (fp_index_ < calling_convention.GetNumberOfFpuRegisters())) { + next_location = LocationFrom(calling_convention.GetFpuRegisterAt(fp_index_++)); + } else if (!IsFPType(type) && (gp_index_ < calling_convention.GetNumberOfRegisters())) { + next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++)); + } else { + size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_); + next_location = Is64BitType(type) ? Location::DoubleStackSlot(stack_offset) + : Location::StackSlot(stack_offset); } - if (gp_index_ < calling_convention.GetNumberOfRegisters()) { - next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_)); - if (type == Primitive::kPrimLong) { - // Double stack slot reserved on the stack. - stack_index_++; - } - } else { // Stack. - if (type == Primitive::kPrimLong) { - next_location = Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_)); - // Double stack slot reserved on the stack. - stack_index_++; - } else { - next_location = Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_)); - } - } - // Move to the next register/stack slot. - gp_index_++; - stack_index_++; + // Space on the stack is reserved for all arguments. + stack_index_ += Is64BitType(type) ? 2 : 1; return next_location; } CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph) : CodeGenerator(graph, kNumberOfAllocatableRegisters, - kNumberOfAllocatableFloatingPointRegisters, + kNumberOfAllocatableFPRegisters, kNumberOfAllocatableRegisterPairs), block_labels_(nullptr), location_builder_(graph, this), @@ -359,35 +392,6 @@ void CodeGeneratorARM64::Bind(HBasicBlock* block) { __ Bind(GetLabelOf(block)); } -void CodeGeneratorARM64::MoveHelper(Location destination, - Location source, - Primitive::Type type) { - if (source.Equals(destination)) { - return; - } - if (destination.IsRegister()) { - Register dst = RegisterFrom(destination, type); - if (source.IsRegister()) { - Register src = RegisterFrom(source, type); - DCHECK(dst.IsSameSizeAndType(src)); - __ Mov(dst, src); - } else { - DCHECK(dst.Is64Bits() || !source.IsDoubleStackSlot()); - __ Ldr(dst, StackOperandFrom(source)); - } - } else { - DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot()); - if (source.IsRegister()) { - __ Str(RegisterFrom(source, type), StackOperandFrom(destination)); - } else { - UseScratchRegisterScope temps(assembler_.vixl_masm_); - Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW(); - __ Ldr(temp, StackOperandFrom(source)); - __ Str(temp, StackOperandFrom(destination)); - } - } -} - void CodeGeneratorARM64::Move(HInstruction* instruction, Location location, HInstruction* move_for) { @@ -397,6 +401,7 @@ void CodeGeneratorARM64::Move(HInstruction* instruction, } Primitive::Type type = instruction->GetType(); + DCHECK_NE(type, Primitive::kPrimVoid); if (instruction->IsIntConstant() || instruction->IsLongConstant()) { int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue() @@ -418,20 +423,10 @@ void CodeGeneratorARM64::Move(HInstruction* instruction, MoveHelper(location, temp_location, type); } else if (instruction->IsLoadLocal()) { uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); - switch (type) { - case Primitive::kPrimNot: - case Primitive::kPrimBoolean: - case Primitive::kPrimByte: - case Primitive::kPrimChar: - case Primitive::kPrimShort: - case Primitive::kPrimInt: - MoveHelper(location, Location::StackSlot(stack_slot), type); - break; - case Primitive::kPrimLong: - MoveHelper(location, Location::DoubleStackSlot(stack_slot), type); - break; - default: - LOG(FATAL) << "Unimplemented type" << type; + if (Is64BitType(type)) { + MoveHelper(location, Location::DoubleStackSlot(stack_slot), type); + } else { + MoveHelper(location, Location::StackSlot(stack_slot), type); } } else { @@ -446,24 +441,25 @@ size_t CodeGeneratorARM64::FrameEntrySpillSize() const { Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const { Primitive::Type type = load->GetType(); + switch (type) { case Primitive::kPrimNot: - case Primitive::kPrimBoolean: - case Primitive::kPrimByte: - case Primitive::kPrimChar: - case Primitive::kPrimShort: case Primitive::kPrimInt: + case Primitive::kPrimFloat: return Location::StackSlot(GetStackSlot(load->GetLocal())); + case Primitive::kPrimLong: - return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); - case Primitive::kPrimFloat: case Primitive::kPrimDouble: - LOG(FATAL) << "Unimplemented type " << type; - break; + return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); + + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: case Primitive::kPrimVoid: - default: LOG(FATAL) << "Unexpected type " << type; } + LOG(FATAL) << "Unreachable"; return Location::NoLocation(); } @@ -487,13 +483,19 @@ void CodeGeneratorARM64::SetupBlockedRegisters() const { // xSuspend (Suspend counter) // lr // sp is not part of the allocatable registers, so we don't need to block it. + // TODO: Avoid blocking callee-saved registers, and instead preserve them + // where necessary. CPURegList reserved_core_registers = vixl_reserved_core_registers; reserved_core_registers.Combine(runtime_reserved_core_registers); - // TODO: See if we should instead allow allocating but preserve those if used. reserved_core_registers.Combine(quick_callee_saved_registers); while (!reserved_core_registers.IsEmpty()) { blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true; } + CPURegList reserved_fp_registers = vixl_reserved_fp_registers; + reserved_fp_registers.Combine(CPURegList::GetCalleeSavedFP()); + while (!reserved_core_registers.IsEmpty()) { + blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true; + } } Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const { @@ -501,17 +503,13 @@ Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const { LOG(FATAL) << "Unreachable type " << type; } - if (type == Primitive::kPrimFloat || type == Primitive::kPrimDouble) { - LOG(FATAL) << "Unimplemented support for floating-point"; - } - - ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfXRegisters); - DCHECK_NE(reg, -1); - blocked_core_registers_[reg] = true; - if (IsFPType(type)) { + ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters); + DCHECK_NE(reg, -1); return Location::FpuRegisterLocation(reg); } else { + ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters); + DCHECK_NE(reg, -1); return Location::RegisterLocation(reg); } } @@ -524,8 +522,107 @@ void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg stream << Arm64ManagedRegister::FromDRegister(DRegister(reg)); } +void CodeGeneratorARM64::MoveHelper(Location destination, + Location source, + Primitive::Type type) { + if (source.Equals(destination)) { + return; + } + if (destination.IsRegister()) { + Register dst = RegisterFrom(destination, type); + if (source.IsStackSlot() || source.IsDoubleStackSlot()) { + DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot()); + __ Ldr(dst, StackOperandFrom(source)); + } else { + __ Mov(dst, OperandFrom(source, type)); + } + } else if (destination.IsFpuRegister()) { + FPRegister dst = FPRegisterFrom(destination, type); + if (source.IsStackSlot() || source.IsDoubleStackSlot()) { + DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot()); + __ Ldr(dst, StackOperandFrom(source)); + } 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()); + } + } + } else { + DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot()); + if (source.IsRegister()) { + __ Str(RegisterFrom(source, type), StackOperandFrom(destination)); + } else if (source.IsFpuRegister()) { + __ Str(FPRegisterFrom(source, type), StackOperandFrom(destination)); + } else { + UseScratchRegisterScope temps(assembler_.vixl_masm_); + Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW(); + __ Ldr(temp, StackOperandFrom(source)); + __ Str(temp, StackOperandFrom(destination)); + } + } +} + +void CodeGeneratorARM64::Load(Primitive::Type type, + vixl::Register dst, + const vixl::MemOperand& src) { + switch (type) { + case Primitive::kPrimBoolean: + __ Ldrb(dst, src); + break; + case Primitive::kPrimByte: + __ Ldrsb(dst, src); + break; + case Primitive::kPrimShort: + __ Ldrsh(dst, src); + break; + case Primitive::kPrimChar: + __ Ldrh(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: + case Primitive::kPrimVoid: + LOG(FATAL) << "Unreachable type " << type; + } +} + +void CodeGeneratorARM64::Store(Primitive::Type type, + vixl::Register rt, + const vixl::MemOperand& dst) { + switch (type) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + __ Strb(rt, dst); + break; + case Primitive::kPrimChar: + case Primitive::kPrimShort: + __ Strh(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: + case Primitive::kPrimVoid: + LOG(FATAL) << "Unreachable type " << type; + } +} + #undef __ -#define __ assembler_->vixl_masm_-> +#define __ GetAssembler()->vixl_masm_-> InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, CodeGeneratorARM64* codegen) @@ -534,24 +631,23 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, codegen_(codegen) {} #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ - M(ArrayGet) \ - M(ArraySet) \ + M(And) \ + M(CheckCast) \ M(ClinitCheck) \ - M(DoubleConstant) \ - M(Div) \ M(DivZeroCheck) \ - M(FloatConstant) \ + M(InstanceOf) \ + M(InvokeInterface) \ M(LoadClass) \ M(LoadException) \ M(LoadString) \ - M(Neg) \ - M(NewArray) \ + M(MonitorOperation) \ + M(Or) \ M(ParallelMove) \ M(StaticFieldGet) \ M(StaticFieldSet) \ M(Throw) \ - M(TypeCheck) \ M(TypeConversion) \ + M(Xor) \ #define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode @@ -582,20 +678,21 @@ void LocationsBuilderARM64::HandleAddSub(HBinaryOperation* instr) { Primitive::Type type = instr->GetResultType(); switch (type) { case Primitive::kPrimInt: - case Primitive::kPrimLong: { + case Primitive::kPrimLong: locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1))); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; - } - case Primitive::kPrimBoolean: - case Primitive::kPrimByte: - case Primitive::kPrimChar: - case Primitive::kPrimShort: - LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type; + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresFpuRegister()); break; + default: - LOG(FATAL) << "Unimplemented " << instr->DebugName() << " type " << type; + LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type; } } @@ -603,28 +700,34 @@ void InstructionCodeGeneratorARM64::HandleAddSub(HBinaryOperation* instr) { DCHECK(instr->IsAdd() || instr->IsSub()); Primitive::Type type = instr->GetType(); - Register dst = OutputRegister(instr); - Register lhs = InputRegisterAt(instr, 0); - Operand rhs = InputOperandAt(instr, 1); switch (type) { case Primitive::kPrimInt: - case Primitive::kPrimLong: + case Primitive::kPrimLong: { + Register dst = OutputRegister(instr); + Register lhs = InputRegisterAt(instr, 0); + Operand rhs = InputOperandAt(instr, 1); if (instr->IsAdd()) { __ Add(dst, lhs, rhs); } else { __ Sub(dst, lhs, rhs); } break; - - case Primitive::kPrimBoolean: - case Primitive::kPrimByte: - case Primitive::kPrimChar: - case Primitive::kPrimShort: - LOG(FATAL) << "Unexpected add/sub type " << type; + } + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + FPRegister dst = OutputFPRegister(instr); + FPRegister lhs = InputFPRegisterAt(instr, 0); + FPRegister rhs = InputFPRegisterAt(instr, 1); + if (instr->IsAdd()) { + __ Fadd(dst, lhs, rhs); + } else { + __ Fsub(dst, lhs, rhs); + } break; + } default: - LOG(FATAL) << "Unimplemented add/sub type " << type; + LOG(FATAL) << "Unexpected add/sub type " << type; } } @@ -636,6 +739,37 @@ void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) { HandleAddSub(instruction); } +void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); + locations->SetOut(Location::RequiresRegister()); +} + +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_); + + if (index.IsConstant()) { + offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type); + source = MemOperand(obj, offset); + } else { + Register temp = temps.AcquireSameSizeAs(obj); + Register index_reg = RegisterFrom(index, Primitive::kPrimInt); + __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type))); + source = MemOperand(temp, offset); + } + + codegen_->Load(type, out, source); +} + void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); locations->SetInAt(0, Location::RequiresRegister()); @@ -647,6 +781,53 @@ void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset())); } +void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) { + Primitive::Type value_type = instruction->GetComponentType(); + bool is_object = value_type == Primitive::kPrimNot; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( + instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall); + if (is_object) { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1))); + locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2))); + } else { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); + locations->SetInAt(2, Location::RequiresRegister()); + } +} + +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()); + } else { + LocationSummary* locations = instruction->GetLocations(); + Register obj = InputRegisterAt(instruction, 0); + Register value = InputRegisterAt(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_); + + if (index.IsConstant()) { + offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type); + destination = MemOperand(obj, offset); + } else { + Register temp = temps.AcquireSameSizeAs(obj); + Register index_reg = InputRegisterAt(instruction, 1); + __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type))); + destination = MemOperand(temp, offset); + } + + codegen_->Store(value_type, value, destination); + } +} + void LocationsBuilderARM64::VisitCompare(HCompare* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); @@ -714,6 +895,58 @@ void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition( FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS) #undef FOR_EACH_CONDITION_INSTRUCTION +void LocationsBuilderARM64::VisitDiv(HDiv* div) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall); + switch (div->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); + break; + + default: + LOG(FATAL) << "Unexpected div type " << div->GetResultType(); + } +} + +void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) { + Primitive::Type type = div->GetResultType(); + switch (type) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: + __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1)); + break; + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1)); + break; + + default: + LOG(FATAL) << "Unexpected div type " << type; + } +} + +void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); + locations->SetOut(Location::ConstantLocation(constant)); +} + +void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) { + UNUSED(constant); + // Will be generated at use site. +} + void LocationsBuilderARM64::VisitExit(HExit* exit) { exit->SetLocations(nullptr); } @@ -726,6 +959,17 @@ void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) { } } +void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); + locations->SetOut(Location::ConstantLocation(constant)); +} + +void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) { + UNUSED(constant); + // Will be generated at use site. +} + void LocationsBuilderARM64::VisitGoto(HGoto* got) { got->SetLocations(nullptr); } @@ -792,44 +1036,9 @@ void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction } void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { - Primitive::Type res_type = instruction->GetType(); - Register res = OutputRegister(instruction); - Register obj = InputRegisterAt(instruction, 0); - uint32_t offset = instruction->GetFieldOffset().Uint32Value(); - - switch (res_type) { - case Primitive::kPrimBoolean: { - __ Ldrb(res, MemOperand(obj, offset)); - break; - } - case Primitive::kPrimByte: { - __ Ldrsb(res, MemOperand(obj, offset)); - break; - } - case Primitive::kPrimShort: { - __ Ldrsh(res, MemOperand(obj, offset)); - break; - } - case Primitive::kPrimChar: { - __ Ldrh(res, MemOperand(obj, offset)); - break; - } - case Primitive::kPrimInt: - case Primitive::kPrimNot: - case Primitive::kPrimLong: { // TODO: support volatile. - DCHECK(res.IsX() == (res_type == Primitive::kPrimLong)); - __ Ldr(res, MemOperand(obj, offset)); - break; - } - - case Primitive::kPrimFloat: - case Primitive::kPrimDouble: - LOG(FATAL) << "Unimplemented register res_type " << res_type; - break; - - case Primitive::kPrimVoid: - LOG(FATAL) << "Unreachable res_type " << res_type; - } + MemOperand field = MemOperand(InputRegisterAt(instruction, 0), + instruction->GetFieldOffset().Uint32Value()); + codegen_->Load(instruction->GetType(), OutputRegister(instruction), field); } void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { @@ -839,43 +1048,12 @@ void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction } void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { - Register obj = InputRegisterAt(instruction, 0); + Primitive::Type field_type = instruction->GetFieldType(); Register value = InputRegisterAt(instruction, 1); - Primitive::Type field_type = instruction->InputAt(1)->GetType(); - uint32_t offset = instruction->GetFieldOffset().Uint32Value(); - - switch (field_type) { - case Primitive::kPrimBoolean: - case Primitive::kPrimByte: { - __ Strb(value, MemOperand(obj, offset)); - break; - } - - case Primitive::kPrimShort: - case Primitive::kPrimChar: { - __ Strh(value, MemOperand(obj, offset)); - break; - } - - case Primitive::kPrimInt: - case Primitive::kPrimNot: - case Primitive::kPrimLong: { - DCHECK(value.IsX() == (field_type == Primitive::kPrimLong)); - __ Str(value, MemOperand(obj, offset)); - - if (field_type == Primitive::kPrimNot) { - codegen_->MarkGCCard(obj, value); - } - break; - } - - case Primitive::kPrimFloat: - case Primitive::kPrimDouble: - LOG(FATAL) << "Unimplemented register type " << field_type; - break; - - case Primitive::kPrimVoid: - LOG(FATAL) << "Unreachable type " << field_type; + Register obj = InputRegisterAt(instruction, 0); + codegen_->Store(field_type, value, MemOperand(obj, instruction->GetFieldOffset().Uint32Value())); + if (field_type == Primitive::kPrimNot) { + codegen_->MarkGCCard(obj, value); } } @@ -931,11 +1109,13 @@ void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) { // temp = method; __ Ldr(temp, MemOperand(sp, kCurrentMethodStackOffset)); // temp = temp->dex_cache_resolved_methods_; - __ Ldr(temp, MemOperand(temp.X(), mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue())); + __ Ldr(temp, MemOperand(temp.X(), + mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue())); // temp = temp[index_in_cache]; __ 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())); + __ Ldr(lr, MemOperand(temp.X(), + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue())); // lr(); __ Blr(lr); @@ -1011,7 +1191,9 @@ void LocationsBuilderARM64::VisitMul(HMul* mul) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: - LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType(); + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresFpuRegister()); break; default: @@ -1028,7 +1210,7 @@ void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: - LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType(); + __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1)); break; default: @@ -1036,6 +1218,71 @@ void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) { } } +void LocationsBuilderARM64::VisitNeg(HNeg* neg) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0))); + locations->SetOut(Location::RequiresRegister()); + break; + } + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + +void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) { + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: + __ Neg(OutputRegister(neg), InputOperandAt(neg, 0)); + break; + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + +void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); + InvokeRuntimeCallingConvention calling_convention; + locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0))); + locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1))); + locations->SetOut(LocationFrom(x0)); + locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(2))); +} + +void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) { + LocationSummary* locations = instruction->GetLocations(); + InvokeRuntimeCallingConvention calling_convention; + Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt); + 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)); + __ 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()); +} + void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); @@ -1053,7 +1300,9 @@ void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) DCHECK(current_method.Is(w1)); __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset)); __ Mov(type_index, instruction->GetTypeIndex()); - __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocObjectWithAccessCheck).Int32Value())); + 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()); @@ -1137,35 +1386,11 @@ void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) { void LocationsBuilderARM64::VisitReturn(HReturn* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); Primitive::Type return_type = instruction->InputAt(0)->GetType(); - - if (return_type == Primitive::kPrimFloat || return_type == Primitive::kPrimDouble) { - LOG(FATAL) << "Unimplemented return type " << return_type; - } - - locations->SetInAt(0, LocationFrom(x0)); + locations->SetInAt(0, ARM64ReturnLocation(return_type)); } void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) { - if (kIsDebugBuild) { - Primitive::Type type = instruction->InputAt(0)->GetType(); - switch (type) { - case Primitive::kPrimBoolean: - case Primitive::kPrimByte: - case Primitive::kPrimChar: - case Primitive::kPrimShort: - case Primitive::kPrimInt: - case Primitive::kPrimNot: - DCHECK(InputRegisterAt(instruction, 0).Is(w0)); - break; - - case Primitive::kPrimLong: - DCHECK(InputRegisterAt(instruction, 0).Is(x0)); - break; - - default: - LOG(FATAL) << "Unimplemented return type " << type; - } - } + UNUSED(instruction); codegen_->GenerateFrameExit(); __ Br(lr); } @@ -1184,16 +1409,18 @@ void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store); Primitive::Type field_type = store->InputAt(1)->GetType(); switch (field_type) { + case Primitive::kPrimNot: case Primitive::kPrimBoolean: case Primitive::kPrimByte: case Primitive::kPrimChar: case Primitive::kPrimShort: case Primitive::kPrimInt: - case Primitive::kPrimNot: + case Primitive::kPrimFloat: locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); break; case Primitive::kPrimLong: + case Primitive::kPrimDouble: locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); break; diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 4a41000e8d..f2ead21e15 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -45,11 +45,14 @@ const vixl::Register wSuspend = vixl::w19; // Suspend Register const vixl::Register xSuspend = vixl::x19; const vixl::CPURegList vixl_reserved_core_registers(vixl::ip0, vixl::ip1); +const vixl::CPURegList vixl_reserved_fp_registers(vixl::d31); const vixl::CPURegList runtime_reserved_core_registers(tr, xSuspend, vixl::lr); const vixl::CPURegList quick_callee_saved_registers(vixl::CPURegister::kRegister, vixl::kXRegSize, kArm64CalleeSaveRefSpills); +Location ARM64ReturnLocation(Primitive::Type return_type); + class InvokeDexCallingConvention : public CallingConvention<vixl::Register, vixl::FPRegister> { public: InvokeDexCallingConvention() @@ -59,11 +62,7 @@ class InvokeDexCallingConvention : public CallingConvention<vixl::Register, vixl kParameterFPRegistersLength) {} Location GetReturnLocation(Primitive::Type return_type) { - DCHECK_NE(return_type, Primitive::kPrimVoid); - if (return_type == Primitive::kPrimFloat || return_type == Primitive::kPrimDouble) { - LOG(FATAL) << "Unimplemented return type " << return_type; - } - return Location::RegisterLocation(X0); + return ARM64ReturnLocation(return_type); } @@ -73,7 +72,7 @@ class InvokeDexCallingConvention : public CallingConvention<vixl::Register, vixl class InvokeDexCallingConventionVisitor { public: - InvokeDexCallingConventionVisitor() : gp_index_(0), stack_index_(0) {} + InvokeDexCallingConventionVisitor() : gp_index_(0), fp_index_(0), stack_index_(0) {} Location GetNextLocation(Primitive::Type type); Location GetReturnLocation(Primitive::Type return_type) { @@ -84,6 +83,8 @@ class InvokeDexCallingConventionVisitor { InvokeDexCallingConvention calling_convention; // The current index for core registers. uint32_t gp_index_; + // The current index for floating-point registers. + uint32_t fp_index_; // The current stack index. uint32_t stack_index_; @@ -204,10 +205,8 @@ class CodeGeneratorARM64 : public CodeGenerator { // (xzr, wzr), or make for poor allocatable registers (sp alignment // requirements, etc.). This also facilitates our task as all other registers // can easily be mapped via to or from their type and index or code. - static const int kNumberOfAllocatableCoreRegisters = vixl::kNumberOfRegisters - 1; - static const int kNumberOfAllocatableFloatingPointRegisters = vixl::kNumberOfFPRegisters; - static const int kNumberOfAllocatableRegisters = - kNumberOfAllocatableCoreRegisters + kNumberOfAllocatableFloatingPointRegisters; + static const int kNumberOfAllocatableRegisters = vixl::kNumberOfRegisters - 1; + static const int kNumberOfAllocatableFPRegisters = vixl::kNumberOfFPRegisters; static constexpr int kNumberOfAllocatableRegisterPairs = 0; void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; @@ -217,8 +216,6 @@ class CodeGeneratorARM64 : public CodeGenerator { return InstructionSet::kArm64; } - void MoveHelper(Location destination, Location source, Primitive::Type type); - void Initialize() OVERRIDE { HGraph* graph = GetGraph(); int length = graph->GetBlocks().Size(); @@ -228,6 +225,11 @@ class CodeGeneratorARM64 : public CodeGenerator { } } + // Code generation helpers. + 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); + private: // Labels for each block that will be compiled. vixl::Label* block_labels_; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 548d6995d0..d470345765 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -270,13 +270,19 @@ class LoadClassSlowPathX86 : public SlowPathCodeX86 { class TypeCheckSlowPathX86 : public SlowPathCodeX86 { public: - TypeCheckSlowPathX86(HTypeCheck* instruction, Location object_class) + TypeCheckSlowPathX86(HInstruction* instruction, + Location class_to_check, + Location object_class, + uint32_t dex_pc) : instruction_(instruction), - object_class_(object_class) {} + class_to_check_(class_to_check), + object_class_(object_class), + dex_pc_(dex_pc) {} virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + DCHECK(instruction_->IsCheckCast() + || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); __ Bind(GetEntryLabel()); @@ -285,7 +291,7 @@ class TypeCheckSlowPathX86 : public SlowPathCodeX86 { // We're moving two locations to locations that could overlap, so we need a parallel // move resolver. InvokeRuntimeCallingConvention calling_convention; - MoveOperands move1(locations->InAt(1), + MoveOperands move1(class_to_check_, Location::RegisterLocation(calling_convention.GetRegisterAt(0)), nullptr); MoveOperands move2(object_class_, @@ -296,17 +302,27 @@ class TypeCheckSlowPathX86 : public SlowPathCodeX86 { parallel_move.AddMove(&move2); x86_codegen->GetMoveResolver()->EmitNativeCode(¶llel_move); - __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInstanceofNonTrivial))); - codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); - x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX)); + if (instruction_->IsInstanceOf()) { + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInstanceofNonTrivial))); + } else { + DCHECK(instruction_->IsCheckCast()); + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pCheckCast))); + } + + codegen->RecordPcInfo(instruction_, dex_pc_); + if (instruction_->IsInstanceOf()) { + x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX)); + } codegen->RestoreLiveRegisters(locations); __ jmp(GetExitLabel()); } private: - HTypeCheck* const instruction_; + HInstruction* const instruction_; + const Location class_to_check_; const Location object_class_; + const uint32_t dex_pc_; DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86); }; @@ -1152,6 +1168,41 @@ void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) { + HandleInvoke(invoke); + // Add the hidden argument. + invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM0)); +} + +void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) { + // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. + Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); + uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + + (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); + uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + + // Set the hidden argument. + __ movl(temp, Immediate(invoke->GetDexMethodIndex())); + __ movd(invoke->GetLocations()->GetTemp(1).As<XmmRegister>(), temp); + + // temp = object->GetClass(); + if (receiver.IsStackSlot()) { + __ movl(temp, Address(ESP, receiver.GetStackIndex())); + __ movl(temp, Address(temp, class_offset)); + } else { + __ movl(temp, Address(receiver.As<Register>(), class_offset)); + } + // temp = temp->GetImtEntryAt(method_offset); + __ movl(temp, Address(temp, method_offset)); + // call temp->GetEntryPoint(); + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); + + DCHECK(!codegen_->IsLeafMethod()); + codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); +} + void LocationsBuilderX86::VisitNeg(HNeg* neg) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); @@ -1226,11 +1277,32 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); switch (result_type) { + case Primitive::kPrimInt: + switch (input_type) { + case Primitive::kPrimLong: + // long-to-int conversion. + locations->SetInAt(0, Location::Any()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + case Primitive::kPrimFloat: + 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::kPrimLong: switch (input_type) { case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: + case Primitive::kPrimChar: // int-to-long conversion. locations->SetInAt(0, Location::RegisterLocation(EAX)); locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); @@ -1248,7 +1320,6 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { } break; - case Primitive::kPrimInt: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1268,11 +1339,40 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); switch (result_type) { + case Primitive::kPrimInt: + switch (input_type) { + case Primitive::kPrimLong: + // long-to-int conversion. + if (in.IsRegisterPair()) { + __ movl(out.As<Register>(), in.AsRegisterPairLow<Register>()); + } else if (in.IsDoubleStackSlot()) { + __ movl(out.As<Register>(), Address(ESP, in.GetStackIndex())); + } else { + DCHECK(in.IsConstant()); + DCHECK(in.GetConstant()->IsLongConstant()); + int64_t value = in.GetConstant()->AsLongConstant()->GetValue(); + __ movl(out.As<Register>(), Immediate(static_cast<int32_t>(value))); + } + break; + + case Primitive::kPrimFloat: + 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::kPrimLong: switch (input_type) { case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: + case Primitive::kPrimChar: // int-to-long conversion. DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX); DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX); @@ -1292,7 +1392,6 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio } break; - case Primitive::kPrimInt: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1349,7 +1448,7 @@ void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { } case Primitive::kPrimLong: { - if (second.IsRegister()) { + if (second.IsRegisterPair()) { __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); } else { @@ -1425,7 +1524,7 @@ void InstructionCodeGeneratorX86::VisitSub(HSub* sub) { } case Primitive::kPrimLong: { - if (second.IsRegister()) { + if (second.IsRegisterPair()) { __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); } else { @@ -2716,7 +2815,7 @@ void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) { codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); } -void LocationsBuilderX86::VisitTypeCheck(HTypeCheck* instruction) { +void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) { LocationSummary::CallKind call_kind = instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath; @@ -2726,7 +2825,7 @@ void LocationsBuilderX86::VisitTypeCheck(HTypeCheck* instruction) { locations->SetOut(Location::RequiresRegister()); } -void InstructionCodeGeneratorX86::VisitTypeCheck(HTypeCheck* instruction) { +void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { LocationSummary* locations = instruction->GetLocations(); Register obj = locations->InAt(0).As<Register>(); Location cls = locations->InAt(1); @@ -2757,7 +2856,7 @@ void InstructionCodeGeneratorX86::VisitTypeCheck(HTypeCheck* instruction) { // If the classes are not equal, we go into a slow path. DCHECK(locations->OnlyCallsOnSlowPath()); slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86( - instruction, Location::RegisterLocation(out)); + instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc()); codegen_->AddSlowPath(slow_path); __ j(kNotEqual, slow_path->GetEntryLabel()); __ movl(out, Immediate(1)); @@ -2771,5 +2870,148 @@ void InstructionCodeGeneratorX86::VisitTypeCheck(HTypeCheck* instruction) { __ Bind(&done); } +void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( + instruction, LocationSummary::kCallOnSlowPath); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::Any()); + locations->AddTemp(Location::RequiresRegister()); +} + +void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Register obj = locations->InAt(0).As<Register>(); + Location cls = locations->InAt(1); + Register temp = locations->GetTemp(0).As<Register>(); + uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86( + instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc()); + codegen_->AddSlowPath(slow_path); + + // TODO: avoid this check if we know obj is not null. + __ testl(obj, obj); + __ j(kEqual, slow_path->GetExitLabel()); + __ movl(temp, Address(obj, class_offset)); + + // Compare the class of `obj` with `cls`. + if (cls.IsRegister()) { + __ cmpl(temp, cls.As<Register>()); + } else { + DCHECK(cls.IsStackSlot()) << cls; + __ cmpl(temp, Address(ESP, cls.GetStackIndex())); + } + + __ j(kNotEqual, slow_path->GetEntryLabel()); + __ Bind(slow_path->GetExitLabel()); +} + +void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); +} + +void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) { + __ fs()->call(Address::Absolute(instruction->IsEnter() + ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject) + : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject))); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); +} + +void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } + +void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt + || instruction->GetResultType() == Primitive::kPrimLong); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::Any()); + locations->SetOut(Location::SameAsFirstInput()); +} + +void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + DCHECK(first.Equals(locations->Out())); + + if (instruction->GetResultType() == Primitive::kPrimInt) { + if (second.IsRegister()) { + if (instruction->IsAnd()) { + __ andl(first.As<Register>(), second.As<Register>()); + } else if (instruction->IsOr()) { + __ orl(first.As<Register>(), second.As<Register>()); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<Register>(), second.As<Register>()); + } + } else if (second.IsConstant()) { + if (instruction->IsAnd()) { + __ andl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue())); + } else if (instruction->IsOr()) { + __ orl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue())); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue())); + } + } else { + if (instruction->IsAnd()) { + __ andl(first.As<Register>(), Address(ESP, second.GetStackIndex())); + } else if (instruction->IsOr()) { + __ orl(first.As<Register>(), Address(ESP, second.GetStackIndex())); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<Register>(), Address(ESP, second.GetStackIndex())); + } + } + } else { + DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); + if (second.IsRegisterPair()) { + if (instruction->IsAnd()) { + __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); + __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); + } else if (instruction->IsOr()) { + __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); + __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); + __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); + } + } else { + if (instruction->IsAnd()) { + __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); + __ andl(first.AsRegisterPairHigh<Register>(), + Address(ESP, second.GetHighStackIndex(kX86WordSize))); + } else if (instruction->IsOr()) { + __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); + __ orl(first.AsRegisterPairHigh<Register>(), + Address(ESP, second.GetHighStackIndex(kX86WordSize))); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); + __ xorl(first.AsRegisterPairHigh<Register>(), + Address(ESP, second.GetHighStackIndex(kX86WordSize))); + } + } + } +} + } // namespace x86 } // namespace art diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 85fe21ca76..9e42b0a90c 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -100,9 +100,10 @@ class LocationsBuilderX86 : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION + private: + void HandleBitwiseOperation(HBinaryOperation* instruction); void HandleInvoke(HInvoke* invoke); - private: CodeGeneratorX86* const codegen_; InvokeDexCallingConventionVisitor parameter_visitor_; @@ -128,6 +129,7 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { // the suspend call. void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeX86* slow_path, Register class_reg); + void HandleBitwiseOperation(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 b9891d6cd9..3c7dd3f56a 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -284,13 +284,19 @@ class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 { class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 { public: - TypeCheckSlowPathX86_64(HTypeCheck* instruction, Location object_class) + TypeCheckSlowPathX86_64(HInstruction* instruction, + Location class_to_check, + Location object_class, + uint32_t dex_pc) : instruction_(instruction), - object_class_(object_class) {} + class_to_check_(class_to_check), + object_class_(object_class), + dex_pc_(dex_pc) {} virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + DCHECK(instruction_->IsCheckCast() + || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen); __ Bind(GetEntryLabel()); @@ -299,7 +305,7 @@ class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 { // We're moving two locations to locations that could overlap, so we need a parallel // move resolver. InvokeRuntimeCallingConvention calling_convention; - MoveOperands move1(locations->InAt(1), + MoveOperands move1(class_to_check_, Location::RegisterLocation(calling_convention.GetRegisterAt(0)), nullptr); MoveOperands move2(object_class_, @@ -310,18 +316,29 @@ class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 { parallel_move.AddMove(&move2); x64_codegen->GetMoveResolver()->EmitNativeCode(¶llel_move); - __ gs()->call( - Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true)); - codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); - x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX)); + if (instruction_->IsInstanceOf()) { + __ gs()->call( + Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true)); + } else { + DCHECK(instruction_->IsCheckCast()); + __ gs()->call( + Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true)); + } + codegen->RecordPcInfo(instruction_, dex_pc_); + + if (instruction_->IsInstanceOf()) { + x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX)); + } codegen->RestoreLiveRegisters(locations); __ jmp(GetExitLabel()); } private: - HTypeCheck* const instruction_; + HInstruction* const instruction_; + const Location class_to_check_; const Location object_class_; + const uint32_t dex_pc_; DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64); }; @@ -1079,10 +1096,6 @@ void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } -void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) { - HandleInvoke(invoke); -} - void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); @@ -1115,6 +1128,10 @@ void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) { } } +void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) { + HandleInvoke(invoke); +} + void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) { CpuRegister temp = invoke->GetLocations()->GetTemp(0).As<CpuRegister>(); size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() + @@ -1138,6 +1155,41 @@ void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) { + HandleInvoke(invoke); + // Add the hidden argument. + invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX)); +} + +void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) { + // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. + CpuRegister temp = invoke->GetLocations()->GetTemp(0).As<CpuRegister>(); + uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + + (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); + size_t class_offset = mirror::Object::ClassOffset().SizeValue(); + + // Set the hidden argument. + __ movq(invoke->GetLocations()->GetTemp(1).As<CpuRegister>(), + Immediate(invoke->GetDexMethodIndex())); + + // temp = object->GetClass(); + if (receiver.IsStackSlot()) { + __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex())); + __ movl(temp, Address(temp, class_offset)); + } else { + __ movl(temp, Address(receiver.As<CpuRegister>(), class_offset)); + } + // temp = temp->GetImtEntryAt(method_offset); + __ movl(temp, Address(temp, method_offset)); + // call temp->GetEntryPoint(); + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue())); + + DCHECK(!codegen_->IsLeafMethod()); + codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); +} + void LocationsBuilderX86_64::VisitNeg(HNeg* neg) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); @@ -1224,11 +1276,32 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); switch (result_type) { + case Primitive::kPrimInt: + switch (input_type) { + case Primitive::kPrimLong: + // long-to-int conversion. + locations->SetInAt(0, Location::Any()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + case Primitive::kPrimFloat: + 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::kPrimLong: switch (input_type) { case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: + case Primitive::kPrimChar: // int-to-long conversion. // TODO: We would benefit from a (to-be-implemented) // Location::RegisterOrStackSlot requirement for this input. @@ -1248,7 +1321,6 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { } break; - case Primitive::kPrimInt: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1268,12 +1340,42 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); switch (result_type) { + case Primitive::kPrimInt: + switch (input_type) { + case Primitive::kPrimLong: + // long-to-int conversion. + if (in.IsRegister()) { + __ movl(out.As<CpuRegister>(), in.As<CpuRegister>()); + } else if (in.IsDoubleStackSlot()) { + __ movl(out.As<CpuRegister>(), + Address(CpuRegister(RSP), in.GetStackIndex())); + } else { + DCHECK(in.IsConstant()); + DCHECK(in.GetConstant()->IsLongConstant()); + int64_t value = in.GetConstant()->AsLongConstant()->GetValue(); + __ movl(out.As<CpuRegister>(), Immediate(static_cast<int32_t>(value))); + } + break; + + case Primitive::kPrimFloat: + 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::kPrimLong: switch (input_type) { DCHECK(out.IsRegister()); case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: + case Primitive::kPrimChar: // int-to-long conversion. DCHECK(in.IsRegister()); __ movsxd(out.As<CpuRegister>(), in.As<CpuRegister>()); @@ -1291,7 +1393,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } break; - case Primitive::kPrimInt: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -2706,7 +2807,7 @@ void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) { codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); } -void LocationsBuilderX86_64::VisitTypeCheck(HTypeCheck* instruction) { +void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) { LocationSummary::CallKind call_kind = instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath; @@ -2716,7 +2817,7 @@ void LocationsBuilderX86_64::VisitTypeCheck(HTypeCheck* instruction) { locations->SetOut(Location::RequiresRegister()); } -void InstructionCodeGeneratorX86_64::VisitTypeCheck(HTypeCheck* instruction) { +void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { LocationSummary* locations = instruction->GetLocations(); CpuRegister obj = locations->InAt(0).As<CpuRegister>(); Location cls = locations->InAt(1); @@ -2746,7 +2847,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeCheck(HTypeCheck* instruction) { // If the classes are not equal, we go into a slow path. DCHECK(locations->OnlyCallsOnSlowPath()); slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64( - instruction, Location::RegisterLocation(out.AsRegister())); + instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc()); codegen_->AddSlowPath(slow_path); __ j(kNotEqual, slow_path->GetEntryLabel()); __ movl(out, Immediate(1)); @@ -2760,5 +2861,135 @@ void InstructionCodeGeneratorX86_64::VisitTypeCheck(HTypeCheck* instruction) { __ Bind(&done); } +void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( + instruction, LocationSummary::kCallOnSlowPath); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::Any()); + locations->AddTemp(Location::RequiresRegister()); +} + +void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { + LocationSummary* locations = instruction->GetLocations(); + CpuRegister obj = locations->InAt(0).As<CpuRegister>(); + Location cls = locations->InAt(1); + CpuRegister temp = locations->GetTemp(0).As<CpuRegister>(); + uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64( + instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc()); + codegen_->AddSlowPath(slow_path); + + // TODO: avoid this check if we know obj is not null. + __ testl(obj, obj); + __ j(kEqual, slow_path->GetExitLabel()); + // Compare the class of `obj` with `cls`. + __ movl(temp, Address(obj, class_offset)); + if (cls.IsRegister()) { + __ cmpl(temp, cls.As<CpuRegister>()); + } else { + DCHECK(cls.IsStackSlot()) << cls; + __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex())); + } + // Classes must be equal for the checkcast to succeed. + __ j(kNotEqual, slow_path->GetEntryLabel()); + __ Bind(slow_path->GetExitLabel()); +} + +void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); +} + +void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) { + __ gs()->call(Address::Absolute(instruction->IsEnter() + ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject) + : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject), + true)); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); +} + +void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } + +void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt + || instruction->GetResultType() == Primitive::kPrimLong); + locations->SetInAt(0, Location::RequiresRegister()); + if (instruction->GetType() == Primitive::kPrimInt) { + locations->SetInAt(1, Location::Any()); + } else { + // Request a register to avoid loading a 64bits constant. + locations->SetInAt(1, Location::RequiresRegister()); + } + locations->SetOut(Location::SameAsFirstInput()); +} + +void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + DCHECK(first.Equals(locations->Out())); + + if (instruction->GetResultType() == Primitive::kPrimInt) { + if (second.IsRegister()) { + if (instruction->IsAnd()) { + __ andl(first.As<CpuRegister>(), second.As<CpuRegister>()); + } else if (instruction->IsOr()) { + __ orl(first.As<CpuRegister>(), second.As<CpuRegister>()); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<CpuRegister>(), second.As<CpuRegister>()); + } + } else if (second.IsConstant()) { + Immediate imm(second.GetConstant()->AsIntConstant()->GetValue()); + if (instruction->IsAnd()) { + __ andl(first.As<CpuRegister>(), imm); + } else if (instruction->IsOr()) { + __ orl(first.As<CpuRegister>(), imm); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<CpuRegister>(), imm); + } + } else { + Address address(CpuRegister(RSP), second.GetStackIndex()); + if (instruction->IsAnd()) { + __ andl(first.As<CpuRegister>(), address); + } else if (instruction->IsOr()) { + __ orl(first.As<CpuRegister>(), address); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<CpuRegister>(), address); + } + } + } else { + DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); + if (instruction->IsAnd()) { + __ andq(first.As<CpuRegister>(), second.As<CpuRegister>()); + } else if (instruction->IsOr()) { + __ orq(first.As<CpuRegister>(), second.As<CpuRegister>()); + } else { + DCHECK(instruction->IsXor()); + __ xorq(first.As<CpuRegister>(), second.As<CpuRegister>()); + } + } +} + } // namespace x86_64 } // namespace art diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 9565b6f876..52806f34d4 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -104,9 +104,10 @@ class LocationsBuilderX86_64 : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION + private: void HandleInvoke(HInvoke* invoke); + void HandleBitwiseOperation(HBinaryOperation* operation); - private: CodeGeneratorX86_64* const codegen_; InvokeDexCallingConventionVisitor parameter_visitor_; @@ -132,6 +133,7 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor { // the suspend call. void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg); + void HandleBitwiseOperation(HBinaryOperation* operation); X86_64Assembler* const assembler_; CodeGeneratorX86_64* const codegen_; diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index ecee44392e..9752b1d34b 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -362,6 +362,27 @@ NOT_LONG_TEST(ReturnNotLongINT64_MAX, #undef NOT_LONG_TEST +#if defined(__aarch64__) +TEST(CodegenTest, DISABLED_IntToLongOfLongToInt) { +#else +TEST(CodegenTest, IntToLongOfLongToInt) { +#endif + const int64_t input = INT64_C(4294967296); // 2^32 + const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW. + const uint16_t word1 = High16Bits(Low32Bits(input)); + const uint16_t word2 = Low16Bits(High32Bits(input)); + const uint16_t word3 = High16Bits(High32Bits(input)); // MSW. + const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM( + Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, + Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0, + Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1 + Instruction::LONG_TO_INT | 4 << 8 | 0 << 12, + Instruction::INT_TO_LONG | 2 << 8 | 4 << 12, + Instruction::RETURN_WIDE | 2 << 8); + + TestCodeLong(data, true, 1); +} + TEST(CodegenTest, ReturnAdd1) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 3 << 12 | 0, diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index ecf8c370f0..6224a11f24 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -475,10 +475,12 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { #define FOR_EACH_CONCRETE_INSTRUCTION(M) \ M(Add, BinaryOperation) \ + M(And, BinaryOperation) \ M(ArrayGet, Instruction) \ M(ArrayLength, Instruction) \ M(ArraySet, Instruction) \ M(BoundsCheck, Instruction) \ + M(CheckCast, Instruction) \ M(ClinitCheck, Instruction) \ M(Compare, BinaryOperation) \ M(Condition, BinaryOperation) \ @@ -494,7 +496,9 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(If, Instruction) \ M(InstanceFieldGet, Instruction) \ M(InstanceFieldSet, Instruction) \ + M(InstanceOf, Instruction) \ M(IntConstant, Constant) \ + M(InvokeInterface, Invoke) \ M(InvokeStatic, Invoke) \ M(InvokeVirtual, Invoke) \ M(LessThan, Condition) \ @@ -505,6 +509,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(LoadString, Instruction) \ M(Local, Instruction) \ M(LongConstant, Constant) \ + M(MonitorOperation, Instruction) \ M(Mul, BinaryOperation) \ M(Neg, UnaryOperation) \ M(NewArray, Instruction) \ @@ -512,6 +517,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(Not, UnaryOperation) \ M(NotEqual, Condition) \ M(NullCheck, Instruction) \ + M(Or, BinaryOperation) \ M(ParallelMove, Instruction) \ M(ParameterValue, Instruction) \ M(Phi, Instruction) \ @@ -524,8 +530,8 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(SuspendCheck, Instruction) \ M(Temporary, Instruction) \ M(Throw, Instruction) \ - M(TypeCheck, Instruction) \ M(TypeConversion, Instruction) \ + M(Xor, BinaryOperation) \ #define FOR_EACH_INSTRUCTION(M) \ FOR_EACH_CONCRETE_INSTRUCTION(M) \ @@ -1604,6 +1610,30 @@ class HInvokeVirtual : public HInvoke { DISALLOW_COPY_AND_ASSIGN(HInvokeVirtual); }; +class HInvokeInterface : public HInvoke { + public: + HInvokeInterface(ArenaAllocator* arena, + uint32_t number_of_arguments, + Primitive::Type return_type, + uint32_t dex_pc, + uint32_t dex_method_index, + uint32_t imt_index) + : HInvoke(arena, number_of_arguments, return_type, dex_pc), + dex_method_index_(dex_method_index), + imt_index_(imt_index) {} + + uint32_t GetImtIndex() const { return imt_index_; } + uint32_t GetDexMethodIndex() const { return dex_method_index_; } + + DECLARE_INSTRUCTION(InvokeInterface); + + private: + const uint32_t dex_method_index_; + const uint32_t imt_index_; + + DISALLOW_COPY_AND_ASSIGN(HInvokeInterface); +}; + class HNewInstance : public HExpression<0> { public: HNewInstance(uint32_t dex_pc, uint16_t type_index) @@ -1764,6 +1794,54 @@ class HDivZeroCheck : public HExpression<1> { DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck); }; +class HAnd : public HBinaryOperation { + public: + HAnd(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + bool IsCommutative() OVERRIDE { return true; } + + int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x & y; } + int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x & y; } + + DECLARE_INSTRUCTION(And); + + private: + DISALLOW_COPY_AND_ASSIGN(HAnd); +}; + +class HOr : public HBinaryOperation { + public: + HOr(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + bool IsCommutative() OVERRIDE { return true; } + + int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x | y; } + int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x | y; } + + DECLARE_INSTRUCTION(Or); + + private: + DISALLOW_COPY_AND_ASSIGN(HOr); +}; + +class HXor : public HBinaryOperation { + public: + HXor(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + bool IsCommutative() OVERRIDE { return true; } + + int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x ^ y; } + int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x ^ y; } + + DECLARE_INSTRUCTION(Xor); + + private: + DISALLOW_COPY_AND_ASSIGN(HXor); +}; + // The value of a parameter in this method. Its location depends on // the calling convention. class HParameterValue : public HExpression<0> { @@ -2089,7 +2167,11 @@ class HTemporary : public HTemplateInstruction<0> { size_t GetIndex() const { return index_; } - Primitive::Type GetType() const OVERRIDE { return GetPrevious()->GetType(); } + Primitive::Type GetType() const OVERRIDE { + // The previous instruction is the one that will be stored in the temporary location. + DCHECK(GetPrevious() != nullptr); + return GetPrevious()->GetType(); + } DECLARE_INSTRUCTION(Temporary); @@ -2326,12 +2408,12 @@ class HThrow : public HTemplateInstruction<1> { DISALLOW_COPY_AND_ASSIGN(HThrow); }; -class HTypeCheck : public HExpression<2> { +class HInstanceOf : public HExpression<2> { public: - explicit HTypeCheck(HInstruction* object, - HLoadClass* constant, - bool class_is_final, - uint32_t dex_pc) + HInstanceOf(HInstruction* object, + HLoadClass* constant, + bool class_is_final, + uint32_t dex_pc) : HExpression(Primitive::kPrimBoolean, SideEffects::None()), class_is_final_(class_is_final), dex_pc_(dex_pc) { @@ -2341,13 +2423,11 @@ class HTypeCheck : public HExpression<2> { bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } bool NeedsEnvironment() const OVERRIDE { - // TODO: Can we debug when doing a runtime instanceof check? return false; } @@ -2355,13 +2435,82 @@ class HTypeCheck : public HExpression<2> { bool IsClassFinal() const { return class_is_final_; } - DECLARE_INSTRUCTION(TypeCheck); + DECLARE_INSTRUCTION(InstanceOf); + + private: + const bool class_is_final_; + const uint32_t dex_pc_; + + DISALLOW_COPY_AND_ASSIGN(HInstanceOf); +}; + +class HCheckCast : public HTemplateInstruction<2> { + public: + HCheckCast(HInstruction* object, + HLoadClass* constant, + bool class_is_final, + uint32_t dex_pc) + : HTemplateInstruction(SideEffects::None()), + class_is_final_(class_is_final), + dex_pc_(dex_pc) { + SetRawInputAt(0, object); + SetRawInputAt(1, constant); + } + + bool CanBeMoved() const OVERRIDE { return true; } + + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { + return true; + } + + bool NeedsEnvironment() const OVERRIDE { + // Instruction may throw a CheckCastError. + return true; + } + + bool CanThrow() const OVERRIDE { return true; } + + uint32_t GetDexPc() const { return dex_pc_; } + + bool IsClassFinal() const { return class_is_final_; } + + DECLARE_INSTRUCTION(CheckCast); private: const bool class_is_final_; const uint32_t dex_pc_; - DISALLOW_COPY_AND_ASSIGN(HTypeCheck); + DISALLOW_COPY_AND_ASSIGN(HCheckCast); +}; + +class HMonitorOperation : public HTemplateInstruction<1> { + public: + enum OperationKind { + kEnter, + kExit, + }; + + HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc) + : HTemplateInstruction(SideEffects::None()), kind_(kind), dex_pc_(dex_pc) { + SetRawInputAt(0, object); + } + + // Instruction may throw a Java exception, so we need an environment. + bool NeedsEnvironment() const OVERRIDE { return true; } + bool CanThrow() const OVERRIDE { return true; } + + uint32_t GetDexPc() const { return dex_pc_; } + + bool IsEnter() const { return kind_ == kEnter; } + + DECLARE_INSTRUCTION(MonitorOperation); + + protected: + const OperationKind kind_; + const uint32_t dex_pc_; + + private: + DISALLOW_COPY_AND_ASSIGN(HMonitorOperation); }; diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index 4a9deea376..4d6e66413d 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -185,10 +185,11 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { // Create synthesized intervals for temporaries. for (size_t i = 0; i < locations->GetTempCount(); ++i) { Location temp = locations->GetTemp(i); - if (temp.IsRegister()) { + if (temp.IsRegister() || temp.IsFpuRegister()) { BlockRegister(temp, position, position + 1); } else { DCHECK(temp.IsUnallocated()); + DCHECK(temp.GetPolicy() == Location::kRequiresRegister); LiveInterval* interval = LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt); temp_intervals_.Add(interval); interval->AddRange(position, position + 1); diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index e83c528fab..fec40f93c7 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -253,4 +253,9 @@ void SsaBuilder::VisitInstruction(HInstruction* instruction) { instruction->SetEnvironment(environment); } +void SsaBuilder::VisitTemporary(HTemporary* temp) { + // Temporaries are only used by the baseline register allocator. + temp->GetBlock()->RemoveInstruction(temp); +} + } // namespace art diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h index 24f5ac55f7..2207cd6bfa 100644 --- a/compiler/optimizing/ssa_builder.h +++ b/compiler/optimizing/ssa_builder.h @@ -51,6 +51,7 @@ class SsaBuilder : public HGraphVisitor { void VisitLoadLocal(HLoadLocal* load); void VisitStoreLocal(HStoreLocal* store); void VisitInstruction(HInstruction* instruction); + void VisitTemporary(HTemporary* instruction); static HInstruction* GetFloatOrDoubleEquivalent(HInstruction* user, HInstruction* instruction, diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 4ddf9793fd..8ebb40e338 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -873,6 +873,13 @@ void X86Assembler::andl(Register dst, Register src) { } +void X86Assembler::andl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x23); + EmitOperand(reg, address); +} + + void X86Assembler::andl(Register dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitComplex(4, Operand(dst), imm); @@ -886,6 +893,13 @@ void X86Assembler::orl(Register dst, Register src) { } +void X86Assembler::orl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0B); + EmitOperand(reg, address); +} + + void X86Assembler::orl(Register dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitComplex(1, Operand(dst), imm); @@ -898,11 +912,20 @@ void X86Assembler::xorl(Register dst, Register src) { EmitOperand(dst, Operand(src)); } + +void X86Assembler::xorl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x33); + EmitOperand(reg, address); +} + + void X86Assembler::xorl(Register dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitComplex(6, Operand(dst), imm); } + void X86Assembler::addl(Register reg, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitComplex(0, Operand(reg), imm); diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index de4e6de878..8aed9348d6 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -350,12 +350,15 @@ class X86Assembler FINAL : public Assembler { void andl(Register dst, const Immediate& imm); void andl(Register dst, Register src); + void andl(Register dst, const Address& address); void orl(Register dst, const Immediate& imm); void orl(Register dst, Register src); + void orl(Register dst, const Address& address); void xorl(Register dst, Register src); void xorl(Register dst, const Immediate& imm); + void xorl(Register dst, const Address& address); void addl(Register dst, Register src); void addl(Register reg, const Immediate& imm); diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index 5b706584bd..5d1c9af202 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -120,6 +120,7 @@ void X86_64Assembler::movq(CpuRegister dst, const Immediate& imm) { void X86_64Assembler::movl(CpuRegister dst, const Immediate& imm) { + CHECK(imm.is_int32()); AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst); EmitUint8(0xB8 + dst.LowBits()); @@ -353,7 +354,7 @@ void X86_64Assembler::movss(XmmRegister dst, XmmRegister src) { void X86_64Assembler::movsxd(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - EmitRex64(dst); + EmitRex64(dst, src); EmitUint8(0x63); EmitRegisterOperand(dst.LowBits(), src.LowBits()); } @@ -1013,6 +1014,14 @@ void X86_64Assembler::andl(CpuRegister dst, CpuRegister src) { } +void X86_64Assembler::andl(CpuRegister reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(reg, address); + EmitUint8(0x23); + EmitOperand(reg.LowBits(), address); +} + + void X86_64Assembler::andl(CpuRegister dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst); @@ -1028,6 +1037,14 @@ void X86_64Assembler::andq(CpuRegister reg, const Immediate& imm) { } +void X86_64Assembler::andq(CpuRegister dst, CpuRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitRex64(dst, src); + EmitUint8(0x23); + EmitOperand(dst.LowBits(), Operand(src)); +} + + void X86_64Assembler::orl(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst, src); @@ -1036,6 +1053,14 @@ void X86_64Assembler::orl(CpuRegister dst, CpuRegister src) { } +void X86_64Assembler::orl(CpuRegister reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(reg, address); + EmitUint8(0x0B); + EmitOperand(reg.LowBits(), address); +} + + void X86_64Assembler::orl(CpuRegister dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst); @@ -1043,6 +1068,14 @@ void X86_64Assembler::orl(CpuRegister dst, const Immediate& imm) { } +void X86_64Assembler::orq(CpuRegister dst, CpuRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitRex64(dst, src); + EmitUint8(0x0B); + EmitOperand(dst.LowBits(), Operand(src)); +} + + void X86_64Assembler::xorl(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst, src); @@ -1051,6 +1084,21 @@ void X86_64Assembler::xorl(CpuRegister dst, CpuRegister src) { } +void X86_64Assembler::xorl(CpuRegister reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(reg, address); + EmitUint8(0x33); + EmitOperand(reg.LowBits(), address); +} + + +void X86_64Assembler::xorl(CpuRegister dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(dst); + EmitComplex(6, Operand(dst), imm); +} + + void X86_64Assembler::xorq(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitRex64(dst, src); diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 42d774a558..285b4cfc43 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -398,12 +398,18 @@ class X86_64Assembler FINAL : public Assembler { void andl(CpuRegister dst, const Immediate& imm); void andl(CpuRegister dst, CpuRegister src); + void andl(CpuRegister reg, const Address& address); void andq(CpuRegister dst, const Immediate& imm); + void andq(CpuRegister dst, CpuRegister src); void orl(CpuRegister dst, const Immediate& imm); void orl(CpuRegister dst, CpuRegister src); + void orl(CpuRegister reg, const Address& address); + void orq(CpuRegister dst, CpuRegister src); void xorl(CpuRegister dst, CpuRegister src); + void xorl(CpuRegister dst, const Immediate& imm); + void xorl(CpuRegister reg, const Address& address); void xorq(CpuRegister dst, const Immediate& imm); void xorq(CpuRegister dst, CpuRegister src); |