diff options
| author | 2015-08-20 10:06:31 +0000 | |
|---|---|---|
| committer | 2015-08-20 10:06:31 +0000 | |
| commit | bffabfce093e26bffb9e820a8f6b45474d28787a (patch) | |
| tree | 49b3183cd1d25b6a5cfb31e0d16678deb023c1e8 /compiler/optimizing | |
| parent | 4d786026efaac41acf8278d1c87d842f7ce06fde (diff) | |
| parent | e418dda75998e0186f7580c2c54705767c3c8f1f (diff) | |
Merge "Be more flexible on the code unit size when inlining."
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/dead_code_elimination.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 62 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.h | 6 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 11 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 4 |
5 files changed, 58 insertions, 26 deletions
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc index 78470db834..50cbf5ca77 100644 --- a/compiler/optimizing/dead_code_elimination.cc +++ b/compiler/optimizing/dead_code_elimination.cc @@ -133,6 +133,7 @@ void HDeadCodeElimination::RemoveDeadInstructions() { && !inst->IsSuspendCheck() // If we added an explicit barrier then we should keep it. && !inst->IsMemoryBarrier() + && !inst->IsParameterValue() && !inst->HasUses()) { block->RemoveInstruction(inst); MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction); diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 202f3f074d..ff90f32754 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -40,6 +40,8 @@ namespace art { +static constexpr size_t kMaximumNumberOfHInstructions = 12; + void HInliner::Run() { if (graph_->IsDebuggable()) { // For simplicity, we currently never inline when the graph is debuggable. This avoids @@ -169,7 +171,7 @@ static uint32_t FindMethodIndexIn(ArtMethod* method, } } -bool HInliner::TryInline(HInvoke* invoke_instruction) const { +bool HInliner::TryInline(HInvoke* invoke_instruction) { uint32_t method_index = invoke_instruction->GetDexMethodIndex(); ScopedObjectAccess soa(Thread::Current()); const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); @@ -244,12 +246,6 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) const { return false; } - if (resolved_method->ShouldNotInline()) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) - << " was already flagged as non inlineable"; - return false; - } - if (invoke_instruction->IsInvokeStaticOrDirect() && invoke_instruction->AsInvokeStaticOrDirect()->IsStaticWithImplicitClinitCheck()) { // Case of a static method that cannot be inlined because it implicitly @@ -271,7 +267,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) const { bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, HInvoke* invoke_instruction, - bool same_dex_file) const { + bool same_dex_file) { ScopedObjectAccess soa(Thread::Current()); const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); const DexFile& callee_dex_file = *resolved_method->GetDexFile(); @@ -335,9 +331,6 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, if (!builder.BuildGraph(*code_item)) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be built, so cannot be inlined"; - // There could be multiple reasons why the graph could not be built, including - // unaccessible methods/fields due to using a different dex cache. We do not mark - // the method as non-inlineable so that other callers can still try to inline it. return false; } @@ -345,17 +338,41 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, compiler_driver_->GetInstructionSet())) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " cannot be inlined because of the register allocator"; - resolved_method->SetShouldNotInline(); return false; } if (!callee_graph->TryBuildingSsa()) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be transformed to SSA"; - resolved_method->SetShouldNotInline(); return false; } + size_t parameter_index = 0; + for (HInstructionIterator instructions(callee_graph->GetEntryBlock()->GetInstructions()); + !instructions.Done(); + instructions.Advance()) { + HInstruction* current = instructions.Current(); + if (current->IsParameterValue()) { + HInstruction* argument = invoke_instruction->InputAt(parameter_index++); + if (argument->IsNullConstant()) { + current->ReplaceWith(callee_graph->GetNullConstant()); + } else if (argument->IsIntConstant()) { + current->ReplaceWith(callee_graph->GetIntConstant(argument->AsIntConstant()->GetValue())); + } else if (argument->IsLongConstant()) { + current->ReplaceWith(callee_graph->GetLongConstant(argument->AsLongConstant()->GetValue())); + } else if (argument->IsFloatConstant()) { + current->ReplaceWith( + callee_graph->GetFloatConstant(argument->AsFloatConstant()->GetValue())); + } else if (argument->IsDoubleConstant()) { + current->ReplaceWith( + callee_graph->GetDoubleConstant(argument->AsDoubleConstant()->GetValue())); + } else if (argument->GetType() == Primitive::kPrimNot) { + current->SetReferenceTypeInfo(argument->GetReferenceTypeInfo()); + current->AsParameterValue()->SetCanBeNull(argument->CanBeNull()); + } + } + } + // Run simple optimizations on the graph. HDeadCodeElimination dce(callee_graph, stats_); HConstantFolding fold(callee_graph); @@ -365,10 +382,10 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, HOptimization* optimizations[] = { &intrinsics, - &dce, - &fold, &type_propagation, &simplify, + &dce, + &fold, }; for (size_t i = 0; i < arraysize(optimizations); ++i) { @@ -376,6 +393,7 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, optimization->Run(); } + size_t number_of_instructions_budget = kMaximumNumberOfHInstructions; if (depth_ + 1 < compiler_driver_->GetCompilerOptions().GetInlineDepthLimit()) { HInliner inliner(callee_graph, outer_compilation_unit_, @@ -385,6 +403,7 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, stats_, depth_ + 1); inliner.Run(); + number_of_instructions_budget += inliner.number_of_inlined_instructions_; } // TODO: We should abort only if all predecessors throw. However, @@ -394,7 +413,6 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, if (exit_block == nullptr) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because it has an infinite loop"; - resolved_method->SetShouldNotInline(); return false; } @@ -408,24 +426,28 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, if (has_throw_predecessor) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because one branch always throws"; - resolved_method->SetShouldNotInline(); return false; } HReversePostOrderIterator it(*callee_graph); it.Advance(); // Past the entry block, it does not contain instructions that prevent inlining. + size_t number_of_instructions = 0; for (; !it.Done(); it.Advance()) { HBasicBlock* block = it.Current(); if (block->IsLoopHeader()) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because it contains a loop"; - resolved_method->SetShouldNotInline(); return false; } for (HInstructionIterator instr_it(block->GetInstructions()); !instr_it.Done(); instr_it.Advance()) { + if (number_of_instructions++ == number_of_instructions_budget) { + VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + << " could not be inlined because it is too big."; + return false; + } HInstruction* current = instr_it.Current(); if (current->IsInvokeInterface()) { @@ -433,7 +455,6 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, // resolution conflict is currently too high. VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because it has an interface call."; - resolved_method->SetShouldNotInline(); return false; } @@ -448,12 +469,11 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because " << current->DebugName() << " it is in a different dex file and requires access to the dex cache"; - // Do not flag the method as not-inlineable. A caller within the same - // dex file could still successfully inline it. return false; } } } + number_of_inlined_instructions_ += number_of_instructions; HInstruction* return_replacement = callee_graph->InlineInto(graph_, invoke_instruction); diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index 9062e1ab00..bce5915219 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -42,6 +42,7 @@ class HInliner : public HOptimization { caller_compilation_unit_(caller_compilation_unit), compiler_driver_(compiler_driver), depth_(depth), + number_of_inlined_instructions_(0), handles_(handles) {} void Run() OVERRIDE; @@ -49,15 +50,16 @@ class HInliner : public HOptimization { static constexpr const char* kInlinerPassName = "inliner"; private: - bool TryInline(HInvoke* invoke_instruction) const; + bool TryInline(HInvoke* invoke_instruction); bool TryBuildAndInline(ArtMethod* resolved_method, HInvoke* invoke_instruction, - bool same_dex_file) const; + bool same_dex_file); const DexCompilationUnit& outer_compilation_unit_; const DexCompilationUnit& caller_compilation_unit_; CompilerDriver* const compiler_driver_; const size_t depth_; + size_t number_of_inlined_instructions_; StackHandleScopeCollection* const handles_; DISALLOW_COPY_AND_ASSIGN(HInliner); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 851dd4ff5e..f2db33086c 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -3775,11 +3775,15 @@ class HXor : public HBinaryOperation { class HParameterValue : public HExpression<0> { public: HParameterValue(uint8_t index, Primitive::Type parameter_type, bool is_this = false) - : HExpression(parameter_type, SideEffects::None()), index_(index), is_this_(is_this) {} + : HExpression(parameter_type, SideEffects::None()), + index_(index), + is_this_(is_this), + can_be_null_(!is_this) {} uint8_t GetIndex() const { return index_; } - bool CanBeNull() const OVERRIDE { return !is_this_; } + bool CanBeNull() const OVERRIDE { return can_be_null_; } + void SetCanBeNull(bool can_be_null) { can_be_null_ = can_be_null; } bool IsThis() const { return is_this_; } @@ -3793,6 +3797,8 @@ class HParameterValue : public HExpression<0> { // Whether or not the parameter value corresponds to 'this' argument. const bool is_this_; + bool can_be_null_; + DISALLOW_COPY_AND_ASSIGN(HParameterValue); }; @@ -4444,6 +4450,7 @@ class HLoadString : public HExpression<1> { // TODO: Can we deopt or debug when we resolve a string? bool NeedsEnvironment() const OVERRIDE { return false; } bool NeedsDexCache() const OVERRIDE { return true; } + bool CanBeNull() const OVERRIDE { return false; } static SideEffects SideEffectsForArchRuntimeCalls() { return SideEffects::CanTriggerGC(); diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 5d029488fd..45b3df008b 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -414,7 +414,9 @@ void RTPVisitor::VisitNewArray(HNewArray* instr) { } void RTPVisitor::VisitParameterValue(HParameterValue* instr) { - if (instr->GetType() == Primitive::kPrimNot) { + ScopedObjectAccess soa(Thread::Current()); + // We check if the existing type is valid: the inliner may have set it. + if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) { // TODO: parse the signature and add precise types for the parameters. SetClassAsTypeInfo(instr, nullptr, /* is_exact */ false); } |