https://github.com/HendrikHuebner updated https://github.com/llvm/llvm-project/pull/172486
From b3dc20805532db4e2f8ddeb6c959cecbf0de912b Mon Sep 17 00:00:00 2001 From: hhuebner <[email protected]> Date: Tue, 16 Dec 2025 15:02:32 +0100 Subject: [PATCH 1/3] Add idiom recognizer pass --- clang/include/clang/CIR/Dialect/Passes.h | 2 + clang/include/clang/CIR/Dialect/Passes.td | 11 +++ .../lib/CIR/Dialect/Transforms/CMakeLists.txt | 1 + .../Dialect/Transforms/IdiomRecognizer.cpp | 69 +++++++++++++++++++ clang/lib/CIR/Lowering/CIRPasses.cpp | 1 + .../test/CIR/Transforms/idiom-recognizer.cpp | 2 + 6 files changed, 86 insertions(+) create mode 100644 clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp create mode 100644 clang/test/CIR/Transforms/idiom-recognizer.cpp diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h index 161f365bb1402..7b57b00f7da8c 100644 --- a/clang/include/clang/CIR/Dialect/Passes.h +++ b/clang/include/clang/CIR/Dialect/Passes.h @@ -30,6 +30,8 @@ std::unique_ptr<Pass> createHoistAllocasPass(); std::unique_ptr<Pass> createLoweringPreparePass(); 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); void populateCIRPreLoweringPasses(mlir::OpPassManager &pm); diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td index ef5308ffffd19..0d1e15903b509 100644 --- a/clang/include/clang/CIR/Dialect/Passes.td +++ b/clang/include/clang/CIR/Dialect/Passes.td @@ -161,4 +161,15 @@ def LoweringPrepare : Pass<"cir-lowering-prepare"> { let dependentDialects = ["cir::CIRDialect"]; } +def IdiomRecognizer : Pass<"cir-idiom-recognizer"> { + let summary = "Raise calls to C/C++ libraries to CIR operations"; + let description = [{ + This pass recognize idiomatic C++ usage and incorporate C++ standard + containers, library functions calls, and types into CIR operation, + attributes and types. + }]; + let constructor = "mlir::createIdiomRecognizerPass()"; + let dependentDialects = ["cir::CIRDialect"]; +} + #endif // CLANG_CIR_DIALECT_PASSES_TD diff --git a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt index 1ace2d8634b40..3fe6c5f9ecb55 100644 --- a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_library(MLIRCIRTransforms HoistAllocas.cpp LoweringPrepare.cpp GotoSolver.cpp + IdiomRecognizer.cpp DEPENDS MLIRCIRPassIncGen diff --git a/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp b/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp new file mode 100644 index 0000000000000..ff1110f86ce8f --- /dev/null +++ b/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp @@ -0,0 +1,69 @@ +//===- IdiomRecognizer.cpp - pareparation work for LLVM lowering ----------===// +// +// 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 is responsible for recognizing idioms (such as uses of functions +// and types to the C/C++ standard library) and replacing them with Clang IR +// operators for later optimization. +// +//===----------------------------------------------------------------------===// + +#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 namespace mlir; +using namespace cir; + +namespace mlir { +#define GEN_PASS_DEF_IDIOMRECOGNIZER +#include "clang/CIR/Dialect/Passes.h.inc" +} // namespace mlir + +namespace { + +struct IdiomRecognizerPass : public impl::IdiomRecognizerBase<IdiomRecognizerPass> { + IdiomRecognizerPass() = default; + void runOnOperation() override; + + clang::ASTContext *astCtx; + void setASTContext(clang::ASTContext *c) { astCtx = c; } + + /// Tracks current module. + ModuleOp theModule; +}; +} // namespace + +void IdiomRecognizerPass::runOnOperation() { + auto *op = getOperation(); + if (isa<::mlir::ModuleOp>(op)) + theModule = cast<::mlir::ModuleOp>(op); +} + +std::unique_ptr<Pass> mlir::createIdiomRecognizerPass() { + return std::make_unique<IdiomRecognizerPass>(); +} + +std::unique_ptr<Pass> +mlir::createIdiomRecognizerPass(clang::ASTContext *astCtx) { + auto pass = std::make_unique<IdiomRecognizerPass>(); + pass->setASTContext(astCtx); + return std::move(pass); +} \ No newline at end of file diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp index 589c2c524c305..9c91ac51bebd7 100644 --- a/clang/lib/CIR/Lowering/CIRPasses.cpp +++ b/clang/lib/CIR/Lowering/CIRPasses.cpp @@ -31,6 +31,7 @@ mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, if (enableCIRSimplify) pm.addPass(mlir::createCIRSimplifyPass()); + pm.addPass(mlir::createIdiomRecognizerPass()); pm.addPass(mlir::createTargetLoweringPass()); pm.addPass(mlir::createCXXABILoweringPass()); pm.addPass(mlir::createLoweringPreparePass(&astContext)); diff --git a/clang/test/CIR/Transforms/idiom-recognizer.cpp b/clang/test/CIR/Transforms/idiom-recognizer.cpp new file mode 100644 index 0000000000000..b309d813ace40 --- /dev/null +++ b/clang/test/CIR/Transforms/idiom-recognizer.cpp @@ -0,0 +1,2 @@ +// RUN: %clang_cc1 -fclangir -emit-cir -mmlir --mlir-print-ir-after-all %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=CIR +// CIR: IR Dump After IdiomRecognizer (cir-idiom-recognizer) From bf20acfccaa63cc64ce076900a94741e880917d5 Mon Sep 17 00:00:00 2001 From: hhuebner <[email protected]> Date: Fri, 19 Dec 2025 22:05:40 +0100 Subject: [PATCH 2/3] fmt --- clang/include/clang/CIR/Dialect/Passes.td | 8 +++--- .../Dialect/Transforms/IdiomRecognizer.cpp | 28 +++++++++++++++---- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td index 0d1e15903b509..0d60d5e33dd4b 100644 --- a/clang/include/clang/CIR/Dialect/Passes.td +++ b/clang/include/clang/CIR/Dialect/Passes.td @@ -161,12 +161,12 @@ def LoweringPrepare : Pass<"cir-lowering-prepare"> { let dependentDialects = ["cir::CIRDialect"]; } -def IdiomRecognizer : Pass<"cir-idiom-recognizer"> { +def IdiomRecognizer : Pass<"cir-idiom-recognizer", "mlir::ModuleOp"> { let summary = "Raise calls to C/C++ libraries to CIR operations"; let description = [{ - This pass recognize idiomatic C++ usage and incorporate C++ standard - containers, library functions calls, and types into CIR operation, - attributes and types. + This pass recognizes idiomatic C++ usage and captures information about C++ + standard library containers, library functions calls, and types into CIR + operations, attributes and types. }]; let constructor = "mlir::createIdiomRecognizerPass()"; let dependentDialects = ["cir::CIRDialect"]; diff --git a/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp b/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp index ff1110f86ce8f..92c031a5a51e1 100644 --- a/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp +++ b/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp @@ -1,4 +1,4 @@ -//===- IdiomRecognizer.cpp - pareparation work for LLVM lowering ----------===// +//===- IdiomRecognizer.cpp - recognizing and raising idioms to CIR --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -39,10 +39,14 @@ namespace mlir { namespace { -struct IdiomRecognizerPass : public impl::IdiomRecognizerBase<IdiomRecognizerPass> { +struct IdiomRecognizerPass + : public impl::IdiomRecognizerBase<IdiomRecognizerPass> { IdiomRecognizerPass() = default; + void runOnOperation() override; + void recognizeStandardLibraryCall(CallOp call); + clang::ASTContext *astCtx; void setASTContext(clang::ASTContext *c) { astCtx = c; } @@ -51,10 +55,22 @@ struct IdiomRecognizerPass : public impl::IdiomRecognizerBase<IdiomRecognizerPas }; } // namespace +void IdiomRecognizerPass::recognizeStandardLibraryCall(CallOp call) { + // To be implemented +} + void IdiomRecognizerPass::runOnOperation() { - auto *op = getOperation(); - if (isa<::mlir::ModuleOp>(op)) - theModule = cast<::mlir::ModuleOp>(op); + theModule = getOperation(); + + // Process call operations + theModule->walk([&](CallOp callOp) { + // Skip indirect calls. + std::optional<llvm::StringRef> callee = callOp.getCallee(); + if (!callee) + return; + + recognizeStandardLibraryCall(callOp); + }); } std::unique_ptr<Pass> mlir::createIdiomRecognizerPass() { @@ -66,4 +82,4 @@ mlir::createIdiomRecognizerPass(clang::ASTContext *astCtx) { auto pass = std::make_unique<IdiomRecognizerPass>(); pass->setASTContext(astCtx); return std::move(pass); -} \ No newline at end of file +} From b1a2ac27516943dcfd705c3de6cbc7bf86a11ea4 Mon Sep 17 00:00:00 2001 From: hhuebner <[email protected]> Date: Sun, 15 Feb 2026 13:34:48 +0100 Subject: [PATCH 3/3] Add CLI flag --- clang/include/clang/CIR/CIRToCIRPasses.h | 1 + clang/include/clang/Frontend/FrontendOptions.h | 8 ++++++-- clang/include/clang/Options/Options.td | 5 +++++ clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp | 11 +++++++++++ clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 1 + clang/lib/CIR/Lowering/CIRPasses.cpp | 5 ++++- 6 files changed, 28 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/CIR/CIRToCIRPasses.h b/clang/include/clang/CIR/CIRToCIRPasses.h index 4a23790ee8b76..c211df44c641b 100644 --- a/clang/include/clang/CIR/CIRToCIRPasses.h +++ b/clang/include/clang/CIR/CIRToCIRPasses.h @@ -33,6 +33,7 @@ mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirCtx, clang::ASTContext &astCtx, bool enableVerifier, + bool enableIdiomRecognizer, bool enableCIRSimplify); } // namespace cir diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index ba7da56cb9fce..9a7fdf5cbcf06 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -422,6 +422,10 @@ class FrontendOptions { LLVM_PREFERRED_TYPE(bool) unsigned ClangIRDisableCIRVerifier : 1; + /// Enable Clang IR (CIR) idiom recognizer + LLVM_PREFERRED_TYPE(bool) + unsigned ClangIREnableIdiomRecognizer : 1; + CodeCompleteOptions CodeCompleteOpts; /// Specifies the output format of the AST. @@ -552,8 +556,8 @@ class FrontendOptions { EmitSymbolGraphSymbolLabelsForTesting(false), EmitPrettySymbolGraphs(false), GenReducedBMI(false), UseClangIRPipeline(false), ClangIRDisablePasses(false), - ClangIRDisableCIRVerifier(false), TimeTraceGranularity(500), - TimeTraceVerbose(false) {} + ClangIRDisableCIRVerifier(false), ClangIREnableIdiomRecognizer(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 a274017953b1d..aa878addd9b9b 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3253,6 +3253,11 @@ def clangir_disable_verifier : Flag<["-"], "clangir-disable-verifier">, HelpText<"ClangIR: Disable MLIR module verifier">, MarshallingInfoFlag<FrontendOpts<"ClangIRDisableCIRVerifier">>; +def clangir_enable_idiom_recognizer : Flag<["-"], "clangir-enable-idiom-recognizer">, + Visibility<[ClangOption, CC1Option]>, + HelpText<"ClangIR: Enable Idiom Recognizer pass">, + MarshallingInfoFlag<FrontendOpts<"ClangIREnableIdiomRecognizer">>; + 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/IdiomRecognizer.cpp b/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp index 92c031a5a51e1..4a8f931dd2d4d 100644 --- a/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp +++ b/clang/lib/CIR/Dialect/Transforms/IdiomRecognizer.cpp @@ -60,6 +60,17 @@ void IdiomRecognizerPass::recognizeStandardLibraryCall(CallOp call) { } void IdiomRecognizerPass::runOnOperation() { + // The AST context will be used to provide additional information such as + // namespaces and template parameter lists that are lost after lowering to + // CIR. This information is necessary to recognize many idioms, such as calls + // to standard library functions. + + // For now, the AST will be required to allow for faster prototyping and + // exploring of new optimizations. In the future, it may be preferable to + // make it optional to reduce memory pressure and allow this pass to run + // on standalone CIR assembly (Possibly generated from non-Clang front ends). + + assert(astCtx && "Missing ASTContext, please construct with the right ctor"); theModule = getOperation(); // Process call operations diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index daec8ae409e0f..e2d883a6b3a55 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -117,6 +117,7 @@ class CIRGenConsumer : public clang::ASTConsumer { // Setup and run CIR pipeline. if (runCIRToCIRPasses(MlirModule, MlirCtx, C, !FEOptions.ClangIRDisableCIRVerifier, + FEOptions.ClangIREnableIdiomRecognizer, CGO.OptimizationLevel > 0) .failed()) { CI.getDiagnostics().Report(diag::err_cir_to_cir_transform_failed); diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp index 9c91ac51bebd7..8ca0263f67ad1 100644 --- a/clang/lib/CIR/Lowering/CIRPasses.cpp +++ b/clang/lib/CIR/Lowering/CIRPasses.cpp @@ -21,6 +21,7 @@ mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirContext, clang::ASTContext &astContext, bool enableVerifier, + bool enableIdiomRecognizer, bool enableCIRSimplify) { llvm::TimeTraceScope scope("CIR To CIR Passes"); @@ -31,7 +32,9 @@ mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, if (enableCIRSimplify) pm.addPass(mlir::createCIRSimplifyPass()); - pm.addPass(mlir::createIdiomRecognizerPass()); + if (enableIdiomRecognizer) + pm.addPass(mlir::createIdiomRecognizerPass()); + pm.addPass(mlir::createTargetLoweringPass()); pm.addPass(mlir::createCXXABILoweringPass()); pm.addPass(mlir::createLoweringPreparePass(&astContext)); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
