[llvm-branch-commits] [clang] [CIR] Hoist genSpecializedAttr into the CIR enum base classes (PR #220889)

Henrich Lauko via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Sep 3 05:46:03 PDT 2026


https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/220889

>From ad4e58a3a38ebf2fb021ae72d2aaae2a18cef729 Mon Sep 17 00:00:00 2001
From: Henrich Lauko <hlauko at nvidia.com>
Date: Thu, 3 Sep 2026 12:44:31 +0000
Subject: [PATCH] [CIR] Hoist genSpecializedAttr into the CIR enum base classes

All 33 CIR enum definitions set `genSpecializedAttr = 0`, and none wanted the
generated IntegerAttr subclass. That made the line pure repetition, and made
"a CIR enum is never backed by IntegerAttr" a convention each new enum had to
remember rather than something the dialect enforces.

Set it once on CIR_I32EnumAttr, CIR_I64EnumAttr and CIR_I32BitEnumAttr,
beside the cppNamespace they already fix, and drop all 33 copies. This is the
same structure SPIRV_I32Enum, Tosa_I32Enum, GPU_I32Enum and OpenMP's enum
base class use.

NFC: no generated attribute, mnemonic or assembly format changes.
---
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  | 43 +++---------
 .../clang/CIR/Dialect/IR/CIRCUDAAttrs.td      |  4 +-
 .../clang/CIR/Dialect/IR/CIREnumAttr.td       |  8 ++-
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 66 +++++--------------
 .../include/clang/CIR/Dialect/IR/CIRTypes.td  |  2 -
 5 files changed, 33 insertions(+), 90 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 2052ddeb577d9..ae288626c732f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -82,11 +82,7 @@ def CIR_SourceLanguage : CIR_I32EnumAttr<"SourceLanguage", "source language", [
   I32EnumAttrCase<"CXX", 2, "cxx">,
   I32EnumAttrCase<"OpenCLC", 3, "opencl_c">,
   I32EnumAttrCase<"OpenCLCXX", 4, "opencl_cxx">
-]> {
-  // The enum attr class is defined in `CIR_SourceLanguageAttr` below,
-  // so that it can define extra class methods.
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_SourceLanguageAttr : CIR_EnumAttr<CIR_SourceLanguage, "lang"> {
 
@@ -127,9 +123,7 @@ def CIR_ArgPassingKind : CIR_I32EnumAttr<
   I32EnumAttrCase<"CanPassInRegs", 0, "can_pass_in_regs">,
   I32EnumAttrCase<"CannotPassInRegs", 1, "cannot_pass_in_regs">,
   I32EnumAttrCase<"CanNeverPassInRegs", 2, "can_never_pass_in_regs">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_RecordLayoutAttr : CIR_Attr<"RecordLayout", "record_layout", [
     // record_align is consumed as an llvm::Align, whose constructor asserts a
@@ -736,9 +730,7 @@ def CIR_CmpOrdering : CIR_I32EnumAttr<
     I32EnumAttrCase<"Strong", 0, "strong">,
     I32EnumAttrCase<"Weak", 1, "weak">,
     I32EnumAttrCase<"Partial", 2, "partial">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
   let summary = "Holds information about a three-way comparison operation";
@@ -829,7 +821,6 @@ def CIR_FPDynamicRoundingMode : CIR_I32EnumAttr<
     If the actual dynamic rounding mode differs from this value, the behavior
     is undefined.
   }];
-  let genSpecializedAttr = 0;
 }
 
 def CIR_FPExceptionMode : CIR_I32EnumAttr<
@@ -843,7 +834,6 @@ def CIR_FPExceptionMode : CIR_I32EnumAttr<
     executed. If the actual exception mode differs from this value, the
     behavior is undefined.
   }];
-  let genSpecializedAttr = 0;
 }
 
 def CIR_FenvAttr : CIR_Attr<"Fenv", "fenv"> {
@@ -1296,9 +1286,7 @@ def CIR_VisibilityKind : CIR_I32EnumAttr<"VisibilityKind", "C/C++ visibility", [
   I32EnumAttrCase<"Default", 0, "default">,
   I32EnumAttrCase<"Hidden", 1, "hidden">,
   I32EnumAttrCase<"Protected", 2, "protected">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 //===----------------------------------------------------------------------===//
 // GloblCtorAttr
@@ -1363,9 +1351,7 @@ def CIR_CtorKind : CIR_I32EnumAttr<"CtorKind", "CXX Constructor Kind", [
   I32EnumAttrCase<"Default", 1, "default">,
   I32EnumAttrCase<"Copy", 2, "copy">,
   I32EnumAttrCase<"Move", 3, "move">,
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_CXXCtorAttr : CIR_Attr<"CXXCtor", "cxx_ctor"> {
   let summary = "Marks a function as a C++ constructor";
@@ -1429,9 +1415,7 @@ def CIR_CXXDtorAttr : CIR_Attr<"CXXDtor", "cxx_dtor"> {
 def CIR_AssignKind : CIR_I32EnumAttr<"AssignKind", "CXX Assignment Operator Kind", [
   I32EnumAttrCase<"Copy", 0, "copy">,
   I32EnumAttrCase<"Move", 1, "move">,
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_CXXAssignAttr : CIR_Attr<"CXXAssign", "cxx_assign"> {
   let summary = "Marks a function as a CXX assignment operator";
@@ -1471,7 +1455,6 @@ def CIR_KnownFuncKind : CIR_I32EnumAttr<"KnownFuncKind",
     "known standard library entity", [
   I32EnumAttrCase<"StdFind", 1, "std::find">,
 ]> {
-  let genSpecializedAttr = 0;
   // A name like std::find is not a bare identifier, so print it as a quoted
   // string. The enum parser already reads a quoted string back.
   let parameterPrinter =
@@ -1701,9 +1684,7 @@ def CIR_InlineKind : CIR_I32EnumAttr<"InlineKind", "inlineKind", [
   I32EnumAttrCase<"NoInline", 1, "no_inline">,
   I32EnumAttrCase<"AlwaysInline", 2, "always_inline">,
   I32EnumAttrCase<"InlineHint", 3, "inline_hint">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_InlineKindAttr: CIR_EnumAttr<CIR_InlineKind, "inline_kind"> {
   let summary = "Inline kind attribute";
@@ -1840,8 +1821,6 @@ def CIR_SideEffect : CIR_I32EnumAttr<
     %2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i side_effect(const)
     ```
   }];
-
-  let genSpecializedAttr = 0;
 }
 
 def CIR_SideEffectAttr : CIR_EnumAttr<CIR_SideEffect, "side_effect">;
@@ -2003,9 +1982,7 @@ def CIR_TLSKind : CIR_I32EnumAttr<"TLSKind", "thread-local storage kind", [
   I32EnumAttrCase<"None", 0, "none">,          // clang::VarDecl::TLS_None
   I32EnumAttrCase<"Static", 1, "static">,      // clang::VarDecl::TLS_Static
   I32EnumAttrCase<"Dynamic", 2, "dynamic">     // clang::VarDecl::TLS_Dynamic
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 // CIR-native template-specialization kind. Cases mirror
 // clang::TemplateSpecializationKind.
@@ -2024,9 +2001,7 @@ def CIR_TemplateSpecializationKind
   // clang::TSK_ExplicitInstantiationDefinition
   I32EnumAttrCase<"ExplicitInstantiationDefinition", 4,
                   "explicit_instantiation_definition">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_StaticLocalInfoAttr
     : CIR_Attr<"StaticLocalInfo", "static_local_info"> {
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td
index 2d5f70ec9c3ad..3362ff1812e34 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td
@@ -75,9 +75,7 @@ def CIR_CUDADeviceVarKind : CIR_I32EnumAttr<"CUDADeviceVarKind",
   I32EnumAttrCase<"Variable", 0>,
   I32EnumAttrCase<"Surface", 1>,   // Future
   I32EnumAttrCase<"Texture", 2>,   // Future
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 // Attribute carrying device variable registration flags
 def CIR_CUDAVarRegistrationInfoAttr : CIR_Attr<"CUDAVarRegistrationInfo", "cu.var_registration"> {
diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index 8d436e5d9b62c..22cc0e6e4b7a6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -16,20 +16,27 @@
 include "mlir/IR/EnumAttr.td"
 include "clang/CIR/Dialect/IR/CIRDialect.td"
 
+// A CIR enum is never backed by an `IntegerAttr`: it either gets a
+// `CIR_EnumAttr` wrapper below, or it is used as a raw parameter of some other
+// attribute. Clearing genSpecializedAttr here rather than per enum means a new
+// enum cannot forget to.
 class CIR_I32EnumAttr<string name, string summary, list<I32EnumAttrCase> cases>
     : I32EnumAttr<name, summary, cases> {
   let cppNamespace = "::cir";
+  let genSpecializedAttr = 0;
 }
 
 class CIR_I64EnumAttr<string name, string summary, list<I64EnumAttrCase> cases>
     : I64EnumAttr<name, summary, cases> {
   let cppNamespace = "::cir";
+  let genSpecializedAttr = 0;
 }
 
 class CIR_I32BitEnumAttr<string name, string summary,
                          list<BitEnumCaseBase> cases>
     : I32BitEnumAttr<name, summary, cases> {
   let cppNamespace = "::cir";
+  let genSpecializedAttr = 0;
 }
 
 // Unlike the upstream `EnumAttr`, which defaults to a bare `$value`, CIR enum
@@ -70,7 +77,6 @@ def CIR_LangAddressSpace : CIR_I32EnumAttr<
     OpenCL `__local`) before target lowering.
   }];
 
-  let genSpecializedAttr = 0;
 }
 
 #endif // CLANG_CIR_DIALECT_IR_CIRENUMATTR_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4fe1c5a696e1d..5d2b2da4a404d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -242,9 +242,7 @@ def CIR_CastKind : CIR_I32EnumAttr<"CastKind", "cast kind", [
   // Enums below are specific to CIR and don't have a correspondence to classic
   // codegen:
   I32EnumAttrCase<"bool_to_float", 1000>,
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_CastKindAttr : CIR_EnumAttr<CIR_CastKind, "cast">;
 
@@ -399,9 +397,7 @@ def CIR_DynamicCastKind : CIR_I32EnumAttr<
   "DynamicCastKind", "dynamic cast kind", [
     I32EnumAttrCase<"Ptr", 0, "ptr">,
     I32EnumAttrCase<"Ref", 1, "ref">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_DynamicCastKindAttr
     : CIR_EnumAttr<CIR_DynamicCastKind, "dynamic_cast">;
@@ -642,9 +638,7 @@ def CIR_MemOrder : CIR_I32EnumAttr<
     I32EnumAttrCase<"Release", 3, "release">,
     I32EnumAttrCase<"AcquireRelease", 4, "acq_rel">,
     I32EnumAttrCase<"SequentiallyConsistent", 5, "seq_cst">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_MemOrderAttr : CIR_EnumAttr<CIR_MemOrder, "mem_order">;
 
@@ -673,9 +667,7 @@ def CIR_SyncScopeKind : CIR_I32EnumAttr<"SyncScopeKind", "sync scope kind", [
   I32EnumAttrCase<"OpenCLDevice", 13, "opencl_device">,
   I32EnumAttrCase<"OpenCLAllSVMDevices", 14, "opencl_all_svm_devices">,
   I32EnumAttrCase<"OpenCLSubGroup", 15, "opencl_sub_group">,
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_SyncScopeKindAttr : CIR_EnumAttr<CIR_SyncScopeKind, "sync_scope">;
 
@@ -1358,9 +1350,7 @@ def CIR_CleanupKind : CIR_I32EnumAttr<"CleanupKind", "cleanup kind", [
   I32EnumAttrCase<"Normal", 1, "normal">,
   I32EnumAttrCase<"EH", 2, "eh">,
   I32EnumAttrCase<"All", 3, "all">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_CleanupKindAttr : CIR_EnumAttr<CIR_CleanupKind, "cleanup"> {
   let summary = "Cleanup kind attribute";
@@ -1530,9 +1520,7 @@ def CIR_CaseOpKind : CIR_I32EnumAttr<"CaseOpKind", "case kind", [
   I32EnumAttrCase<"Equal", 1, "equal">,
   I32EnumAttrCase<"Anyof", 2, "anyof">,
   I32EnumAttrCase<"Range", 3, "range">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_CaseOpKindAttr : CIR_EnumAttr<CIR_CaseOpKind, "case">;
 
@@ -2544,9 +2532,7 @@ def CIR_CmpOpKind : CIR_I32EnumAttr<"CmpOpKind", "compare operation kind", [
   I32EnumAttrCase<"ne", 5>,
   I32EnumAttrCase<"one", 6>,
   I32EnumAttrCase<"uno", 7>
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_CmpOpKindAttr : CIR_EnumAttr<CIR_CmpOpKind, "cmp">;
 
@@ -3333,9 +3319,7 @@ def CIR_GlobalLinkageKind : CIR_I32EnumAttr<
     I32EnumAttrCase<"ExternalWeakLinkage", 9, "extern_weak">,
     // Tentative definitions.
     I32EnumAttrCase<"CommonLinkage", 10, "common">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_GlobalLinkageKindAttr
     : CIR_EnumAttr<CIR_GlobalLinkageKind, "linkage">;
@@ -3349,9 +3333,7 @@ def CIR_TLSModel : CIR_I32EnumAttr<"TLSModel", "TLS model", [
   I32EnumAttrCase<"LocalDynamic", 2, "tls_local_dyn">,
   I32EnumAttrCase<"InitialExec", 3, "tls_init_exec">,
   I32EnumAttrCase<"LocalExec", 4, "tls_local_exec">
-  ]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_TLSModelAttr: CIR_EnumAttr<CIR_TLSModel, "tls_model"> {
   let summary = "TLS Model attribute";
@@ -4196,9 +4178,7 @@ def CIR_CallingConv : CIR_I32EnumAttr<"CallingConv", "calling convention", [
   I32EnumAttrCase<"SpirFunction", 2, "spir_function">,
   I32EnumAttrCase<"SpirKernel", 3, "spir_kernel">,
   I32EnumAttrCase<"AMDGPUKernel", 4, "amdgpu_kernel">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_CallingConvAttr : CIR_EnumAttr<CIR_CallingConv, "calling_conv">;
 
@@ -4753,9 +4733,7 @@ def CIR_AwaitKind : CIR_I32EnumAttr<"AwaitKind", "await kind", [
   I32EnumAttrCase<"User", 1, "user">,
   I32EnumAttrCase<"Yield", 2, "yield">,
   I32EnumAttrCase<"Final", 3, "final">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_AwaitKindAttr : CIR_EnumAttr<CIR_AwaitKind, "await">;
 
@@ -5423,9 +5401,7 @@ def CIR_LifetimeEndOp : CIR_Op<"lifetime.end"> {
 
 def CIR_AsmFlavor : CIR_I32EnumAttr<"AsmFlavor", "ATT or Intel",
                                     [I32EnumAttrCase<"x86_att", 0>,
-                                     I32EnumAttrCase<"x86_intel", 1>]> {
-  let genSpecializedAttr = 0;
-}
+                                     I32EnumAttrCase<"x86_intel", 1>]>;
 
 def CIR_AsmFlavorAttr : CIR_EnumAttr<CIR_AsmFlavor, "asm_flavor">;
 
@@ -6545,9 +6521,7 @@ def CIR_ComplexRangeKind : CIR_I32EnumAttr<
     I32EnumAttrCase<"Improved", 1, "improved">,
     I32EnumAttrCase<"Promoted", 2, "promoted">,
     I32EnumAttrCase<"Basic", 3, "basic">,
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_ComplexRangeKindAttr
     : CIR_EnumAttr<CIR_ComplexRangeKind, "complex_range">;
@@ -6961,8 +6935,6 @@ def FPClassTestEnum
   // off, together with the `enum` directive on cir.is_fp_class, gets a
   // separator-aware parser and printer that spell every value unquoted.
   let printBitEnumQuoted = 0;
-
-  let genSpecializedAttr = 0;
 }
 
 def CIR_FPClassTestAttr : CIR_EnumAttr<FPClassTestEnum, "fp_class">;
@@ -7010,9 +6982,7 @@ def CIR_AssumeBundleKind : CIR_I32EnumAttr<
   I32EnumAttrCase<"Align", 1, "align">,
   I32EnumAttrCase<"SeparateStorage", 2, "separate_storage">,
   I32EnumAttrCase<"Dereferenceable", 3, "dereferenceable">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_AssumeBundleKindAttr
     : CIR_EnumAttr<CIR_AssumeBundleKind, "assume_bundle">;
@@ -8766,9 +8736,7 @@ def CIR_InitCatchKind : CIR_I32EnumAttr<
     I32EnumAttrCase<"Objc", 3, "objc">,
     I32EnumAttrCase<"TrivialCopy", 4, "trivial_copy">,
     I32EnumAttrCase<"NonTrivialCopy", 5, "non_trivial_copy">,
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_InitCatchKindAttr : CIR_EnumAttr<CIR_InitCatchKind, "init_catch">;
 
@@ -8902,9 +8870,7 @@ def CIR_AtomicFetchKind : CIR_I32EnumAttr<
     I32EnumAttrCase<"Minimum", 11, "minimum">,
     I32EnumAttrCase<"MaximumNum", 12, "maximum_num">,
     I32EnumAttrCase<"MinimumNum", 13, "minimum_num">
-]> {
-  let genSpecializedAttr = 0;
-}
+]>;
 
 def CIR_AtomicFetchKindAttr
     : CIR_EnumAttr<CIR_AtomicFetchKind, "atomic_fetch">;
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index b004f3f202987..958785de7beec 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -689,8 +689,6 @@ def CIR_RecordMemberKind : CIR_I32EnumAttr<
     record whose trailing member is an unnamed bit-field unit keeps that unit in
     its data size.
   }];
-
-  let genSpecializedAttr = 0;
 }
 
 //===----------------------------------------------------------------------===//



More information about the llvm-branch-commits mailing list