diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/boolean_simplifier.cc | 131 | ||||
| -rw-r--r-- | compiler/optimizing/boolean_simplifier.h | 74 | ||||
| -rw-r--r-- | compiler/optimizing/builder.cc | 38 | ||||
| -rw-r--r-- | compiler/optimizing/builder.h | 9 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator.cc | 20 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator.h | 6 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 29 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 35 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 36 | ||||
| -rw-r--r-- | compiler/optimizing/codegen_test.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/graph_checker.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 26 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.h | 3 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.cc | 138 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 88 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 8 | ||||
| -rw-r--r-- | compiler/optimizing/register_allocator_test.cc | 6 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_builder.cc | 8 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.cc | 4 |
20 files changed, 545 insertions, 121 deletions
diff --git a/compiler/optimizing/boolean_simplifier.cc b/compiler/optimizing/boolean_simplifier.cc new file mode 100644 index 0000000000..0ecc0d7433 --- /dev/null +++ b/compiler/optimizing/boolean_simplifier.cc @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "boolean_simplifier.h" + +namespace art { + +// Returns true if 'block1' and 'block2' are empty, merge into the same single +// successor and the successor can only be reached from them. +static bool BlocksDoMergeTogether(HBasicBlock* block1, HBasicBlock* block2) { + if (!block1->IsSingleGoto() || !block2->IsSingleGoto()) return false; + HBasicBlock* succ1 = block1->GetSuccessors().Get(0); + HBasicBlock* succ2 = block2->GetSuccessors().Get(0); + return succ1 == succ2 && succ1->GetPredecessors().Size() == 2u; +} + +// Returns true if the outcome of the branching matches the boolean value of +// the branching condition. +static bool PreservesCondition(HInstruction* input_true, HInstruction* input_false) { + return input_true->IsIntConstant() && input_true->AsIntConstant()->IsOne() + && input_false->IsIntConstant() && input_false->AsIntConstant()->IsZero(); +} + +// Returns true if the outcome of the branching is exactly opposite of the +// boolean value of the branching condition. +static bool NegatesCondition(HInstruction* input_true, HInstruction* input_false) { + return input_true->IsIntConstant() && input_true->AsIntConstant()->IsZero() + && input_false->IsIntConstant() && input_false->AsIntConstant()->IsOne(); +} + +// Returns an instruction with the opposite boolean value from 'cond'. +static HInstruction* GetOppositeCondition(HInstruction* cond) { + HGraph* graph = cond->GetBlock()->GetGraph(); + ArenaAllocator* allocator = graph->GetArena(); + + if (cond->IsCondition()) { + HInstruction* lhs = cond->InputAt(0); + HInstruction* rhs = cond->InputAt(1); + if (cond->IsEqual()) { + return new (allocator) HNotEqual(lhs, rhs); + } else if (cond->IsNotEqual()) { + return new (allocator) HEqual(lhs, rhs); + } else if (cond->IsLessThan()) { + return new (allocator) HGreaterThanOrEqual(lhs, rhs); + } else if (cond->IsLessThanOrEqual()) { + return new (allocator) HGreaterThan(lhs, rhs); + } else if (cond->IsGreaterThan()) { + return new (allocator) HLessThanOrEqual(lhs, rhs); + } else if (cond->IsGreaterThanOrEqual()) { + return new (allocator) HLessThan(lhs, rhs); + } + } else if (cond->IsIntConstant()) { + HIntConstant* int_const = cond->AsIntConstant(); + if (int_const->IsZero()) { + return graph->GetIntConstant1(); + } else { + DCHECK(int_const->IsOne()); + return graph->GetIntConstant0(); + } + } + + LOG(FATAL) << "Instruction " << cond->DebugName() << " used as a condition"; + UNREACHABLE(); +} + +void HBooleanSimplifier::Run() { + // Iterate in post order in the unlikely case that removing one occurrence of + // the pattern empties a branch block of another occurrence. Otherwise the + // order does not matter. + for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) { + HBasicBlock* block = it.Current(); + if (!block->EndsWithIf()) continue; + + // Find elements of the pattern. + HIf* if_instruction = block->GetLastInstruction()->AsIf(); + HBasicBlock* true_block = if_instruction->IfTrueSuccessor(); + HBasicBlock* false_block = if_instruction->IfFalseSuccessor(); + if (!BlocksDoMergeTogether(true_block, false_block)) { + continue; + } + HBasicBlock* merge_block = true_block->GetSuccessors().Get(0); + if (!merge_block->HasSinglePhi()) { + continue; + } + HPhi* phi = merge_block->GetFirstPhi()->AsPhi(); + HInstruction* true_value = phi->InputAt(merge_block->GetPredecessorIndexOf(true_block)); + HInstruction* false_value = phi->InputAt(merge_block->GetPredecessorIndexOf(false_block)); + + // Check if the selection negates/preserves the value of the condition and + // if so, generate a suitable replacement instruction. + HInstruction* if_condition = if_instruction->InputAt(0); + HInstruction* replacement; + if (NegatesCondition(true_value, false_value)) { + replacement = GetOppositeCondition(if_condition); + if (replacement->GetBlock() == nullptr) { + block->InsertInstructionBefore(replacement, if_instruction); + } + } else if (PreservesCondition(true_value, false_value)) { + replacement = if_condition; + } else { + continue; + } + + // Replace the selection outcome with the new instruction. + phi->ReplaceWith(replacement); + merge_block->RemovePhi(phi); + + // Link the start/end blocks and remove empty branches. + graph_->MergeEmptyBranches(block, merge_block); + + // Remove the original condition if it is now unused. + if (!if_condition->HasUses()) { + if_condition->GetBlock()->RemoveInstruction(if_condition); + } + } +} + +} // namespace art diff --git a/compiler/optimizing/boolean_simplifier.h b/compiler/optimizing/boolean_simplifier.h new file mode 100644 index 0000000000..a88733e1af --- /dev/null +++ b/compiler/optimizing/boolean_simplifier.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This optimization recognizes a common pattern where a boolean value is +// either cast to an integer or negated by selecting from zero/one integer +// constants with an If statement. Because boolean values are internally +// represented as zero/one, we can safely replace the pattern with a suitable +// condition instruction. + +// Example: Negating a boolean value +// B1: +// z1 ParameterValue +// i2 IntConstant 0 +// i3 IntConstant 1 +// v4 Goto B2 +// B2: +// z5 NotEquals [ z1 i2 ] +// v6 If [ z5 ] then B3 else B4 +// B3: +// v7 Goto B5 +// B4: +// v8 Goto B5 +// B5: +// i9 Phi [ i3 i2 ] +// v10 Return [ i9 ] +// turns into +// B1: +// z1 ParameterValue +// i2 IntConstant 0 +// v4 Goto B2 +// B2: +// z11 Equals [ z1 i2 ] +// v10 Return [ z11 ] +// B3, B4, B5: removed + +// Note: in order to recognize empty blocks, this optimization must be run +// after the instruction simplifier has removed redundant suspend checks. + +#ifndef ART_COMPILER_OPTIMIZING_BOOLEAN_SIMPLIFIER_H_ +#define ART_COMPILER_OPTIMIZING_BOOLEAN_SIMPLIFIER_H_ + +#include "optimization.h" + +namespace art { + +class HBooleanSimplifier : public HOptimization { + public: + explicit HBooleanSimplifier(HGraph* graph) + : HOptimization(graph, true, kBooleanSimplifierPassName) {} + + void Run() OVERRIDE; + + static constexpr const char* kBooleanSimplifierPassName = "boolean_simplifier"; + + private: + DISALLOW_COPY_AND_ASSIGN(HBooleanSimplifier); +}; + +} // namespace art + +#endif // ART_COMPILER_OPTIMIZING_BOOLEAN_SIMPLIFIER_H_ diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index cbb41b1837..a21c311d90 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -616,8 +616,8 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, DCHECK((optimized_invoke_type == invoke_type) || (optimized_invoke_type != kDirect) || compiler_driver_->GetCompilerOptions().GetCompilePic()); bool is_recursive = - (target_method.dex_method_index == dex_compilation_unit_->GetDexMethodIndex()); - DCHECK(!is_recursive || (target_method.dex_file == dex_compilation_unit_->GetDexFile())); + (target_method.dex_method_index == outer_compilation_unit_->GetDexMethodIndex()); + DCHECK(!is_recursive || (target_method.dex_file == outer_compilation_unit_->GetDexFile())); invoke = new (arena_) HInvokeStaticOrDirect( arena_, number_of_arguments, return_type, dex_pc, target_method.dex_method_index, is_recursive, optimized_invoke_type); @@ -711,7 +711,7 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, uint16_t field_index = instruction.VRegB_21c(); ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<5> hs(soa.Self()); + StackHandleScope<4> hs(soa.Self()); Handle<mirror::DexCache> dex_cache(hs.NewHandle( dex_compilation_unit_->GetClassLinker()->FindDexCache(*dex_compilation_unit_->GetDexFile()))); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( @@ -724,10 +724,8 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, return false; } - Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle( - outer_compilation_unit_->GetClassLinker()->FindDexCache(*outer_compilation_unit_->GetDexFile()))); Handle<mirror::Class> referrer_class(hs.NewHandle(compiler_driver_->ResolveCompilingMethodsClass( - soa, outer_dex_cache, class_loader, outer_compilation_unit_))); + soa, dex_cache, class_loader, outer_compilation_unit_))); // The index at which the field's class is stored in the DexCache's type array. uint32_t storage_index; @@ -740,7 +738,7 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, // TODO: find out why this check is needed. bool is_in_dex_cache = compiler_driver_->CanAssumeTypeIsPresentInDexCache( - *dex_compilation_unit_->GetDexFile(), storage_index); + *outer_compilation_unit_->GetDexFile(), storage_index); bool is_initialized = resolved_field->GetDeclaringClass()->IsInitialized() && is_in_dex_cache; bool is_referrer_class = (referrer_class.Get() == resolved_field->GetDeclaringClass()); @@ -2060,31 +2058,13 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 return true; } // NOLINT(readability/fn_size) -HIntConstant* HGraphBuilder::GetIntConstant0() { - if (constant0_ != nullptr) { - return constant0_; - } - constant0_ = new(arena_) HIntConstant(0); - entry_block_->AddInstruction(constant0_); - return constant0_; -} - -HIntConstant* HGraphBuilder::GetIntConstant1() { - if (constant1_ != nullptr) { - return constant1_; - } - constant1_ = new(arena_) HIntConstant(1); - entry_block_->AddInstruction(constant1_); - return constant1_; -} - HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) { switch (constant) { - case 0: return GetIntConstant0(); - case 1: return GetIntConstant1(); + case 0: return graph_->GetIntConstant0(); + case 1: return graph_->GetIntConstant1(); default: { HIntConstant* instruction = new (arena_) HIntConstant(constant); - entry_block_->AddInstruction(instruction); + graph_->AddConstant(instruction); return instruction; } } @@ -2092,7 +2072,7 @@ HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) { HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) { HLongConstant* instruction = new (arena_) HLongConstant(constant); - entry_block_->AddInstruction(instruction); + graph_->AddConstant(instruction); return instruction; } diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 96196de588..c70170bb46 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -47,8 +47,6 @@ class HGraphBuilder : public ValueObject { exit_block_(nullptr), current_block_(nullptr), graph_(graph), - constant0_(nullptr), - constant1_(nullptr), dex_file_(dex_file), dex_compilation_unit_(dex_compilation_unit), compiler_driver_(driver), @@ -67,8 +65,6 @@ class HGraphBuilder : public ValueObject { exit_block_(nullptr), current_block_(nullptr), graph_(graph), - constant0_(nullptr), - constant1_(nullptr), dex_file_(nullptr), dex_compilation_unit_(nullptr), compiler_driver_(nullptr), @@ -100,8 +96,6 @@ class HGraphBuilder : public ValueObject { void MaybeUpdateCurrentBlock(size_t index); HBasicBlock* FindBlockStartingAt(int32_t index) const; - HIntConstant* GetIntConstant0(); - HIntConstant* GetIntConstant1(); HIntConstant* GetIntConstant(int32_t constant); HLongConstant* GetLongConstant(int64_t constant); void InitializeLocals(uint16_t count); @@ -253,9 +247,6 @@ class HGraphBuilder : public ValueObject { HBasicBlock* current_block_; HGraph* const graph_; - HIntConstant* constant0_; - HIntConstant* constant1_; - // The dex file where the method being compiled is. const DexFile* const dex_file_; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 561dcb7315..bd6e943bf0 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -40,16 +40,6 @@ size_t CodeGenerator::GetCacheOffset(uint32_t index) { return mirror::ObjectArray<mirror::Object>::OffsetOfElement(index).SizeValue(); } -static bool IsSingleGoto(HBasicBlock* block) { - HLoopInformation* loop_info = block->GetLoopInformation(); - // TODO: Remove the null check b/19084197. - return (block->GetFirstInstruction() != nullptr) - && (block->GetFirstInstruction() == block->GetLastInstruction()) - && block->GetLastInstruction()->IsGoto() - // Back edges generate the suspend check. - && (loop_info == nullptr || !loop_info->IsBackEdge(block)); -} - void CodeGenerator::CompileBaseline(CodeAllocator* allocator, bool is_leaf) { Initialize(); if (!is_leaf) { @@ -74,7 +64,7 @@ bool CodeGenerator::GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) con HBasicBlock* CodeGenerator::GetNextBlockToEmit() const { for (size_t i = current_block_index_ + 1; i < block_order_->Size(); ++i) { HBasicBlock* block = block_order_->Get(i); - if (!IsSingleGoto(block)) { + if (!block->IsSingleGoto()) { return block; } } @@ -82,7 +72,7 @@ HBasicBlock* CodeGenerator::GetNextBlockToEmit() const { } HBasicBlock* CodeGenerator::FirstNonEmptyBlock(HBasicBlock* block) const { - while (IsSingleGoto(block)) { + while (block->IsSingleGoto()) { block = block->GetSuccessors().Get(0); } return block; @@ -97,7 +87,7 @@ void CodeGenerator::CompileInternal(CodeAllocator* allocator, bool is_baseline) // Don't generate code for an empty block. Its predecessors will branch to its successor // directly. Also, the label of that block will not be emitted, so this helps catch // errors where we reference that label. - if (IsSingleGoto(block)) continue; + if (block->IsSingleGoto()) continue; Bind(block); for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { HInstruction* current = it.Current(); @@ -628,7 +618,7 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, ++i, DexRegisterLocation::Kind::kConstant, High32Bits(value)); DCHECK_LT(i, environment_size); } else if (current->IsDoubleConstant()) { - int64_t value = bit_cast<double, int64_t>(current->AsDoubleConstant()->GetValue()); + int64_t value = bit_cast<int64_t, double>(current->AsDoubleConstant()->GetValue()); stack_map_stream_.AddDexRegisterEntry( i, DexRegisterLocation::Kind::kConstant, Low32Bits(value)); stack_map_stream_.AddDexRegisterEntry( @@ -641,7 +631,7 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, 0); } else { DCHECK(current->IsFloatConstant()) << current->DebugName(); - int32_t value = bit_cast<float, int32_t>(current->AsFloatConstant()->GetValue()); + int32_t value = bit_cast<int32_t, float>(current->AsFloatConstant()->GetValue()); stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, value); } break; diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index ecaa6f0123..07ca6b1ccf 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -271,7 +271,7 @@ class CodeGenerator { return 0; } else { DCHECK(constant->IsFloatConstant()); - return bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue()); + return bit_cast<int32_t, float>(constant->AsFloatConstant()->GetValue()); } } @@ -281,12 +281,12 @@ class CodeGenerator { } else if (constant->IsNullConstant()) { return 0; } else if (constant->IsFloatConstant()) { - return bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue()); + return bit_cast<int32_t, float>(constant->AsFloatConstant()->GetValue()); } else if (constant->IsLongConstant()) { return constant->AsLongConstant()->GetValue(); } else { DCHECK(constant->IsDoubleConstant()); - return bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue()); + return bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue()); } } diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 0a069a75ef..5a79a692d1 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -883,7 +883,7 @@ void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) { HInstruction* previous = got->GetPrevious(); HLoopInformation* info = block->GetLoopInformation(); - if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) { + if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; @@ -1388,9 +1388,14 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind); + // The Java language does not allow treating boolean as an integral type but + // our bit representation makes it safe. + switch (result_type) { case Primitive::kPrimByte: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1407,6 +1412,8 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimShort: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1451,6 +1458,8 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimLong: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1487,6 +1496,8 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimChar: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1503,6 +1514,8 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimFloat: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1536,6 +1549,8 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimDouble: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1582,6 +1597,8 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio switch (result_type) { case Primitive::kPrimByte: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1597,6 +1614,8 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimShort: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1654,6 +1673,8 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimLong: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1692,6 +1713,8 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimChar: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1707,6 +1730,8 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimFloat: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1773,6 +1798,8 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimDouble: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 99283a0056..9455a918d4 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -1621,7 +1621,7 @@ void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) { HInstruction* previous = got->GetPrevious(); HLoopInformation* info = block->GetLoopInformation(); - if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) { + if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 02b9b3294c..4414a65efa 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -680,7 +680,7 @@ void CodeGeneratorX86::Move64(Location destination, Location source) { value = constant->AsLongConstant()->GetValue(); } else { DCHECK(constant->IsDoubleConstant()); - value = bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue()); + value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue()); } __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value))); __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value))); @@ -792,7 +792,7 @@ void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) { HInstruction* previous = got->GetPrevious(); HLoopInformation* info = block->GetLoopInformation(); - if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) { + if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; @@ -1370,9 +1370,14 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind); + // The Java language does not allow treating boolean as an integral type but + // our bit representation makes it safe. + switch (result_type) { case Primitive::kPrimByte: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1391,6 +1396,8 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimShort: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1435,6 +1442,8 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimLong: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1464,6 +1473,8 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimChar: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1480,6 +1491,8 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimFloat: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1511,6 +1524,8 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimDouble: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1556,6 +1571,8 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio switch (result_type) { case Primitive::kPrimByte: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1577,6 +1594,8 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimShort: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1672,6 +1691,8 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimLong: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1703,6 +1724,8 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimChar: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1726,6 +1749,8 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimFloat: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1783,6 +1808,8 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimDouble: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -3665,7 +3692,7 @@ void ParallelMoveResolverX86::EmitMove(size_t index) { } } else if (constant->IsFloatConstant()) { float fp_value = constant->AsFloatConstant()->GetValue(); - int32_t value = bit_cast<float, int32_t>(fp_value); + int32_t value = bit_cast<int32_t, float>(fp_value); Immediate imm(value); if (destination.IsFpuRegister()) { XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); @@ -3699,7 +3726,7 @@ void ParallelMoveResolverX86::EmitMove(size_t index) { } else { DCHECK(constant->IsDoubleConstant()); double dbl_value = constant->AsDoubleConstant()->GetValue(); - int64_t value = bit_cast<double, int64_t>(dbl_value); + int64_t value = bit_cast<int64_t, double>(dbl_value); int32_t low_value = Low32Bits(value); int32_t high_value = High32Bits(value); Immediate low(low_value); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index d09c8f8e51..c1f601e6d4 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -625,7 +625,7 @@ void CodeGeneratorX86_64::Move(Location destination, Location source) { HConstant* constant = source.GetConstant(); int64_t value = constant->AsLongConstant()->GetValue(); if (constant->IsDoubleConstant()) { - value = bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue()); + value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue()); } else { DCHECK(constant->IsLongConstant()); value = constant->AsLongConstant()->GetValue(); @@ -729,7 +729,7 @@ void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) { HInstruction* previous = got->GetPrevious(); HLoopInformation* info = block->GetLoopInformation(); - if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) { + if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; @@ -1409,9 +1409,15 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); DCHECK_NE(result_type, input_type); + + // The Java language does not allow treating boolean as an integral type but + // our bit representation makes it safe. + switch (result_type) { case Primitive::kPrimByte: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1428,6 +1434,8 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimShort: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1472,6 +1480,8 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimLong: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1505,6 +1515,8 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimChar: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1521,6 +1533,8 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimFloat: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1550,6 +1564,8 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimDouble: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1593,6 +1609,8 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver switch (result_type) { case Primitive::kPrimByte: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1617,6 +1635,8 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver case Primitive::kPrimShort: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimInt: case Primitive::kPrimChar: @@ -1715,6 +1735,8 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver case Primitive::kPrimLong: switch (input_type) { DCHECK(out.IsRegister()); + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1782,6 +1804,8 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver case Primitive::kPrimChar: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1806,6 +1830,8 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver case Primitive::kPrimFloat: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -1832,6 +1858,8 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver case Primitive::kPrimDouble: switch (input_type) { + case Primitive::kPrimBoolean: + // Boolean input is a result of code transformations. case Primitive::kPrimByte: case Primitive::kPrimShort: case Primitive::kPrimInt: @@ -3344,7 +3372,7 @@ void ParallelMoveResolverX86_64::EmitMove(size_t index) { } } else if (constant->IsFloatConstant()) { float fp_value = constant->AsFloatConstant()->GetValue(); - int32_t value = bit_cast<float, int32_t>(fp_value); + int32_t value = bit_cast<int32_t, float>(fp_value); Immediate imm(value); if (destination.IsFpuRegister()) { XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); @@ -3362,7 +3390,7 @@ void ParallelMoveResolverX86_64::EmitMove(size_t index) { } else { DCHECK(constant->IsDoubleConstant()) << constant->DebugName(); double fp_value = constant->AsDoubleConstant()->GetValue(); - int64_t value = bit_cast<double, int64_t>(fp_value); + int64_t value = bit_cast<int64_t, double>(fp_value); Immediate imm(value); if (destination.IsFpuRegister()) { XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index 868fc5b867..40f0adc63d 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -145,6 +145,7 @@ static void RunCodeOptimized(CodeGenerator* codegen, std::function<void(HGraph*)> hook_before_codegen, bool has_result, Expected expected) { + graph->BuildDominatorTree(); SsaLivenessAnalysis liveness(*graph, codegen); liveness.Analyze(); diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index 76b9f4fe7e..09a3ae431f 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -227,13 +227,13 @@ void SSAChecker::CheckLoop(HBasicBlock* loop_header) { } else { HLoopInformation* loop_information = loop_header->GetLoopInformation(); HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0); - if (loop_information->IsBackEdge(first_predecessor)) { + if (loop_information->IsBackEdge(*first_predecessor)) { AddError(StringPrintf( "First predecessor of loop header %d is a back edge.", id)); } HBasicBlock* second_predecessor = loop_header->GetPredecessors().Get(1); - if (!loop_information->IsBackEdge(second_predecessor)) { + if (!loop_information->IsBackEdge(*second_predecessor)) { AddError(StringPrintf( "Second predecessor of loop header %d is not a back edge.", id)); diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 82d63573bc..968fe3e73c 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -85,9 +85,11 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, return false; } - bool can_use_dex_cache = true; if (resolved_method->GetDexFile()->GetLocation().compare(outer_dex_file.GetLocation()) != 0) { - can_use_dex_cache = false; + VLOG(compiler) << "Did not inline " + << PrettyMethod(method_index, outer_dex_file) + << " because it is in a different dex file"; + return false; } const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); @@ -122,7 +124,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, return false; } - if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index, can_use_dex_cache)) { + if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index)) { resolved_method->SetShouldNotInline(); return false; } @@ -134,8 +136,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, HInvoke* invoke_instruction, - uint32_t method_index, - bool can_use_dex_cache) const { + uint32_t method_index) const { ScopedObjectAccess soa(Thread::Current()); const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile(); @@ -144,10 +145,10 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, nullptr, outer_compilation_unit_.GetClassLoader(), outer_compilation_unit_.GetClassLinker(), - *resolved_method->GetDexFile(), + outer_dex_file, code_item, resolved_method->GetDeclaringClass()->GetDexClassDefIndex(), - resolved_method->GetDexMethodIndex(), + method_index, resolved_method->GetAccessFlags(), nullptr); @@ -158,7 +159,7 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, HGraphBuilder builder(callee_graph, &dex_compilation_unit, &outer_compilation_unit_, - resolved_method->GetDexFile(), + &outer_dex_file, compiler_driver_, &inline_stats); @@ -199,7 +200,7 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, if (depth_ + 1 < kDepthLimit) { HInliner inliner( - callee_graph, dex_compilation_unit, compiler_driver_, stats_, depth_ + 1); + callee_graph, outer_compilation_unit_, compiler_driver_, stats_, depth_ + 1); inliner.Run(); } @@ -234,13 +235,6 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, << " needs an environment"; return false; } - - if (!can_use_dex_cache && current->NeedsDexCache()) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file) - << " could not be inlined because " << current->DebugName() - << " it is in a different dex file and requires access to the dex cache"; - return false; - } } } diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index 4b7e2ff213..1251977138 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -48,8 +48,7 @@ class HInliner : public HOptimization { bool TryInline(HInvoke* invoke_instruction, uint32_t method_index, InvokeType invoke_type) const; bool TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, HInvoke* invoke_instruction, - uint32_t method_index, - bool can_use_dex_cache) const; + uint32_t method_index) const; const DexCompilationUnit& outer_compilation_unit_; CompilerDriver* const compiler_driver_; diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index a90ebced69..4f6565d315 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -185,7 +185,7 @@ void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) { if (successor->IsLoopHeader()) { // If we split at a back edge boundary, make the new block the back edge. HLoopInformation* info = successor->GetLoopInformation(); - if (info->IsBackEdge(block)) { + if (info->IsBackEdge(*block)) { info->RemoveBackEdge(block); info->AddBackEdge(new_block); } @@ -287,19 +287,49 @@ bool HGraph::AnalyzeNaturalLoops() const { return true; } +void HGraph::AddConstant(HConstant* instruction) { + HInstruction* last_instruction = entry_block_->GetLastInstruction(); + if (last_instruction == nullptr || !last_instruction->IsControlFlow()) { + // Called from the builder. Insert at the end of the block. + entry_block_->AddInstruction(instruction); + } else { + // Entry block ends with control-flow. Insert before the last instruction. + entry_block_->InsertInstructionBefore(instruction, last_instruction); + } +} + HNullConstant* HGraph::GetNullConstant() { if (cached_null_constant_ == nullptr) { cached_null_constant_ = new (arena_) HNullConstant(); - entry_block_->InsertInstructionBefore(cached_null_constant_, - entry_block_->GetLastInstruction()); + AddConstant(cached_null_constant_); } return cached_null_constant_; } +HIntConstant* HGraph::GetIntConstant0() { + if (cached_int_constant0_ == nullptr) { + cached_int_constant0_ = new (arena_) HIntConstant(0); + AddConstant(cached_int_constant0_); + } + return cached_int_constant0_; +} + +HIntConstant* HGraph::GetIntConstant1() { + if (cached_int_constant1_ == nullptr) { + cached_int_constant1_ = new (arena_) HIntConstant(1); + AddConstant(cached_int_constant1_); + } + return cached_int_constant1_; +} + void HLoopInformation::Add(HBasicBlock* block) { blocks_.SetBit(block->GetBlockId()); } +void HLoopInformation::Remove(HBasicBlock* block) { + blocks_.ClearBit(block->GetBlockId()); +} + void HLoopInformation::PopulateRecursive(HBasicBlock* block) { if (blocks_.IsBitSet(block->GetBlockId())) { return; @@ -621,7 +651,10 @@ FOR_EACH_INSTRUCTION(DEFINE_ACCEPT) void HGraphVisitor::VisitInsertionOrder() { const GrowableArray<HBasicBlock*>& blocks = graph_->GetBlocks(); for (size_t i = 0 ; i < blocks.Size(); i++) { - VisitBasicBlock(blocks.Get(i)); + HBasicBlock* block = blocks.Get(i); + if (block != nullptr) { + VisitBasicBlock(block); + } } } @@ -788,6 +821,25 @@ HBasicBlock* HBasicBlock::SplitAfter(HInstruction* cursor) { return new_block; } +bool HBasicBlock::IsSingleGoto() const { + HLoopInformation* loop_info = GetLoopInformation(); + // TODO: Remove the null check b/19084197. + return GetFirstInstruction() != nullptr + && GetPhis().IsEmpty() + && GetFirstInstruction() == GetLastInstruction() + && GetLastInstruction()->IsGoto() + // Back edges generate the suspend check. + && (loop_info == nullptr || !loop_info->IsBackEdge(*this)); +} + +bool HBasicBlock::EndsWithIf() const { + return !GetInstructions().IsEmpty() && GetLastInstruction()->IsIf(); +} + +bool HBasicBlock::HasSinglePhi() const { + return !GetPhis().IsEmpty() && GetFirstPhi()->GetNext() == nullptr; +} + void HInstructionList::SetBlockOfInstructions(HBasicBlock* block) const { for (HInstruction* current = first_instruction_; current != nullptr; @@ -811,14 +863,35 @@ void HInstructionList::AddAfter(HInstruction* cursor, const HInstructionList& in } void HInstructionList::Add(const HInstructionList& instruction_list) { - DCHECK(!IsEmpty()); - AddAfter(last_instruction_, instruction_list); + if (IsEmpty()) { + first_instruction_ = instruction_list.first_instruction_; + last_instruction_ = instruction_list.last_instruction_; + } else { + AddAfter(last_instruction_, instruction_list); + } +} + +void HBasicBlock::DisconnectFromAll() { + DCHECK(dominated_blocks_.IsEmpty()) << "Unimplemented scenario"; + + for (size_t i = 0, e = predecessors_.Size(); i < e; ++i) { + predecessors_.Get(i)->successors_.Delete(this); + } + for (size_t i = 0, e = successors_.Size(); i < e; ++i) { + successors_.Get(i)->predecessors_.Delete(this); + } + dominator_->dominated_blocks_.Delete(this); + + predecessors_.Reset(); + successors_.Reset(); + dominator_ = nullptr; + graph_ = nullptr; } void HBasicBlock::MergeWith(HBasicBlock* other) { DCHECK(successors_.IsEmpty()) << "Unimplemented block merge scenario"; - DCHECK(dominated_blocks_.IsEmpty()) << "Unimplemented block merge scenario"; - DCHECK(other->GetDominator()->IsEntryBlock() && other->GetGraph() != graph_) + DCHECK(dominated_blocks_.IsEmpty() + || (dominated_blocks_.Size() == 1 && dominated_blocks_.Get(0) == other)) << "Unimplemented block merge scenario"; DCHECK(other->GetPhis().IsEmpty()); @@ -1006,7 +1079,7 @@ void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { if (info != nullptr) { info->Add(to); to->SetLoopInformation(info); - if (info->IsBackEdge(at)) { + if (info->IsBackEdge(*at)) { // Only `at` can become a back edge, as the inlined blocks // are predecessors of `at`. DCHECK_EQ(1u, info->NumberOfBackEdges()); @@ -1020,6 +1093,53 @@ void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { invoke->GetBlock()->RemoveInstruction(invoke); } +void HGraph::MergeEmptyBranches(HBasicBlock* start_block, HBasicBlock* end_block) { + // Find the two branches of an If. + DCHECK_EQ(start_block->GetSuccessors().Size(), 2u); + HBasicBlock* left_branch = start_block->GetSuccessors().Get(0); + HBasicBlock* right_branch = start_block->GetSuccessors().Get(1); + + // Make sure this is a diamond control-flow path. + DCHECK_EQ(left_branch->GetSuccessors().Get(0), end_block); + DCHECK_EQ(right_branch->GetSuccessors().Get(0), end_block); + DCHECK_EQ(end_block->GetPredecessors().Size(), 2u); + DCHECK_EQ(start_block, end_block->GetDominator()); + + // Disconnect the branches and merge the two blocks. This will move + // all instructions from 'end_block' to 'start_block'. + DCHECK(left_branch->IsSingleGoto()); + DCHECK(right_branch->IsSingleGoto()); + left_branch->DisconnectFromAll(); + right_branch->DisconnectFromAll(); + start_block->RemoveInstruction(start_block->GetLastInstruction()); + start_block->MergeWith(end_block); + + // Delete the now redundant blocks from the graph. + blocks_.Put(left_branch->GetBlockId(), nullptr); + blocks_.Put(right_branch->GetBlockId(), nullptr); + blocks_.Put(end_block->GetBlockId(), nullptr); + + // Update reverse post order. + reverse_post_order_.Delete(left_branch); + reverse_post_order_.Delete(right_branch); + reverse_post_order_.Delete(end_block); + + // Update loops which contain the code. + for (HLoopInformationOutwardIterator it(*start_block); !it.Done(); it.Advance()) { + HLoopInformation* loop_info = it.Current(); + DCHECK(loop_info->Contains(*left_branch)); + DCHECK(loop_info->Contains(*right_branch)); + DCHECK(loop_info->Contains(*end_block)); + loop_info->Remove(left_branch); + loop_info->Remove(right_branch); + loop_info->Remove(end_block); + if (loop_info->IsBackEdge(*end_block)) { + loop_info->RemoveBackEdge(end_block); + loop_info->AddBackEdge(start_block); + } + } +} + std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs) { ScopedObjectAccess soa(Thread::Current()); os << "[" diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 07ff8ba010..664cf18ad7 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -128,6 +128,7 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { void SetExitBlock(HBasicBlock* block) { exit_block_ = block; } void AddBlock(HBasicBlock* block); + void AddConstant(HConstant* instruction); // Try building the SSA form of this graph, with dominance computation and loop // recognition. Returns whether it was successful in doing all these steps. @@ -154,6 +155,8 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { // Inline this graph in `outer_graph`, replacing the given `invoke` instruction. void InlineInto(HGraph* outer_graph, HInvoke* invoke); + void MergeEmptyBranches(HBasicBlock* start_block, HBasicBlock* end_block); + void SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor); void SimplifyLoop(HBasicBlock* header); @@ -217,6 +220,8 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { bool IsDebuggable() const { return debuggable_; } HNullConstant* GetNullConstant(); + HIntConstant* GetIntConstant0(); + HIntConstant* GetIntConstant1(); private: HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const; @@ -267,6 +272,10 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { // Cached null constant that might be created when building SSA form. HNullConstant* cached_null_constant_; + // Cached common constants often needed by optimization passes. + HIntConstant* cached_int_constant0_; + HIntConstant* cached_int_constant1_; + ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1); DISALLOW_COPY_AND_ASSIGN(HGraph); }; @@ -300,9 +309,9 @@ class HLoopInformation : public ArenaObject<kArenaAllocMisc> { back_edges_.Delete(back_edge); } - bool IsBackEdge(HBasicBlock* block) { + bool IsBackEdge(const HBasicBlock& block) const { for (size_t i = 0, e = back_edges_.Size(); i < e; ++i) { - if (back_edges_.Get(i) == block) return true; + if (back_edges_.Get(i) == &block) return true; } return false; } @@ -336,6 +345,7 @@ class HLoopInformation : public ArenaObject<kArenaAllocMisc> { const ArenaBitVector& GetBlocks() const { return blocks_; } void Add(HBasicBlock* block); + void Remove(HBasicBlock* block); private: // Internal recursive implementation of `Populate`. @@ -391,6 +401,8 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { return graph_->GetExitBlock() == this; } + bool IsSingleGoto() const; + void AddBackEdge(HBasicBlock* back_edge) { if (loop_information_ == nullptr) { loop_information_ = new (graph_->GetArena()) HLoopInformation(this, graph_); @@ -512,8 +524,16 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { // of `this` are moved to `other`. // Note that this method does not update the graph, reverse post order, loop // information, nor make sure the blocks are consistent (for example ending + // with a control flow instruction). void ReplaceWith(HBasicBlock* other); + // Disconnects `this` from all its predecessors, successors and the dominator. + // It assumes that `this` does not dominate any blocks. + // Note that this method does not update the graph, reverse post order, loop + // information, nor make sure the blocks are consistent (for example ending + // with a control flow instruction). + void DisconnectFromAll(); + void AddInstruction(HInstruction* instruction); void InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor); // Replace instruction `initial` with `replacement` within this block. @@ -582,6 +602,9 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { bool IsCatchBlock() const { return is_catch_block_; } void SetIsCatchBlock() { is_catch_block_ = true; } + bool EndsWithIf() const; + bool HasSinglePhi() const; + private: HGraph* graph_; GrowableArray<HBasicBlock*> predecessors_; @@ -604,6 +627,31 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { DISALLOW_COPY_AND_ASSIGN(HBasicBlock); }; +// Iterates over the LoopInformation of all loops which contain 'block' +// from the innermost to the outermost. +class HLoopInformationOutwardIterator : public ValueObject { + public: + explicit HLoopInformationOutwardIterator(const HBasicBlock& block) + : current_(block.GetLoopInformation()) {} + + bool Done() const { return current_ == nullptr; } + + void Advance() { + DCHECK(!Done()); + current_ = current_->GetHeader()->GetDominator()->GetLoopInformation(); + } + + HLoopInformation* Current() const { + DCHECK(!Done()); + return current_; + } + + private: + HLoopInformation* current_; + + DISALLOW_COPY_AND_ASSIGN(HLoopInformationOutwardIterator); +}; + #define FOR_EACH_CONCRETE_INSTRUCTION(M) \ M(Add, BinaryOperation) \ M(And, BinaryOperation) \ @@ -1200,8 +1248,6 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { return NeedsEnvironment() || IsLoadClass() || IsLoadString(); } - virtual bool NeedsDexCache() const { return false; } - protected: virtual const HUserRecord<HInstruction*> InputRecordAt(size_t i) const = 0; virtual void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) = 0; @@ -1875,20 +1921,22 @@ class HFloatConstant : public HConstant { float GetValue() const { return value_; } bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - return bit_cast<float, int32_t>(other->AsFloatConstant()->value_) == - bit_cast<float, int32_t>(value_); + return bit_cast<uint32_t, float>(other->AsFloatConstant()->value_) == + bit_cast<uint32_t, float>(value_); } size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); } bool IsMinusOne() const OVERRIDE { - return bit_cast<uint32_t>(AsFloatConstant()->GetValue()) == bit_cast<uint32_t>((-1.0f)); + return bit_cast<uint32_t, float>(AsFloatConstant()->GetValue()) == + bit_cast<uint32_t, float>((-1.0f)); } bool IsZero() const OVERRIDE { return AsFloatConstant()->GetValue() == 0.0f; } bool IsOne() const OVERRIDE { - return bit_cast<uint32_t>(AsFloatConstant()->GetValue()) == bit_cast<uint32_t>(1.0f); + return bit_cast<uint32_t, float>(AsFloatConstant()->GetValue()) == + bit_cast<uint32_t, float>(1.0f); } DECLARE_INSTRUCTION(FloatConstant); @@ -1906,20 +1954,22 @@ class HDoubleConstant : public HConstant { double GetValue() const { return value_; } bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - return bit_cast<double, int64_t>(other->AsDoubleConstant()->value_) == - bit_cast<double, int64_t>(value_); + return bit_cast<uint64_t, double>(other->AsDoubleConstant()->value_) == + bit_cast<uint64_t, double>(value_); } size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); } bool IsMinusOne() const OVERRIDE { - return bit_cast<uint64_t>(AsDoubleConstant()->GetValue()) == bit_cast<uint64_t>((-1.0)); + return bit_cast<uint64_t, double>(AsDoubleConstant()->GetValue()) == + bit_cast<uint64_t, double>((-1.0)); } bool IsZero() const OVERRIDE { return AsDoubleConstant()->GetValue() == 0.0; } bool IsOne() const OVERRIDE { - return bit_cast<uint64_t>(AsDoubleConstant()->GetValue()) == bit_cast<uint64_t>(1.0); + return bit_cast<uint64_t, double>(AsDoubleConstant()->GetValue()) == + bit_cast<uint64_t, double>(1.0); } DECLARE_INSTRUCTION(DoubleConstant); @@ -2092,7 +2142,6 @@ class HInvokeStaticOrDirect : public HInvoke { InvokeType GetInvokeType() const { return invoke_type_; } bool IsRecursive() const { return is_recursive_; } - bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); } DECLARE_INSTRUCTION(InvokeStaticOrDirect); @@ -2975,8 +3024,6 @@ class HLoadClass : public HExpression<0> { return loaded_class_rti_.IsExact(); } - bool NeedsDexCache() const OVERRIDE { return !is_referrers_class_; } - DECLARE_INSTRUCTION(LoadClass); private: @@ -3012,7 +3059,6 @@ class HLoadString : public HExpression<0> { // TODO: Can we deopt or debug when we resolve a string? bool NeedsEnvironment() const OVERRIDE { return false; } - bool NeedsDexCache() const OVERRIDE { return true; } DECLARE_INSTRUCTION(LoadString); @@ -3465,7 +3511,10 @@ class HInsertionOrderIterator : public ValueObject { class HReversePostOrderIterator : public ValueObject { public: - explicit HReversePostOrderIterator(const HGraph& graph) : graph_(graph), index_(0) {} + explicit HReversePostOrderIterator(const HGraph& graph) : graph_(graph), index_(0) { + // Check that reverse post order of the graph has been built. + DCHECK(!graph.GetReversePostOrder().IsEmpty()); + } bool Done() const { return index_ == graph_.GetReversePostOrder().Size(); } HBasicBlock* Current() const { return graph_.GetReversePostOrder().Get(index_); } @@ -3481,7 +3530,10 @@ class HReversePostOrderIterator : public ValueObject { class HPostOrderIterator : public ValueObject { public: explicit HPostOrderIterator(const HGraph& graph) - : graph_(graph), index_(graph_.GetReversePostOrder().Size()) {} + : graph_(graph), index_(graph_.GetReversePostOrder().Size()) { + // Check that reverse post order of the graph has been built. + DCHECK(!graph.GetReversePostOrder().IsEmpty()); + } bool Done() const { return index_ == 0; } HBasicBlock* Current() const { return graph_.GetReversePostOrder().Get(index_ - 1); } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 933a8a005c..eaa30df4f1 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -22,6 +22,7 @@ #include "base/arena_allocator.h" #include "base/dumpable.h" #include "base/timing_logger.h" +#include "boolean_simplifier.h" #include "bounds_check_elimination.h" #include "builder.h" #include "code_generator.h" @@ -313,6 +314,7 @@ static void RunOptimizations(HGraph* graph, HDeadCodeElimination dce(graph); HConstantFolding fold1(graph); InstructionSimplifier simplify1(graph, stats); + HBooleanSimplifier boolean_not(graph); HInliner inliner(graph, dex_compilation_unit, driver, stats); @@ -331,6 +333,9 @@ static void RunOptimizations(HGraph* graph, &dce, &fold1, &simplify1, + // BooleanSimplifier depends on the InstructionSimplifier removing redundant + // suspend checks to recognize empty blocks. + &boolean_not, &inliner, &fold2, &side_effects, @@ -477,8 +482,7 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite class_def_idx, method_idx, access_flags, compiler_driver->GetVerifiedMethod(&dex_file, method_idx)); - ArenaPool pool; - ArenaAllocator arena(&pool); + ArenaAllocator arena(Runtime::Current()->GetArenaPool()); HGraph* graph = new (&arena) HGraph( &arena, compiler_driver->GetCompilerOptions().GetDebuggable()); diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc index b757a3b9b9..7a2d84b056 100644 --- a/compiler/optimizing/register_allocator_test.cc +++ b/compiler/optimizing/register_allocator_test.cc @@ -596,6 +596,8 @@ static HGraph* BuildFieldReturn(ArenaAllocator* allocator, graph->AddBlock(exit); block->AddSuccessor(exit); exit->AddInstruction(new (allocator) HExit()); + + graph->BuildDominatorTree(); return graph; } @@ -658,6 +660,8 @@ static HGraph* BuildTwoSubs(ArenaAllocator* allocator, block->AddInstruction(*second_sub); block->AddInstruction(new (allocator) HExit()); + + graph->BuildDominatorTree(); return graph; } @@ -719,6 +723,8 @@ static HGraph* BuildDiv(ArenaAllocator* allocator, block->AddInstruction(*div); block->AddInstruction(new (allocator) HExit()); + + graph->BuildDominatorTree(); return graph; } diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index ba11e90d9c..ae6bf16f77 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -359,12 +359,12 @@ static HFloatConstant* GetFloatEquivalent(HIntConstant* constant) { if (result == nullptr) { HGraph* graph = constant->GetBlock()->GetGraph(); ArenaAllocator* allocator = graph->GetArena(); - result = new (allocator) HFloatConstant(bit_cast<int32_t, float>(constant->GetValue())); + result = new (allocator) HFloatConstant(bit_cast<float, int32_t>(constant->GetValue())); constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext()); } else { // If there is already a constant with the expected type, we know it is // the floating point equivalent of this constant. - DCHECK_EQ((bit_cast<float, int32_t>(result->GetValue())), constant->GetValue()); + DCHECK_EQ((bit_cast<int32_t, float>(result->GetValue())), constant->GetValue()); } return result; } @@ -381,12 +381,12 @@ static HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant) { if (result == nullptr) { HGraph* graph = constant->GetBlock()->GetGraph(); ArenaAllocator* allocator = graph->GetArena(); - result = new (allocator) HDoubleConstant(bit_cast<int64_t, double>(constant->GetValue())); + result = new (allocator) HDoubleConstant(bit_cast<double, int64_t>(constant->GetValue())); constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext()); } else { // If there is already a constant with the expected type, we know it is // the floating point equivalent of this constant. - DCHECK_EQ((bit_cast<double, int64_t>(result->GetValue())), constant->GetValue()); + DCHECK_EQ((bit_cast<int64_t, double>(result->GetValue())), constant->GetValue()); } return result; } diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc index c0d6f42ca5..56ccd717cf 100644 --- a/compiler/optimizing/ssa_liveness_analysis.cc +++ b/compiler/optimizing/ssa_liveness_analysis.cc @@ -71,8 +71,8 @@ void SsaLivenessAnalysis::LinearizeGraph() { // for it. GrowableArray<uint32_t> forward_predecessors(graph_.GetArena(), graph_.GetBlocks().Size()); forward_predecessors.SetSize(graph_.GetBlocks().Size()); - for (size_t i = 0, e = graph_.GetBlocks().Size(); i < e; ++i) { - HBasicBlock* block = graph_.GetBlocks().Get(i); + for (HReversePostOrderIterator it(graph_); !it.Done(); it.Advance()) { + HBasicBlock* block = it.Current(); size_t number_of_forward_predecessors = block->GetPredecessors().Size(); if (block->IsLoopHeader()) { // We rely on having simplified the CFG. |