gollvm: add support -Rpass=<regex> and related options

Add suport for -Rpass=<regex>, -Rpass-missed=<regex>, and
-Rpass-analysis=<regex> command line options, to allow enabling of
optimization remarks. Adding "-Rpass=inline" (for example) can be a
very handy way to understand what is/is-not being done by the inliner
when your code is compiled.

Change-Id: Ibbf65b502775f9f6b68ff96479113d43e3b71046
Reviewed-on: https://go-review.googlesource.com/c/161057
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/driver/CompileGo.cpp b/driver/CompileGo.cpp
index 9eeca21..fcad320 100644
--- a/driver/CompileGo.cpp
+++ b/driver/CompileGo.cpp
@@ -78,6 +78,14 @@
 namespace gollvm {
 namespace driver {
 
+// For keeping track of info on -Rpass=<regex> and related options.
+class RemarkCtl {
+ public:
+  std::shared_ptr<llvm::Regex> optimizationRemarkPattern_;
+  std::shared_ptr<llvm::Regex> optimizationRemarkMissedPattern_;
+  std::shared_ptr<llvm::Regex> optimizationRemarkAnalysisPattern_;
+};
+
 class CompileGoImpl {
  public:
   CompileGoImpl(ToolChain &tc, const std::string &executablePath);
@@ -107,6 +115,7 @@
   std::string asmOutFileName_;
   std::unique_ptr<ToolOutputFile> asmout_;
   std::unique_ptr<ToolOutputFile> optRecordFile_;
+  RemarkCtl remarkCtl_;
   std::unique_ptr<TargetLibraryInfoImpl> tlii_;
   std::string targetCpuAttr_;
   std::string targetFeaturesAttr_;
@@ -191,8 +200,8 @@
 class BEDiagnosticHandler : public DiagnosticHandler {
   bool *error_;
  public:
-  BEDiagnosticHandler(bool *errorPtr)
-      : error_(errorPtr) {}
+  BEDiagnosticHandler(bool *errorPtr, RemarkCtl &remarkCtl)
+    : error_(errorPtr), r_(remarkCtl) {}
   bool handleDiagnostics(const DiagnosticInfo &DI) override {
     if (DI.getSeverity() == DS_Error)
       *error_ = true;
@@ -205,6 +214,28 @@
     errs() << "\n";
     return true;
   }
+
+  // Overrides of parent class methods.
+  bool isAnalysisRemarkEnabled(StringRef passName) const override {
+    return (r_.optimizationRemarkAnalysisPattern_ &&
+            r_.optimizationRemarkAnalysisPattern_->match(passName));
+  }
+  bool isMissedOptRemarkEnabled(StringRef passName) const override {
+    return (r_.optimizationRemarkMissedPattern_ &&
+            r_.optimizationRemarkMissedPattern_->match(passName));
+  }
+  bool isPassedOptRemarkEnabled(StringRef passName) const override {
+    return (r_.optimizationRemarkPattern_ &&
+            r_.optimizationRemarkPattern_->match(passName));
+  }
+  bool isAnyRemarkEnabled() const override {
+    return (r_.optimizationRemarkPattern_ ||
+            r_.optimizationRemarkMissedPattern_ ||
+            r_.optimizationRemarkAnalysisPattern_);
+  }
+
+ private:
+  RemarkCtl &r_;
 };
 
 void CompileGoImpl::quoteDump(const std::string &str, bool doquote)
@@ -293,6 +324,21 @@
   return true;
 }
 
+static std::shared_ptr<llvm::Regex>
+generateOptimizationRemarkRegex(opt::ArgList &args, opt::Arg *rpassArg)
+{
+  llvm::StringRef val = rpassArg->getValue();
+  std::string regexError;
+  std::shared_ptr<llvm::Regex> pattern = std::make_shared<llvm::Regex>(val);
+  if (!pattern->isValid(regexError)) {
+    errs() << "error: invalid regex for '"
+           << rpassArg->getAsString(args) << "' option: "
+           << regexError << "\n";
+    pattern.reset();
+  }
+  return pattern;
+}
+
 bool CompileGoImpl::setup()
 {
   // Set triple.
@@ -399,6 +445,20 @@
     }
   }
 
+  // Vet/honor -Rpass= and friends.
+  if (opt::Arg *arg = args_.getLastArg(gollvm::options::OPT_Rpass_EQ)) {
+    remarkCtl_.optimizationRemarkPattern_ =
+        generateOptimizationRemarkRegex(args_, arg);
+  }
+  if (opt::Arg *arg = args_.getLastArg(gollvm::options::OPT_Rpass_missed_EQ)) {
+    remarkCtl_.optimizationRemarkMissedPattern_ =
+        generateOptimizationRemarkRegex(args_, arg);
+  }
+  if (opt::Arg *arg = args_.getLastArg(gollvm::options::OPT_Rpass_analysis_EQ)) {
+    remarkCtl_.optimizationRemarkAnalysisPattern_ =
+        generateOptimizationRemarkRegex(args_, arg);
+  }
+
   TargetOptions Options;
 
   // FIXME: turn off integrated assembler for now.
@@ -516,7 +576,7 @@
 {
   // Set up the LLVM context
   context_.setDiagnosticHandler(
-      llvm::make_unique<BEDiagnosticHandler>(&this->hasError_));
+      llvm::make_unique<BEDiagnosticHandler>(&this->hasError_, this->remarkCtl_));
 
   llvm::Optional<unsigned> enable_gc =
       driver_.getLastArgAsInteger(gollvm::options::OPT_enable_gc_EQ, 0u);
diff --git a/driver/GollvmOptions.td b/driver/GollvmOptions.td
index 70a3ba7..3eda9cf 100644
--- a/driver/GollvmOptions.td
+++ b/driver/GollvmOptions.td
@@ -64,6 +64,9 @@
 def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>,
               DocName<"Target-dependent compilation options">;
 
+def R_Group : OptionGroup<"<R group>">, Group<CompileOnly_Group>,
+              DocName<"Optimization remark control options">;
+
 def DebugInfo_Group : OptionGroup<"<g group>">, Group<CompileOnly_Group>,
                       DocName<"Debug information generation">, DocBrief<[{
 Flags controlling how much and what kind of debug information should be
@@ -326,6 +329,16 @@
     Group<f_Group>, Flags<[DriverOption]>,
     HelpText<"Specify the file name of any generated YAML optimization record">;
 
+def Rpass_EQ : Joined<["-"], "Rpass=">, Group<R_Group>,
+  HelpText<"Report transformations performed by optimization passes whose "
+           "name matches the given POSIX regular expression">;
+def Rpass_missed_EQ : Joined<["-"], "Rpass-missed=">, Group<R_Group>,
+  HelpText<"Report missed transformations by optimization passes whose "
+           "name matches the given POSIX regular expression">;
+def Rpass_analysis_EQ : Joined<["-"], "Rpass-analysis=">, Group<R_Group>,
+  HelpText<"Report transformation analysis from optimization passes whose "
+           "name matches the given POSIX regular expression">;
+
 // Target-dependent "-m" options.
 
 def march_EQ : Joined<["-"], "march=">, Group<m_Group>;