diff options
author | 2014-05-01 05:52:04 -0700 | |
---|---|---|
committer | 2014-05-22 06:42:23 -0700 | |
commit | 4f59668b3d51f63601ebe59dbd2b7e8a7c5bd093 (patch) | |
tree | cf93995a8e42da6799e895918ee2ee52dc1c03a0 | |
parent | 59f3f62534581311c7c403c832f56c272426a17c (diff) |
ART: Pass driver generalization
- Generalizing Pass Driver.
- Migrating ME Pass Driver to use the new generalized Pass Driver.
There will be some more changes after in the compiler code to generalize
it a bit more by separating what is being done by the optimizing passes
and post-pass cleanups.
Change-Id: I140a70e88483d7c3991b7d336bd593b2613ae194
Signed-off-by: James C Scott <james.c.scott@intel.com>
-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/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-- | dex2oat/dex2oat.cc | 6 |
10 files changed, 635 insertions, 173 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index cb900eac61..4108ba463d 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/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/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 9914875d5e..f0b575041d 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -33,7 +33,7 @@ #include "compiler.h" #include "compiler_callbacks.h" #include "dex_file-inl.h" -#include "dex/pass_driver.h" +#include "dex/pass_driver_me.h" #include "dex/verification_results.h" #include "driver/compiler_callbacks_impl.h" #include "driver/compiler_driver.h" @@ -918,10 +918,10 @@ static int dex2oat(int argc, char** argv) { } else if (option == "--no-profile-file") { // No profile } else if (option == "--print-pass-names") { - PassDriver::PrintPassNames(); + PassDriverME::PrintPassNames(); } else if (option.starts_with("--disable-passes=")) { std::string disable_passes = option.substr(strlen("--disable-passes=")).data(); - PassDriver::CreateDefaultPassList(disable_passes); + PassDriverME::CreateDefaultPassList(disable_passes); } else { Usage("Unknown argument %s", option.data()); } |