diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/builder.cc | 66 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 55 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 10 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 56 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips64.h | 8 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 9 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 8 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 348 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_mips64.cc | 14 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 311 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 28 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_cfi_test_expected.inc | 19 |
13 files changed, 679 insertions, 257 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 37218139fb..c7430e7eb6 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -798,7 +798,7 @@ static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) { ArtMethod* HGraphBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_type) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); + StackHandleScope<3> hs(soa.Self()); ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker(); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( @@ -833,31 +833,56 @@ ArtMethod* HGraphBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_t } // We have to special case the invoke-super case, as ClassLinker::ResolveMethod does not. - // We need to look at the referrer's super class vtable. + // We need to look at the referrer's super class vtable. We need to do this to know if we need to + // make this an invoke-unresolved to handle cross-dex invokes or abstract super methods, both of + // which require runtime handling. if (invoke_type == kSuper) { if (compiling_class.Get() == nullptr) { - // Invoking a super method requires knowing the actual super class. If we did not resolve - // the compiling method's declaring class (which only happens for ahead of time compilation), - // bail out. + // We could not determine the method's class we need to wait until runtime. DCHECK(Runtime::Current()->IsAotCompiler()); return nullptr; } - uint16_t vtable_index = resolved_method->GetMethodIndex(); - ArtMethod* actual_method = compiling_class->GetSuperClass()->GetVTableEntry( - vtable_index, class_linker->GetImagePointerSize()); - if (actual_method != resolved_method && - !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { - // TODO: The actual method could still be referenced in the current dex file, so we - // could try locating it. - // TODO: Remove the dex_file restriction. - return nullptr; - } - if (!actual_method->IsInvokable()) { - // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub - // could resolve the callee to the wrong method. + ArtMethod* current_method = graph_->GetArtMethod(); + DCHECK(current_method != nullptr); + Handle<mirror::Class> methods_class(hs.NewHandle( + dex_compilation_unit_->GetClassLinker()->ResolveReferencedClassOfMethod(Thread::Current(), + method_idx, + current_method))); + if (methods_class.Get() == nullptr) { + // Invoking a super method requires knowing the actual super class. If we did not resolve + // the compiling method's declaring class (which only happens for ahead of time + // compilation), bail out. + DCHECK(Runtime::Current()->IsAotCompiler()); return nullptr; + } else { + ArtMethod* actual_method; + if (methods_class->IsInterface()) { + actual_method = methods_class->FindVirtualMethodForInterfaceSuper( + resolved_method, class_linker->GetImagePointerSize()); + } else { + uint16_t vtable_index = resolved_method->GetMethodIndex(); + actual_method = compiling_class->GetSuperClass()->GetVTableEntry( + vtable_index, class_linker->GetImagePointerSize()); + } + if (actual_method != resolved_method && + !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { + // The back-end code generator relies on this check in order to ensure that it will not + // attempt to read the dex_cache with a dex_method_index that is not from the correct + // dex_file. If we didn't do this check then the dex_method_index will not be updated in the + // builder, which means that the code-generator (and compiler driver during sharpening and + // inliner, maybe) might invoke an incorrect method. + // TODO: The actual method could still be referenced in the current dex file, so we + // could try locating it. + // TODO: Remove the dex_file restriction. + return nullptr; + } + if (!actual_method->IsInvokable()) { + // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub + // could resolve the callee to the wrong method. + return nullptr; + } + resolved_method = actual_method; } - resolved_method = actual_method; } // Check for incompatible class changes. The class linker has a fast path for @@ -923,7 +948,7 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, ArtMethod* resolved_method = ResolveMethod(method_idx, invoke_type); - if (resolved_method == nullptr) { + if (UNLIKELY(resolved_method == nullptr)) { MaybeRecordStat(MethodCompilationStat::kUnresolvedMethod); HInvoke* invoke = new (arena_) HInvokeUnresolved(arena_, number_of_arguments, @@ -943,7 +968,6 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, // Potential class initialization check, in the case of a static method call. HClinitCheck* clinit_check = nullptr; HInvoke* invoke = nullptr; - if (invoke_type == kDirect || invoke_type == kStatic || invoke_type == kSuper) { // By default, consider that the called method implicitly requires // an initialization check of its declaring method. diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index a59024e139..4179fabe48 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -1556,21 +1556,13 @@ void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCod UseScratchRegisterScope temps(GetVIXLAssembler()); Register temp = temps.AcquireW(); size_t status_offset = mirror::Class::StatusOffset().SizeValue(); - bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease(); // Even if the initialized flag is set, we need to ensure consistent memory ordering. - if (use_acquire_release) { - // TODO(vixl): Let the MacroAssembler handle MemOperand. - __ Add(temp, class_reg, status_offset); - __ Ldar(temp, HeapOperand(temp)); - __ Cmp(temp, mirror::Class::kStatusInitialized); - __ B(lt, slow_path->GetEntryLabel()); - } else { - __ Ldr(temp, HeapOperand(class_reg, status_offset)); - __ Cmp(temp, mirror::Class::kStatusInitialized); - __ B(lt, slow_path->GetEntryLabel()); - __ Dmb(InnerShareable, BarrierReads); - } + // TODO(vixl): Let the MacroAssembler handle MemOperand. + __ Add(temp, class_reg, status_offset); + __ Ldar(temp, HeapOperand(temp)); + __ Cmp(temp, mirror::Class::kStatusInitialized); + __ B(lt, slow_path->GetEntryLabel()); __ Bind(slow_path->GetExitLabel()); } @@ -1716,9 +1708,7 @@ void InstructionCodeGeneratorARM64::HandleFieldGet(HInstruction* instruction, uint32_t offset = field_info.GetFieldOffset().Uint32Value(); Primitive::Type field_type = field_info.GetFieldType(); BlockPoolsScope block_pools(GetVIXLAssembler()); - MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), field_info.GetFieldOffset()); - bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease(); if (field_type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) { // Object FieldGet with Baker's read barrier case. @@ -1736,26 +1726,15 @@ void InstructionCodeGeneratorARM64::HandleFieldGet(HInstruction* instruction, offset, temp, /* needs_null_check */ true, - field_info.IsVolatile() && use_acquire_release); - if (field_info.IsVolatile() && !use_acquire_release) { - // For IRIW sequential consistency kLoadAny is not sufficient. - codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny); - } + field_info.IsVolatile()); } else { // General case. if (field_info.IsVolatile()) { - if (use_acquire_release) { - // Note that a potential implicit null check is handled in this - // CodeGeneratorARM64::LoadAcquire call. - // NB: LoadAcquire will record the pc info if needed. - codegen_->LoadAcquire( - instruction, OutputCPURegister(instruction), field, /* needs_null_check */ true); - } else { - codegen_->Load(field_type, OutputCPURegister(instruction), field); - codegen_->MaybeRecordImplicitNullCheck(instruction); - // For IRIW sequential consistency kLoadAny is not sufficient. - codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny); - } + // Note that a potential implicit null check is handled in this + // CodeGeneratorARM64::LoadAcquire call. + // NB: LoadAcquire will record the pc info if needed. + codegen_->LoadAcquire( + instruction, OutputCPURegister(instruction), field, /* needs_null_check */ true); } else { codegen_->Load(field_type, OutputCPURegister(instruction), field); codegen_->MaybeRecordImplicitNullCheck(instruction); @@ -1791,7 +1770,6 @@ void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction, CPURegister source = value; Offset offset = field_info.GetFieldOffset(); Primitive::Type field_type = field_info.GetFieldType(); - bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease(); { // We use a block to end the scratch scope before the write barrier, thus @@ -1807,15 +1785,8 @@ void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction, } if (field_info.IsVolatile()) { - if (use_acquire_release) { - codegen_->StoreRelease(field_type, source, HeapOperand(obj, offset)); - codegen_->MaybeRecordImplicitNullCheck(instruction); - } else { - codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore); - codegen_->Store(field_type, source, HeapOperand(obj, offset)); - codegen_->MaybeRecordImplicitNullCheck(instruction); - codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny); - } + codegen_->StoreRelease(field_type, source, HeapOperand(obj, offset)); + codegen_->MaybeRecordImplicitNullCheck(instruction); } else { codegen_->Store(field_type, source, HeapOperand(obj, offset)); codegen_->MaybeRecordImplicitNullCheck(instruction); diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 85ffd66ce8..f92a68f6ba 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -634,11 +634,11 @@ void ParallelMoveResolverMIPS::EmitSwap(size_t index) { intptr_t offset_h = loc1.IsDoubleStackSlot() ? loc1.GetHighStackIndex(kMipsWordSize) : loc2.GetHighStackIndex(kMipsWordSize); __ Move(TMP, reg_l); - __ Move(AT, reg_h); __ LoadFromOffset(kLoadWord, reg_l, SP, offset_l); - __ LoadFromOffset(kLoadWord, reg_h, SP, offset_h); __ StoreToOffset(kStoreWord, TMP, SP, offset_l); - __ StoreToOffset(kStoreWord, AT, SP, offset_h); + __ Move(TMP, reg_h); + __ LoadFromOffset(kLoadWord, reg_h, SP, offset_h); + __ StoreToOffset(kStoreWord, TMP, SP, offset_h); } else { LOG(FATAL) << "Swap between " << loc1 << " and " << loc2 << " is unsupported"; } @@ -1132,11 +1132,11 @@ size_t CodeGeneratorMIPS::RestoreFloatingPointRegister(size_t stack_index, uint3 } void CodeGeneratorMIPS::DumpCoreRegister(std::ostream& stream, int reg) const { - stream << MipsManagedRegister::FromCoreRegister(Register(reg)); + stream << Register(reg); } void CodeGeneratorMIPS::DumpFloatingPointRegister(std::ostream& stream, int reg) const { - stream << MipsManagedRegister::FromFRegister(FRegister(reg)); + stream << FRegister(reg); } void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint, diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 3c928dedde..3e1563c66b 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -106,7 +106,7 @@ Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type) } #define __ down_cast<CodeGeneratorMIPS64*>(codegen)->GetAssembler()-> -#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, x).Int32Value() +#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, x).Int32Value() class BoundsCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 { public: @@ -437,7 +437,7 @@ CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph, #undef __ #define __ down_cast<Mips64Assembler*>(GetAssembler())-> -#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, x).Int32Value() +#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, x).Int32Value() void CodeGeneratorMIPS64::Finalize(CodeAllocator* allocator) { // Ensure that we fix up branches. @@ -486,12 +486,12 @@ void ParallelMoveResolverMIPS64::EmitSwap(size_t index) { void ParallelMoveResolverMIPS64::RestoreScratch(int reg) { // Pop reg __ Ld(GpuRegister(reg), SP, 0); - __ DecreaseFrameSize(kMips64WordSize); + __ DecreaseFrameSize(kMips64DoublewordSize); } void ParallelMoveResolverMIPS64::SpillScratch(int reg) { // Push reg - __ IncreaseFrameSize(kMips64WordSize); + __ IncreaseFrameSize(kMips64DoublewordSize); __ Sd(GpuRegister(reg), SP, 0); } @@ -503,7 +503,7 @@ void ParallelMoveResolverMIPS64::Exchange(int index1, int index2, bool double_sl // automatically unspilled when the scratch scope object is destroyed). ScratchRegisterScope ensure_scratch(this, TMP, V0, codegen_->GetNumberOfCoreRegisters()); // If V0 spills onto the stack, SP-relative offsets need to be adjusted. - int stack_offset = ensure_scratch.IsSpilled() ? kMips64WordSize : 0; + int stack_offset = ensure_scratch.IsSpilled() ? kMips64DoublewordSize : 0; __ LoadFromOffset(load_type, GpuRegister(ensure_scratch.GetRegister()), SP, @@ -523,7 +523,9 @@ static dwarf::Reg DWARFReg(GpuRegister reg) { return dwarf::Reg::Mips64Core(static_cast<int>(reg)); } -// TODO: mapping of floating-point registers to DWARF +static dwarf::Reg DWARFReg(FpuRegister reg) { + return dwarf::Reg::Mips64Fp(static_cast<int>(reg)); +} void CodeGeneratorMIPS64::GenerateFrameEntry() { __ Bind(&frame_entry_label_); @@ -562,7 +564,7 @@ void CodeGeneratorMIPS64::GenerateFrameEntry() { for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) { GpuRegister reg = kCoreCalleeSaves[i]; if (allocated_registers_.ContainsCoreRegister(reg)) { - ofs -= kMips64WordSize; + ofs -= kMips64DoublewordSize; __ Sd(reg, SP, ofs); __ cfi().RelOffset(DWARFReg(reg), ofs); } @@ -571,9 +573,9 @@ void CodeGeneratorMIPS64::GenerateFrameEntry() { for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) { FpuRegister reg = kFpuCalleeSaves[i]; if (allocated_registers_.ContainsFloatingPointRegister(reg)) { - ofs -= kMips64WordSize; + ofs -= kMips64DoublewordSize; __ Sdc1(reg, SP, ofs); - // TODO: __ cfi().RelOffset(DWARFReg(reg), ofs); + __ cfi().RelOffset(DWARFReg(reg), ofs); } } @@ -609,8 +611,8 @@ void CodeGeneratorMIPS64::GenerateFrameExit() { FpuRegister reg = kFpuCalleeSaves[i]; if (allocated_registers_.ContainsFloatingPointRegister(reg)) { __ Ldc1(reg, SP, ofs); - ofs += kMips64WordSize; - // TODO: __ cfi().Restore(DWARFReg(reg)); + ofs += kMips64DoublewordSize; + __ cfi().Restore(DWARFReg(reg)); } } @@ -618,7 +620,7 @@ void CodeGeneratorMIPS64::GenerateFrameExit() { GpuRegister reg = kCoreCalleeSaves[i]; if (allocated_registers_.ContainsCoreRegister(reg)) { __ Ld(reg, SP, ofs); - ofs += kMips64WordSize; + ofs += kMips64DoublewordSize; __ cfi().Restore(DWARFReg(reg)); } } @@ -976,7 +978,7 @@ void CodeGeneratorMIPS64::MarkGCCard(GpuRegister object, __ LoadFromOffset(kLoadDoubleword, card, TR, - Thread::CardTableOffset<kMips64WordSize>().Int32Value()); + Thread::CardTableOffset<kMips64DoublewordSize>().Int32Value()); __ Dsrl(temp, object, gc::accounting::CardTable::kCardShift); __ Daddu(temp, card, temp); __ Sb(card, temp, 0); @@ -994,10 +996,11 @@ void CodeGeneratorMIPS64::SetupBlockedRegisters() const { blocked_core_registers_[SP] = true; blocked_core_registers_[RA] = true; - // AT and TMP(T8) are used as temporary/scratch registers - // (similar to how AT is used by MIPS assemblers). + // AT, TMP(T8) and TMP2(T3) are used as temporary/scratch + // registers (similar to how AT is used by MIPS assemblers). blocked_core_registers_[AT] = true; blocked_core_registers_[TMP] = true; + blocked_core_registers_[TMP2] = true; blocked_fpu_registers_[FTMP] = true; // Reserve suspend and thread registers. @@ -1021,22 +1024,22 @@ void CodeGeneratorMIPS64::SetupBlockedRegisters() const { size_t CodeGeneratorMIPS64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) { __ StoreToOffset(kStoreDoubleword, GpuRegister(reg_id), SP, stack_index); - return kMips64WordSize; + return kMips64DoublewordSize; } size_t CodeGeneratorMIPS64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) { __ LoadFromOffset(kLoadDoubleword, GpuRegister(reg_id), SP, stack_index); - return kMips64WordSize; + return kMips64DoublewordSize; } size_t CodeGeneratorMIPS64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) { __ StoreFpuToOffset(kStoreDoubleword, FpuRegister(reg_id), SP, stack_index); - return kMips64WordSize; + return kMips64DoublewordSize; } size_t CodeGeneratorMIPS64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) { __ LoadFpuFromOffset(kLoadDoubleword, FpuRegister(reg_id), SP, stack_index); - return kMips64WordSize; + return kMips64DoublewordSize; } void CodeGeneratorMIPS64::DumpCoreRegister(std::ostream& stream, int reg) const { @@ -1051,7 +1054,7 @@ void CodeGeneratorMIPS64::InvokeRuntime(QuickEntrypointEnum entrypoint, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path) { - InvokeRuntime(GetThreadOffset<kMips64WordSize>(entrypoint).Int32Value(), + InvokeRuntime(GetThreadOffset<kMips64DoublewordSize>(entrypoint).Int32Value(), instruction, dex_pc, slow_path); @@ -1091,7 +1094,7 @@ void InstructionCodeGeneratorMIPS64::GenerateSuspendCheck(HSuspendCheck* instruc __ LoadFromOffset(kLoadUnsignedHalfword, TMP, TR, - Thread::ThreadFlagsOffset<kMips64WordSize>().Int32Value()); + Thread::ThreadFlagsOffset<kMips64DoublewordSize>().Int32Value()); if (successor == nullptr) { __ Bnezc(TMP, slow_path->GetEntryLabel()); __ Bind(slow_path->GetReturnLabel()); @@ -3014,7 +3017,7 @@ void InstructionCodeGeneratorMIPS64::VisitInvokeInterface(HInvokeInterface* invo invoke->GetImtIndex() % mirror::Class::kImtSize, kMips64PointerSize).Uint32Value(); Location receiver = invoke->GetLocations()->InAt(0); uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); - Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize); + Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64DoublewordSize); // Set the hidden argument. __ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister<GpuRegister>(), @@ -3190,7 +3193,7 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo T9, callee_method.AsRegister<GpuRegister>(), ArtMethod::EntryPointFromQuickCompiledCodeOffset( - kMips64WordSize).Int32Value()); + kMips64DoublewordSize).Int32Value()); // T9() __ Jalr(T9); __ Nop(); @@ -3228,7 +3231,7 @@ void CodeGeneratorMIPS64::GenerateVirtualCall(HInvokeVirtual* invoke, Location t size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset( invoke->GetVTableIndex(), kMips64PointerSize).SizeValue(); uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); - Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize); + Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64DoublewordSize); // temp = object->GetClass(); __ LoadFromOffset(kLoadUnsignedWord, temp, receiver, class_offset); @@ -3306,7 +3309,7 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) { } static int32_t GetExceptionTlsOffset() { - return Thread::ExceptionOffset<kMips64WordSize>().Int32Value(); + return Thread::ExceptionOffset<kMips64DoublewordSize>().Int32Value(); } void LocationsBuilderMIPS64::VisitLoadException(HLoadException* load) { @@ -3546,7 +3549,8 @@ void InstructionCodeGeneratorMIPS64::VisitNewInstance(HNewInstance* instruction) if (instruction->IsStringAlloc()) { // String is allocated through StringFactory. Call NewEmptyString entry point. GpuRegister temp = instruction->GetLocations()->GetTemp(0).AsRegister<GpuRegister>(); - MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize); + MemberOffset code_offset = + ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64DoublewordSize); __ LoadFromOffset(kLoadDoubleword, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString)); __ LoadFromOffset(kLoadDoubleword, T9, temp, code_offset.Int32Value()); __ Jalr(T9); diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index 08e56158b8..c836f837de 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -27,10 +27,6 @@ namespace art { namespace mips64 { -// Use a local definition to prevent copying mistakes. -static constexpr size_t kMips64WordSize = kMips64PointerSize; - - // InvokeDexCallingConvention registers static constexpr GpuRegister kParameterCoreRegisters[] = @@ -274,9 +270,9 @@ class CodeGeneratorMIPS64 : public CodeGenerator { void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; - size_t GetWordSize() const OVERRIDE { return kMips64WordSize; } + size_t GetWordSize() const OVERRIDE { return kMips64DoublewordSize; } - size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64WordSize; } + size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64DoublewordSize; } uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE { return assembler_.GetLabelLocation(GetLabelOf(block)); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 86ffb0f70d..6795488769 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -6447,8 +6447,17 @@ void InstructionCodeGeneratorX86_64::VisitPackedSwitch(HPackedSwitch* switch_ins __ jmp(temp_reg); } +void CodeGeneratorX86_64::Load32BitValue(CpuRegister dest, int32_t value) { + if (value == 0) { + __ xorl(dest, dest); + } else { + __ movl(dest, Immediate(value)); + } +} + void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) { if (value == 0) { + // Clears upper bits too. __ xorl(dest, dest); } else if (value > 0 && IsInt<32>(value)) { // We can use a 32 bit move, as it will zero-extend and is one byte shorter. diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 96265902ba..318087eb9c 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -478,8 +478,10 @@ class CodeGeneratorX86_64 : public CodeGenerator { Address LiteralInt32Address(int32_t v); Address LiteralInt64Address(int64_t v); - // Load a 64 bit value into a register in the most efficient manner. + // Load a 32/64 bit value into a register in the most efficient manner. + void Load32BitValue(CpuRegister dest, int32_t value); void Load64BitValue(CpuRegister dest, int64_t value); + Address LiteralCaseTable(HPackedSwitch* switch_instr); // Store a 64 bit value into a DoubleStackSlot in the most efficient manner. diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 51fef7c9cb..a839d2dee8 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -669,7 +669,9 @@ HInstanceFieldGet* HInliner::CreateInstanceFieldGet(ArtMethod* resolved_method, resolved_field->GetDeclaringClass()->GetDexClassDefIndex(), *resolved_method->GetDexFile(), dex_cache, - kNoDexPc); + // Read barrier generates a runtime call in slow path and we need a valid + // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537. + /* dex_pc */ 0); if (iget->GetType() == Primitive::kPrimNot) { ReferenceTypePropagation rtp(graph_, handles_); rtp.Visit(iget); @@ -696,7 +698,9 @@ HInstanceFieldSet* HInliner::CreateInstanceFieldSet(ArtMethod* resolved_method, resolved_field->GetDeclaringClass()->GetDexClassDefIndex(), *resolved_method->GetDexFile(), dex_cache, - kNoDexPc); + // Read barrier generates a runtime call in slow path and we need a valid + // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537. + /* dex_pc */ 0); return iput; } bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index d5ed58530d..5dce83a69c 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -275,6 +275,45 @@ void IntrinsicCodeGeneratorARM64::VisitShortReverseBytes(HInvoke* invoke) { GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetVIXLAssembler()); } +static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { + LocationSummary* locations = new (arena) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +static void GenCompare(LocationSummary* locations, bool is_long, vixl::MacroAssembler* masm) { + Location op1 = locations->InAt(0); + Location op2 = locations->InAt(1); + Location out = locations->Out(); + + Register op1_reg = is_long ? XRegisterFrom(op1) : WRegisterFrom(op1); + Register op2_reg = is_long ? XRegisterFrom(op2) : WRegisterFrom(op2); + Register out_reg = WRegisterFrom(out); + + __ Cmp(op1_reg, op2_reg); + __ Cset(out_reg, gt); // out == +1 if GT or 0 otherwise + __ Cinv(out_reg, out_reg, lt); // out == -1 if LT or unchanged otherwise +} + +void IntrinsicLocationsBuilderARM64::VisitIntegerCompare(HInvoke* invoke) { + CreateIntIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitIntegerCompare(HInvoke* invoke) { + GenCompare(invoke->GetLocations(), /* is_long */ false, GetVIXLAssembler()); +} + +void IntrinsicLocationsBuilderARM64::VisitLongCompare(HInvoke* invoke) { + CreateIntIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitLongCompare(HInvoke* invoke) { + GenCompare(invoke->GetLocations(), /* is_long */ true, GetVIXLAssembler()); +} + static void GenNumberOfLeadingZeros(LocationSummary* locations, Primitive::Type type, vixl::MacroAssembler* masm) { @@ -504,15 +543,6 @@ static void GenMinMax(LocationSummary* locations, __ Csel(out_reg, op1_reg, op2_reg, is_min ? lt : gt); } -static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { - LocationSummary* locations = new (arena) LocationSummary(invoke, - LocationSummary::kNoCall, - kIntrinsified); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); -} - void IntrinsicLocationsBuilderARM64::VisitMathMinIntInt(HInvoke* invoke) { CreateIntIntToIntLocations(arena_, invoke); } @@ -750,7 +780,6 @@ static void GenUnsafeGet(HInvoke* invoke, Register offset = XRegisterFrom(offset_loc); // Long offset. Location trg_loc = locations->Out(); Register trg = RegisterFrom(trg_loc, type); - bool use_acquire_release = codegen->GetInstructionSetFeatures().PreferAcquireRelease(); if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) { // UnsafeGetObject/UnsafeGetObjectVolatile with Baker's read barrier case. @@ -758,19 +787,11 @@ static void GenUnsafeGet(HInvoke* invoke, Register temp = temps.AcquireW(); codegen->GenerateArrayLoadWithBakerReadBarrier( invoke, trg_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false); - if (is_volatile && !use_acquire_release) { - __ Dmb(InnerShareable, BarrierReads); - } } else { // Other cases. MemOperand mem_op(base.X(), offset); if (is_volatile) { - if (use_acquire_release) { - codegen->LoadAcquire(invoke, trg, mem_op, /* needs_null_check */ true); - } else { - codegen->Load(type, trg, mem_op); - __ Dmb(InnerShareable, BarrierReads); - } + codegen->LoadAcquire(invoke, trg, mem_op, /* needs_null_check */ true); } else { codegen->Load(type, trg, mem_op); } @@ -884,8 +905,6 @@ static void GenUnsafePut(LocationSummary* locations, Register offset = XRegisterFrom(locations->InAt(2)); // Long offset. Register value = RegisterFrom(locations->InAt(3), type); Register source = value; - bool use_acquire_release = codegen->GetInstructionSetFeatures().PreferAcquireRelease(); - MemOperand mem_op(base.X(), offset); { @@ -902,15 +921,7 @@ static void GenUnsafePut(LocationSummary* locations, } if (is_volatile || is_ordered) { - if (use_acquire_release) { - codegen->StoreRelease(type, source, mem_op); - } else { - __ Dmb(InnerShareable, BarrierAll); - codegen->Store(type, source, mem_op); - if (is_volatile) { - __ Dmb(InnerShareable, BarrierReads); - } - } + codegen->StoreRelease(type, source, mem_op); } else { codegen->Store(type, source, mem_op); } @@ -1007,7 +1018,6 @@ static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena, } static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM64* codegen) { - bool use_acquire_release = codegen->GetInstructionSetFeatures().PreferAcquireRelease(); vixl::MacroAssembler* masm = codegen->GetAssembler()->vixl_masm_; Register out = WRegisterFrom(locations->Out()); // Boolean result. @@ -1048,43 +1058,20 @@ static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGenerat // result = tmp_value != 0; vixl::Label loop_head, exit_loop; - if (use_acquire_release) { - __ Bind(&loop_head); - // TODO: When `type == Primitive::kPrimNot`, add a read barrier for - // the reference stored in the object before attempting the CAS, - // similar to the one in the art::Unsafe_compareAndSwapObject JNI - // implementation. - // - // Note that this code is not (yet) used when read barriers are - // enabled (see IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject). - DCHECK(!(type == Primitive::kPrimNot && kEmitCompilerReadBarrier)); - __ Ldaxr(tmp_value, MemOperand(tmp_ptr)); - __ Cmp(tmp_value, expected); - __ B(&exit_loop, ne); - __ Stlxr(tmp_32, value, MemOperand(tmp_ptr)); - __ Cbnz(tmp_32, &loop_head); - } else { - // Emit a `Dmb(InnerShareable, BarrierAll)` (DMB ISH) instruction - // instead of a `Dmb(InnerShareable, BarrierWrites)` (DMB ISHST) - // one, as the latter allows a preceding load to be delayed past - // the STXR instruction below. - __ Dmb(InnerShareable, BarrierAll); - __ Bind(&loop_head); - // TODO: When `type == Primitive::kPrimNot`, add a read barrier for - // the reference stored in the object before attempting the CAS, - // similar to the one in the art::Unsafe_compareAndSwapObject JNI - // implementation. - // - // Note that this code is not (yet) used when read barriers are - // enabled (see IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject). - DCHECK(!(type == Primitive::kPrimNot && kEmitCompilerReadBarrier)); - __ Ldxr(tmp_value, MemOperand(tmp_ptr)); - __ Cmp(tmp_value, expected); - __ B(&exit_loop, ne); - __ Stxr(tmp_32, value, MemOperand(tmp_ptr)); - __ Cbnz(tmp_32, &loop_head); - __ Dmb(InnerShareable, BarrierAll); - } + __ Bind(&loop_head); + // TODO: When `type == Primitive::kPrimNot`, add a read barrier for + // the reference stored in the object before attempting the CAS, + // similar to the one in the art::Unsafe_compareAndSwapObject JNI + // implementation. + // + // Note that this code is not (yet) used when read barriers are + // enabled (see IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject). + DCHECK(!(type == Primitive::kPrimNot && kEmitCompilerReadBarrier)); + __ Ldaxr(tmp_value, MemOperand(tmp_ptr)); + __ Cmp(tmp_value, expected); + __ B(&exit_loop, ne); + __ Stlxr(tmp_32, value, MemOperand(tmp_ptr)); + __ Cbnz(tmp_32, &loop_head); __ Bind(&exit_loop); __ Cset(out, eq); @@ -1469,6 +1456,209 @@ void IntrinsicCodeGeneratorARM64::VisitStringNewStringFromString(HInvoke* invoke __ Bind(slow_path->GetExitLabel()); } +static void GenSignum(LocationSummary* locations, bool is_long, vixl::MacroAssembler* masm) { + Location op1 = locations->InAt(0); + Location out = locations->Out(); + + Register op1_reg = is_long ? XRegisterFrom(op1) : WRegisterFrom(op1); + Register out_reg = WRegisterFrom(out); + + __ Cmp(op1_reg, 0); + __ Cset(out_reg, gt); // out == +1 if GT or 0 otherwise + __ Cinv(out_reg, out_reg, lt); // out == -1 if LT or unchanged otherwise +} + +void IntrinsicLocationsBuilderARM64::VisitIntegerSignum(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitIntegerSignum(HInvoke* invoke) { + GenSignum(invoke->GetLocations(), /* is_long */ false, GetVIXLAssembler()); +} + +void IntrinsicLocationsBuilderARM64::VisitLongSignum(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitLongSignum(HInvoke* invoke) { + GenSignum(invoke->GetLocations(), /* is_long */ true, GetVIXLAssembler()); +} + +static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) { + DCHECK_EQ(invoke->GetNumberOfArguments(), 1U); + DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(0)->GetType())); + DCHECK(Primitive::IsFloatingPointType(invoke->GetType())); + + LocationSummary* const locations = new (arena) LocationSummary(invoke, + LocationSummary::kCall, + kIntrinsified); + InvokeRuntimeCallingConvention calling_convention; + + locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0))); + locations->SetOut(calling_convention.GetReturnLocation(invoke->GetType())); +} + +static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) { + DCHECK_EQ(invoke->GetNumberOfArguments(), 2U); + DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(0)->GetType())); + DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(1)->GetType())); + DCHECK(Primitive::IsFloatingPointType(invoke->GetType())); + + LocationSummary* const locations = new (arena) LocationSummary(invoke, + LocationSummary::kCall, + kIntrinsified); + InvokeRuntimeCallingConvention calling_convention; + + locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0))); + locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1))); + locations->SetOut(calling_convention.GetReturnLocation(invoke->GetType())); +} + +static void GenFPToFPCall(HInvoke* invoke, + vixl::MacroAssembler* masm, + CodeGeneratorARM64* codegen, + QuickEntrypointEnum entry) { + __ Ldr(lr, MemOperand(tr, GetThreadOffset<kArm64WordSize>(entry).Int32Value())); + __ Blr(lr); + codegen->RecordPcInfo(invoke, invoke->GetDexPc()); +} + +void IntrinsicLocationsBuilderARM64::VisitMathCos(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathCos(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickCos); +} + +void IntrinsicLocationsBuilderARM64::VisitMathSin(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathSin(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickSin); +} + +void IntrinsicLocationsBuilderARM64::VisitMathAcos(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathAcos(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAcos); +} + +void IntrinsicLocationsBuilderARM64::VisitMathAsin(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathAsin(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAsin); +} + +void IntrinsicLocationsBuilderARM64::VisitMathAtan(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathAtan(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAtan); +} + +void IntrinsicLocationsBuilderARM64::VisitMathCbrt(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathCbrt(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickCbrt); +} + +void IntrinsicLocationsBuilderARM64::VisitMathCosh(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathCosh(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickCosh); +} + +void IntrinsicLocationsBuilderARM64::VisitMathExp(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathExp(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickExp); +} + +void IntrinsicLocationsBuilderARM64::VisitMathExpm1(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathExpm1(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickExpm1); +} + +void IntrinsicLocationsBuilderARM64::VisitMathLog(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathLog(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickLog); +} + +void IntrinsicLocationsBuilderARM64::VisitMathLog10(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathLog10(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickLog10); +} + +void IntrinsicLocationsBuilderARM64::VisitMathSinh(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathSinh(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickSinh); +} + +void IntrinsicLocationsBuilderARM64::VisitMathTan(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathTan(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickTan); +} + +void IntrinsicLocationsBuilderARM64::VisitMathTanh(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathTanh(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickTanh); +} + +void IntrinsicLocationsBuilderARM64::VisitMathAtan2(HInvoke* invoke) { + CreateFPFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathAtan2(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAtan2); +} + +void IntrinsicLocationsBuilderARM64::VisitMathHypot(HInvoke* invoke) { + CreateFPFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathHypot(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickHypot); +} + +void IntrinsicLocationsBuilderARM64::VisitMathNextAfter(HInvoke* invoke) { + CreateFPFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitMathNextAfter(HInvoke* invoke) { + GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickNextAfter); +} + // Unimplemented intrinsics. #define UNIMPLEMENTED_INTRINSIC(Name) \ @@ -1484,37 +1674,15 @@ UNIMPLEMENTED_INTRINSIC(SystemArrayCopy) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) -UNIMPLEMENTED_INTRINSIC(MathCos) -UNIMPLEMENTED_INTRINSIC(MathSin) -UNIMPLEMENTED_INTRINSIC(MathAcos) -UNIMPLEMENTED_INTRINSIC(MathAsin) -UNIMPLEMENTED_INTRINSIC(MathAtan) -UNIMPLEMENTED_INTRINSIC(MathAtan2) -UNIMPLEMENTED_INTRINSIC(MathCbrt) -UNIMPLEMENTED_INTRINSIC(MathCosh) -UNIMPLEMENTED_INTRINSIC(MathExp) -UNIMPLEMENTED_INTRINSIC(MathExpm1) -UNIMPLEMENTED_INTRINSIC(MathHypot) -UNIMPLEMENTED_INTRINSIC(MathLog) -UNIMPLEMENTED_INTRINSIC(MathLog10) -UNIMPLEMENTED_INTRINSIC(MathNextAfter) -UNIMPLEMENTED_INTRINSIC(MathSinh) -UNIMPLEMENTED_INTRINSIC(MathTan) -UNIMPLEMENTED_INTRINSIC(MathTanh) - UNIMPLEMENTED_INTRINSIC(FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) UNIMPLEMENTED_INTRINSIC(FloatIsNaN) UNIMPLEMENTED_INTRINSIC(DoubleIsNaN) -UNIMPLEMENTED_INTRINSIC(IntegerCompare) -UNIMPLEMENTED_INTRINSIC(LongCompare) UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit) UNIMPLEMENTED_INTRINSIC(LongLowestOneBit) -UNIMPLEMENTED_INTRINSIC(IntegerSignum) -UNIMPLEMENTED_INTRINSIC(LongSignum) // Rotate operations are handled as HRor instructions. UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index cba84fa3e3..f681d1fd56 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -1429,8 +1429,7 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringCompareTo(HInvoke* invoke) { __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, - pStringCompareTo).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pStringCompareTo).Int32Value()); __ Jalr(TMP); __ Nop(); __ Bind(slow_path->GetExitLabel()); @@ -1583,7 +1582,7 @@ static void GenerateStringIndexOf(HInvoke* invoke, __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pIndexOf).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pIndexOf).Int32Value()); __ Jalr(TMP); __ Nop(); @@ -1659,7 +1658,8 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pAllocStringFromBytes).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, + pAllocStringFromBytes).Int32Value()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); __ Jalr(TMP); __ Nop(); @@ -1685,7 +1685,8 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromChars(HInvoke* invoke __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pAllocStringFromChars).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, + pAllocStringFromChars).Int32Value()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); __ Jalr(TMP); __ Nop(); @@ -1716,7 +1717,8 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromString(HInvoke* invok __ LoadFromOffset(kLoadDoubleword, TMP, TR, - QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pAllocStringFromString).Int32Value()); + QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, + pAllocStringFromString).Int32Value()); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); __ Jalr(TMP); __ Nop(); diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 6ccc5d1e01..51fa514cb6 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -2302,7 +2302,7 @@ static void SwapBits(CpuRegister reg, CpuRegister temp, int32_t shift, int32_t m } void IntrinsicCodeGeneratorX86_64::VisitIntegerReverse(HInvoke* invoke) { - X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler()); + X86_64Assembler* assembler = GetAssembler(); LocationSummary* locations = invoke->GetLocations(); CpuRegister reg = locations->InAt(0).AsRegister<CpuRegister>(); @@ -2346,7 +2346,7 @@ static void SwapBits64(CpuRegister reg, CpuRegister temp, CpuRegister temp_mask, } void IntrinsicCodeGeneratorX86_64::VisitLongReverse(HInvoke* invoke) { - X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler()); + X86_64Assembler* assembler = GetAssembler(); LocationSummary* locations = invoke->GetLocations(); CpuRegister reg = locations->InAt(0).AsRegister<CpuRegister>(); @@ -2382,7 +2382,10 @@ static void CreateBitCountLocations( locations->SetOut(Location::RequiresRegister()); } -static void GenBitCount(X86_64Assembler* assembler, HInvoke* invoke, bool is_long) { +static void GenBitCount(X86_64Assembler* assembler, + CodeGeneratorX86_64* codegen, + HInvoke* invoke, + bool is_long) { LocationSummary* locations = invoke->GetLocations(); Location src = locations->InAt(0); CpuRegister out = locations->Out().AsRegister<CpuRegister>(); @@ -2393,11 +2396,7 @@ static void GenBitCount(X86_64Assembler* assembler, HInvoke* invoke, bool is_lon value = is_long ? POPCOUNT(static_cast<uint64_t>(value)) : POPCOUNT(static_cast<uint32_t>(value)); - if (value == 0) { - __ xorl(out, out); - } else { - __ movl(out, Immediate(value)); - } + codegen->Load32BitValue(out, value); return; } @@ -2421,7 +2420,7 @@ void IntrinsicLocationsBuilderX86_64::VisitIntegerBitCount(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitIntegerBitCount(HInvoke* invoke) { - GenBitCount(GetAssembler(), invoke, /* is_long */ false); + GenBitCount(GetAssembler(), codegen_, invoke, /* is_long */ false); } void IntrinsicLocationsBuilderX86_64::VisitLongBitCount(HInvoke* invoke) { @@ -2429,7 +2428,190 @@ void IntrinsicLocationsBuilderX86_64::VisitLongBitCount(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitLongBitCount(HInvoke* invoke) { - GenBitCount(GetAssembler(), invoke, /* is_long */ true); + GenBitCount(GetAssembler(), codegen_, invoke, /* is_long */ true); +} + +static void CreateCompareLocations(ArenaAllocator* arena, HInvoke* invoke) { + LocationSummary* locations = new (arena) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister()); +} + +static void GenCompare(X86_64Assembler* assembler, HInvoke* invoke, bool is_long) { + LocationSummary* locations = invoke->GetLocations(); + CpuRegister src1 = locations->InAt(0).AsRegister<CpuRegister>(); + CpuRegister src2 = locations->InAt(1).AsRegister<CpuRegister>(); + CpuRegister out = locations->Out().AsRegister<CpuRegister>(); + + NearLabel is_lt, done; + + __ xorl(out, out); + + if (is_long) { + __ cmpq(src1, src2); + } else { + __ cmpl(src1, src2); + } + __ j(kEqual, &done); + __ j(kLess, &is_lt); + + __ movl(out, Immediate(1)); + __ jmp(&done); + + __ Bind(&is_lt); + __ movl(out, Immediate(-1)); + + __ Bind(&done); +} + +void IntrinsicLocationsBuilderX86_64::VisitIntegerCompare(HInvoke* invoke) { + CreateCompareLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitIntegerCompare(HInvoke* invoke) { + GenCompare(GetAssembler(), invoke, /* is_long */ false); +} + +void IntrinsicLocationsBuilderX86_64::VisitLongCompare(HInvoke* invoke) { + CreateCompareLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitLongCompare(HInvoke* invoke) { + GenCompare(GetAssembler(), invoke, /* is_long */ true); +} + +static void CreateOneBitLocations(ArenaAllocator* arena, HInvoke* invoke, bool is_high) { + LocationSummary* locations = new (arena) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::Any()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(is_high ? Location::RegisterLocation(RCX) // needs CL + : Location::RequiresRegister()); // any will do +} + +static void GenOneBit(X86_64Assembler* assembler, + CodeGeneratorX86_64* codegen, + HInvoke* invoke, + bool is_high, bool is_long) { + LocationSummary* locations = invoke->GetLocations(); + Location src = locations->InAt(0); + CpuRegister out = locations->Out().AsRegister<CpuRegister>(); + + if (invoke->InputAt(0)->IsConstant()) { + // Evaluate this at compile time. + int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant()); + if (value == 0) { + __ xorl(out, out); // Clears upper bits too. + return; + } + // Nonzero value. + if (is_high) { + value = is_long ? 63 - CLZ(static_cast<uint64_t>(value)) + : 31 - CLZ(static_cast<uint32_t>(value)); + } else { + value = is_long ? CTZ(static_cast<uint64_t>(value)) + : CTZ(static_cast<uint32_t>(value)); + } + if (is_long) { + codegen->Load64BitValue(out, 1L << value); + } else { + codegen->Load32BitValue(out, 1 << value); + } + return; + } + + // Handle the non-constant cases. + CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>(); + if (is_high) { + // Use architectural support: basically 1 << bsr. + if (src.IsRegister()) { + if (is_long) { + __ bsrq(tmp, src.AsRegister<CpuRegister>()); + } else { + __ bsrl(tmp, src.AsRegister<CpuRegister>()); + } + } else if (is_long) { + DCHECK(src.IsDoubleStackSlot()); + __ bsrq(tmp, Address(CpuRegister(RSP), src.GetStackIndex())); + } else { + DCHECK(src.IsStackSlot()); + __ bsrl(tmp, Address(CpuRegister(RSP), src.GetStackIndex())); + } + // BSR sets ZF if the input was zero. + NearLabel is_zero, done; + __ j(kEqual, &is_zero); + __ movl(out, Immediate(1)); // Clears upper bits too. + if (is_long) { + __ shlq(out, tmp); + } else { + __ shll(out, tmp); + } + __ jmp(&done); + __ Bind(&is_zero); + __ xorl(out, out); // Clears upper bits too. + __ Bind(&done); + } else { + // Copy input into temporary. + if (src.IsRegister()) { + if (is_long) { + __ movq(tmp, src.AsRegister<CpuRegister>()); + } else { + __ movl(tmp, src.AsRegister<CpuRegister>()); + } + } else if (is_long) { + DCHECK(src.IsDoubleStackSlot()); + __ movq(tmp, Address(CpuRegister(RSP), src.GetStackIndex())); + } else { + DCHECK(src.IsStackSlot()); + __ movl(tmp, Address(CpuRegister(RSP), src.GetStackIndex())); + } + // Do the bit twiddling: basically tmp & -tmp; + if (is_long) { + __ movq(out, tmp); + __ negq(tmp); + __ andq(out, tmp); + } else { + __ movl(out, tmp); + __ negl(tmp); + __ andl(out, tmp); + } + } +} + +void IntrinsicLocationsBuilderX86_64::VisitIntegerHighestOneBit(HInvoke* invoke) { + CreateOneBitLocations(arena_, invoke, /* is_high */ true); +} + +void IntrinsicCodeGeneratorX86_64::VisitIntegerHighestOneBit(HInvoke* invoke) { + GenOneBit(GetAssembler(), codegen_, invoke, /* is_high */ true, /* is_long */ false); +} + +void IntrinsicLocationsBuilderX86_64::VisitLongHighestOneBit(HInvoke* invoke) { + CreateOneBitLocations(arena_, invoke, /* is_high */ true); +} + +void IntrinsicCodeGeneratorX86_64::VisitLongHighestOneBit(HInvoke* invoke) { + GenOneBit(GetAssembler(), codegen_, invoke, /* is_high */ true, /* is_long */ true); +} + +void IntrinsicLocationsBuilderX86_64::VisitIntegerLowestOneBit(HInvoke* invoke) { + CreateOneBitLocations(arena_, invoke, /* is_high */ false); +} + +void IntrinsicCodeGeneratorX86_64::VisitIntegerLowestOneBit(HInvoke* invoke) { + GenOneBit(GetAssembler(), codegen_, invoke, /* is_high */ false, /* is_long */ false); +} + +void IntrinsicLocationsBuilderX86_64::VisitLongLowestOneBit(HInvoke* invoke) { + CreateOneBitLocations(arena_, invoke, /* is_high */ false); +} + +void IntrinsicCodeGeneratorX86_64::VisitLongLowestOneBit(HInvoke* invoke) { + GenOneBit(GetAssembler(), codegen_, invoke, /* is_high */ false, /* is_long */ true); } static void CreateLeadingZeroLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -2440,7 +2622,9 @@ static void CreateLeadingZeroLocations(ArenaAllocator* arena, HInvoke* invoke) { locations->SetOut(Location::RequiresRegister()); } -static void GenLeadingZeros(X86_64Assembler* assembler, HInvoke* invoke, bool is_long) { +static void GenLeadingZeros(X86_64Assembler* assembler, + CodeGeneratorX86_64* codegen, + HInvoke* invoke, bool is_long) { LocationSummary* locations = invoke->GetLocations(); Location src = locations->InAt(0); CpuRegister out = locations->Out().AsRegister<CpuRegister>(); @@ -2454,11 +2638,7 @@ static void GenLeadingZeros(X86_64Assembler* assembler, HInvoke* invoke, bool is } else { value = is_long ? CLZ(static_cast<uint64_t>(value)) : CLZ(static_cast<uint32_t>(value)); } - if (value == 0) { - __ xorl(out, out); - } else { - __ movl(out, Immediate(value)); - } + codegen->Load32BitValue(out, value); return; } @@ -2497,8 +2677,7 @@ void IntrinsicLocationsBuilderX86_64::VisitIntegerNumberOfLeadingZeros(HInvoke* } void IntrinsicCodeGeneratorX86_64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { - X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler()); - GenLeadingZeros(assembler, invoke, /* is_long */ false); + GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long */ false); } void IntrinsicLocationsBuilderX86_64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { @@ -2506,8 +2685,7 @@ void IntrinsicLocationsBuilderX86_64::VisitLongNumberOfLeadingZeros(HInvoke* inv } void IntrinsicCodeGeneratorX86_64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { - X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler()); - GenLeadingZeros(assembler, invoke, /* is_long */ true); + GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true); } static void CreateTrailingZeroLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -2518,7 +2696,9 @@ static void CreateTrailingZeroLocations(ArenaAllocator* arena, HInvoke* invoke) locations->SetOut(Location::RequiresRegister()); } -static void GenTrailingZeros(X86_64Assembler* assembler, HInvoke* invoke, bool is_long) { +static void GenTrailingZeros(X86_64Assembler* assembler, + CodeGeneratorX86_64* codegen, + HInvoke* invoke, bool is_long) { LocationSummary* locations = invoke->GetLocations(); Location src = locations->InAt(0); CpuRegister out = locations->Out().AsRegister<CpuRegister>(); @@ -2532,11 +2712,7 @@ static void GenTrailingZeros(X86_64Assembler* assembler, HInvoke* invoke, bool i } else { value = is_long ? CTZ(static_cast<uint64_t>(value)) : CTZ(static_cast<uint32_t>(value)); } - if (value == 0) { - __ xorl(out, out); - } else { - __ movl(out, Immediate(value)); - } + codegen->Load32BitValue(out, value); return; } @@ -2570,8 +2746,7 @@ void IntrinsicLocationsBuilderX86_64::VisitIntegerNumberOfTrailingZeros(HInvoke* } void IntrinsicCodeGeneratorX86_64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { - X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler()); - GenTrailingZeros(assembler, invoke, /* is_long */ false); + GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ false); } void IntrinsicLocationsBuilderX86_64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { @@ -2579,8 +2754,75 @@ void IntrinsicLocationsBuilderX86_64::VisitLongNumberOfTrailingZeros(HInvoke* in } void IntrinsicCodeGeneratorX86_64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { - X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler()); - GenTrailingZeros(assembler, invoke, /* is_long */ true); + GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true); +} + +static void CreateSignLocations(ArenaAllocator* arena, HInvoke* invoke) { + LocationSummary* locations = new (arena) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::Any()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); // Need a writeable register. +} + +static void GenSign(X86_64Assembler* assembler, + CodeGeneratorX86_64* codegen, + HInvoke* invoke, bool is_long) { + LocationSummary* locations = invoke->GetLocations(); + Location src = locations->InAt(0); + CpuRegister out = locations->Out().AsRegister<CpuRegister>(); + + if (invoke->InputAt(0)->IsConstant()) { + // Evaluate this at compile time. + int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant()); + codegen->Load32BitValue(out, value == 0 ? 0 : (value > 0 ? 1 : -1)); + return; + } + + // Copy input into temporary. + CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>(); + if (src.IsRegister()) { + if (is_long) { + __ movq(tmp, src.AsRegister<CpuRegister>()); + } else { + __ movl(tmp, src.AsRegister<CpuRegister>()); + } + } else if (is_long) { + DCHECK(src.IsDoubleStackSlot()); + __ movq(tmp, Address(CpuRegister(RSP), src.GetStackIndex())); + } else { + DCHECK(src.IsStackSlot()); + __ movl(tmp, Address(CpuRegister(RSP), src.GetStackIndex())); + } + + // Do the bit twiddling: basically tmp >> 63/31 | -tmp >>> 63/31 for long/int. + if (is_long) { + __ movq(out, tmp); + __ sarq(out, Immediate(63)); + __ negq(tmp); + __ shrq(tmp, Immediate(63)); + __ orq(out, tmp); + } else { + __ movl(out, tmp); + __ sarl(out, Immediate(31)); + __ negl(tmp); + __ shrl(tmp, Immediate(31)); + __ orl(out, tmp); + } +} + +void IntrinsicLocationsBuilderX86_64::VisitIntegerSignum(HInvoke* invoke) { + CreateSignLocations(arena_, invoke); +} +void IntrinsicCodeGeneratorX86_64::VisitIntegerSignum(HInvoke* invoke) { + GenSign(GetAssembler(), codegen_, invoke, /* is_long */ false); +} +void IntrinsicLocationsBuilderX86_64::VisitLongSignum(HInvoke* invoke) { + CreateSignLocations(arena_, invoke); +} +void IntrinsicCodeGeneratorX86_64::VisitLongSignum(HInvoke* invoke) { + GenSign(GetAssembler(), codegen_, invoke, /* is_long */ true); } // Unimplemented intrinsics. @@ -2598,15 +2840,6 @@ UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) UNIMPLEMENTED_INTRINSIC(FloatIsNaN) UNIMPLEMENTED_INTRINSIC(DoubleIsNaN) -UNIMPLEMENTED_INTRINSIC(IntegerCompare) -UNIMPLEMENTED_INTRINSIC(LongCompare) -UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit) -UNIMPLEMENTED_INTRINSIC(LongHighestOneBit) -UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit) -UNIMPLEMENTED_INTRINSIC(LongLowestOneBit) -UNIMPLEMENTED_INTRINSIC(IntegerSignum) -UNIMPLEMENTED_INTRINSIC(LongSignum) - // Rotate operations are handled as HRor instructions. UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index d90c1fb335..b8083477cf 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -4450,9 +4450,6 @@ class HTypeConversion : public HExpression<1> { Primitive::Type GetInputType() const { return GetInput()->GetType(); } Primitive::Type GetResultType() const { return GetType(); } - // Required by the x86, ARM, MIPS and MIPS64 code generators when producing calls - // to the runtime. - bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } @@ -4819,8 +4816,7 @@ class HArraySet : public HTemplateInstruction<3> { } bool NeedsEnvironment() const OVERRIDE { - // We currently always call a runtime method to catch array store - // exceptions. + // We call a runtime method to throw ArrayStoreException. return needs_type_check_; } @@ -5131,11 +5127,13 @@ class HLoadString : public HExpression<1> { uint32_t GetStringIndex() const { return string_index_; } - // TODO: Can we deopt or debug when we resolve a string? - bool NeedsEnvironment() const OVERRIDE { return false; } + // Will call the runtime if the string is not already in the dex cache. + bool NeedsEnvironment() const OVERRIDE { return !IsInDexCache(); } + bool NeedsDexCacheOfDeclaringClass() const OVERRIDE { return true; } bool CanBeNull() const OVERRIDE { return false; } bool IsInDexCache() const { return is_in_dex_cache_; } + bool CanThrow() const OVERRIDE { return !IsInDexCache(); } static SideEffects SideEffectsForArchRuntimeCalls() { return SideEffects::CanTriggerGC(); @@ -5465,7 +5463,7 @@ class HInstanceOf : public HExpression<2> { } bool NeedsEnvironment() const OVERRIDE { - return false; + return CanCallRuntime(check_kind_); } bool IsExactCheck() const { return check_kind_ == TypeCheckKind::kExactCheck; } @@ -5476,11 +5474,13 @@ class HInstanceOf : public HExpression<2> { bool MustDoNullCheck() const { return must_do_null_check_; } void ClearMustDoNullCheck() { must_do_null_check_ = false; } + static bool CanCallRuntime(TypeCheckKind check_kind) { + // Mips currently does runtime calls for any other checks. + return check_kind != TypeCheckKind::kExactCheck; + } + static SideEffects SideEffectsForArchRuntimeCalls(TypeCheckKind check_kind) { - return (check_kind == TypeCheckKind::kExactCheck) - ? SideEffects::None() - // Mips currently does runtime calls for any other checks. - : SideEffects::CanTriggerGC(); + return CanCallRuntime(check_kind) ? SideEffects::CanTriggerGC() : SideEffects::None(); } DECLARE_INSTRUCTION(InstanceOf); @@ -5605,8 +5605,8 @@ class HMonitorOperation : public HTemplateInstruction<1> { SetRawInputAt(0, object); } - // Instruction may throw a Java exception, so we need an environment. - bool NeedsEnvironment() const OVERRIDE { return CanThrow(); } + // Instruction may go into runtime, so we need an environment. + bool NeedsEnvironment() const OVERRIDE { return true; } bool CanThrow() const OVERRIDE { // Verifier guarantees that monitor-exit cannot throw. diff --git a/compiler/optimizing/optimizing_cfi_test_expected.inc b/compiler/optimizing/optimizing_cfi_test_expected.inc index de857295c7..fc66823b04 100644 --- a/compiler/optimizing/optimizing_cfi_test_expected.inc +++ b/compiler/optimizing/optimizing_cfi_test_expected.inc @@ -198,8 +198,9 @@ static constexpr uint8_t expected_asm_kMips64[] = { }; static constexpr uint8_t expected_cfi_kMips64[] = { 0x44, 0x0E, 0x28, 0x44, 0x9F, 0x02, 0x44, 0x91, 0x04, 0x44, 0x90, 0x06, - 0x4C, 0x0E, 0x40, 0x44, 0x0A, 0x44, 0x0E, 0x28, 0x4C, 0xD0, 0x44, 0xD1, - 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40, + 0x44, 0xB9, 0x08, 0x44, 0xB8, 0x0A, 0x44, 0x0E, 0x40, 0x44, 0x0A, 0x44, + 0x0E, 0x28, 0x44, 0xF8, 0x44, 0xF9, 0x44, 0xD0, 0x44, 0xD1, 0x44, 0xDF, + 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40, }; // 0x00000000: daddiu r29, r29, -40 // 0x00000004: .cfi_def_cfa_offset: 40 @@ -210,7 +211,9 @@ static constexpr uint8_t expected_cfi_kMips64[] = { // 0x0000000c: sd r16, +16(r29) // 0x00000010: .cfi_offset: r16 at cfa-24 // 0x00000010: sdc1 f25, +8(r29) +// 0x00000014: .cfi_offset: r57 at cfa-32 // 0x00000014: sdc1 f24, +0(r29) +// 0x00000018: .cfi_offset: r56 at cfa-40 // 0x00000018: daddiu r29, r29, -24 // 0x0000001c: .cfi_def_cfa_offset: 64 // 0x0000001c: sd r4, +0(r29) @@ -218,7 +221,9 @@ static constexpr uint8_t expected_cfi_kMips64[] = { // 0x00000020: daddiu r29, r29, 24 // 0x00000024: .cfi_def_cfa_offset: 40 // 0x00000024: ldc1 f24, +0(r29) +// 0x00000028: .cfi_restore: r56 // 0x00000028: ldc1 f25, +8(r29) +// 0x0000002c: .cfi_restore: r57 // 0x0000002c: ld r16, +16(r29) // 0x00000030: .cfi_restore: r16 // 0x00000030: ld r17, +24(r29) @@ -427,9 +432,9 @@ static constexpr uint8_t expected_asm_kMips64_adjust_tail[] = { }; static constexpr uint8_t expected_cfi_kMips64_adjust[] = { 0x44, 0x0E, 0x28, 0x44, 0x9F, 0x02, 0x44, 0x91, 0x04, 0x44, 0x90, 0x06, - 0x4C, 0x0E, 0x40, 0x04, 0x14, 0x00, 0x02, 0x00, 0x0A, 0x44, 0x0E, 0x28, - 0x4C, 0xD0, 0x44, 0xD1, 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, - 0x40, + 0x44, 0xB9, 0x08, 0x44, 0xB8, 0x0A, 0x44, 0x0E, 0x40, 0x04, 0x14, 0x00, + 0x02, 0x00, 0x0A, 0x44, 0x0E, 0x28, 0x44, 0xF8, 0x44, 0xF9, 0x44, 0xD0, + 0x44, 0xD1, 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40, }; // 0x00000000: daddiu r29, r29, -40 // 0x00000004: .cfi_def_cfa_offset: 40 @@ -440,7 +445,9 @@ static constexpr uint8_t expected_cfi_kMips64_adjust[] = { // 0x0000000c: sd r16, +16(r29) // 0x00000010: .cfi_offset: r16 at cfa-24 // 0x00000010: sdc1 f25, +8(r29) +// 0x00000014: .cfi_offset: r57 at cfa-32 // 0x00000014: sdc1 f24, +0(r29) +// 0x00000018: .cfi_offset: r56 at cfa-40 // 0x00000018: daddiu r29, r29, -24 // 0x0000001c: .cfi_def_cfa_offset: 64 // 0x0000001c: sd r4, +0(r29) @@ -454,7 +461,9 @@ static constexpr uint8_t expected_cfi_kMips64_adjust[] = { // 0x00020030: daddiu r29, r29, 24 // 0x00020034: .cfi_def_cfa_offset: 40 // 0x00020034: ldc1 f24, +0(r29) +// 0x00020038: .cfi_restore: r56 // 0x00020038: ldc1 f25, +8(r29) +// 0x0002003c: .cfi_restore: r57 // 0x0002003c: ld r16, +16(r29) // 0x00020040: .cfi_restore: r16 // 0x00020040: ld r17, +24(r29) |