Skip to content

[mlir][LLVMIR][NFC] Migrate to OpAsmAttrInterface for ASM alias generation #130479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

ZenithalHourlyRate
Copy link
Member

@ZenithalHourlyRate ZenithalHourlyRate commented Mar 9, 2025

After the introduction of OpAsmAttrInterface, it is favorable to migrate code using OpAsmDialectInterface for ASM alias generation, which lives in Dialect.cpp, to use OpAsmAttrInterface, which lives in Attrs.td. In this way, attribute behavior is placed near its tablegen definition and people won't need to go through other files to know what other (unexpected) hooks comes into play.

See #124721 for the interface itself and #128191 for prior migration for Builtin Attributes.

See #131504 for the genMnemonicAlias tablegen field.

Cc @River707 based on the comment here #121187 (review)

@llvmbot
Copy link
Member

llvmbot commented Mar 9, 2025

@llvm/pr-subscribers-mlir-ods
@llvm/pr-subscribers-mlir-core

@llvm/pr-subscribers-mlir-llvm

Author: Hongren Zheng (ZenithalHourlyRate)

Changes

After the introduction of OpAsmAttrInterface, it is favorable to migrate code using OpAsmDialectInterface for ASM alias generation, which lives in Dialect.cpp, to use OpAsmAttrInterface, which lives in Attrs.td. In this way, attribute behavior is placed near its tablegen definition and people won't need to go through other files to know what other (unexpected) hooks comes into play.

See #124721 for the interface itself and #128191 for prior migration for Builtin Attributes.

As there are many LLVM Attributes that has ASM alias behavior, instead of creating extraClassDeclaraction for each of them, a base implementation is put in LLVM_Attr tablegen class and uses a custom enableMnemonicAlias flag for concrete attribute to select whether it wants such behavior.

For attribute definition that already has extraClassDeclaration, it needs to copy-paste the OpAsmAttrInterface Method from LLVM_Attr as it will override the record there.

Cc @River707 based on the comment here #121187 (review)


Full diff: https://github.com/llvm/llvm-project/pull/130479.diff

2 Files Affected:

  • (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td (+143-1)
  • (modified) mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp (-33)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 267389774bd5a..544945921bbc4 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -13,13 +13,30 @@ include "mlir/Dialect/LLVMIR/LLVMDialect.td"
 include "mlir/Dialect/LLVMIR/LLVMInterfaces.td"
 include "mlir/IR/AttrTypeBase.td"
 include "mlir/IR/CommonAttrConstraints.td"
+include "mlir/IR/OpAsmInterface.td"
 
 // All of the attributes will extend this class.
 class LLVM_Attr<string name, string attrMnemonic,
                 list<Trait> traits = [],
                 string baseCppClass = "::mlir::Attribute">
-    : AttrDef<LLVM_Dialect, name, traits, baseCppClass> {
+    : AttrDef<LLVM_Dialect, name, traits # [OpAsmAttrInterface], baseCppClass> {
   let mnemonic = attrMnemonic;
+
+  // Custom flag for attribute to indicate whether it wants mnemonic alias.
+  int enableMnemonicAlias = 0;
+  // If the attribute already uses extraClassDeclaration, it should create
+  // its own OpAsmAttrInterface methods instead of relying on here as this
+  // part will be overriden.
+  let extraClassDeclaration = !if(!eq(enableMnemonicAlias, 1), [{
+    //===------------------------------------------------------------------===//
+    // OpAsmAttrInterface Methods
+    //===------------------------------------------------------------------===//
+
+    ::mlir::OpAsmAliasResult getAlias(::llvm::raw_ostream &os) const {
+      os << "}] # mnemonic # [{";
+      return ::mlir::OpAsmAliasResult::OverridableAlias;
+    }
+  }], "");
 }
 
 //===----------------------------------------------------------------------===//
@@ -79,6 +96,9 @@ def LoopVectorizeAttr : LLVM_Attr<"LoopVectorize", "loop_vectorize"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopInterleaveAttr : LLVM_Attr<"LoopInterleave", "loop_interleave"> {
@@ -92,6 +112,9 @@ def LoopInterleaveAttr : LLVM_Attr<"LoopInterleave", "loop_interleave"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopUnrollAttr : LLVM_Attr<"LoopUnroll", "loop_unroll"> {
@@ -111,6 +134,9 @@ def LoopUnrollAttr : LLVM_Attr<"LoopUnroll", "loop_unroll"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopUnrollAndJamAttr : LLVM_Attr<"LoopUnrollAndJam", "loop_unroll_and_jam"> {
@@ -130,6 +156,9 @@ def LoopUnrollAndJamAttr : LLVM_Attr<"LoopUnrollAndJam", "loop_unroll_and_jam">
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopLICMAttr : LLVM_Attr<"LoopLICM", "loop_licm"> {
@@ -145,6 +174,9 @@ def LoopLICMAttr : LLVM_Attr<"LoopLICM", "loop_licm"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopDistributeAttr : LLVM_Attr<"LoopDistribute", "loop_distribute"> {
@@ -162,6 +194,9 @@ def LoopDistributeAttr : LLVM_Attr<"LoopDistribute", "loop_distribute"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopPipelineAttr : LLVM_Attr<"LoopPipeline", "loop_pipeline"> {
@@ -176,6 +211,9 @@ def LoopPipelineAttr : LLVM_Attr<"LoopPipeline", "loop_pipeline"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopPeeledAttr : LLVM_Attr<"LoopPeeled", "loop_peeled"> {
@@ -189,6 +227,9 @@ def LoopPeeledAttr : LLVM_Attr<"LoopPeeled", "loop_peeled"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopUnswitchAttr : LLVM_Attr<"LoopUnswitch", "loop_unswitch"> {
@@ -202,6 +243,9 @@ def LoopUnswitchAttr : LLVM_Attr<"LoopUnswitch", "loop_unswitch"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopAnnotationAttr : LLVM_Attr<"LoopAnnotation", "loop_annotation"> {
@@ -232,6 +276,9 @@ def LoopAnnotationAttr : LLVM_Attr<"LoopAnnotation", "loop_annotation"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -311,6 +358,9 @@ def LLVM_DIExpressionAttr : LLVM_Attr<"DIExpression", "di_expression"> {
 def LLVM_DINullTypeAttr : LLVM_Attr<"DINullType", "di_null_type",
                                     /*traits=*/[], "DITypeAttr"> {
   let parameters = (ins);
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -336,6 +386,9 @@ def LLVM_DIBasicTypeAttr : LLVM_Attr<"DIBasicType", "di_basic_type",
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -365,6 +418,9 @@ def LLVM_DICompileUnitAttr : LLVM_Attr<"DICompileUnit", "di_compile_unit",
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -421,7 +477,20 @@ def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type",
     static DIRecursiveTypeAttrInterface getRecSelf(DistinctAttr recId);
 
     /// @}
+
+    //===------------------------------------------------------------------===//
+    // OpAsmAttrInterface Methods
+    //===------------------------------------------------------------------===//
+
+    ::mlir::OpAsmAliasResult getAlias(::llvm::raw_ostream &os) const {
+      os << "}] # mnemonic # [{";
+      return ::mlir::OpAsmAliasResult::OverridableAlias;
+    }
   }];
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  // Disable overriding in LLVM_Attr class.
+  let enableMnemonicAlias = 0;
 }
 
 //===----------------------------------------------------------------------===//
@@ -441,6 +510,9 @@ def LLVM_DIDerivedTypeAttr : LLVM_Attr<"DIDerivedType", "di_derived_type",
     OptionalParameter<"DINodeAttr">:$extraData
   );
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -455,6 +527,9 @@ def LLVM_DIFileAttr : LLVM_Attr<"DIFile", "di_file", /*traits=*/[], "DIScopeAttr
     }]>
   ];
   let assemblyFormat = "`<` $name `in` $directory `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -469,6 +544,9 @@ def LLVM_DIGlobalVariableExpressionAttr
   );
   let assemblyFormat = "`<` struct(params) `>`";
   let constBuilderCall = "$0";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def DIGlobalVariableExpressionArrayAttr :
@@ -492,6 +570,9 @@ def LLVM_DIGlobalVariable : LLVM_Attr<"DIGlobalVariable", "di_global_variable",
     OptionalParameter<"bool">:$isDefined,
     OptionalParameter<"unsigned">:$alignInBits);
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -515,6 +596,9 @@ def LLVM_DILexicalBlockAttr : LLVM_Attr<"DILexicalBlock", "di_lexical_block",
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -536,6 +620,9 @@ def LLVM_DILexicalBlockFile : LLVM_Attr<"DILexicalBlockFile", "di_lexical_block_
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -566,6 +653,9 @@ def LLVM_DILocalVariableAttr : LLVM_Attr<"DILocalVariable", "di_local_variable",
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -618,7 +708,20 @@ def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram",
     static DIRecursiveTypeAttrInterface getRecSelf(DistinctAttr recId);
 
     /// @}
+
+    //===------------------------------------------------------------------===//
+    // OpAsmAttrInterface Methods
+    //===------------------------------------------------------------------===//
+
+    ::mlir::OpAsmAliasResult getAlias(::llvm::raw_ostream &os) const {
+      os << "}] # mnemonic # [{";
+      return ::mlir::OpAsmAliasResult::OverridableAlias;
+    }
   }];
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  // Disable overriding in LLVM_Attr class.
+  let enableMnemonicAlias = 0;
 }
 
 //===----------------------------------------------------------------------===//
@@ -639,6 +742,9 @@ def LLVM_DIModuleAttr : LLVM_Attr<"DIModule", "di_module",
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -654,6 +760,9 @@ def LLVM_DINamespaceAttr : LLVM_Attr<"DINamespace", "di_namespace",
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -673,6 +782,9 @@ def LLVM_DIImportedEntityAttr : LLVM_Attr<"DIImportedEntity", "di_imported_entit
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -719,6 +831,9 @@ def LLVM_DICommonBlockAttr : LLVM_Attr<"DICommonBlock", "di_common_block",
     OptionalParameter<"unsigned">:$line
   );
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -753,6 +868,9 @@ def LLVM_DISubroutineTypeAttr : LLVM_Attr<"DISubroutineType", "di_subroutine_typ
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -778,6 +896,9 @@ def LLVM_DILabelAttr : LLVM_Attr<"DILabel", "di_label",
   ];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -797,6 +918,9 @@ def LLVM_DIStringTypeAttr : LLVM_Attr<"DIStringType", "di_string_type",
     LLVM_DIEncodingParameter:$encoding
   );
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -845,6 +969,9 @@ def LLVM_AliasScopeDomainAttr : LLVM_Attr<"AliasScopeDomain",
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -902,6 +1029,9 @@ def LLVM_AliasScopeAttr : LLVM_Attr<"AliasScope", "alias_scope"> {
   let assemblyFormat = "`<` struct(params) `>`";
 
   let genVerifyDecl = 1;
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LLVM_AliasScopeArrayAttr
@@ -937,6 +1067,9 @@ def LLVM_AccessGroupAttr : LLVM_Attr<"AccessGroup", "access_group"> {
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LLVM_AccessGroupArrayAttr
@@ -967,6 +1100,9 @@ def LLVM_TBAARootAttr : LLVM_Attr<"TBAARoot", "tbaa_root", [], "TBAANodeAttr"> {
   }];
 
   let assemblyFormat = "(`<` struct(params)^ `>`)?";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1040,6 +1176,9 @@ def LLVM_TBAATypeDescriptorAttr : LLVM_Attr<"TBAATypeDescriptor",
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1082,6 +1221,9 @@ def LLVM_TBAATagAttr : LLVM_Attr<"TBAATag", "tbaa_tag"> {
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LLVM_TBAATagArrayAttr
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 8a6325af201f4..99f2bb1dce981 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -3670,36 +3670,6 @@ void CallIntrinsicOp::print(OpAsmPrinter &p) {
       /*isVariadic=*/false, getResultTypes(), getResAttrsAttr());
 }
 
-//===----------------------------------------------------------------------===//
-// OpAsmDialectInterface
-//===----------------------------------------------------------------------===//
-
-namespace {
-struct LLVMOpAsmDialectInterface : public OpAsmDialectInterface {
-  using OpAsmDialectInterface::OpAsmDialectInterface;
-
-  AliasResult getAlias(Attribute attr, raw_ostream &os) const override {
-    return TypeSwitch<Attribute, AliasResult>(attr)
-        .Case<AccessGroupAttr, AliasScopeAttr, AliasScopeDomainAttr,
-              DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr,
-              DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr,
-              DIGlobalVariableAttr, DIGlobalVariableExpressionAttr,
-              DIImportedEntityAttr, DILabelAttr, DILexicalBlockAttr,
-              DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr,
-              DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr,
-              DISubprogramAttr, DISubroutineTypeAttr, LoopAnnotationAttr,
-              LoopVectorizeAttr, LoopInterleaveAttr, LoopUnrollAttr,
-              LoopUnrollAndJamAttr, LoopLICMAttr, LoopDistributeAttr,
-              LoopPipelineAttr, LoopPeeledAttr, LoopUnswitchAttr, TBAARootAttr,
-              TBAATagAttr, TBAATypeDescriptorAttr>([&](auto attr) {
-          os << decltype(attr)::getMnemonic();
-          return AliasResult::OverridableAlias;
-        })
-        .Default([](Attribute) { return AliasResult::NoAlias; });
-  }
-};
-} // namespace
-
 //===----------------------------------------------------------------------===//
 // LinkerOptionsOp
 //===----------------------------------------------------------------------===//
@@ -3833,9 +3803,6 @@ void LLVMDialect::initialize() {
 
   // Support unknown operations because not all LLVM operations are registered.
   allowUnknownOperations();
-  // clang-format off
-  addInterfaces<LLVMOpAsmDialectInterface>();
-  // clang-format on
   declarePromisedInterface<DialectInlinerInterface, LLVMDialect>();
 }
 

@llvmbot
Copy link
Member

llvmbot commented Mar 9, 2025

@llvm/pr-subscribers-mlir

Author: Hongren Zheng (ZenithalHourlyRate)

Changes

After the introduction of OpAsmAttrInterface, it is favorable to migrate code using OpAsmDialectInterface for ASM alias generation, which lives in Dialect.cpp, to use OpAsmAttrInterface, which lives in Attrs.td. In this way, attribute behavior is placed near its tablegen definition and people won't need to go through other files to know what other (unexpected) hooks comes into play.

See #124721 for the interface itself and #128191 for prior migration for Builtin Attributes.

As there are many LLVM Attributes that has ASM alias behavior, instead of creating extraClassDeclaraction for each of them, a base implementation is put in LLVM_Attr tablegen class and uses a custom enableMnemonicAlias flag for concrete attribute to select whether it wants such behavior.

For attribute definition that already has extraClassDeclaration, it needs to copy-paste the OpAsmAttrInterface Method from LLVM_Attr as it will override the record there.

Cc @River707 based on the comment here #121187 (review)


Full diff: https://github.com/llvm/llvm-project/pull/130479.diff

2 Files Affected:

  • (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td (+143-1)
  • (modified) mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp (-33)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 267389774bd5a..544945921bbc4 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -13,13 +13,30 @@ include "mlir/Dialect/LLVMIR/LLVMDialect.td"
 include "mlir/Dialect/LLVMIR/LLVMInterfaces.td"
 include "mlir/IR/AttrTypeBase.td"
 include "mlir/IR/CommonAttrConstraints.td"
+include "mlir/IR/OpAsmInterface.td"
 
 // All of the attributes will extend this class.
 class LLVM_Attr<string name, string attrMnemonic,
                 list<Trait> traits = [],
                 string baseCppClass = "::mlir::Attribute">
-    : AttrDef<LLVM_Dialect, name, traits, baseCppClass> {
+    : AttrDef<LLVM_Dialect, name, traits # [OpAsmAttrInterface], baseCppClass> {
   let mnemonic = attrMnemonic;
+
+  // Custom flag for attribute to indicate whether it wants mnemonic alias.
+  int enableMnemonicAlias = 0;
+  // If the attribute already uses extraClassDeclaration, it should create
+  // its own OpAsmAttrInterface methods instead of relying on here as this
+  // part will be overriden.
+  let extraClassDeclaration = !if(!eq(enableMnemonicAlias, 1), [{
+    //===------------------------------------------------------------------===//
+    // OpAsmAttrInterface Methods
+    //===------------------------------------------------------------------===//
+
+    ::mlir::OpAsmAliasResult getAlias(::llvm::raw_ostream &os) const {
+      os << "}] # mnemonic # [{";
+      return ::mlir::OpAsmAliasResult::OverridableAlias;
+    }
+  }], "");
 }
 
 //===----------------------------------------------------------------------===//
@@ -79,6 +96,9 @@ def LoopVectorizeAttr : LLVM_Attr<"LoopVectorize", "loop_vectorize"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopInterleaveAttr : LLVM_Attr<"LoopInterleave", "loop_interleave"> {
@@ -92,6 +112,9 @@ def LoopInterleaveAttr : LLVM_Attr<"LoopInterleave", "loop_interleave"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopUnrollAttr : LLVM_Attr<"LoopUnroll", "loop_unroll"> {
@@ -111,6 +134,9 @@ def LoopUnrollAttr : LLVM_Attr<"LoopUnroll", "loop_unroll"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopUnrollAndJamAttr : LLVM_Attr<"LoopUnrollAndJam", "loop_unroll_and_jam"> {
@@ -130,6 +156,9 @@ def LoopUnrollAndJamAttr : LLVM_Attr<"LoopUnrollAndJam", "loop_unroll_and_jam">
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopLICMAttr : LLVM_Attr<"LoopLICM", "loop_licm"> {
@@ -145,6 +174,9 @@ def LoopLICMAttr : LLVM_Attr<"LoopLICM", "loop_licm"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopDistributeAttr : LLVM_Attr<"LoopDistribute", "loop_distribute"> {
@@ -162,6 +194,9 @@ def LoopDistributeAttr : LLVM_Attr<"LoopDistribute", "loop_distribute"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopPipelineAttr : LLVM_Attr<"LoopPipeline", "loop_pipeline"> {
@@ -176,6 +211,9 @@ def LoopPipelineAttr : LLVM_Attr<"LoopPipeline", "loop_pipeline"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopPeeledAttr : LLVM_Attr<"LoopPeeled", "loop_peeled"> {
@@ -189,6 +227,9 @@ def LoopPeeledAttr : LLVM_Attr<"LoopPeeled", "loop_peeled"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopUnswitchAttr : LLVM_Attr<"LoopUnswitch", "loop_unswitch"> {
@@ -202,6 +243,9 @@ def LoopUnswitchAttr : LLVM_Attr<"LoopUnswitch", "loop_unswitch"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LoopAnnotationAttr : LLVM_Attr<"LoopAnnotation", "loop_annotation"> {
@@ -232,6 +276,9 @@ def LoopAnnotationAttr : LLVM_Attr<"LoopAnnotation", "loop_annotation"> {
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -311,6 +358,9 @@ def LLVM_DIExpressionAttr : LLVM_Attr<"DIExpression", "di_expression"> {
 def LLVM_DINullTypeAttr : LLVM_Attr<"DINullType", "di_null_type",
                                     /*traits=*/[], "DITypeAttr"> {
   let parameters = (ins);
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -336,6 +386,9 @@ def LLVM_DIBasicTypeAttr : LLVM_Attr<"DIBasicType", "di_basic_type",
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -365,6 +418,9 @@ def LLVM_DICompileUnitAttr : LLVM_Attr<"DICompileUnit", "di_compile_unit",
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -421,7 +477,20 @@ def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type",
     static DIRecursiveTypeAttrInterface getRecSelf(DistinctAttr recId);
 
     /// @}
+
+    //===------------------------------------------------------------------===//
+    // OpAsmAttrInterface Methods
+    //===------------------------------------------------------------------===//
+
+    ::mlir::OpAsmAliasResult getAlias(::llvm::raw_ostream &os) const {
+      os << "}] # mnemonic # [{";
+      return ::mlir::OpAsmAliasResult::OverridableAlias;
+    }
   }];
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  // Disable overriding in LLVM_Attr class.
+  let enableMnemonicAlias = 0;
 }
 
 //===----------------------------------------------------------------------===//
@@ -441,6 +510,9 @@ def LLVM_DIDerivedTypeAttr : LLVM_Attr<"DIDerivedType", "di_derived_type",
     OptionalParameter<"DINodeAttr">:$extraData
   );
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -455,6 +527,9 @@ def LLVM_DIFileAttr : LLVM_Attr<"DIFile", "di_file", /*traits=*/[], "DIScopeAttr
     }]>
   ];
   let assemblyFormat = "`<` $name `in` $directory `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -469,6 +544,9 @@ def LLVM_DIGlobalVariableExpressionAttr
   );
   let assemblyFormat = "`<` struct(params) `>`";
   let constBuilderCall = "$0";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def DIGlobalVariableExpressionArrayAttr :
@@ -492,6 +570,9 @@ def LLVM_DIGlobalVariable : LLVM_Attr<"DIGlobalVariable", "di_global_variable",
     OptionalParameter<"bool">:$isDefined,
     OptionalParameter<"unsigned">:$alignInBits);
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -515,6 +596,9 @@ def LLVM_DILexicalBlockAttr : LLVM_Attr<"DILexicalBlock", "di_lexical_block",
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -536,6 +620,9 @@ def LLVM_DILexicalBlockFile : LLVM_Attr<"DILexicalBlockFile", "di_lexical_block_
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -566,6 +653,9 @@ def LLVM_DILocalVariableAttr : LLVM_Attr<"DILocalVariable", "di_local_variable",
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -618,7 +708,20 @@ def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram",
     static DIRecursiveTypeAttrInterface getRecSelf(DistinctAttr recId);
 
     /// @}
+
+    //===------------------------------------------------------------------===//
+    // OpAsmAttrInterface Methods
+    //===------------------------------------------------------------------===//
+
+    ::mlir::OpAsmAliasResult getAlias(::llvm::raw_ostream &os) const {
+      os << "}] # mnemonic # [{";
+      return ::mlir::OpAsmAliasResult::OverridableAlias;
+    }
   }];
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  // Disable overriding in LLVM_Attr class.
+  let enableMnemonicAlias = 0;
 }
 
 //===----------------------------------------------------------------------===//
@@ -639,6 +742,9 @@ def LLVM_DIModuleAttr : LLVM_Attr<"DIModule", "di_module",
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -654,6 +760,9 @@ def LLVM_DINamespaceAttr : LLVM_Attr<"DINamespace", "di_namespace",
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -673,6 +782,9 @@ def LLVM_DIImportedEntityAttr : LLVM_Attr<"DIImportedEntity", "di_imported_entit
   );
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -719,6 +831,9 @@ def LLVM_DICommonBlockAttr : LLVM_Attr<"DICommonBlock", "di_common_block",
     OptionalParameter<"unsigned">:$line
   );
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -753,6 +868,9 @@ def LLVM_DISubroutineTypeAttr : LLVM_Attr<"DISubroutineType", "di_subroutine_typ
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -778,6 +896,9 @@ def LLVM_DILabelAttr : LLVM_Attr<"DILabel", "di_label",
   ];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -797,6 +918,9 @@ def LLVM_DIStringTypeAttr : LLVM_Attr<"DIStringType", "di_string_type",
     LLVM_DIEncodingParameter:$encoding
   );
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -845,6 +969,9 @@ def LLVM_AliasScopeDomainAttr : LLVM_Attr<"AliasScopeDomain",
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -902,6 +1029,9 @@ def LLVM_AliasScopeAttr : LLVM_Attr<"AliasScope", "alias_scope"> {
   let assemblyFormat = "`<` struct(params) `>`";
 
   let genVerifyDecl = 1;
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LLVM_AliasScopeArrayAttr
@@ -937,6 +1067,9 @@ def LLVM_AccessGroupAttr : LLVM_Attr<"AccessGroup", "access_group"> {
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LLVM_AccessGroupArrayAttr
@@ -967,6 +1100,9 @@ def LLVM_TBAARootAttr : LLVM_Attr<"TBAARoot", "tbaa_root", [], "TBAANodeAttr"> {
   }];
 
   let assemblyFormat = "(`<` struct(params)^ `>`)?";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1040,6 +1176,9 @@ def LLVM_TBAATypeDescriptorAttr : LLVM_Attr<"TBAATypeDescriptor",
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1082,6 +1221,9 @@ def LLVM_TBAATagAttr : LLVM_Attr<"TBAATag", "tbaa_tag"> {
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
+
+  // Custom flag for alias, check LLVM_Attr class for more details.
+  let enableMnemonicAlias = 1;
 }
 
 def LLVM_TBAATagArrayAttr
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 8a6325af201f4..99f2bb1dce981 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -3670,36 +3670,6 @@ void CallIntrinsicOp::print(OpAsmPrinter &p) {
       /*isVariadic=*/false, getResultTypes(), getResAttrsAttr());
 }
 
-//===----------------------------------------------------------------------===//
-// OpAsmDialectInterface
-//===----------------------------------------------------------------------===//
-
-namespace {
-struct LLVMOpAsmDialectInterface : public OpAsmDialectInterface {
-  using OpAsmDialectInterface::OpAsmDialectInterface;
-
-  AliasResult getAlias(Attribute attr, raw_ostream &os) const override {
-    return TypeSwitch<Attribute, AliasResult>(attr)
-        .Case<AccessGroupAttr, AliasScopeAttr, AliasScopeDomainAttr,
-              DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr,
-              DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr,
-              DIGlobalVariableAttr, DIGlobalVariableExpressionAttr,
-              DIImportedEntityAttr, DILabelAttr, DILexicalBlockAttr,
-              DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr,
-              DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr,
-              DISubprogramAttr, DISubroutineTypeAttr, LoopAnnotationAttr,
-              LoopVectorizeAttr, LoopInterleaveAttr, LoopUnrollAttr,
-              LoopUnrollAndJamAttr, LoopLICMAttr, LoopDistributeAttr,
-              LoopPipelineAttr, LoopPeeledAttr, LoopUnswitchAttr, TBAARootAttr,
-              TBAATagAttr, TBAATypeDescriptorAttr>([&](auto attr) {
-          os << decltype(attr)::getMnemonic();
-          return AliasResult::OverridableAlias;
-        })
-        .Default([](Attribute) { return AliasResult::NoAlias; });
-  }
-};
-} // namespace
-
 //===----------------------------------------------------------------------===//
 // LinkerOptionsOp
 //===----------------------------------------------------------------------===//
@@ -3833,9 +3803,6 @@ void LLVMDialect::initialize() {
 
   // Support unknown operations because not all LLVM operations are registered.
   allowUnknownOperations();
-  // clang-format off
-  addInterfaces<LLVMOpAsmDialectInterface>();
-  // clang-format on
   declarePromisedInterface<DialectInlinerInterface, LLVMDialect>();
 }
 

Copy link
Contributor

@Dinistro Dinistro left a comment

Choose a reason for hiding this comment

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

Added a small comment, but that can probably not be resolved.

Comment on lines 30 to 38
let extraClassDeclaration = !if(!eq(enableMnemonicAlias, 1), [{
//===------------------------------------------------------------------===//
// OpAsmAttrInterface Methods
//===------------------------------------------------------------------===//

::mlir::OpAsmAliasResult getAlias(::llvm::raw_ostream &os) const {
os << "}] # mnemonic # [{";
return ::mlir::OpAsmAliasResult::OverridableAlias;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally, we would always prepend this to the extraClassDeclaration in this base class, instead of just setting the entire value. AFAIK, this is not easily doable, without handing the subclass' value to the base class, though.

Copy link
Member Author

Choose a reason for hiding this comment

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

AFAIK, this is not easily doable, without handing the subclass' value to the base class, though.

I Agree.

Another idea is to modify tablegen to recognize let alias = xxx and generate extra code snippet like extraClassOpAsmAttrInterfaceDeclaration, but I think that is too much change and may need RFC.

Copy link
Contributor

Choose a reason for hiding this comment

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

Does that imply that all aliases are supposed to implement this function in the exact same way? If so, adding this to tablegen would make sense, I think.

Copy link
Member Author

Choose a reason for hiding this comment

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

No I have a downstream example where the type/attribute want to have custom suffix to better distinguish different instances (instead of the generic 1,2,3 numbering). In this way the type/attribute has to define the function on its own and a tablegen default may not make sense.

https://github.com/google/heir/blob/2c27a9adc27c6ea670e2377d67bc4678d8a3853c/lib/Dialect/LWE/IR/NewLWEAttributes.td#L368-L384

Copy link
Contributor

Choose a reason for hiding this comment

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

I see. In this case this is probably fine then. Opinions @gysit ?

Copy link
Contributor

Choose a reason for hiding this comment

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

It may still make sense to have some tablegen for a flag that can automatically generate a getAlias function that uses the mnemonic. Basically what is in the LLVM attribute base class now. Downstream users that do something more clever can still implement their own solution?

I would assume that other dialects may also would like to have the same functionality?

However, if this is too complex we can also land the current solution. I am a bit worried that this will lead to unexpected behavior when someone overwrites the extraClassDeclaration. I do not see a better solution though (except for proper tablegen support).

Copy link
Member Author

Choose a reason for hiding this comment

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

Formed a PR on tablegen in #131504. Lets see how people would say about this (namely is it worth it)

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for giving it a shot!

Copy link
Member Author

Choose a reason for hiding this comment

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

Now this PR depends on #131504. Pushed a version with that PR cherry-picked to show its effect.

@llvmbot llvmbot added mlir:core MLIR Core Infrastructure mlir:ods labels Apr 11, 2025
@ZenithalHourlyRate ZenithalHourlyRate marked this pull request as draft April 11, 2025 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants