ART: Setting up cleanup
- Moved code around to actually have the clean-up code in a PassDriver format.
This allows us to better control what is being called after an optimization
It also allows the use of a centralized pass system for both optimizations
and cleanup.
Change-Id: I9d21e9bb9ee663739722f440d82adf04f73e380c
Signed-off-by: Jean Christophe Beyler <jean.christophe.beyler@intel.com>
Signed-off-by: Razvan A Lupusoru <razvan.a.lupusoru@intel.com>
Signed-off-by: Yixin Shou <yixin.shou@intel.com>
Signed-off-by: Chao-ying Fu <chao-ying.fu@intel.com>
Signed-off-by: Udayan Banerji <udayan.banerji@intel.com>
diff --git a/compiler/dex/pass_driver_me.h b/compiler/dex/pass_driver_me.h
index 0142934..7d76fb8 100644
--- a/compiler/dex/pass_driver_me.h
+++ b/compiler/dex/pass_driver_me.h
@@ -18,28 +18,155 @@
#define ART_COMPILER_DEX_PASS_DRIVER_ME_H_
#include "bb_optimizations.h"
+#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
#include "pass_driver.h"
#include "pass_me.h"
namespace art {
-class PassDriverME: public PassDriver<PassDriverME> {
+template <typename PassDriverType>
+class PassDriverME: public PassDriver<PassDriverType> {
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;
+ explicit PassDriverME(CompilationUnit* cu)
+ : pass_me_data_holder_(), dump_cfg_folder_("/sdcard/") {
+ pass_me_data_holder_.bb = nullptr;
+ pass_me_data_holder_.c_unit = cu;
+ }
+
+ ~PassDriverME() {
+ }
+
+ void 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 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) {
+ bool old_print_pass = c_unit->print_pass;
+
+ c_unit->print_pass = PassDriver<PassDriverType>::default_print_passes_;
+
+ const char* print_pass_list = PassDriver<PassDriverType>::print_pass_list_.c_str();
+
+ if (print_pass_list != nullptr && strstr(print_pass_list, pass->GetName()) != nullptr) {
+ c_unit->print_pass = true;
+ }
+
+ // Applying the pass: first start, doWork, and end calls.
+ this->ApplyPass(&pass_me_data_holder_, pass);
+
+ bool should_dump = ((c_unit->enable_debug & (1 << kDebugDumpCFG)) != 0);
+
+ const char* dump_pass_list = PassDriver<PassDriverType>::dump_pass_list_.c_str();
+
+ if (dump_pass_list != nullptr) {
+ bool found = strstr(dump_pass_list, pass->GetName());
+ should_dump = (should_dump || found);
+ }
+
+ if (should_dump) {
+ // 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);
+ }
+ }
+ }
+
+ c_unit->print_pass = old_print_pass;
+ }
+
+ // If the pass gate passed, we can declare success.
+ return should_apply_pass;
+ }
+
+ const char* GetDumpCFGFolder() const {
+ return dump_cfg_folder_;
+ }
+
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_;
-};
+ static 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 != nullptr; bb = iterator->Next(change)) {
+ data->bb = bb;
+ change = pass->Worker(data);
+ }
+ }
+
+ template <typename Iterator>
+ inline static 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);
+ }
+};
} // namespace art
#endif // ART_COMPILER_DEX_PASS_DRIVER_ME_H_
+