Add flags -Rpass-missed and -Rpass-analysis.
authorDiego Novillo <dnovillo@google.com>
Thu, 29 May 2014 19:55:06 +0000 (19:55 +0000)
committerDiego Novillo <dnovillo@google.com>
Thu, 29 May 2014 19:55:06 +0000 (19:55 +0000)
Summary:
These two flags are in the same family as -Rpass, but are used in
different situations.

-Rpass-missed is used by optimizers to inform the user when they tried
to apply an optimization but couldn't (or wouldn't).

-Rpass-analysis is used by optimizers to report analysis results back
to the user (e.g., why the transformation could not be applied).

Depends on D3682.

Reviewers: rsmith

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D3683

llvm-svn: 209839

clang/include/clang/Basic/DiagnosticFrontendKinds.td
clang/include/clang/Basic/DiagnosticGroups.td
clang/include/clang/Driver/Options.td
clang/include/clang/Frontend/CodeGenOptions.h
clang/lib/CodeGen/CodeGenAction.cpp
clang/lib/Driver/Tools.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/test/Frontend/optimization-remark.c

index 91faa0a..03ed691 100644 (file)
@@ -34,6 +34,10 @@ def note_fe_backend_plugin: Note<"%0">, CatBackend;
 
 def remark_fe_backend_optimization_remark : Remark<"%0">, CatBackend,
     InGroup<BackendOptimizationRemark>, DefaultRemark;
+def remark_fe_backend_optimization_remark_missed : Remark<"%0">, CatBackend,
+    InGroup<BackendOptimizationRemarkMissed>, DefaultRemark;
+def remark_fe_backend_optimization_remark_analysis : Remark<"%0">, CatBackend,
+    InGroup<BackendOptimizationRemarkAnalysis>, DefaultRemark;
 def note_fe_backend_optimization_remark_missing_loc : Note<"use "
   "-gline-tables-only -gcolumn-info to track source location information "
   "for this optimization remark">;
index 230e021..637d4fc 100644 (file)
@@ -685,6 +685,8 @@ def BackendFrameLargerThan : DiagGroup<"frame-larger-than">;
 def BackendPlugin : DiagGroup<"backend-plugin">;
 def RemarkBackendPlugin : DiagGroup<"remark-backend-plugin">;
 def BackendOptimizationRemark : DiagGroup<"pass">;
+def BackendOptimizationRemarkMissed : DiagGroup<"pass-missed">;
+def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">;
 
 // Instrumentation based profiling warnings.
 def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
index 0e251aa..d277551 100644 (file)
@@ -257,6 +257,14 @@ def Q : Flag<["-"], "Q">;
 def Rpass_EQ : Joined<["-"], "Rpass=">, Group<R_Group>, Flags<[CC1Option]>,
   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>,
+  Flags<[CC1Option]>,
+  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>,
+  Flags<[CC1Option]>,
+  HelpText<"Report transformation analysis from optimization passes whose "
+           "name matches the given POSIX regular expression">;
 def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
   HelpText<"Only run preprocess and compilation steps">;
 def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>;
index 9c8de1b..c1ad408 100644 (file)
@@ -153,6 +153,21 @@ public:
   /// -Rpass=regexp flag.
   std::shared_ptr<llvm::Regex> OptimizationRemarkPattern;
 
+  /// Regular expression to select optimizations for which we should enable
+  /// missed optimization remarks. Transformation passes whose name matches this
+  /// expression (and support this feature), will emit a diagnostic
+  /// whenever they tried but failed to perform a transformation. This is
+  /// enabled by the -Rpass-missed=regexp flag.
+  std::shared_ptr<llvm::Regex> OptimizationRemarkMissedPattern;
+
+  /// Regular expression to select optimizations for which we should enable
+  /// optimization analyses. Transformation passes whose name matches this
+  /// expression (and support this feature), will emit a diagnostic
+  /// whenever they want to explain why they decided to apply or not apply
+  /// a given transformation. This is enabled by the -Rpass-analysis=regexp
+  /// flag.
+  std::shared_ptr<llvm::Regex> OptimizationRemarkAnalysisPattern;
+
 public:
   // Define accessors/mutators for code generation options of enumeration type.
 #define CODEGENOPT(Name, Bits, Default)
index 4bb3895..d337fa7 100644 (file)
@@ -235,11 +235,18 @@ namespace clang {
     /// \return True if the diagnostic has been successfully reported, false
     /// otherwise.
     bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D);
-    /// \brief Specialized handler for the optimization diagnostic.
-    /// Note that this handler only accepts remarks and it always handles
+    /// \brief Specialized handlers for optimization remarks.
+    /// Note that these handlers only accept remarks and they always handle
     /// them.
     void
+    EmitOptimizationRemark(const llvm::DiagnosticInfoOptimizationRemarkBase &D,
+                           unsigned DiagID);
+    void
     OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationRemark &D);
+    void OptimizationRemarkHandler(
+        const llvm::DiagnosticInfoOptimizationRemarkMissed &D);
+    void OptimizationRemarkHandler(
+        const llvm::DiagnosticInfoOptimizationRemarkAnalysis &D);
   };
   
   void BackendConsumer::anchor() {}
@@ -394,49 +401,74 @@ BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) {
   return true;
 }
 
-void BackendConsumer::OptimizationRemarkHandler(
-    const llvm::DiagnosticInfoOptimizationRemark &D) {
+void BackendConsumer::EmitOptimizationRemark(
+    const llvm::DiagnosticInfoOptimizationRemarkBase &D, unsigned DiagID) {
   // We only support remarks.
   assert(D.getSeverity() == llvm::DS_Remark);
 
-  // Optimization remarks are active only if -Rpass=regexp is given and the
-  // regular expression pattern in 'regexp' matches the name of the pass
-  // name in \p D.
-  if (CodeGenOpts.OptimizationRemarkPattern &&
-      CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName())) {
-    SourceManager &SourceMgr = Context->getSourceManager();
-    FileManager &FileMgr = SourceMgr.getFileManager();
-    StringRef Filename;
-    unsigned Line, Column;
-    D.getLocation(&Filename, &Line, &Column);
-    SourceLocation Loc;
-    const FileEntry *FE = FileMgr.getFile(Filename);
-    if (FE && Line > 0) {
-      // If -gcolumn-info was not used, Column will be 0. This upsets the
-      // source manager, so if Column is not set, set it to 1.
-      if (Column == 0)
-        Column = 1;
-      Loc = SourceMgr.translateFileLineCol(FE, Line, Column);
-    }
-    Diags.Report(Loc, diag::remark_fe_backend_optimization_remark)
-        << AddFlagValue(D.getPassName()) << D.getMsg().str();
-
-    if (Line == 0)
-      // If we could not extract a source location for the diagnostic,
-      // inform the user how they can get source locations back.
-      //
-      // FIXME: We should really be generating !srcloc annotations when
-      // -Rpass is used. !srcloc annotations need to be emitted in
-      // approximately the same spots as !dbg nodes.
-      Diags.Report(diag::note_fe_backend_optimization_remark_missing_loc);
-    else if (Loc.isInvalid())
-      // If we were not able to translate the file:line:col information
-      // back to a SourceLocation, at least emit a note stating that
-      // we could not translate this location. This can happen in the
-      // case of #line directives.
-      Diags.Report(diag::note_fe_backend_optimization_remark_invalid_loc)
-        << Filename << Line << Column;
+  SourceManager &SourceMgr = Context->getSourceManager();
+  FileManager &FileMgr = SourceMgr.getFileManager();
+  StringRef Filename;
+  unsigned Line, Column;
+  D.getLocation(&Filename, &Line, &Column);
+  SourceLocation Loc;
+  const FileEntry *FE = FileMgr.getFile(Filename);
+  if (FE && Line > 0) {
+    // If -gcolumn-info was not used, Column will be 0. This upsets the
+    // source manager, so if Column is not set, set it to 1.
+    if (Column == 0)
+      Column = 1;
+    Loc = SourceMgr.translateFileLineCol(FE, Line, Column);
   }
+  Diags.Report(Loc, DiagID) << AddFlagValue(D.getPassName())
+                            << D.getMsg().str();
+
+  if (Line == 0)
+    // If we could not extract a source location for the diagnostic,
+    // inform the user how they can get source locations back.
+    //
+    // FIXME: We should really be generating !srcloc annotations when
+    // -Rpass is used. !srcloc annotations need to be emitted in
+    // approximately the same spots as !dbg nodes.
+    Diags.Report(diag::note_fe_backend_optimization_remark_missing_loc);
+  else if (Loc.isInvalid())
+    // If we were not able to translate the file:line:col information
+    // back to a SourceLocation, at least emit a note stating that
+    // we could not translate this location. This can happen in the
+    // case of #line directives.
+    Diags.Report(diag::note_fe_backend_optimization_remark_invalid_loc)
+        << Filename << Line << Column;
+}
+
+void BackendConsumer::OptimizationRemarkHandler(
+    const llvm::DiagnosticInfoOptimizationRemark &D) {
+  // Optimization remarks are active only if the -Rpass flag has a regular
+  // expression that matches the name of the pass name in \p D.
+  if (CodeGenOpts.OptimizationRemarkPattern &&
+      CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName()))
+    EmitOptimizationRemark(D, diag::remark_fe_backend_optimization_remark);
+}
+
+void BackendConsumer::OptimizationRemarkHandler(
+    const llvm::DiagnosticInfoOptimizationRemarkMissed &D) {
+  // Missed optimization remarks are active only if the -Rpass-missed
+  // flag has a regular expression that matches the name of the pass
+  // name in \p D.
+  if (CodeGenOpts.OptimizationRemarkMissedPattern &&
+      CodeGenOpts.OptimizationRemarkMissedPattern->match(D.getPassName()))
+    EmitOptimizationRemark(D,
+                           diag::remark_fe_backend_optimization_remark_missed);
+}
+
+void BackendConsumer::OptimizationRemarkHandler(
+    const llvm::DiagnosticInfoOptimizationRemarkAnalysis &D) {
+  // Optimization analysis remarks are active only if the -Rpass-analysis
+  // flag has a regular expression that matches the name of the pass
+  // name in \p D.
+  if (CodeGenOpts.OptimizationRemarkAnalysisPattern &&
+      CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName()))
+    EmitOptimizationRemark(
+        D, diag::remark_fe_backend_optimization_remark_analysis);
 }
 
 /// \brief This function is invoked when the backend needs
@@ -462,10 +494,15 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
     OptimizationRemarkHandler(cast<DiagnosticInfoOptimizationRemark>(DI));
     return;
   case llvm::DK_OptimizationRemarkMissed:
+    // Optimization remarks are always handled completely by this
+    // handler. There is no generic way of emitting them.
+    OptimizationRemarkHandler(cast<DiagnosticInfoOptimizationRemarkMissed>(DI));
+    return;
   case llvm::DK_OptimizationRemarkAnalysis:
-    // TODO: Do nothing for now. The implementation of these
-    // two remarks is still under review (http://reviews.llvm.org/D3683).
-    // Remove this once that patch lands.
+    // Optimization remarks are always handled completely by this
+    // handler. There is no generic way of emitting them.
+    OptimizationRemarkHandler(
+        cast<DiagnosticInfoOptimizationRemarkAnalysis>(DI));
     return;
   default:
     // Plugin IDs are not bound to any value as they are set dynamically.
index b623e10..ee3b7ff 100644 (file)
@@ -3469,6 +3469,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   if (Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
     A->render(Args, CmdArgs);
 
+  if (Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ))
+    A->render(Args, CmdArgs);
+
+  if (Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ))
+    A->render(Args, CmdArgs);
+
   if (Args.hasArg(options::OPT_mkernel)) {
     if (!Args.hasArg(options::OPT_fapple_kext) && types::isCXX(InputType))
       CmdArgs.push_back("-fapple-kext");
index 1ed24a7..70c2fec 100644 (file)
@@ -309,6 +309,22 @@ static StringRef getCodeModel(ArgList &Args, DiagnosticsEngine &Diags) {
   return "default";
 }
 
+/// \brief Create a new Regex instance out of the string value in \p RpassArg.
+/// It returns a pointer to the newly generated Regex instance.
+static std::shared_ptr<llvm::Regex>
+GenerateOptimizationRemarkRegex(DiagnosticsEngine &Diags, ArgList &Args,
+                                Arg *RpassArg) {
+  StringRef Val = RpassArg->getValue();
+  std::string RegexError;
+  std::shared_ptr<llvm::Regex> Pattern = std::make_shared<llvm::Regex>(Val);
+  if (!Pattern->isValid(RegexError)) {
+    Diags.Report(diag::err_drv_optimization_remark_pattern)
+        << RegexError << RpassArg->getAsString(Args);
+    Pattern.reset();
+  }
+  return Pattern;
+}
+
 static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
                              DiagnosticsEngine &Diags,
                              const TargetOptions &TargetOpts) {
@@ -545,6 +561,18 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
     }
   }
 
+  if (Arg *A = Args.getLastArg(OPT_Rpass_EQ))
+    Opts.OptimizationRemarkPattern =
+        GenerateOptimizationRemarkRegex(Diags, Args, A);
+
+  if (Arg *A = Args.getLastArg(OPT_Rpass_missed_EQ))
+    Opts.OptimizationRemarkMissedPattern =
+        GenerateOptimizationRemarkRegex(Diags, Args, A);
+
+  if (Arg *A = Args.getLastArg(OPT_Rpass_analysis_EQ))
+    Opts.OptimizationRemarkAnalysisPattern =
+        GenerateOptimizationRemarkRegex(Diags, Args, A);
+
   return Success;
 }
 
index 3a62db0..c36a9d4 100644 (file)
@@ -1,18 +1,29 @@
-// This file tests the -Rpass= flag with the inliner. The test is
-// designed to always trigger the inliner, so it should be independent
-// of the optimization level.
+// This file tests the -Rpass family of flags (-Rpass, -Rpass-missed
+// and -Rpass-analysis) with the inliner. The test is designed to
+// always trigger the inliner, so it should be independent of the
+// optimization level.
 
-// RUN: %clang_cc1 %s -Rpass=inline -O0 -gline-tables-only -emit-obj -verify -S -o /dev/null 2> %t.err
+// RUN: %clang_cc1 %s -Rpass=inline -Rpass-analysis=inline -Rpass-missed=inline -O0 -gline-tables-only -emit-obj -verify -S -o /dev/null 2> %t.err
 
 // RUN: %clang -c %s -Rpass=inline -O0 -S -o /dev/null 2> %t.err
 // RUN: FileCheck < %t.err %s --check-prefix=INLINE-NO-LOC
 
 int foo(int x, int y) __attribute__((always_inline));
-
 int foo(int x, int y) { return x + y; }
 
+float foz(int x, int y) __attribute__((noinline));
+float foz(int x, int y) { return x * y; }
+
+// The negative diagnostics are emitted twice because the inliner runs
+// twice.
+//
+// expected-remark@+6 {{foz should never be inlined (cost=never)}}
+// expected-remark@+5 {{foz will not be inlined into bar}}
+// expected-remark@+4 {{foz should never be inlined}}
+// expected-remark@+3 {{foz will not be inlined into bar}}
+// expected-remark@+2 {{foo should always be inlined}}
 // expected-remark@+1 {{foo inlined into bar}}
-int bar(int j) { return foo(j, j - 2); }
+int bar(int j) { return foo(j, j - 2) * foz(j - 2, j); }
 
 // INLINE-NO-LOC: {{^remark: foo inlined into bar}}
 // INLINE-NO-LOC: note: use -gline-tables-only -gcolumn-info to track