Add a compilation tracing mechanism to the new compiler.
Code mostly imported from: https://android-review.googlesource.com/#/c/81653/.
Change-Id: I150fe942be0fb270e03fabb19032180f7a065d13
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 1b70d59..8592aaa 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -82,6 +82,7 @@
optimizing/code_generator.cc \
optimizing/code_generator_arm.cc \
optimizing/code_generator_x86.cc \
+ optimizing/graph_visualizer.cc \
optimizing/nodes.cc \
optimizing/optimizing_compiler.cc \
optimizing/ssa_builder.cc \
diff --git a/compiler/compilers.h b/compiler/compilers.h
index 3ca78c9..e523d64 100644
--- a/compiler/compilers.h
+++ b/compiler/compilers.h
@@ -73,7 +73,7 @@
class OptimizingCompiler FINAL : public QuickCompiler {
public:
- explicit OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) { }
+ explicit OptimizingCompiler(CompilerDriver* driver);
CompiledMethod* Compile(const DexFile::CodeItem* code_item,
uint32_t access_flags,
@@ -92,6 +92,8 @@
const DexFile& dex_file) const;
private:
+ UniquePtr<std::ostream> visualizer_output_;
+
DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler);
};
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index b0aa63b..2c2564d 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -311,6 +311,10 @@
}
}
+ if (return_type == Primitive::kPrimDouble || return_type == Primitive::kPrimFloat) {
+ return false;
+ }
+
DCHECK_EQ(argument_index, number_of_arguments);
current_block_->AddInstruction(invoke);
return true;
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bbebd3a..beafbcc 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -47,7 +47,7 @@
Bind(GetLabelOf(block));
HGraphVisitor* location_builder = GetLocationBuilder();
HGraphVisitor* instruction_visitor = GetInstructionVisitor();
- for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
HInstruction* current = it.Current();
current->Accept(location_builder);
InitLocations(current);
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
new file mode 100644
index 0000000..a7604be
--- /dev/null
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 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 "graph_visualizer.h"
+
+#include "driver/dex_compilation_unit.h"
+#include "nodes.h"
+
+namespace art {
+
+/**
+ * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
+ */
+class HGraphVisualizerPrinter : public HGraphVisitor {
+ public:
+ HGraphVisualizerPrinter(HGraph* graph, std::ostream& output)
+ : HGraphVisitor(graph), output_(output), indent_(0) {}
+
+ void StartTag(const char* name) {
+ AddIndent();
+ output_ << "begin_" << name << std::endl;
+ indent_++;
+ }
+
+ void EndTag(const char* name) {
+ indent_--;
+ AddIndent();
+ output_ << "end_" << name << std::endl;
+ }
+
+ void PrintProperty(const char* name, const char* property) {
+ AddIndent();
+ output_ << name << " \"" << property << "\"" << std::endl;
+ }
+
+ void PrintProperty(const char* name, const char* property, int id) {
+ AddIndent();
+ output_ << name << " \"" << property << id << "\"" << std::endl;
+ }
+
+ void PrintEmptyProperty(const char* name) {
+ AddIndent();
+ output_ << name << std::endl;
+ }
+
+ void PrintTime(const char* name) {
+ AddIndent();
+ output_ << name << " " << time(NULL) << std::endl;
+ }
+
+ void PrintInt(const char* name, int value) {
+ AddIndent();
+ output_ << name << " " << value << std::endl;
+ }
+
+ void AddIndent() {
+ for (size_t i = 0; i < indent_; ++i) {
+ output_ << " ";
+ }
+ }
+
+ void PrintPredecessors(HBasicBlock* block) {
+ AddIndent();
+ output_ << "predecessors";
+ for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
+ HBasicBlock* predecessor = block->GetPredecessors().Get(i);
+ output_ << " \"B" << predecessor->GetBlockId() << "\" ";
+ }
+ output_<< std::endl;
+ }
+
+ void PrintSuccessors(HBasicBlock* block) {
+ AddIndent();
+ output_ << "successors";
+ for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
+ HBasicBlock* successor = block->GetSuccessors().Get(i);
+ output_ << " \"B" << successor->GetBlockId() << "\" ";
+ }
+ output_<< std::endl;
+ }
+
+
+ void VisitInstruction(HInstruction* instruction) {
+ output_ << instruction->DebugName();
+ if (instruction->InputCount() > 0) {
+ output_ << " [ ";
+ for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
+ output_ << "v" << inputs.Current()->GetId() << " ";
+ }
+ output_ << "]";
+ }
+ }
+
+ void PrintInstructions(const HInstructionList& list) {
+ const char* kEndInstructionMarker = "<|@";
+ for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
+ HInstruction* instruction = it.Current();
+ AddIndent();
+ int bci = 0;
+ output_ << bci << " " << instruction->NumberOfUses() << " v" << instruction->GetId() << " ";
+ instruction->Accept(this);
+ output_ << kEndInstructionMarker << std::endl;
+ }
+ }
+
+ void Run(const char* pass_name) {
+ StartTag("cfg");
+ PrintProperty("name", pass_name);
+ VisitInsertionOrder();
+ EndTag("cfg");
+ }
+
+ void VisitBasicBlock(HBasicBlock* block) {
+ StartTag("block");
+ PrintProperty("name", "B", block->GetBlockId());
+ PrintInt("from_bci", -1);
+ PrintInt("to_bci", -1);
+ PrintPredecessors(block);
+ PrintSuccessors(block);
+ PrintEmptyProperty("xhandlers");
+ PrintEmptyProperty("flags");
+ if (block->GetDominator() != nullptr) {
+ PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
+ }
+
+ StartTag("states");
+ StartTag("locals");
+ PrintInt("size", 0);
+ PrintProperty("method", "None");
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+ AddIndent();
+ HInstruction* instruction = it.Current();
+ output_ << instruction->GetId() << " v" << instruction->GetId() << "[ ";
+ for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
+ output_ << inputs.Current()->GetId() << " ";
+ }
+ output_ << "]" << std::endl;
+ }
+ EndTag("locals");
+ EndTag("states");
+
+ StartTag("HIR");
+ PrintInstructions(block->GetPhis());
+ PrintInstructions(block->GetInstructions());
+ EndTag("HIR");
+ EndTag("block");
+ }
+
+ private:
+ std::ostream& output_;
+ size_t indent_;
+
+ DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
+};
+
+HGraphVisualizer::HGraphVisualizer(std::ostream* output,
+ HGraph* graph,
+ const char* string_filter,
+ const DexCompilationUnit& cu)
+ : output_(output), graph_(graph), is_enabled_(false) {
+ if (output == nullptr) {
+ return;
+ }
+ std::string pretty_name = PrettyMethod(cu.GetDexMethodIndex(), *cu.GetDexFile());
+ if (pretty_name.find(string_filter) == std::string::npos) {
+ return;
+ }
+
+ is_enabled_ = true;
+ HGraphVisualizerPrinter printer(graph, *output_);
+ printer.StartTag("compilation");
+ printer.PrintProperty("name", pretty_name.c_str());
+ printer.PrintProperty("method", pretty_name.c_str());
+ printer.PrintTime("date");
+ printer.EndTag("compilation");
+}
+
+void HGraphVisualizer::DumpGraph(const char* pass_name) {
+ if (!is_enabled_) {
+ return;
+ }
+ HGraphVisualizerPrinter printer(graph_, *output_);
+ printer.Run(pass_name);
+}
+
+} // namespace art
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
new file mode 100644
index 0000000..433d55d
--- /dev/null
+++ b/compiler/optimizing/graph_visualizer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
+#define ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
+
+#include "utils/allocation.h"
+
+namespace art {
+
+class DexCompilationUnit;
+class HGraph;
+
+/**
+ * If enabled, emits compilation information suitable for the c1visualizer tool
+ * and IRHydra.
+ * Currently only works if the compiler is single threaded.
+ */
+class HGraphVisualizer : public ValueObject {
+ public:
+ /**
+ * If output is not null, and the method name of the dex compilation
+ * unit contains `string_filter`, the compilation information will be
+ * emitted.
+ */
+ HGraphVisualizer(std::ostream* output,
+ HGraph* graph,
+ const char* string_filter,
+ const DexCompilationUnit& cu);
+
+ /**
+ * If this visualizer is enabled, emit the compilation information
+ * in `output_`.
+ */
+ void DumpGraph(const char* pass_name);
+
+ private:
+ std::ostream* const output_;
+ HGraph* const graph_;
+
+ // Is true when `output_` is not null, and the compiled method's name
+ // contains the string_filter given in the constructor.
+ bool is_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(HGraphVisualizer);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index cf2d1ee..afaedd7 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -37,10 +37,10 @@
for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
block->GetSuccessors().Get(j)->RemovePredecessor(block, false);
}
- for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
block->RemovePhi(it.Current()->AsPhi());
}
- for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
block->RemoveInstruction(it.Current());
}
}
@@ -420,10 +420,10 @@
}
void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
- for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
it.Current()->Accept(this);
}
- for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
it.Current()->Accept(this);
}
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 081c2bd..27b87ca 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -82,7 +82,7 @@
void SimplifyCFG();
// Find all natural loops in this graph. Aborts computation and returns false
- // if one loop is not natural, that is the header does not dominated the back
+ // if one loop is not natural, that is the header does not dominate the back
// edge.
bool FindNaturalLoops() const;
@@ -268,8 +268,8 @@
HInstruction* GetFirstInstruction() const { return instructions_.first_instruction_; }
HInstruction* GetLastInstruction() const { return instructions_.last_instruction_; }
- HInstructionList const* GetInstructions() const { return &instructions_; }
- HInstructionList const* GetPhis() const { return &phis_; }
+ const HInstructionList& GetInstructions() const { return instructions_; }
+ const HInstructionList& GetPhis() const { return phis_; }
void AddSuccessor(HBasicBlock* block) {
successors_.Add(block);
@@ -444,6 +444,17 @@
bool HasUses() const { return uses_ != nullptr || env_uses_ != nullptr; }
+ size_t NumberOfUses() const {
+ // TODO: Optimize this method if it is used outside of the HGraphTracer.
+ size_t result = 0;
+ HUseListNode<HInstruction>* current = uses_;
+ while (current != nullptr) {
+ current = current->GetTail();
+ ++result;
+ }
+ return result;
+ }
+
int GetId() const { return id_; }
void SetId(int id) { id_ = id; }
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index a5031e0..f435cb0 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <fstream>
#include <stdint.h>
#include "builder.h"
@@ -21,6 +22,7 @@
#include "compilers.h"
#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
+#include "graph_visualizer.h"
#include "nodes.h"
#include "ssa_liveness_analysis.h"
#include "utils/arena_allocator.h"
@@ -50,6 +52,22 @@
DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator);
};
+/**
+ * If set to true, generates a file suitable for the c1visualizer tool and IRHydra.
+ */
+static bool kIsVisualizerEnabled = false;
+
+/**
+ * Filter to apply to the visualizer. Methods whose name contain that filter will
+ * be in the file.
+ */
+static const char* kStringFilter = "";
+
+OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) {
+ if (kIsVisualizerEnabled) {
+ visualizer_output_.reset(new std::ofstream("art.cfg"));
+ }
+}
CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
uint32_t access_flags,
@@ -70,6 +88,7 @@
ArenaPool pool;
ArenaAllocator arena(&pool);
HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file);
+
HGraph* graph = builder.BuildGraph(*code_item);
if (graph == nullptr) {
if (shouldCompile) {
@@ -77,6 +96,8 @@
}
return nullptr;
}
+ HGraphVisualizer visualizer(visualizer_output_.get(), graph, kStringFilter, dex_compilation_unit);
+ visualizer.DumpGraph("builder");
InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet();
// The optimizing compiler currently does not have a Thumb2 assembler.
@@ -104,6 +125,8 @@
// Run these phases to get some test coverage.
graph->BuildDominatorTree();
graph->TransformToSSA();
+ visualizer.DumpGraph("ssa");
+
graph->FindNaturalLoops();
SsaLivenessAnalysis(*graph).Analyze();
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 1fc041c..50e3254 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -30,7 +30,7 @@
// 2) Set inputs of loop phis.
for (size_t i = 0; i < loop_headers_.Size(); i++) {
HBasicBlock* block = loop_headers_.Get(i);
- for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
HPhi* phi = it.Current()->AsPhi();
for (size_t pred = 0; pred < block->GetPredecessors().Size(); pred++) {
phi->AddInput(ValueOfLocal(block->GetPredecessors().Get(pred), phi->GetRegNumber()));
@@ -40,7 +40,7 @@
// 3) Clear locals.
// TODO: Move this to a dead code eliminator phase.
- for (HInstructionIterator it(*GetGraph()->GetEntryBlock()->GetInstructions());
+ for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
!it.Done();
it.Advance()) {
HInstruction* current = it.Current();
@@ -106,7 +106,7 @@
// - HStoreLocal: update current value of the local and remove the instruction.
// - Instructions that require an environment: populate their environment
// with the current values of the locals.
- for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
it.Current()->Accept(this);
}
}
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 0ab77ca..7c2ec39 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -29,14 +29,14 @@
for (HReversePostOrderIterator it(graph_); !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
- for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
HInstruction* current = it.Current();
if (current->HasUses()) {
current->SetSsaIndex(ssa_index++);
}
}
- for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
HInstruction* current = it.Current();
if (current->HasUses()) {
current->SetSsaIndex(ssa_index++);
@@ -73,7 +73,7 @@
BitVector* kill = GetKillSet(*block);
BitVector* live_in = GetLiveInSet(*block);
- for (HBackwardInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+ for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
HInstruction* current = it.Current();
if (current->HasSsaIndex()) {
kill->SetBit(current->GetSsaIndex());
@@ -99,7 +99,7 @@
}
}
- for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
HInstruction* current = it.Current();
if (current->HasSsaIndex()) {
kill->SetBit(current->GetSsaIndex());
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index 9be2197..415d146 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -66,10 +66,10 @@
int id = 0;
for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
HBasicBlock* block = graph->GetBlocks().Get(i);
- for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
it.Current()->SetId(id++);
}
- for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
it.Current()->SetId(id++);
}
}