[Mlir-commits] [mlir] [MLIR][CMake] Add PCH for MLIRIR (PR #213412)

Maksim Levental llvmlistbot at llvm.org
Fri Jul 31 22:57:07 PDT 2026


https://github.com/makslevental created https://github.com/llvm/llvm-project/pull/213412

Add a precompiled header for `MLIRIR`, following the infrastructure added in #176420 and the per-component PCHs for `llvm/IR` (#183303), `llvm/CodeGen` (#183346) and `clang/AST` (#183358).

### Header selection

Same methodology as the earlier patches: compile all 1173 CUs under `mlir/lib` with `-ftime-trace`, then rank `mlir/` headers by time spent parsing them (including transitively included headers). Rather than taking the top of that list directly, I ran a greedy marginal-coverage pass over the `-ftime-trace` include trees: pick the header that saves the most, mark its whole subtree as covered, repeat. This avoids double-counting headers that are only ever reached through another candidate.

Candidates were restricted to headers already reachable from `MLIRIR`'s own sources. The unrestricted greedy pass wants dialect headers at the top (`LLVMIR/LLVMDialect.h` alone is 355s marginal, and the top-28 unrestricted set reaches 2494s/3674s), but putting those in MLIRIR's PCH would invert the library layering. Those belong in per-dialect PCHs later, if at all.

Coverage of the selected set over the `mlir/lib` CUs:

| set | frontend time covered |
|---|---|
| `mlir/IR` core only | 1080s (29.4%) |
| \+ `mlir/Bytecode` | 1127s (30.7%) |
| \+ `llvm/Support/pch.h` (this patch) | 1227s (33.4%) |

`llvm/Support/pch.h` is included at the end for the same reason `llvm/IR/pch.h` and `clang/lib/CodeGen/pch.h` chain to their parents. Defining `PRECOMPILE_HEADERS` on a target *replaces* the PCH it would otherwise reuse from a dependency rather than stacking with it, so without that include MLIRIR and everything reusing its PCH would silently lose the LLVMSupport PCH they get today (531s of coverage on its own).

Top of the ranking, for reference (first-parse inclusive time summed over all CUs that parse the header):

```
first-parse s  #CUs   ms/CU  header
        426.9   911   468.6  mlir/Bytecode/BytecodeImplementation.h
        422.7   902   468.6  mlir/Bytecode/BytecodeOpInterface.h
        337.7  1035   326.3  mlir/IR/OperationSupport.h
        325.6  1053   309.2  mlir/IR/MLIRContext.h
        294.5  1051   280.2  mlir/IR/Attributes.h
        293.0  1015   288.7  mlir/IR/Dialect.h
        237.7  1045   227.4  mlir/IR/BuiltinAttributes.h
        216.1  1066   202.7  mlir/Support/TypeID.h
        193.6   998   194.0  mlir/IR/OpDefinition.h
        181.9   828   219.7  mlir/IR/PatternMatch.h
        164.2  1111   147.8  mlir/Support/LLVM.h
        108.6  1047   103.8  mlir/IR/AffineMap.h
        106.7   385   277.1  mlir/Pass/Pass.h
        103.0   937   109.9  mlir/IR/OpImplementation.h
         99.2   904   109.7  mlir/IR/Builders.h
```

I don't think it's worth investing much more in tooling to find an optimal set; consider this a reasonable starting point that can be adjusted.

### Measured effect

Clean build of `mlir-opt`, Release + assertions, Apple M-series, `-j16`, Apple clang 21:

```
                    wall      user
without MLIR PCH   468.3s   6802.6s
with MLIR PCH      440.8s   6382.4s
                   -5.9%     -6.2%
```

715 of 1536 MLIR objects reuse the PCH. The rest either don't list `MLIRIR` as a *direct* dependency (PCH reuse is deliberately non-transitive) or have reuse disabled, e.g. the C API libraries via #182862.

The modest wall-clock number relative to the frontend-time coverage is expected: this is a Release build where the backend is a large share of the total, and only ~half the MLIR objects are eligible for reuse.

### Layering

`mlir/lib/CMakeLists.txt` gains an explicit `add_subdirectory(IR)` ahead of the others. CMake can only reuse a PCH from an already-defined target, so `MLIRIR` has to exist before `Analysis`, `AsmParser`, `Bytecode`, `Conversion` and `Dialect` are processed. Same constraint that moved `IR` before `ABI` in `llvm/lib/CMakeLists.txt` in #176420.

### Name collision

As with the earlier PCHs, wider header visibility exposes one collision. `mlir-lsp-server/LSPServer.cpp` has both `using namespace mlir;` and `using llvm::lsp::Location;`; once `mlir::Location` is declared via the PCH, unqualified `Location` is ambiguous. Qualified the six uses in that file. This was the only such failure across `mlir-opt`, `mlir-translate`, `mlir-lsp-server`, `mlir-pdll-lsp-server`, `tblgen-lsp-server`, `mlir-reduce`, `mlir-query`, `mlir-runner` and `mlir-tblgen`.

### Testing

- `check-mlir` with PCH enabled: 3821 passed, 1 expectedly failed, 0 unexpected failures.
- Configure and build with `-DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON`: clean, no CMake warnings.


>From c72e559157248b271439ac1ebca6187634922328 Mon Sep 17 00:00:00 2001
From: makslevental <maksim.levental at gmail.com>
Date: Fri, 31 Jul 2026 22:56:14 -0700
Subject: [PATCH] [MLIR][CMake] Add PCH for MLIRIR

Add a precompiled header for MLIRIR, following the infrastructure added in
llvm#176420 and the per-component PCHs for llvm/IR (llvm#183303),
llvm/CodeGen (llvm#183346) and clang/AST (llvm#183358).

The header list was selected with the same methodology: compile all 1173
CUs under mlir/lib with -ftime-trace, rank mlir headers by the time spent
parsing them (including transitively included headers), then greedily pick
the header with the largest marginal coverage until the marginal gain
falls off. Candidates were restricted to headers already reachable from
MLIRIR's own sources, so the PCH does not invert the library layering.

Over the mlir/lib CUs, the selected set covers 1227s of 3674s total
frontend time (33%). On a Release+assertions build of mlir-opt
(Apple M-series, -j16), clean build wall time goes from 468.3s to 440.8s
(-5.9%); 715 of 1536 MLIR objects reuse the PCH.

mlir/lib/CMakeLists.txt gains an explicit add_subdirectory(IR) before the
other directories: CMake can only reuse a PCH from a target that is
already defined, so MLIRIR must exist before its dependants.

As with the earlier PCHs, the wider header visibility exposes a name
collision: mlir-lsp-server/LSPServer.cpp does `using namespace mlir` and
`using llvm::lsp::Location`, which becomes ambiguous once mlir::Location
is declared. Qualify the llvm::lsp::Location uses in that file.
---
 mlir/include/mlir/IR/pch.h                   | 47 ++++++++++++++++++++
 mlir/lib/CMakeLists.txt                      |  5 ++-
 mlir/lib/IR/CMakeLists.txt                   |  3 ++
 mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp | 16 +++----
 4 files changed, 62 insertions(+), 9 deletions(-)
 create mode 100644 mlir/include/mlir/IR/pch.h

diff --git a/mlir/include/mlir/IR/pch.h b/mlir/include/mlir/IR/pch.h
new file mode 100644
index 0000000000000..69bb4ef798451
--- /dev/null
+++ b/mlir/include/mlir/IR/pch.h
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// Precompiled header for MLIRIR.
+///
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Bytecode/BytecodeImplementation.h"
+#include "mlir/Bytecode/BytecodeOpInterface.h"
+#include "mlir/IR/AffineExpr.h"
+#include "mlir/IR/AffineMap.h"
+#include "mlir/IR/AsmState.h"
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/Block.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/Diagnostics.h"
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/Dominance.h"
+#include "mlir/IR/IRMapping.h"
+#include "mlir/IR/Location.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/IR/Matchers.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/IR/OpImplementation.h"
+#include "mlir/IR/Operation.h"
+#include "mlir/IR/OperationSupport.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/Region.h"
+#include "mlir/IR/SymbolTable.h"
+#include "mlir/IR/TypeRange.h"
+#include "mlir/IR/TypeUtilities.h"
+#include "mlir/IR/Types.h"
+#include "mlir/IR/Value.h"
+#include "mlir/IR/ValueRange.h"
+#include "mlir/IR/Visitors.h"
+#include "mlir/Support/LLVM.h"
+#include "mlir/Support/TypeID.h"
+#include "mlir/Support/WalkResult.h"
+#include "llvm/Support/pch.h"
diff --git a/mlir/lib/CMakeLists.txt b/mlir/lib/CMakeLists.txt
index 576942b78f4a8..5b4f901bd80ad 100644
--- a/mlir/lib/CMakeLists.txt
+++ b/mlir/lib/CMakeLists.txt
@@ -1,6 +1,10 @@
 # Enable errors for any global constructors.
 add_flag_if_supported("-Werror=global-constructors" WERROR_GLOBAL_CONSTRUCTOR)
 
+# MLIRIR defines the PCH that most other MLIR libraries reuse. CMake can only
+# reuse a PCH from an already-defined target, so IR must come first.
+add_subdirectory(IR)
+
 add_subdirectory(ABI)
 add_subdirectory(Analysis)
 add_subdirectory(AsmParser)
@@ -8,7 +12,6 @@ add_subdirectory(Bytecode)
 add_subdirectory(Conversion)
 add_subdirectory(Debug)
 add_subdirectory(Dialect)
-add_subdirectory(IR)
 add_subdirectory(Interfaces)
 add_subdirectory(Parser)
 add_subdirectory(Pass)
diff --git a/mlir/lib/IR/CMakeLists.txt b/mlir/lib/IR/CMakeLists.txt
index 6cadc3131ccd4..08a049980fcb9 100644
--- a/mlir/lib/IR/CMakeLists.txt
+++ b/mlir/lib/IR/CMakeLists.txt
@@ -50,6 +50,9 @@ add_mlir_library(MLIRIR
   ADDITIONAL_HEADER_DIRS
   ${MLIR_MAIN_INCLUDE_DIR}/mlir/IR
 
+  PRECOMPILE_HEADERS
+  [["mlir/IR/pch.h"]]
+
   DEPENDS
   MLIRBuiltinAttributesIncGen
   MLIRBuiltinAttributeInterfacesIncGen
diff --git a/mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp b/mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp
index 73ebe6a6b1f09..9df65dd61488e 100644
--- a/mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp
+++ b/mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp
@@ -32,7 +32,6 @@ using llvm::lsp::Hover;
 using llvm::lsp::InitializedParams;
 using llvm::lsp::InitializeParams;
 using llvm::lsp::JSONTransport;
-using llvm::lsp::Location;
 using llvm::lsp::Logger;
 using llvm::lsp::MessageHandler;
 using llvm::lsp::MLIRConvertBytecodeParams;
@@ -72,9 +71,9 @@ struct LSPServer {
   // Definitions and References
 
   void onGoToDefinition(const TextDocumentPositionParams &params,
-                        Callback<std::vector<Location>> reply);
+                        Callback<std::vector<llvm::lsp::Location>> reply);
   void onReference(const ReferenceParams &params,
-                   Callback<std::vector<Location>> reply);
+                   Callback<std::vector<llvm::lsp::Location>> reply);
 
   //===--------------------------------------------------------------------===//
   // Hover
@@ -240,16 +239,17 @@ void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams &params) {
 // Definitions and References
 //===----------------------------------------------------------------------===//
 
-void LSPServer::onGoToDefinition(const TextDocumentPositionParams &params,
-                                 Callback<std::vector<Location>> reply) {
-  std::vector<Location> locations;
+void LSPServer::onGoToDefinition(
+    const TextDocumentPositionParams &params,
+    Callback<std::vector<llvm::lsp::Location>> reply) {
+  std::vector<llvm::lsp::Location> locations;
   server.getLocationsOf(params.textDocument.uri, params.position, locations);
   reply(std::move(locations));
 }
 
 void LSPServer::onReference(const ReferenceParams &params,
-                            Callback<std::vector<Location>> reply) {
-  std::vector<Location> locations;
+                            Callback<std::vector<llvm::lsp::Location>> reply) {
+  std::vector<llvm::lsp::Location> locations;
   server.findReferencesOf(params.textDocument.uri, params.position, locations);
   reply(std::move(locations));
 }



More information about the Mlir-commits mailing list