diff options
Diffstat (limited to 'compiler')
21 files changed, 153 insertions, 109 deletions
diff --git a/compiler/dex/bb_optimizations.cc b/compiler/dex/bb_optimizations.cc index f351d990d0..11a7e44f98 100644 --- a/compiler/dex/bb_optimizations.cc +++ b/compiler/dex/bb_optimizations.cc @@ -17,7 +17,6 @@ #include "bb_optimizations.h" #include "dataflow_iterator.h" #include "dataflow_iterator-inl.h" -#include "global_value_numbering.h" namespace art { @@ -80,14 +79,4 @@ bool MethodUseCount::Worker(PassDataHolder* data) const { return false; } -bool GlobalValueNumberingCleanupPass::Gate(const PassDataHolder* data) const { - DCHECK(data != nullptr); - CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit; - DCHECK(c_unit != nullptr); - // Do not do cleanup if GVN skipped this. - // TODO: Proper dependencies between passes? - return !GlobalValueNumbering::Skip(c_unit); -} - - } // namespace art diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h index 72919b6a9d..02d532798c 100644 --- a/compiler/dex/bb_optimizations.h +++ b/compiler/dex/bb_optimizations.h @@ -308,9 +308,6 @@ class GlobalValueNumberingCleanupPass : public PassME { : PassME("GVNCleanup", kNoNodes, "") { } - // Depends on GlobalValueNumbering, so implemented in cc file. - bool Gate(const PassDataHolder* data) const OVERRIDE; - void Start(PassDataHolder* data) const OVERRIDE { DCHECK(data != nullptr); CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit; diff --git a/compiler/dex/global_value_numbering.cc b/compiler/dex/global_value_numbering.cc index 30e3ce0354..e2b99871c8 100644 --- a/compiler/dex/global_value_numbering.cc +++ b/compiler/dex/global_value_numbering.cc @@ -128,8 +128,9 @@ bool GlobalValueNumbering::FinishBasicBlock(BasicBlock* bb) { ++bbs_processed_; merge_lvns_.clear(); - bool change = (lvns_[bb->id] == nullptr) || !lvns_[bb->id]->Equals(*work_lvn_); + bool change = false; if (mode_ == kModeGvn) { + change = (lvns_[bb->id] == nullptr) || !lvns_[bb->id]->Equals(*work_lvn_); // In GVN mode, keep the latest LVN even if Equals() indicates no change. This is // to keep the correct values of fields that do not contribute to Equals() as long // as they depend only on predecessor LVNs' fields that do contribute to Equals(). @@ -137,6 +138,9 @@ bool GlobalValueNumbering::FinishBasicBlock(BasicBlock* bb) { std::unique_ptr<const LocalValueNumbering> old_lvn(lvns_[bb->id]); lvns_[bb->id] = work_lvn_.release(); } else { + DCHECK_EQ(mode_, kModeGvnPostProcessing); // kModeLvn doesn't use FinishBasicBlock(). + DCHECK(lvns_[bb->id] != nullptr); + DCHECK(lvns_[bb->id]->Equals(*work_lvn_)); work_lvn_.reset(); } return change; diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index b5c42f11ac..9e3fbbc967 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -291,8 +291,12 @@ BasicBlock* MIRGraph::SplitBlock(DexOffset code_offset, BasicBlock* MIRGraph::FindBlock(DexOffset code_offset, bool create, BasicBlock** immed_pred_block_p, ScopedArenaVector<uint16_t>* dex_pc_to_block_map) { - if (code_offset >= current_code_item_->insns_size_in_code_units_) { - return nullptr; + if (UNLIKELY(code_offset >= current_code_item_->insns_size_in_code_units_)) { + // There can be a fall-through out of the method code. We shall record such a block + // here (assuming create==true) and check that it's dead at the end of InlineMethod(). + // Though we're only aware of the cases where code_offset is exactly the same as + // insns_size_in_code_units_, treat greater code_offset the same just in case. + code_offset = current_code_item_->insns_size_in_code_units_; } int block_id = (*dex_pc_to_block_map)[code_offset]; @@ -483,6 +487,7 @@ BasicBlock* MIRGraph::ProcessCanBranch(BasicBlock* cur_block, MIR* insn, DexOffs BasicBlock* taken_block = FindBlock(target, /* create */ true, /* immed_pred_block_p */ &cur_block, dex_pc_to_block_map); + DCHECK(taken_block != nullptr); cur_block->taken = taken_block->id; taken_block->predecessors.push_back(cur_block->id); @@ -494,6 +499,7 @@ BasicBlock* MIRGraph::ProcessCanBranch(BasicBlock* cur_block, MIR* insn, DexOffs /* immed_pred_block_p */ &cur_block, dex_pc_to_block_map); + DCHECK(fallthrough_block != nullptr); cur_block->fall_through = fallthrough_block->id; fallthrough_block->predecessors.push_back(cur_block->id); } else if (code_ptr < code_end) { @@ -508,7 +514,8 @@ BasicBlock* MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, DexOffs ScopedArenaVector<uint16_t>* dex_pc_to_block_map) { UNUSED(flags); const uint16_t* switch_data = - reinterpret_cast<const uint16_t*>(GetCurrentInsns() + cur_offset + insn->dalvikInsn.vB); + reinterpret_cast<const uint16_t*>(GetCurrentInsns() + cur_offset + + static_cast<int32_t>(insn->dalvikInsn.vB)); int size; const int* keyTable; const int* target_table; @@ -561,6 +568,7 @@ BasicBlock* MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, DexOffs BasicBlock* case_block = FindBlock(cur_offset + target_table[i], /* create */ true, /* immed_pred_block_p */ &cur_block, dex_pc_to_block_map); + DCHECK(case_block != nullptr); SuccessorBlockInfo* successor_block_info = static_cast<SuccessorBlockInfo*>(arena_->Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor)); @@ -576,6 +584,7 @@ BasicBlock* MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, DexOffs BasicBlock* fallthrough_block = FindBlock(cur_offset + width, /* create */ true, /* immed_pred_block_p */ nullptr, dex_pc_to_block_map); + DCHECK(fallthrough_block != nullptr); cur_block->fall_through = fallthrough_block->id; fallthrough_block->predecessors.push_back(cur_block->id); return cur_block; @@ -709,8 +718,8 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ // FindBlock lookup cache. ScopedArenaAllocator allocator(&cu_->arena_stack); ScopedArenaVector<uint16_t> dex_pc_to_block_map(allocator.Adapter()); - dex_pc_to_block_map.resize(dex_pc_to_block_map.size() + - current_code_item_->insns_size_in_code_units_); + dex_pc_to_block_map.resize(current_code_item_->insns_size_in_code_units_ + + 1 /* Fall-through on last insn; dead or punt to interpreter. */); // TODO: replace with explicit resize routine. Using automatic extension side effect for now. try_block_addr_->SetBit(current_code_item_->insns_size_in_code_units_); @@ -876,6 +885,20 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ if (cu_->verbose) { DumpMIRGraph(); } + + // Check if there's been a fall-through out of the method code. + BasicBlockId out_bb_id = dex_pc_to_block_map[current_code_item_->insns_size_in_code_units_]; + if (UNLIKELY(out_bb_id != NullBasicBlockId)) { + // Eagerly calculate DFS order to determine if the block is dead. + DCHECK(!DfsOrdersUpToDate()); + ComputeDFSOrders(); + BasicBlock* out_bb = GetBasicBlock(out_bb_id); + DCHECK(out_bb != nullptr); + if (out_bb->block_type != kDead) { + LOG(WARNING) << "Live fall-through out of method in " << PrettyMethod(method_idx, dex_file); + SetPuntToInterpreter(true); + } + } } void MIRGraph::ShowOpcodeStats() { diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 25c159f2a1..217dbeeb44 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -1453,13 +1453,13 @@ void MIRGraph::EliminateDeadCodeEnd() { } void MIRGraph::GlobalValueNumberingCleanup() { + // If the GVN didn't run, these pointers should be null and everything is effectively no-op. delete temp_.gvn.dce; temp_.gvn.dce = nullptr; delete temp_.gvn.gvn; temp_.gvn.gvn = nullptr; temp_.gvn.ifield_ids = nullptr; temp_.gvn.sfield_ids = nullptr; - DCHECK(temp_scoped_alloc_ != nullptr); temp_scoped_alloc_.reset(); } diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index a07274f17e..4fdc7289bf 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -1467,26 +1467,6 @@ class Mir2Lir { return InexpensiveConstantInt(value); } - /** - * @brief Whether division by the given divisor can be converted to multiply by its reciprocal. - * @param divisor A constant divisor bits of float type. - * @return Returns true iff, x/divisor == x*(1.0f/divisor), for every float x. - */ - bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) { - // True, if float value significand bits are 0. - return ((divisor & 0x7fffff) == 0); - } - - /** - * @brief Whether division by the given divisor can be converted to multiply by its reciprocal. - * @param divisor A constant divisor bits of double type. - * @return Returns true iff, x/divisor == x*(1.0/divisor), for every double x. - */ - bool CanDivideByReciprocalMultiplyDouble(int64_t divisor) { - // True, if double value significand bits are 0. - return ((divisor & ((UINT64_C(1) << 52) - 1)) == 0); - } - // May be optimized by targets. virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src); virtual void GenMonitorExit(int opt_flags, RegLocation rl_src); diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index a883bd0149..0f44af07b8 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -702,7 +702,6 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, current_block_->AddInstruction(load_class); clinit_check = new (arena_) HClinitCheck(load_class, dex_pc); current_block_->AddInstruction(clinit_check); - ++number_of_arguments; } } } @@ -745,14 +744,14 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, i++; } } + DCHECK_EQ(argument_index, number_of_arguments); if (clinit_check_requirement == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit) { // Add the class initialization check as last input of `invoke`. DCHECK(clinit_check != nullptr); - invoke->SetArgumentAt(argument_index++, clinit_check); + invoke->SetArgumentAt(argument_index, clinit_check); } - DCHECK_EQ(argument_index, number_of_arguments); current_block_->AddInstruction(invoke); latest_result_ = invoke; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 5163395cac..cfe121e0ec 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -153,6 +153,7 @@ HBasicBlock* CodeGenerator::FirstNonEmptyBlock(HBasicBlock* block) const { } void CodeGenerator::CompileInternal(CodeAllocator* allocator, bool is_baseline) { + is_baseline_ = is_baseline; HGraphVisitor* instruction_visitor = GetInstructionVisitor(); DCHECK_EQ(current_block_index_, 0u); GenerateFrameEntry(); diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index e536b2d0ee..6342f91684 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -212,6 +212,10 @@ class CodeGenerator { std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const; void BuildStackMaps(std::vector<uint8_t>* vector); + bool IsBaseline() const { + return is_baseline_; + } + bool IsLeafMethod() const { return is_leaf_; } @@ -325,6 +329,7 @@ class CodeGenerator { number_of_register_pairs_(number_of_register_pairs), core_callee_save_mask_(core_callee_save_mask), fpu_callee_save_mask_(fpu_callee_save_mask), + is_baseline_(false), graph_(graph), compiler_options_(compiler_options), pc_infos_(graph->GetArena(), 32), @@ -404,6 +409,9 @@ class CodeGenerator { const uint32_t core_callee_save_mask_; const uint32_t fpu_callee_save_mask_; + // Whether we are using baseline. + bool is_baseline_; + private: void InitLocationsBaseline(HInstruction* instruction); size_t GetStackOffsetOfSavedRegister(size_t index); diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index bcdfccdd16..159bd30e45 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1241,13 +1241,9 @@ void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { } void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { - // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation, but this step is not - // run in baseline. So we remove them manually here if we find them. - // TODO: Instead of this local workaround, address this properly. - if (invoke->IsStaticWithExplicitClinitCheck()) { - invoke->RemoveClinitCheckOrLoadClassAsLastInput(); - } + // When we do not run baseline, explicit clinit checks triggered by static + // invokes must have been pruned by art::PrepareForRegisterAllocation. + DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(), codegen_->GetInstructionSetFeatures()); @@ -1273,9 +1269,9 @@ static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) } void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { - // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation. - DCHECK(!invoke->IsStaticWithExplicitClinitCheck()); + // When we do not run baseline, explicit clinit checks triggered by static + // invokes must have been pruned by art::PrepareForRegisterAllocation. + DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); if (TryGenerateIntrinsicCode(invoke, codegen_)) { return; @@ -1293,7 +1289,7 @@ void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { locations->AddTemp(Location::RegisterLocation(R0)); InvokeDexCallingConventionVisitor calling_convention_visitor; - for (size_t i = 0; i < invoke->InputCount(); i++) { + for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { HInstruction* input = invoke->InputAt(i); locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 0d963d73b4..946ffc8ea8 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -1908,7 +1908,7 @@ void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) { locations->AddTemp(LocationFrom(x0)); InvokeDexCallingConventionVisitor calling_convention_visitor; - for (size_t i = 0; i < invoke->InputCount(); i++) { + for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { HInstruction* input = invoke->InputAt(i); locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); } @@ -1968,13 +1968,9 @@ void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { } void LocationsBuilderARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { - // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation, but this step is not - // run in baseline. So we remove them manually here if we find them. - // TODO: Instead of this local workaround, address this properly. - if (invoke->IsStaticWithExplicitClinitCheck()) { - invoke->RemoveClinitCheckOrLoadClassAsLastInput(); - } + // When we do not run baseline, explicit clinit checks triggered by static + // invokes must have been pruned by art::PrepareForRegisterAllocation. + DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); IntrinsicLocationsBuilderARM64 intrinsic(GetGraph()->GetArena()); if (intrinsic.TryDispatch(invoke)) { @@ -2036,9 +2032,9 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok } void InstructionCodeGeneratorARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { - // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation. - DCHECK(!invoke->IsStaticWithExplicitClinitCheck()); + // When we do not run baseline, explicit clinit checks triggered by static + // invokes must have been pruned by art::PrepareForRegisterAllocation. + DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); if (TryGenerateIntrinsicCode(invoke, codegen_)) { return; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index a037040ae4..7df4b53cbe 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1194,13 +1194,9 @@ void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) { } void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { - // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation, but this step is not - // run in baseline. So we remove them manually here if we find them. - // TODO: Instead of this local workaround, address this properly. - if (invoke->IsStaticWithExplicitClinitCheck()) { - invoke->RemoveClinitCheckOrLoadClassAsLastInput(); - } + // When we do not run baseline, explicit clinit checks triggered by static + // invokes must have been pruned by art::PrepareForRegisterAllocation. + DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); IntrinsicLocationsBuilderX86 intrinsic(codegen_); if (intrinsic.TryDispatch(invoke)) { @@ -1220,9 +1216,9 @@ static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) } void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { - // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation. - DCHECK(!invoke->IsStaticWithExplicitClinitCheck()); + // When we do not run baseline, explicit clinit checks triggered by static + // invokes must have been pruned by art::PrepareForRegisterAllocation. + DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); if (TryGenerateIntrinsicCode(invoke, codegen_)) { return; @@ -1243,7 +1239,7 @@ void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) { locations->AddTemp(Location::RegisterLocation(EAX)); InvokeDexCallingConventionVisitor calling_convention_visitor; - for (size_t i = 0; i < invoke->InputCount(); i++) { + for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { HInstruction* input = invoke->InputAt(i); locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index f175283885..37b00c8d52 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1297,13 +1297,9 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type } void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { - // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation, but this step is not - // run in baseline. So we remove them manually here if we find them. - // TODO: Instead of this local workaround, address this properly. - if (invoke->IsStaticWithExplicitClinitCheck()) { - invoke->RemoveClinitCheckOrLoadClassAsLastInput(); - } + // When we do not run baseline, explicit clinit checks triggered by static + // invokes must have been pruned by art::PrepareForRegisterAllocation. + DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); IntrinsicLocationsBuilderX86_64 intrinsic(codegen_); if (intrinsic.TryDispatch(invoke)) { @@ -1323,9 +1319,9 @@ static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codeg } void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { - // Explicit clinit checks triggered by static invokes must have been - // pruned by art::PrepareForRegisterAllocation. - DCHECK(!invoke->IsStaticWithExplicitClinitCheck()); + // When we do not run baseline, explicit clinit checks triggered by static + // invokes must have been pruned by art::PrepareForRegisterAllocation. + DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); if (TryGenerateIntrinsicCode(invoke, codegen_)) { return; @@ -1343,7 +1339,7 @@ void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) { locations->AddTemp(Location::RegisterLocation(RDI)); InvokeDexCallingConventionVisitor calling_convention_visitor; - for (size_t i = 0; i < invoke->InputCount(); i++) { + for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { HInstruction* input = invoke->InputAt(i); locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); } diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 2df7c166d8..e79d4f4bdc 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -377,15 +377,42 @@ void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) { return; } - if ((input_cst != nullptr) && input_cst->IsMinusOne() && - (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) { + if ((input_cst != nullptr) && input_cst->IsMinusOne()) { // Replace code looking like // DIV dst, src, -1 // with // NEG dst, src instruction->GetBlock()->ReplaceAndRemoveInstructionWith( - instruction, (new (GetGraph()->GetArena()) HNeg(type, input_other))); + instruction, new (GetGraph()->GetArena()) HNeg(type, input_other)); RecordSimplification(); + return; + } + + if ((input_cst != nullptr) && Primitive::IsFloatingPointType(type)) { + // Try replacing code looking like + // DIV dst, src, constant + // with + // MUL dst, src, 1 / constant + HConstant* reciprocal = nullptr; + if (type == Primitive::Primitive::kPrimDouble) { + double value = input_cst->AsDoubleConstant()->GetValue(); + if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) { + reciprocal = GetGraph()->GetDoubleConstant(1.0 / value); + } + } else { + DCHECK_EQ(type, Primitive::kPrimFloat); + float value = input_cst->AsFloatConstant()->GetValue(); + if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) { + reciprocal = GetGraph()->GetFloatConstant(1.0f / value); + } + } + + if (reciprocal != nullptr) { + instruction->GetBlock()->ReplaceAndRemoveInstructionWith( + instruction, new (GetGraph()->GetArena()) HMul(type, input_other, reciprocal)); + RecordSimplification(); + return; + } } } diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 27d2d43e17..e3fa272d22 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -78,7 +78,7 @@ static void MoveFromReturnRegister(Location trg, Primitive::Type type, CodeGener } static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorARM* codegen) { - if (invoke->InputCount() == 0) { + if (invoke->GetNumberOfArguments() == 0) { // No argument to move. return; } @@ -90,7 +90,7 @@ static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorA // a parallel move resolver. HParallelMove parallel_move(arena); - for (size_t i = 0; i < invoke->InputCount(); i++) { + for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { HInstruction* input = invoke->InputAt(i); Location cc_loc = calling_convention_visitor.GetNextLocation(input->GetType()); Location actual_loc = locations->InAt(i); diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 4f008e7537..d71b49e6f1 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -87,7 +87,7 @@ static void MoveFromReturnRegister(Location trg, } static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorARM64* codegen) { - if (invoke->InputCount() == 0) { + if (invoke->GetNumberOfArguments() == 0) { // No argument to move. return; } @@ -99,7 +99,7 @@ static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorA // a parallel move resolver. HParallelMove parallel_move(arena); - for (size_t i = 0; i < invoke->InputCount(); i++) { + for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { HInstruction* input = invoke->InputAt(i); Location cc_loc = calling_convention_visitor.GetNextLocation(input->GetType()); Location actual_loc = locations->InAt(i); diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index b3e821cfbe..18fb3c4d43 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -112,7 +112,7 @@ static void MoveFromReturnRegister(Location target, } static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorX86* codegen) { - if (invoke->InputCount() == 0) { + if (invoke->GetNumberOfArguments() == 0) { // No argument to move. return; } @@ -124,7 +124,7 @@ static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorX // a parallel move resolver. HParallelMove parallel_move(arena); - for (size_t i = 0; i < invoke->InputCount(); i++) { + for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { HInstruction* input = invoke->InputAt(i); Location cc_loc = calling_convention_visitor.GetNextLocation(input->GetType()); Location actual_loc = locations->InAt(i); diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 5779b9cb9f..db7b58bc66 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -104,7 +104,7 @@ static void MoveFromReturnRegister(Location trg, } static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorX86_64* codegen) { - if (invoke->InputCount() == 0) { + if (invoke->GetNumberOfArguments() == 0) { // No argument to move. return; } @@ -116,7 +116,7 @@ static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorX // a parallel move resolver. HParallelMove parallel_move(arena); - for (size_t i = 0; i < invoke->InputCount(); i++) { + for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { HInstruction* input = invoke->InputAt(i); Location cc_loc = calling_convention_visitor.GetNextLocation(input->GetType()); Location actual_loc = locations->InAt(i); diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index e2eb46aabb..699987c05e 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -449,6 +449,20 @@ void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstructio instructions_.InsertInstructionBefore(instruction, cursor); } +void HBasicBlock::InsertInstructionAfter(HInstruction* instruction, HInstruction* cursor) { + DCHECK(!cursor->IsPhi()); + DCHECK(!instruction->IsPhi()); + DCHECK_EQ(instruction->GetId(), -1); + DCHECK_NE(cursor->GetId(), -1); + DCHECK_EQ(cursor->GetBlock(), this); + DCHECK(!instruction->IsControlFlow()); + DCHECK(!cursor->IsControlFlow()); + instruction->SetBlock(this); + instruction->SetId(GetGraph()->GetNextInstructionId()); + UpdateInputsUsers(instruction); + instructions_.InsertInstructionAfter(instruction, cursor); +} + void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) { DCHECK_EQ(phi->GetId(), -1); DCHECK_NE(cursor->GetId(), -1); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 9e8df04cfb..3fe23e1816 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -620,7 +620,9 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { void DisconnectAndDelete(); void AddInstruction(HInstruction* instruction); + // Insert `instruction` before/after an existing instruction `cursor`. void InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor); + void InsertInstructionAfter(HInstruction* instruction, HInstruction* cursor); // Replace instruction `initial` with `replacement` within this block. void ReplaceAndRemoveInstructionWith(HInstruction* initial, HInstruction* replacement); @@ -2230,6 +2232,12 @@ class HInvoke : public HInstruction { SetRawInputAt(index, argument); } + // Return the number of arguments. This number can be lower than + // the number of inputs returned by InputCount(), as some invoke + // instructions (e.g. HInvokeStaticOrDirect) can have non-argument + // inputs at the end of their list of inputs. + uint32_t GetNumberOfArguments() const { return number_of_arguments_; } + Primitive::Type GetType() const OVERRIDE { return return_type_; } uint32_t GetDexPc() const { return dex_pc_; } @@ -2249,16 +2257,19 @@ class HInvoke : public HInstruction { protected: HInvoke(ArenaAllocator* arena, uint32_t number_of_arguments, + uint32_t number_of_other_inputs, Primitive::Type return_type, uint32_t dex_pc, uint32_t dex_method_index) : HInstruction(SideEffects::All()), + number_of_arguments_(number_of_arguments), inputs_(arena, number_of_arguments), return_type_(return_type), dex_pc_(dex_pc), dex_method_index_(dex_method_index), intrinsic_(Intrinsics::kNone) { - inputs_.SetSize(number_of_arguments); + uint32_t number_of_inputs = number_of_arguments + number_of_other_inputs; + inputs_.SetSize(number_of_inputs); } const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE { return inputs_.Get(i); } @@ -2266,6 +2277,7 @@ class HInvoke : public HInstruction { inputs_.Put(index, input); } + uint32_t number_of_arguments_; GrowableArray<HUserRecord<HInstruction*> > inputs_; const Primitive::Type return_type_; const uint32_t dex_pc_; @@ -2296,7 +2308,12 @@ class HInvokeStaticOrDirect : public HInvoke { InvokeType original_invoke_type, InvokeType invoke_type, ClinitCheckRequirement clinit_check_requirement) - : HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index), + : HInvoke(arena, + number_of_arguments, + clinit_check_requirement == ClinitCheckRequirement::kExplicit ? 1u : 0u, + return_type, + dex_pc, + dex_method_index), original_invoke_type_(original_invoke_type), invoke_type_(invoke_type), is_recursive_(is_recursive), @@ -2322,15 +2339,16 @@ class HInvokeStaticOrDirect : public HInvoke { return GetInvokeType() == kStatic; } - // Remove the art::HClinitCheck or art::HLoadClass instruction as - // last input (only relevant for static calls with explicit clinit - // check). - void RemoveClinitCheckOrLoadClassAsLastInput() { + // Remove the art::HLoadClass instruction set as last input by + // art::PrepareForRegisterAllocation::VisitClinitCheck in lieu of + // the initial art::HClinitCheck instruction (only relevant for + // static calls with explicit clinit check). + void RemoveLoadClassAsLastInput() { DCHECK(IsStaticWithExplicitClinitCheck()); size_t last_input_index = InputCount() - 1; HInstruction* last_input = InputAt(last_input_index); DCHECK(last_input != nullptr); - DCHECK(last_input->IsClinitCheck() || last_input->IsLoadClass()) << last_input->DebugName(); + DCHECK(last_input->IsLoadClass()) << last_input->DebugName(); RemoveAsUserOfInput(last_input_index); inputs_.DeleteAt(last_input_index); clinit_check_requirement_ = ClinitCheckRequirement::kImplicit; @@ -2386,7 +2404,7 @@ class HInvokeVirtual : public HInvoke { uint32_t dex_pc, uint32_t dex_method_index, uint32_t vtable_index) - : HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index), + : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index), vtable_index_(vtable_index) {} bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { @@ -2412,7 +2430,7 @@ class HInvokeInterface : public HInvoke { uint32_t dex_pc, uint32_t dex_method_index, uint32_t imt_index) - : HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index), + : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index), imt_index_(imt_index) {} bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc index fa6b3c292c..78d11857c3 100644 --- a/compiler/optimizing/prepare_for_register_allocation.cc +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -91,7 +91,7 @@ void PrepareForRegisterAllocation::VisitInvokeStaticOrDirect(HInvokeStaticOrDire // previously) by the graph builder during the creation of the // static invoke instruction, but is no longer required at this // stage (i.e., after inlining has been performed). - invoke->RemoveClinitCheckOrLoadClassAsLastInput(); + invoke->RemoveLoadClassAsLastInput(); // If the load class instruction is no longer used, remove it from // the graph. |