summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/boolean_simplifier.cc131
-rw-r--r--compiler/optimizing/boolean_simplifier.h74
-rw-r--r--compiler/optimizing/builder.cc38
-rw-r--r--compiler/optimizing/builder.h9
-rw-r--r--compiler/optimizing/code_generator.cc20
-rw-r--r--compiler/optimizing/code_generator.h6
-rw-r--r--compiler/optimizing/code_generator_arm.cc29
-rw-r--r--compiler/optimizing/code_generator_arm64.cc2
-rw-r--r--compiler/optimizing/code_generator_x86.cc35
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc36
-rw-r--r--compiler/optimizing/codegen_test.cc1
-rw-r--r--compiler/optimizing/graph_checker.cc4
-rw-r--r--compiler/optimizing/inliner.cc26
-rw-r--r--compiler/optimizing/inliner.h3
-rw-r--r--compiler/optimizing/nodes.cc138
-rw-r--r--compiler/optimizing/nodes.h88
-rw-r--r--compiler/optimizing/optimizing_compiler.cc8
-rw-r--r--compiler/optimizing/register_allocator_test.cc6
-rw-r--r--compiler/optimizing/ssa_builder.cc8
-rw-r--r--compiler/optimizing/ssa_liveness_analysis.cc4
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.