[clang] [CIR] Intitial upstreaming of LibOpt pass (PR #172487)
Hendrik Hübner via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 30 01:25:34 PDT 2026
https://github.com/HendrikHuebner updated https://github.com/llvm/llvm-project/pull/172487
>From e54f437429c62d7754685c4a26c0d69be6408e17 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Tue, 16 Dec 2025 15:50:20 +0100
Subject: [PATCH 1/4] Add LibOpt pass skeleton
---
clang/include/clang/CIR/CIRToCIRPasses.h | 3 +-
clang/include/clang/CIR/Dialect/Passes.h | 2 +
clang/include/clang/CIR/Dialect/Passes.td | 12 +++
.../include/clang/Frontend/FrontendOptions.h | 13 +++-
clang/include/clang/Options/Options.td | 10 +++
.../lib/CIR/Dialect/Transforms/CMakeLists.txt | 1 +
clang/lib/CIR/Dialect/Transforms/LibOpt.cpp | 77 +++++++++++++++++++
clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 7 +-
clang/lib/CIR/Lowering/CIRPasses.cpp | 16 +++-
clang/lib/Frontend/CompilerInvocation.cpp | 3 +
clang/test/CIR/Transforms/lib-opt.cpp | 6 ++
11 files changed, 145 insertions(+), 5 deletions(-)
create mode 100644 clang/lib/CIR/Dialect/Transforms/LibOpt.cpp
create mode 100644 clang/test/CIR/Transforms/lib-opt.cpp
diff --git a/clang/include/clang/CIR/CIRToCIRPasses.h b/clang/include/clang/CIR/CIRToCIRPasses.h
index ec6d75332bed9..de0d4fab8597d 100644
--- a/clang/include/clang/CIR/CIRToCIRPasses.h
+++ b/clang/include/clang/CIR/CIRToCIRPasses.h
@@ -32,7 +32,8 @@ namespace cir {
mlir::LogicalResult
runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirCtx,
clang::ASTContext &astCtx, bool enableVerifier,
- bool enableIdiomRecognizer, bool enableCIRSimplify);
+ bool enableIdiomRecognizer, bool enableCIRSimplify,
+ bool enableLibOpt, llvm::StringRef libOptOptions);
} // namespace cir
diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h
index a68f7b621f5d8..651a1319cfe5d 100644
--- a/clang/include/clang/CIR/Dialect/Passes.h
+++ b/clang/include/clang/CIR/Dialect/Passes.h
@@ -34,6 +34,8 @@ std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
std::unique_ptr<Pass> createGotoSolverPass();
std::unique_ptr<Pass> createIdiomRecognizerPass();
std::unique_ptr<Pass> createIdiomRecognizerPass(clang::ASTContext *astCtx);
+std::unique_ptr<Pass> createLibOptPass();
+std::unique_ptr<Pass> createLibOptPass(clang::ASTContext *astCtx);
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);
diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td
index 6a7c4bf9aac88..9cdeb4d42d5a1 100644
--- a/clang/include/clang/CIR/Dialect/Passes.td
+++ b/clang/include/clang/CIR/Dialect/Passes.td
@@ -195,6 +195,18 @@ def IdiomRecognizer : Pass<"cir-idiom-recognizer", "mlir::ModuleOp"> {
let dependentDialects = ["cir::CIRDialect"];
}
+def LibOpt : Pass<"cir-lib-opt"> {
+ let summary = "Optimize C/C++ library calls";
+ let description = [{
+ This pass applies transformations on C/C++ standard library idioms,
+ such as library function calls and structs raised to CIR operations
+ using the `cir-idiom-recognize` pass.
+ }];
+
+ let constructor = "mlir::createLibOptPass()";
+ let dependentDialects = ["cir::CIRDialect"];
+}
+
def CallConvLowering : Pass<"cir-call-conv-lowering", "mlir::ModuleOp"> {
let summary = "Lower CIR function signatures and call sites to match target ABI";
let description = [{
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index f65547e68b29d..3de7a0ce4b211 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -422,10 +422,18 @@ class FrontendOptions {
LLVM_PREFERRED_TYPE(bool)
unsigned ClangIRDisableCIRVerifier : 1;
- /// Enable Clang IR (CIR) idiom recognizer
+ // Enable Clang IR (CIR) idiom recognizer
LLVM_PREFERRED_TYPE(bool)
unsigned ClangIREnableIdiomRecognizer : 1;
+ // Enable ClangIR library optimization.
+ // Set when -fclangir-lib-opt or -fclangir-lib-opt= was passed.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned ClangIRLibOptEnabled : 1;
+
+ // Options to control ClangIR library optimization
+ std::string clangIRLibOptOptions;
+
CodeCompleteOptions CodeCompleteOpts;
/// Specifies the output format of the AST.
@@ -560,7 +568,8 @@ class FrontendOptions {
EmitPrettySymbolGraphs(false), GenReducedBMI(false),
UseClangIRPipeline(false), ClangIRDisablePasses(false),
ClangIRDisableCIRVerifier(false), ClangIREnableIdiomRecognizer(false),
- TimeTraceGranularity(500), TimeTraceVerbose(false) {}
+ ClangIRLibOptEnabled(false), TimeTraceGranularity(500),
+ TimeTraceVerbose(false) {}
/// getInputKindForExtension - Return the appropriate input kind for a file
/// extension. For example, "c" would return Language::C.
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 5d5d409ac5494..d121e1a84ec70 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -3405,6 +3405,16 @@ def clangir_enable_idiom_recognizer : Flag<["-"], "clangir-enable-idiom-recogniz
HelpText<"ClangIR: Enable Idiom Recognizer pass">,
MarshallingInfoFlag<FrontendOpts<"ClangIREnableIdiomRecognizer">>;
+def clangir_lib_opt_EQ : Joined<["-"], "clangir-lib-opt=">,
+ Visibility<[ClangOption, CC1Option]>, Group<f_Group>, Values<"all">,
+ HelpText<"Enable C/C++ library based optimizations (with options)">,
+ MarshallingInfoString<FrontendOpts<"clangIRLibOptOptions">>;
+
+def clangir_lib_opt : Flag<["-"], "clangir-lib-opt">,
+ Visibility<[ClangOption, CC1Option]>, Group<f_Group>,
+ Alias<clangir_lib_opt_EQ>, AliasArgs<["all"]>,
+ HelpText<"Enable C/C++ library based optimizations">;
+
defm clangir : BoolFOption<"clangir",
FrontendOpts<"UseClangIRPipeline">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Use the ClangIR pipeline to compile">,
diff --git a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
index 27d9d26c28bd4..5edbfcf467f90 100644
--- a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
@@ -13,6 +13,7 @@ add_clang_library(MLIRCIRTransforms
LoweringPrepare.cpp
GotoSolver.cpp
IdiomRecognizer.cpp
+ LibOpt.cpp
DEPENDS
MLIRCIRPassIncGen
diff --git a/clang/lib/CIR/Dialect/Transforms/LibOpt.cpp b/clang/lib/CIR/Dialect/Transforms/LibOpt.cpp
new file mode 100644
index 0000000000000..92a9339545931
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/LibOpt.cpp
@@ -0,0 +1,77 @@
+//===- LibOpt.cpp - Optimize CIR raised C/C++ library idioms --------------===//
+//
+// 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 pass optimizes C/C++ standard library idioms in Clang IR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PassDetail.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/Region.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Mangle.h"
+#include "clang/Basic/Module.h"
+#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/Passes.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Path.h"
+
+using cir::CIRBaseBuilderTy;
+using namespace mlir;
+using namespace cir;
+
+namespace mlir {
+#define GEN_PASS_DEF_LIBOPT
+#include "clang/CIR/Dialect/Passes.h.inc"
+} // namespace mlir
+
+namespace {
+
+struct LibOptPass : public impl::LibOptBase<LibOptPass> {
+ LibOptPass() = default;
+ mlir::LogicalResult
+ initializeOptions(llvm::StringRef options,
+ llvm::function_ref<mlir::LogicalResult(const llvm::Twine &)>
+ errorHandler) override;
+ void runOnOperation() override;
+
+ // Raw libopt option string forwarded by the frontend. This will later control
+ // which optimizations the pass enables.
+ std::string optimizationOptions;
+
+ /// Tracks current module.
+ ModuleOp theModule;
+};
+} // namespace
+
+mlir::LogicalResult LibOptPass::initializeOptions(
+ llvm::StringRef options,
+ llvm::function_ref<mlir::LogicalResult(const llvm::Twine &)> errorHandler) {
+ (void)errorHandler;
+ optimizationOptions = options.str();
+ // TODO(cir): Parse options to select the active transformations for the
+ // pass.
+ return mlir::success();
+}
+
+void LibOptPass::runOnOperation() {
+ auto *op = getOperation();
+ if (isa<::mlir::ModuleOp>(op))
+ theModule = cast<::mlir::ModuleOp>(op);
+}
+
+std::unique_ptr<Pass> mlir::createLibOptPass() {
+ return std::make_unique<LibOptPass>();
+}
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
index fccd270a95ccd..8ce08d7c4c7c8 100644
--- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -135,10 +135,15 @@ class CIRGenConsumer : public clang::ASTConsumer {
mlir::MLIRContext &MlirCtx = Gen->getMLIRContext();
if (!FEOptions.ClangIRDisablePasses) {
+ std::string LibOptOptions = FEOptions.clangIRLibOptOptions;
+
// Setup and run CIR pipeline.
+ const bool EnableLibOpt =
+ FEOptions.ClangIRLibOptEnabled && (CGO.OptimizationLevel > 0);
if (runCIRToCIRPasses(
MlirModule, MlirCtx, C, !FEOptions.ClangIRDisableCIRVerifier,
- FEOptions.ClangIREnableIdiomRecognizer, CGO.OptimizationLevel > 0)
+ FEOptions.ClangIREnableIdiomRecognizer, CGO.OptimizationLevel > 0,
+ EnableLibOpt, LibOptOptions)
.failed()) {
CI.getDiagnostics().Report(diag::err_cir_to_cir_transform_failed);
return;
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp
index 7b93356a34c38..f476ee04430cd 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -17,10 +17,12 @@
#include "llvm/Support/TimeProfiler.h"
namespace cir {
+
mlir::LogicalResult
runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirContext,
clang::ASTContext &astContext, bool enableVerifier,
- bool enableIdiomRecognizer, bool enableCIRSimplify) {
+ bool enableIdiomRecognizer, bool enableCIRSimplify,
+ bool enableLibOpt, llvm::StringRef libOptOptions) {
llvm::TimeTraceScope scope("CIR To CIR Passes");
@@ -33,6 +35,18 @@ runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirContext,
if (enableIdiomRecognizer)
pm.addPass(mlir::createIdiomRecognizerPass(&astContext));
+ if (enableLibOpt) {
+ auto libOptPass = mlir::createLibOptPass();
+ auto errorHandler = [](const llvm::Twine &) -> mlir::LogicalResult {
+ return mlir::LogicalResult::failure();
+ };
+
+ if (libOptPass->initializeOptions(libOptOptions, errorHandler).failed())
+ return mlir::failure();
+
+ pm.addPass(std::move(libOptPass));
+ }
+
pm.addPass(mlir::createTargetLoweringPass());
pm.addPass(mlir::createCXXABILoweringPass());
pm.addPass(mlir::createLoweringPreparePass(&astContext));
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index ce1d7dc98e99c..34b278803e050 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3188,6 +3188,9 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_clangir_disable_verifier))
Opts.ClangIRDisableCIRVerifier = true;
+
+ if (Args.hasArg(OPT_clangir_lib_opt) || Args.hasArg(OPT_clangir_lib_opt_EQ))
+ Opts.ClangIRLibOptEnabled = true;
#endif // CLANG_ENABLE_CIR
if (Args.hasArg(OPT_aux_target_cpu))
diff --git a/clang/test/CIR/Transforms/lib-opt.cpp b/clang/test/CIR/Transforms/lib-opt.cpp
new file mode 100644
index 0000000000000..9790d8d237461
--- /dev/null
+++ b/clang/test/CIR/Transforms/lib-opt.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fclangir -O1 -emit-cir -mmlir --mlir-print-ir-after-all -clangir-lib-opt=all %s -o - 2>&1 | FileCheck %s -check-prefix=ENABLED
+// RUN: %clang_cc1 -fclangir -O1 -emit-cir -mmlir --mlir-print-ir-after-all %s -o - 2>&1 | FileCheck %s -check-prefix=DISABLED
+// RUN: %clang_cc1 -fclangir -O0 -emit-cir -mmlir --mlir-print-ir-after-all -clangir-lib-opt=all %s -o - 2>&1 | FileCheck %s -check-prefix=DISABLED
+
+// ENABLED: IR Dump After LibOpt: cir-lib-opt
+// DISABLED-NOT: IR Dump After LibOpt: cir-lib-opt
>From bcacfae1a735a77e1967f5bd06b8846f5719dbd6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hendrik=20H=C3=BCbner?=
<117831077+HendrikHuebner at users.noreply.github.com>
Date: Tue, 30 Jun 2026 10:20:36 +0200
Subject: [PATCH 2/4] Nits
---
clang/include/clang/Frontend/FrontendOptions.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 3de7a0ce4b211..ec42e44d035b6 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -422,17 +422,17 @@ class FrontendOptions {
LLVM_PREFERRED_TYPE(bool)
unsigned ClangIRDisableCIRVerifier : 1;
- // Enable Clang IR (CIR) idiom recognizer
+ /// Enable Clang IR (CIR) idiom recognizer
LLVM_PREFERRED_TYPE(bool)
unsigned ClangIREnableIdiomRecognizer : 1;
- // Enable ClangIR library optimization.
- // Set when -fclangir-lib-opt or -fclangir-lib-opt= was passed.
+ /// Enable ClangIR library optimization.
+ /// Set when -fclangir-lib-opt or -fclangir-lib-opt= was passed.
LLVM_PREFERRED_TYPE(bool)
unsigned ClangIRLibOptEnabled : 1;
- // Options to control ClangIR library optimization
- std::string clangIRLibOptOptions;
+ /// Options to control ClangIR library optimization
+ std::string ClangIRLibOptOptions;
CodeCompleteOptions CodeCompleteOpts;
>From 3b68204cdcb6038fc94c7bb067505b0202e6903e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hendrik=20H=C3=BCbner?=
<117831077+HendrikHuebner at users.noreply.github.com>
Date: Tue, 30 Jun 2026 10:23:32 +0200
Subject: [PATCH 3/4] Nits
---
clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
index 8ce08d7c4c7c8..92c9ef5499693 100644
--- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -135,7 +135,7 @@ class CIRGenConsumer : public clang::ASTConsumer {
mlir::MLIRContext &MlirCtx = Gen->getMLIRContext();
if (!FEOptions.ClangIRDisablePasses) {
- std::string LibOptOptions = FEOptions.clangIRLibOptOptions;
+ std::string LibOptOptions = FEOptions.ClangIRLibOptOptions;
// Setup and run CIR pipeline.
const bool EnableLibOpt =
>From adcaa019a96a62916de5e56c57e05e26df78c901 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hendrik=20H=C3=BCbner?=
<117831077+HendrikHuebner at users.noreply.github.com>
Date: Tue, 30 Jun 2026 10:25:23 +0200
Subject: [PATCH 4/4] Nits
---
clang/include/clang/Options/Options.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index d121e1a84ec70..a099aa2824159 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -3408,7 +3408,7 @@ def clangir_enable_idiom_recognizer : Flag<["-"], "clangir-enable-idiom-recogniz
def clangir_lib_opt_EQ : Joined<["-"], "clangir-lib-opt=">,
Visibility<[ClangOption, CC1Option]>, Group<f_Group>, Values<"all">,
HelpText<"Enable C/C++ library based optimizations (with options)">,
- MarshallingInfoString<FrontendOpts<"clangIRLibOptOptions">>;
+ MarshallingInfoString<FrontendOpts<"ClangIRLibOptOptions">>;
def clangir_lib_opt : Flag<["-"], "clangir-lib-opt">,
Visibility<[ClangOption, CC1Option]>, Group<f_Group>,
More information about the cfe-commits
mailing list