diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/nodes.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 1 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 23 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.h | 10 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation_test.cc | 3 | ||||
| -rw-r--r-- | compiler/optimizing/select_generator.cc | 68 | ||||
| -rw-r--r-- | compiler/optimizing/select_generator.h | 27 |
8 files changed, 108 insertions, 32 deletions
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 508027e52a..1510eafa40 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -1751,6 +1751,10 @@ bool HBasicBlock::IsSingleGoto() const { return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsGoto(); } +bool HBasicBlock::IsSingleReturn() const { + return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsReturn(); +} + bool HBasicBlock::IsSingleTryBoundary() const { return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsTryBoundary(); } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 68d6c2ebbc..f60d532c37 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -959,6 +959,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> { } bool IsSingleGoto() const; + bool IsSingleReturn() const; bool IsSingleTryBoundary() const; // Returns true if this block emits nothing but a jump. diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 426a1691f5..e98c97cf9a 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -489,7 +489,7 @@ static HOptimization* BuildOptimization( } else if (opt_name == HSharpening::kSharpeningPassName) { return new (arena) HSharpening(graph, codegen, dex_compilation_unit, driver, handles); } else if (opt_name == HSelectGenerator::kSelectGeneratorPassName) { - return new (arena) HSelectGenerator(graph, stats); + return new (arena) HSelectGenerator(graph, handles, stats); } else if (opt_name == HInductionVarAnalysis::kInductionPassName) { return new (arena) HInductionVarAnalysis(graph); } else if (opt_name == InstructionSimplifier::kInstructionSimplifierPassName) { @@ -758,7 +758,7 @@ void OptimizingCompiler::RunOptimizations(HGraph* graph, HConstantFolding* fold1 = new (arena) HConstantFolding(graph, "constant_folding"); InstructionSimplifier* simplify1 = new (arena) InstructionSimplifier( graph, codegen, driver, stats); - HSelectGenerator* select_generator = new (arena) HSelectGenerator(graph, stats); + HSelectGenerator* select_generator = new (arena) HSelectGenerator(graph, handles, stats); HConstantFolding* fold2 = new (arena) HConstantFolding( graph, "constant_folding$after_inlining"); HConstantFolding* fold3 = new (arena) HConstantFolding(graph, "constant_folding$after_bce"); diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 561c9eafa2..93613a5542 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -754,8 +754,23 @@ void ReferenceTypePropagation::VisitPhi(HPhi* phi) { } } +void ReferenceTypePropagation::FixUpInstructionType(HInstruction* instruction, + VariableSizedHandleScope* handle_scope) { + if (instruction->IsSelect()) { + ScopedObjectAccess soa(Thread::Current()); + HandleCache handle_cache(handle_scope); + HSelect* select = instruction->AsSelect(); + ReferenceTypeInfo false_rti = select->GetFalseValue()->GetReferenceTypeInfo(); + ReferenceTypeInfo true_rti = select->GetTrueValue()->GetReferenceTypeInfo(); + select->SetReferenceTypeInfo(MergeTypes(false_rti, true_rti, &handle_cache)); + } else { + LOG(FATAL) << "Invalid instruction in FixUpInstructionType"; + } +} + ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a, - const ReferenceTypeInfo& b) { + const ReferenceTypeInfo& b, + HandleCache* handle_cache) { if (!b.IsValid()) { return a; } @@ -780,7 +795,7 @@ ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& is_exact = false; } else if (!a_is_interface && !b_is_interface) { result_type_handle = - handle_cache_.NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle)); + handle_cache->NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle)); is_exact = false; } else { // This can happen if: @@ -790,7 +805,7 @@ ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& // void foo(Interface i, boolean cond) { // Object o = cond ? i : new Object(); // } - result_type_handle = handle_cache_.GetObjectClassHandle(); + result_type_handle = handle_cache->GetObjectClassHandle(); is_exact = false; } @@ -916,7 +931,7 @@ void ReferenceTypePropagation::UpdatePhi(HPhi* instr) { if (inputs[i]->IsNullConstant()) { continue; } - new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo()); + new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo(), &handle_cache_); if (new_rti.IsValid() && new_rti.IsObjectClass()) { if (!new_rti.IsExact()) { break; diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h index b19f473e27..c221282b9b 100644 --- a/compiler/optimizing/reference_type_propagation.h +++ b/compiler/optimizing/reference_type_propagation.h @@ -54,6 +54,12 @@ class ReferenceTypePropagation : public HOptimization { static constexpr const char* kReferenceTypePropagationPassName = "reference_type_propagation"; + // Fix the reference type for an instruction whose inputs have changed. + // For a select instruction, the reference types of the inputs are merged + // and the resulting reference type is set on the select instruction. + static void FixUpInstructionType(HInstruction* instruction, + VariableSizedHandleScope* handle_scope); + private: class HandleCache { public: @@ -101,7 +107,9 @@ class ReferenceTypePropagation : public HOptimization { static void UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) REQUIRES_SHARED(Locks::mutator_lock_); - ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a, const ReferenceTypeInfo& b) + static ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a, + const ReferenceTypeInfo& b, + HandleCache* handle_cache) REQUIRES_SHARED(Locks::mutator_lock_); void ValidateTypes(); diff --git a/compiler/optimizing/reference_type_propagation_test.cc b/compiler/optimizing/reference_type_propagation_test.cc index d537459113..cb2af91d87 100644 --- a/compiler/optimizing/reference_type_propagation_test.cc +++ b/compiler/optimizing/reference_type_propagation_test.cc @@ -49,7 +49,7 @@ class ReferenceTypePropagationTest : public CommonCompilerTest { // Relay method to merge type in reference type propagation. ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a, const ReferenceTypeInfo& b) REQUIRES_SHARED(Locks::mutator_lock_) { - return propagation_->MergeTypes(a, b); + return propagation_->MergeTypes(a, b, &propagation_->handle_cache_); } // Helper method to construct an invalid type. @@ -163,4 +163,3 @@ TEST_F(ReferenceTypePropagationTest, MergeValidTypes) { } } // namespace art - diff --git a/compiler/optimizing/select_generator.cc b/compiler/optimizing/select_generator.cc index cb7ade915f..e220d32344 100644 --- a/compiler/optimizing/select_generator.cc +++ b/compiler/optimizing/select_generator.cc @@ -20,9 +20,16 @@ namespace art { static constexpr size_t kMaxInstructionsInBranch = 1u; -// Returns true if `block` has only one predecessor, ends with a Goto and -// contains at most `kMaxInstructionsInBranch` other movable instruction with -// no side-effects. +HSelectGenerator::HSelectGenerator(HGraph* graph, + VariableSizedHandleScope* handles, + OptimizingCompilerStats* stats) + : HOptimization(graph, kSelectGeneratorPassName, stats), + handle_scope_(handles) { +} + +// Returns true if `block` has only one predecessor, ends with a Goto +// or a Return and contains at most `kMaxInstructionsInBranch` other +// movable instruction with no side-effects. static bool IsSimpleBlock(HBasicBlock* block) { if (block->GetPredecessors().size() != 1u) { return false; @@ -33,7 +40,10 @@ static bool IsSimpleBlock(HBasicBlock* block) { for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { HInstruction* instruction = it.Current(); if (instruction->IsControlFlow()) { - return instruction->IsGoto() && num_instructions <= kMaxInstructionsInBranch; + if (num_instructions > kMaxInstructionsInBranch) { + return false; + } + return instruction->IsGoto() || instruction->IsReturn(); } else if (instruction->CanBeMoved() && !instruction->HasSideEffects()) { num_instructions++; } else { @@ -45,8 +55,8 @@ static bool IsSimpleBlock(HBasicBlock* block) { UNREACHABLE(); } -// Returns true if 'block1' and 'block2' are empty, merge into the same single -// successor and the successor can only be reached from them. +// Returns true if 'block1' and 'block2' are empty and merge into the +// same single successor. static bool BlocksMergeTogether(HBasicBlock* block1, HBasicBlock* block2) { return block1->GetSingleSuccessor() == block2->GetSingleSuccessor(); } @@ -94,48 +104,68 @@ void HSelectGenerator::Run() { // If the branches are not empty, move instructions in front of the If. // TODO(dbrazdil): This puts an instruction between If and its condition. // Implement moving of conditions to first users if possible. - if (!true_block->IsSingleGoto()) { + if (!true_block->IsSingleGoto() && !true_block->IsSingleReturn()) { true_block->GetFirstInstruction()->MoveBefore(if_instruction); } - if (!false_block->IsSingleGoto()) { + if (!false_block->IsSingleGoto() && !false_block->IsSingleReturn()) { false_block->GetFirstInstruction()->MoveBefore(if_instruction); } - DCHECK(true_block->IsSingleGoto()); - DCHECK(false_block->IsSingleGoto()); + DCHECK(true_block->IsSingleGoto() || true_block->IsSingleReturn()); + DCHECK(false_block->IsSingleGoto() || false_block->IsSingleReturn()); // Find the resulting true/false values. size_t predecessor_index_true = merge_block->GetPredecessorIndexOf(true_block); size_t predecessor_index_false = merge_block->GetPredecessorIndexOf(false_block); DCHECK_NE(predecessor_index_true, predecessor_index_false); + bool both_successors_return = true_block->IsSingleReturn() && false_block->IsSingleReturn(); HPhi* phi = GetSingleChangedPhi(merge_block, predecessor_index_true, predecessor_index_false); - if (phi == nullptr) { + + HInstruction* true_value = nullptr; + HInstruction* false_value = nullptr; + if (both_successors_return) { + true_value = true_block->GetFirstInstruction()->InputAt(0); + false_value = false_block->GetFirstInstruction()->InputAt(0); + } else if (phi != nullptr) { + true_value = phi->InputAt(predecessor_index_true); + false_value = phi->InputAt(predecessor_index_false); + } else { continue; } - HInstruction* true_value = phi->InputAt(predecessor_index_true); - HInstruction* false_value = phi->InputAt(predecessor_index_false); + DCHECK(both_successors_return || phi != nullptr); // Create the Select instruction and insert it in front of the If. HSelect* select = new (graph_->GetArena()) HSelect(if_instruction->InputAt(0), true_value, false_value, if_instruction->GetDexPc()); - if (phi->GetType() == Primitive::kPrimNot) { + if (both_successors_return) { + if (true_value->GetType() == Primitive::kPrimNot) { + DCHECK(false_value->GetType() == Primitive::kPrimNot); + ReferenceTypePropagation::FixUpInstructionType(select, handle_scope_); + } + } else if (phi->GetType() == Primitive::kPrimNot) { select->SetReferenceTypeInfo(phi->GetReferenceTypeInfo()); } block->InsertInstructionBefore(select, if_instruction); - // Remove the true branch which removes the corresponding Phi input. - // If left only with the false branch, the Phi is automatically removed. - phi->ReplaceInput(select, predecessor_index_false); + // Remove the true branch which removes the corresponding Phi + // input if needed. If left only with the false branch, the Phi is + // automatically removed. + if (both_successors_return) { + false_block->GetFirstInstruction()->ReplaceInput(select, 0); + } else { + phi->ReplaceInput(select, predecessor_index_false); + } + bool only_two_predecessors = (merge_block->GetPredecessors().size() == 2u); true_block->DisconnectAndDelete(); - DCHECK_EQ(only_two_predecessors, phi->GetBlock() == nullptr); // Merge remaining blocks which are now connected with Goto. DCHECK_EQ(block->GetSingleSuccessor(), false_block); block->MergeWith(false_block); - if (only_two_predecessors) { + if (!both_successors_return && only_two_predecessors) { + DCHECK_EQ(only_two_predecessors, phi->GetBlock() == nullptr); DCHECK_EQ(block->GetSingleSuccessor(), merge_block); block->MergeWith(merge_block); } diff --git a/compiler/optimizing/select_generator.h b/compiler/optimizing/select_generator.h index c6dca581cc..c060146478 100644 --- a/compiler/optimizing/select_generator.h +++ b/compiler/optimizing/select_generator.h @@ -18,7 +18,7 @@ * This optimization recognizes the common diamond selection pattern and * replaces it with an instance of the HSelect instruction. * - * Recognized pattern: + * Recognized patterns: * * If [ Condition ] * / \ @@ -26,14 +26,30 @@ * \ / * Phi [FalseValue, TrueValue] * + * and + * + * If [ Condition ] + * / \ + * false branch true branch + * return FalseValue return TrueValue + * * The pattern will be simplified if `true_branch` and `false_branch` each * contain at most one instruction without any side effects. * - * Blocks are merged into one and Select replaces the If and the Phi: + * Blocks are merged into one and Select replaces the If and the Phi. + * + * For the first pattern it simplifies to: + * * true branch * false branch * Select [FalseValue, TrueValue, Condition] * + * For the second pattern it simplifies to: + * + * true branch + * false branch + * return Select [FalseValue, TrueValue, Condition] + * * Note: In order to recognize no side-effect blocks, this optimization must be * run after the instruction simplifier has removed redundant suspend checks. */ @@ -42,19 +58,22 @@ #define ART_COMPILER_OPTIMIZING_SELECT_GENERATOR_H_ #include "optimization.h" +#include "reference_type_propagation.h" namespace art { class HSelectGenerator : public HOptimization { public: - HSelectGenerator(HGraph* graph, OptimizingCompilerStats* stats) - : HOptimization(graph, kSelectGeneratorPassName, stats) {} + HSelectGenerator(HGraph* graph, + VariableSizedHandleScope* handles, + OptimizingCompilerStats* stats); void Run() OVERRIDE; static constexpr const char* kSelectGeneratorPassName = "select_generator"; private: + VariableSizedHandleScope* handle_scope_; DISALLOW_COPY_AND_ASSIGN(HSelectGenerator); }; |