[clang] [CIR] Intitial upstreaming of LibOpt pass (PR #172487)
Hendrik Hübner via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 29 11:55:20 PDT 2026
https://github.com/HendrikHuebner updated https://github.com/llvm/llvm-project/pull/172487
>From 1125c6eee0381393aee9bd8c7c4be7feba71b93c 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] 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 | 18 ++++
.../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 | 96 +++++++++++++++++++
clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 7 +-
clang/lib/CIR/Lowering/CIRPasses.cpp | 17 +++-
clang/lib/Frontend/CompilerInvocation.cpp | 3 +
clang/test/CIR/Transforms/lib-opt.cpp | 6 ++
11 files changed, 171 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..c9187825c6e0a 100644
--- a/clang/include/clang/CIR/Dialect/Passes.td
+++ b/clang/include/clang/CIR/Dialect/Passes.td
@@ -195,6 +195,24 @@ 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"];
+ let options = [
+ ListOption<"remarksList", "remarks", "std::string",
+ "Diagnostic remarks to enable."
+ " Supported options: {all|transforms}",
+ "llvm::cl::ZeroOrMore">,
+ ];
+}
+
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..f1ccdd222379c
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/LibOpt.cpp
@@ -0,0 +1,96 @@
+//===- 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/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;
+ void runOnOperation() override;
+
+ class PassOptions {
+ enum : unsigned {
+ None = 0,
+ RemarkTransforms = 1,
+ RemarkAll = 1 << 1,
+ };
+
+ public:
+ void parseOption(const llvm::StringRef remark) {
+ value |= StringSwitch<unsigned>(remark)
+ .Case("transforms", RemarkTransforms)
+ .Case("all", RemarkAll)
+ .Default(None);
+ }
+
+ void parseOptions(LibOptPass &pass) {
+ if (isOptionsParsed)
+ return;
+
+ for (const llvm::StringRef &remark : pass.remarksList)
+ parseOption(remark);
+
+ isOptionsParsed = true;
+ }
+
+ bool emitRemarkAll() { return value & RemarkAll; }
+ bool emitRemarkTransforms() {
+ return emitRemarkAll() || value & RemarkTransforms;
+ }
+
+ private:
+ unsigned value = None;
+ bool isOptionsParsed = false;
+ };
+
+ PassOptions passOptions;
+
+ /// Tracks current module.
+ ModuleOp theModule;
+};
+} // namespace
+
+void LibOptPass::runOnOperation() {
+ passOptions.parseOptions(*this);
+ 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..a558bc457bfa7 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,19 @@ 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..89c712ffb9f21
--- /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)
More information about the cfe-commits
mailing list