[clang] fce45b3 - [Frontend] Consolidate frontend timer setup in CompilerInstance::ExecuteAction. NFC (#192266)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 16 08:27:41 PDT 2026
Author: Vassil Vassilev
Date: 2026-04-16T17:27:35+02:00
New Revision: fce45b3e961cac33e6b26725405a14a5b1f5d733
URL: https://github.com/llvm/llvm-project/commit/fce45b3e961cac33e6b26725405a14a5b1f5d733
DIFF: https://github.com/llvm/llvm-project/commit/fce45b3e961cac33e6b26725405a14a5b1f5d733.diff
LOG: [Frontend] Consolidate frontend timer setup in CompilerInstance::ExecuteAction. NFC (#192266)
Move the frontend timer creation (-ftime-report) and TimeTraceScope
("ExecuteCompiler") from cc1_main into CompilerInstance::ExecuteAction
via a new private PrepareForExecution() method. This ensures all tools
that use ExecuteAction (cc1, clang-repl, libclang, etc.) get consistent
timing infrastructure without duplicating setup code.
Added:
clang/test/Interpreter/ftime-report.cpp
Modified:
clang/include/clang/Frontend/CompilerInstance.h
clang/lib/Frontend/CompilerInstance.cpp
clang/tools/driver/cc1_main.cpp
clang/unittests/Support/TimeProfilerTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index be44817aa5a1b..bce9ff421ec87 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -217,6 +217,13 @@ class CompilerInstance : public ModuleLoader {
/// @name High-Level Operations
/// @{
+ // FIXME: Add a static InitializeProcess() method to consolidate process-level
+ // setup that is currently scattered across tool entry points (cc1_main,
+ // clang-repl, libclang, etc.). This would include things like AsmParsers and
+ // install_fatal_error_handler.
+ // These are process-global, so a single static method would allow clang-based
+ // tools to share them without duplication.
+
/// ExecuteAction - Execute the provided action against the compiler's
/// CompilerInvocation object.
///
@@ -809,6 +816,13 @@ class CompilerInstance : public ModuleLoader {
bool UseTemporary, bool CreateMissingDirectories = false);
private:
+ /// Prepare the CompilerInstance for executing a frontend action.
+ ///
+ /// Called by ExecuteAction. Consolidates instance-level setup that was
+ /// previously duplicated across tool entry points (cc1_main,
+ /// clang-repl/Interpreter, etc.).
+ void PrepareForExecution();
+
/// Create a new output file and add it to the list of tracked output files.
///
/// If \p OutputPath is empty, then createOutputFile will derive an output
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 8e2a948be6fd0..be097ba867407 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -944,11 +944,31 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
// High-Level Operations
+void CompilerInstance::PrepareForExecution() {
+ // Set up the frontend timer for -ftime-report. BackendConsumer uses
+ // getTimerGroup() and getFrontendTimer() when TimePasses is set. In the
+ // cc1 driver path this was done in cc1_main before calling
+ // ExecuteCompilerInvocation; we consolidate it here so that all tools
+ // (cc1, clang-repl, libclang, etc.) get consistent behavior.
+ if (getCodeGenOpts().TimePasses && !FrontendTimer) {
+ createFrontendTimer();
+ getFrontendTimer().startTimer();
+ }
+
+ // FIXME: Consider consolidating additional per-instance setup here:
+ // - llvm::timeTraceProfilerInitialize) when TimeTracePath is set.
+ // - Plugin loading (LoadRequestedPlugins) and -mllvm argument processing.
+}
+
bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
assert(hasDiagnostics() && "Diagnostics engine is not initialized!");
assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!");
assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!");
+ llvm::TimeTraceScope TimeScope("ExecuteCompiler");
+
+ PrepareForExecution();
+
// Mark this point as the bottom of the stack if we don't have somewhere
// better. We generally expect frontend actions to be invoked with (nearly)
// DesiredStackSpace available.
diff --git a/clang/test/Interpreter/ftime-report.cpp b/clang/test/Interpreter/ftime-report.cpp
new file mode 100644
index 0000000000000..1c19a9bf0e79b
--- /dev/null
+++ b/clang/test/Interpreter/ftime-report.cpp
@@ -0,0 +1,5 @@
+// Tests that -ftime-report works with clang-repl without crashing.
+// RUN: clang-repl -Xcc -ftime-report "int x = 42;" 2>&1 | FileCheck %s
+// CHECK-NOT: Assertion
+// CHECK-NOT: PLEASE submit a bug report
+// CHECK: Clang time report
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 0a9ded1cf213a..35405044d8d37 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -293,14 +293,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
return 1;
// Execute the frontend actions.
- {
- llvm::TimeTraceScope TimeScope("ExecuteCompiler");
- bool TimePasses = Clang->getCodeGenOpts().TimePasses;
- if (TimePasses)
- Clang->createFrontendTimer();
- llvm::TimeRegion Timer(TimePasses ? &Clang->getFrontendTimer() : nullptr);
- Success = ExecuteCompilerInvocation(Clang.get());
- }
+ Success = ExecuteCompilerInvocation(Clang.get());
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index 5eacae6d200eb..84e9dc232be75 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -219,30 +219,31 @@ constexpr int slow_init_list[] = {1, 1, 2, 3, 5, 8, 13, 21}; // 25th line
ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc"));
std::string Json = teardownProfiler();
ASSERT_EQ(R"(
-Frontend (test.cc)
-| ParseDeclarationOrFunctionDefinition (test.cc:2:1)
-| ParseDeclarationOrFunctionDefinition (test.cc:6:1)
-| | ParseFunctionDefinition (slow_func)
-| | | EvaluateAsRValue (<test.cc:8:21>)
-| | | EvaluateForOverflow (<test.cc:8:21, col:25>)
-| | | EvaluateForOverflow (<test.cc:8:30, col:32>)
-| | | EvaluateAsRValue (<test.cc:9:14>)
-| | | EvaluateForOverflow (<test.cc:9:9, col:14>)
-| | | isPotentialConstantExpr (slow_namespace::slow_func)
-| | | EvaluateAsBooleanCondition (<test.cc:8:21, col:25>)
-| | | | EvaluateAsRValue (<test.cc:8:21, col:25>)
-| | | EvaluateAsBooleanCondition (<test.cc:8:21, col:25>)
-| | | | EvaluateAsRValue (<test.cc:8:21, col:25>)
-| ParseDeclarationOrFunctionDefinition (test.cc:16:1)
-| | ParseFunctionDefinition (slow_test)
-| | | EvaluateAsInitializer (slow_value)
-| | | EvaluateAsConstantExpr (<test.cc:17:33, col:59>)
-| | | EvaluateAsConstantExpr (<test.cc:18:11, col:37>)
-| ParseDeclarationOrFunctionDefinition (test.cc:22:1)
-| | EvaluateAsConstantExpr (<test.cc:23:31, col:57>)
-| | EvaluateAsRValue (<test.cc:22:14, line:23:58>)
-| ParseDeclarationOrFunctionDefinition (test.cc:25:1)
-| | EvaluateAsInitializer (slow_init_list)
+ExecuteCompiler
+| Frontend (test.cc)
+| | ParseDeclarationOrFunctionDefinition (test.cc:2:1)
+| | ParseDeclarationOrFunctionDefinition (test.cc:6:1)
+| | | ParseFunctionDefinition (slow_func)
+| | | | EvaluateAsRValue (<test.cc:8:21>)
+| | | | EvaluateForOverflow (<test.cc:8:21, col:25>)
+| | | | EvaluateForOverflow (<test.cc:8:30, col:32>)
+| | | | EvaluateAsRValue (<test.cc:9:14>)
+| | | | EvaluateForOverflow (<test.cc:9:9, col:14>)
+| | | | isPotentialConstantExpr (slow_namespace::slow_func)
+| | | | EvaluateAsBooleanCondition (<test.cc:8:21, col:25>)
+| | | | | EvaluateAsRValue (<test.cc:8:21, col:25>)
+| | | | EvaluateAsBooleanCondition (<test.cc:8:21, col:25>)
+| | | | | EvaluateAsRValue (<test.cc:8:21, col:25>)
+| | ParseDeclarationOrFunctionDefinition (test.cc:16:1)
+| | | ParseFunctionDefinition (slow_test)
+| | | | EvaluateAsInitializer (slow_value)
+| | | | EvaluateAsConstantExpr (<test.cc:17:33, col:59>)
+| | | | EvaluateAsConstantExpr (<test.cc:18:11, col:37>)
+| | ParseDeclarationOrFunctionDefinition (test.cc:22:1)
+| | | EvaluateAsConstantExpr (<test.cc:23:31, col:57>)
+| | | EvaluateAsRValue (<test.cc:22:14, line:23:58>)
+| | ParseDeclarationOrFunctionDefinition (test.cc:25:1)
+| | | EvaluateAsInitializer (slow_init_list)
| PerformPendingInstantiations
)",
buildTraceGraph(Json));
@@ -270,18 +271,19 @@ TEST(TimeProfilerTest, ClassTemplateInstantiations) {
ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc"));
std::string Json = teardownProfiler();
ASSERT_EQ(R"(
-Frontend (test.cc)
-| ParseClass (S)
-| CheckConstraintSatisfaction (<test.cc:9:21, col:29>)
-| InstantiateClass (S<double>, test.cc:9)
-| InstantiateFunction (S<double>::foo, test.cc:5)
-| ParseDeclarationOrFunctionDefinition (test.cc:11:5)
-| | ParseFunctionDefinition (user)
-| | | CheckConstraintSatisfaction (<test.cc:12:7, col:12>)
-| | | InstantiateClass (S<int>, test.cc:3)
-| | | CheckConstraintSatisfaction (<test.cc:13:7, col:14>)
-| | | InstantiateClass (S<float>, test.cc:3)
-| | | DeferInstantiation (S<float>::foo)
+ExecuteCompiler
+| Frontend (test.cc)
+| | ParseClass (S)
+| | CheckConstraintSatisfaction (<test.cc:9:21, col:29>)
+| | InstantiateClass (S<double>, test.cc:9)
+| | InstantiateFunction (S<double>::foo, test.cc:5)
+| | ParseDeclarationOrFunctionDefinition (test.cc:11:5)
+| | | ParseFunctionDefinition (user)
+| | | | CheckConstraintSatisfaction (<test.cc:12:7, col:12>)
+| | | | InstantiateClass (S<int>, test.cc:3)
+| | | | CheckConstraintSatisfaction (<test.cc:13:7, col:14>)
+| | | | InstantiateClass (S<float>, test.cc:3)
+| | | | DeferInstantiation (S<float>::foo)
| PerformPendingInstantiations
| | InstantiateFunction (S<float>::foo, test.cc:5)
)",
@@ -321,14 +323,15 @@ TEST(TimeProfilerTest, TemplateInstantiations) {
/*Headers=*/{{"a.h", A_H}, {"b.h", B_H}}));
std::string Json = teardownProfiler();
ASSERT_EQ(R"(
-Frontend (test.cc)
-| ParseFunctionDefinition (fooC)
-| ParseFunctionDefinition (fooB)
-| ParseFunctionDefinition (fooMTA)
-| ParseFunctionDefinition (fooA)
-| ParseDeclarationOrFunctionDefinition (test.cc:3:5)
-| | ParseFunctionDefinition (user)
-| | | DeferInstantiation (fooA<int>)
+ExecuteCompiler
+| Frontend (test.cc)
+| | ParseFunctionDefinition (fooC)
+| | ParseFunctionDefinition (fooB)
+| | ParseFunctionDefinition (fooMTA)
+| | ParseFunctionDefinition (fooA)
+| | ParseDeclarationOrFunctionDefinition (test.cc:3:5)
+| | | ParseFunctionDefinition (user)
+| | | | DeferInstantiation (fooA<int>)
| PerformPendingInstantiations
| | InstantiateFunction (fooA<int>, a.h:7)
| | | InstantiateFunction (fooB<int>, b.h:8)
@@ -353,10 +356,11 @@ struct {
ASSERT_TRUE(compileFromString(Code, "-std=c99", "test.c"));
std::string Json = teardownProfiler();
ASSERT_EQ(R"(
-Frontend (test.c)
-| ParseDeclarationOrFunctionDefinition (test.c:2:1)
-| | isIntegerConstantExpr (<test.c:3:18>)
-| | EvaluateKnownConstIntCheckOverflow (<test.c:3:18>)
+ExecuteCompiler
+| Frontend (test.c)
+| | ParseDeclarationOrFunctionDefinition (test.c:2:1)
+| | | isIntegerConstantExpr (<test.c:3:18>)
+| | | EvaluateKnownConstIntCheckOverflow (<test.c:3:18>)
| PerformPendingInstantiations
)",
buildTraceGraph(Json));
More information about the cfe-commits
mailing list