gollvm: initial support for Auto-FDO

Support the -fsample-profile-use= and -fdebug-info-for-profiling
command line options, along with driver changes to enable Auto-FDO.

[Note: Go function/package names cause issues "create_llvm_prof";
without a separate fix to that tool the optimization gains from
AutoFDO will be degraded.]

Change-Id: Ibd6744f7da1483262051b0e6c2461bcee2e77213
Reviewed-on: https://go-review.googlesource.com/c/157240
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/driver/CompileGo.cpp b/driver/CompileGo.cpp
index 23fc08c..a9d30a5 100644
--- a/driver/CompileGo.cpp
+++ b/driver/CompileGo.cpp
@@ -69,6 +69,7 @@
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils.h"
 
 #include <sstream>
 
@@ -108,6 +109,7 @@
   std::unique_ptr<TargetLibraryInfoImpl> tlii_;
   std::string targetCpuAttr_;
   std::string targetFeaturesAttr_;
+  std::string sampleProfileFile_;
   bool enable_gc_;
 
   void createPasses(legacy::PassManager &MPM,
@@ -343,6 +345,32 @@
                                   gollvm::options::OPT_fno_show_column,
                                   true);
 
+  // AutoFDO.
+  opt::Arg *sprofarg =
+      args_.getLastArg(gollvm::options::OPT_fprofile_sample_use,
+                       gollvm::options::OPT_fno_profile_sample_use,
+                       gollvm::options::OPT_fprofile_sample_use_EQ);
+  if (sprofarg) {
+    opt::Arg *fnamearg =
+        args_.getLastArg(gollvm::options::OPT_fprofile_sample_use_EQ);
+    if (fnamearg == nullptr) {
+      // Using -fsample-profile-use / -fno-sample-profile-use without
+      // also using -fprofile-sample-use=XXXX doesn't make sense
+      errs() << progname_ << ": warning: "
+             << "-fprofile-sample-use / -fno-profile-sample-use "
+             << "flags ignored (since no -fprofile-sample-use=<file> "
+             << "specified).\n";
+    } else if (!sprofarg->getOption().matches(
+        gollvm::options::OPT_fno_profile_sample_use)) {
+      StringRef fname = fnamearg->getValue();
+      if (!llvm::sys::fs::exists(fname)) {
+        errs() << progname_ << ": unable to access file: " << fname << "\n";
+        return false;
+      }
+      sampleProfileFile_ = fname;
+    }
+  }
+
   TargetOptions Options;
 
   // FIXME: turn off integrated assembler for now.
@@ -713,6 +741,11 @@
                                        enable);
 }
 
+static void addAddDiscriminatorsPass(const llvm::PassManagerBuilder &Builder,
+                                     llvm::legacy::PassManagerBase &PM) {
+  PM.add(createAddDiscriminatorsPass());
+}
+
 void CompileGoImpl::createPasses(legacy::PassManager &MPM,
                                  legacy::FunctionPassManager &FPM)
 {
@@ -740,6 +773,25 @@
   pmb.SLPVectorize = enableVectorization(true);
   pmb.LoopVectorize = enableVectorization(false);
 
+  bool needDwarfDiscr = false;
+  if (! sampleProfileFile_.empty()) {
+    pmb.PGOSampleUse = sampleProfileFile_;
+    needDwarfDiscr = true;
+  }
+  opt::Arg *dbgprofarg =
+      args_.getLastArg(gollvm::options::OPT_fdebug_info_for_profiling,
+                       gollvm::options::OPT_fno_debug_info_for_profiling);
+  if (dbgprofarg) {
+    if (dbgprofarg->getOption().matches(gollvm::options::OPT_fdebug_info_for_profiling))
+      needDwarfDiscr = true;
+    else
+      needDwarfDiscr = false;
+  }
+  if (needDwarfDiscr)
+    pmb.addExtension(llvm::PassManagerBuilder::EP_EarlyAsPossible,
+                           addAddDiscriminatorsPass);
+
+
   FPM.add(new TargetLibraryInfoWrapperPass(*tlii_));
   if (! args_.hasArg(gollvm::options::OPT_noverify))
     FPM.add(createVerifierPass());
diff --git a/driver/GollvmOptions.td b/driver/GollvmOptions.td
index a997b08..b74e61f 100644
--- a/driver/GollvmOptions.td
+++ b/driver/GollvmOptions.td
@@ -301,6 +301,21 @@
 def fdebug_prefix_map_EQ : Joined<["-"], "fdebug-prefix-map=">, Group<f_Group>,
   HelpText<"remap file source paths in debug info">;
 
+
+def fprofile_sample_use : Flag<["-"], "fprofile-sample-use">, Group<f_Group>, Flags<[DriverOption]>;
+def fno_profile_sample_use : Flag<["-"], "fno-profile-sample-use">, Group<f_Group>, Flags<[DriverOption]>;
+
+def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">,
+    Group<f_Group>, Flags<[DriverOption]>,
+    HelpText<"Enable sample-based profile guided optimizations">;
+
+def fdebug_info_for_profiling : Flag<["-"], "fdebug-info-for-profiling">, Group<f_Group>,
+    Flags<[DriverOption]>,
+    HelpText<"Emit extra debug info to make sample profile more accurate.">;
+def fno_debug_info_for_profiling : Flag<["-"], "fno-debug-info-for-profiling">, Group<f_Group>,
+    Flags<[DriverOption]>,
+    HelpText<"Do not emit extra debug info for sample profiler.">;
+    
 // Target-dependent "-m" options.
 
 def march_EQ : Joined<["-"], "march=">, Group<m_Group>;