ART: Print and dump functionalities per pass

LOG is a great logging tool but sometimes a pass has some debugging text it
 want to be able to turn on/off easily.

By going via a print_pass flag, we can actually turn it on/off easily per pass
 when debugging/instrumenting.

- Added a pass printer to help debug messages for future passes.
- Added a print_pass flag in CompilationUnit to filter out messages.

At the same time, did a similar system for dumping the CFG.

- Also moved some API into public from protected.

Change-Id: Ie0e89a8fc773e8583f3e4ffd6e4bd2eebdbb2bf4
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/compiler_ir.h b/compiler/dex/compiler_ir.h
index 35d777e..66fb608 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -88,6 +88,7 @@
   std::unique_ptr<MIRGraph> mir_graph;   // MIR container.
   std::unique_ptr<Backend> cg;           // Target-specific codegen.
   TimingLogger timings;
+  bool print_pass;                 // Do we want to print a pass or not?
 };
 
 }  // namespace art
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 9bad736..e246302 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -105,7 +105,8 @@
     arena_stack(pool),
     mir_graph(nullptr),
     cg(nullptr),
-    timings("QuickCompiler", true, false) {
+    timings("QuickCompiler", true, false),
+    print_pass(false) {
 }
 
 CompilationUnit::~CompilationUnit() {
diff --git a/compiler/dex/pass.h b/compiler/dex/pass.h
index 4ce040e..b4906d6 100644
--- a/compiler/dex/pass.h
+++ b/compiler/dex/pass.h
@@ -89,6 +89,21 @@
     return false;
   }
 
+  static void BasePrintMessage(CompilationUnit* c_unit, const char* pass_name, const char* message, ...) {
+    // Check if we want to log something or not.
+    if (c_unit->print_pass) {
+      // Stringify the message.
+      va_list args;
+      va_start(args, message);
+      std::string stringified_message;
+      StringAppendV(&stringified_message, message, args);
+      va_end(args);
+
+      // Log the message and ensure to include pass name.
+      LOG(INFO) << pass_name << ": " << stringified_message;
+    }
+  }
+
  protected:
   /** @brief The pass name: used for searching for a pass when running a particular pass or debugging. */
   const char* const pass_name_;
diff --git a/compiler/dex/pass_driver.h b/compiler/dex/pass_driver.h
index aa0d1ae..788f24b 100644
--- a/compiler/dex/pass_driver.h
+++ b/compiler/dex/pass_driver.h
@@ -141,7 +141,6 @@
     }
   }
 
- protected:
   /**
    * @brief Gets the list of passes currently schedule to execute.
    * @return pass_list_
@@ -150,14 +149,27 @@
     return pass_list_;
   }
 
-  virtual void InitializePasses() {
-    SetDefaultPasses();
+  static void SetPrintAllPasses() {
+    default_print_passes_ = true;
+  }
+
+  static void SetDumpPassList(const char* list) {
+    dump_pass_list_.reset(list);
+  }
+
+  static void SetPrintPassList(const char* list) {
+    print_pass_list_.reset(list);
   }
 
   void SetDefaultPasses() {
     pass_list_ = PassDriver<PassDriverType>::g_default_pass_list;
   }
 
+ protected:
+  virtual void InitializePasses() {
+    SetDefaultPasses();
+  }
+
   /**
    * @brief Apply a patch: perform start/work/end functions.
    */
@@ -185,6 +197,15 @@
 
   /** @brief The default pass list is used to initialize pass_list_. */
   static std::vector<const Pass*> g_default_pass_list;
+
+  /** @brief Do we, by default, want to be printing the log messages? */
+  static bool default_print_passes_;
+
+  /** @brief What are the passes we want to be printing the log messages? */
+  static std::unique_ptr<const char> print_pass_list_;
+
+  /** @brief What are the passes we want to be dumping the CFG? */
+  static std::unique_ptr<const char> dump_pass_list_;
 };
 
 }  // namespace art
diff --git a/compiler/dex/pass_driver_me.cc b/compiler/dex/pass_driver_me.cc
index d054500..099cfee 100644
--- a/compiler/dex/pass_driver_me.cc
+++ b/compiler/dex/pass_driver_me.cc
@@ -77,6 +77,19 @@
 template<>
 std::vector<const Pass*> PassDriver<PassDriverME>::g_default_pass_list(PassDriver<PassDriverME>::g_passes, PassDriver<PassDriverME>::g_passes + PassDriver<PassDriverME>::g_passes_size);
 
+// By default, do not have a dump pass list.
+template<>
+std::unique_ptr<const char> PassDriver<PassDriverME>::dump_pass_list_(nullptr);
+
+// By default, do not have a print pass list.
+template<>
+std::unique_ptr<const char> PassDriver<PassDriverME>::print_pass_list_(nullptr);
+
+// By default, we do not print the pass' information.
+template<>
+bool PassDriver<PassDriverME>::default_print_passes_ = false;
+
+
 PassDriverME::PassDriverME(CompilationUnit* cu)
     : PassDriver(), pass_me_data_holder_(), dump_cfg_folder_("/sdcard/") {
   pass_me_data_holder_.bb = nullptr;
@@ -136,26 +149,51 @@
 
   // 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 = default_print_passes_;
+
+    const char* print_pass_list = print_pass_list_.get();
+
+    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.
     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);
+    bool should_dump = ((c_unit->enable_debug & (1 << kDebugDumpCFG)) != 0);
 
-      if (passFolder[0] != 0) {
-        // Create directory prefix.
-        std::string prefix = GetDumpCFGFolder();
-        prefix += passFolder;
-        prefix += "/";
+    const char* dump_pass_list = dump_pass_list_.get();
 
-        c_unit->mir_graph->DumpCFG(prefix.c_str(), false);
+    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.
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index f0b5750..6d05e5e 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -922,6 +922,20 @@
     } else if (option.starts_with("--disable-passes=")) {
       std::string disable_passes = option.substr(strlen("--disable-passes=")).data();
       PassDriverME::CreateDefaultPassList(disable_passes);
+    } else if (option.starts_with("--print-passes=")) {
+      std::string print_passes = option.substr(strlen("--print-passes=")).data();
+      size_t len = print_passes.length() + 1;
+      char* duplicate = new char[len];
+      strncpy(duplicate, print_passes.c_str(), len);
+      PassDriverME::SetPrintPassList(duplicate);
+    } else if (option == "--print-all-passes") {
+      PassDriverME::SetPrintAllPasses();
+    } else if (option.starts_with("--dump-cfg-passes=")) {
+      std::string dump_passes = option.substr(strlen("--dump-cfg-passes=")).data();
+      size_t len = dump_passes.length() + 1;
+      char* duplicate = new char[len];
+      strncpy(duplicate, dump_passes.c_str(), len);
+      PassDriverME::SetDumpPassList(duplicate);
     } else {
       Usage("Unknown argument %s", option.data());
     }