summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/code_generator.cc4
-rw-r--r--compiler/optimizing/constant_folding.h6
-rw-r--r--compiler/optimizing/constant_folding_test.cc5
-rw-r--r--compiler/optimizing/dead_code_elimination.h6
-rw-r--r--compiler/optimizing/dead_code_elimination_test.cc3
-rw-r--r--compiler/optimizing/gvn.h10
-rw-r--r--compiler/optimizing/instruction_simplifier.cc19
-rw-r--r--compiler/optimizing/instruction_simplifier.h13
-rw-r--r--compiler/optimizing/locations.h8
-rw-r--r--compiler/optimizing/optimization.cc6
-rw-r--r--compiler/optimizing/optimization.h13
-rw-r--r--compiler/optimizing/optimizing_compiler.cc29
-rw-r--r--compiler/optimizing/register_allocator.cc34
-rw-r--r--compiler/optimizing/ssa_phi_elimination.h17
14 files changed, 100 insertions, 73 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 4d71cb780a..0b593275c7 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -589,12 +589,14 @@ void CodeGenerator::SaveLiveRegisters(LocationSummary* locations) {
if (locations->RegisterContainsObject(i)) {
locations->SetStackBit(stack_offset / kVRegSize);
}
+ DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
stack_offset += SaveCoreRegister(stack_offset, i);
}
}
for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) {
if (register_set->ContainsFloatingPointRegister(i)) {
+ DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
stack_offset += SaveFloatingPointRegister(stack_offset, i);
}
}
@@ -605,12 +607,14 @@ void CodeGenerator::RestoreLiveRegisters(LocationSummary* locations) {
size_t stack_offset = first_register_slot_in_slow_path_;
for (size_t i = 0, e = GetNumberOfCoreRegisters(); i < e; ++i) {
if (register_set->ContainsCoreRegister(i)) {
+ DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
stack_offset += RestoreCoreRegister(stack_offset, i);
}
}
for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) {
if (register_set->ContainsFloatingPointRegister(i)) {
+ DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
stack_offset += RestoreFloatingPointRegister(stack_offset, i);
}
}
diff --git a/compiler/optimizing/constant_folding.h b/compiler/optimizing/constant_folding.h
index d2acfa6973..ac00824e33 100644
--- a/compiler/optimizing/constant_folding.h
+++ b/compiler/optimizing/constant_folding.h
@@ -32,10 +32,10 @@ namespace art {
*/
class HConstantFolding : public HOptimization {
public:
- HConstantFolding(HGraph* graph, const HGraphVisualizer& visualizer)
- : HOptimization(graph, true, kConstantFoldingPassName, visualizer) {}
+ explicit HConstantFolding(HGraph* graph)
+ : HOptimization(graph, true, kConstantFoldingPassName) {}
- virtual void Run() OVERRIDE;
+ void Run() OVERRIDE;
static constexpr const char* kConstantFoldingPassName = "constant_folding";
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index 856c5165a3..a56b9d9a12 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -47,8 +47,7 @@ static void TestCode(const uint16_t* data,
ASSERT_EQ(expected_before, actual_before);
x86::CodeGeneratorX86 codegen(graph);
- HGraphVisualizer visualizer(nullptr, graph, codegen, "");
- HConstantFolding(graph, visualizer).Run();
+ HConstantFolding(graph).Run();
SSAChecker ssa_checker(&allocator, graph);
ssa_checker.Run();
ASSERT_TRUE(ssa_checker.IsValid());
@@ -60,7 +59,7 @@ static void TestCode(const uint16_t* data,
check_after_cf(graph);
- HDeadCodeElimination(graph, visualizer).Run();
+ HDeadCodeElimination(graph).Run();
ssa_checker.Run();
ASSERT_TRUE(ssa_checker.IsValid());
diff --git a/compiler/optimizing/dead_code_elimination.h b/compiler/optimizing/dead_code_elimination.h
index a4446ae04d..3db2c3ff3f 100644
--- a/compiler/optimizing/dead_code_elimination.h
+++ b/compiler/optimizing/dead_code_elimination.h
@@ -28,10 +28,10 @@ namespace art {
*/
class HDeadCodeElimination : public HOptimization {
public:
- HDeadCodeElimination(HGraph* graph, const HGraphVisualizer& visualizer)
- : HOptimization(graph, true, kDeadCodeEliminationPassName, visualizer) {}
+ explicit HDeadCodeElimination(HGraph* graph)
+ : HOptimization(graph, true, kDeadCodeEliminationPassName) {}
- virtual void Run() OVERRIDE;
+ void Run() OVERRIDE;
static constexpr const char* kDeadCodeEliminationPassName =
"dead_code_elimination";
diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc
index 0c6807482a..5d4b9cb024 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -41,8 +41,7 @@ static void TestCode(const uint16_t* data,
ASSERT_EQ(actual_before, expected_before);
x86::CodeGeneratorX86 codegen(graph);
- HGraphVisualizer visualizer(nullptr, graph, codegen, "");
- HDeadCodeElimination(graph, visualizer).Run();
+ HDeadCodeElimination(graph).Run();
SSAChecker ssa_checker(&allocator, graph);
ssa_checker.Run();
ASSERT_TRUE(ssa_checker.IsValid());
diff --git a/compiler/optimizing/gvn.h b/compiler/optimizing/gvn.h
index 8d2c77475c..a841d5f65a 100644
--- a/compiler/optimizing/gvn.h
+++ b/compiler/optimizing/gvn.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_OPTIMIZING_GVN_H_
#include "nodes.h"
+#include "optimization.h"
namespace art {
@@ -165,11 +166,11 @@ class ValueSet : public ArenaObject<kArenaAllocMisc> {
/**
* Optimization phase that removes redundant instruction.
*/
-class GlobalValueNumberer : public ValueObject {
+class GlobalValueNumberer : public HOptimization {
public:
GlobalValueNumberer(ArenaAllocator* allocator, HGraph* graph)
- : allocator_(allocator),
- graph_(graph),
+ : HOptimization(graph, true, "GVN"),
+ allocator_(allocator),
block_effects_(allocator, graph->GetBlocks().Size()),
loop_effects_(allocator, graph->GetBlocks().Size()),
sets_(allocator, graph->GetBlocks().Size()),
@@ -186,7 +187,7 @@ class GlobalValueNumberer : public ValueObject {
}
}
- void Run();
+ void Run() OVERRIDE;
private:
// Per-block GVN. Will also update the ValueSet of the dominated and
@@ -202,7 +203,6 @@ class GlobalValueNumberer : public ValueObject {
SideEffects GetBlockEffects(HBasicBlock* block) const;
ArenaAllocator* const allocator_;
- HGraph* const graph_;
// Side effects of individual blocks, that is the union of the side effects
// of the instructions in the block.
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 3e8361eca1..3d65e9a0a4 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -18,11 +18,22 @@
namespace art {
+class InstructionSimplifierVisitor : public HGraphVisitor {
+ public:
+ explicit InstructionSimplifierVisitor(HGraph* graph) : HGraphVisitor(graph) {}
+
+ private:
+ void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
+ void VisitEqual(HEqual* equal) OVERRIDE;
+ void VisitArraySet(HArraySet* equal) OVERRIDE;
+};
+
void InstructionSimplifier::Run() {
- VisitInsertionOrder();
+ InstructionSimplifierVisitor visitor(graph_);
+ visitor.VisitInsertionOrder();
}
-void InstructionSimplifier::VisitSuspendCheck(HSuspendCheck* check) {
+void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
HBasicBlock* block = check->GetBlock();
// Currently always keep the suspend check at entry.
if (block->IsEntryBlock()) return;
@@ -38,7 +49,7 @@ void InstructionSimplifier::VisitSuspendCheck(HSuspendCheck* check) {
block->RemoveInstruction(check);
}
-void InstructionSimplifier::VisitEqual(HEqual* equal) {
+void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
HInstruction* input1 = equal->InputAt(0);
HInstruction* input2 = equal->InputAt(1);
if (input1->GetType() == Primitive::kPrimBoolean && input2->IsIntConstant()) {
@@ -55,7 +66,7 @@ void InstructionSimplifier::VisitEqual(HEqual* equal) {
}
}
-void InstructionSimplifier::VisitArraySet(HArraySet* instruction) {
+void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
HInstruction* value = instruction->GetValue();
if (value->GetType() != Primitive::kPrimNot) return;
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index 3844d57439..7068c7fc10 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -18,22 +18,19 @@
#define ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_H_
#include "nodes.h"
+#include "optimization.h"
namespace art {
/**
* Implements optimizations specific to each instruction.
*/
-class InstructionSimplifier : public HGraphVisitor {
+class InstructionSimplifier : public HOptimization {
public:
- explicit InstructionSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
+ explicit InstructionSimplifier(HGraph* graph)
+ : HOptimization(graph, true, "instruction_simplifier") {}
- void Run();
-
- private:
- virtual void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
- virtual void VisitEqual(HEqual* equal) OVERRIDE;
- virtual void VisitArraySet(HArraySet* equal) OVERRIDE;
+ void Run() OVERRIDE;
};
} // namespace art
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index d1555d4e11..e1c8e8ed6e 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -391,6 +391,10 @@ class RegisterSet : public ValueObject {
return (register_set & (1 << reg)) != 0;
}
+ size_t GetNumberOfRegisters() const {
+ return __builtin_popcount(core_registers_) + __builtin_popcount(floating_point_registers_);
+ }
+
private:
uint32_t core_registers_;
uint32_t floating_point_registers_;
@@ -503,6 +507,10 @@ class LocationSummary : public ArenaObject<kArenaAllocMisc> {
return &live_registers_;
}
+ size_t GetNumberOfLiveRegisters() const {
+ return live_registers_.GetNumberOfRegisters();
+ }
+
bool InputOverlapsWithOutputOrTemp(uint32_t input_index, bool is_environment) const {
if (is_environment) return true;
if ((input_index == 0)
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index ea98186d11..d1178d5798 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -21,12 +21,6 @@
namespace art {
-void HOptimization::Execute() {
- Run();
- visualizer_.DumpGraph(pass_name_);
- Check();
-}
-
void HOptimization::Check() {
if (kIsDebugBuild) {
if (is_in_ssa_form_) {
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index 59683e2075..d281248f4a 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -29,25 +29,19 @@ class HOptimization : public ValueObject {
public:
HOptimization(HGraph* graph,
bool is_in_ssa_form,
- const char* pass_name,
- const HGraphVisualizer& visualizer)
+ const char* pass_name)
: graph_(graph),
is_in_ssa_form_(is_in_ssa_form),
- pass_name_(pass_name),
- visualizer_(visualizer) {}
+ pass_name_(pass_name) {}
virtual ~HOptimization() {}
- // Execute the optimization pass.
- void Execute();
-
// Return the name of the pass.
const char* GetPassName() const { return pass_name_; }
// Peform the analysis itself.
virtual void Run() = 0;
- private:
// Verify the graph; abort if it is not valid.
void Check();
@@ -59,9 +53,6 @@ class HOptimization : public ValueObject {
const bool is_in_ssa_form_;
// Optimization pass name.
const char* pass_name_;
- // A graph visualiser invoked after the execution of the optimization
- // pass if enabled.
- const HGraphVisualizer& visualizer_;
DISALLOW_COPY_AND_ASSIGN(HOptimization);
};
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 53273a4568..42ac77d1d8 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -190,6 +190,25 @@ static bool CanOptimize(const DexFile::CodeItem& code_item) {
return code_item.tries_size_ == 0;
}
+static void RunOptimizations(HGraph* graph, const HGraphVisualizer& visualizer) {
+ HDeadCodeElimination opt1(graph);
+ HConstantFolding opt2(graph);
+ SsaRedundantPhiElimination opt3(graph);
+ SsaDeadPhiElimination opt4(graph);
+ InstructionSimplifier opt5(graph);
+ GlobalValueNumberer opt6(graph->GetArena(), graph);
+ InstructionSimplifier opt7(graph);
+
+ HOptimization* optimizations[] = { &opt1, &opt2, &opt3, &opt4, &opt5, &opt6, &opt7 };
+
+ for (size_t i = 0; i < arraysize(optimizations); ++i) {
+ HOptimization* optimization = optimizations[i];
+ optimization->Run();
+ optimization->Check();
+ visualizer.DumpGraph(optimization->GetPassName());
+ }
+}
+
CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
@@ -257,17 +276,9 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
visualizer.DumpGraph("ssa");
graph->FindNaturalLoops();
- HDeadCodeElimination(graph, visualizer).Execute();
- HConstantFolding(graph, visualizer).Execute();
+ RunOptimizations(graph, visualizer);
- SsaRedundantPhiElimination(graph).Run();
- SsaDeadPhiElimination(graph).Run();
- InstructionSimplifier(graph).Run();
- GlobalValueNumberer(graph->GetArena(), graph).Run();
- visualizer.DumpGraph(kGVNPassName);
- InstructionSimplifier(graph).Run();
PrepareForRegisterAllocation(graph).Run();
-
SsaLivenessAnalysis liveness(*graph, codegen);
liveness.Analyze();
visualizer.DumpGraph(kLivenessPassName);
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 4d6e66413d..2948496e15 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -215,9 +215,16 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) {
// By adding the following interval in the algorithm, we can compute this
// maximum before updating locations.
LiveInterval* interval = LiveInterval::MakeSlowPathInterval(allocator_, instruction);
- interval->AddRange(position, position + 1);
- unhandled_core_intervals_.Add(interval);
- unhandled_fp_intervals_.Add(interval);
+ // The start of the interval must be after the position of the safepoint, so that
+ // we can just check the number of active registers at that position. Note that this
+ // will include the current interval in the computation of
+ // `maximum_number_of_live_registers`, so we need a better strategy if this becomes
+ // a problem.
+ // TODO: We could put the logic in AddSorted, to ensure the safepoint range is
+ // after all other intervals starting at that same position.
+ interval->AddRange(position + 1, position + 2);
+ AddSorted(&unhandled_core_intervals_, interval);
+ AddSorted(&unhandled_fp_intervals_, interval);
}
}
@@ -250,6 +257,7 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) {
: unhandled_fp_intervals_;
DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek()));
+
// Some instructions define their output in fixed register/stack slot. We need
// to ensure we know these locations before doing register allocation. For a
// given register, we create an interval that covers these locations. The register
@@ -475,6 +483,17 @@ void RegisterAllocator::LinearScan() {
LiveInterval* current = unhandled_->Pop();
DCHECK(!current->IsFixed() && !current->HasSpillSlot());
DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() >= current->GetStart());
+
+ if (current->IsSlowPathSafepoint()) {
+ // Synthesized interval to record the maximum number of live registers
+ // at safepoints. No need to allocate a register for it.
+ // We know that current actives are all live at the safepoint (modulo
+ // the one created by the safepoint).
+ maximum_number_of_live_registers_ =
+ std::max(maximum_number_of_live_registers_, active_.Size());
+ continue;
+ }
+
size_t position = current->GetStart();
// Remember the inactive_ size here since the ones moved to inactive_ from
@@ -515,14 +534,6 @@ void RegisterAllocator::LinearScan() {
}
}
- if (current->IsSlowPathSafepoint()) {
- // Synthesized interval to record the maximum number of live registers
- // at safepoints. No need to allocate a register for it.
- maximum_number_of_live_registers_ =
- std::max(maximum_number_of_live_registers_, active_.Size());
- continue;
- }
-
// (4) Try to find an available register.
bool success = TryAllocateFreeReg(current);
@@ -1062,6 +1073,7 @@ void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
switch (source.GetKind()) {
case Location::kRegister: {
locations->AddLiveRegister(source);
+ DCHECK_LE(locations->GetNumberOfLiveRegisters(), maximum_number_of_live_registers_);
if (current->GetType() == Primitive::kPrimNot) {
locations->SetRegisterBit(source.reg());
}
diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h
index 5274f09f3f..b7899712d6 100644
--- a/compiler/optimizing/ssa_phi_elimination.h
+++ b/compiler/optimizing/ssa_phi_elimination.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_OPTIMIZING_SSA_PHI_ELIMINATION_H_
#include "nodes.h"
+#include "optimization.h"
namespace art {
@@ -25,15 +26,15 @@ namespace art {
* Optimization phase that removes dead phis from the graph. Dead phis are unused
* phis, or phis only used by other phis.
*/
-class SsaDeadPhiElimination : public ValueObject {
+class SsaDeadPhiElimination : public HOptimization {
public:
explicit SsaDeadPhiElimination(HGraph* graph)
- : graph_(graph), worklist_(graph->GetArena(), kDefaultWorklistSize) {}
+ : HOptimization(graph, true, "dead_phi_elimination"),
+ worklist_(graph->GetArena(), kDefaultWorklistSize) {}
- void Run();
+ void Run() OVERRIDE;
private:
- HGraph* const graph_;
GrowableArray<HPhi*> worklist_;
static constexpr size_t kDefaultWorklistSize = 8;
@@ -47,15 +48,15 @@ class SsaDeadPhiElimination : public ValueObject {
* registers might be updated with the same value, or not updated at all. We can just
* replace the phi with the value when entering the loop.
*/
-class SsaRedundantPhiElimination : public ValueObject {
+class SsaRedundantPhiElimination : public HOptimization {
public:
explicit SsaRedundantPhiElimination(HGraph* graph)
- : graph_(graph), worklist_(graph->GetArena(), kDefaultWorklistSize) {}
+ : HOptimization(graph, true, "redundant_phi_elimination"),
+ worklist_(graph->GetArena(), kDefaultWorklistSize) {}
- void Run();
+ void Run() OVERRIDE;
private:
- HGraph* const graph_;
GrowableArray<HPhi*> worklist_;
static constexpr size_t kDefaultWorklistSize = 8;