Skip to content

Conversation

@Lancern
Copy link
Member

@Lancern Lancern commented Sep 17, 2025

Most lowering patterns have exactly the same class declaration with different names and different matchAndRewrite implementations, yet their declaration occupies near 1000 lines of code in LowerToLLVM.h, making this file difficult to read and boring to maintain. In this patch, I migrate their declarations to be generated from CIROps.td using clang-tblgen. Some extra CIR_Op TableGen fields are introduced to help this:

  • The CIR_Op class now defines a bit field hasLLVMLowering which defaults to true. If its value is true, clang-tblgen would generate an LLVM lowering pattern declaration for the operation.

  • Some LLVM lowering patterns has bounded recursion. This could be enabled by setting the isLLVMLoweringRecursive field in a CIR_Op record to true.

  • Some LLVM lowering patterns have defined additional class members. They could be listed in the extraLLVMLoweringPatternDecl field.

Note that in the incubator we have a similar TableGen code generator that generates LLVM lowering code for CIR builtin ops which has a one-to-one correspondence to LLVM dialect operations. This patch does NOT try to upstream it.

Some additional noticeable changes made by this patch:

  • This patch adds the dataLayout member to every LLVM lowering pattern class to make the job easier for a code generator. In the future we might want to add more members to the lowering patterns, and we will need to update the code generator to make such changes.

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Sep 17, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 17, 2025

@llvm/pr-subscribers-clang

Author: Sirui Mu (Lancern)

Changes

Most lowering patterns have exactly the same class declaration with different names and different matchAndRewrite implementations, yet their declaration occupies near 1000 lines of code in LowerToLLVM.h, making this file difficult to read and boring to maintain. In this patch, I migrate their declarations to be generated from CIROps.td using clang-tblgen. Some extra CIR_Op TableGen fields are introduced to help this:

  • The CIR_Op class now defines a bit field hasLLVMLowering which defaults to true. If its value is true, clang-tblgen would generate an LLVM lowering pattern declaration for the operation.

  • Some LLVM lowering patterns has bounded recursion. This could be enabled by setting the isLLVMLoweringRecursive field in a CIR_Op record to true.

  • Some LLVM lowering patterns have defined additional class members. They could be listed in the extraLLVMLoweringPatternDecl field.

Note that in the incubator we have a similar TableGen code generator that generates LLVM lowering code for CIR builtin ops which has a one-to-one correspondence to LLVM dialect operations. This patch does NOT try to upstream it.

Some additional noticeable changes made by this patch:

  • This patch adds the dataLayout member to every LLVM lowering pattern class to make the job easier for a code generator. In the future we might want to add more members to the lowering patterns, and we will need to update the code generator to make such changes.

Patch is 47.18 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/159390.diff

8 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+79-1)
  • (modified) clang/include/clang/CIR/Dialect/IR/CMakeLists.txt (+4)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+4-80)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+3-795)
  • (added) clang/utils/TableGen/CIRLoweringEmitter.cpp (+125)
  • (modified) clang/utils/TableGen/CMakeLists.txt (+1)
  • (modified) clang/utils/TableGen/TableGen.cpp (+6)
  • (modified) clang/utils/TableGen/TableGenBackends.h (+1)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 38c4a87f69d6d..f80c9faf708ef 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -78,7 +78,15 @@ class LLVMLoweringInfo {
 }
 
 class CIR_Op<string mnemonic, list<Trait> traits = []> :
-    Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;
+    Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo {
+  // Should we generate an LLVM lowering pattern for this op?
+  bit hasLLVMLowering = true;
+  // Is the LLVM lowering pattern for this operation recursive?
+  bit isLLVMLoweringRecursive = false;
+  // Extra class declarations to be included in the generated LLVM lowering
+  // pattern.
+  code extraLLVMLoweringPatternDecl = "";
+}
 
 //===----------------------------------------------------------------------===//
 // CastOp
@@ -218,6 +226,10 @@ def CIR_CastOp : CIR_Op<"cast", [
   // The input and output types should match the cast kind.
   let hasVerifier = 1;
   let hasFolder = 1;
+
+  let extraLLVMLoweringPatternDecl = [{
+    mlir::Type convertTy(mlir::Type ty) const;
+  }];
 }
 
 
@@ -297,6 +309,8 @@ def CIR_ConstantOp : CIR_Op<"const", [
   }];
 
   let hasFolder = 1;
+
+  let isLLVMLoweringRecursive = true;
 }
 
 //===----------------------------------------------------------------------===//
@@ -613,6 +627,8 @@ def CIR_IfOp : CIR_Op<"if", [
       CArg<"BuilderCallbackRef", "buildTerminatedBody">:$thenBuilder,
       CArg<"BuilderCallbackRef", "nullptr">:$elseBuilder)>
   ];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -659,6 +675,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [
   let arguments = (ins CIR_BoolType:$condition);
   let assemblyFormat = " `(` $condition `)` attr-dict ";
   let hasVerifier = 1;
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -726,6 +743,8 @@ def CIR_YieldOp : CIR_Op<"yield", [
   let builders = [
     OpBuilder<(ins), [{ /* nothing to do */ }]>,
   ];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -741,6 +760,7 @@ def CIR_BreakOp : CIR_Op<"break", [Terminator]> {
   }];
   let assemblyFormat = "attr-dict";
   let hasVerifier = 1;
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -756,6 +776,7 @@ def CIR_ContinueOp : CIR_Op<"continue", [Terminator]> {
   }];
   let assemblyFormat = "attr-dict";
   let hasVerifier = 1;
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -814,6 +835,8 @@ def CIR_ScopeOp : CIR_Op<"scope", [
     // Scopes without yielding values.
     OpBuilder<(ins "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$scopeBuilder)>
   ];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -860,6 +883,8 @@ def CIR_CaseOp : CIR_Op<"case", [
                    "CaseOpKind":$kind,
                    "mlir::OpBuilder::InsertPoint &":$insertPoint)>
   ];
+
+  let hasLLVMLowering = false;
 }
 
 def CIR_SwitchOp : CIR_Op<"switch", [
@@ -1025,6 +1050,8 @@ def CIR_SwitchOp : CIR_Op<"switch", [
     // This is an expensive and need to be used with caution.
     bool isSimpleForm(llvm::SmallVectorImpl<CaseOp> &cases);
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1170,6 +1197,8 @@ def CIR_GotoOp : CIR_Op<"goto", [Terminator]> {
   }];
   let arguments = (ins StrAttr:$label);
   let assemblyFormat = [{ $label attr-dict }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1185,6 +1214,8 @@ def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> {
   let arguments = (ins StrAttr:$label);
   let assemblyFormat = [{ $label attr-dict }];
   let hasVerifier = 1;
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1349,6 +1380,8 @@ def CIR_WhileOp : CIR_WhileOpBase<"while"> {
     }
     ```
   }];
+
+  let hasLLVMLowering = false;
 }
 
 def CIR_DoWhileOp : CIR_WhileOpBase<"do"> {
@@ -1375,6 +1408,8 @@ def CIR_DoWhileOp : CIR_WhileOpBase<"do"> {
     }
     ```
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1442,6 +1477,8 @@ def CIR_ForOp : CIR_LoopOpBase<"for"> {
       return llvm::SmallVector<mlir::Region *, 3>{&getCond(), &getBody(), &getStep()};
     }
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1480,6 +1517,8 @@ def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
   let assemblyFormat = [{
     `(` $kind `,` $lhs `,` $rhs  `)` `:` type($lhs) `,` type($result) attr-dict
   }];
+
+  let isLLVMLoweringRecursive = true;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1550,6 +1589,10 @@ def CIR_BinOp : CIR_Op<"binop", [
   }];
 
   let hasVerifier = 1;
+
+  let extraLLVMLoweringPatternDecl = [{
+    mlir::LLVM::IntegerOverflowFlags getIntOverflowFlag(cir::BinOp op) const;
+  }];
 }
 
 //===----------------------------------------------------------------------===//
@@ -1687,6 +1730,8 @@ def CIR_TernaryOp : CIR_Op<"ternary", [
       `false` $falseRegion
     `)` `:` functional-type(operands, results) attr-dict
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1790,6 +1835,20 @@ def CIR_GlobalOp : CIR_Op<"global", [
     "cir::GlobalLinkageKind::ExternalLinkage">:$linkage)>];
 
   let hasVerifier = 1;
+
+  let isLLVMLoweringRecursive = true;
+  let extraLLVMLoweringPatternDecl = [{
+    mlir::LogicalResult matchAndRewriteRegionInitializedGlobal(
+      cir::GlobalOp op, mlir::Attribute init,
+      mlir::ConversionPatternRewriter &rewriter) const;
+
+    void setupRegionInitializedLLVMGlobalOp(
+        cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const;
+
+    mutable mlir::LLVM::ComdatOp comdatOp = nullptr;
+    mlir::SymbolRefAttr getComdatAttr(cir::GlobalOp &op,
+                                      mlir::OpBuilder &builder) const;
+  }];
 }
 
 //===----------------------------------------------------------------------===//
@@ -2340,6 +2399,19 @@ def CIR_FuncOp : CIR_Op<"func", [
 
   let hasCustomAssemblyFormat = 1;
   let hasVerifier = 1;
+
+  let extraLLVMLoweringPatternDecl = [{
+    static mlir::StringRef getLinkageAttrNameString() { return "linkage"; }
+
+    void lowerFuncAttributes(
+        cir::FuncOp func, bool filterArgAndResAttrs,
+        mlir::SmallVectorImpl<mlir::NamedAttribute> &result) const;
+
+    mlir::LogicalResult
+    matchAndRewriteAlias(cir::FuncOp op, llvm::StringRef aliasee, mlir::Type ty,
+                         OpAdaptor adaptor,
+                         mlir::ConversionPatternRewriter &rewriter) const;
+  }];
 }
 
 //===----------------------------------------------------------------------===//
@@ -2761,6 +2833,8 @@ class CIR_ArrayInitDestroy<string mnemonic> : CIR_Op<mnemonic> {
         regionBuilder($_builder, $_state.location);
     }]>
   ];
+
+  let hasLLVMLowering = false;
 }
 
 def CIR_ArrayCtor : CIR_ArrayInitDestroy<"array.ctor"> {
@@ -3380,6 +3454,8 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [
   let assemblyFormat = [{
     $lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict
   }];
+
+  let hasLLVMLowering = false;
 }
 
 def CIR_ComplexDivOp : CIR_Op<"complex.div", [
@@ -3422,6 +3498,8 @@ def CIR_ComplexDivOp : CIR_Op<"complex.div", [
   let assemblyFormat = [{
     $lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
index 6e7f3da4add3e..870f9e3f5d052 100644
--- a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
@@ -20,6 +20,10 @@ mlir_tablegen(CIROpsAttributes.h.inc -gen-attrdef-decls)
 mlir_tablegen(CIROpsAttributes.cpp.inc -gen-attrdef-defs)
 add_public_tablegen_target(MLIRCIREnumsGen)
 
+clang_tablegen(CIRLowering.inc -gen-cir-lowering
+               SOURCE CIROps.td
+               TARGET CIRLowering)
+
 set(LLVM_TARGET_DEFINITIONS CIRTypeConstraints.td)
 mlir_tablegen(CIRTypeConstraints.h.inc -gen-type-constraint-decls)
 mlir_tablegen(CIRTypeConstraints.cpp.inc -gen-type-constraint-defs)
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 1d7e3df1430ac..e18149a61abd0 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2463,87 +2463,11 @@ void ConvertCIRToLLVMPass::runOnOperation() {
 
   mlir::RewritePatternSet patterns(&getContext());
 
-  patterns.add<CIRToLLVMReturnOpLowering>(patterns.getContext());
-  // This could currently be merged with the group below, but it will get more
-  // arguments later, so we'll keep it separate for now.
-  patterns.add<CIRToLLVMAllocaOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMLoadOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMStoreOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMCastOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMPtrStrideOpLowering>(converter, patterns.getContext(),
-                                             dl);
-  patterns.add<CIRToLLVMInlineAsmOpLowering>(converter, patterns.getContext(),
-                                             dl);
   patterns.add<
-      // clang-format off
-               CIRToLLVMACosOpLowering,
-               CIRToLLVMASinOpLowering,
-               CIRToLLVMAssumeOpLowering,
-               CIRToLLVMAssumeAlignedOpLowering,
-               CIRToLLVMAssumeSepStorageOpLowering,
-               CIRToLLVMAtomicCmpXchgLowering,
-               CIRToLLVMBaseClassAddrOpLowering,
-               CIRToLLVMATanOpLowering,
-               CIRToLLVMBinOpLowering,
-               CIRToLLVMBitClrsbOpLowering,
-               CIRToLLVMBitClzOpLowering,
-               CIRToLLVMBitCtzOpLowering,
-               CIRToLLVMBitFfsOpLowering,
-               CIRToLLVMBitParityOpLowering,
-               CIRToLLVMBitPopcountOpLowering,
-               CIRToLLVMBitReverseOpLowering,
-               CIRToLLVMBrCondOpLowering,
-               CIRToLLVMBrOpLowering,
-               CIRToLLVMByteSwapOpLowering,
-               CIRToLLVMCallOpLowering,
-               CIRToLLVMCmpOpLowering,
-               CIRToLLVMComplexAddOpLowering,
-               CIRToLLVMComplexCreateOpLowering,
-               CIRToLLVMComplexImagOpLowering,
-               CIRToLLVMComplexImagPtrOpLowering,
-               CIRToLLVMComplexRealOpLowering,
-               CIRToLLVMComplexRealPtrOpLowering,
-               CIRToLLVMComplexSubOpLowering,
-               CIRToLLVMCopyOpLowering,
-               CIRToLLVMCosOpLowering,
-               CIRToLLVMConstantOpLowering,
-               CIRToLLVMExpectOpLowering,
-               CIRToLLVMFAbsOpLowering,
-               CIRToLLVMFrameAddrOpLowering,
-               CIRToLLVMFuncOpLowering,
-               CIRToLLVMGetBitfieldOpLowering,
-               CIRToLLVMGetGlobalOpLowering,
-               CIRToLLVMGetMemberOpLowering,
-               CIRToLLVMReturnAddrOpLowering,
-               CIRToLLVMRotateOpLowering,
-               CIRToLLVMSelectOpLowering,
-               CIRToLLVMSetBitfieldOpLowering,
-               CIRToLLVMShiftOpLowering,
-               CIRToLLVMStackRestoreOpLowering,
-               CIRToLLVMStackSaveOpLowering,
-               CIRToLLVMSwitchFlatOpLowering,
-               CIRToLLVMThrowOpLowering,
-               CIRToLLVMTrapOpLowering,
-               CIRToLLVMUnaryOpLowering,
-               CIRToLLVMUnreachableOpLowering,
-               CIRToLLVMVAArgOpLowering,
-               CIRToLLVMVAEndOpLowering,
-               CIRToLLVMVAStartOpLowering,
-               CIRToLLVMVecCmpOpLowering,
-               CIRToLLVMVecCreateOpLowering,
-               CIRToLLVMVecExtractOpLowering,
-               CIRToLLVMVecInsertOpLowering,
-               CIRToLLVMVecShuffleDynamicOpLowering,
-               CIRToLLVMVecShuffleOpLowering,
-               CIRToLLVMVecSplatOpLowering,
-               CIRToLLVMVecTernaryOpLowering,
-               CIRToLLVMVTableAddrPointOpLowering,
-               CIRToLLVMVTableGetVPtrOpLowering,
-               CIRToLLVMVTableGetVirtualFnAddrOpLowering,
-               CIRToLLVMVTTAddrPointOpLowering
-      // clang-format on
-      >(converter, patterns.getContext());
+#define GET_LLVM_LOWERING_PATTERNS_LIST
+#include "clang/CIR/Dialect/IR/CIRLowering.inc"
+#undef GET_LLVM_LOWERING_PATTERNS_LIST
+      >(converter, patterns.getContext(), dl);
 
   processCIRAttrs(module);
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 09ff7a0901c69..0591de545b81d 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -34,801 +34,9 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
                               mlir::LLVM::MemoryEffectsAttr &memoryEffect,
                               bool &noUnwind, bool &willReturn);
 
-class CIRToLLVMAssumeOpLowering
-    : public mlir::OpConversionPattern<cir::AssumeOp> {
-public:
-  using mlir::OpConversionPattern<cir::AssumeOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::AssumeOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMAssumeAlignedOpLowering
-    : public mlir::OpConversionPattern<cir::AssumeAlignedOp> {
-public:
-  using mlir::OpConversionPattern<cir::AssumeAlignedOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::AssumeAlignedOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMAssumeSepStorageOpLowering
-    : public mlir::OpConversionPattern<cir::AssumeSepStorageOp> {
-public:
-  using mlir::OpConversionPattern<cir::AssumeSepStorageOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::AssumeSepStorageOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitClrsbOpLowering
-    : public mlir::OpConversionPattern<cir::BitClrsbOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitClrsbOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitClrsbOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitClzOpLowering
-    : public mlir::OpConversionPattern<cir::BitClzOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitClzOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitClzOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitCtzOpLowering
-    : public mlir::OpConversionPattern<cir::BitCtzOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitCtzOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitCtzOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitFfsOpLowering
-    : public mlir::OpConversionPattern<cir::BitFfsOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitFfsOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitFfsOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitParityOpLowering
-    : public mlir::OpConversionPattern<cir::BitParityOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitParityOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitParityOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitPopcountOpLowering
-    : public mlir::OpConversionPattern<cir::BitPopcountOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitPopcountOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitPopcountOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitReverseOpLowering
-    : public mlir::OpConversionPattern<cir::BitReverseOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitReverseOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitReverseOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMAtomicCmpXchgLowering
-    : public mlir::OpConversionPattern<cir::AtomicCmpXchg> {
-public:
-  using mlir::OpConversionPattern<cir::AtomicCmpXchg>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::AtomicCmpXchg op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBrCondOpLowering
-    : public mlir::OpConversionPattern<cir::BrCondOp> {
-public:
-  using mlir::OpConversionPattern<cir::BrCondOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BrCondOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMByteSwapOpLowering
-    : public mlir::OpConversionPattern<cir::ByteSwapOp> {
-public:
-  using mlir::OpConversionPattern<cir::ByteSwapOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::ByteSwapOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMCastOpLowering : public mlir::OpConversionPattern<cir::CastOp> {
-  mlir::DataLayout const &dataLayout;
-
-  mlir::Type convertTy(mlir::Type ty) const;
-
-public:
-  CIRToLLVMCastOpLowering(const mlir::TypeConverter &typeConverter,
-                          mlir::MLIRContext *context,
-                          mlir::DataLayout const &dataLayout)
-      : OpConversionPattern(typeConverter, context), dataLayout(dataLayout) {}
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::CastOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMCopyOpLowering : public mlir::OpConversionPattern<cir::CopyOp> {
-public:
-  using mlir::OpConversionPattern<cir::CopyOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::CopyOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMCosOpLowering : public mlir::OpConversionPattern<cir::CosOp> {
-public:
-  using mlir::OpConversionPattern<cir::CosOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::CosOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMExpectOpLowering
-    : public mlir::OpConversionPattern<cir::ExpectOp> {
-public:
-  using mlir::OpConversionPattern<cir::ExpectOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::ExpectOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMReturnOpLowering
-    : public mlir::OpConversionPattern<cir::ReturnOp> {
-public:
-  using mlir::OpConversionPattern<cir::ReturnOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::ReturnOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMRotateOpLowering
-    : public mlir::OpConversionPattern<cir::RotateOp> {
-public:
-  using mlir::OpConversionPattern<cir::RotateOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::RotateOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const overri...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Sep 17, 2025

@llvm/pr-subscribers-clangir

Author: Sirui Mu (Lancern)

Changes

Most lowering patterns have exactly the same class declaration with different names and different matchAndRewrite implementations, yet their declaration occupies near 1000 lines of code in LowerToLLVM.h, making this file difficult to read and boring to maintain. In this patch, I migrate their declarations to be generated from CIROps.td using clang-tblgen. Some extra CIR_Op TableGen fields are introduced to help this:

  • The CIR_Op class now defines a bit field hasLLVMLowering which defaults to true. If its value is true, clang-tblgen would generate an LLVM lowering pattern declaration for the operation.

  • Some LLVM lowering patterns has bounded recursion. This could be enabled by setting the isLLVMLoweringRecursive field in a CIR_Op record to true.

  • Some LLVM lowering patterns have defined additional class members. They could be listed in the extraLLVMLoweringPatternDecl field.

Note that in the incubator we have a similar TableGen code generator that generates LLVM lowering code for CIR builtin ops which has a one-to-one correspondence to LLVM dialect operations. This patch does NOT try to upstream it.

Some additional noticeable changes made by this patch:

  • This patch adds the dataLayout member to every LLVM lowering pattern class to make the job easier for a code generator. In the future we might want to add more members to the lowering patterns, and we will need to update the code generator to make such changes.

Patch is 47.18 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/159390.diff

8 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+79-1)
  • (modified) clang/include/clang/CIR/Dialect/IR/CMakeLists.txt (+4)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+4-80)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+3-795)
  • (added) clang/utils/TableGen/CIRLoweringEmitter.cpp (+125)
  • (modified) clang/utils/TableGen/CMakeLists.txt (+1)
  • (modified) clang/utils/TableGen/TableGen.cpp (+6)
  • (modified) clang/utils/TableGen/TableGenBackends.h (+1)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 38c4a87f69d6d..f80c9faf708ef 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -78,7 +78,15 @@ class LLVMLoweringInfo {
 }
 
 class CIR_Op<string mnemonic, list<Trait> traits = []> :
-    Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;
+    Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo {
+  // Should we generate an LLVM lowering pattern for this op?
+  bit hasLLVMLowering = true;
+  // Is the LLVM lowering pattern for this operation recursive?
+  bit isLLVMLoweringRecursive = false;
+  // Extra class declarations to be included in the generated LLVM lowering
+  // pattern.
+  code extraLLVMLoweringPatternDecl = "";
+}
 
 //===----------------------------------------------------------------------===//
 // CastOp
@@ -218,6 +226,10 @@ def CIR_CastOp : CIR_Op<"cast", [
   // The input and output types should match the cast kind.
   let hasVerifier = 1;
   let hasFolder = 1;
+
+  let extraLLVMLoweringPatternDecl = [{
+    mlir::Type convertTy(mlir::Type ty) const;
+  }];
 }
 
 
@@ -297,6 +309,8 @@ def CIR_ConstantOp : CIR_Op<"const", [
   }];
 
   let hasFolder = 1;
+
+  let isLLVMLoweringRecursive = true;
 }
 
 //===----------------------------------------------------------------------===//
@@ -613,6 +627,8 @@ def CIR_IfOp : CIR_Op<"if", [
       CArg<"BuilderCallbackRef", "buildTerminatedBody">:$thenBuilder,
       CArg<"BuilderCallbackRef", "nullptr">:$elseBuilder)>
   ];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -659,6 +675,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [
   let arguments = (ins CIR_BoolType:$condition);
   let assemblyFormat = " `(` $condition `)` attr-dict ";
   let hasVerifier = 1;
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -726,6 +743,8 @@ def CIR_YieldOp : CIR_Op<"yield", [
   let builders = [
     OpBuilder<(ins), [{ /* nothing to do */ }]>,
   ];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -741,6 +760,7 @@ def CIR_BreakOp : CIR_Op<"break", [Terminator]> {
   }];
   let assemblyFormat = "attr-dict";
   let hasVerifier = 1;
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -756,6 +776,7 @@ def CIR_ContinueOp : CIR_Op<"continue", [Terminator]> {
   }];
   let assemblyFormat = "attr-dict";
   let hasVerifier = 1;
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -814,6 +835,8 @@ def CIR_ScopeOp : CIR_Op<"scope", [
     // Scopes without yielding values.
     OpBuilder<(ins "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$scopeBuilder)>
   ];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -860,6 +883,8 @@ def CIR_CaseOp : CIR_Op<"case", [
                    "CaseOpKind":$kind,
                    "mlir::OpBuilder::InsertPoint &":$insertPoint)>
   ];
+
+  let hasLLVMLowering = false;
 }
 
 def CIR_SwitchOp : CIR_Op<"switch", [
@@ -1025,6 +1050,8 @@ def CIR_SwitchOp : CIR_Op<"switch", [
     // This is an expensive and need to be used with caution.
     bool isSimpleForm(llvm::SmallVectorImpl<CaseOp> &cases);
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1170,6 +1197,8 @@ def CIR_GotoOp : CIR_Op<"goto", [Terminator]> {
   }];
   let arguments = (ins StrAttr:$label);
   let assemblyFormat = [{ $label attr-dict }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1185,6 +1214,8 @@ def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> {
   let arguments = (ins StrAttr:$label);
   let assemblyFormat = [{ $label attr-dict }];
   let hasVerifier = 1;
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1349,6 +1380,8 @@ def CIR_WhileOp : CIR_WhileOpBase<"while"> {
     }
     ```
   }];
+
+  let hasLLVMLowering = false;
 }
 
 def CIR_DoWhileOp : CIR_WhileOpBase<"do"> {
@@ -1375,6 +1408,8 @@ def CIR_DoWhileOp : CIR_WhileOpBase<"do"> {
     }
     ```
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1442,6 +1477,8 @@ def CIR_ForOp : CIR_LoopOpBase<"for"> {
       return llvm::SmallVector<mlir::Region *, 3>{&getCond(), &getBody(), &getStep()};
     }
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1480,6 +1517,8 @@ def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
   let assemblyFormat = [{
     `(` $kind `,` $lhs `,` $rhs  `)` `:` type($lhs) `,` type($result) attr-dict
   }];
+
+  let isLLVMLoweringRecursive = true;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1550,6 +1589,10 @@ def CIR_BinOp : CIR_Op<"binop", [
   }];
 
   let hasVerifier = 1;
+
+  let extraLLVMLoweringPatternDecl = [{
+    mlir::LLVM::IntegerOverflowFlags getIntOverflowFlag(cir::BinOp op) const;
+  }];
 }
 
 //===----------------------------------------------------------------------===//
@@ -1687,6 +1730,8 @@ def CIR_TernaryOp : CIR_Op<"ternary", [
       `false` $falseRegion
     `)` `:` functional-type(operands, results) attr-dict
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1790,6 +1835,20 @@ def CIR_GlobalOp : CIR_Op<"global", [
     "cir::GlobalLinkageKind::ExternalLinkage">:$linkage)>];
 
   let hasVerifier = 1;
+
+  let isLLVMLoweringRecursive = true;
+  let extraLLVMLoweringPatternDecl = [{
+    mlir::LogicalResult matchAndRewriteRegionInitializedGlobal(
+      cir::GlobalOp op, mlir::Attribute init,
+      mlir::ConversionPatternRewriter &rewriter) const;
+
+    void setupRegionInitializedLLVMGlobalOp(
+        cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const;
+
+    mutable mlir::LLVM::ComdatOp comdatOp = nullptr;
+    mlir::SymbolRefAttr getComdatAttr(cir::GlobalOp &op,
+                                      mlir::OpBuilder &builder) const;
+  }];
 }
 
 //===----------------------------------------------------------------------===//
@@ -2340,6 +2399,19 @@ def CIR_FuncOp : CIR_Op<"func", [
 
   let hasCustomAssemblyFormat = 1;
   let hasVerifier = 1;
+
+  let extraLLVMLoweringPatternDecl = [{
+    static mlir::StringRef getLinkageAttrNameString() { return "linkage"; }
+
+    void lowerFuncAttributes(
+        cir::FuncOp func, bool filterArgAndResAttrs,
+        mlir::SmallVectorImpl<mlir::NamedAttribute> &result) const;
+
+    mlir::LogicalResult
+    matchAndRewriteAlias(cir::FuncOp op, llvm::StringRef aliasee, mlir::Type ty,
+                         OpAdaptor adaptor,
+                         mlir::ConversionPatternRewriter &rewriter) const;
+  }];
 }
 
 //===----------------------------------------------------------------------===//
@@ -2761,6 +2833,8 @@ class CIR_ArrayInitDestroy<string mnemonic> : CIR_Op<mnemonic> {
         regionBuilder($_builder, $_state.location);
     }]>
   ];
+
+  let hasLLVMLowering = false;
 }
 
 def CIR_ArrayCtor : CIR_ArrayInitDestroy<"array.ctor"> {
@@ -3380,6 +3454,8 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [
   let assemblyFormat = [{
     $lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict
   }];
+
+  let hasLLVMLowering = false;
 }
 
 def CIR_ComplexDivOp : CIR_Op<"complex.div", [
@@ -3422,6 +3498,8 @@ def CIR_ComplexDivOp : CIR_Op<"complex.div", [
   let assemblyFormat = [{
     $lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict
   }];
+
+  let hasLLVMLowering = false;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
index 6e7f3da4add3e..870f9e3f5d052 100644
--- a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
@@ -20,6 +20,10 @@ mlir_tablegen(CIROpsAttributes.h.inc -gen-attrdef-decls)
 mlir_tablegen(CIROpsAttributes.cpp.inc -gen-attrdef-defs)
 add_public_tablegen_target(MLIRCIREnumsGen)
 
+clang_tablegen(CIRLowering.inc -gen-cir-lowering
+               SOURCE CIROps.td
+               TARGET CIRLowering)
+
 set(LLVM_TARGET_DEFINITIONS CIRTypeConstraints.td)
 mlir_tablegen(CIRTypeConstraints.h.inc -gen-type-constraint-decls)
 mlir_tablegen(CIRTypeConstraints.cpp.inc -gen-type-constraint-defs)
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 1d7e3df1430ac..e18149a61abd0 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2463,87 +2463,11 @@ void ConvertCIRToLLVMPass::runOnOperation() {
 
   mlir::RewritePatternSet patterns(&getContext());
 
-  patterns.add<CIRToLLVMReturnOpLowering>(patterns.getContext());
-  // This could currently be merged with the group below, but it will get more
-  // arguments later, so we'll keep it separate for now.
-  patterns.add<CIRToLLVMAllocaOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMLoadOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMStoreOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMCastOpLowering>(converter, patterns.getContext(), dl);
-  patterns.add<CIRToLLVMPtrStrideOpLowering>(converter, patterns.getContext(),
-                                             dl);
-  patterns.add<CIRToLLVMInlineAsmOpLowering>(converter, patterns.getContext(),
-                                             dl);
   patterns.add<
-      // clang-format off
-               CIRToLLVMACosOpLowering,
-               CIRToLLVMASinOpLowering,
-               CIRToLLVMAssumeOpLowering,
-               CIRToLLVMAssumeAlignedOpLowering,
-               CIRToLLVMAssumeSepStorageOpLowering,
-               CIRToLLVMAtomicCmpXchgLowering,
-               CIRToLLVMBaseClassAddrOpLowering,
-               CIRToLLVMATanOpLowering,
-               CIRToLLVMBinOpLowering,
-               CIRToLLVMBitClrsbOpLowering,
-               CIRToLLVMBitClzOpLowering,
-               CIRToLLVMBitCtzOpLowering,
-               CIRToLLVMBitFfsOpLowering,
-               CIRToLLVMBitParityOpLowering,
-               CIRToLLVMBitPopcountOpLowering,
-               CIRToLLVMBitReverseOpLowering,
-               CIRToLLVMBrCondOpLowering,
-               CIRToLLVMBrOpLowering,
-               CIRToLLVMByteSwapOpLowering,
-               CIRToLLVMCallOpLowering,
-               CIRToLLVMCmpOpLowering,
-               CIRToLLVMComplexAddOpLowering,
-               CIRToLLVMComplexCreateOpLowering,
-               CIRToLLVMComplexImagOpLowering,
-               CIRToLLVMComplexImagPtrOpLowering,
-               CIRToLLVMComplexRealOpLowering,
-               CIRToLLVMComplexRealPtrOpLowering,
-               CIRToLLVMComplexSubOpLowering,
-               CIRToLLVMCopyOpLowering,
-               CIRToLLVMCosOpLowering,
-               CIRToLLVMConstantOpLowering,
-               CIRToLLVMExpectOpLowering,
-               CIRToLLVMFAbsOpLowering,
-               CIRToLLVMFrameAddrOpLowering,
-               CIRToLLVMFuncOpLowering,
-               CIRToLLVMGetBitfieldOpLowering,
-               CIRToLLVMGetGlobalOpLowering,
-               CIRToLLVMGetMemberOpLowering,
-               CIRToLLVMReturnAddrOpLowering,
-               CIRToLLVMRotateOpLowering,
-               CIRToLLVMSelectOpLowering,
-               CIRToLLVMSetBitfieldOpLowering,
-               CIRToLLVMShiftOpLowering,
-               CIRToLLVMStackRestoreOpLowering,
-               CIRToLLVMStackSaveOpLowering,
-               CIRToLLVMSwitchFlatOpLowering,
-               CIRToLLVMThrowOpLowering,
-               CIRToLLVMTrapOpLowering,
-               CIRToLLVMUnaryOpLowering,
-               CIRToLLVMUnreachableOpLowering,
-               CIRToLLVMVAArgOpLowering,
-               CIRToLLVMVAEndOpLowering,
-               CIRToLLVMVAStartOpLowering,
-               CIRToLLVMVecCmpOpLowering,
-               CIRToLLVMVecCreateOpLowering,
-               CIRToLLVMVecExtractOpLowering,
-               CIRToLLVMVecInsertOpLowering,
-               CIRToLLVMVecShuffleDynamicOpLowering,
-               CIRToLLVMVecShuffleOpLowering,
-               CIRToLLVMVecSplatOpLowering,
-               CIRToLLVMVecTernaryOpLowering,
-               CIRToLLVMVTableAddrPointOpLowering,
-               CIRToLLVMVTableGetVPtrOpLowering,
-               CIRToLLVMVTableGetVirtualFnAddrOpLowering,
-               CIRToLLVMVTTAddrPointOpLowering
-      // clang-format on
-      >(converter, patterns.getContext());
+#define GET_LLVM_LOWERING_PATTERNS_LIST
+#include "clang/CIR/Dialect/IR/CIRLowering.inc"
+#undef GET_LLVM_LOWERING_PATTERNS_LIST
+      >(converter, patterns.getContext(), dl);
 
   processCIRAttrs(module);
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 09ff7a0901c69..0591de545b81d 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -34,801 +34,9 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
                               mlir::LLVM::MemoryEffectsAttr &memoryEffect,
                               bool &noUnwind, bool &willReturn);
 
-class CIRToLLVMAssumeOpLowering
-    : public mlir::OpConversionPattern<cir::AssumeOp> {
-public:
-  using mlir::OpConversionPattern<cir::AssumeOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::AssumeOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMAssumeAlignedOpLowering
-    : public mlir::OpConversionPattern<cir::AssumeAlignedOp> {
-public:
-  using mlir::OpConversionPattern<cir::AssumeAlignedOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::AssumeAlignedOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMAssumeSepStorageOpLowering
-    : public mlir::OpConversionPattern<cir::AssumeSepStorageOp> {
-public:
-  using mlir::OpConversionPattern<cir::AssumeSepStorageOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::AssumeSepStorageOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitClrsbOpLowering
-    : public mlir::OpConversionPattern<cir::BitClrsbOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitClrsbOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitClrsbOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitClzOpLowering
-    : public mlir::OpConversionPattern<cir::BitClzOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitClzOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitClzOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitCtzOpLowering
-    : public mlir::OpConversionPattern<cir::BitCtzOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitCtzOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitCtzOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitFfsOpLowering
-    : public mlir::OpConversionPattern<cir::BitFfsOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitFfsOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitFfsOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitParityOpLowering
-    : public mlir::OpConversionPattern<cir::BitParityOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitParityOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitParityOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitPopcountOpLowering
-    : public mlir::OpConversionPattern<cir::BitPopcountOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitPopcountOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitPopcountOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBitReverseOpLowering
-    : public mlir::OpConversionPattern<cir::BitReverseOp> {
-public:
-  using mlir::OpConversionPattern<cir::BitReverseOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BitReverseOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMAtomicCmpXchgLowering
-    : public mlir::OpConversionPattern<cir::AtomicCmpXchg> {
-public:
-  using mlir::OpConversionPattern<cir::AtomicCmpXchg>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::AtomicCmpXchg op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMBrCondOpLowering
-    : public mlir::OpConversionPattern<cir::BrCondOp> {
-public:
-  using mlir::OpConversionPattern<cir::BrCondOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::BrCondOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMByteSwapOpLowering
-    : public mlir::OpConversionPattern<cir::ByteSwapOp> {
-public:
-  using mlir::OpConversionPattern<cir::ByteSwapOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::ByteSwapOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMCastOpLowering : public mlir::OpConversionPattern<cir::CastOp> {
-  mlir::DataLayout const &dataLayout;
-
-  mlir::Type convertTy(mlir::Type ty) const;
-
-public:
-  CIRToLLVMCastOpLowering(const mlir::TypeConverter &typeConverter,
-                          mlir::MLIRContext *context,
-                          mlir::DataLayout const &dataLayout)
-      : OpConversionPattern(typeConverter, context), dataLayout(dataLayout) {}
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::CastOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMCopyOpLowering : public mlir::OpConversionPattern<cir::CopyOp> {
-public:
-  using mlir::OpConversionPattern<cir::CopyOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::CopyOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMCosOpLowering : public mlir::OpConversionPattern<cir::CosOp> {
-public:
-  using mlir::OpConversionPattern<cir::CosOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::CosOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMExpectOpLowering
-    : public mlir::OpConversionPattern<cir::ExpectOp> {
-public:
-  using mlir::OpConversionPattern<cir::ExpectOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::ExpectOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMReturnOpLowering
-    : public mlir::OpConversionPattern<cir::ReturnOp> {
-public:
-  using mlir::OpConversionPattern<cir::ReturnOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::ReturnOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMRotateOpLowering
-    : public mlir::OpConversionPattern<cir::RotateOp> {
-public:
-  using mlir::OpConversionPattern<cir::RotateOp>::OpConversionPattern;
-
-  mlir::LogicalResult
-  matchAndRewrite(cir::RotateOp op, OpAdaptor,
-                  mlir::ConversionPatternRewriter &) const overri...
[truncated]

Most lowering patterns have exactly the same class declaration with different
names and different `matchAndRewrite` implementations, yet their declaration
occupies near 1000 lines of code in `LowerToLLVM.h`, making this file difficult
to read and boring to maintain. In this patch, I migrate their declarations to
be generated from `CIROps.td` using `clang-tblgen`. Some extra `CIR_Op` TableGen
fields are introduced to help this:

  - The `CIR_Op` class now defines a `bit` field `hasLLVMLowering` which
    defaults to `true`. If its value is `true`, `clang-tblgen` would generate an
    LLVM lowering pattern declaration for the operation.

  - Some LLVM lowering patterns has bounded recursion. This could be enabled by
    setting the `isLLVMLoweringRecursive` field in a `CIR_Op` record to `true`.

  - Some LLVM lowering patterns have defined additional class members. They
    could be listed in the `extraLLVMLoweringPatternDecl` field.

Note that in the incubator we have a similar TableGen code generator that
generates LLVM lowering code for CIR builtin ops which has a one-to-one
correspondence to LLVM dialect operations. This patch does NOT try to upstream
it.

Some additional noticeable changes made by this patch:

  - This patch adds the `dataLayout` member to every LLVM lowering pattern class
    to make the job easier for a code generator. In the future we might want to
    add more members to the lowering patterns, and we will need to update the
    code generator to make such changes.
@Lancern Lancern force-pushed the cir/tablegen-cir-lowering branch from 63db52b to b44f246 Compare September 17, 2025 16:14
Copy link
Member

@bcardosolopes bcardosolopes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty cool, thanks. Any chance we could get it backported to incubator?

@Lancern
Copy link
Member Author

Lancern commented Sep 18, 2025

Any chance we could get it backported to incubator?

Yes, I'll backport it once this patch gets merged.

@Lancern Lancern merged commit 81aaca3 into llvm:main Sep 18, 2025
9 checks passed
@Lancern Lancern deleted the cir/tablegen-cir-lowering branch September 18, 2025 13:43
@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 18, 2025

LLVM Buildbot has detected a new failure on builder clang-aarch64-sve2-vla running on linaro-g4-02 while building clang at step 7 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/198/builds/7968

Here is the relevant piece of the build log for the reference
Step 7 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'SanitizerCommon-tsan-aarch64-Linux :: compress_stack_depot.cpp' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
/home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/./bin/clang  --driver-mode=g++ -gline-tables-only -fsanitize=thread   -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta  -funwind-tables  -I/home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test -ldl /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp -fsanitize-memory-track-origins=1 -o /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp # RUN: at line 1
+ /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/./bin/clang --driver-mode=g++ -gline-tables-only -fsanitize=thread -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta -funwind-tables -I/home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test -ldl /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp -fsanitize-memory-track-origins=1 -o /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp
clang: warning: argument unused during compilation: '-fsanitize-memory-track-origins=1' [-Wunused-command-line-argument]
env TSAN_OPTIONS="compress_stack_depot=0:malloc_context_size=128:verbosity=1"  /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp 2>&1 | FileCheck /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp --implicit-check-not="StackDepot released" # RUN: at line 2
+ env TSAN_OPTIONS=compress_stack_depot=0:malloc_context_size=128:verbosity=1 /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp
+ FileCheck /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp '--implicit-check-not=StackDepot released'
env TSAN_OPTIONS="compress_stack_depot=-1:malloc_context_size=128:verbosity=1"  /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp 2>&1 | FileCheck /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp --check-prefixes=COMPRESS # RUN: at line 3
+ FileCheck /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp --check-prefixes=COMPRESS
+ env TSAN_OPTIONS=compress_stack_depot=-1:malloc_context_size=128:verbosity=1 /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp
env TSAN_OPTIONS="compress_stack_depot=-2:malloc_context_size=128:verbosity=1"  /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp 2>&1 | FileCheck /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp --check-prefixes=COMPRESS # RUN: at line 4
+ env TSAN_OPTIONS=compress_stack_depot=-2:malloc_context_size=128:verbosity=1 /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp
+ FileCheck /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp --check-prefixes=COMPRESS
env TSAN_OPTIONS="compress_stack_depot=1:malloc_context_size=128:verbosity=1"  /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp 2>&1 | FileCheck /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp --check-prefixes=COMPRESS,THREAD # RUN: at line 5
+ FileCheck /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp --check-prefixes=COMPRESS,THREAD
+ env TSAN_OPTIONS=compress_stack_depot=1:malloc_context_size=128:verbosity=1 /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/stage1/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/tsan-aarch64-Linux/Output/compress_stack_depot.cpp.tmp
/home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp:53:14: error: COMPRESS: expected string not found in input
// COMPRESS: StackDepot released {{[0-9]+}}
             ^
<stdin>:8:55: note: scanning from here
ThreadSanitizer: StackDepot compression thread started
                                                      ^
<stdin>:9:18: note: possible intended match here
ThreadSanitizer: StackDepot compression thread stopped
                 ^

Input file: <stdin>
Check file: /home/tcwg-buildbot/worker/clang-aarch64-sve2-vla/llvm/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: ==3074168==WARNING: ThreadSanitizer: memory layout is incompatible, possibly due to high-entropy ASLR. 
            2: Re-execing with fixed virtual address space. 
            3: N.B. reducing ASLR entropy is preferable. 
            4: ==3074168==Installed the sigaction for signal 11 
            5: ==3074168==Installed the sigaction for signal 7 
            6: ==3074168==Installed the sigaction for signal 8 
            7: ***** Running under ThreadSanitizer v3 (pid 3074168) ***** 
            8: ThreadSanitizer: StackDepot compression thread started 
check:53'0                                                           X error: no match found
            9: ThreadSanitizer: StackDepot compression thread stopped 
check:53'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:53'1                      ?                                      possible intended match
           10: Stats: LargeMmapAllocator: allocated 0 times, remains 0 (0 K) max 0 M; by size logs:  
...

@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 18, 2025

LLVM Buildbot has detected a new failure on builder lldb-aarch64-windows running on linaro-armv8-windows-msvc-05 while building clang at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/141/builds/11628

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: functionalities/recursion/TestValueObjectRecursion.py (603 of 2306)
PASS: lldb-api :: functionalities/reverse-execution/TestReverseContinueWatchpoints.py (604 of 2306)
PASS: lldb-api :: functionalities/reverse-execution/TestReverseExecutionNotSupported.py (605 of 2306)
UNSUPPORTED: lldb-api :: functionalities/scripted_process/TestScriptedProcess.py (606 of 2306)
UNSUPPORTED: lldb-api :: functionalities/scripted_process/TestStackCoreScriptedProcess.py (607 of 2306)
UNSUPPORTED: lldb-api :: functionalities/scripted_process_empty_memory_region/TestScriptedProcessEmptyMemoryRegion.py (608 of 2306)
UNSUPPORTED: lldb-api :: functionalities/set-data/TestSetData.py (609 of 2306)
PASS: lldb-api :: functionalities/show_location/TestShowLocationDwarf5.py (610 of 2306)
UNSUPPORTED: lldb-api :: functionalities/signal/TestSendSignal.py (611 of 2306)
UNSUPPORTED: lldb-api :: functionalities/signal/handle-abrt/TestHandleAbort.py (612 of 2306)
FAIL: lldb-api :: functionalities/reverse-execution/TestReverseContinueBreakpoints.py (613 of 2306)
******************** TEST 'lldb-api :: functionalities/reverse-execution/TestReverseContinueBreakpoints.py' FAILED ********************
Script:
--
C:/Users/tcwg/scoop/apps/python/current/python.exe C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/llvm-project/lldb\test\API\dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/./lib --env LLVM_INCLUDE_DIR=C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/include --env LLVM_TOOLS_DIR=C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/./bin --arch aarch64 --build-dir C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/lldb-test-build.noindex --lldb-module-cache-dir C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/lldb-test-build.noindex/module-cache-lldb\lldb-api --clang-module-cache-dir C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/lldb-test-build.noindex/module-cache-clang\lldb-api --executable C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/./bin/lldb.exe --compiler C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/./bin/clang.exe --dsymutil C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/./bin/dsymutil.exe --make C:/Users/tcwg/scoop/shims/make.exe --llvm-tools-dir C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/./bin --lldb-obj-root C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/tools/lldb --lldb-libs-dir C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/./lib --cmake-build-type Release --skip-category=watchpoint C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\lldb\test\API\functionalities\reverse-execution -p TestReverseContinueBreakpoints.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 22.0.0git (https://github.com/llvm/llvm-project.git revision 81aaca359b2d5a6529d9620fa4181c4d89c83c7c)
  clang revision 81aaca359b2d5a6529d9620fa4181c4d89c83c7c
  llvm revision 81aaca359b2d5a6529d9620fa4181c4d89c83c7c
Skipping the following test categories: ['watchpoint', 'libc++', 'libstdcxx', 'dwo', 'dsym', 'gmodules', 'debugserver', 'objc', 'fork', 'pexpect']

An exception happened when receiving the response from the gdb server. Closing the client...


--
Command Output (stderr):
--
lldb-server exiting...

PASS: LLDB (C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\bin\clang.exe-aarch64) :: test_continue_preserves_direction (TestReverseContinueBreakpoints.TestReverseContinueBreakpoints.test_continue_preserves_direction)

lldb-server exiting...

PASS: LLDB (C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\bin\clang.exe-aarch64) :: test_continue_preserves_direction_asyhc (TestReverseContinueBreakpoints.TestReverseContinueBreakpoints.test_continue_preserves_direction_asyhc)

lldb-server exiting...

PASS: LLDB (C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\bin\clang.exe-aarch64) :: test_reverse_continue (TestReverseContinueBreakpoints.TestReverseContinueBreakpoints.test_reverse_continue)

lldb-server exiting...

PASS: LLDB (C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\bin\clang.exe-aarch64) :: test_reverse_continue_async (TestReverseContinueBreakpoints.TestReverseContinueBreakpoints.test_reverse_continue_async)

lldb-server exiting...


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants