https://github.com/xlauko created https://github.com/llvm/llvm-project/pull/220883
CastKind, DynamicCastKind, CmpOpKind, ComplexRangeKind, InitCatchKind, CaseOpKind and AwaitKind were I32EnumAttrs with the default genSpecializedAttr, so each generated an IntegerAttr subclass. Operations printed them symbolically because the format referenced the argument directly, but the underlying attribute had no dialect spelling at all. In an attribute dictionary or a generic-form dump it was a plain integer, so `cir.cast bitcast` was stored as `kind = 1 : i32`. Each enum now sets genSpecializedAttr = 0 and gets a CIR_EnumAttr wrapper, which is the pattern EnumAttr.td documents, and the operations wrap the argument in `enum()` to keep the bare keyword. The attributes gain a real spelling, e.g. `#cir.cast<bitcast>`. Operation syntax is unchanged, hence no test churn. enum-attrs.cir covers the new standalone spellings, since nothing else in the test suite exercises them. It also covers tls_model, whose spelling the earlier TLS commit changed without leaving a standalone case behind. Mnemonics drop the suffix the C++ enum class name carries, since `kind` adds nothing to `#cir.cast<bitcast>`. DynamicCastKind spells out `dynamic_cast` rather than abbreviating. `dyn_cast` is already taken by the operation and by `#cir.dyn_cast_info`, and it reads as the LLVM cast function rather than the C++ operator being modelled. The def names are constrained, unlike the mnemonics. CIRLoweringEmitter turns each EnumAttr record into an `isa<cir::...>` entry for CXXABILowering by stripping the prefix up to the first underscore, so the def must be CIR_<CppClassName>, and EnumAttr's cppClassName defaults to <EnumName>Attr. CUDADeviceVarKind gets different treatment. It is only ever a raw parameter of CIR_CUDAVarRegistrationInfoAttr, which has a custom assembly format, and its generated CUDADeviceVarKindAttr was referenced nowhere, so it just sets genSpecializedAttr = 0 with no wrapper. It also moves to CIR_I32EnumAttr instead of spelling out cppNamespace. --- Stacked on #220881. Based on `users/xlauko/cir-enum-04-drop-visibility-attr`, so the diff shown is this commit alone. >From d86c70a39146c1c72815cdc5094a29ae325404ec Mon Sep 17 00:00:00 2001 From: Henrich Lauko <[email protected]> Date: Thu, 3 Sep 2026 11:29:23 +0000 Subject: [PATCH] [CIR] Migrate seven operation enums off IntegerAttr CastKind, DynamicCastKind, CmpOpKind, ComplexRangeKind, InitCatchKind, CaseOpKind and AwaitKind were I32EnumAttrs with the default genSpecializedAttr, so each generated an IntegerAttr subclass. Operations printed them symbolically because the format referenced the argument directly, but the underlying attribute had no dialect spelling at all. In an attribute dictionary or a generic-form dump it was a plain integer, so `cir.cast bitcast` was stored as `kind = 1 : i32`. Each enum now sets genSpecializedAttr = 0 and gets a CIR_EnumAttr wrapper, which is the pattern EnumAttr.td documents, and the operations wrap the argument in `enum()` to keep the bare keyword. The attributes gain a real spelling, e.g. `#cir.cast<bitcast>`. Operation syntax is unchanged, hence no test churn. enum-attrs.cir covers the new standalone spellings, since nothing else in the test suite exercises them. It also covers tls_model, whose spelling the earlier TLS commit changed without leaving a standalone case behind. Mnemonics drop the suffix the C++ enum class name carries, since `kind` adds nothing to `#cir.cast<bitcast>`. DynamicCastKind spells out `dynamic_cast` rather than abbreviating. `dyn_cast` is already taken by the operation and by `#cir.dyn_cast_info`, and it reads as the LLVM cast function rather than the C++ operator being modelled. The def names are constrained, unlike the mnemonics. CIRLoweringEmitter turns each EnumAttr record into an `isa<cir::...>` entry for CXXABILowering by stripping the prefix up to the first underscore, so the def must be CIR_<CppClassName>, and EnumAttr's cppClassName defaults to <EnumName>Attr. CUDADeviceVarKind gets different treatment. It is only ever a raw parameter of CIR_CUDAVarRegistrationInfoAttr, which has a custom assembly format, and its generated CUDADeviceVarKindAttr was referenced nowhere, so it just sets genSpecializedAttr = 0 with no wrapper. It also moves to CIR_I32EnumAttr instead of spelling out cppNamespace. --- .../clang/CIR/Dialect/IR/CIRCUDAAttrs.td | 7 +- clang/include/clang/CIR/Dialect/IR/CIROps.td | 82 ++++++++++++------ clang/test/CIR/IR/enum-attrs.cir | 86 +++++++++++++++++++ 3 files changed, 147 insertions(+), 28 deletions(-) create mode 100644 clang/test/CIR/IR/enum-attrs.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td index 73dd7baaa5caa..2d5f70ec9c3ad 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td @@ -68,14 +68,15 @@ def CIR_CUDABinaryHandleAttr : CIR_Attr< let assemblyFormat = "`<` $name `>`"; } -// Enum for device variable kinds -def CIR_CUDADeviceVarKind : I32EnumAttr<"CUDADeviceVarKind", +// No wrapper attribute: the kind is only ever printed by +// CIR_CUDAVarRegistrationInfoAttr's own assembly format. +def CIR_CUDADeviceVarKind : CIR_I32EnumAttr<"CUDADeviceVarKind", "CUDA device variable kind", [ I32EnumAttrCase<"Variable", 0>, I32EnumAttrCase<"Surface", 1>, // Future I32EnumAttrCase<"Texture", 2>, // Future ]> { - let cppNamespace = "::cir"; + let genSpecializedAttr = 0; } // Attribute carrying device variable registration flags diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 8ccd086a146fb..4d807f88715c2 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -242,7 +242,11 @@ 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">; def CIR_CastOp : CIR_Op<"cast", !listconcat([ DeclareOpInterfaceMethods<PromotableOpInterface> @@ -302,12 +306,12 @@ def CIR_CastOp : CIR_Op<"cast", !listconcat([ ``` }]; - let arguments = (ins CIR_CastKind:$kind, CIR_AnyType:$src, + let arguments = (ins CIR_CastKindAttr:$kind, CIR_AnyType:$src, OptionalAttr<CIR_FenvAttr>:$fenv); let results = (outs CIR_AnyType:$result); let assemblyFormat = [{ - $kind $src `:` type($src) `->` type($result) attr-dict + enum($kind) $src `:` type($src) `->` type($result) attr-dict }]; let builders = [ @@ -395,7 +399,12 @@ 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">; def CIR_DynamicCastOp : CIR_Op<"dyn_cast"> { let summary = "Perform dynamic cast on record pointers"; @@ -450,7 +459,7 @@ def CIR_DynamicCastOp : CIR_Op<"dyn_cast"> { }]; let arguments = (ins - CIR_DynamicCastKind:$kind, + CIR_DynamicCastKindAttr:$kind, CIR_PtrToRecordType:$src, OptionalAttr<CIR_DynamicCastInfoAttr>:$info, UnitAttr:$relative_layout @@ -461,7 +470,7 @@ def CIR_DynamicCastOp : CIR_Op<"dyn_cast"> { ); let assemblyFormat = [{ - $kind (`relative_layout` $relative_layout^)? $src + enum($kind) (`relative_layout` $relative_layout^)? $src `:` qualified(type($src)) `->` qualified(type($result)) (qualified($info)^)? attr-dict }]; @@ -1513,7 +1522,11 @@ 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">; def CIR_CaseOp : CIR_Op<"case", [ DeclareOpInterfaceMethods<RegionBranchOpInterface, ["getSuccessorInputs"]>, @@ -1537,10 +1550,11 @@ def CIR_CaseOp : CIR_Op<"case", [ Each case region must be explicitly terminated. }]; - let arguments = (ins ArrayAttr:$value, CIR_CaseOpKind:$kind); + let arguments = (ins ArrayAttr:$value, CIR_CaseOpKindAttr:$kind); let regions = (region AnyRegion:$caseRegion); - let assemblyFormat = "`(` $kind `,` $value `)` $caseRegion attr-dict"; + let assemblyFormat = + "`(` enum($kind) `,` $value `)` $caseRegion attr-dict"; let skipDefaultBuilders = 1; let builders = [ @@ -2522,7 +2536,11 @@ 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">; def CIR_CmpOp : CIR_Op<"cmp", !listconcat([SameTypeOperands], CIR_FenvOpTraits)> { @@ -2561,7 +2579,7 @@ def CIR_CmpOp : CIR_Op<"cmp", }]; let arguments = (ins - CIR_CmpOpKind:$kind, + CIR_CmpOpKindAttr:$kind, CIR_ComparableType:$lhs, CIR_ComparableType:$rhs, OptionalAttr<CIR_FenvAttr>:$fenv @@ -2570,7 +2588,7 @@ def CIR_CmpOp : CIR_Op<"cmp", let results = (outs CIR_BoolType:$result); let assemblyFormat = [{ - $kind $lhs `,` $rhs `:` type($lhs) attr-dict + enum($kind) $lhs `,` $rhs `:` type($lhs) attr-dict }]; let builders = [ @@ -4718,7 +4736,11 @@ 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">; def CIR_AwaitOp : CIR_Op<"await",[ DeclareOpInterfaceMethods<RegionBranchOpInterface, ["getSuccessorInputs"]>, @@ -4774,12 +4796,12 @@ def CIR_AwaitOp : CIR_Op<"await",[ as part of the enclosing await scope. }]; - let arguments = (ins CIR_AwaitKind:$kind); + let arguments = (ins CIR_AwaitKindAttr:$kind); let regions = (region SizedRegion<1>:$ready, SizedRegion<1>:$suspend, SizedRegion<1>:$resume); let assemblyFormat = [{ - `(` $kind `,` + `(` enum($kind) `,` `ready` `:` $ready `,` `suspend` `:` $suspend `,` `resume` `:` $resume `,` @@ -5919,7 +5941,7 @@ def CIR_VecCmpOp : CIR_Op<"vec.cmp", }]; let arguments = (ins - CIR_CmpOpKind:$kind, + CIR_CmpOpKindAttr:$kind, CIR_VectorType:$lhs, CIR_VectorType:$rhs, OptionalAttr<CIR_FenvAttr>:$fenv @@ -5928,7 +5950,7 @@ def CIR_VecCmpOp : CIR_Op<"vec.cmp", let results = (outs CIR_VectorType:$result); let assemblyFormat = [{ - `(` $kind `,` $lhs `,` $rhs `)` `:` qualified(type($lhs)) `,` + `(` enum($kind) `,` $lhs `,` $rhs `)` `:` qualified(type($lhs)) `,` qualified(type($result)) attr-dict }]; @@ -6502,20 +6524,26 @@ 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">; class CIR_ComplexRangeBinOp<string mnemonic> : CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]> { let arguments = (ins CIR_ComplexType:$lhs, CIR_ComplexType:$rhs, - CIR_ComplexRangeKind:$range + CIR_ComplexRangeKindAttr:$range ); let results = (outs CIR_ComplexType:$result); let assemblyFormat = [{ - $lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict + $lhs `,` $rhs `range` `(` enum($range) `)` `:` qualified(type($result)) + attr-dict }]; let hasLLVMLowering = false; @@ -8703,7 +8731,11 @@ 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">; def CIR_InitCatchParamOp : CIR_Op<"init_catch_param"> { let summary = "Initialize a catch parameter from the exception pointer"; @@ -8733,11 +8765,11 @@ def CIR_InitCatchParamOp : CIR_Op<"init_catch_param"> { let arguments = (ins CIR_PointerType:$exn_ptr, CIR_PointerType:$param_addr, - CIR_InitCatchKind:$kind + CIR_InitCatchKindAttr:$kind ); let assemblyFormat = [{ - $kind $exn_ptr `to` $param_addr `:` + enum($kind) $exn_ptr `to` $param_addr `:` qualified(type($exn_ptr)) `,` qualified(type($param_addr)) attr-dict }]; @@ -8783,12 +8815,12 @@ def CIR_ConstructCatchParamOp : CIR_Op<"construct_catch_param", [ let arguments = (ins CIR_EhTokenType:$eh_token, CIR_PointerType:$param_addr, - CIR_InitCatchKind:$kind, + CIR_InitCatchKindAttr:$kind, OptionalAttr<FlatSymbolRefAttr>:$copy_fn ); let assemblyFormat = [{ - $kind $eh_token `to` $param_addr `using` ($copy_fn^)? `:` + enum($kind) $eh_token `to` $param_addr `using` ($copy_fn^)? `:` qualified(type($param_addr)) attr-dict }]; diff --git a/clang/test/CIR/IR/enum-attrs.cir b/clang/test/CIR/IR/enum-attrs.cir new file mode 100644 index 0000000000000..0e0238c690dbc --- /dev/null +++ b/clang/test/CIR/IR/enum-attrs.cir @@ -0,0 +1,86 @@ +// RUN: cir-opt %s --verify-roundtrip | FileCheck %s + +// Enum attributes that operations print as a bare keyword must still have a +// readable standalone spelling for when they show up in an attribute +// dictionary. These used to be IntegerAttr subclasses, which printed as +// `2 : i32`. + +!s32i = !cir.int<s, 32> + +module { + +cir.func @cast_attr() { + cir.return {cir.test = [#cir.cast<bitcast>, #cir.cast<integral>, + #cir.cast<bool_to_float>]} +} + +// CHECK: cir.func @cast_attr() { +// CHECK: cir.return {cir.test = [#cir.cast<bitcast>, #cir.cast<integral>, #cir.cast<bool_to_float>]} + +cir.func @dynamic_cast_attr() { + cir.return {cir.test = [#cir.dynamic_cast<ptr>, + #cir.dynamic_cast<ref>]} +} + +// CHECK: cir.func @dynamic_cast_attr() { +// CHECK: cir.return {cir.test = [#cir.dynamic_cast<ptr>, #cir.dynamic_cast<ref>]} + +cir.func @cmp_attr() { + cir.return {cir.test = [#cir.cmp<lt>, #cir.cmp<eq>, + #cir.cmp<uno>]} +} + +// CHECK: cir.func @cmp_attr() { +// CHECK: cir.return {cir.test = [#cir.cmp<lt>, #cir.cmp<eq>, #cir.cmp<uno>]} + +cir.func @complex_range_attr() { + cir.return {cir.test = [#cir.complex_range<full>, + #cir.complex_range<basic>]} +} + +// CHECK: cir.func @complex_range_attr() { +// CHECK: cir.return {cir.test = [#cir.complex_range<full>, #cir.complex_range<basic>]} + +cir.func @init_catch_attr() { + cir.return {cir.test = [#cir.init_catch<reference>, + #cir.init_catch<non_trivial_copy>]} +} + +// CHECK: cir.func @init_catch_attr() { +// CHECK: cir.return {cir.test = [#cir.init_catch<reference>, #cir.init_catch<non_trivial_copy>]} + +cir.func @case_attr() { + cir.return {cir.test = [#cir.case<default>, #cir.case<anyof>, + #cir.case<range>]} +} + +// CHECK: cir.func @case_attr() { +// CHECK: cir.return {cir.test = [#cir.case<default>, #cir.case<anyof>, #cir.case<range>]} + +cir.func @await_attr() { + cir.return {cir.test = [#cir.await<init>, #cir.await<final>]} +} + +// CHECK: cir.func @await_attr() { +// CHECK: cir.return {cir.test = [#cir.await<init>, #cir.await<final>]} + +cir.func @tls_model_attr() { + cir.return {cir.test = [#cir.tls_model<tls_dyn>, + #cir.tls_model<tls_local_exec>]} +} + +// CHECK: cir.func @tls_model_attr() { +// CHECK: cir.return {cir.test = [#cir.tls_model<tls_dyn>, #cir.tls_model<tls_local_exec>]} + +// The operations themselves keep printing a bare keyword. +cir.func @operations_print_bare_keywords(%arg0: !s32i, %arg1: !s32i) { + %0 = cir.cast bitcast %arg0 : !s32i -> !s32i + %1 = cir.cmp lt %arg0, %arg1 : !s32i + cir.return +} + +// CHECK: cir.func @operations_print_bare_keywords(%arg0: !s32i, %arg1: !s32i) { +// CHECK: %0 = cir.cast bitcast %arg0 : !s32i -> !s32i +// CHECK: %1 = cir.cmp lt %arg0, %arg1 : !s32i + +} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
