diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.cc | 125 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 20 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 228 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips64.h | 50 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_utils.h | 8 | ||||
-rw-r--r-- | compiler/optimizing/graph_checker.cc | 5 | ||||
-rw-r--r-- | compiler/optimizing/graph_test.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 12 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 51 | ||||
-rw-r--r-- | compiler/optimizing/linearize_test.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 29 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 5 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 5 | ||||
-rw-r--r-- | compiler/optimizing/pretty_printer.h | 5 | ||||
-rw-r--r-- | compiler/optimizing/pretty_printer_test.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/sharpening.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/ssa_test.cc | 5 |
18 files changed, 388 insertions, 169 deletions
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 2c6df38daa..55f3c3ceef 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -57,6 +57,9 @@ using helpers::OutputVRegister; using helpers::RegisterFrom; using helpers::SRegisterFrom; +using vixl::ExactAssemblyScope; +using vixl::CodeBufferCheckScope; + using RegisterList = vixl32::RegisterList; static bool ExpectedPairLayout(Location location) { @@ -843,9 +846,9 @@ class ReadBarrierMarkAndUpdateFieldSlowPathARMVIXL : public SlowPathCodeARMVIXL __ Subs(tmp, tmp, expected); { - AssemblerAccurateScope aas(arm_codegen->GetVIXLAssembler(), - 2 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(arm_codegen->GetVIXLAssembler(), + 2 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ it(ne); __ clrex(ne); @@ -1261,9 +1264,9 @@ void JumpTableARMVIXL::EmitTable(CodeGeneratorARMVIXL* codegen) { // We are about to use the assembler to place literals directly. Make sure we have enough // underlying code buffer and we have generated a jump table of the right size, using // codegen->GetVIXLAssembler()->GetBuffer().Align(); - AssemblerAccurateScope aas(codegen->GetVIXLAssembler(), - num_entries * sizeof(int32_t), - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(codegen->GetVIXLAssembler(), + num_entries * sizeof(int32_t), + CodeBufferCheckScope::kMaximumSize); // TODO(VIXL): Check that using lower case bind is fine here. codegen->GetVIXLAssembler()->bind(&table_start_); for (uint32_t i = 0; i < num_entries; i++) { @@ -1377,9 +1380,9 @@ void CodeGeneratorARMVIXL::GenerateFrameEntry() { vixl32::Register temp = temps.Acquire(); __ Sub(temp, sp, static_cast<int32_t>(GetStackOverflowReservedBytes(kArm))); // The load must immediately precede RecordPcInfo. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ ldr(temp, MemOperand(temp)); RecordPcInfo(nullptr, 0); } @@ -1637,9 +1640,9 @@ void CodeGeneratorARMVIXL::InvokeRuntime(QuickEntrypointEnum entrypoint, __ Ldr(lr, MemOperand(tr, GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value())); // Ensure the pc position is recorded immediately after the `blx` instruction. // blx in T32 has only 16bit encoding that's why a stricter check for the scope is used. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::k16BitT32InstructionSizeInBytes, + CodeBufferCheckScope::kExactSize); __ blx(lr); if (EntrypointRequiresStackMap(entrypoint)) { RecordPcInfo(instruction, dex_pc, slow_path); @@ -2082,9 +2085,9 @@ void InstructionCodeGeneratorARMVIXL::HandleCondition(HCondition* cond) { __ Cmp(InputRegisterAt(cond, 0), CodeGenerator::GetInt32ValueOf(right.GetConstant())); } - AssemblerAccurateScope aas(GetVIXLAssembler(), - 3 * vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + 3 * vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ ite(ARMCondition(cond->GetCondition())); __ mov(ARMCondition(cond->GetCondition()), OutputRegister(cond), 1); __ mov(ARMCondition(cond->GetOppositeCondition()), OutputRegister(cond), 0); @@ -2370,9 +2373,9 @@ void InstructionCodeGeneratorARMVIXL::VisitInvokeInterface(HInvokeInterface* inv // Ensure the pc position is recorded immediately after the `ldr` instruction. { - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); // /* HeapReference<Class> */ temp = receiver->klass_ __ ldr(temp, MemOperand(RegisterFrom(receiver), class_offset)); codegen_->MaybeRecordImplicitNullCheck(invoke); @@ -2418,7 +2421,7 @@ void InstructionCodeGeneratorARMVIXL::VisitInvokeInterface(HInvokeInterface* inv { // Ensure the pc position is recorded immediately after the `blx` instruction. // blx in T32 has only 16bit encoding that's why a stricter check for the scope is used. - AssemblerAccurateScope aas(GetVIXLAssembler(), + ExactAssemblyScope aas(GetVIXLAssembler(), vixl32::k16BitT32InstructionSizeInBytes, CodeBufferCheckScope::kExactSize); // LR(); @@ -3793,9 +3796,9 @@ void InstructionCodeGeneratorARMVIXL::HandleShift(HBinaryOperation* op) { // If the shift is > 32 bits, override the high part __ Subs(temp, o_l, Operand::From(kArmBitsPerWord)); { - AssemblerAccurateScope guard(GetVIXLAssembler(), - 2 * vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope guard(GetVIXLAssembler(), + 2 * vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ it(pl); __ lsl(pl, o_h, low, temp); } @@ -3812,9 +3815,9 @@ void InstructionCodeGeneratorARMVIXL::HandleShift(HBinaryOperation* op) { // If the shift is > 32 bits, override the low part __ Subs(temp, o_h, Operand::From(kArmBitsPerWord)); { - AssemblerAccurateScope guard(GetVIXLAssembler(), - 2 * vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope guard(GetVIXLAssembler(), + 2 * vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ it(pl); __ asr(pl, o_l, high, temp); } @@ -3829,9 +3832,9 @@ void InstructionCodeGeneratorARMVIXL::HandleShift(HBinaryOperation* op) { __ Orr(o_l, o_l, temp); __ Subs(temp, o_h, Operand::From(kArmBitsPerWord)); { - AssemblerAccurateScope guard(GetVIXLAssembler(), - 2 * vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope guard(GetVIXLAssembler(), + 2 * vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ it(pl); __ lsr(pl, o_l, high, temp); } @@ -3948,9 +3951,9 @@ void InstructionCodeGeneratorARMVIXL::VisitNewInstance(HNewInstance* instruction GetAssembler()->LoadFromOffset(kLoadWord, temp, tr, QUICK_ENTRY_POINT(pNewEmptyString)); GetAssembler()->LoadFromOffset(kLoadWord, lr, temp, code_offset.Int32Value()); // blx in T32 has only 16bit encoding that's why a stricter check for the scope is used. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::k16BitT32InstructionSizeInBytes, + CodeBufferCheckScope::kExactSize); __ blx(lr); codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); } else { @@ -4192,9 +4195,9 @@ void InstructionCodeGeneratorARMVIXL::GenerateWideAtomicStore(vixl32::Register a __ Bind(&fail); { // Ensure the pc position is recorded immediately after the `ldrexd` instruction. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); // We need a load followed by store. (The address used in a STREX instruction must // be the same as the address in the most recently executed LDREX instruction.) __ ldrexd(temp1, temp2, MemOperand(addr)); @@ -4715,9 +4718,9 @@ void CodeGeneratorARMVIXL::GenerateImplicitNullCheck(HNullCheck* instruction) { UseScratchRegisterScope temps(GetVIXLAssembler()); // Ensure the pc position is recorded immediately after the `ldr` instruction. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ ldr(temps.Acquire(), MemOperand(InputRegisterAt(instruction, 0))); RecordPcInfo(instruction, instruction->GetDexPc()); } @@ -5233,9 +5236,9 @@ void InstructionCodeGeneratorARMVIXL::VisitArraySet(HArraySet* instruction) { { // Ensure we record the pc position immediately after the `ldr` instruction. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); // /* HeapReference<Class> */ temp1 = array->klass_ __ ldr(temp1, MemOperand(array, class_offset)); codegen_->MaybeRecordImplicitNullCheck(instruction); @@ -5384,9 +5387,9 @@ void InstructionCodeGeneratorARMVIXL::VisitArrayLength(HArrayLength* instruction vixl32::Register obj = InputRegisterAt(instruction, 0); vixl32::Register out = OutputRegister(instruction); { - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ ldr(out, MemOperand(obj, offset)); codegen_->MaybeRecordImplicitNullCheck(instruction); } @@ -7351,9 +7354,9 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall( relative_call_patches_.emplace_back(*invoke->GetTargetMethod().dex_file, invoke->GetTargetMethod().dex_method_index); { - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ bind(&relative_call_patches_.back().label); // Arbitrarily branch to the BL itself, override at link time. __ bl(&relative_call_patches_.back().label); @@ -7365,9 +7368,9 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall( // LR() { // blx in T32 has only 16bit encoding that's why a stricter check for the scope is used. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::k16BitT32InstructionSizeInBytes, + CodeBufferCheckScope::kExactSize); __ blx(lr); } break; @@ -7380,9 +7383,9 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall( ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value()); { // blx in T32 has only 16bit encoding that's why a stricter check for the scope is used. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::k16BitT32InstructionSizeInBytes, + CodeBufferCheckScope::kExactSize); // LR() __ blx(lr); } @@ -7406,9 +7409,9 @@ void CodeGeneratorARMVIXL::GenerateVirtualCall(HInvokeVirtual* invoke, Location uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); { // Make sure the pc is recorded immediately after the `ldr` instruction. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); // /* HeapReference<Class> */ temp = receiver->klass_ __ ldr(temp, MemOperand(receiver, class_offset)); MaybeRecordImplicitNullCheck(invoke); @@ -7433,9 +7436,9 @@ void CodeGeneratorARMVIXL::GenerateVirtualCall(HInvokeVirtual* invoke, Location // `RecordPcInfo()` immediately following record the correct pc. Use a scope to help guarantee // that. // blx in T32 has only 16bit encoding that's why a stricter check for the scope is used. - AssemblerAccurateScope aas(GetVIXLAssembler(), - vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + vixl32::k16BitT32InstructionSizeInBytes, + CodeBufferCheckScope::kExactSize); __ blx(lr); } @@ -7702,9 +7705,9 @@ void InstructionCodeGeneratorARMVIXL::VisitClassTableGet(HClassTableGet* instruc void CodeGeneratorARMVIXL::EmitMovwMovtPlaceholder( CodeGeneratorARMVIXL::PcRelativePatchInfo* labels, vixl32::Register out) { - AssemblerAccurateScope aas(GetVIXLAssembler(), - 3 * vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(GetVIXLAssembler(), + 3 * vixl32::kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); // TODO(VIXL): Think about using mov instead of movw. __ bind(&labels->movw_label); __ movw(out, /* placeholder */ 0u); diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 5ec3da4652..93ea601ed8 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -120,7 +120,7 @@ class JumpTableARMVIXL : public DeletableArenaObject<kArenaAllocSwitchTable> { bb_addresses_(switch_instr->GetArena()->Adapter(kArenaAllocCodeGenerator)) { uint32_t num_entries = switch_instr_->GetNumEntries(); for (uint32_t i = 0; i < num_entries; i++) { - IntLiteral *lit = new IntLiteral(0); + IntLiteral *lit = new IntLiteral(0, vixl32::RawLiteral::kManuallyPlaced); bb_addresses_.emplace_back(lit); } } diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index cae4161daf..456c5c6a92 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -757,6 +757,11 @@ void CodeGeneratorMIPS::GenerateFrameEntry() { if (RequiresCurrentMethod()) { __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, kCurrentMethodStackOffset); } + + if (GetGraph()->HasShouldDeoptimizeFlag()) { + // Initialize should deoptimize flag to 0. + __ StoreToOffset(kStoreWord, ZERO, SP, GetStackOffsetOfShouldDeoptimizeFlag()); + } } void CodeGeneratorMIPS::GenerateFrameExit() { @@ -4689,14 +4694,17 @@ void InstructionCodeGeneratorMIPS::GenConditionalMoveR6(HSelect* select) { } } -void LocationsBuilderMIPS::VisitShouldDeoptimizeFlag( - HShouldDeoptimizeFlag* flag ATTRIBUTE_UNUSED) { - // TODO: to be implemented. +void LocationsBuilderMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) { + LocationSummary* locations = new (GetGraph()->GetArena()) + LocationSummary(flag, LocationSummary::kNoCall); + locations->SetOut(Location::RequiresRegister()); } -void InstructionCodeGeneratorMIPS::VisitShouldDeoptimizeFlag( - HShouldDeoptimizeFlag* flag ATTRIBUTE_UNUSED) { - // TODO: to be implemented. +void InstructionCodeGeneratorMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) { + __ LoadFromOffset(kLoadWord, + flag->GetLocations()->Out().AsRegister<Register>(), + SP, + codegen_->GetStackOffsetOfShouldDeoptimizeFlag()); } void LocationsBuilderMIPS::VisitSelect(HSelect* select) { diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index b1f9b1db53..44d3759978 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -18,6 +18,7 @@ #include "art_method.h" #include "code_generator_utils.h" +#include "compiled_method.h" #include "entrypoints/quick/quick_entrypoints.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "gc/accounting/card_table.h" @@ -399,7 +400,15 @@ CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph, instruction_visitor_(graph, this), move_resolver_(graph->GetArena(), this), assembler_(graph->GetArena()), - isa_features_(isa_features) { + isa_features_(isa_features), + uint64_literals_(std::less<uint64_t>(), + graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + method_patches_(MethodReferenceComparator(), + graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + call_patches_(MethodReferenceComparator(), + graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) { // Save RA (containing the return address) to mimic Quick. AddAllocatedRegister(Location::RegisterLocation(RA)); } @@ -510,8 +519,6 @@ void CodeGeneratorMIPS64::GenerateFrameEntry() { RecordPcInfo(nullptr, 0); } - // TODO: anything related to T9/GP/GOT/PIC/.so's? - if (HasEmptyFrame()) { return; } @@ -562,13 +569,16 @@ void CodeGeneratorMIPS64::GenerateFrameEntry() { "kCurrentMethodStackOffset must fit into int16_t"); __ Sd(kMethodRegisterArgument, SP, kCurrentMethodStackOffset); } + + if (GetGraph()->HasShouldDeoptimizeFlag()) { + // Initialize should_deoptimize flag to 0. + __ StoreToOffset(kStoreWord, ZERO, SP, GetStackOffsetOfShouldDeoptimizeFlag()); + } } void CodeGeneratorMIPS64::GenerateFrameExit() { __ cfi().RememberState(); - // TODO: anything related to T9/GP/GOT/PIC/.so's? - if (!HasEmptyFrame()) { // Deallocate the rest of the frame. @@ -878,6 +888,103 @@ void CodeGeneratorMIPS64::MarkGCCard(GpuRegister object, } } +template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)> +inline void CodeGeneratorMIPS64::EmitPcRelativeLinkerPatches( + const ArenaDeque<PcRelativePatchInfo>& infos, + ArenaVector<LinkerPatch>* linker_patches) { + for (const PcRelativePatchInfo& info : infos) { + const DexFile& dex_file = info.target_dex_file; + size_t offset_or_index = info.offset_or_index; + DCHECK(info.pc_rel_label.IsBound()); + uint32_t pc_rel_offset = __ GetLabelLocation(&info.pc_rel_label); + linker_patches->push_back(Factory(pc_rel_offset, &dex_file, pc_rel_offset, offset_or_index)); + } +} + +void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) { + DCHECK(linker_patches->empty()); + size_t size = + method_patches_.size() + + call_patches_.size() + + pc_relative_dex_cache_patches_.size() + + relative_call_patches_.size(); + linker_patches->reserve(size); + for (const auto& entry : method_patches_) { + const MethodReference& target_method = entry.first; + Literal* literal = entry.second; + DCHECK(literal->GetLabel()->IsBound()); + uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel()); + linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset, + target_method.dex_file, + target_method.dex_method_index)); + } + for (const auto& entry : call_patches_) { + const MethodReference& target_method = entry.first; + Literal* literal = entry.second; + DCHECK(literal->GetLabel()->IsBound()); + uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel()); + linker_patches->push_back(LinkerPatch::CodePatch(literal_offset, + target_method.dex_file, + target_method.dex_method_index)); + } + EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_, + linker_patches); + for (const PcRelativePatchInfo& info : relative_call_patches_) { + const DexFile& dex_file = info.target_dex_file; + uint32_t method_index = info.offset_or_index; + DCHECK(info.pc_rel_label.IsBound()); + uint32_t pc_rel_offset = __ GetLabelLocation(&info.pc_rel_label); + linker_patches->push_back( + LinkerPatch::RelativeCodePatch(pc_rel_offset, &dex_file, method_index)); + } +} + +CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeDexCacheArrayPatch( + const DexFile& dex_file, uint32_t element_offset) { + return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_); +} + +CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeCallPatch( + const DexFile& dex_file, uint32_t method_index) { + return NewPcRelativePatch(dex_file, method_index, &relative_call_patches_); +} + +CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativePatch( + const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) { + patches->emplace_back(dex_file, offset_or_index); + return &patches->back(); +} + +Literal* CodeGeneratorMIPS64::DeduplicateUint64Literal(uint64_t value) { + return uint64_literals_.GetOrCreate( + value, + [this, value]() { return __ NewLiteral<uint64_t>(value); }); +} + +Literal* CodeGeneratorMIPS64::DeduplicateMethodLiteral(MethodReference target_method, + MethodToLiteralMap* map) { + return map->GetOrCreate( + target_method, + [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); }); +} + +Literal* CodeGeneratorMIPS64::DeduplicateMethodAddressLiteral(MethodReference target_method) { + return DeduplicateMethodLiteral(target_method, &method_patches_); +} + +Literal* CodeGeneratorMIPS64::DeduplicateMethodCodeLiteral(MethodReference target_method) { + return DeduplicateMethodLiteral(target_method, &call_patches_); +} + +void CodeGeneratorMIPS64::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info, + GpuRegister out) { + __ Bind(&info->pc_rel_label); + // Add the high half of a 32-bit offset to PC. + __ Auipc(out, /* placeholder */ 0x1234); + // The immediately following instruction will add the sign-extended low half of the 32-bit + // offset to `out` (e.g. ld, jialc, addiu). +} + void CodeGeneratorMIPS64::SetupBlockedRegisters() const { // ZERO, K0, K1, GP, SP, RA are always reserved and can't be allocated. blocked_core_registers_[ZERO] = true; @@ -946,7 +1053,6 @@ void CodeGeneratorMIPS64::InvokeRuntime(QuickEntrypointEnum entrypoint, uint32_t dex_pc, SlowPathCode* slow_path) { ValidateInvokeRuntime(entrypoint, instruction, slow_path); - // TODO: anything related to T9/GP/GOT/PIC/.so's? __ LoadFromOffset(kLoadDoubleword, T9, TR, @@ -2636,14 +2742,17 @@ void InstructionCodeGeneratorMIPS64::VisitDeoptimize(HDeoptimize* deoptimize) { /* false_target */ nullptr); } -void LocationsBuilderMIPS64::VisitShouldDeoptimizeFlag( - HShouldDeoptimizeFlag* flag ATTRIBUTE_UNUSED) { - // TODO: to be implemented. +void LocationsBuilderMIPS64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) { + LocationSummary* locations = new (GetGraph()->GetArena()) + LocationSummary(flag, LocationSummary::kNoCall); + locations->SetOut(Location::RequiresRegister()); } -void InstructionCodeGeneratorMIPS64::VisitShouldDeoptimizeFlag( - HShouldDeoptimizeFlag* flag ATTRIBUTE_UNUSED) { - // TODO: to be implemented. +void InstructionCodeGeneratorMIPS64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) { + __ LoadFromOffset(kLoadWord, + flag->GetLocations()->Out().AsRegister<GpuRegister>(), + SP, + codegen_->GetStackOffsetOfShouldDeoptimizeFlag()); } void LocationsBuilderMIPS64::VisitSelect(HSelect* select) { @@ -2986,39 +3095,33 @@ HLoadClass::LoadKind CodeGeneratorMIPS64::GetSupportedLoadClassKind( HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS64::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { - switch (desired_dispatch_info.method_load_kind) { - case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup: - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: - // TODO: Implement these types. For the moment, we fall back to kDexCacheViaMethod. - return HInvokeStaticOrDirect::DispatchInfo { - HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod, - HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod, - 0u, - 0u - }; - default: - break; - } - switch (desired_dispatch_info.code_ptr_location) { - case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup: - case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: - // TODO: Implement these types. For the moment, we fall back to kCallArtMethod. - return HInvokeStaticOrDirect::DispatchInfo { - desired_dispatch_info.method_load_kind, - HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod, - desired_dispatch_info.method_load_data, - 0u - }; - default: - return desired_dispatch_info; - } + // On MIPS64 we support all dispatch types. + return desired_dispatch_info; } void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) { // All registers are assumed to be correctly set up per the calling convention. - Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp. - switch (invoke->GetMethodLoadKind()) { + HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind(); + HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = invoke->GetCodePtrLocation(); + + // For better instruction scheduling we load the direct code pointer before the method pointer. + switch (code_ptr_location) { + case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect: + // T9 = invoke->GetDirectCodePtr(); + __ LoadLiteral(T9, kLoadDoubleword, DeduplicateUint64Literal(invoke->GetDirectCodePtr())); + break; + case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup: + // T9 = code address from literal pool with link-time patch. + __ LoadLiteral(T9, + kLoadUnsignedWord, + DeduplicateMethodCodeLiteral(invoke->GetTargetMethod())); + break; + default: + break; + } + + switch (method_load_kind) { case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: { // temp = thread->string_init_entrypoint uint32_t offset = @@ -3033,14 +3136,23 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()); break; case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress: - __ LoadConst64(temp.AsRegister<GpuRegister>(), invoke->GetMethodAddress()); + __ LoadLiteral(temp.AsRegister<GpuRegister>(), + kLoadDoubleword, + DeduplicateUint64Literal(invoke->GetMethodAddress())); break; case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup: - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: - // TODO: Implement these types. - // Currently filtered out by GetSupportedInvokeStaticOrDirectDispatch(). - LOG(FATAL) << "Unsupported"; - UNREACHABLE(); + __ LoadLiteral(temp.AsRegister<GpuRegister>(), + kLoadUnsignedWord, + DeduplicateMethodAddressLiteral(invoke->GetTargetMethod())); + break; + case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: { + uint32_t offset = invoke->GetDexCacheArrayOffset(); + CodeGeneratorMIPS64::PcRelativePatchInfo* info = + NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset); + EmitPcRelativeAddressPlaceholderHigh(info, AT); + __ Ld(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678); + break; + } case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: { Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()); GpuRegister reg = temp.AsRegister<GpuRegister>(); @@ -3071,23 +3183,25 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo } } - switch (invoke->GetCodePtrLocation()) { + switch (code_ptr_location) { case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf: - __ Jialc(&frame_entry_label_, T9); + __ Balc(&frame_entry_label_); break; case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect: - // LR = invoke->GetDirectCodePtr(); - __ LoadConst64(T9, invoke->GetDirectCodePtr()); - // LR() + case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup: + // T9 prepared above for better instruction scheduling. + // T9() __ Jalr(T9); __ Nop(); break; - case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup: - case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: - // TODO: Implement these types. - // Currently filtered out by GetSupportedInvokeStaticOrDirectDispatch(). - LOG(FATAL) << "Unsupported"; - UNREACHABLE(); + case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: { + CodeGeneratorMIPS64::PcRelativePatchInfo* info = + NewPcRelativeCallPatch(*invoke->GetTargetMethod().dex_file, + invoke->GetTargetMethod().dex_method_index); + EmitPcRelativeAddressPlaceholderHigh(info, AT); + __ Jialc(AT, /* placeholder */ 0x5678); + break; + } case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod: // T9 = callee_method->entry_point_from_quick_compiled_code_; __ LoadFromOffset(kLoadDoubleword, diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index 690eccb7d8..067c1f940f 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -279,6 +279,9 @@ class CodeGeneratorMIPS64 : public CodeGenerator { Mips64Assembler* GetAssembler() OVERRIDE { return &assembler_; } const Mips64Assembler& GetAssembler() const OVERRIDE { return assembler_; } + // Emit linker patches. + void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE; + void MarkGCCard(GpuRegister object, GpuRegister value, bool value_can_be_null); // Register allocation. @@ -357,7 +360,44 @@ class CodeGeneratorMIPS64 : public CodeGenerator { void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE; void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE; + // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays, + // boot image strings and method calls. The only difference is the interpretation of + // the offset_or_index. + struct PcRelativePatchInfo { + PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx) + : target_dex_file(dex_file), offset_or_index(off_or_idx) { } + PcRelativePatchInfo(PcRelativePatchInfo&& other) = default; + + const DexFile& target_dex_file; + // Either the dex cache array element offset or the string/type/method index. + uint32_t offset_or_index; + // Label for the auipc instruction. + Mips64Label pc_rel_label; + }; + + PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, + uint32_t element_offset); + PcRelativePatchInfo* NewPcRelativeCallPatch(const DexFile& dex_file, + uint32_t method_index); + + void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info, GpuRegister out); + private: + using Uint64ToLiteralMap = ArenaSafeMap<uint64_t, Literal*>; + using MethodToLiteralMap = ArenaSafeMap<MethodReference, Literal*, MethodReferenceComparator>; + Literal* DeduplicateUint64Literal(uint64_t value); + Literal* DeduplicateMethodLiteral(MethodReference target_method, MethodToLiteralMap* map); + Literal* DeduplicateMethodAddressLiteral(MethodReference target_method); + Literal* DeduplicateMethodCodeLiteral(MethodReference target_method); + + PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file, + uint32_t offset_or_index, + ArenaDeque<PcRelativePatchInfo>* patches); + + template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)> + void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos, + ArenaVector<LinkerPatch>* linker_patches); + // Labels for each block that will be compiled. Mips64Label* block_labels_; // Indexed by block id. Mips64Label frame_entry_label_; @@ -367,6 +407,16 @@ class CodeGeneratorMIPS64 : public CodeGenerator { Mips64Assembler assembler_; const Mips64InstructionSetFeatures& isa_features_; + // Deduplication map for 64-bit literals, used for non-patchable method address or method code + // address. + Uint64ToLiteralMap uint64_literals_; + // Method patch info, map MethodReference to a literal for method address and method code. + MethodToLiteralMap method_patches_; + MethodToLiteralMap call_patches_; + // PC-relative patch info. + ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_; + ArenaDeque<PcRelativePatchInfo> relative_call_patches_; + DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS64); }; diff --git a/compiler/optimizing/code_generator_utils.h b/compiler/optimizing/code_generator_utils.h index 7efed8c9ec..a6b41c0588 100644 --- a/compiler/optimizing/code_generator_utils.h +++ b/compiler/optimizing/code_generator_utils.h @@ -18,6 +18,8 @@ #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_UTILS_H_ #include <cstdint> +#include <cstdlib> +#include <limits> namespace art { @@ -32,6 +34,12 @@ void CalculateMagicAndShiftForDivRem(int64_t divisor, bool is_long, int64_t* mag // that it has been previously visited by the InstructionCodeGenerator. bool IsBooleanValueOrMaterializedCondition(HInstruction* cond_input); +template <typename T> T AbsOrMin(T value) { + return (value == std::numeric_limits<T>::min()) + ? value + : std::abs(value); +} + } // namespace art #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_UTILS_H_ diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index 188ee3a8d1..34b52a87b5 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -20,12 +20,15 @@ #include <string> #include <sstream> +#include "android-base/stringprintf.h" + #include "base/arena_containers.h" #include "base/bit_vector-inl.h" -#include "base/stringprintf.h" namespace art { +using android::base::StringPrintf; + static bool IsAllowedToJumpToExitBlock(HInstruction* instruction) { return instruction->IsThrow() || instruction->IsReturn() || instruction->IsReturnVoid(); } diff --git a/compiler/optimizing/graph_test.cc b/compiler/optimizing/graph_test.cc index d5305646a8..28ee3a5e8b 100644 --- a/compiler/optimizing/graph_test.cc +++ b/compiler/optimizing/graph_test.cc @@ -15,7 +15,6 @@ */ #include "base/arena_allocator.h" -#include "base/stringprintf.h" #include "builder.h" #include "nodes.h" #include "optimizing_unit_test.h" diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 658b80468e..c615df1f1d 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -1185,6 +1185,18 @@ void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) { RecordSimplification(); } +// Return whether x / divisor == x * (1.0f / divisor), for every float x. +static constexpr bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) { + // True, if the most significant bits of divisor are 0. + return ((divisor & 0x7fffff) == 0); +} + +// Return whether x / divisor == x * (1.0 / divisor), for every double x. +static constexpr bool CanDivideByReciprocalMultiplyDouble(int64_t divisor) { + // True, if the most significant bits of divisor are 0. + return ((divisor & ((UINT64_C(1) << 52) - 1)) == 0); +} + void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) { HConstant* input_cst = instruction->GetConstantRight(); HInstruction* input_other = instruction->GetLeastConstantLeft(); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 433dced9d7..95551c8fd9 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -47,6 +47,9 @@ using helpers::SRegisterFrom; using namespace vixl::aarch32; // NOLINT(build/namespaces) +using vixl::ExactAssemblyScope; +using vixl::CodeBufferCheckScope; + ArmVIXLAssembler* IntrinsicCodeGeneratorARMVIXL::GetAssembler() { return codegen_->GetAssembler(); } @@ -467,9 +470,9 @@ static void GenMinMax(HInvoke* invoke, bool is_min, ArmVIXLAssembler* assembler) __ Cmp(op1, op2); { - AssemblerAccurateScope aas(assembler->GetVIXLAssembler(), - 3 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(assembler->GetVIXLAssembler(), + 3 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ ite(is_min ? lt : gt); __ mov(is_min ? lt : gt, out, op1); @@ -1050,9 +1053,9 @@ static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorARMVIXL* __ Subs(tmp, tmp, expected); { - AssemblerAccurateScope aas(assembler->GetVIXLAssembler(), - 3 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(assembler->GetVIXLAssembler(), + 3 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ itt(eq); __ strex(eq, tmp, value, MemOperand(tmp_ptr)); @@ -1066,9 +1069,9 @@ static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorARMVIXL* __ Rsbs(out, tmp, 1); { - AssemblerAccurateScope aas(assembler->GetVIXLAssembler(), - 2 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(assembler->GetVIXLAssembler(), + 2 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ it(cc); __ mov(cc, out, 0); @@ -1185,9 +1188,9 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { // temp0 = min(len(str), len(arg)). { - AssemblerAccurateScope aas(assembler->GetVIXLAssembler(), - 2 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(assembler->GetVIXLAssembler(), + 2 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ it(gt); __ mov(gt, temp0, temp1); @@ -1207,9 +1210,9 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { // This could in theory exceed INT32_MAX, so treat temp0 as unsigned. __ Lsls(temp3, temp3, 31u); // Extract purely the compression flag. - AssemblerAccurateScope aas(assembler->GetVIXLAssembler(), - 2 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(assembler->GetVIXLAssembler(), + 2 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ it(ne); __ add(ne, temp0, temp0, temp0); @@ -1324,9 +1327,9 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { __ Mov(temp2, arg); __ Lsrs(temp3, temp3, 1u); // Continue the move of the compression flag. { - AssemblerAccurateScope aas(assembler->GetVIXLAssembler(), - 3 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(assembler->GetVIXLAssembler(), + 3 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ itt(cs); // Interleave with selection of temp1 and temp2. __ mov(cs, temp1, arg); // Preserves flags. __ mov(cs, temp2, str); // Preserves flags. @@ -1361,9 +1364,9 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u, "Expecting 0=compressed, 1=uncompressed"); - AssemblerAccurateScope aas(assembler->GetVIXLAssembler(), - 2 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(assembler->GetVIXLAssembler(), + 2 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ it(cc); __ rsb(cc, out, out, 0); } @@ -1457,9 +1460,9 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringEquals(HInvoke* invoke) { // For string compression, calculate the number of bytes to compare (not chars). // This could in theory exceed INT32_MAX, so treat temp as unsigned. __ Lsrs(temp, temp, 1u); // Extract length and check compression flag. - AssemblerAccurateScope aas(assembler->GetVIXLAssembler(), - 2 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); + ExactAssemblyScope aas(assembler->GetVIXLAssembler(), + 2 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); __ it(cs); // If uncompressed, __ add(cs, temp, temp, temp); // double the byte count. } diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc index 13e14c53b5..3831aa6c91 100644 --- a/compiler/optimizing/linearize_test.cc +++ b/compiler/optimizing/linearize_test.cc @@ -18,7 +18,6 @@ #include "arch/x86/instruction_set_features_x86.h" #include "base/arena_allocator.h" -#include "base/stringprintf.h" #include "builder.h" #include "code_generator.h" #include "code_generator_x86.h" diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 925d4f1fd1..1e946d67b6 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2440,6 +2440,17 @@ std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::ClinitCheckReq } } +// Helper for InstructionDataEquals to fetch the mirror Class out +// from a kJitTableAddress LoadClass kind. +// NO_THREAD_SAFETY_ANALYSIS because even though we're accessing +// mirrors, they are stored in a variable size handle scope which is always +// visited during a pause. Also, the only caller of this helper +// only uses the mirror for pointer comparison. +static inline mirror::Class* AsMirrorInternal(uint64_t address) + NO_THREAD_SAFETY_ANALYSIS { + return reinterpret_cast<StackReference<mirror::Class>*>(address)->AsMirrorPtr(); +} + bool HLoadClass::InstructionDataEquals(const HInstruction* other) const { const HLoadClass* other_load_class = other->AsLoadClass(); // TODO: To allow GVN for HLoadClass from different dex files, we should compare the type @@ -2448,16 +2459,14 @@ bool HLoadClass::InstructionDataEquals(const HInstruction* other) const { GetPackedFields() != other_load_class->GetPackedFields()) { return false; } - LoadKind load_kind = GetLoadKind(); - if (HasAddress(load_kind)) { - return GetAddress() == other_load_class->GetAddress(); - } else if (HasTypeReference(load_kind)) { - return IsSameDexFile(GetDexFile(), other_load_class->GetDexFile()); - } else { - DCHECK(HasDexCacheReference(load_kind)) << load_kind; - // If the type indexes and dex files are the same, dex cache element offsets - // must also be the same, so we don't need to compare them. - return IsSameDexFile(GetDexFile(), other_load_class->GetDexFile()); + switch (GetLoadKind()) { + case LoadKind::kBootImageAddress: + return GetAddress() == other_load_class->GetAddress(); + case LoadKind::kJitTableAddress: + return AsMirrorInternal(GetAddress()) == AsMirrorInternal(other_load_class->GetAddress()); + default: + DCHECK(HasTypeReference(GetLoadKind()) || HasDexCacheReference(GetLoadKind())); + return IsSameDexFile(GetDexFile(), other_load_class->GetDexFile()); } } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 659cddae05..4a8cfcb158 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -125,6 +125,11 @@ enum GraphAnalysisResult { kAnalysisSuccess, }; +template <typename T> +static inline typename std::make_unsigned<T>::type MakeUnsigned(T x) { + return static_cast<typename std::make_unsigned<T>::type>(x); +} + class HInstructionList : public ValueObject { public: HInstructionList() : first_instruction_(nullptr), last_instruction_(nullptr) {} diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 64c87dc13a..ba7012ab1a 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -22,6 +22,8 @@ #include <stdint.h> +#include "android-base/strings.h" + #ifdef ART_ENABLE_CODEGEN_arm #include "dex_cache_array_fixups_arm.h" #endif @@ -1115,7 +1117,8 @@ Compiler* CreateOptimizingCompiler(CompilerDriver* driver) { bool IsCompilingWithCoreImage() { const std::string& image = Runtime::Current()->GetImageLocation(); // TODO: This is under-approximating... - if (EndsWith(image, "core.art") || EndsWith(image, "core-optimizing.art")) { + if (android::base::EndsWith(image, "core.art") || + android::base::EndsWith(image, "core-optimizing.art")) { return true; } return false; diff --git a/compiler/optimizing/pretty_printer.h b/compiler/optimizing/pretty_printer.h index 5891350894..c6579dc5e0 100644 --- a/compiler/optimizing/pretty_printer.h +++ b/compiler/optimizing/pretty_printer.h @@ -17,7 +17,8 @@ #ifndef ART_COMPILER_OPTIMIZING_PRETTY_PRINTER_H_ #define ART_COMPILER_OPTIMIZING_PRETTY_PRINTER_H_ -#include "base/stringprintf.h" +#include "android-base/stringprintf.h" + #include "nodes.h" namespace art { @@ -108,7 +109,7 @@ class StringPrettyPrinter : public HPrettyPrinter { : HPrettyPrinter(graph), str_(""), current_block_(nullptr) { } void PrintInt(int value) OVERRIDE { - str_ += StringPrintf("%d", value); + str_ += android::base::StringPrintf("%d", value); } void PrintString(const char* value) OVERRIDE { diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc index 951cdfbd8b..1af94f3445 100644 --- a/compiler/optimizing/pretty_printer_test.cc +++ b/compiler/optimizing/pretty_printer_test.cc @@ -15,7 +15,6 @@ */ #include "base/arena_allocator.h" -#include "base/stringprintf.h" #include "builder.h" #include "dex_file.h" #include "dex_instruction.h" diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc index bbbb1a18ce..91efb80015 100644 --- a/compiler/optimizing/sharpening.cc +++ b/compiler/optimizing/sharpening.cc @@ -197,7 +197,9 @@ void HSharpening::ProcessLoadClass(HLoadClass* load_class) { // out which class loader to use. address = reinterpret_cast<uint64_t>(handles_->NewHandle(klass).GetReference()); } else { - // Class not loaded yet. Fallback to the dex cache. + // Class not loaded yet. This happens when the dex code requesting + // this `HLoadClass` hasn't been executed in the interpreter. + // Fallback to the dex cache. // TODO(ngeoffray): Generate HDeoptimize instead. desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod; } diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc index 429763423c..f69f417efc 100644 --- a/compiler/optimizing/ssa_test.cc +++ b/compiler/optimizing/ssa_test.cc @@ -14,8 +14,9 @@ * limitations under the License. */ +#include "android-base/stringprintf.h" + #include "base/arena_allocator.h" -#include "base/stringprintf.h" #include "builder.h" #include "dex_file.h" #include "dex_instruction.h" @@ -35,7 +36,7 @@ class SsaPrettyPrinter : public HPrettyPrinter { explicit SsaPrettyPrinter(HGraph* graph) : HPrettyPrinter(graph), str_("") {} void PrintInt(int value) OVERRIDE { - str_ += StringPrintf("%d", value); + str_ += android::base::StringPrintf("%d", value); } void PrintString(const char* value) OVERRIDE { |