https://github.com/HendrikHuebner updated https://github.com/llvm/llvm-project/pull/172487
From e54f437429c62d7754685c4a26c0d69be6408e17 Mon Sep 17 00:00:00 2001 From: hhuebner <[email protected]> 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?= <[email protected]> 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?= <[email protected]> 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?= <[email protected]> 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>, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
