[clang] [CIR] Add custom constructor declaration to CIR lowering TableGen (PR #176664)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 25 10:32:17 PST 2026
https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/176664
>From 8b9b35fac43c6fbdd082ab49b0a035cb5227a502 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Sun, 21 Dec 2025 21:22:21 -0500
Subject: [PATCH 1/3] [CIR] Add custom constructor declaration to CIR lowering
TableGen
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 26 +++++-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 15 ++++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 42 +++++++++
clang/utils/TableGen/CIRLoweringEmitter.cpp | 87 ++++++++++++++++---
4 files changed, 158 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index e31024f7dfa84..0907939d124b6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -77,6 +77,11 @@ class LLVMLoweringInfo {
string llvmOp = "";
}
+class loweringBuilders<dag p, code b = ""> {
+ dag dagParams = p;
+ code body = b;
+}
+
class CIR_Op<string mnemonic, list<Trait> traits = []> :
Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo {
// Should we generate an ABI lowering pattern for this op?
@@ -88,6 +93,21 @@ class CIR_Op<string mnemonic, list<Trait> traits = []> :
// Extra class declarations to be included in the generated LLVM lowering
// pattern.
code extraLLVMLoweringPatternDecl = "";
+ // Optional custom constructor for the generated LLVM lowering pattern.
+ //
+ // By default, CIR generates a standard lowering pattern constructor that
+ // receives the TypeConverter, MLIRContext, LowerModule, and DataLayout.
+ // Some operations require additional state or external context to be passed
+ // to the lowering pattern.
+ //
+ // This field allows an operation to define a single custom constructor for
+ // its LLVM lowering pattern. When specified, the default constructor is not
+ // generated, and only this custom constructor is emitted.
+ // NOTE: When providing a custom constructor, the corresponding lowering
+ // pattern is not automatically added to the RewritePatternSet. Users are
+ // responsible for manually registering the lowering pattern in the lowering
+ // pass.
+ loweringBuilders customLLVMLoweringConstructorDecl = ?;
}
//===----------------------------------------------------------------------===//
@@ -1481,7 +1501,8 @@ def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> {
let assemblyFormat = [{ $label attr-dict }];
let hasVerifier = 1;
- let hasLLVMLowering = false;
+ let customLLVMLoweringConstructorDecl =
+ loweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>;
}
//===----------------------------------------------------------------------===//
@@ -6023,6 +6044,9 @@ def CIR_BlockAddressOp : CIR_Op<"block_address", [Pure]> {
let assemblyFormat = [{
$block_addr_info `:` qualified(type($addr)) attr-dict
}];
+
+ let customLLVMLoweringConstructorDecl =
+ loweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7625bcccd520f..69daaf72b66e3 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3230,7 +3230,16 @@ void ConvertCIRToLLVMPass::runOnOperation() {
std::unique_ptr<cir::LowerModule> lowerModule = prepareLowerModule(module);
prepareTypeConverter(converter, dl, lowerModule.get());
+ /// Tracks the state required to lower CIR `LabelOp` and `BlockAddressOp`.
+ /// Maps labels to their corresponding `BlockTagOp` and keeps bookkeeping
+ /// of unresolved `BlockAddressOp`s until they are matched with the
+ /// corresponding `BlockTagOp` in `resolveBlockAddressOp`.
+ LLVMBlockAddressInfo blockInfoAddr;
mlir::RewritePatternSet patterns(&getContext());
+ patterns.add<CIRToLLVMBlockAddressOpLowering>(
+ converter, patterns.getContext(), lowerModule.get(), dl, blockInfoAddr);
+ patterns.add<CIRToLLVMLabelOpLowering>(converter, patterns.getContext(),
+ lowerModule.get(), dl, blockInfoAddr);
patterns.add<
#define GET_LLVM_LOWERING_PATTERNS_LIST
@@ -4279,6 +4288,12 @@ mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMLabelOpLowering::matchAndRewrite(
+ cir::LabelOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ return mlir::failure();
+}
+
mlir::LogicalResult CIRToLLVMBlockAddressOpLowering::matchAndRewrite(
cir::BlockAddressOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index d32f8603ee0be..7235794c3f9b4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -36,6 +36,48 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
mlir::LLVM::MemoryEffectsAttr &memoryEffect,
bool &noUnwind, bool &willReturn);
+struct LLVMBlockAddressInfo {
+ // Get the next tag index
+ uint32_t getTagIndex() { return blockTagOpIndex++; }
+
+ void mapBlockTag(cir::BlockAddrInfoAttr info, mlir::LLVM::BlockTagOp tagOp) {
+ auto result = blockInfoToTagOp.try_emplace(info, tagOp);
+ assert(result.second &&
+ "attempting to map a BlockTag operation that is already mapped");
+ }
+
+ // Lookup a BlockTagOp, may return nullptr if not yet registered.
+ mlir::LLVM::BlockTagOp lookupBlockTag(cir::BlockAddrInfoAttr info) const {
+ return blockInfoToTagOp.lookup(info);
+ }
+
+ // Record an unresolved BlockAddressOp that needs patching later.
+ void addUnresolvedBlockAddress(mlir::LLVM::BlockAddressOp op,
+ cir::BlockAddrInfoAttr info) {
+ unresolvedBlockAddressOp.try_emplace(op, info);
+ }
+
+ void clearUnresolvedMap() { unresolvedBlockAddressOp.clear(); }
+
+ llvm::DenseMap<mlir::LLVM::BlockAddressOp, cir::BlockAddrInfoAttr> &
+ getUnresolvedBlockAddress() {
+ return unresolvedBlockAddressOp;
+ }
+
+private:
+ // Maps a (function name, label name) pair to the corresponding BlockTagOp.
+ // Used to resolve CIR LabelOps into their LLVM BlockTagOp.
+ llvm::DenseMap<cir::BlockAddrInfoAttr, mlir::LLVM::BlockTagOp>
+ blockInfoToTagOp;
+ // Tracks BlockAddressOps that could not yet be fully resolved because
+ // their BlockTagOp was not available at the time of lowering. The map
+ // stores the unresolved BlockAddressOp along with its (function name, label
+ // name) pair so it can be patched later.
+ llvm::DenseMap<mlir::LLVM::BlockAddressOp, cir::BlockAddrInfoAttr>
+ unresolvedBlockAddressOp;
+ int32_t blockTagOpIndex;
+};
+
#define GET_LLVM_LOWERING_PATTERNS
#include "clang/CIR/Dialect/IR/CIRLowering.inc"
#undef GET_LLVM_LOWERING_PATTERNS
diff --git a/clang/utils/TableGen/CIRLoweringEmitter.cpp b/clang/utils/TableGen/CIRLoweringEmitter.cpp
index a669f21aa1108..4af8026a559de 100644
--- a/clang/utils/TableGen/CIRLoweringEmitter.cpp
+++ b/clang/utils/TableGen/CIRLoweringEmitter.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "TableGenBackends.h"
+#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <string>
#include <utility>
@@ -25,6 +26,16 @@ std::vector<std::string> CXXABILoweringPatternsList;
std::vector<std::string> LLVMLoweringPatterns;
std::vector<std::string> LLVMLoweringPatternsList;
+struct CustomLoweringCtor {
+ struct Param {
+ std::string Type;
+ std::string Name;
+ };
+
+ std::vector<Param> Params;
+ std::string Body;
+};
+
// Adapted from mlir/lib/TableGen/Operator.cpp
// Returns the C++ class name of the operation, which is the name of the
// operation with the dialect prefix removed and the first underscore removed.
@@ -60,6 +71,34 @@ std::string GetOpLLVMLoweringPatternName(llvm::StringRef OpName) {
Name += "Lowering";
return Name;
}
+std::optional<CustomLoweringCtor> parseCustomLoweringCtor(const Record *R) {
+ if (!R)
+ return std::nullopt;
+
+ CustomLoweringCtor Ctor;
+ const DagInit *Args = R->getValueAsDag("dagParams");
+ Ctor.Body = R->getValueAsString("body");
+
+ for (const auto &[Arg, Name] : Args->getArgAndNames()) {
+ Ctor.Params.push_back(
+ {Arg->getAsUnquotedString(), Name->getAsUnquotedString()});
+ }
+
+ return Ctor;
+}
+void emitCustomParamList(raw_ostream &Code,
+ ArrayRef<CustomLoweringCtor::Param> Params) {
+ for (const auto &Param : Params) {
+ Code << ", ";
+ Code << Param.Type << " " << Param.Name;
+ }
+}
+
+void emitCustomInitList(raw_ostream &Code,
+ ArrayRef<CustomLoweringCtor::Param> Params) {
+ for (auto &P : Params)
+ Code << ", " << P.Name << "(" << P.Name << ")";
+}
void GenerateABILoweringPattern(llvm::StringRef OpName,
llvm::StringRef PatternName) {
@@ -93,7 +132,9 @@ void GenerateABILoweringPattern(llvm::StringRef OpName,
void GenerateLLVMLoweringPattern(llvm::StringRef OpName,
llvm::StringRef PatternName, bool IsRecursive,
- llvm::StringRef ExtraDecl) {
+ llvm::StringRef ExtraDecl,
+ const Record *CustomCtorRec) {
+ auto CustomCtor = parseCustomLoweringCtor(CustomCtorRec);
std::string CodeBuffer;
llvm::raw_string_ostream Code(CodeBuffer);
@@ -101,29 +142,46 @@ void GenerateLLVMLoweringPattern(llvm::StringRef OpName,
<< " : public mlir::OpConversionPattern<cir::" << OpName << "> {\n";
Code << " [[maybe_unused]] cir::LowerModule *lowerMod;\n";
Code << " [[maybe_unused]] mlir::DataLayout const &dataLayout;\n";
+
+ if (CustomCtor) {
+ for (auto &P : CustomCtor->Params)
+ Code << " " << P.Type << " " << P.Name << ";\n";
+ }
+
Code << "\n";
Code << "public:\n";
Code << " using mlir::OpConversionPattern<cir::" << OpName
<< ">::OpConversionPattern;\n";
+ // Constructor
Code << " " << PatternName
<< "(mlir::TypeConverter const "
"&typeConverter, mlir::MLIRContext *context, "
"cir::LowerModule *lowerMod, mlir::DataLayout const "
- "&dataLayout)\n";
+ "&dataLayout";
+
+ if (CustomCtor)
+ emitCustomParamList(Code, CustomCtor->Params);
+
+ Code << ")\n";
+
Code << " : OpConversionPattern<cir::" << OpName
<< ">(typeConverter, context), lowerMod(lowerMod), "
"dataLayout(dataLayout)";
- if (IsRecursive) {
- Code << " {\n";
+
+ if (CustomCtor)
+ emitCustomInitList(Code, CustomCtor->Params);
+
+ Code << " {\n";
+
+ if (IsRecursive)
Code << " setHasBoundedRewriteRecursion();\n";
- Code << " }\n";
- } else {
- Code << " {}\n";
- }
- Code << "\n";
+ if (CustomCtor)
+ Code << CustomCtor->Body << "\n";
+
+ Code << " }\n\n";
Code << " mlir::LogicalResult matchAndRewrite(cir::" << OpName
<< " op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) "
@@ -151,11 +209,18 @@ void Generate(const Record *OpRecord) {
if (OpRecord->getValueAsBit("hasLLVMLowering")) {
std::string PatternName = GetOpLLVMLoweringPatternName(OpName);
bool IsRecursive = OpRecord->getValueAsBit("isLLVMLoweringRecursive");
+ const Record *CustomCtor =
+ OpRecord->getValueAsOptionalDef("customLLVMLoweringConstructorDecl");
llvm::StringRef ExtraDecl =
OpRecord->getValueAsString("extraLLVMLoweringPatternDecl");
- GenerateLLVMLoweringPattern(OpName, PatternName, IsRecursive, ExtraDecl);
- LLVMLoweringPatternsList.push_back(std::move(PatternName));
+ GenerateLLVMLoweringPattern(OpName, PatternName, IsRecursive, ExtraDecl,
+ CustomCtor);
+ // Only automatically register patterns that use the default constructor.
+ // Patterns with a custom constructor must be manually registered by the
+ // lowering pass.
+ if (!CustomCtor)
+ LLVMLoweringPatternsList.push_back(std::move(PatternName));
}
}
} // namespace
>From c9f602dc283f9cbaa8c6f68421f31f11db04d767 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Tue, 20 Jan 2026 21:03:48 -0500
Subject: [PATCH 2/3] Address review feedback
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 9 ++++-----
clang/utils/TableGen/CIRLoweringEmitter.cpp | 15 ++++++---------
2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 0907939d124b6..33fadd0f762b5 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -77,9 +77,8 @@ class LLVMLoweringInfo {
string llvmOp = "";
}
-class loweringBuilders<dag p, code b = ""> {
+class LoweringBuilders<dag p> {
dag dagParams = p;
- code body = b;
}
class CIR_Op<string mnemonic, list<Trait> traits = []> :
@@ -107,7 +106,7 @@ class CIR_Op<string mnemonic, list<Trait> traits = []> :
// pattern is not automatically added to the RewritePatternSet. Users are
// responsible for manually registering the lowering pattern in the lowering
// pass.
- loweringBuilders customLLVMLoweringConstructorDecl = ?;
+ LoweringBuilders customLLVMLoweringConstructorDecl = ?;
}
//===----------------------------------------------------------------------===//
@@ -1502,7 +1501,7 @@ def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> {
let hasVerifier = 1;
let customLLVMLoweringConstructorDecl =
- loweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>;
+ LoweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>;
}
//===----------------------------------------------------------------------===//
@@ -6046,7 +6045,7 @@ def CIR_BlockAddressOp : CIR_Op<"block_address", [Pure]> {
}];
let customLLVMLoweringConstructorDecl =
- loweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>;
+ LoweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/utils/TableGen/CIRLoweringEmitter.cpp b/clang/utils/TableGen/CIRLoweringEmitter.cpp
index 4af8026a559de..d50373bb8b5dc 100644
--- a/clang/utils/TableGen/CIRLoweringEmitter.cpp
+++ b/clang/utils/TableGen/CIRLoweringEmitter.cpp
@@ -33,7 +33,6 @@ struct CustomLoweringCtor {
};
std::vector<Param> Params;
- std::string Body;
};
// Adapted from mlir/lib/TableGen/Operator.cpp
@@ -77,7 +76,6 @@ std::optional<CustomLoweringCtor> parseCustomLoweringCtor(const Record *R) {
CustomLoweringCtor Ctor;
const DagInit *Args = R->getValueAsDag("dagParams");
- Ctor.Body = R->getValueAsString("body");
for (const auto &[Arg, Name] : Args->getArgAndNames()) {
Ctor.Params.push_back(
@@ -86,9 +84,10 @@ std::optional<CustomLoweringCtor> parseCustomLoweringCtor(const Record *R) {
return Ctor;
}
+
void emitCustomParamList(raw_ostream &Code,
ArrayRef<CustomLoweringCtor::Param> Params) {
- for (const auto &Param : Params) {
+ for (const CustomLoweringCtor::Param &Param : Params) {
Code << ", ";
Code << Param.Type << " " << Param.Name;
}
@@ -96,7 +95,7 @@ void emitCustomParamList(raw_ostream &Code,
void emitCustomInitList(raw_ostream &Code,
ArrayRef<CustomLoweringCtor::Param> Params) {
- for (auto &P : Params)
+ for (const CustomLoweringCtor::Param &P : Params)
Code << ", " << P.Name << "(" << P.Name << ")";
}
@@ -134,7 +133,8 @@ void GenerateLLVMLoweringPattern(llvm::StringRef OpName,
llvm::StringRef PatternName, bool IsRecursive,
llvm::StringRef ExtraDecl,
const Record *CustomCtorRec) {
- auto CustomCtor = parseCustomLoweringCtor(CustomCtorRec);
+ std::optional<CustomLoweringCtor> CustomCtor =
+ parseCustomLoweringCtor(CustomCtorRec);
std::string CodeBuffer;
llvm::raw_string_ostream Code(CodeBuffer);
@@ -144,7 +144,7 @@ void GenerateLLVMLoweringPattern(llvm::StringRef OpName,
Code << " [[maybe_unused]] mlir::DataLayout const &dataLayout;\n";
if (CustomCtor) {
- for (auto &P : CustomCtor->Params)
+ for (const CustomLoweringCtor::Param &P : CustomCtor->Params)
Code << " " << P.Type << " " << P.Name << ";\n";
}
@@ -178,9 +178,6 @@ void GenerateLLVMLoweringPattern(llvm::StringRef OpName,
if (IsRecursive)
Code << " setHasBoundedRewriteRecursion();\n";
- if (CustomCtor)
- Code << CustomCtor->Body << "\n";
-
Code << " }\n\n";
Code << " mlir::LogicalResult matchAndRewrite(cir::" << OpName
>From fb738d470be82b517efb3011ab85a5bb8d59c9af Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Sun, 25 Jan 2026 13:31:24 -0500
Subject: [PATCH 3/3] Add [[maybe_unused]] to LLVMBlockAddressInfo
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 ++--
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 4 +---
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 33fadd0f762b5..6d4d7b313f6e3 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1501,7 +1501,7 @@ def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> {
let hasVerifier = 1;
let customLLVMLoweringConstructorDecl =
- LoweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>;
+ LoweringBuilders<(ins "[[maybe_unused]] LLVMBlockAddressInfo &":$blockInfoAddr)>;
}
//===----------------------------------------------------------------------===//
@@ -6045,7 +6045,7 @@ def CIR_BlockAddressOp : CIR_Op<"block_address", [Pure]> {
}];
let customLLVMLoweringConstructorDecl =
- LoweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>;
+ LoweringBuilders<(ins "[[maybe_unused]] LLVMBlockAddressInfo &":$blockInfoAddr)>;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 69daaf72b66e3..a45025430b961 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3236,10 +3236,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
/// corresponding `BlockTagOp` in `resolveBlockAddressOp`.
LLVMBlockAddressInfo blockInfoAddr;
mlir::RewritePatternSet patterns(&getContext());
- patterns.add<CIRToLLVMBlockAddressOpLowering>(
+ patterns.add<CIRToLLVMBlockAddressOpLowering, CIRToLLVMLabelOpLowering>(
converter, patterns.getContext(), lowerModule.get(), dl, blockInfoAddr);
- patterns.add<CIRToLLVMLabelOpLowering>(converter, patterns.getContext(),
- lowerModule.get(), dl, blockInfoAddr);
patterns.add<
#define GET_LLVM_LOWERING_PATTERNS_LIST
More information about the cfe-commits
mailing list