diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/Android.mk | 2 | ||||
| -rw-r--r-- | compiler/dex/bb_optimizations.cc | 55 | ||||
| -rw-r--r-- | compiler/dex/bb_optimizations.h | 175 | ||||
| -rw-r--r-- | compiler/dex/frontend.cc | 4 | ||||
| -rw-r--r-- | compiler/dex/local_value_numbering_test.cc | 1 | ||||
| -rw-r--r-- | compiler/dex/mir_graph.cc | 162 | ||||
| -rw-r--r-- | compiler/dex/mir_graph.h | 28 | ||||
| -rw-r--r-- | compiler/dex/mir_optimization_test.cc | 1 | ||||
| -rw-r--r-- | compiler/dex/pass.h | 94 | ||||
| -rw-r--r-- | compiler/dex/pass_driver.h | 156 | ||||
| -rw-r--r-- | compiler/dex/pass_driver_me.cc | 170 | ||||
| -rw-r--r-- | compiler/dex/pass_driver_me.h | 45 | ||||
| -rw-r--r-- | compiler/dex/pass_me.h | 101 | ||||
| -rw-r--r-- | compiler/dex/quick/codegen_util.cc | 28 | ||||
| -rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.cc | 11 | ||||
| -rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 1 | ||||
| -rw-r--r-- | compiler/dex/ssa_transformation.cc | 3 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 38 |
18 files changed, 854 insertions, 221 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index e9010c9470..cb9e41a4fb 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -59,8 +59,8 @@ LIBART_COMPILER_SRC_FILES := \ dex/mir_field_info.cc \ dex/mir_method_info.cc \ dex/mir_optimization.cc \ - dex/pass_driver.cc \ dex/bb_optimizations.cc \ + dex/pass_driver_me.cc \ dex/bit_vector_block_iterator.cc \ dex/frontend.cc \ dex/mir_graph.cc \ diff --git a/compiler/dex/bb_optimizations.cc b/compiler/dex/bb_optimizations.cc index abfa7a7eb7..1852f805f4 100644 --- a/compiler/dex/bb_optimizations.cc +++ b/compiler/dex/bb_optimizations.cc @@ -23,7 +23,13 @@ namespace art { /* * Code Layout pass implementation start. */ -bool CodeLayout::WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { +bool CodeLayout::Worker(const PassDataHolder* data) const { + DCHECK(data != nullptr); + const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data); + CompilationUnit* cUnit = pass_me_data_holder->c_unit; + DCHECK(cUnit != nullptr); + BasicBlock* bb = pass_me_data_holder->bb; + DCHECK(bb != nullptr); cUnit->mir_graph->LayoutBlocks(bb); // No need of repeating, so just return false. return false; @@ -32,13 +38,22 @@ bool CodeLayout::WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { /* * SSATransformation pass implementation start. */ -bool SSATransformation::WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { +bool SSATransformation::Worker(const PassDataHolder* data) const { + DCHECK(data != nullptr); + const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data); + CompilationUnit* cUnit = pass_me_data_holder->c_unit; + DCHECK(cUnit != nullptr); + BasicBlock* bb = pass_me_data_holder->bb; + DCHECK(bb != nullptr); cUnit->mir_graph->InsertPhiNodeOperands(bb); // No need of repeating, so just return false. return false; } -void SSATransformation::End(CompilationUnit* cUnit) const { +void SSATransformation::End(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); // Verify the dataflow information after the pass. if (cUnit->enable_debug & (1 << kDebugVerifyDataflow)) { cUnit->mir_graph->VerifyDataflow(); @@ -48,7 +63,13 @@ void SSATransformation::End(CompilationUnit* cUnit) const { /* * ConstantPropagation pass implementation start */ -bool ConstantPropagation::WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { +bool ConstantPropagation::Worker(const PassDataHolder* data) const { + DCHECK(data != nullptr); + const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data); + CompilationUnit* cUnit = pass_me_data_holder->c_unit; + DCHECK(cUnit != nullptr); + BasicBlock* bb = pass_me_data_holder->bb; + DCHECK(bb != nullptr); cUnit->mir_graph->DoConstantPropagation(bb); // No need of repeating, so just return false. return false; @@ -57,7 +78,10 @@ bool ConstantPropagation::WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb /* * MethodUseCount pass implementation start. */ -bool MethodUseCount::Gate(const CompilationUnit* cUnit) const { +bool MethodUseCount::Gate(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); // First initialize the data. cUnit->mir_graph->InitializeMethodUses(); @@ -67,7 +91,13 @@ bool MethodUseCount::Gate(const CompilationUnit* cUnit) const { return res; } -bool MethodUseCount::WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { +bool MethodUseCount::Worker(const PassDataHolder* data) const { + DCHECK(data != nullptr); + const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data); + CompilationUnit* cUnit = pass_me_data_holder->c_unit; + DCHECK(cUnit != nullptr); + BasicBlock* bb = pass_me_data_holder->bb; + DCHECK(bb != nullptr); cUnit->mir_graph->CountUses(bb); // No need of repeating, so just return false. return false; @@ -76,7 +106,13 @@ bool MethodUseCount::WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) con /* * BasicBlock Combine pass implementation start. */ -bool BBCombine::WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { +bool BBCombine::Worker(const PassDataHolder* data) const { + DCHECK(data != nullptr); + const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data); + CompilationUnit* cUnit = pass_me_data_holder->c_unit; + DCHECK(cUnit != nullptr); + BasicBlock* bb = pass_me_data_holder->bb; + DCHECK(bb != nullptr); cUnit->mir_graph->CombineBlocks(bb); // No need of repeating, so just return false. @@ -86,7 +122,10 @@ bool BBCombine::WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { /* * BasicBlock Optimization pass implementation start. */ -void BBOptimizations::Start(CompilationUnit* cUnit) const { +void BBOptimizations::Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); /* * This pass has a different ordering depEnding on the suppress exception, * so do the pass here for now: diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h index 6d500a56ec..43dcdf4504 100644 --- a/compiler/dex/bb_optimizations.h +++ b/compiler/dex/bb_optimizations.h @@ -18,7 +18,7 @@ #define ART_COMPILER_DEX_BB_OPTIMIZATIONS_H_ #include "compiler_internals.h" -#include "pass.h" +#include "pass_me.h" namespace art { @@ -26,16 +26,22 @@ namespace art { * @class CacheFieldLoweringInfo * @brief Cache the lowering info for fields used by IGET/IPUT/SGET/SPUT insns. */ -class CacheFieldLoweringInfo : public Pass { +class CacheFieldLoweringInfo : public PassME { public: - CacheFieldLoweringInfo() : Pass("CacheFieldLoweringInfo", kNoNodes) { + CacheFieldLoweringInfo() : PassME("CacheFieldLoweringInfo", kNoNodes) { } - void Start(CompilationUnit* cUnit) const { + void Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->DoCacheFieldLoweringInfo(); } - bool Gate(const CompilationUnit *cUnit) const { + bool Gate(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); return cUnit->mir_graph->HasFieldAccess(); } }; @@ -44,16 +50,22 @@ class CacheFieldLoweringInfo : public Pass { * @class CacheMethodLoweringInfo * @brief Cache the lowering info for methods called by INVOKEs. */ -class CacheMethodLoweringInfo : public Pass { +class CacheMethodLoweringInfo : public PassME { public: - CacheMethodLoweringInfo() : Pass("CacheMethodLoweringInfo", kNoNodes) { + CacheMethodLoweringInfo() : PassME("CacheMethodLoweringInfo", kNoNodes) { } - void Start(CompilationUnit* cUnit) const { + void Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->DoCacheMethodLoweringInfo(); } - bool Gate(const CompilationUnit *cUnit) const { + bool Gate(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); return cUnit->mir_graph->HasInvokes(); } }; @@ -62,26 +74,41 @@ class CacheMethodLoweringInfo : public Pass { * @class CallInlining * @brief Perform method inlining pass. */ -class CallInlining : public Pass { +class CallInlining : public PassME { public: - CallInlining() : Pass("CallInlining") { + CallInlining() : PassME("CallInlining") { } - bool Gate(const CompilationUnit* cUnit) const { + bool Gate(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); return cUnit->mir_graph->InlineCallsGate(); } - void Start(CompilationUnit* cUnit) const { + void Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->InlineCallsStart(); } - bool WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { + bool Worker(const PassDataHolder* data) const { + DCHECK(data != nullptr); + const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data); + CompilationUnit* cUnit = pass_me_data_holder->c_unit; + DCHECK(cUnit != nullptr); + BasicBlock* bb = pass_me_data_holder->bb; + DCHECK(bb != nullptr); cUnit->mir_graph->InlineCalls(bb); // No need of repeating, so just return false. return false; } - void End(CompilationUnit* cUnit) const { + void End(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->InlineCallsEnd(); } }; @@ -90,48 +117,57 @@ class CallInlining : public Pass { * @class CodeLayout * @brief Perform the code layout pass. */ -class CodeLayout : public Pass { +class CodeLayout : public PassME { public: - CodeLayout() : Pass("CodeLayout", "2_post_layout_cfg") { + CodeLayout() : PassME("CodeLayout", "2_post_layout_cfg") { } - void Start(CompilationUnit* cUnit) const { + void Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->VerifyDataflow(); } - bool WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const; + bool Worker(const PassDataHolder* data) const; }; /** * @class SSATransformation * @brief Perform an SSA representation pass on the CompilationUnit. */ -class SSATransformation : public Pass { +class SSATransformation : public PassME { public: - SSATransformation() : Pass("SSATransformation", kPreOrderDFSTraversal, "3_post_ssa_cfg") { + SSATransformation() : PassME("SSATransformation", kPreOrderDFSTraversal, "3_post_ssa_cfg") { } - bool WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const; + bool Worker(const PassDataHolder* data) const; - void Start(CompilationUnit* cUnit) const { + void Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->InitializeSSATransformation(); } - void End(CompilationUnit* cUnit) const; + void End(const PassDataHolder* data) const; }; /** * @class ConstantPropagation * @brief Perform a constant propagation pass. */ -class ConstantPropagation : public Pass { +class ConstantPropagation : public PassME { public: - ConstantPropagation() : Pass("ConstantPropagation") { + ConstantPropagation() : PassME("ConstantPropagation") { } - bool WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const; + bool Worker(const PassDataHolder* data) const; - void Start(CompilationUnit* cUnit) const { + void Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->InitializeConstantPropagation(); } }; @@ -140,12 +176,15 @@ class ConstantPropagation : public Pass { * @class InitRegLocations * @brief Initialize Register Locations. */ -class InitRegLocations : public Pass { +class InitRegLocations : public PassME { public: - InitRegLocations() : Pass("InitRegLocation", kNoNodes) { + InitRegLocations() : PassME("InitRegLocation", kNoNodes) { } - void Start(CompilationUnit* cUnit) const { + void Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->InitRegLocations(); } }; @@ -154,53 +193,77 @@ class InitRegLocations : public Pass { * @class MethodUseCount * @brief Count the register uses of the method */ -class MethodUseCount : public Pass { +class MethodUseCount : public PassME { public: - MethodUseCount() : Pass("UseCount") { + MethodUseCount() : PassME("UseCount") { } - bool WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const; + bool Worker(const PassDataHolder* data) const; - bool Gate(const CompilationUnit* cUnit) const; + bool Gate(const PassDataHolder* data) const; }; /** * @class NullCheckEliminationAndTypeInference * @brief Null check elimination and type inference. */ -class NullCheckEliminationAndTypeInference : public Pass { +class NullCheckEliminationAndTypeInference : public PassME { public: NullCheckEliminationAndTypeInference() - : Pass("NCE_TypeInference", kRepeatingPreOrderDFSTraversal, "4_post_nce_cfg") { + : PassME("NCE_TypeInference", kRepeatingPreOrderDFSTraversal, "4_post_nce_cfg") { } - void Start(CompilationUnit* cUnit) const { + void Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->EliminateNullChecksAndInferTypesStart(); } - bool WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { + bool Worker(const PassDataHolder* data) const { + DCHECK(data != nullptr); + const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data); + CompilationUnit* cUnit = pass_me_data_holder->c_unit; + DCHECK(cUnit != nullptr); + BasicBlock* bb = pass_me_data_holder->bb; + DCHECK(bb != nullptr); return cUnit->mir_graph->EliminateNullChecksAndInferTypes(bb); } - void End(CompilationUnit* cUnit) const { + void End(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->EliminateNullChecksAndInferTypesEnd(); } }; -class ClassInitCheckElimination : public Pass { +class ClassInitCheckElimination : public PassME { public: - ClassInitCheckElimination() : Pass("ClInitCheckElimination", kRepeatingPreOrderDFSTraversal) { + ClassInitCheckElimination() : PassME("ClInitCheckElimination", kRepeatingPreOrderDFSTraversal) { } - bool Gate(const CompilationUnit* cUnit) const { + bool Gate(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); return cUnit->mir_graph->EliminateClassInitChecksGate(); } - bool WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const { + bool Worker(const PassDataHolder* data) const { + DCHECK(data != nullptr); + const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data); + CompilationUnit* cUnit = pass_me_data_holder->c_unit; + DCHECK(cUnit != nullptr); + BasicBlock* bb = pass_me_data_holder->bb; + DCHECK(bb != nullptr); return cUnit->mir_graph->EliminateClassInitChecks(bb); } - void End(CompilationUnit* cUnit) const { + void End(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); cUnit->mir_graph->EliminateClassInitChecksEnd(); } }; @@ -209,32 +272,38 @@ class ClassInitCheckElimination : public Pass { * @class NullCheckEliminationAndTypeInference * @brief Null check elimination and type inference. */ -class BBCombine : public Pass { +class BBCombine : public PassME { public: - BBCombine() : Pass("BBCombine", kPreOrderDFSTraversal, "5_post_bbcombine_cfg") { + BBCombine() : PassME("BBCombine", kPreOrderDFSTraversal, "5_post_bbcombine_cfg") { } - bool Gate(const CompilationUnit* cUnit) const { + bool Gate(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); return ((cUnit->disable_opt & (1 << kSuppressExceptionEdges)) != 0); } - bool WalkBasicBlocks(CompilationUnit* cUnit, BasicBlock* bb) const; + bool Worker(const PassDataHolder* data) const; }; /** * @class BasicBlock Optimizations * @brief Any simple BasicBlock optimization can be put here. */ -class BBOptimizations : public Pass { +class BBOptimizations : public PassME { public: - BBOptimizations() : Pass("BBOptimizations", kNoNodes, "5_post_bbo_cfg") { + BBOptimizations() : PassME("BBOptimizations", kNoNodes, "5_post_bbo_cfg") { } - bool Gate(const CompilationUnit* cUnit) const { + bool Gate(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); return ((cUnit->disable_opt & (1 << kBBOpt)) == 0); } - void Start(CompilationUnit* cUnit) const; + void Start(const PassDataHolder* data) const; }; } // namespace art diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 77b5057538..ec2556b206 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -21,7 +21,7 @@ #include "dataflow_iterator-inl.h" #include "leb128.h" #include "mirror/object.h" -#include "pass_driver.h" +#include "pass_driver_me.h" #include "runtime.h" #include "base/logging.h" #include "base/timing_logger.h" @@ -924,7 +924,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver, } /* Create the pass driver and launch it */ - PassDriver pass_driver(&cu); + PassDriverME pass_driver(&cu); pass_driver.Launch(); if (cu.enable_debug & (1 << kDebugDumpCheckStats)) { diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc index 2b1c4207e8..e56e0160ca 100644 --- a/compiler/dex/local_value_numbering_test.cc +++ b/compiler/dex/local_value_numbering_test.cc @@ -144,7 +144,6 @@ class LocalValueNumberingTest : public testing::Test { mir->ssa_rep->fp_def = nullptr; // Not used by LVN. mir->dalvikInsn.opcode = def->opcode; mir->offset = i; // LVN uses offset only for debug output - mir->width = 1u; // Not used by LVN. mir->optimization_flags = 0u; if (i != 0u) { diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index ba4224ea78..4ba66771b4 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -196,7 +196,7 @@ BasicBlock* MIRGraph::SplitBlock(DexOffset code_offset, } orig_block->last_mir_insn = prev; - prev->next = NULL; + prev->next = nullptr; /* * Update the immediate predecessor block pointer so that outgoing edges @@ -220,6 +220,7 @@ BasicBlock* MIRGraph::SplitBlock(DexOffset code_offset, while (p != bottom_block->last_mir_insn) { p = p->next; DCHECK(p != nullptr); + p->bb = bottom_block->id; int opcode = p->dalvikInsn.opcode; /* * Some messiness here to ensure that we only enter real opcodes and only the @@ -543,7 +544,7 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, DexOffse new_block->start_offset = insn->offset; cur_block->fall_through = new_block->id; new_block->predecessors->Insert(cur_block->id); - MIR* new_insn = static_cast<MIR*>(arena_->Alloc(sizeof(MIR), kArenaAllocMIR)); + MIR* new_insn = NewMIR(); *new_insn = *insn; insn->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpCheck); @@ -629,11 +630,10 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ /* Parse all instructions and put them into containing basic blocks */ while (code_ptr < code_end) { - MIR *insn = static_cast<MIR *>(arena_->Alloc(sizeof(MIR), kArenaAllocMIR)); + MIR *insn = NewMIR(); insn->offset = current_offset_; insn->m_unit_index = current_method_; int width = ParseInsn(code_ptr, &insn->dalvikInsn); - insn->width = width; Instruction::Code opcode = insn->dalvikInsn.opcode; if (opcode_count_ != NULL) { opcode_count_[static_cast<int>(opcode)]++; @@ -924,7 +924,7 @@ void MIRGraph::DumpCFG(const char* dir_prefix, bool all_blocks, const char *suff fclose(file); } -/* Insert an MIR instruction to the end of a basic block */ +/* Insert an MIR instruction to the end of a basic block. */ void BasicBlock::AppendMIR(MIR* mir) { if (first_mir_insn == nullptr) { DCHECK(last_mir_insn == nullptr); @@ -935,9 +935,11 @@ void BasicBlock::AppendMIR(MIR* mir) { mir->next = nullptr; last_mir_insn = mir; } + + mir->bb = id; } -/* Insert an MIR instruction to the head of a basic block */ +/* Insert an MIR instruction to the head of a basic block. */ void BasicBlock::PrependMIR(MIR* mir) { if (first_mir_insn == nullptr) { DCHECK(last_mir_insn == nullptr); @@ -947,17 +949,53 @@ void BasicBlock::PrependMIR(MIR* mir) { mir->next = first_mir_insn; first_mir_insn = mir; } + + mir->bb = id; } -/* Insert a MIR instruction after the specified MIR */ +/* Insert a MIR instruction after the specified MIR. */ void BasicBlock::InsertMIRAfter(MIR* current_mir, MIR* new_mir) { new_mir->next = current_mir->next; current_mir->next = new_mir; if (last_mir_insn == current_mir) { - /* Is the last MIR in the block */ + /* Is the last MIR in the block? */ last_mir_insn = new_mir; } + + new_mir->bb = id; +} + +MIR* BasicBlock::FindPreviousMIR(MIR* mir) { + MIR* current = first_mir_insn; + + while (current != nullptr) { + MIR* next = current->next; + + if (next == mir) { + return current; + } + + current = next; + } + + return nullptr; +} + +void BasicBlock::InsertMIRBefore(MIR* current_mir, MIR* new_mir) { + if (first_mir_insn == current_mir) { + /* Is the first MIR in the block? */ + first_mir_insn = new_mir; + new_mir->bb = id; + } + + MIR* prev = FindPreviousMIR(current_mir); + + if (prev != nullptr) { + prev->next = new_mir; + new_mir->next = current_mir; + new_mir->bb = id; + } } MIR* BasicBlock::GetNextUnconditionalMir(MIRGraph* mir_graph, MIR* current) { @@ -1240,6 +1278,12 @@ CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, return info; } +// Allocate a new MIR. +MIR* MIRGraph::NewMIR() { + MIR* mir = new (arena_) MIR(); + return mir; +} + // Allocate a new basic block. BasicBlock* MIRGraph::NewMemBB(BBType block_type, int block_id) { BasicBlock* bb = static_cast<BasicBlock*>(arena_->Alloc(sizeof(BasicBlock), @@ -1344,4 +1388,106 @@ BasicBlock* ChildBlockIterator::Next() { return nullptr; } +bool BasicBlock::RemoveMIR(MIR* mir) { + if (mir == nullptr) { + return false; + } + + // Find the MIR, and the one before it if they exist. + MIR* current = nullptr; + MIR* prev = nullptr; + + // Find the mir we are looking for. + for (current = first_mir_insn; current != nullptr; prev = current, current = current->next) { + if (current == mir) { + break; + } + } + + // Did we find it? + if (current != nullptr) { + MIR* next = current->next; + + // Just update the links of prev and next and current is almost gone. + if (prev != nullptr) { + prev->next = next; + } + + // Exceptions are if first or last mirs are invoke. + if (first_mir_insn == current) { + first_mir_insn = next; + } + + if (last_mir_insn == current) { + last_mir_insn = prev; + } + + // Found it and removed it. + return true; + } + + // We did not find it. + return false; +} + +MIR* MIR::Copy(MIRGraph* mir_graph) { + MIR* res = mir_graph->NewMIR(); + *res = *this; + + // Remove links + res->next = nullptr; + res->bb = NullBasicBlockId; + res->ssa_rep = nullptr; + + return res; +} + +MIR* MIR::Copy(CompilationUnit* c_unit) { + return Copy(c_unit->mir_graph.get()); +} + +uint32_t SSARepresentation::GetStartUseIndex(Instruction::Code opcode) { + // Default result. + int res = 0; + + // We are basically setting the iputs to their igets counterparts. + switch (opcode) { + case Instruction::IPUT: + case Instruction::IPUT_OBJECT: + case Instruction::IPUT_BOOLEAN: + case Instruction::IPUT_BYTE: + case Instruction::IPUT_CHAR: + case Instruction::IPUT_SHORT: + case Instruction::IPUT_QUICK: + case Instruction::IPUT_OBJECT_QUICK: + case Instruction::APUT: + case Instruction::APUT_OBJECT: + case Instruction::APUT_BOOLEAN: + case Instruction::APUT_BYTE: + case Instruction::APUT_CHAR: + case Instruction::APUT_SHORT: + case Instruction::SPUT: + case Instruction::SPUT_OBJECT: + case Instruction::SPUT_BOOLEAN: + case Instruction::SPUT_BYTE: + case Instruction::SPUT_CHAR: + case Instruction::SPUT_SHORT: + // Skip the VR containing what to store. + res = 1; + break; + case Instruction::IPUT_WIDE: + case Instruction::IPUT_WIDE_QUICK: + case Instruction::APUT_WIDE: + case Instruction::SPUT_WIDE: + // Skip the two VRs containing what to store. + res = 2; + break; + default: + // Do nothing in the general case. + break; + } + + return res; +} + } // namespace art diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 11d2fbe039..0bb82659a2 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -242,6 +242,8 @@ struct SSARepresentation { bool* fp_use; int32_t* defs; bool* fp_def; + + static uint32_t GetStartUseIndex(Instruction::Code opcode); }; /* @@ -261,12 +263,15 @@ struct MIR { uint32_t vC; uint32_t arg[5]; /* vC/D/E/F/G in invoke or filled-new-array */ Instruction::Code opcode; + + explicit DecodedInstruction():vA(0), vB(0), vB_wide(0), vC(0), opcode(Instruction::NOP) { + } } dalvikInsn; - uint16_t width; // Note: width can include switch table or fill array data. NarrowDexOffset offset; // Offset of the instruction in code units. uint16_t optimization_flags; int16_t m_unit_index; // From which method was this MIR included + BasicBlockId bb; MIR* next; SSARepresentation* ssa_rep; union { @@ -285,6 +290,23 @@ struct MIR { // INVOKE data index, points to MIRGraph::method_lowering_infos_. uint32_t method_lowering_info; } meta; + + explicit MIR():offset(0), optimization_flags(0), m_unit_index(0), bb(NullBasicBlockId), + next(nullptr), ssa_rep(nullptr) { + memset(&meta, 0, sizeof(meta)); + } + + uint32_t GetStartUseIndex() const { + return SSARepresentation::GetStartUseIndex(dalvikInsn.opcode); + } + + MIR* Copy(CompilationUnit *c_unit); + MIR* Copy(MIRGraph* mir_Graph); + + static void* operator new(size_t size, ArenaAllocator* arena) { + return arena->Alloc(sizeof(MIR), kArenaAllocMIR); + } + static void operator delete(void* p) {} // Nop. }; struct SuccessorBlockInfo; @@ -319,6 +341,8 @@ struct BasicBlock { void AppendMIR(MIR* mir); void PrependMIR(MIR* mir); void InsertMIRAfter(MIR* current_mir, MIR* new_mir); + void InsertMIRBefore(MIR* current_mir, MIR* new_mir); + MIR* FindPreviousMIR(MIR* mir); /** * @brief Used to obtain the next MIR that follows unconditionally. @@ -329,6 +353,7 @@ struct BasicBlock { * @return Returns the following MIR if one can be found. */ MIR* GetNextUnconditionalMir(MIRGraph* mir_graph, MIR* current); + bool RemoveMIR(MIR* mir); }; /* @@ -836,6 +861,7 @@ class MIRGraph { void DumpMIRGraph(); CallInfo* NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, bool is_range); BasicBlock* NewMemBB(BBType block_type, int block_id); + MIR* NewMIR(); MIR* AdvanceMIR(BasicBlock** p_bb, MIR* mir); BasicBlock* NextDominatedBlock(BasicBlock* bb); bool LayoutBlocks(BasicBlock* bb); diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc index 891d9fb7ea..86092b6e3d 100644 --- a/compiler/dex/mir_optimization_test.cc +++ b/compiler/dex/mir_optimization_test.cc @@ -170,7 +170,6 @@ class ClassInitCheckEliminationTest : public testing::Test { } mir->ssa_rep = nullptr; mir->offset = 2 * i; // All insns need to be at least 2 code units long. - mir->width = 2u; mir->optimization_flags = 0u; merged_df_flags |= MIRGraph::GetDataFlowAttributes(def->opcode); } diff --git a/compiler/dex/pass.h b/compiler/dex/pass.h index 9457d5be76..ac22294811 100644 --- a/compiler/dex/pass.h +++ b/compiler/dex/pass.h @@ -19,49 +19,21 @@ #include <string> +#include "base/macros.h" namespace art { -// Forward declarations. -struct BasicBlock; -struct CompilationUnit; -class Pass; - -/** - * @brief OptimizationFlag is an enumeration to perform certain tasks for a given pass. - * @details Each enum should be a power of 2 to be correctly used. - */ -enum OptimizationFlag { -}; - -enum DataFlowAnalysisMode { - kAllNodes = 0, /**< @brief All nodes. */ - kPreOrderDFSTraversal, /**< @brief Depth-First-Search / Pre-Order. */ - kRepeatingPreOrderDFSTraversal, /**< @brief Depth-First-Search / Repeating Pre-Order. */ - kReversePostOrderDFSTraversal, /**< @brief Depth-First-Search / Reverse Post-Order. */ - kRepeatingPostOrderDFSTraversal, /**< @brief Depth-First-Search / Repeating Post-Order. */ - kRepeatingReversePostOrderDFSTraversal, /**< @brief Depth-First-Search / Repeating Reverse Post-Order. */ - kPostOrderDOMTraversal, /**< @brief Dominator tree / Post-Order. */ - kNoNodes, /**< @brief Skip BasicBlock traversal. */ +// Empty Pass Data Class, can be extended by any pass extending the base Pass class. +class PassDataHolder { }; /** * @class Pass - * @brief Pass is the Pass structure for the optimizations. - * @details The following structure has the different optimization passes that we are going to do. + * @brief Base Pass class, can be extended to perform a more defined way of doing the work call. */ class Pass { public: - explicit Pass(const char* name, DataFlowAnalysisMode type = kAllNodes, - unsigned int flags = 0u, const char* dump = "") - : pass_name_(name), traversal_type_(type), flags_(flags), dump_cfg_folder_(dump) { - } - - Pass(const char* name, DataFlowAnalysisMode type, const char* dump) - : pass_name_(name), traversal_type_(type), flags_(0), dump_cfg_folder_(dump) { - } - - Pass(const char* name, const char* dump) - : pass_name_(name), traversal_type_(kAllNodes), flags_(0), dump_cfg_folder_(dump) { + explicit Pass(const char* name) + : pass_name_(name) { } virtual ~Pass() { @@ -71,59 +43,42 @@ class Pass { return pass_name_; } - virtual DataFlowAnalysisMode GetTraversal() const { - return traversal_type_; - } - - virtual bool GetFlag(OptimizationFlag flag) const { - return (flags_ & flag); - } - - const char* GetDumpCFGFolder() const { - return dump_cfg_folder_; - } - /** * @brief Gate for the pass: determines whether to execute the pass or not considering a CompilationUnit - * @param c_unit the CompilationUnit. - * @return whether or not to execute the pass + * @param data the PassDataHolder. + * @return whether or not to execute the pass. */ - virtual bool Gate(const CompilationUnit* c_unit) const { + virtual bool Gate(const PassDataHolder* data) const { // Unused parameter. - UNUSED(c_unit); + UNUSED(data); // Base class says yes. return true; } /** - * @brief Start of the pass: called before the WalkBasicBlocks function - * @param c_unit the considered CompilationUnit. + * @brief Start of the pass: called before the Worker function. */ - virtual void Start(CompilationUnit* c_unit) const { + virtual void Start(const PassDataHolder* data) const { // Unused parameter. - UNUSED(c_unit); + UNUSED(data); } /** - * @brief End of the pass: called after the WalkBasicBlocks function - * @param c_unit the considered CompilationUnit. + * @brief End of the pass: called after the WalkBasicBlocks function. */ - virtual void End(CompilationUnit* c_unit) const { + virtual void End(const PassDataHolder* data) const { // Unused parameter. - UNUSED(c_unit); + UNUSED(data); } /** - * @brief Actually walk the BasicBlocks following a particular traversal type. - * @param c_unit the CompilationUnit. - * @param bb the BasicBlock. + * @param data the object containing data necessary for the pass. * @return whether or not there is a change when walking the BasicBlock */ - virtual bool WalkBasicBlocks(CompilationUnit* c_unit, BasicBlock* bb) const { - // Unused parameters. - UNUSED(c_unit); - UNUSED(bb); + virtual bool Worker(const PassDataHolder* data) const { + // Unused parameter. + UNUSED(data); // BasicBlock did not change. return false; @@ -133,15 +88,6 @@ class Pass { /** @brief The pass name: used for searching for a pass when running a particular pass or debugging. */ const char* const pass_name_; - /** @brief Type of traversal: determines the order to execute the pass on the BasicBlocks. */ - const DataFlowAnalysisMode traversal_type_; - - /** @brief Flags for additional directives: used to determine if a particular clean-up is necessary post pass. */ - const unsigned int flags_; - - /** @brief CFG Dump Folder: what sub-folder to use for dumping the CFGs post pass. */ - const char* const dump_cfg_folder_; - private: // In order to make the all passes not copy-friendly. DISALLOW_COPY_AND_ASSIGN(Pass); diff --git a/compiler/dex/pass_driver.h b/compiler/dex/pass_driver.h index 2b7196e187..aa0d1ae462 100644 --- a/compiler/dex/pass_driver.h +++ b/compiler/dex/pass_driver.h @@ -22,77 +22,169 @@ #include "safe_map.h" // Forward Declarations. -class CompilationUnit; class Pass; - +class PassDriver; namespace art { +/** + * @brief Helper function to create a single instance of a given Pass and can be shared across + * the threads. + */ +template <typename PassType> +const Pass* GetPassInstance() { + static const PassType pass; + return &pass; +} + +// Empty holder for the constructor. +class PassDriverDataHolder { +}; /** * @class PassDriver - * @brief PassDriver is the wrapper around all Pass instances in order to execute them from the Middle-End + * @brief PassDriver is the wrapper around all Pass instances in order to execute them */ +template <typename PassDriverType> class PassDriver { public: - explicit PassDriver(CompilationUnit* cu, bool create_default_passes = true); + explicit PassDriver() { + InitializePasses(); + } - ~PassDriver(); + virtual ~PassDriver() { + } /** * @brief Insert a Pass: can warn if multiple passes have the same name. - * @param new_pass the new Pass to insert in the map and list. - * @param warn_override warn if the name of the Pass is already used. */ - void InsertPass(const Pass* new_pass); + void InsertPass(const Pass* new_pass) { + DCHECK(new_pass != nullptr); + DCHECK(new_pass->GetName() != nullptr && new_pass->GetName()[0] != 0); + + // It is an error to override an existing pass. + DCHECK(GetPass(new_pass->GetName()) == nullptr) + << "Pass name " << new_pass->GetName() << " already used."; + + // Now add to the list. + pass_list_.push_back(new_pass); + } /** * @brief Run a pass using the name as key. - * @param c_unit the considered CompilationUnit. - * @param pass_name the Pass name. * @return whether the pass was applied. */ - bool RunPass(CompilationUnit* c_unit, const char* pass_name); + virtual bool RunPass(const char* pass_name) { + // Paranoid: c_unit cannot be nullptr and we need a pass name. + DCHECK(pass_name != nullptr && pass_name[0] != 0); + + const Pass* cur_pass = GetPass(pass_name); + + if (cur_pass != nullptr) { + return RunPass(cur_pass); + } + + // Return false, we did not find the pass. + return false; + } /** - * @brief Run a pass using the Pass itself. - * @param time_split do we want a time split request(default: false)? - * @return whether the pass was applied. + * @brief Runs all the passes with the pass_list_. */ - bool RunPass(CompilationUnit* c_unit, const Pass* pass, bool time_split = false); + void Launch() { + for (const Pass* cur_pass : pass_list_) { + RunPass(cur_pass); + } + } - void Launch(); + /** + * @brief Searches for a particular pass. + * @param the name of the pass to be searched for. + */ + const Pass* GetPass(const char* name) const { + for (const Pass* cur_pass : pass_list_) { + if (strcmp(name, cur_pass->GetName()) == 0) { + return cur_pass; + } + } + return nullptr; + } - void HandlePassFlag(CompilationUnit* c_unit, const Pass* pass); + static void CreateDefaultPassList(const std::string& disable_passes) { + // Insert each pass from g_passes into g_default_pass_list. + PassDriverType::g_default_pass_list.clear(); + PassDriverType::g_default_pass_list.reserve(PassDriver<PassDriverType>::g_passes_size); + for (uint16_t i = 0; i < PassDriver<PassDriverType>::g_passes_size; ++i) { + const Pass* pass = PassDriver<PassDriverType>::g_passes[i]; + // Check if we should disable this pass. + if (disable_passes.find(pass->GetName()) != std::string::npos) { + LOG(INFO) << "Skipping " << pass->GetName(); + } else { + PassDriver<PassDriverType>::g_default_pass_list.push_back(pass); + } + } + } /** - * @brief Apply a patch: perform start/work/end functions. + * @brief Run a pass using the Pass itself. + * @param time_split do we want a time split request(default: false)? + * @return whether the pass was applied. */ - void ApplyPass(CompilationUnit* c_unit, const Pass* pass); + virtual bool RunPass(const Pass* pass, bool time_split = false) = 0; /** - * @brief Dispatch a patch: walk the BasicBlocks depending on the traversal mode + * @brief Print the pass names of all the passes available. */ - void DispatchPass(CompilationUnit* c_unit, const Pass* pass); + static void PrintPassNames() { + LOG(INFO) << "Loop Passes are:"; - static void PrintPassNames(); - static void CreateDefaultPassList(const std::string& disable_passes); + for (const Pass* cur_pass : PassDriver<PassDriverType>::g_default_pass_list) { + LOG(INFO) << "\t-" << cur_pass->GetName(); + } + } - const Pass* GetPass(const char* name) const; + protected: + /** + * @brief Gets the list of passes currently schedule to execute. + * @return pass_list_ + */ + std::vector<const Pass*>& GetPasses() { + return pass_list_; + } - const char* GetDumpCFGFolder() const { - return dump_cfg_folder_; + virtual void InitializePasses() { + SetDefaultPasses(); } - protected: - void CreatePasses(); + void SetDefaultPasses() { + pass_list_ = PassDriver<PassDriverType>::g_default_pass_list; + } + + /** + * @brief Apply a patch: perform start/work/end functions. + */ + virtual void ApplyPass(PassDataHolder* data, const Pass* pass) { + pass->Start(data); + DispatchPass(pass); + pass->End(data); + } + /** + * @brief Dispatch a patch. + * Gives the ability to add logic when running the patch. + */ + virtual void DispatchPass(const Pass* pass) { + UNUSED(pass); + } /** @brief List of passes: provides the order to execute the passes. */ std::vector<const Pass*> pass_list_; - /** @brief The CompilationUnit on which to execute the passes on. */ - CompilationUnit* const cu_; + /** @brief The number of passes within g_passes. */ + static const uint16_t g_passes_size; + + /** @brief The number of passes within g_passes. */ + static const Pass* const g_passes[]; - /** @brief Dump CFG base folder: where is the base folder for dumping CFGs. */ - const char* dump_cfg_folder_; + /** @brief The default pass list is used to initialize pass_list_. */ + static std::vector<const Pass*> g_default_pass_list; }; } // namespace art diff --git a/compiler/dex/pass_driver_me.cc b/compiler/dex/pass_driver_me.cc new file mode 100644 index 0000000000..d0545004f7 --- /dev/null +++ b/compiler/dex/pass_driver_me.cc @@ -0,0 +1,170 @@ +/* + * 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 "base/macros.h" +#include "bb_optimizations.h" +#include "compiler_internals.h" +#include "dataflow_iterator.h" +#include "dataflow_iterator-inl.h" +#include "pass_driver_me.h" + +namespace art { + +namespace { // anonymous namespace + +void DoWalkBasicBlocks(PassMEDataHolder* data, const PassME* pass, DataflowIterator* iterator) { + // Paranoid: Check the iterator before walking the BasicBlocks. + DCHECK(iterator != nullptr); + bool change = false; + for (BasicBlock *bb = iterator->Next(change); bb != 0; bb = iterator->Next(change)) { + data->bb = bb; + change = pass->Worker(data); + } +} + +template <typename Iterator> +inline void DoWalkBasicBlocks(PassMEDataHolder* data, const PassME* pass) { + DCHECK(data != nullptr); + CompilationUnit* c_unit = data->c_unit; + DCHECK(c_unit != nullptr); + Iterator iterator(c_unit->mir_graph.get()); + DoWalkBasicBlocks(data, pass, &iterator); +} +} // anonymous namespace + +/* + * Create the pass list. These passes are immutable and are shared across the threads. + * + * Advantage is that there will be no race conditions here. + * Disadvantage is the passes can't change their internal states depending on CompilationUnit: + * - This is not yet an issue: no current pass would require it. + */ +// The initial list of passes to be used by the PassDriveME. +template<> +const Pass* const PassDriver<PassDriverME>::g_passes[] = { + GetPassInstance<CacheFieldLoweringInfo>(), + GetPassInstance<CacheMethodLoweringInfo>(), + GetPassInstance<CallInlining>(), + GetPassInstance<CodeLayout>(), + GetPassInstance<SSATransformation>(), + GetPassInstance<ConstantPropagation>(), + GetPassInstance<InitRegLocations>(), + GetPassInstance<MethodUseCount>(), + GetPassInstance<NullCheckEliminationAndTypeInference>(), + GetPassInstance<ClassInitCheckElimination>(), + GetPassInstance<BBCombine>(), + GetPassInstance<BBOptimizations>(), +}; + +// The number of the passes in the initial list of Passes (g_passes). +template<> +uint16_t const PassDriver<PassDriverME>::g_passes_size = arraysize(PassDriver<PassDriverME>::g_passes); + +// The default pass list is used by the PassDriverME instance of PassDriver to initialize pass_list_. +template<> +std::vector<const Pass*> PassDriver<PassDriverME>::g_default_pass_list(PassDriver<PassDriverME>::g_passes, PassDriver<PassDriverME>::g_passes + PassDriver<PassDriverME>::g_passes_size); + +PassDriverME::PassDriverME(CompilationUnit* cu) + : PassDriver(), pass_me_data_holder_(), dump_cfg_folder_("/sdcard/") { + pass_me_data_holder_.bb = nullptr; + pass_me_data_holder_.c_unit = cu; +} + +PassDriverME::~PassDriverME() { +} + +void PassDriverME::DispatchPass(const Pass* pass) { + VLOG(compiler) << "Dispatching " << pass->GetName(); + const PassME* me_pass = down_cast<const PassME*>(pass); + + DataFlowAnalysisMode mode = me_pass->GetTraversal(); + + switch (mode) { + case kPreOrderDFSTraversal: + DoWalkBasicBlocks<PreOrderDfsIterator>(&pass_me_data_holder_, me_pass); + break; + case kRepeatingPreOrderDFSTraversal: + DoWalkBasicBlocks<RepeatingPreOrderDfsIterator>(&pass_me_data_holder_, me_pass); + break; + case kRepeatingPostOrderDFSTraversal: + DoWalkBasicBlocks<RepeatingPostOrderDfsIterator>(&pass_me_data_holder_, me_pass); + break; + case kReversePostOrderDFSTraversal: + DoWalkBasicBlocks<ReversePostOrderDfsIterator>(&pass_me_data_holder_, me_pass); + break; + case kRepeatingReversePostOrderDFSTraversal: + DoWalkBasicBlocks<RepeatingReversePostOrderDfsIterator>(&pass_me_data_holder_, me_pass); + break; + case kPostOrderDOMTraversal: + DoWalkBasicBlocks<PostOrderDOMIterator>(&pass_me_data_holder_, me_pass); + break; + case kAllNodes: + DoWalkBasicBlocks<AllNodesIterator>(&pass_me_data_holder_, me_pass); + break; + case kNoNodes: + break; + default: + LOG(FATAL) << "Iterator mode not handled in dispatcher: " << mode; + break; + } +} + +bool PassDriverME::RunPass(const Pass* pass, bool time_split) { + // Paranoid: c_unit and pass cannot be nullptr, and the pass should have a name + DCHECK(pass != nullptr); + DCHECK(pass->GetName() != nullptr && pass->GetName()[0] != 0); + CompilationUnit* c_unit = pass_me_data_holder_.c_unit; + DCHECK(c_unit != nullptr); + + // Do we perform a time split + if (time_split) { + c_unit->NewTimingSplit(pass->GetName()); + } + + // Check the pass gate first. + bool should_apply_pass = pass->Gate(&pass_me_data_holder_); + if (should_apply_pass) { + // Applying the pass: first start, doWork, and end calls. + ApplyPass(&pass_me_data_holder_, pass); + + // Do we want to log it? + if ((c_unit->enable_debug& (1 << kDebugDumpCFG)) != 0) { + // Do we have a pass folder? + const PassME* me_pass = (down_cast<const PassME*>(pass)); + const char* passFolder = me_pass->GetDumpCFGFolder(); + DCHECK(passFolder != nullptr); + + if (passFolder[0] != 0) { + // Create directory prefix. + std::string prefix = GetDumpCFGFolder(); + prefix += passFolder; + prefix += "/"; + + c_unit->mir_graph->DumpCFG(prefix.c_str(), false); + } + } + } + + // If the pass gate passed, we can declare success. + return should_apply_pass; +} + +const char* PassDriverME::GetDumpCFGFolder() const { + return dump_cfg_folder_; +} + + +} // namespace art diff --git a/compiler/dex/pass_driver_me.h b/compiler/dex/pass_driver_me.h new file mode 100644 index 0000000000..0142934be2 --- /dev/null +++ b/compiler/dex/pass_driver_me.h @@ -0,0 +1,45 @@ +/* + * 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_DEX_PASS_DRIVER_ME_H_ +#define ART_COMPILER_DEX_PASS_DRIVER_ME_H_ + +#include "bb_optimizations.h" +#include "pass_driver.h" +#include "pass_me.h" + +namespace art { + +class PassDriverME: public PassDriver<PassDriverME> { + public: + explicit PassDriverME(CompilationUnit* cu); + ~PassDriverME(); + /** + * @brief Dispatch a patch: walk the BasicBlocks depending on the traversal mode + */ + void DispatchPass(const Pass* pass); + bool RunPass(const Pass* pass, bool time_split = false); + const char* GetDumpCFGFolder() const; + protected: + /** @brief The data holder that contains data needed for the PassDriverME. */ + PassMEDataHolder pass_me_data_holder_; + + /** @brief Dump CFG base folder: where is the base folder for dumping CFGs. */ + const char* dump_cfg_folder_; +}; + +} // namespace art +#endif // ART_COMPILER_DEX_PASS_DRIVER_ME_H_ diff --git a/compiler/dex/pass_me.h b/compiler/dex/pass_me.h new file mode 100644 index 0000000000..1132166a34 --- /dev/null +++ b/compiler/dex/pass_me.h @@ -0,0 +1,101 @@ +/* + * 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_DEX_PASS_ME_H_ +#define ART_COMPILER_DEX_PASS_ME_H_ + +#include <string> +#include "pass.h" + +namespace art { + +// Forward declarations. +struct BasicBlock; +struct CompilationUnit; +class Pass; + +/** + * @brief OptimizationFlag is an enumeration to perform certain tasks for a given pass. + * @details Each enum should be a power of 2 to be correctly used. + */ +enum OptimizationFlag { +}; + +// Data holder class. +class PassMEDataHolder: public PassDataHolder { + public: + CompilationUnit* c_unit; + BasicBlock* bb; +}; + +enum DataFlowAnalysisMode { + kAllNodes = 0, /**< @brief All nodes. */ + kPreOrderDFSTraversal, /**< @brief Depth-First-Search / Pre-Order. */ + kRepeatingPreOrderDFSTraversal, /**< @brief Depth-First-Search / Repeating Pre-Order. */ + kReversePostOrderDFSTraversal, /**< @brief Depth-First-Search / Reverse Post-Order. */ + kRepeatingPostOrderDFSTraversal, /**< @brief Depth-First-Search / Repeating Post-Order. */ + kRepeatingReversePostOrderDFSTraversal, /**< @brief Depth-First-Search / Repeating Reverse Post-Order. */ + kPostOrderDOMTraversal, /**< @brief Dominator tree / Post-Order. */ + kNoNodes, /**< @brief Skip BasicBlock traversal. */ +}; + +/** + * @class Pass + * @brief Pass is the Pass structure for the optimizations. + * @details The following structure has the different optimization passes that we are going to do. + */ +class PassME: public Pass { + public: + explicit PassME(const char* name, DataFlowAnalysisMode type = kAllNodes, + unsigned int flags = 0u, const char* dump = "") + : Pass(name), traversal_type_(type), flags_(flags), dump_cfg_folder_(dump) { + } + + PassME(const char* name, DataFlowAnalysisMode type, const char* dump) + : Pass(name), traversal_type_(type), flags_(0), dump_cfg_folder_(dump) { + } + + PassME(const char* name, const char* dump) + : Pass(name), traversal_type_(kAllNodes), flags_(0), dump_cfg_folder_(dump) { + } + + ~PassME() { + } + + virtual DataFlowAnalysisMode GetTraversal() const { + return traversal_type_; + } + + const char* GetDumpCFGFolder() const { + return dump_cfg_folder_; + } + + bool GetFlag(OptimizationFlag flag) const { + return (flags_ & flag); + } + + protected: + /** @brief Type of traversal: determines the order to execute the pass on the BasicBlocks. */ + const DataFlowAnalysisMode traversal_type_; + + /** @brief Flags for additional directives: used to determine if a particular clean-up is necessary post pass. */ + const unsigned int flags_; + + /** @brief CFG Dump Folder: what sub-folder to use for dumping the CFGs post pass. */ + const char* const dump_cfg_folder_; +}; +} // namespace art +#endif // ART_COMPILER_DEX_PASS_ME_H_ diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 6ccf252a14..256135df71 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -364,6 +364,18 @@ LIR* Mir2Lir::ScanLiteralPoolWide(LIR* data_target, int val_lo, int val_hi) { return NULL; } +/* Search the existing constants in the literal pool for an exact method match */ +LIR* Mir2Lir::ScanLiteralPoolMethod(LIR* data_target, const MethodReference& method) { + while (data_target) { + if (static_cast<uint32_t>(data_target->operands[0]) == method.dex_method_index && + UnwrapPointer(data_target->operands[1]) == method.dex_file) { + return data_target; + } + data_target = data_target->next; + } + return nullptr; +} + /* * The following are building blocks to insert constants into the pool or * instruction streams. @@ -1143,11 +1155,13 @@ void Mir2Lir::AddSlowPath(LIRSlowPath* slowpath) { void Mir2Lir::LoadCodeAddress(const MethodReference& target_method, InvokeType type, SpecialTargetRegister symbolic_reg) { - int target_method_idx = target_method.dex_method_index; - LIR* data_target = ScanLiteralPool(code_literal_list_, target_method_idx, 0); + LIR* data_target = ScanLiteralPoolMethod(code_literal_list_, target_method); if (data_target == NULL) { - data_target = AddWordData(&code_literal_list_, target_method_idx); + data_target = AddWordData(&code_literal_list_, target_method.dex_method_index); data_target->operands[1] = WrapPointer(const_cast<DexFile*>(target_method.dex_file)); + // NOTE: The invoke type doesn't contribute to the literal identity. In fact, we can have + // the same method invoked with kVirtual, kSuper and kInterface but the class linker will + // resolve these invokes to the same method, so we don't care which one we record here. data_target->operands[2] = type; } LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target); @@ -1157,11 +1171,13 @@ void Mir2Lir::LoadCodeAddress(const MethodReference& target_method, InvokeType t void Mir2Lir::LoadMethodAddress(const MethodReference& target_method, InvokeType type, SpecialTargetRegister symbolic_reg) { - int target_method_idx = target_method.dex_method_index; - LIR* data_target = ScanLiteralPool(method_literal_list_, target_method_idx, 0); + LIR* data_target = ScanLiteralPoolMethod(method_literal_list_, target_method); if (data_target == NULL) { - data_target = AddWordData(&method_literal_list_, target_method_idx); + data_target = AddWordData(&method_literal_list_, target_method.dex_method_index); data_target->operands[1] = WrapPointer(const_cast<DexFile*>(target_method.dex_file)); + // NOTE: The invoke type doesn't contribute to the literal identity. In fact, we can have + // the same method invoked with kVirtual, kSuper and kInterface but the class linker will + // resolve these invokes to the same method, so we don't care which one we record here. data_target->operands[2] = type; } LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target); diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index 3ec31ba7d9..526c981ae9 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -35,15 +35,9 @@ namespace art { namespace { // anonymous namespace MIR* AllocReplacementMIR(MIRGraph* mir_graph, MIR* invoke, MIR* move_return) { - ArenaAllocator* arena = mir_graph->GetArena(); - MIR* insn = static_cast<MIR*>(arena->Alloc(sizeof(MIR), kArenaAllocMIR)); + MIR* insn = mir_graph->NewMIR(); insn->offset = invoke->offset; - insn->width = invoke->width; insn->optimization_flags = MIR_CALLEE; - if (move_return != nullptr) { - DCHECK_EQ(move_return->offset, invoke->offset + invoke->width); - insn->width += move_return->width; - } return insn; } @@ -660,7 +654,6 @@ bool DexFileMethodInliner::GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MI } MIR* insn = AllocReplacementMIR(mir_graph, invoke, move_result); - insn->width += insn->offset - invoke->offset; insn->offset = invoke->offset; insn->dalvikInsn.opcode = opcode; insn->dalvikInsn.vA = move_result->dalvikInsn.vA; @@ -737,9 +730,7 @@ bool DexFileMethodInliner::GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MI if (move_result != nullptr) { MIR* move = AllocReplacementMIR(mir_graph, invoke, move_result); - insn->width = invoke->width; move->offset = move_result->offset; - move->width = move_result->width; if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT) { move->dalvikInsn.opcode = Instruction::MOVE_FROM16; } else if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 3e0ba7517a..3584c33291 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -617,6 +617,7 @@ class Mir2Lir : public Backend { LIR* NewLIR5(int opcode, int dest, int src1, int src2, int info1, int info2); LIR* ScanLiteralPool(LIR* data_target, int value, unsigned int delta); LIR* ScanLiteralPoolWide(LIR* data_target, int val_lo, int val_hi); + LIR* ScanLiteralPoolMethod(LIR* data_target, const MethodReference& method); LIR* AddWordData(LIR* *constant_list_p, int value); LIR* AddWideData(LIR* *constant_list_p, int val_lo, int val_hi); void ProcessSwitchTables(); diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc index 5aa093a494..865311b084 100644 --- a/compiler/dex/ssa_transformation.cc +++ b/compiler/dex/ssa_transformation.cc @@ -557,8 +557,7 @@ void MIRGraph::InsertPhiNodes() { if (!phi_bb->data_flow_info->live_in_v->IsBitSet(dalvik_reg)) { continue; } - MIR *phi = - static_cast<MIR*>(arena_->Alloc(sizeof(MIR), kArenaAllocDFInfo)); + MIR *phi = NewMIR(); phi->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpPhi); phi->dalvikInsn.vA = dalvik_reg; phi->offset = phi_bb->start_offset; diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index eb62f1b577..0f41d2b2f6 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1152,28 +1152,22 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType *type = sharp_type; } } else { - if (compiling_boot) { + bool method_in_image = compiling_boot || + Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace(); + if (method_in_image) { + CHECK(!method->IsAbstract()); *type = sharp_type; - *direct_method = -1; - *direct_code = -1; + *direct_method = compiling_boot ? -1 : reinterpret_cast<uintptr_t>(method); + *direct_code = compiling_boot ? -1 : compiler_->GetEntryPointOf(method); + target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); + target_method->dex_method_index = method->GetDexMethodIndex(); + } else if (!must_use_direct_pointers) { + // Set the code and rely on the dex cache for the method. + *type = sharp_type; + *direct_code = compiler_->GetEntryPointOf(method); } else { - bool method_in_image = - Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace(); - if (method_in_image) { - CHECK(!method->IsAbstract()); - *type = sharp_type; - *direct_method = reinterpret_cast<uintptr_t>(method); - *direct_code = compiler_->GetEntryPointOf(method); - target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); - target_method->dex_method_index = method->GetDexMethodIndex(); - } else if (!must_use_direct_pointers) { - // Set the code and rely on the dex cache for the method. - *type = sharp_type; - *direct_code = compiler_->GetEntryPointOf(method); - } else { - // Direct pointers were required but none were available. - VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method); - } + // Direct pointers were required but none were available. + VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method); } } } @@ -1369,7 +1363,7 @@ class ParallelCompilationManager { self->AssertNoPendingException(); CHECK_GT(work_units, 0U); - index_ = begin; + index_.StoreRelaxed(begin); for (size_t i = 0; i < work_units; ++i) { thread_pool_->AddTask(self, new ForAllClosure(this, end, callback)); } @@ -1384,7 +1378,7 @@ class ParallelCompilationManager { } size_t NextIndex() { - return index_.FetchAndAdd(1); + return index_.FetchAndAddSequentiallyConsistent(1); } private: |