Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flang][Driver] Preliminary support for -ftime-report #122894

Merged
merged 1 commit into from
Jan 14, 2025

Conversation

macurtis-amd
Copy link
Contributor

@macurtis-amd macurtis-amd commented Jan 14, 2025

The behavior is not entirely consistent with that of clang for the moment since detailed timing information on the LLVM IR optimization and code generation passes is not provided. The -ftime-report= option is also not enabled since that is only relevant for information about the LLVM IR passes. However, some code to handle that option has been included, to make it easier to support the option when the issues blocking it are resolved. A FortranSupport library has been created that is intended to mirror the LLVM and MLIR support libraries.

Based on @tarunprabhu's PR #107270 with minor changes addressing latest review feedback. He's busy and we'd like to get this support in ASAP.

The behavior is not entirely consistent with that of clang for the moment
since detailed timing information on the LLVM IR optimization and code
generation passes is not provided. The -ftime-report= option is also not enabled
since that is only relevant for information about the LLVM IR passes. However,
some code to handle that option has been included, to make it easier to support
the option when the issues blocking it are resolved. A FortranSupport library
has been created that is intended to mirror the LLVM and MLIR support libraries.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' flang:driver flang Flang issues not falling into any other category labels Jan 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 14, 2025

@llvm/pr-subscribers-clang-driver
@llvm/pr-subscribers-flang-driver

@llvm/pr-subscribers-clang

Author: None (macurtis-amd)

Changes

The behavior is not entirely consistent with that of clang for the moment since detailed timing information on the LLVM IR optimization and code generation passes is not provided. The -ftime-report= option is also not enabled since that is only relevant for information about the LLVM IR passes. However, some code to handle that option has been included, to make it easier to support the option when the issues blocking it are resolved. A FortranSupport library has been created that is intended to mirror the LLVM and MLIR support libraries.


Patch is 26.96 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122894.diff

14 Files Affected:

  • (modified) clang/include/clang/Driver/Options.td (+1-1)
  • (modified) clang/lib/Driver/ToolChains/Flang.cpp (+6-4)
  • (modified) flang/include/flang/Frontend/CompilerInstance.h (+58)
  • (modified) flang/include/flang/Frontend/CompilerInvocation.h (+7)
  • (added) flang/include/flang/Support/StringOstream.h (+32)
  • (added) flang/include/flang/Support/Timing.h (+27)
  • (modified) flang/lib/CMakeLists.txt (+1)
  • (modified) flang/lib/Frontend/CMakeLists.txt (+1)
  • (modified) flang/lib/Frontend/CompilerInstance.cpp (+51-1)
  • (modified) flang/lib/Frontend/CompilerInvocation.cpp (+4)
  • (modified) flang/lib/Frontend/FrontendActions.cpp (+66-6)
  • (added) flang/lib/Support/CMakeLists.txt (+9)
  • (added) flang/lib/Support/Timing.cpp (+67)
  • (added) flang/test/Driver/time-report.f90 (+22)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 7c41d38e00a492..2721c1b5d8dc55 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4108,7 +4108,7 @@ defm ms_tls_guards : BoolFOption<"ms-tls-guards",
           "Do not emit code to perform on-demand initialization of thread-local variables">,
   PosFlag<SetTrue>>;
 def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>,
-  Visibility<[ClangOption, CC1Option]>,
+  Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
   MarshallingInfoFlag<CodeGenOpts<"TimePasses">>;
 def ftime_report_EQ: Joined<["-"], "ftime-report=">, Group<f_Group>,
   Visibility<[ClangOption, CC1Option]>, Values<"per-pass,per-pass-run">,
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 75b10e88371ae7..a7d0cc99f27d2d 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -150,10 +150,12 @@ void Flang::addCodegenOptions(const ArgList &Args,
   if (shouldLoopVersion(Args))
     CmdArgs.push_back("-fversion-loops-for-stride");
 
-  Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir,
-                            options::OPT_flang_deprecated_no_hlfir,
-                            options::OPT_fno_ppc_native_vec_elem_order,
-                            options::OPT_fppc_native_vec_elem_order});
+  Args.addAllArgs(CmdArgs,
+                  {options::OPT_flang_experimental_hlfir,
+                   options::OPT_flang_deprecated_no_hlfir,
+                   options::OPT_fno_ppc_native_vec_elem_order,
+                   options::OPT_fppc_native_vec_elem_order,
+                   options::OPT_ftime_report, options::OPT_ftime_report_EQ});
 }
 
 void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
diff --git a/flang/include/flang/Frontend/CompilerInstance.h b/flang/include/flang/Frontend/CompilerInstance.h
index 4fcc59f7cf577b..509c9f4b9e91aa 100644
--- a/flang/include/flang/Frontend/CompilerInstance.h
+++ b/flang/include/flang/Frontend/CompilerInstance.h
@@ -20,6 +20,7 @@
 #include "flang/Parser/provenance.h"
 #include "flang/Semantics/runtime-type-info.h"
 #include "flang/Semantics/semantics.h"
+#include "flang/Support/StringOstream.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetMachine.h"
 
@@ -85,6 +86,27 @@ class CompilerInstance {
   /// facilitate this. It is optional and will normally be just a nullptr.
   std::unique_ptr<llvm::raw_pwrite_stream> outputStream;
 
+  /// @name Timing
+  /// Objects needed when timing is enabled.
+  /// @{
+  /// The timing manager.
+  mlir::DefaultTimingManager timingMgr;
+
+  /// The root of the timingScope. This will be reset in @ref executeAction if
+  /// timers have been enabled.
+  mlir::TimingScope timingScopeRoot;
+
+  /// @name Timing stream
+  /// The output streams to capture the timing. Three different streams are
+  /// needed because the timing classes all work slightly differently. We create
+  /// these streams so we have control over when and how the timing is
+  /// displayed. Otherwise, the timing is only displayed when the corresponding
+  /// managers/timers go out of scope.
+  std::unique_ptr<Fortran::support::string_ostream> timingStreamMLIR;
+  std::unique_ptr<Fortran::support::string_ostream> timingStreamLLVM;
+  std::unique_ptr<Fortran::support::string_ostream> timingStreamCodeGen;
+  /// @}
+
 public:
   explicit CompilerInstance();
 
@@ -254,6 +276,42 @@ class CompilerInstance {
   /// Produces the string which represents target feature
   std::string getTargetFeatures();
 
+  /// {
+  /// @name Timing
+  /// @{
+  bool isTimingEnabled() const { return timingMgr.isEnabled(); }
+
+  mlir::DefaultTimingManager &getTimingManager() { return timingMgr; }
+  const mlir::DefaultTimingManager &getTimingManager() const {
+    return timingMgr;
+  }
+
+  mlir::TimingScope &getTimingScopeRoot() { return timingScopeRoot; }
+  const mlir::TimingScope &getTimingScopeRoot() const {
+    return timingScopeRoot;
+  }
+
+  /// Get the timing stream for the MLIR pass manager.
+  llvm::raw_ostream &getTimingStreamMLIR() {
+    assert(timingStreamMLIR && "Timing stream for MLIR was not set");
+    return *timingStreamMLIR;
+  }
+
+  /// Get the timing stream for the new LLVM pass manager.
+  llvm::raw_ostream &getTimingStreamLLVM() {
+    assert(timingStreamLLVM && "Timing stream for LLVM was not set");
+    return *timingStreamLLVM;
+  }
+
+  /// Get the timing stream fro the legacy LLVM pass manager.
+  /// NOTE: If the codegen is updated to use the new pass manager, this should
+  /// no longer be needed.
+  llvm::raw_ostream &getTimingStreamCodeGen() {
+    assert(timingStreamCodeGen && "Timing stream for codegen was not set");
+    return *timingStreamCodeGen;
+  }
+  /// @}
+
 private:
   /// Create a new output file
   ///
diff --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h
index 50d908d0832024..7d3f0bdf2e510e 100644
--- a/flang/include/flang/Frontend/CompilerInvocation.h
+++ b/flang/include/flang/Frontend/CompilerInvocation.h
@@ -21,6 +21,7 @@
 #include "flang/Lower/LoweringOptions.h"
 #include "flang/Parser/parsing.h"
 #include "flang/Semantics/semantics.h"
+#include "mlir/Support/Timing.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "llvm/Option/ArgList.h"
@@ -143,6 +144,10 @@ class CompilerInvocation : public CompilerInvocationBase {
       },
   };
 
+  /// Whether to time the invocation. Set when -ftime-report or -ftime-report=
+  /// is enabled.
+  bool enableTimers;
+
 public:
   CompilerInvocation() = default;
 
@@ -222,6 +227,8 @@ class CompilerInvocation : public CompilerInvocationBase {
     return defaultKinds;
   }
 
+  bool getEnableTimers() const { return enableTimers; }
+
   /// Create a compiler invocation from a list of input options.
   /// \returns true on success.
   /// \returns false if an error was encountered while parsing the arguments
diff --git a/flang/include/flang/Support/StringOstream.h b/flang/include/flang/Support/StringOstream.h
new file mode 100644
index 00000000000000..2e5c87eae058c6
--- /dev/null
+++ b/flang/include/flang/Support/StringOstream.h
@@ -0,0 +1,32 @@
+//===-- CompilerInstance.h - Flang Compiler Instance ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_SUPPORT_STRINGOSTREAM_H
+#define FORTRAN_SUPPORT_STRINGOSTREAM_H
+
+#include <llvm/Support/raw_ostream.h>
+
+namespace Fortran::support {
+
+/// Helper class to maintain both the an llvm::raw_string_ostream object and
+/// its associated buffer.
+class string_ostream : public llvm::raw_string_ostream {
+private:
+  std::string buf;
+
+public:
+  string_ostream() : llvm::raw_string_ostream(buf) {}
+};
+
+} // namespace Fortran::support
+
+#endif // FORTRAN_SUPPORT_STRINGOSTREAM_H
diff --git a/flang/include/flang/Support/Timing.h b/flang/include/flang/Support/Timing.h
new file mode 100644
index 00000000000000..75ba2a8d85f39f
--- /dev/null
+++ b/flang/include/flang/Support/Timing.h
@@ -0,0 +1,27 @@
+//===- Timing.h - Execution time measurement facilities ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Facilities to measure and provide statistics on execution time.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_SUPPORT_TIMING_H
+#define FORTRAN_SUPPORT_TIMING_H
+
+#include "mlir/Support/Timing.h"
+
+namespace Fortran::support {
+
+/// Create a strategy to render the captured times in plain text. This is
+/// intended to be passed to a TimingManager.
+std::unique_ptr<mlir::OutputStrategy> createTimingFormatterText(
+    llvm::raw_ostream &os);
+
+} // namespace Fortran::support
+
+#endif // FORTRAN_SUPPORT_TIMING_H
diff --git a/flang/lib/CMakeLists.txt b/flang/lib/CMakeLists.txt
index f41d4df1f07e3c..2182e845b6a793 100644
--- a/flang/lib/CMakeLists.txt
+++ b/flang/lib/CMakeLists.txt
@@ -4,6 +4,7 @@ add_subdirectory(Decimal)
 add_subdirectory(Lower)
 add_subdirectory(Parser)
 add_subdirectory(Semantics)
+add_subdirectory(Support)
 add_subdirectory(Frontend)
 add_subdirectory(FrontendTool)
 
diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt
index e954800c3b88b0..1b90fe826af6c9 100644
--- a/flang/lib/Frontend/CMakeLists.txt
+++ b/flang/lib/Frontend/CMakeLists.txt
@@ -29,6 +29,7 @@ add_flang_library(flangFrontend
   FortranEvaluate
   FortranCommon
   FortranLower
+  FortranSupport
   FIRDialect
   FIRDialectSupport
   FIRSupport
diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp
index 35c2ae3c73e69e..298790bae66558 100644
--- a/flang/lib/Frontend/CompilerInstance.cpp
+++ b/flang/lib/Frontend/CompilerInstance.cpp
@@ -17,9 +17,12 @@
 #include "flang/Parser/parsing.h"
 #include "flang/Parser/provenance.h"
 #include "flang/Semantics/semantics.h"
+#include "flang/Support/Timing.h"
+#include "mlir/Support/RawOstreamExtras.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Pass.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
@@ -147,7 +150,7 @@ void CompilerInstance::clearOutputFiles(bool eraseFiles) {
 }
 
 bool CompilerInstance::executeAction(FrontendAction &act) {
-  auto &invoc = this->getInvocation();
+  CompilerInvocation &invoc = this->getInvocation();
 
   llvm::Triple targetTriple{llvm::Triple(invoc.getTargetOpts().triple)};
   if (targetTriple.getArch() == llvm::Triple::ArchType::x86_64) {
@@ -167,6 +170,25 @@ bool CompilerInstance::executeAction(FrontendAction &act) {
   // Set options controlling lowering to FIR.
   invoc.setLoweringOptions();
 
+  if (invoc.getEnableTimers()) {
+    llvm::TimePassesIsEnabled = true;
+
+    timingStreamMLIR = std::make_unique<Fortran::support::string_ostream>();
+    timingStreamLLVM = std::make_unique<Fortran::support::string_ostream>();
+    timingStreamCodeGen = std::make_unique<Fortran::support::string_ostream>();
+
+    timingMgr.setEnabled(true);
+    timingMgr.setDisplayMode(mlir::DefaultTimingManager::DisplayMode::Tree);
+    timingMgr.setOutput(
+        Fortran::support::createTimingFormatterText(*timingStreamMLIR));
+
+    // Creating a new TimingScope will automatically start the timer. Since this
+    // is the top-level timer, this is ok because it will end up capturing the
+    // time for all the bookkeeping and other tasks that take place between
+    // parsing, lowering etc. for which finer-grained timers will be created.
+    timingScopeRoot = timingMgr.getRootScope();
+  }
+
   // Run the frontend action `act` for every input file.
   for (const FrontendInputFile &fif : getFrontendOpts().inputs) {
     if (act.beginSourceFile(*this, fif)) {
@@ -176,6 +198,34 @@ bool CompilerInstance::executeAction(FrontendAction &act) {
       act.endSourceFile();
     }
   }
+
+  if (timingMgr.isEnabled()) {
+    timingScopeRoot.stop();
+
+    // Write the timings to the associated output stream and clear all timers.
+    // We need to provide another stream because the TimingManager will attempt
+    // to print in its destructor even if it has been cleared. By the time that
+    // destructor runs, the output streams will have been destroyed, so give it
+    // a null stream.
+    timingMgr.print();
+    timingMgr.setOutput(
+        Fortran::support::createTimingFormatterText(mlir::thread_safe_nulls()));
+
+    // This prints the timings in "reverse" order, starting from code
+    // generation, followed by LLVM-IR optimizations, then MLIR optimizations
+    // and transformations and the frontend. If any of the steps are disabled,
+    // for instance because code generation was not performed, the strings
+    // will be empty.
+    if (!timingStreamCodeGen->str().empty())
+      llvm::errs() << timingStreamCodeGen->str() << "\n";
+
+    if (!timingStreamLLVM->str().empty())
+      llvm::errs() << timingStreamLLVM->str() << "\n";
+
+    if (!timingStreamMLIR->str().empty())
+      llvm::errs() << timingStreamMLIR->str() << "\n";
+  }
+
   return !getDiagnostics().getClient()->getNumErrors();
 }
 
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 340efb1c63a5e5..5e7127313c1335 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1436,6 +1436,10 @@ bool CompilerInvocation::createFromArgs(
     }
   }
 
+  // Process the timing-related options.
+  if (args.hasArg(clang::driver::options::OPT_ftime_report))
+    invoc.enableTimers = true;
+
   invoc.setArgv0(argv0);
 
   return success;
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 310cd650349c7a..52a18d59c7cda5 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -84,6 +84,15 @@ extern cl::opt<bool> PrintPipelinePasses;
 
 using namespace Fortran::frontend;
 
+constexpr llvm::StringLiteral timingIdParse = "Parse";
+constexpr llvm::StringLiteral timingIdMLIRGen = "MLIR generation";
+constexpr llvm::StringLiteral timingIdMLIRPasses =
+    "MLIR translation/optimization";
+constexpr llvm::StringLiteral timingIdLLVMIRGen = "LLVM IR generation";
+constexpr llvm::StringLiteral timingIdLLVMIRPasses = "LLVM IR optimizations";
+constexpr llvm::StringLiteral timingIdBackend =
+    "Assembly/Object code generation";
+
 // Declare plugin extension function declarations.
 #define HANDLE_EXTENSION(Ext)                                                  \
   llvm::PassPluginLibraryInfo get##Ext##PluginInfo();
@@ -227,6 +236,14 @@ static void addAMDGPUSpecificMLIRItems(mlir::ModuleOp mlirModule,
 bool CodeGenAction::beginSourceFileAction() {
   llvmCtx = std::make_unique<llvm::LLVMContext>();
   CompilerInstance &ci = this->getInstance();
+  mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
+  mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
+
+  // This will provide timing information even when the input is an LLVM IR or
+  // MLIR file. That is fine because those do have to be parsed, so the label
+  // is still accurate.
+  mlir::TimingScope timingScopeParse = timingScopeRoot.nest(
+      mlir::TimingIdentifier::get(timingIdParse, timingMgr));
 
   // If the input is an LLVM file, just parse it and return.
   if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR) {
@@ -288,6 +305,10 @@ bool CodeGenAction::beginSourceFileAction() {
   if (!res)
     return res;
 
+  timingScopeParse.stop();
+  mlir::TimingScope timingScopeMLIRGen = timingScopeRoot.nest(
+      mlir::TimingIdentifier::get(timingIdMLIRGen, timingMgr));
+
   // Create a LoweringBridge
   const common::IntrinsicTypeDefaultKinds &defKinds =
       ci.getSemanticsContext().defaultKinds();
@@ -322,6 +343,7 @@ bool CodeGenAction::beginSourceFileAction() {
   // constants etc.
   addDependentLibs(*mlirModule, ci);
   addAMDGPUSpecificMLIRItems(*mlirModule, ci);
+  timingScopeMLIRGen.stop();
 
   // run the default passes.
   mlir::PassManager pm((*mlirModule)->getName(),
@@ -344,6 +366,7 @@ bool CodeGenAction::beginSourceFileAction() {
 
   pm.enableVerifier(/*verifyPasses=*/true);
   pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
+  pm.enableTiming(timingScopeMLIRGen);
 
   if (mlir::failed(pm.run(*mlirModule))) {
     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
@@ -352,6 +375,7 @@ bool CodeGenAction::beginSourceFileAction() {
     ci.getDiagnostics().Report(diagID);
     return false;
   }
+  timingScopeMLIRGen.stop();
 
   // Print initial full MLIR module, before lowering or transformations, if
   // -save-temps has been specified.
@@ -704,8 +728,10 @@ void CodeGenAction::lowerHLFIRToFIR() {
   assert(mlirModule && "The MLIR module has not been generated yet.");
 
   CompilerInstance &ci = this->getInstance();
-  auto opts = ci.getInvocation().getCodeGenOpts();
+  const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts();
   llvm::OptimizationLevel level = mapToLevel(opts);
+  mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
+  mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
 
   fir::support::loadDialects(*mlirCtx);
 
@@ -724,6 +750,9 @@ void CodeGenAction::lowerHLFIRToFIR() {
       level);
   (void)mlir::applyPassManagerCLOptions(pm);
 
+  mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest(
+      mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr));
+  pm.enableTiming(timingScopeMLIRPasses);
   if (!mlir::succeeded(pm.run(*mlirModule))) {
     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
         clang::DiagnosticsEngine::Error, "Lowering to FIR failed");
@@ -808,9 +837,12 @@ void CodeGenAction::generateLLVMIR() {
   assert(mlirModule && "The MLIR module has not been generated yet.");
 
   CompilerInstance &ci = this->getInstance();
-  auto opts = ci.getInvocation().getCodeGenOpts();
-  auto mathOpts = ci.getInvocation().getLoweringOpts().getMathOptions();
+  CompilerInvocation &invoc = ci.getInvocation();
+  const CodeGenOptions &opts = invoc.getCodeGenOpts();
+  const auto &mathOpts = invoc.getLoweringOpts().getMathOptions();
   llvm::OptimizationLevel level = mapToLevel(opts);
+  mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
+  mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
 
   fir::support::loadDialects(*mlirCtx);
   mlir::DialectRegistry registry;
@@ -846,11 +878,15 @@ void CodeGenAction::generateLLVMIR() {
   (void)mlir::applyPassManagerCLOptions(pm);
 
   // run the pass manager
+  mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest(
+      mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr));
+  pm.enableTiming(timingScopeMLIRPasses);
   if (!mlir::succeeded(pm.run(*mlirModule))) {
     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
         clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed");
     ci.getDiagnostics().Report(diagID);
   }
+  timingScopeMLIRPasses.stop();
 
   // Print final MLIR module, just before translation into LLVM IR, if
   // -save-temps has been specified.
@@ -863,6 +899,8 @@ void CodeGenAction::generateLLVMIR() {
   }
 
   // Translate to LLVM IR
+  mlir::TimingScope timingScopeLLVMIRGen = timingScopeRoot.nest(
+      mlir::TimingIdentifier::get(timingIdLLVMIRGen, timingMgr));
   std::optional<llvm::StringRef> moduleName = mlirModule->getName();
   llvmModule = mlir::translateModuleToLLVMIR(
       *mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule");
@@ -969,11 +1007,12 @@ static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags,
 }
 
 void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
-  auto opts = getInstance().getInvocation().getCodeGenOpts();
-  auto &diags = getInstance().getDiagnostics();
+  CompilerInstance &ci = getInstance();
+  const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts();
+  clang::DiagnosticsEngine &diags = ci.getDiagnostics();
   llvm::OptimizationLevel level = mapToLevel(opts);
 
-  llvm::TargetMachine *targetMachine = &getInstance().getTargetMachine();
+  llvm::TargetMachine *targetMachine = &ci.getTargetMachine();
   // Create the analysis managers.
   llvm::LoopAnalysisManager lam;
   llvm::FunctionAnalysisManager fam;
@@ -987,6 +1026,8 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
   llvm::StandardInstrumentations si(llvmModule->getContext(),
                                     opts.DebugPassManager);
   si.registerCallbacks(pic, &mam);
+  if (ci.isTimingEnabled...
[truncated]

Copy link
Contributor

@tarunprabhu tarunprabhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you intend to make the behavior consistent with clang (by printing timing information for LLVM passes) in a separate PR?

@macurtis-amd
Copy link
Contributor Author

macurtis-amd commented Jan 14, 2025

Do you intend to make the behavior consistent with clang (by printing timing information for LLVM passes) in a separate PR?

I'm not sure exactly what you are referring to. I did uncomment llvm::TimePassesIsEnabled = true; here.

I'm going to submit this as it is. We can follow-up with additional PRs if functionality is missing.

@macurtis-amd macurtis-amd merged commit 310c281 into llvm:main Jan 14, 2025
13 checks passed
paulhuggett pushed a commit to paulhuggett/llvm-project that referenced this pull request Jan 16, 2025
The behavior is not entirely consistent with that of clang for the
moment since detailed timing information on the LLVM IR optimization and
code generation passes is not provided. The -ftime-report= option is
also not enabled since that is only relevant for information about the
LLVM IR passes. However, some code to handle that option has been
included, to make it easier to support the option when the issues
blocking it are resolved. A FortranSupport library has been created that
is intended to mirror the LLVM and MLIR support libraries.

Based on @tarunprabhu's PR
llvm#107270 with minor changes
addressing latest review feedback. He's busy and we'd like to get this
support in ASAP.

Co-authored-by: Tarun Prabhu <[email protected]>
DKLoehr pushed a commit to DKLoehr/llvm-project that referenced this pull request Jan 17, 2025
The behavior is not entirely consistent with that of clang for the
moment since detailed timing information on the LLVM IR optimization and
code generation passes is not provided. The -ftime-report= option is
also not enabled since that is only relevant for information about the
LLVM IR passes. However, some code to handle that option has been
included, to make it easier to support the option when the issues
blocking it are resolved. A FortranSupport library has been created that
is intended to mirror the LLVM and MLIR support libraries.

Based on @tarunprabhu's PR
llvm#107270 with minor changes
addressing latest review feedback. He's busy and we'd like to get this
support in ASAP.

Co-authored-by: Tarun Prabhu <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category flang:driver flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants