CODEGENOPT(FineGrainedBitfieldAccesses, 1, 0) ///< Enable fine-grained bitfield accesses.
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers
-CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled.
+CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report or -ftime-report= is enabled.
+CODEGENOPT(TimePassesPerRun , 1, 0) ///< Set when -ftime-report=per-pass-run is enabled.
CODEGENOPT(TimeTrace , 1, 0) ///< Set when -ftime-trace is enabled.
VALUE_CODEGENOPT(TimeTraceGranularity, 32, 500) ///< Minimum time granularity (in microseconds),
///< traced by time profiler
def : Flag<["-"], "fterminated-vtables">, Alias<fapple_kext>;
def fthreadsafe_statics : Flag<["-"], "fthreadsafe-statics">, Group<f_Group>;
def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>, Flags<[CC1Option]>,
- MarshallingInfoFlag<"FrontendOpts.ShowTimers">;
+ MarshallingInfoFlag<"CodeGenOpts.TimePasses">;
+def ftime_report_EQ: Joined<["-"], "ftime-report=">, Group<f_Group>,
+ Flags<[CC1Option]>, Values<"per-pass,per-pass-run">,
+ MarshallingInfoFlag<"CodeGenOpts.TimePassesPerRun">,
+ HelpText<"(For new pass manager) \"per-pass\": one report for each pass; "
+ "\"per-pass-run\": one report for each pass invocation">;
def ftime_trace : Flag<["-"], "ftime-trace">, Group<f_Group>,
HelpText<"Turn on time profiler. Generates JSON file based on output filename.">,
DocBrief<[{
/// Show frontend performance metrics and statistics.
unsigned ShowStats : 1;
- /// Show timers for individual actions.
- unsigned ShowTimers : 1;
-
/// print the supported cpus for the current target
unsigned PrintSupportedCPUs : 1;
public:
FrontendOptions()
: DisableFree(false), RelocatablePCH(false), ShowHelp(false),
- ShowStats(false), ShowTimers(false), TimeTrace(false),
- ShowVersion(false), FixWhatYouCan(false), FixOnlyWarnings(false),
- FixAndRecompile(false), FixToTemporaries(false),
- ARCMTMigrateEmitARCErrors(false), SkipFunctionBodies(false),
- UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true),
- ASTDumpDecls(false), ASTDumpLookups(false),
- BuildingImplicitModule(false), ModulesEmbedAllFiles(false),
- IncludeTimestamps(true), UseTemporary(true),
- AllowPCMWithCompilerErrors(false), TimeTraceGranularity(500) {}
+ ShowStats(false), TimeTrace(false), ShowVersion(false),
+ FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
+ FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
+ SkipFunctionBodies(false), UseGlobalModuleIndex(true),
+ GenerateGlobalModuleIndex(true), ASTDumpDecls(false),
+ ASTDumpLookups(false), BuildingImplicitModule(false),
+ ModulesEmbedAllFiles(false), IncludeTimestamps(true),
+ UseTemporary(true), AllowPCMWithCompilerErrors(false),
+ TimeTraceGranularity(500) {}
/// getInputKindForExtension - Return the appropriate input kind for a file
/// extension. For example, "c" would return Language::C.
// Frontend timing utils
-/// If the user specifies the -ftime-report argument on an Clang command line
-/// then the value of this boolean will be true, otherwise false.
-extern bool FrontendTimesIsEnabled;
-
} // namespace clang
#endif // LLVM_CLANG_FRONTEND_UTILS_H
void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
std::unique_ptr<raw_pwrite_stream> OS) {
- TimeRegion Region(FrontendTimesIsEnabled ? &CodeGenerationTime : nullptr);
+ TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : nullptr);
setCommandLineOpts(CodeGenOpts);
/// `EmitAssembly` at some point in the future when the default switches.
void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) {
- TimeRegion Region(FrontendTimesIsEnabled ? &CodeGenerationTime : nullptr);
+ TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : nullptr);
setCommandLineOpts(CodeGenOpts);
bool RequiresCodeGen = (Action != Backend_EmitNothing &&
/// can happen when Clang plugins trigger additional AST deserialization.
bool IRGenFinished = false;
+ bool TimerIsEnabled = false;
+
std::unique_ptr<CodeGenerator> Gen;
SmallVector<LinkModule, 4> LinkModules;
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts,
- const LangOptions &LangOpts, bool TimePasses,
- const std::string &InFile,
+ const LangOptions &LangOpts, const std::string &InFile,
SmallVector<LinkModule, 4> LinkModules,
std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr)
Gen(CreateLLVMCodeGen(Diags, InFile, HeaderSearchOpts, PPOpts,
CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)) {
- FrontendTimesIsEnabled = TimePasses;
- llvm::TimePassesIsEnabled = TimePasses;
+ TimerIsEnabled = CodeGenOpts.TimePasses;
+ llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
+ llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
}
// This constructor is used in installing an empty BackendConsumer
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts,
- const LangOptions &LangOpts, bool TimePasses,
+ const LangOptions &LangOpts,
SmallVector<LinkModule, 4> LinkModules, LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr)
: Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
Gen(CreateLLVMCodeGen(Diags, "", HeaderSearchOpts, PPOpts,
CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)) {
- FrontendTimesIsEnabled = TimePasses;
- llvm::TimePassesIsEnabled = TimePasses;
+ TimerIsEnabled = CodeGenOpts.TimePasses;
+ llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
+ llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
}
llvm::Module *getModule() const { return Gen->GetModule(); }
std::unique_ptr<llvm::Module> takeModule() {
Context = &Ctx;
- if (FrontendTimesIsEnabled)
+ if (TimerIsEnabled)
LLVMIRGeneration.startTimer();
Gen->Initialize(Ctx);
- if (FrontendTimesIsEnabled)
+ if (TimerIsEnabled)
LLVMIRGeneration.stopTimer();
}
"LLVM IR generation of declaration");
// Recurse.
- if (FrontendTimesIsEnabled) {
+ if (TimerIsEnabled) {
LLVMIRGenerationRefCount += 1;
if (LLVMIRGenerationRefCount == 1)
LLVMIRGeneration.startTimer();
Gen->HandleTopLevelDecl(D);
- if (FrontendTimesIsEnabled) {
+ if (TimerIsEnabled) {
LLVMIRGenerationRefCount -= 1;
if (LLVMIRGenerationRefCount == 0)
LLVMIRGeneration.stopTimer();
PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
Context->getSourceManager(),
"LLVM IR generation of inline function");
- if (FrontendTimesIsEnabled)
+ if (TimerIsEnabled)
LLVMIRGeneration.startTimer();
Gen->HandleInlineFunctionDefinition(D);
- if (FrontendTimesIsEnabled)
+ if (TimerIsEnabled)
LLVMIRGeneration.stopTimer();
}
{
llvm::TimeTraceScope TimeScope("Frontend");
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
- if (FrontendTimesIsEnabled) {
+ if (TimerIsEnabled) {
LLVMIRGenerationRefCount += 1;
if (LLVMIRGenerationRefCount == 1)
LLVMIRGeneration.startTimer();
Gen->HandleTranslationUnit(C);
- if (FrontendTimesIsEnabled) {
+ if (TimerIsEnabled) {
LLVMIRGenerationRefCount -= 1;
if (LLVMIRGenerationRefCount == 0)
LLVMIRGeneration.stopTimer();
std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
- CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, std::string(InFile),
- std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo));
+ CI.getLangOpts(), std::string(InFile), std::move(LinkModules),
+ std::move(OS), *VMContext, CoverageInfo));
BEConsumer = Result.get();
// Enable generating macro debug info only when debug info is not disabled and
BackendConsumer Result(BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
CI.getTargetOpts(), CI.getLangOpts(),
- CI.getFrontendOpts().ShowTimers,
std::move(LinkModules), *VMContext, nullptr);
// PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be
// true here because the valued names are needed for reading textual IR.
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
+ Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace);
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
FrontendAction.cpp
FrontendActions.cpp
FrontendOptions.cpp
- FrontendTiming.cpp
HeaderIncludeGen.cpp
InitHeaderSearch.cpp
InitPreprocessor.cpp
<< " based upon " << BACKEND_PACKAGE_STRING
<< " default target " << llvm::sys::getDefaultTargetTriple() << "\n";
- if (getFrontendOpts().ShowTimers)
+ if (getCodeGenOpts().TimePasses)
createFrontendTimer();
if (getFrontendOpts().ShowStats || !getFrontendOpts().StatsFile.empty())
Opts.setFramePointer(FP);
}
+ if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ)) {
+ Opts.TimePasses = true;
+
+ // -ftime-report= is only for new pass manager.
+ if (A->getOption().getID() == OPT_ftime_report_EQ) {
+ if (!Opts.ExperimentalNewPassManager)
+ Diags.Report(diag::err_drv_argument_only_allowed_with)
+ << A->getAsString(Args) << "-fexperimental-new-pass-manager";
+
+ StringRef Val = A->getValue();
+ if (Val == "per-pass")
+ Opts.TimePassesPerRun = false;
+ else if (Val == "per-pass-run")
+ Opts.TimePassesPerRun = true;
+ else
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ }
+
Opts.DisableFree = Args.hasArg(OPT_disable_free);
Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names);
Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);
+++ /dev/null
-//===- FrontendTiming.cpp - Implements Frontend timing utils -------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file keps implementation of frontend timing utils.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/Utils.h"
-
-namespace clang {
-
-bool FrontendTimesIsEnabled = false;
-
-}
--- /dev/null
+// Check that -ftime-report flag is passed to compiler. The value of the flag
+// is only diagnosed in the compiler for simplicity since this is a dev option.
+// RUN: %clang -### -c -ftime-report %s 2>&1 | FileCheck %s
+// RUN: %clang -### -c -ftime-report=per-pass %s 2>&1 | FileCheck %s -check-prefix=PER-PASS
+// RUN: %clang -### -c -ftime-report=per-pass-run %s 2>&1 | FileCheck %s -check-prefix=PER-PASS-INVOKE
+// RUN: %clang -### -c -ftime-report=unknown %s 2>&1 | FileCheck %s -check-prefix=UNKNOWN
+
+// CHECK: "-ftime-report"
+// PER-PASS: "-ftime-report=per-pass"
+// PER-PASS-INVOKE: "-ftime-report=per-pass-run"
+// UNKNOWN: "-ftime-report=unknown"
--- /dev/null
+// Check that legacy pass manager could only use -ftime-report
+// RUN: %clang_cc1 -fno-experimental-new-pass-manager -emit-obj -O1 \
+// RUN: -ftime-report %s -o /dev/null 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=TIME,LPM
+// RUN: not %clang_cc1 -fno-experimental-new-pass-manager -emit-obj -O1 \
+// RUN: -ftime-report=per-pass %s -o /dev/null 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=ERROR
+// RUN: not %clang_cc1 -fno-experimental-new-pass-manager -emit-obj -O1 \
+// RUN: -ftime-report=per-pass-run %s -o /dev/null 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=ERROR
+
+// Check -ftime-report/-ftime-report= output for the new pass manager
+// RUN: %clang_cc1 -emit-obj -O1 -fexperimental-new-pass-manager \
+// RUN: -ftime-report %s -o /dev/null 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=TIME,NPM
+// RUN: %clang_cc1 -emit-obj -O1 -fexperimental-new-pass-manager \
+// RUN: -ftime-report=per-pass %s -o /dev/null 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=TIME,NPM
+// RUN: %clang_cc1 -emit-obj -O1 -fexperimental-new-pass-manager \
+// RUN: -ftime-report=per-pass-run %s -o /dev/null 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=TIME,NPM-PER-INVOKE
+
+// TIME: Pass execution timing report
+// TIME: Total Execution Time:
+// TIME: Name
+// LPM-DAG: Dominator Tree Construction #
+// LPM-DAG: Dominator Tree Construction #
+// LPM-DAG: Dominator Tree Construction #
+// NPM-PER-INVOKE-DAG: InstCombinePass #
+// NPM-PER-INVOKE-DAG: InstCombinePass #
+// NPM-PER-INVOKE-DAG: InstCombinePass #
+// NPM-NOT: InstCombinePass #
+// NPM: InstCombinePass{{$}}
+// NPM-NOT: InstCombinePass #
+// TIME: Total{{$}}
+// LPM-NOT: Pass execution timing report
+// NPM: Pass execution timing report
+
+// ERROR: error: invalid argument '-ftime-report={{.*}}' only allowed with '-fexperimental-new-pass-manager'
+
+int foo(int x, int y) { return x + y; }
/// Request the timer for this legacy-pass-manager's pass instance.
Timer *getPassTimer(Pass *);
-/// If the user specifies the -time-passes argument on an LLVM tool command line
-/// then the value of this boolean will be true, otherwise false.
-/// This is the storage for the -time-passes option.
-extern bool TimePassesIsEnabled;
-
/// This class implements -time-passes functionality for new pass manager.
/// It provides the pass-instrumentation callbacks that measure the pass
/// execution time. They collect timing info into individual timers as
raw_ostream *OutStream = nullptr;
bool Enabled;
+ bool PerRun;
public:
- TimePassesHandler(bool Enabled = TimePassesIsEnabled);
+ TimePassesHandler();
+ TimePassesHandler(bool Enabled, bool PerRun = false);
/// Destructor handles the print action if it has not been handled before.
~TimePassesHandler() { print(); }
/// then the value of this boolean will be true, otherwise false.
/// This is the storage for the -time-passes option.
extern bool TimePassesIsEnabled;
+/// If TimePassesPerRun is true, there would be one line of report for
+/// each pass invocation.
+/// If TimePassesPerRun is false, there would be only one line of
+/// report for each pass (even there are more than one pass objects).
+/// (For new pass manager only)
+extern bool TimePassesPerRun;
} // end namespace llvm
namespace llvm {
bool TimePassesIsEnabled = false;
+bool TimePassesPerRun = false;
static cl::opt<bool, true> EnableTiming(
"time-passes", cl::location(TimePassesIsEnabled), cl::Hidden,
cl::desc("Time each pass, printing elapsed time for each on exit"));
+static cl::opt<bool, true> EnableTimingPerRun(
+ "time-passes-per-run", cl::location(TimePassesPerRun), cl::Hidden,
+ cl::desc("Time each pass run, printing elapsed time for each run on exit"),
+ cl::callback([](const bool &) { TimePassesIsEnabled = true; }));
+
namespace {
namespace legacy {
/// Returns the timer for the specified pass invocation of \p PassID.
/// Each time it creates a new timer.
Timer &TimePassesHandler::getPassTimer(StringRef PassID) {
+ if (!PerRun) {
+ TimerVector &Timers = TimingData[PassID];
+ if (Timers.size() == 0)
+ Timers.emplace_back(new Timer(PassID, PassID, TG));
+ return *Timers.front();
+ }
+
// Take a vector of Timers created for this \p PassID and append
// one more timer to it.
TimerVector &Timers = TimingData[PassID];
return *T;
}
-TimePassesHandler::TimePassesHandler(bool Enabled)
- : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled) {}
+TimePassesHandler::TimePassesHandler(bool Enabled, bool PerRun)
+ : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled),
+ PerRun(PerRun) {}
+
+TimePassesHandler::TimePassesHandler()
+ : TimePassesHandler(TimePassesIsEnabled, TimePassesPerRun) {}
void TimePassesHandler::setOutStream(raw_ostream &Out) {
OutStream = &Out;
; RUN: opt -enable-new-pm=0 < %s -disable-output -instcombine -instcombine -licm -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-LEGACY
; RUN: opt -enable-new-pm=0 < %s -disable-output -instcombine -instcombine -licm -licm -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-LEGACY --check-prefix=TIME-DOUBLE-LICM-LEGACY
-; RUN: opt < %s -disable-output -passes='instcombine,instcombine,loop(licm)' -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-NEW
-; RUN: opt < %s -disable-output -passes='instcombine,loop(licm),instcombine,loop(licm)' -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-NEW -check-prefix=TIME-DOUBLE-LICM-NEW
; RUN: opt < %s -disable-output -passes='default<O2>' -time-passes 2>&1 | FileCheck %s --check-prefix=TIME
;
+; For new pass manager, check that -time-passes-per-run emit one report for each pass run.
+; RUN: opt < %s -disable-output -passes='instcombine,instcombine,loop(licm)' -time-passes-per-run 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-NEW
+; RUN: opt < %s -disable-output -passes='instcombine,loop(licm),instcombine,loop(licm)' -time-passes-per-run 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-NEW -check-prefix=TIME-DOUBLE-LICM-NEW
+;
+; For new pass manager, check that -time-passes emit one report for each pass.
+; RUN: opt < %s -disable-output -passes='instcombine,instcombine,loop(licm)' -time-passes 2>&1 | FileCheck %s --check-prefixes=TIME,TIME-NEW-PER-PASS
+; RUN: opt < %s -disable-output -passes='instcombine,loop(licm),instcombine,loop(licm)' -time-passes 2>&1 | FileCheck %s --check-prefixes=TIME,TIME-NEW-PER-PASS
+;
; The following 4 test runs verify -info-output-file interaction (default goes to stderr, '-' goes to stdout).
; RUN: opt -enable-new-pm=0 < %s -disable-output -O2 -time-passes -info-output-file='-' 2>/dev/null | FileCheck %s --check-prefix=TIME
; RUN: opt < %s -disable-output -passes='default<O2>' -time-passes -info-output-file='-' 2>/dev/null | FileCheck %s --check-prefix=TIME
; TIME-NEW-DAG: VerifierPass
; TIME-NEW-DAG: DominatorTreeAnalysis
; TIME-NEW-DAG: TargetLibraryAnalysis
+; TIME-NEW-PER-PASS-DAG: InstCombinePass
+; TIME-NEW-PER-PASS-DAG: LICMPass
+; TIME-NEW-PER-PASS-DAG: LCSSAPass
+; TIME-NEW-PER-PASS-DAG: LoopSimplifyPass
+; TIME-NEW-PER-PASS-DAG: ScalarEvolutionAnalysis
+; TIME-NEW-PER-PASS-DAG: LoopAnalysis
+; TIME-NEW-PER-PASS-DAG: VerifierPass
+; TIME-NEW-PER-PASS-DAG: DominatorTreeAnalysis
+; TIME-NEW-PER-PASS-DAG: TargetLibraryAnalysis
+; TIME-NEW-PER-PASS-NOT: InstCombinePass #
+; TIME-NEW-PER-PASS-NOT: LICMPass #
+; TIME-NEW-PER-PASS-NOT: LCSSAPass #
+; TIME-NEW-PER-PASS-NOT: LoopSimplifyPass #
+; TIME-NEW-PER-PASS-NOT: ScalarEvolutionAnalysis #
+; TIME-NEW-PER-PASS-NOT: LoopAnalysis #
+; TIME-NEW-PER-PASS-NOT: VerifierPass #
+; TIME-NEW-PER-PASS-NOT: DominatorTreeAnalysis #
+; TIME-NEW-PER-PASS-NOT: TargetLibraryAnalysis #
; TIME: Total{{$}}
define i32 @foo() {