diff options
author | Dragos Sbirlea <dragoss@google.com> | 2013-08-01 15:38:43 -0700 |
---|---|---|
committer | Dragos Sbirlea <dragoss@google.com> | 2013-08-05 10:21:12 -0700 |
commit | 6447919b5ee8d34c4767f908c7cd7223c224544c (patch) | |
tree | f5931682be1b8e618051b3b2b4150c06aea6825e /compiler/sea_ir | |
parent | 3d1b8c1931fcc7e1d13a19b09e61a69fafb77d3b (diff) | |
download | android_art-6447919b5ee8d34c4767f908c7cd7223c224544c.tar.gz android_art-6447919b5ee8d34c4767f908c7cd7223c224544c.tar.bz2 android_art-6447919b5ee8d34c4767f908c7cd7223c224544c.zip |
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
Diffstat (limited to 'compiler/sea_ir')
-rw-r--r-- | compiler/sea_ir/code_gen.h | 2 | ||||
-rw-r--r-- | compiler/sea_ir/debug/dot_gen.cc | 136 | ||||
-rw-r--r-- | compiler/sea_ir/debug/dot_gen.h | 116 | ||||
-rw-r--r-- | compiler/sea_ir/frontend.cc | 13 | ||||
-rw-r--r-- | compiler/sea_ir/instruction_nodes.h | 40 | ||||
-rw-r--r-- | compiler/sea_ir/sea.cc | 118 | ||||
-rw-r--r-- | compiler/sea_ir/sea.h | 59 | ||||
-rw-r--r-- | compiler/sea_ir/sea_node.h | 4 | ||||
-rw-r--r-- | compiler/sea_ir/types/type_inference.cc | 14 | ||||
-rw-r--r-- | compiler/sea_ir/types/type_inference.h | 83 | ||||
-rw-r--r-- | compiler/sea_ir/types/type_inference_visitor.cc | 33 | ||||
-rw-r--r-- | compiler/sea_ir/types/type_inference_visitor.h | 71 | ||||
-rw-r--r-- | compiler/sea_ir/types/types.h | 29 | ||||
-rw-r--r-- | compiler/sea_ir/visitor.h | 2 |
14 files changed, 448 insertions, 272 deletions
diff --git a/compiler/sea_ir/code_gen.h b/compiler/sea_ir/code_gen.h index f656453559..5fea79a0a2 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 0000000000..9e071e16cd --- /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 0000000000..520d9df2ec --- /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 cc49ea58f2..951273c304 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 @@ static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler, // 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 1b81e9add3..fb1f83f076 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 @@ class InstructionNode: public SeaNode { // 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 @@ class InstructionNode: public SeaNode { } 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 @@ class InstructionNode: public SeaNode { 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 @@ class UnnamedConstInstructionNode: public ConstInstructionNode { 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 @@ class UnnamedConstInstructionNode: public ConstInstructionNode { 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 IfNeInstructionNode: public InstructionNode { 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 @@ class AddIntLitInstructionNode: public AddIntInstructionNode { 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 585b2aa83c..cb159e1105 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 @@ void IRVisitor::Traverse(Region* region) { 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 @@ SeaGraph* SeaGraph::GetCurrentGraph(const art::DexFile& dex_file) { 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 @@ void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, } r = nextRegion; } + r->AddChild(node); } i += inst->SizeInCodeUnits(); } @@ -433,8 +418,8 @@ void SeaGraph::CompileMethod(const art::DexFile::CodeItem* code_item, uint32_t c // 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 @@ void SeaGraph::AddRegion(Region* r) { 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 @@ SeaNode* Region::GetLastChild() const { 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 @@ std::vector<InstructionNode*> InstructionNode::Create(const art::Instruction* in 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 @@ std::vector<int> InstructionNode::GetDefinitions() const { 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 @@ std::vector<int> InstructionNode::GetUses() { } 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 efdbb3b135..3a8efcde3e 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 @@ enum RegionNumbering { 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 @@ class SignatureNode: public InstructionNode { 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 @@ class SignatureNode: public InstructionNode { } 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 @@ class Region : public SeaNode { 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 @@ class SeaGraph: IVisitable { 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 @@ class SeaGraph: IVisitable { 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 @@ class SeaGraph: IVisitable { // 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 c13e5d6aba..98bbe9e36e 100644 --- a/compiler/sea_ir/sea_node.h +++ b/compiler/sea_ir/sea_node.h @@ -56,10 +56,6 @@ class SeaNode: public IVisitable { 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 ad81310468..78888f3d43 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 @@ void TypeInference::ComputeTypes(SeaGraph* graph) SHARED_LOCKS_REQUIRED(Locks::m // 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 @@ void TypeInference::ComputeTypes(SeaGraph* graph) SHARED_LOCKS_REQUIRED(Locks::m 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 1c0d42ec29..9014c96e91 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" -namespace sea_ir { +#include "sea_ir/types/types.h" -typedef art::verifier::RegType Type; +namespace sea_ir { +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 @@ class TypeInference { // 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 @@ class FunctionTypeInfo { 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 0000000000..8faa4d5f83 --- /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 0000000000..9518c975e7 --- /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 0000000000..8aa5d161ef --- /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 f4cecd8519..ffb073ece9 100644 --- a/compiler/sea_ir/visitor.h +++ b/compiler/sea_ir/visitor.h @@ -40,7 +40,7 @@ class IfEqzInstructionNode; 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; |