Generation of dot files through visitor.Added type info to .dot.
visitor.h: Fixed formatting.
type_inference.cc: Changed GetSSAConsumers() to return pointer.
sea_node.h, sea.cc: Removed ToDot classes functions.
instruction_nodes.h: Added acessor for SSA producers.
Marked GetUses() as const.
sea.h: Marked fields as const.
frontend.cc: Changed .dot generation code.
code_gen.h: Fixed include to have full path.
Change-Id: Ia84371c171c4537d9cf2f56644baa075f1706df1
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 86f5213..bffda6c 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -97,7 +97,9 @@
sea_ir/instruction_tools.cc \
sea_ir/sea.cc \
sea_ir/code_gen.cc \
- sea_ir/types/type_inference.cc
+ sea_ir/types/type_inference.cc \
+ sea_ir/types/type_inference_visitor.cc \
+ sea_ir/debug/dot_gen.cc
endif
LIBART_COMPILER_CFLAGS :=
diff --git a/compiler/sea_ir/code_gen.h b/compiler/sea_ir/code_gen.h
index f656453..5fea79a 100644
--- a/compiler/sea_ir/code_gen.h
+++ b/compiler/sea_ir/code_gen.h
@@ -22,7 +22,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Analysis/Verifier.h"
-#include "visitor.h"
+#include "sea_ir/visitor.h"
namespace sea_ir {
// Abstracts away the containers we use to map SEA IR objects to LLVM IR objects.
diff --git a/compiler/sea_ir/debug/dot_gen.cc b/compiler/sea_ir/debug/dot_gen.cc
new file mode 100644
index 0000000..9e071e1
--- /dev/null
+++ b/compiler/sea_ir/debug/dot_gen.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 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 "sea_ir/debug/dot_gen.h"
+
+namespace sea_ir {
+
+void DotGenerationVisitor::Initialize(SeaGraph* graph) {
+ graph_ = graph;
+ Region* root_region;
+ ordered_regions_.clear();
+ for (std::vector<Region*>::const_iterator cit = graph->GetRegions()->begin();
+ cit != graph->GetRegions()->end(); cit++ ) {
+ if ((*cit)->GetIDominator() == (*cit)) {
+ root_region = *cit;
+ }
+ }
+ ordered_regions_.push_back(root_region);
+ for (unsigned int id = 0; id < ordered_regions_.size(); id++) {
+ Region* current_region = ordered_regions_.at(id);
+ const std::set<Region*>* dominated_regions = current_region->GetIDominatedSet();
+ for (std::set<Region*>::const_iterator cit = dominated_regions->begin();
+ cit != dominated_regions->end(); cit++ ) {
+ ordered_regions_.push_back(*cit);
+ }
+ }
+}
+
+void DotGenerationVisitor::ToDotSSAEdges(InstructionNode* instruction) {
+ std::map<int, InstructionNode*>* definition_edges = instruction->GetSSAProducersMap();
+ // SSA definitions:
+ for (std::map<int, InstructionNode*>::const_iterator
+ def_it = definition_edges->begin();
+ def_it != definition_edges->end(); def_it++) {
+ if (NULL != def_it->second) {
+ dot_text_ += def_it->second->StringId() + " -> ";
+ dot_text_ += instruction->StringId() + "[color=gray,label=\"";
+ dot_text_ += art::StringPrintf("vR = %d", def_it->first);
+ std::map<int, const Type*>::const_iterator type_it = types_->find(def_it->second->Id());
+ if (type_it != types_->end()) {
+ dot_text_ += "(" + type_it->second->Dump() + ")";
+ } else {
+ dot_text_ += "()";
+ }
+ dot_text_ += "\"] ; // SSA edge\n";
+ }
+ }
+
+ // SSA used-by:
+ if (options_->WillSaveUseEdges()) {
+ std::vector<InstructionNode*>* used_in = instruction->GetSSAConsumers();
+ for (std::vector<InstructionNode*>::const_iterator cit = used_in->begin();
+ cit != used_in->end(); cit++) {
+ dot_text_ += (*cit)->StringId() + " -> " + instruction->StringId() + "[color=gray,label=\"";
+ dot_text_ += "\"] ; // SSA used-by edge\n";
+ }
+ }
+}
+
+void DotGenerationVisitor::Visit(SignatureNode* parameter) {
+ dot_text_ += parameter->StringId() +" [label=\"signature:";
+ dot_text_ += art::StringPrintf("r%d", parameter->GetResultRegister());
+ dot_text_ += "\"] // signature node\n";
+ ToDotSSAEdges(parameter);
+}
+
+// Appends to @result a dot language formatted string representing the node and
+// (by convention) outgoing edges, so that the composition of theToDot() of all nodes
+// builds a complete dot graph (without prolog and epilog though).
+void DotGenerationVisitor::Visit(Region* region) {
+ dot_text_ += "\n// Region: \nsubgraph " + region->StringId();
+ dot_text_ += " { label=\"region " + region->StringId() + "(rpo=";
+ dot_text_ += art::StringPrintf("%d", region->GetRPO());
+ if (NULL != region->GetIDominator()) {
+ dot_text_ += " dom=" + region->GetIDominator()->StringId();
+ }
+ dot_text_ += ")\";\n";
+
+ std::vector<PhiInstructionNode*>* phi_instructions = region->GetPhiNodes();
+ for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions->begin();
+ cit != phi_instructions->end(); cit++) {
+ dot_text_ += (*cit)->StringId() +";\n";
+ }
+ std::vector<InstructionNode*>* instructions = region->GetInstructions();
+ for (std::vector<InstructionNode*>::const_iterator cit = instructions->begin();
+ cit != instructions->end(); cit++) {
+ dot_text_ += (*cit)->StringId() +";\n";
+ }
+
+ dot_text_ += "} // End Region.\n";
+ std::vector<Region*>* successors = region->GetSuccessors();
+ for (std::vector<Region*>::const_iterator cit = successors->begin(); cit != successors->end();
+ cit++) {
+ DCHECK(NULL != *cit) << "Null successor found for SeaNode" <<
+ region->GetLastChild()->StringId() << ".";
+ dot_text_ += region->GetLastChild()->StringId() + " -> " +
+ (*cit)->GetLastChild()->StringId() +
+ "[lhead=" + (*cit)->StringId() + ", " + "ltail=" + region->StringId() + "];\n\n";
+ }
+}
+void DotGenerationVisitor::Visit(InstructionNode* instruction) {
+ dot_text_ += "// Instruction ("+instruction->StringId()+"): \n" + instruction->StringId() +
+ " [label=\"" + instruction->GetInstruction()->DumpString(graph_->GetDexFile()) + "\"";
+ dot_text_ += "];\n";
+ ToDotSSAEdges(instruction);
+}
+
+void DotGenerationVisitor::Visit(UnnamedConstInstructionNode* instruction) {
+ dot_text_ += "// Instruction ("+instruction->StringId()+"): \n" + instruction->StringId() +
+ " [label=\"const/x v-3, #"+ art::StringPrintf("%d", instruction->GetConstValue()) + "\"";
+ dot_text_ += "];\n";
+ ToDotSSAEdges(instruction);
+}
+
+void DotGenerationVisitor::Visit(PhiInstructionNode* phi) {
+ dot_text_ += "// PhiInstruction: \n" + phi->StringId() +
+ " [label=\"" + "PHI(";
+ dot_text_ += art::StringPrintf("%d", phi->GetRegisterNumber());
+ dot_text_ += ")\"";
+ dot_text_ += "];\n";
+ ToDotSSAEdges(phi);
+}
+} // namespace sea_ir
diff --git a/compiler/sea_ir/debug/dot_gen.h b/compiler/sea_ir/debug/dot_gen.h
new file mode 100644
index 0000000..520d9df
--- /dev/null
+++ b/compiler/sea_ir/debug/dot_gen.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2013 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_SEA_IR_DEBUG_DOT_GEN_H_
+#define ART_COMPILER_SEA_IR_DEBUG_DOT_GEN_H_
+
+#include "base/stringprintf.h"
+#include "file_output_stream.h"
+#include "sea_ir/sea.h"
+#include "sea_ir/types/type_inference.h"
+
+namespace sea_ir {
+
+class DotConversionOptions {
+ public:
+ DotConversionOptions(): save_use_edges_(false) { }
+ bool WillSaveUseEdges() const {
+ return save_use_edges_;
+ }
+ private:
+ bool save_use_edges_;
+};
+
+class DotGenerationVisitor: public IRVisitor {
+ public:
+ explicit DotGenerationVisitor(const DotConversionOptions* const options,
+ std::map<int, const Type*>* types): graph_(), types_(types), options_(options) { }
+
+ virtual void Initialize(SeaGraph* graph);
+ // Saves the ssa def->use edges corresponding to @instruction.
+ void ToDotSSAEdges(InstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void Visit(SeaGraph* graph) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ dot_text_ += "digraph seaOfNodes {\ncompound=true\n";
+ }
+ void Visit(SignatureNode* parameter) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Appends to @result a dot language formatted string representing the node and
+ // (by convention) outgoing edges, so that the composition of theToDot() of all nodes
+ // builds a complete dot graph (without prolog and epilog though).
+ void Visit(Region* region) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void Visit(InstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void Visit(PhiInstructionNode* phi) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void Visit(UnnamedConstInstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ void Visit(ConstInstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Visit(reinterpret_cast<InstructionNode*>(instruction));
+ }
+ void Visit(ReturnInstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Visit(reinterpret_cast<InstructionNode*>(instruction));
+ }
+ void Visit(IfNeInstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Visit(reinterpret_cast<InstructionNode*>(instruction));
+ }
+ void Visit(MoveResultInstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Visit(reinterpret_cast<InstructionNode*>(instruction));
+ }
+ void Visit(InvokeStaticInstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Visit(reinterpret_cast<InstructionNode*>(instruction));
+ }
+ void Visit(AddIntInstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Visit(reinterpret_cast<InstructionNode*>(instruction));
+ }
+ void Visit(GotoInstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Visit(reinterpret_cast<InstructionNode*>(instruction));
+ }
+ void Visit(IfEqzInstructionNode* instruction) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Visit(reinterpret_cast<InstructionNode*>(instruction));
+ }
+
+ std::string GetResult() const {
+ return dot_text_;
+ }
+
+ private:
+ std::string dot_text_;
+ SeaGraph* graph_;
+ std::map<int, const Type*>* types_;
+ const DotConversionOptions* const options_;
+};
+
+// Stores options for turning a SEA IR graph to a .dot file.
+class DotConversion {
+ public:
+ DotConversion(): options_() { }
+ // Saves to @filename the .dot representation of @graph with the options @options.
+ void DumpSea(SeaGraph* graph, std::string filename, std::map<int, const Type*>* types) const {
+ LOG(INFO) << "Starting to write SEA string to file.";
+ DotGenerationVisitor dgv = DotGenerationVisitor(&options_, types);
+ graph->Accept(&dgv);
+ art::File* file = art::OS::OpenFile(filename.c_str(), true, true);
+ art::FileOutputStream fos(file);
+ std::string graph_as_string = dgv.GetResult();
+ graph_as_string += "}";
+ fos.WriteFully(graph_as_string.c_str(), graph_as_string.size());
+ LOG(INFO) << "Written SEA string to file.";
+ }
+
+ private:
+ DotConversionOptions options_;
+};
+
+} // namespace sea_ir
+#endif // ART_COMPILER_SEA_IR_DEBUG_DOT_GEN_H_
diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc
index cc49ea5..951273c 100644
--- a/compiler/sea_ir/frontend.cc
+++ b/compiler/sea_ir/frontend.cc
@@ -23,8 +23,11 @@
#include "llvm/llvm_compilation_unit.h"
#include "mirror/object.h"
#include "runtime.h"
-#include "sea_ir/sea.h"
+
+#include "sea_ir/sea.h"
+#include "sea_ir/debug/dot_gen.h"
+#include "sea_ir/types/types.h"
namespace art {
static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler,
@@ -40,9 +43,11 @@
// NOTE: Instead of keeping the convention from the Dalvik frontend.cc
// and silencing the cpplint.py warning, I just corrected the formatting.
VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
- sea_ir::SeaGraph* sg = sea_ir::SeaGraph::GetCurrentGraph(dex_file);
- sg->CompileMethod(code_item, class_def_idx, method_idx, method_access_flags, dex_file);
- sg->DumpSea("/tmp/temp.dot");
+ sea_ir::SeaGraph* ir_graph = sea_ir::SeaGraph::GetCurrentGraph(dex_file);
+ ir_graph->CompileMethod(code_item, class_def_idx, method_idx, method_access_flags, dex_file);
+ sea_ir::DotConversion dc;
+ std::map<int, const sea_ir::Type*> types = ir_graph->ti_->GetTypeMap();
+ dc.DumpSea(ir_graph, "/tmp/temp.dot", &types);
CHECK(0 && "No SEA compiled function exists yet.");
return NULL;
}
diff --git a/compiler/sea_ir/instruction_nodes.h b/compiler/sea_ir/instruction_nodes.h
index 1b81e9a..fb1f83f 100644
--- a/compiler/sea_ir/instruction_nodes.h
+++ b/compiler/sea_ir/instruction_nodes.h
@@ -16,9 +16,10 @@
#ifndef ART_COMPILER_SEA_IR_INSTRUCTION_NODES_H_
#define ART_COMPILER_SEA_IR_INSTRUCTION_NODES_H_
-#include "sea_node.h"
-#include "visitor.h"
#include "dex_instruction-inl.h"
+#include "sea_ir/sea_node.h"
+#include "sea_ir/visitor.h"
+
namespace sea_ir {
@@ -48,9 +49,7 @@
// Returns the set of registers defined by the current instruction.
virtual std::vector<int> GetDefinitions() const;
// Returns the set of register numbers that are used by the instruction.
- virtual std::vector<int> GetUses();
- // Appends to @result the .dot string representation of the instruction.
- virtual void ToDot(std::string& result, const art::DexFile& dex_file) const;
+ virtual std::vector<int> GetUses() const;
// Mark the current instruction as a downward exposed definition.
void MarkAsDEDef();
// Rename the use of @reg_no to refer to the instruction @definition,
@@ -69,15 +68,15 @@
}
return ssa_uses;
}
-
- std::vector<InstructionNode*> GetSSAConsumers() {
- return used_in_;
+ std::map<int, InstructionNode* >* GetSSAProducersMap() {
+ return &definition_edges_;
}
-
+ std::vector<InstructionNode*>* GetSSAConsumers() {
+ return &used_in_;
+ }
virtual void AddSSAUse(InstructionNode* use) {
used_in_.push_back(use);
}
-
void Accept(IRVisitor* v) {
v->Visit(this);
v->Traverse(this);
@@ -95,11 +94,10 @@
protected:
explicit InstructionNode(const art::Instruction* in):
SeaNode(), instruction_(in), used_in_(), de_def_(false), region_(NULL) { }
- void ToDotSSAEdges(std::string& result) const;
protected:
const art::Instruction* const instruction_;
- std::map<int, InstructionNode* > definition_edges_;
+ std::map<int, InstructionNode* > definition_edges_; // Maps used registers to their definitions.
// Stores pointers to instructions that use the result of the current instruction.
std::vector<InstructionNode*> used_in_;
bool de_def_;
@@ -125,6 +123,7 @@
public:
explicit UnnamedConstInstructionNode(const art::Instruction* inst, int32_t value):
ConstInstructionNode(inst), value_(value) { }
+
void Accept(IRVisitor* v) {
v->Visit(this);
v->Traverse(this);
@@ -138,19 +137,6 @@
return value_;
}
- void ToDot(std::string& result, const art::DexFile& dex_file) const {
- std::ostringstream sstream;
- sstream << GetConstValue();
- const std::string value_as_string(sstream.str());
- result += "// Instruction ("+StringId()+"): \n" + StringId() +
- " [label=\"const/x v-3, #"+ value_as_string + "\"";
- if (de_def_) {
- result += "style=bold";
- }
- result += "];\n";
- ToDotSSAEdges(result);
- }
-
private:
const int32_t value_;
};
@@ -180,7 +166,7 @@
class MoveResultInstructionNode: public InstructionNode {
public:
explicit MoveResultInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
- std::vector<int> GetUses() {
+ std::vector<int> GetUses() const {
std::vector<int> uses; // Using vector<> instead of set<> because order matters.
uses.push_back(RETURN_REGISTER);
return uses;
@@ -217,7 +203,7 @@
explicit AddIntLitInstructionNode(const art::Instruction* inst):
AddIntInstructionNode(inst) { }
- std::vector<int> GetUses() {
+ std::vector<int> GetUses() const {
std::vector<int> uses = AddIntInstructionNode::GetUses();
uses.push_back(UNNAMED_CONST_REGISTER);
return uses;
diff --git a/compiler/sea_ir/sea.cc b/compiler/sea_ir/sea.cc
index 585b2aa..cb159e1 100644
--- a/compiler/sea_ir/sea.cc
+++ b/compiler/sea_ir/sea.cc
@@ -14,7 +14,6 @@
* limitations under the License.
*/
#include "base/stringprintf.h"
-#include "file_output_stream.h"
#include "instruction_tools.h"
#include "sea.h"
#include "code_gen.h"
@@ -36,7 +35,6 @@
cit != phis->end(); cit++) {
(*cit)->Accept(this);
}
-
std::vector<InstructionNode*>* instructions = region->GetInstructions();
for (std::vector<InstructionNode*>::const_iterator cit = instructions->begin();
cit != instructions->end(); cit++) {
@@ -55,20 +53,6 @@
return new SeaGraph(dex_file);
}
-void SeaGraph::DumpSea(std::string filename) const {
- LOG(INFO) << "Starting to write SEA string to file.";
- std::string result;
- result += "digraph seaOfNodes {\ncompound=true\n";
- for (std::vector<Region*>::const_iterator cit = regions_.begin(); cit != regions_.end(); cit++) {
- (*cit)->ToDot(result, dex_file_);
- }
- result += "}\n";
- art::File* file = art::OS::OpenFile(filename.c_str(), true, true);
- art::FileOutputStream fos(file);
- fos.WriteFully(result.c_str(), result.size());
- LOG(INFO) << "Written SEA string to file.";
-}
-
void SeaGraph::AddEdge(Region* src, Region* dst) const {
src->AddSuccessor(dst);
dst->AddPredecessor(src);
@@ -264,6 +248,7 @@
}
r = nextRegion;
}
+ r->AddChild(node);
}
i += inst->SizeInCodeUnits();
}
@@ -433,8 +418,8 @@
// Two Passes: Phi node insertion.
ConvertToSSA();
// Pass: type inference
- TypeInference ti = TypeInference();
- ti.ComputeTypes(this);
+ std::cout << "TYPES." << std::endl;
+ ti_->ComputeTypes(this);
// Pass: Generate LLVM IR.
GenerateLLVM();
}
@@ -467,18 +452,10 @@
regions_.push_back(r);
}
-/*
-void SeaNode::AddSuccessor(Region* successor) {
- DCHECK(successor) << "Tried to add NULL successor to SEA node.";
- successors_.push_back(successor);
- return;
-}
+SeaGraph::SeaGraph(const art::DexFile& df)
+ :ti_(new TypeInference()), class_def_idx_(0), method_idx_(0), method_access_flags_(),
+ regions_(), parameters_(), dex_file_(df), code_item_(NULL) { }
-void SeaNode::AddPredecessor(Region* predecessor) {
- DCHECK(predecessor) << "Tried to add NULL predecessor to SEA node.";
- predecessors_.push_back(predecessor);
-}
-*/
void Region::AddChild(sea_ir::InstructionNode* instruction) {
DCHECK(instruction) << "Tried to add NULL instruction to region node.";
instructions_.push_back(instruction);
@@ -492,46 +469,6 @@
return NULL;
}
-void Region::ToDot(std::string& result, const art::DexFile& dex_file) const {
- result += "\n// Region: \nsubgraph " + StringId() + " { label=\"region " + StringId() + "(rpo=";
- result += art::StringPrintf("%d", rpo_number_);
- if (NULL != GetIDominator()) {
- result += " dom=" + GetIDominator()->StringId();
- }
- result += ")\";\n";
-
- for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions_.begin();
- cit != phi_instructions_.end(); cit++) {
- result += (*cit)->StringId() +";\n";
- }
-
- for (std::vector<InstructionNode*>::const_iterator cit = instructions_.begin();
- cit != instructions_.end(); cit++) {
- result += (*cit)->StringId() +";\n";
- }
-
- result += "} // End Region.\n";
-
- // Save phi-nodes.
- for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions_.begin();
- cit != phi_instructions_.end(); cit++) {
- (*cit)->ToDot(result, dex_file);
- }
-
- // Save instruction nodes.
- for (std::vector<InstructionNode*>::const_iterator cit = instructions_.begin();
- cit != instructions_.end(); cit++) {
- (*cit)->ToDot(result, dex_file);
- }
-
- for (std::vector<Region*>::const_iterator cit = successors_.begin(); cit != successors_.end();
- cit++) {
- DCHECK(NULL != *cit) << "Null successor found for SeaNode" << GetLastChild()->StringId() << ".";
- result += GetLastChild()->StringId() + " -> " + (*cit)->GetLastChild()->StringId() +
- "[lhead=" + (*cit)->StringId() + ", " + "ltail=" + StringId() + "];\n\n";
- }
-}
-
void Region::ComputeDownExposedDefs() {
for (std::vector<InstructionNode*>::const_iterator inst_it = instructions_.begin();
inst_it != instructions_.end(); inst_it++) {
@@ -694,38 +631,6 @@
return sea_instructions;
}
-void InstructionNode::ToDotSSAEdges(std::string& result) const {
- // SSA definitions:
- for (std::map<int, InstructionNode*>::const_iterator def_it = definition_edges_.begin();
- def_it != definition_edges_.end(); def_it++) {
- if (NULL != def_it->second) {
- result += def_it->second->StringId() + " -> " + StringId() + "[color=gray,label=\"";
- result += art::StringPrintf("vR = %d", def_it->first);
- result += "\"] ; // ssa edge\n";
- }
- }
-
- // SSA used-by:
- if (DotConversion::SaveUseEdges()) {
- for (std::vector<InstructionNode*>::const_iterator cit = used_in_.begin();
- cit != used_in_.end(); cit++) {
- result += (*cit)->StringId() + " -> " + StringId() + "[color=gray,label=\"";
- result += "\"] ; // SSA used-by edge\n";
- }
- }
-}
-
-void InstructionNode::ToDot(std::string& result, const art::DexFile& dex_file) const {
- result += "// Instruction ("+StringId()+"): \n" + StringId() +
- " [label=\"" + instruction_->DumpString(&dex_file) + "\"";
- if (de_def_) {
- result += "style=bold";
- }
- result += "];\n";
-
- ToDotSSAEdges(result);
-}
-
void InstructionNode::MarkAsDEDef() {
de_def_ = true;
}
@@ -749,7 +654,7 @@
return definitions;
}
-std::vector<int> InstructionNode::GetUses() {
+std::vector<int> InstructionNode::GetUses() const {
std::vector<int> uses; // Using vector<> instead of set<> because order matters.
if (!InstructionTools::IsDefinition(instruction_) && (instruction_->HasVRegA())) {
int vA = instruction_->VRegA();
@@ -765,13 +670,4 @@
}
return uses;
}
-
-void PhiInstructionNode::ToDot(std::string& result, const art::DexFile& dex_file) const {
- result += "// PhiInstruction: \n" + StringId() +
- " [label=\"" + "PHI(";
- result += art::StringPrintf("%d", register_no_);
- result += ")\"";
- result += "];\n";
- ToDotSSAEdges(result);
-}
} // namespace sea_ir
diff --git a/compiler/sea_ir/sea.h b/compiler/sea_ir/sea.h
index efdbb3b..3a8efcd 100644
--- a/compiler/sea_ir/sea.h
+++ b/compiler/sea_ir/sea.h
@@ -23,8 +23,8 @@
#include "dex_file.h"
#include "dex_instruction.h"
-#include "instruction_tools.h"
-#include "instruction_nodes.h"
+#include "sea_ir/instruction_tools.h"
+#include "sea_ir/instruction_nodes.h"
#include "utils/scoped_hashtable.h"
namespace sea_ir {
@@ -35,19 +35,9 @@
VISITING = -2
};
-// Stores options for turning a SEA IR graph to a .dot file.
-class DotConversion {
- public:
- static bool SaveUseEdges() {
- return save_use_edges_;
- }
-
- private:
- static const bool save_use_edges_ = false; // TODO: Enable per-sea graph configuration.
-};
+class TypeInference;
class Region;
-
class InstructionNode;
class PhiInstructionNode;
class SignatureNode;
@@ -62,22 +52,15 @@
explicit SignatureNode(unsigned int parameter_register, unsigned int position):
InstructionNode(NULL), parameter_register_(parameter_register), position_(position) { }
- void ToDot(std::string& result, const art::DexFile& dex_file) const {
- result += StringId() +" [label=\"signature:";
- result += art::StringPrintf("r%d", GetResultRegister());
- result += "\"] // signature node\n";
- ToDotSSAEdges(result);
- }
-
int GetResultRegister() const {
return parameter_register_;
}
- unsigned int GetPositionInSignature() {
+ unsigned int GetPositionInSignature() const {
return position_;
}
- std::vector<int> GetUses() {
+ std::vector<int> GetUses() const {
return std::vector<int>();
}
@@ -87,16 +70,15 @@
}
private:
- unsigned int parameter_register_;
- unsigned int position_; // The position of this parameter node is in the function parameter list.
+ const unsigned int parameter_register_;
+ const unsigned int position_; // The position of this parameter node is
+ // in the function parameter list.
};
class PhiInstructionNode: public InstructionNode {
public:
explicit PhiInstructionNode(int register_no):
InstructionNode(NULL), register_no_(register_no), definition_edges_() {}
- // Appends to @result the .dot string representation of the instruction.
- void ToDot(std::string& result, const art::DexFile& dex_file) const;
// Returns the register on which this phi-function is used.
int GetRegisterNumber() const {
return register_no_;
@@ -157,10 +139,7 @@
std::vector<InstructionNode*>* GetInstructions() {
return &instructions_;
}
- // Appends to @result a dot language formatted string representing the node and
- // (by convention) outgoing edges, so that the composition of theToDot() of all nodes
- // builds a complete dot graph (without prolog and epilog though).
- virtual void ToDot(std::string& result, const art::DexFile& dex_file) const;
+
// Computes Downward Exposed Definitions for the current node.
void ComputeDownExposedDefs();
const std::map<int, sea_ir::InstructionNode*>* GetDownExposedDefs() const;
@@ -272,8 +251,6 @@
std::vector<Region*>* GetRegions() {
return ®ions_;
}
- // Returns a string representation of the region and its Instruction children.
- void DumpSea(std::string filename) const;
// Recursively computes the reverse postorder value for @crt_bb and successors.
static void ComputeRPO(Region* crt_bb, int& crt_rpo);
// Returns the "lowest common ancestor" of @i and @j in the dominator tree.
@@ -287,15 +264,19 @@
return &dex_file_;
}
+ virtual void Accept(IRVisitor* visitor) {
+ visitor->Initialize(this);
+ visitor->Visit(this);
+ visitor->Traverse(this);
+ }
+
+ TypeInference* ti_;
uint32_t class_def_idx_;
uint32_t method_idx_;
uint32_t method_access_flags_;
private:
- explicit SeaGraph(const art::DexFile& df):
- class_def_idx_(0), method_idx_(0), method_access_flags_(), regions_(),
- parameters_(), dex_file_(df), code_item_(NULL) {
- }
+ explicit SeaGraph(const art::DexFile& df);
// Registers @childReg as a region belonging to the SeaGraph instance.
void AddRegion(Region* childReg);
// Returns new region and registers it with the SeaGraph instance.
@@ -336,11 +317,7 @@
// by using the scoped hashtable of names @ scoped_table.
void RenameAsSSA(Region* node, utils::ScopedHashtable<int, InstructionNode*>* scoped_table);
- virtual void Accept(IRVisitor* visitor) {
- visitor->Initialize(this);
- visitor->Visit(this);
- visitor->Traverse(this);
- }
+
virtual ~SeaGraph() {}
// Generate LLVM IR for the method.
diff --git a/compiler/sea_ir/sea_node.h b/compiler/sea_ir/sea_node.h
index c13e5d6..98bbe9e 100644
--- a/compiler/sea_ir/sea_node.h
+++ b/compiler/sea_ir/sea_node.h
@@ -56,10 +56,6 @@
int Id() const {
return id_;
}
- // Appends to @result a dot language formatted string representing the node and
- // (by convention) outgoing edges, so that the composition of theToDot() of all nodes
- // builds a complete dot graph, but without prolog ("digraph {") and epilog ("}").
- virtual void ToDot(std::string& result, const art::DexFile& dex_file) const = 0;
virtual ~SeaNode() { }
diff --git a/compiler/sea_ir/types/type_inference.cc b/compiler/sea_ir/types/type_inference.cc
index ad81310..78888f3 100644
--- a/compiler/sea_ir/types/type_inference.cc
+++ b/compiler/sea_ir/types/type_inference.cc
@@ -15,6 +15,8 @@
*/
#include "sea_ir/types/type_inference.h"
+#include "sea_ir/types/type_inference_visitor.h"
+#include "sea_ir/sea.h"
namespace sea_ir {
@@ -133,9 +135,10 @@
// maintain this invariant, but they should.
// [1] http://www.sgi.com/tech/stl/List.html
// TODO: Making this conditional (as in sparse conditional constant propagation) would be good.
+ // TODO: Remove elements as I go.
for (std::list<InstructionNode*>::const_iterator instruction_it = worklist.begin();
instruction_it != worklist.end(); instruction_it++) {
- std::cout << "Instruction: " << (*instruction_it)->Id() << std::endl;
+ std::cout << "[TI] Instruction: " << (*instruction_it)->Id() << std::endl;
(*instruction_it)->Accept(&tiv);
std::map<int, const Type*>::const_iterator old_result_it =
type_map_.find((*instruction_it)->Id());
@@ -144,16 +147,15 @@
bool type_changed = (old_result_it != type_map_.end()) && ((*old_result_it).second != new_type);
if (first_time_set || type_changed) {
std::cout << " New type:" << new_type->IsIntegralTypes() << std::endl;
- std::cout << " Descriptor:" << new_type->Dump() << std::endl;
+ std::cout << " Descrip:" << new_type->Dump()<< "on " << (*instruction_it)->Id() << std::endl;
type_map_[(*instruction_it)->Id()] = new_type;
// Add SSA consumers of the current instruction to the work-list.
- std::vector<InstructionNode*> consumers = (*instruction_it)->GetSSAConsumers();
- for (std::vector<InstructionNode*>::iterator consumer = consumers.begin();
- consumer != consumers.end(); consumer++) {
+ std::vector<InstructionNode*>* consumers = (*instruction_it)->GetSSAConsumers();
+ for (std::vector<InstructionNode*>::iterator consumer = consumers->begin();
+ consumer != consumers->end(); consumer++) {
worklist.push_back(*consumer);
}
}
}
}
-
} // namespace sea_ir
diff --git a/compiler/sea_ir/types/type_inference.h b/compiler/sea_ir/types/type_inference.h
index 1c0d42e..9014c96 100644
--- a/compiler/sea_ir/types/type_inference.h
+++ b/compiler/sea_ir/types/type_inference.h
@@ -17,15 +17,12 @@
#ifndef ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_H_
#define ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_H_
-#include "sea_ir/sea.h"
#include "dex_file-inl.h"
-#include "verifier/reg_type.h"
-#include "verifier/reg_type_cache.h"
-#include "verifier/reg_type_cache.h"
+#include "sea_ir/types/types.h"
+
namespace sea_ir {
-typedef art::verifier::RegType Type;
-
+class SeaGraph;
// The type inference in SEA IR is different from the verifier in that it is concerned
// with a rich type hierarchy (TODO) usable in optimization and does not perform
@@ -39,6 +36,9 @@
// Computes the types for the method with SEA IR representation provided by @graph.
void ComputeTypes(SeaGraph* graph);
+ std::map<int, const Type*> GetTypeMap() const {
+ return type_map_;
+ }
// Returns true if @descriptor corresponds to a primitive type.
static bool IsPrimitiveDescriptor(char descriptor);
@@ -76,77 +76,6 @@
art::verifier::RegTypeCache* type_cache_;
const uint32_t method_access_flags_; // Method's access flags.
};
-
-// The TypeInferenceVisitor visits each instruction and computes its type taking into account
-// the current type of the operands. The type is stored in the visitor.
-// We may be better off by using a separate visitor type hierarchy that has return values
-// or that passes data as parameters, than to use fields to store information that should
-// in fact be returned after visiting each element. Ideally, I would prefer to use templates
-// to specify the returned value type, but I am not aware of a possible implementation
-// that does not horribly duplicate the visitor infrastructure code (version 1: no return value,
-// version 2: with template return value).
-class TypeInferenceVisitor: public IRVisitor {
- public:
- TypeInferenceVisitor(SeaGraph* graph, art::verifier::RegTypeCache* types):
- graph_(graph), type_cache_(types), crt_type_() { }
- void Initialize(SeaGraph* graph) { }
- // There are no type related actions to be performed on these classes.
- void Visit(SeaGraph* graph) { }
- void Visit(Region* region) { }
-
- void Visit(PhiInstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
- void Visit(SignatureNode* parameter) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- std::cout << "[TI] Visiting signature node:" << parameter->GetResultRegister() << std::endl;
- FunctionTypeInfo fti(graph_, type_cache_);
- std::vector<const Type*> arguments = fti.GetDeclaredArgumentTypes();
- crt_type_.clear();
- std::cout << "Pos:" << parameter->GetPositionInSignature() << "/" << arguments.size() <<std::endl;
- DCHECK_LT(parameter->GetPositionInSignature(), arguments.size())
- << "Signature node position not present in signature.";
- crt_type_.push_back(arguments.at(parameter->GetPositionInSignature()));
- }
- void Visit(InstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
- void Visit(ConstInstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
- void Visit(ReturnInstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
- void Visit(IfNeInstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
- void Visit(MoveResultInstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
- void Visit(InvokeStaticInstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
- void Visit(AddIntInstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
- void Visit(GotoInstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
- void Visit(IfEqzInstructionNode* instruction) {
- std::cout << "[TI] Visiting node:" << instruction->Id() << std::endl;
- }
-
- const Type* GetType() const {
- // TODO: Currently multiple defined types are not supported.
- if (crt_type_.size()>0) return crt_type_.at(0);
- return NULL;
- }
-
- protected:
- const SeaGraph* graph_;
- art::verifier::RegTypeCache* type_cache_;
- std::vector<const Type*> crt_type_; // Stored temporarily between two calls to Visit.
-};
-
} // namespace sea_ir
#endif // ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_H_
diff --git a/compiler/sea_ir/types/type_inference_visitor.cc b/compiler/sea_ir/types/type_inference_visitor.cc
new file mode 100644
index 0000000..8faa4d5
--- /dev/null
+++ b/compiler/sea_ir/types/type_inference_visitor.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 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 "sea_ir/types/type_inference_visitor.h"
+#include "sea_ir/types/type_inference.h"
+#include "sea_ir/sea.h"
+
+namespace sea_ir {
+
+void TypeInferenceVisitor::Visit(SignatureNode* parameter) {
+ std::cout << "[TI] Visiting signature node:" << parameter->GetResultRegister() << std::endl;
+ FunctionTypeInfo fti(graph_, type_cache_);
+ std::vector<const Type*> arguments = fti.GetDeclaredArgumentTypes();
+ crt_type_.clear();
+ DCHECK_LT(parameter->GetPositionInSignature(), arguments.size())
+ << "Signature node position not present in signature.";
+ crt_type_.push_back(arguments.at(parameter->GetPositionInSignature()));
+}
+
+} // namespace sea_ir
diff --git a/compiler/sea_ir/types/type_inference_visitor.h b/compiler/sea_ir/types/type_inference_visitor.h
new file mode 100644
index 0000000..9518c97
--- /dev/null
+++ b/compiler/sea_ir/types/type_inference_visitor.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 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_SEA_IR_TYPES_TYPE_INFERENCE_VISITOR_H_
+#define ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_VISITOR_H_
+
+
+#include "dex_file-inl.h"
+#include "sea_ir/visitor.h"
+#include "sea_ir/types/types.h"
+
+namespace sea_ir {
+
+// The TypeInferenceVisitor visits each instruction and computes its type taking into account
+// the current type of the operands. The type is stored in the visitor.
+// We may be better off by using a separate visitor type hierarchy that has return values
+// or that passes data as parameters, than to use fields to store information that should
+// in fact be returned after visiting each element. Ideally, I would prefer to use templates
+// to specify the returned value type, but I am not aware of a possible implementation
+// that does not horribly duplicate the visitor infrastructure code (version 1: no return value,
+// version 2: with template return value).
+class TypeInferenceVisitor: public IRVisitor {
+ public:
+ TypeInferenceVisitor(SeaGraph* graph, art::verifier::RegTypeCache* types):
+ graph_(graph), type_cache_(types), crt_type_() {
+ }
+ // There are no type related actions to be performed on these classes.
+ void Initialize(SeaGraph* graph) { }
+ void Visit(SeaGraph* graph) { }
+ void Visit(Region* region) { }
+
+ void Visit(PhiInstructionNode* instruction) { }
+ void Visit(SignatureNode* parameter) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void Visit(InstructionNode* instruction) { }
+ void Visit(ConstInstructionNode* instruction) { }
+ void Visit(ReturnInstructionNode* instruction) { }
+ void Visit(IfNeInstructionNode* instruction) { }
+ void Visit(MoveResultInstructionNode* instruction) { }
+ void Visit(InvokeStaticInstructionNode* instruction) { }
+ void Visit(AddIntInstructionNode* instruction) { }
+ void Visit(GotoInstructionNode* instruction) { }
+ void Visit(IfEqzInstructionNode* instruction) { }
+
+ const Type* GetType() const {
+ // TODO: Currently multiple defined types are not supported.
+ if (crt_type_.size()>0) return crt_type_.at(0);
+ return NULL;
+ }
+
+ protected:
+ const SeaGraph* const graph_;
+ art::verifier::RegTypeCache* type_cache_;
+ std::vector<const Type*> crt_type_; // Stored temporarily between two calls to Visit.
+};
+
+} // namespace sea_ir
+
+#endif // ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_VISITOR_H_
diff --git a/compiler/sea_ir/types/types.h b/compiler/sea_ir/types/types.h
new file mode 100644
index 0000000..8aa5d16
--- /dev/null
+++ b/compiler/sea_ir/types/types.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 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_SEA_IR_TYPES_TYPES_H_
+#define ART_COMPILER_SEA_IR_TYPES_TYPES_H_
+
+#include "verifier/reg_type.h"
+#include "verifier/reg_type_cache.h"
+
+namespace sea_ir {
+
+// TODO: Replace typedef with an actual class implementation when we have more types.
+typedef art::verifier::RegType Type;
+
+} // namespace sea_ir
+#endif // ART_COMPILER_SEA_IR_TYPES_TYPES_H_
diff --git a/compiler/sea_ir/visitor.h b/compiler/sea_ir/visitor.h
index f4cecd8..ffb073e 100644
--- a/compiler/sea_ir/visitor.h
+++ b/compiler/sea_ir/visitor.h
@@ -40,7 +40,7 @@
class IRVisitor {
public:
- explicit IRVisitor():ordered_regions_() { }
+ explicit IRVisitor(): ordered_regions_() { }
virtual void Initialize(SeaGraph* graph) = 0;
virtual void Visit(SeaGraph* graph) = 0;
virtual void Visit(Region* region) = 0;