[Mlir-commits] [mlir] [MLIR][LLVMIR][DLTI] Pass to update #llvm.target's features per relevant backend (PR #154938)

Rolf Morel llvmlistbot at llvm.org
Sat Aug 23 07:35:36 PDT 2025


https://github.com/rolfmorel updated https://github.com/llvm/llvm-project/pull/154938

>From d95c6ed430642f6b8c07c850c0ba5dd0633cf59b Mon Sep 17 00:00:00 2001
From: Rolf Morel <rolf.morel at intel.com>
Date: Thu, 21 Aug 2025 10:15:28 -0700
Subject: [PATCH 1/9] [MLIR][LLVMIR][DLTI] Pass for updating target features
 per TargetMachine

---
 .../mlir/Dialect/LLVMIR/CMakeLists.txt        | 18 ++++-
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       | 67 +------------------
 mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h  |  5 ++
 .../mlir/Dialect/LLVMIR/LLVMDialect.td        |  9 +++
 .../mlir/Dialect/LLVMIR/LLVMInterfaces.td     |  2 +-
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td   |  1 +
 .../mlir/Target/LLVMIR/Transforms/Passes.td   | 14 ++++
 mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp      | 14 ++++
 .../Target/LLVMIR/Transforms/CMakeLists.txt   |  1 +
 .../LLVMIR/Transforms/TargetToDataLayout.cpp  |  3 +-
 .../Dialect/LLVMIR/target-to-data-layout.mlir |  6 +-
 11 files changed, 68 insertions(+), 72 deletions(-)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
index cfad07e57021f..f1385cdff62be 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
@@ -7,12 +7,26 @@ mlir_tablegen(LLVMOpsDialect.h.inc -gen-dialect-decls)
 mlir_tablegen(LLVMOpsDialect.cpp.inc -gen-dialect-defs)
 mlir_tablegen(LLVMOpsEnums.h.inc -gen-enum-decls)
 mlir_tablegen(LLVMOpsEnums.cpp.inc -gen-enum-defs)
-mlir_tablegen(LLVMOpsAttrDefs.h.inc -gen-attrdef-decls
-              -attrdefs-dialect=llvm)
+#For LLVMOpsAttrDefs.h.inc, see below.
 mlir_tablegen(LLVMOpsAttrDefs.cpp.inc -gen-attrdef-defs
               -attrdefs-dialect=llvm)
 add_public_tablegen_target(MLIRLLVMOpsIncGen)
 
+# NB: Separate out LLVMOpsAttrDefs.h.inc generation as generating it
+#     through LLVMOps.td ends up defining LLVMTargetFeaturesAttr even
+#     though LLVMTargetFeaturesAttrDefs.* is responsible for that.
+set(LLVM_TARGET_DEFINITIONS LLVMAttrAndEnumDefs.td)
+mlir_tablegen(LLVMOpsAttrDefs.h.inc -gen-attrdef-decls -attrdefs-dialect=llvm)
+add_public_tablegen_target(MLIRLLVMAttrsIncGen)
+
+# NB: LLVMTargetFeaturesAttr is split out into its own file
+#     to break a recursive dependency: LLVMInterfaces depends
+#     on it, and other LLVMAttrs depending on LLVMInterfaces.
+set(LLVM_TARGET_DEFINITIONS LLVMTargetFeaturesAttrDefs.td)
+mlir_tablegen(LLVMTargetFeaturesAttrDefs.h.inc -gen-attrdef-decls)
+mlir_tablegen(LLVMTargetFeaturesAttrDefs.cpp.inc -gen-attrdef-defs)
+add_public_tablegen_target(MLIRLLVMTargetFeaturesAttrsIncGen)
+
 set(LLVM_TARGET_DEFINITIONS LLVMTypes.td)
 mlir_tablegen(LLVMTypes.h.inc -gen-typedef-decls -typedefs-dialect=llvm)
 mlir_tablegen(LLVMTypes.cpp.inc -gen-typedef-defs -typedefs-dialect=llvm)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 138dd7703a5e7..b149f4d334665 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -1243,70 +1243,7 @@ def LLVM_VScaleRangeAttr : LLVM_Attr<"VScaleRange", "vscale_range"> {
 }
 
 //===----------------------------------------------------------------------===//
-// TargetFeaturesAttr
-//===----------------------------------------------------------------------===//
-
-def LLVM_TargetFeaturesAttr : LLVM_Attr<"TargetFeatures", "target_features">
-{
-  let summary = "LLVM target features attribute";
-
-  let description = [{
-    Represents the LLVM target features as a list that can be checked within
-    passes/rewrites.
-
-    Example:
-    ```mlir
-    #llvm.target_features<["+sme", "+sve", "+sme-f64f64"]>
-    ```
-
-    Then within a pass or rewrite the features active at an op can be queried:
-
-    ```c++
-    auto targetFeatures = LLVM::TargetFeaturesAttr::featuresAt(op);
-
-    if (!targetFeatures.contains("+sme-f64f64"))
-      return failure();
-    ```
-  }];
-
-  let parameters = (ins OptionalArrayRefParameter<"StringAttr">:$features);
-
-  let builders = [
-    TypeBuilder<(ins "::llvm::StringRef":$features)>,
-    TypeBuilder<(ins "::llvm::ArrayRef<::llvm::StringRef>":$features)>
-  ];
-
-  let extraClassDeclaration = [{
-    /// Checks if a feature is contained within the features list.
-    /// Note: Using a StringAttr allows doing pointer-comparisons.
-    bool contains(::mlir::StringAttr feature) const;
-    bool contains(::llvm::StringRef feature) const;
-
-    bool nullOrEmpty() const {
-      // Checks if this attribute is null, or the features are empty.
-      return !bool(*this) || getFeatures().empty();
-    }
-
-    /// Returns the list of features as an LLVM-compatible string.
-    std::string getFeaturesString() const;
-
-    /// Finds the target features on the parent FunctionOpInterface.
-    /// Note: This assumes the attribute name matches the return value of
-    /// `getAttributeName()`.
-    static TargetFeaturesAttr featuresAt(Operation* op);
-
-    /// Canonical name for this attribute within MLIR.
-    static constexpr StringLiteral getAttributeName() {
-      return StringLiteral("target_features");
-    }
-  }];
-
-  let assemblyFormat = "`<` `[` (`]`) : ($features^ `]`)? `>`";
-  let genVerifyDecl = 1;
-}
-
-//===----------------------------------------------------------------------===//
-// LLVM_TargetAttr
+// TargetAttr
 //===----------------------------------------------------------------------===//
 
 def LLVM_TargetAttr : LLVM_Attr<"Target", "target",
@@ -1324,7 +1261,7 @@ def LLVM_TargetAttr : LLVM_Attr<"Target", "target",
   }];
   let parameters = (ins "StringAttr":$triple,
                         "StringAttr":$chip,
-                        OptionalParameter<"StringAttr", "">:$features);
+                        OptionalParameter<"TargetFeaturesAttr", "">:$features);
 
   let assemblyFormat = [{`<` struct($triple, $chip, $features) `>`}];
 
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
index 1ceeb7e4ba2a5..4a24a9146fb72 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
@@ -92,9 +92,14 @@ class TBAANodeAttr : public Attribute {
 using cconv::CConv;
 using linkage::Linkage;
 using tailcallkind::TailCallKind;
+
+class TargetFeaturesAttr;
 } // namespace LLVM
 } // namespace mlir
 
+#define GET_ATTRDEF_CLASSES
+#include "mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.h.inc"
+
 #include "mlir/Dialect/LLVMIR/LLVMAttrInterfaces.h.inc"
 
 #define GET_ATTRDEF_CLASSES
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
index ab0462f945a33..541df23784c01 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
@@ -10,6 +10,7 @@
 #define LLVMIR_DIALECT
 
 include "mlir/IR/DialectBase.td"
+include "mlir/IR/AttrTypeBase.td"
 
 def LLVM_Dialect : Dialect {
   let name = "llvm";
@@ -127,4 +128,12 @@ def LLVM_Dialect : Dialect {
   }];
 }
 
+// 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> {
+  let mnemonic = attrMnemonic;
+}
+
 #endif  // LLVMIR_DIALECT
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
index 64600e86bedfb..dab2af75d071e 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
@@ -561,7 +561,7 @@ def LLVM_TargetAttrInterface
     >,
     InterfaceMethod<
       /*description=*/"Returns the target features as a string.",
-      /*retTy=*/"StringAttr",
+      /*retTy=*/"LLVM::TargetFeaturesAttr",
       /*methodName=*/"getFeatures",
       /*args=*/(ins)
     >
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 3f27f6d9ae8b7..6e6e5b0aa75b1 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -14,6 +14,7 @@
 #define LLVMIR_OPS
 
 include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
+include "mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td"
 include "mlir/Dialect/LLVMIR/LLVMEnums.td"
 include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
 include "mlir/IR/EnumAttr.td"
diff --git a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
index 906f6e82efa50..d082503feb4bc 100644
--- a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
+++ b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
@@ -27,4 +27,18 @@ def LLVMTargetToDataLayout : Pass<"llvm-target-to-data-layout"> {
   ];
 }
 
+def LLVMFeaturesFromTarget : Pass<"llvm-features-from-target"> {
+  let summary = "TODO";
+  let dependentDialects = ["mlir::DLTIDialect"];
+  let description = [{
+    TODO
+  }];
+  let options = [
+    Option<"initializeLLVMTargets", "initialize-llvm-targets", "bool",
+           /*default=*/"true",
+           "Whether to pre-load all available target machines, that LLVM is "
+           "configured to support, into the TargetRegistry.">
+  ];
+}
+
 #endif // MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
index 634efcaea794e..8860b82d48a39 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -403,6 +403,20 @@ ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
                      << key << "'";
 }
 
+FailureOr<Attribute> TargetFeaturesAttr::query(DataLayoutEntryKey key) {
+  if (auto stringKey = dyn_cast<StringAttr>(key)) {
+    if (contains(stringKey))
+      return UnitAttr::get(getContext());
+
+    if (contains((std::string("+") + stringKey.strref()).str()))
+      return BoolAttr::get(getContext(), true);
+
+    if (contains((std::string("-") + stringKey.strref()).str()))
+      return BoolAttr::get(getContext(), false);
+  }
+  return failure();
+}
+
 //===----------------------------------------------------------------------===//
 // LLVM_TargetAttr
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt b/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt
index a0232601c5f9c..6ef2d621af401 100644
--- a/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt
+++ b/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_mlir_dialect_library(MLIRTargetLLVMIRTransforms
   TargetToDataLayout.cpp
+  FeaturesFromTarget.cpp
 
   DEPENDS
   MLIRTargetLLVMIRTransformsIncGen
diff --git a/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp b/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
index d41d441812039..95363c85bc6de 100644
--- a/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
+++ b/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
@@ -33,7 +33,8 @@ static FailureOr<std::unique_ptr<llvm::TargetMachine>>
 getTargetMachine(LLVM::TargetAttrInterface attr) {
   StringRef triple = attr.getTriple();
   StringRef chipAKAcpu = attr.getChip();
-  StringRef features = attr.getFeatures() ? attr.getFeatures().getValue() : "";
+  std::string features =
+      attr.getFeatures() ? attr.getFeatures().getFeaturesString() : "";
 
   std::string error;
   const llvm::Target *target =
diff --git a/mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir b/mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir
index 45bfd6a465d7c..17db9bc5e114b 100644
--- a/mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir
+++ b/mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir
@@ -25,7 +25,7 @@ module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
 
 module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
                                                chip = "",
-                                               features = "+mmx,+sse"> } {
+                                               features = <["+mmx","+sse"]>> } {
 }
 
 // -----
@@ -54,7 +54,7 @@ module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
 
 module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
                                                chip = "skylake",
-                                               features = "+mmx,+sse"> } {
+                                               features = <["+mmx","+sse"]>> } {
 }
 
 // -----
@@ -71,5 +71,5 @@ module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
 module attributes { dlti.dl_spec = #dlti.dl_spec<index = 32>,
                     llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
                                                chip = "skylake",
-                                               features = "+mmx,+sse"> } {
+                                               features = <["+mmx","+sse"]>> } {
 }

>From fbcd09dd5870286d9c8100cd1af304fe0c670fbd Mon Sep 17 00:00:00 2001
From: Rolf Morel <rolf.morel at intel.com>
Date: Fri, 22 Aug 2025 05:04:50 -0700
Subject: [PATCH 2/9] Sharing is caring

---
 .../Dialect/LLVMIR/LLVMAttrAndEnumDefs.td     | 10 +++
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       |  8 --
 .../LLVMIR/LLVMTargetFeaturesAttrDefs.td      | 82 +++++++++++++++++++
 .../mlir/Target/LLVMIR/Transforms/Passes.h    | 14 ++++
 .../mlir/Target/LLVMIR/Transforms/Passes.td   |  2 +-
 .../Target/LLVMIR/Transforms/CMakeLists.txt   |  3 +-
 .../LLVMIR/Transforms/TargetToDataLayout.cpp  | 54 ++----------
 .../Transforms/TargetToTargetFeatures.cpp     | 67 +++++++++++++++
 .../Target/LLVMIR/Transforms/TargetUtils.cpp  | 70 ++++++++++++++++
 .../LLVMIR/target-to-data-layout-invalid.mlir |  0
 .../LLVMIR/target-to-data-layout-no-init.mlir |  0
 .../LLVMIR/target-to-data-layout.mlir         |  0
 12 files changed, 251 insertions(+), 59 deletions(-)
 create mode 100644 mlir/include/mlir/Dialect/LLVMIR/LLVMAttrAndEnumDefs.td
 create mode 100644 mlir/include/mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td
 create mode 100644 mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp
 create mode 100644 mlir/lib/Target/LLVMIR/Transforms/TargetUtils.cpp
 rename mlir/test/{Dialect => Target}/LLVMIR/target-to-data-layout-invalid.mlir (100%)
 rename mlir/test/{Dialect => Target}/LLVMIR/target-to-data-layout-no-init.mlir (100%)
 rename mlir/test/{Dialect => Target}/LLVMIR/target-to-data-layout.mlir (100%)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrAndEnumDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrAndEnumDefs.td
new file mode 100644
index 0000000000000..e34375076ffd1
--- /dev/null
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrAndEnumDefs.td
@@ -0,0 +1,10 @@
+//===-- LLVMAttrDefs.td - Solely LLVM Attribute and Enum definitions ----*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
+include "mlir/Dialect/LLVMIR/LLVMEnums.td"
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index b149f4d334665..af469d3eb8be2 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -15,14 +15,6 @@ include "mlir/IR/AttrTypeBase.td"
 include "mlir/IR/CommonAttrConstraints.td"
 include "mlir/Interfaces/DataLayoutInterfaces.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> {
-  let mnemonic = attrMnemonic;
-}
-
 //===----------------------------------------------------------------------===//
 // CConvAttr
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td
new file mode 100644
index 0000000000000..bc60591514c28
--- /dev/null
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td
@@ -0,0 +1,82 @@
+//===-- LLVMAttrDefs.td - LLVM Attributes definition file --*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVMIR_TARGETFEATURESATTRDEFS
+#define LLVMIR_TARGETFEATURESATTRDEFS
+
+include "mlir/Dialect/LLVMIR/LLVMDialect.td"
+include "mlir/Interfaces/DataLayoutInterfaces.td"
+
+//===----------------------------------------------------------------------===//
+// TargetFeaturesAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_TargetFeaturesAttr : LLVM_Attr<"TargetFeatures", "target_features",
+                                        [DLTIQueryInterface]>
+{
+  let summary = "LLVM target features attribute";
+
+  let description = [{
+    Represents the LLVM target features as a list that can be checked within
+    passes/rewrites.
+
+    Example:
+    ```mlir
+    #llvm.target_features<["+sme", "+sve", "+sme-f64f64"]>
+    ```
+
+    Then within a pass or rewrite the features active at an op can be queried:
+
+    ```c++
+    auto targetFeatures = LLVM::TargetFeaturesAttr::featuresAt(op);
+
+    if (!targetFeatures.contains("+sme-f64f64"))
+      return failure();
+    ```
+  }];
+
+  let parameters = (ins OptionalArrayRefParameter<"StringAttr">:$features);
+
+  let builders = [
+    TypeBuilder<(ins "::llvm::StringRef":$features)>,
+    TypeBuilder<(ins "::llvm::ArrayRef<::llvm::StringRef>":$features)>
+  ];
+
+  let extraClassDeclaration = [{
+    /// Checks if a feature is contained within the features list.
+    /// Note: Using a StringAttr allows doing pointer-comparisons.
+    bool contains(::mlir::StringAttr feature) const;
+    bool contains(::llvm::StringRef feature) const;
+
+    bool nullOrEmpty() const {
+      // Checks if this attribute is null, or the features are empty.
+      return !bool(*this) || getFeatures().empty();
+    }
+
+    /// Returns the list of features as an LLVM-compatible string.
+    std::string getFeaturesString() const;
+
+    /// Finds the target features on the parent FunctionOpInterface.
+    /// Note: This assumes the attribute name matches the return value of
+    /// `getAttributeName()`.
+    static TargetFeaturesAttr featuresAt(Operation* op);
+
+    /// Canonical name for this attribute within MLIR.
+    static constexpr StringLiteral getAttributeName() {
+      return StringLiteral("target_features");
+    }
+
+    /// Returns the attribute associated with the key.
+    FailureOr<Attribute> query(DataLayoutEntryKey key);
+  }];
+
+  let assemblyFormat = "`<` `[` (`]`) : ($features^ `]`)? `>`";
+  let genVerifyDecl = 1;
+}
+
+#endif // LLVMIR_TARGETFEATURESATTRDEFS
diff --git a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h
index 1e6419154108c..db8feb3ae2396 100644
--- a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h
+++ b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h
@@ -9,12 +9,26 @@
 #ifndef MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES_H
 #define MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES_H
 
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
 #include "mlir/Pass/Pass.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Target/TargetMachine.h"
 
 namespace mlir {
 
 namespace LLVM {
 
+namespace detail {
+
+void initializeBackendsOnce();
+
+FailureOr<std::unique_ptr<llvm::TargetMachine>>
+getTargetMachine(mlir::LLVM::TargetAttrInterface attr);
+
+FailureOr<llvm::DataLayout> getDataLayout(mlir::LLVM::TargetAttrInterface attr);
+
+} // namespace detail
+
 #define GEN_PASS_DECL
 #define GEN_PASS_REGISTRATION
 #include "mlir/Target/LLVMIR/Transforms/Passes.h.inc"
diff --git a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
index d082503feb4bc..b01baa8744ee3 100644
--- a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
+++ b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
@@ -27,7 +27,7 @@ def LLVMTargetToDataLayout : Pass<"llvm-target-to-data-layout"> {
   ];
 }
 
-def LLVMFeaturesFromTarget : Pass<"llvm-features-from-target"> {
+def LLVMTargetToTargetFeatures : Pass<"llvm-target-to-target-features"> {
   let summary = "TODO";
   let dependentDialects = ["mlir::DLTIDialect"];
   let description = [{
diff --git a/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt b/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt
index 6ef2d621af401..044da1c442049 100644
--- a/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt
+++ b/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_mlir_dialect_library(MLIRTargetLLVMIRTransforms
   TargetToDataLayout.cpp
-  FeaturesFromTarget.cpp
+  TargetToTargetFeatures.cpp
+  TargetUtils.cpp
 
   DEPENDS
   MLIRTargetLLVMIRTransformsIncGen
diff --git a/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp b/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
index 95363c85bc6de..250d6162fd780 100644
--- a/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
+++ b/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
@@ -5,21 +5,13 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+
 #include "mlir/Target/LLVMIR/Transforms/Passes.h"
 
 #include "mlir/Dialect/DLTI/DLTI.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/Target/LLVMIR/Import.h"
 
-#include "llvm/MC/TargetRegistry.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/TargetSelect.h"
-#include "llvm/Target/TargetMachine.h"
-
-#define DEBUG_TYPE "mlir-llvm-target-to-data-layout"
-#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ")
-#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n")
-
 namespace mlir {
 namespace LLVM {
 #define GEN_PASS_DEF_LLVMTARGETTODATALAYOUT
@@ -29,36 +21,6 @@ namespace LLVM {
 
 using namespace mlir;
 
-static FailureOr<std::unique_ptr<llvm::TargetMachine>>
-getTargetMachine(LLVM::TargetAttrInterface attr) {
-  StringRef triple = attr.getTriple();
-  StringRef chipAKAcpu = attr.getChip();
-  std::string features =
-      attr.getFeatures() ? attr.getFeatures().getFeaturesString() : "";
-
-  std::string error;
-  const llvm::Target *target =
-      llvm::TargetRegistry::lookupTarget(triple, error);
-  if (!target || !error.empty()) {
-    LDBG("Looking up target '" << triple << "' failed: " << error << "\n");
-    return failure();
-  }
-
-  return std::unique_ptr<llvm::TargetMachine>(target->createTargetMachine(
-      llvm::Triple(triple), chipAKAcpu, features, {}, {}));
-}
-
-static FailureOr<llvm::DataLayout>
-getDataLayout(LLVM::TargetAttrInterface attr) {
-  FailureOr<std::unique_ptr<llvm::TargetMachine>> targetMachine =
-      getTargetMachine(attr);
-  if (failed(targetMachine)) {
-    LDBG("Failed to retrieve the target machine for data layout.\n");
-    return failure();
-  }
-  return (targetMachine.value())->createDataLayout();
-}
-
 struct TargetToDataLayoutPass
     : public LLVM::impl::LLVMTargetToDataLayoutBase<TargetToDataLayoutPass> {
   using LLVM::impl::LLVMTargetToDataLayoutBase<
@@ -67,15 +29,8 @@ struct TargetToDataLayoutPass
   void runOnOperation() override {
     Operation *op = getOperation();
 
-    if (initializeLLVMTargets) {
-      static llvm::once_flag initializeBackendsOnce;
-      llvm::call_once(initializeBackendsOnce, []() {
-        // Ensure that the targets, that LLVM has been configured to support,
-        // are loaded into the TargetRegistry.
-        llvm::InitializeAllTargets();
-        llvm::InitializeAllTargetMCs();
-      });
-    }
+    if (initializeLLVMTargets)
+      LLVM::detail::initializeBackendsOnce();
 
     auto targetAttr = op->getAttrOfType<LLVM::TargetAttrInterface>(
         LLVM::LLVMDialect::getTargetAttrName());
@@ -86,7 +41,8 @@ struct TargetToDataLayoutPass
       return signalPassFailure();
     }
 
-    FailureOr<llvm::DataLayout> dataLayout = getDataLayout(targetAttr);
+    FailureOr<llvm::DataLayout> dataLayout =
+        LLVM::detail::getDataLayout(targetAttr);
     if (failed(dataLayout)) {
       op->emitError() << "failed to obtain llvm::DataLayout for " << targetAttr;
       return signalPassFailure();
diff --git a/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp b/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp
new file mode 100644
index 0000000000000..22153fc883aaa
--- /dev/null
+++ b/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp
@@ -0,0 +1,67 @@
+//===- TargetToTargetFeatures.cpp - extract features from TargetMachine ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Target/LLVMIR/Transforms/Passes.h"
+
+#include "mlir/Dialect/DLTI/DLTI.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Target/LLVMIR/Import.h"
+
+#include "llvm/MC/MCSubtargetInfo.h"
+
+namespace mlir {
+namespace LLVM {
+#define GEN_PASS_DEF_LLVMTARGETTOTARGETFEATURES
+#include "mlir/Target/LLVMIR/Transforms/Passes.h.inc"
+} // namespace LLVM
+} // namespace mlir
+
+using namespace mlir;
+
+struct TargetToTargetFeaturesPass
+    : public LLVM::impl::LLVMTargetToTargetFeaturesBase<TargetToTargetFeaturesPass> {
+  using LLVM::impl::LLVMTargetToTargetFeaturesBase<
+      TargetToTargetFeaturesPass>::LLVMTargetToTargetFeaturesBase;
+
+  void runOnOperation() override {
+    Operation *op = getOperation();
+
+    if (initializeLLVMTargets)
+      LLVM::detail::initializeBackendsOnce();
+
+    auto targetAttr = op->getAttrOfType<LLVM::TargetAttr>(
+        LLVM::LLVMDialect::getTargetAttrName());
+    if (!targetAttr) {
+      op->emitError() << "no LLVM::TargetAttr attribute at key \""
+                      << LLVM::LLVMDialect::getTargetAttrName() << "\"";
+      return signalPassFailure();
+    }
+
+    FailureOr<std::unique_ptr<llvm::TargetMachine>> targetMachine =
+        LLVM::detail::getTargetMachine(targetAttr);
+    if (failed(targetMachine)) {
+      op->emitError() << "failed to obtain llvm::TargetMachine for "
+                      << targetAttr;
+      return signalPassFailure();
+    }
+
+    llvm::MCSubtargetInfo const *subTargetInfo =
+        (*targetMachine)->getMCSubtargetInfo();
+
+    StringRef fullTargetFeaturesStr = subTargetInfo->getFeatureString();
+
+    auto fullTargetFeaturesAttr =
+        LLVM::TargetFeaturesAttr::get(&getContext(), fullTargetFeaturesStr);
+
+    auto updatedTargetAttr =
+        LLVM::TargetAttr::get(&getContext(), targetAttr.getTriple(),
+                              targetAttr.getChip(), fullTargetFeaturesAttr);
+
+    op->setAttr(LLVM::LLVMDialect::getTargetAttrName(), updatedTargetAttr);
+  }
+};
diff --git a/mlir/lib/Target/LLVMIR/Transforms/TargetUtils.cpp b/mlir/lib/Target/LLVMIR/Transforms/TargetUtils.cpp
new file mode 100644
index 0000000000000..5c12ec125c845
--- /dev/null
+++ b/mlir/lib/Target/LLVMIR/Transforms/TargetUtils.cpp
@@ -0,0 +1,70 @@
+//===- TargetUtils.cpp - utils for obtaining generic target backend info --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "mlir/Target/LLVMIR/Transforms/Passes.h"
+
+#include "mlir/Dialect/DLTI/DLTI.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Target/LLVMIR/Import.h"
+
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+
+#define DEBUG_TYPE "mlir-llvm-target-utils"
+#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ")
+#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n")
+
+llvm::once_flag initializeBackendsOnce;
+
+namespace mlir {
+namespace LLVM {
+namespace detail {
+void initializeBackendsOnce() {
+  static llvm::once_flag initializeOnceFlag;
+  llvm::call_once(initializeOnceFlag, []() {
+    // Ensure that the targets, that LLVM has been configured to support,
+    // are loaded into the TargetRegistry.
+    llvm::InitializeAllTargets();
+    llvm::InitializeAllTargetMCs();
+  });
+}
+
+FailureOr<std::unique_ptr<llvm::TargetMachine>>
+getTargetMachine(mlir::LLVM::TargetAttrInterface attr) {
+  StringRef triple = attr.getTriple();
+  StringRef chipAKAcpu = attr.getChip();
+  std::string features =
+      attr.getFeatures() ? attr.getFeatures().getFeaturesString() : "";
+
+  std::string error;
+  const llvm::Target *target =
+      llvm::TargetRegistry::lookupTarget(triple, error);
+  if (!target || !error.empty()) {
+    LDBG("Looking up target '" << triple << "' failed: " << error << "\n");
+    return failure();
+  }
+
+  return std::unique_ptr<llvm::TargetMachine>(target->createTargetMachine(
+      llvm::Triple(triple), chipAKAcpu, features, {}, {}));
+}
+
+FailureOr<llvm::DataLayout>
+getDataLayout(mlir::LLVM::TargetAttrInterface attr) {
+  FailureOr<std::unique_ptr<llvm::TargetMachine>> targetMachine =
+      getTargetMachine(attr);
+  if (failed(targetMachine)) {
+    LDBG("Failed to retrieve the target machine for data layout.\n");
+    return failure();
+  }
+  return (targetMachine.value())->createDataLayout();
+}
+
+} // namespace detail
+} // namespace LLVM
+} // namespace mlir
diff --git a/mlir/test/Dialect/LLVMIR/target-to-data-layout-invalid.mlir b/mlir/test/Target/LLVMIR/target-to-data-layout-invalid.mlir
similarity index 100%
rename from mlir/test/Dialect/LLVMIR/target-to-data-layout-invalid.mlir
rename to mlir/test/Target/LLVMIR/target-to-data-layout-invalid.mlir
diff --git a/mlir/test/Dialect/LLVMIR/target-to-data-layout-no-init.mlir b/mlir/test/Target/LLVMIR/target-to-data-layout-no-init.mlir
similarity index 100%
rename from mlir/test/Dialect/LLVMIR/target-to-data-layout-no-init.mlir
rename to mlir/test/Target/LLVMIR/target-to-data-layout-no-init.mlir
diff --git a/mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir b/mlir/test/Target/LLVMIR/target-to-data-layout.mlir
similarity index 100%
rename from mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir
rename to mlir/test/Target/LLVMIR/target-to-data-layout.mlir

>From ec157172dbf280212ccd5c9c02372e4296703376 Mon Sep 17 00:00:00 2001
From: Rolf Morel <rolf.morel at intel.com>
Date: Fri, 22 Aug 2025 07:33:18 -0700
Subject: [PATCH 3/9] Get feature flags from proper source

Thanks Renato!
---
 .../LLVMIR/Transforms/TargetToTargetFeatures.cpp | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp b/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp
index 22153fc883aaa..34d1981ee11df 100644
--- a/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp
+++ b/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp
@@ -24,7 +24,8 @@ namespace LLVM {
 using namespace mlir;
 
 struct TargetToTargetFeaturesPass
-    : public LLVM::impl::LLVMTargetToTargetFeaturesBase<TargetToTargetFeaturesPass> {
+    : public LLVM::impl::LLVMTargetToTargetFeaturesBase<
+          TargetToTargetFeaturesPass> {
   using LLVM::impl::LLVMTargetToTargetFeaturesBase<
       TargetToTargetFeaturesPass>::LLVMTargetToTargetFeaturesBase;
 
@@ -53,10 +54,19 @@ struct TargetToTargetFeaturesPass
     llvm::MCSubtargetInfo const *subTargetInfo =
         (*targetMachine)->getMCSubtargetInfo();
 
-    StringRef fullTargetFeaturesStr = subTargetInfo->getFeatureString();
+    const std::vector<llvm::SubtargetFeatureKV> enabledFeatures =
+        subTargetInfo->getEnabledProcessorFeatures();
+
+    auto plussedFeatures = llvm::to_vector(
+        llvm::map_range(enabledFeatures, [](llvm::SubtargetFeatureKV feature) {
+          return std::string("+") + feature.Key;
+        }));
+
+    auto plussedFeaturesRefs = llvm::to_vector(llvm::map_range(
+        plussedFeatures, [](auto &it) { return StringRef(it.c_str()); }));
 
     auto fullTargetFeaturesAttr =
-        LLVM::TargetFeaturesAttr::get(&getContext(), fullTargetFeaturesStr);
+        LLVM::TargetFeaturesAttr::get(&getContext(), plussedFeaturesRefs);
 
     auto updatedTargetAttr =
         LLVM::TargetAttr::get(&getContext(), targetAttr.getTriple(),

>From 32c9cea9d5ee18dcfcc3e92952810c5ba2707fe7 Mon Sep 17 00:00:00 2001
From: Rolf Morel <rolf.morel at intel.com>
Date: Fri, 22 Aug 2025 09:53:18 -0700
Subject: [PATCH 4/9] Add test cases

---
 ...et-to-data-layout-and-target-features.mlir | 137 ++++++++++++++++++
 .../Target/LLVMIR/target-to-data-layout.mlir  |  75 ----------
 2 files changed, 137 insertions(+), 75 deletions(-)
 create mode 100644 mlir/test/Target/LLVMIR/target-to-data-layout-and-target-features.mlir
 delete mode 100644 mlir/test/Target/LLVMIR/target-to-data-layout.mlir

diff --git a/mlir/test/Target/LLVMIR/target-to-data-layout-and-target-features.mlir b/mlir/test/Target/LLVMIR/target-to-data-layout-and-target-features.mlir
new file mode 100644
index 0000000000000..b6b2976860541
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/target-to-data-layout-and-target-features.mlir
@@ -0,0 +1,137 @@
+// REQUIRES: target=x86{{.*}}
+
+// RUN: mlir-opt -llvm-target-to-data-layout -split-input-file %s | FileCheck --check-prefix=DATA-LAYOUT %s
+// RUN: mlir-opt -llvm-target-to-target-features -split-input-file %s | FileCheck --check-prefix=TARGET-FEATURES %s
+
+// DATA-LAYOUT: module attributes
+// DATA-LAYOUT-SAME: dlti.dl_spec = #dlti.dl_spec
+// DATA-LAYOUT-SAME:   "dlti.endianness" = "little"
+// DATA-LAYOUT-SAME: llvm.target = #llvm.target<
+// DATA-LAYOUT-SAME:   triple = "x86_64-unknown-linux"
+// DATA-LAYOUT-SAME:   chip = ""
+// DATA-LAYOUT-NOT:    features =
+
+// TARGET-FEATURES: module attributes
+// TARGET-FEATURES-NOT:  dlti.dl_spec
+// TARGET-FEATURES-SAME: llvm.target = #llvm.target<
+// TARGET-FEATURES-SAME:   triple = "x86_64-unknown-linux"
+// TARGET-FEATURES-SAME:   chip = ""
+// TARGET-FEATURES-SAME:   features = <[
+// TARGET-FEATURES-SAME:     +64bit
+// TARGET-FEATURES-NOT:      +avx
+// TARGET-FEATURES-SAME:     +sse
+// TARGET-FEATURES-NOT:      +mmx
+
+module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
+                                               chip = ""> } {
+}
+
+// -----
+
+// DATA-LAYOUT: module attributes
+// DATA-LAYOUT-SAME: dlti.dl_spec = #dlti.dl_spec
+// DATA-LAYOUT-SAME:   "dlti.endianness" = "little"
+// DATA-LAYOUT-SAME: llvm.target = #llvm.target<
+// DATA-LAYOUT-SAME:   triple = "x86_64-unknown-linux"
+// DATA-LAYOUT-SAME:   chip = ""
+// DATA-LAYOUT-SAME:   features = <["+mmx", "+sse"]>
+
+// TARGET-FEATURES: module attributes
+// TARGET-FEATURES-NOT:  dlti.dl_spec
+// TARGET-FEATURES-SAME: llvm.target = #llvm.target<
+// TARGET-FEATURES-SAME:   triple = "x86_64-unknown-linux"
+// TARGET-FEATURES-SAME:   chip = ""
+// TARGET-FEATURES-SAME:   features = <[
+// TARGET-FEATURES-SAME:     +64bit
+// TARGET-FEATURES-NOT:      +avx
+// TARGET-FEATURES-SAME:     +mmx
+// TARGET-FEATURES-SAME:     +sse
+
+module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
+                                               chip = "",
+                                               features = <["+mmx", "+sse"]>> } {
+}
+
+// -----
+
+// DATA-LAYOUT: module attributes
+// DATA-LAYOUT-SAME: dlti.dl_spec = #dlti.dl_spec
+// DATA-LAYOUT-SAME:   "dlti.endianness" = "little"
+// DATA-LAYOUT-SAME: llvm.target = #llvm.target<
+// DATA-LAYOUT-SAME:   triple = "x86_64-unknown-linux"
+// DATA-LAYOUT-SAME:   chip = "skylake"
+// DATA-LAYOUT-NOT:    features =
+
+// TARGET-FEATURES: module attributes
+// TARGET-FEATURES-NOT:  dlti.dl_spec
+// TARGET-FEATURES-SAME: llvm.target = #llvm.target<
+// TARGET-FEATURES-SAME:   triple = "x86_64-unknown-linux"
+// TARGET-FEATURES-SAME:   chip = "skylake"
+// TARGET-FEATURES-SAME:   features = <[
+// TARGET-FEATURES-SAME:     +64bit
+// TARGET-FEATURES-SAME:     +avx
+// TARGET-FEATURES-SAME:     +avx2
+// TARGET-FEATURES-NOT:      +avx512f
+// TARGET-FEATURES-SAME:     +mmx
+// TARGET-FEATURES-SAME:     +sse
+
+module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
+                                               chip = "skylake"> } {
+}
+
+// -----
+
+// DATA-LAYOUT: module attributes
+// DATA-LAYOUT-SAME: dlti.dl_spec = #dlti.dl_spec
+// DATA-LAYOUT-SAME:   "dlti.endianness" = "little"
+// DATA-LAYOUT-SAME: llvm.target = #llvm.target<
+// DATA-LAYOUT-SAME:   triple = "x86_64-unknown-linux"
+// DATA-LAYOUT-SAME:   chip = "skylake"
+// DATA-LAYOUT-SAME:   features = <["-sse", "-avx"]>
+
+// TARGET-FEATURES: module attributes
+// TARGET-FEATURES-NOT:  dlti.dl_spec
+// TARGET-FEATURES-SAME: llvm.target = #llvm.target<
+// TARGET-FEATURES-SAME:   triple = "x86_64-unknown-linux"
+// TARGET-FEATURES-SAME:   chip = "skylake"
+// TARGET-FEATURES-SAME:   features = <[
+// TARGET-FEATURES-SAME:     +64bit
+// TARGET-FEATURES-NOT:      +avx
+// TARGET-FEATURES-NOT:      +avx2
+// TARGET-FEATURES-SAME:     +mmx
+// TARGET-FEATURES-NOT:      +sse
+
+module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
+                                               chip = "skylake",
+                                               features = <["-sse", "-avx"]>> } {
+}
+
+// -----
+
+// DATA-LAYOUT: module attributes
+// DATA-LAYOUT-SAME: dlti.dl_spec = #dlti.dl_spec
+// DATA-LAYOUT-SAME:   "dlti.endianness" = "little"
+// DATA-LAYOUT-SAME:   index = 32
+// DATA-LAYOUT-SAME: llvm.target = #llvm.target<
+// DATA-LAYOUT-SAME:   triple = "x86_64-unknown-linux"
+// DATA-LAYOUT-SAME:   chip = "skylake"
+// DATA-LAYOUT-SAME:   features = <["-mmx", "+avx512f"]>
+
+// TARGET-FEATURES: module attributes
+// TARGET-FEATURES-SAME: #dlti.dl_spec<index = 32 : i64>
+// TARGET-FEATURES-SAME: llvm.target = #llvm.target<
+// TARGET-FEATURES-SAME:   triple = "x86_64-unknown-linux"
+// TARGET-FEATURES-SAME:   chip = "skylake"
+// TARGET-FEATURES-SAME:   features = <[
+// TARGET-FEATURES-SAME:     +64bit
+// TARGET-FEATURES-SAME:     +avx
+// TARGET-FEATURES-SAME:     +avx2
+// TARGET-FEATURES-SAME:     +avx512f
+// TARGET-FEATURES-NOT:      +mmx
+// TARGET-FEATURES-SAME:     +sse
+
+module attributes { dlti.dl_spec = #dlti.dl_spec<index = 32>,
+                    llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
+                                               chip = "skylake",
+                                               features = <["-mmx", "+avx512f"]>> } {
+}
diff --git a/mlir/test/Target/LLVMIR/target-to-data-layout.mlir b/mlir/test/Target/LLVMIR/target-to-data-layout.mlir
deleted file mode 100644
index 17db9bc5e114b..0000000000000
--- a/mlir/test/Target/LLVMIR/target-to-data-layout.mlir
+++ /dev/null
@@ -1,75 +0,0 @@
-// REQUIRES: target=x86{{.*}}
-// RUN: mlir-opt -llvm-target-to-data-layout -split-input-file %s | FileCheck %s
-
-// CHECK: module attributes
-// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec
-// CHECK-SAME:   "dlti.endianness" = "little"
-// CHECK-SAME: llvm.target = #llvm.target<
-// CHECK-SAME:   triple = "x86_64-unknown-linux"
-// CHECK-SAME:   chip = ""
-// CHECK-NOT:    features =
-
-module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
-                                               chip = ""> } {
-}
-
-// -----
-
-// CHECK: module attributes
-// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec
-// CHECK-SAME:   "dlti.endianness" = "little"
-// CHECK-SAME: llvm.target = #llvm.target<
-// CHECK-SAME:   triple = "x86_64-unknown-linux"
-// CHECK-SAME:   chip = ""
-// CHECK-SAME:   features = "+mmx,+sse"
-
-module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
-                                               chip = "",
-                                               features = <["+mmx","+sse"]>> } {
-}
-
-// -----
-
-// CHECK: module attributes
-// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec
-// CHECK-SAME:   "dlti.endianness" = "little"
-// CHECK-SAME: llvm.target = #llvm.target<
-// CHECK-SAME:   triple = "x86_64-unknown-linux"
-// CHECK-SAME:   chip = "skylake"
-// CHECK-NOT:    features =
-
-module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
-                                               chip = "skylake"> } {
-}
-
-// -----
-
-// CHECK: module attributes
-// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec
-// CHECK-SAME:   "dlti.endianness" = "little"
-// CHECK-SAME: llvm.target = #llvm.target<
-// CHECK-SAME:   triple = "x86_64-unknown-linux"
-// CHECK-SAME:   chip = "skylake"
-// CHECK-SAME:   features = "+mmx,+sse">
-
-module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
-                                               chip = "skylake",
-                                               features = <["+mmx","+sse"]>> } {
-}
-
-// -----
-
-// CHECK: module attributes
-// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec
-// CHECK-SAME:   "dlti.endianness" = "little"
-// CHECK-SAME:   index = 32
-// CHECK-SAME: llvm.target = #llvm.target<
-// CHECK-SAME:   triple = "x86_64-unknown-linux"
-// CHECK-SAME:   chip = "skylake"
-// CHECK-SAME:   features = "+mmx,+sse"
-
-module attributes { dlti.dl_spec = #dlti.dl_spec<index = 32>,
-                    llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
-                                               chip = "skylake",
-                                               features = <["+mmx","+sse"]>> } {
-}

>From facc90735ca2fac6565070a590003b3e0d1fe846 Mon Sep 17 00:00:00 2001
From: Rolf Morel <rolf.morel at intel.com>
Date: Sat, 23 Aug 2025 05:26:30 -0700
Subject: [PATCH 5/9] Add comment explaining file structuring

---
 .../mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td    | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td
index bc60591514c28..9ee52c3dfc7bf 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMTargetFeaturesAttrDefs.td
@@ -1,10 +1,17 @@
-//===-- LLVMAttrDefs.td - LLVM Attributes definition file --*- tablegen -*-===//
+//===-- LLVMTargetFeaturesAttrDefs.td ----------------------*- tablegen -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+//
+// Separate out the LLVM_TargetFeaturesAttr definition from LLVMAttrDefs.td so
+// as to break a circular dependency between LLVMInterfaces.td and LLVMAttrDefs.
+// In particular, the TargetAttrInterface requires LLVMTargetFeaturesAttr
+// and attrs in LLVMAttrDefs.td require interfaces from LLVMInterfaces.td.
+//
+//===----------------------------------------------------------------------===//
 
 #ifndef LLVMIR_TARGETFEATURESATTRDEFS
 #define LLVMIR_TARGETFEATURESATTRDEFS

>From 36c3ba46c6a1d6d5c64d5214ad643ad27d978d7f Mon Sep 17 00:00:00 2001
From: Rolf Morel <rolf.morel at intel.com>
Date: Sat, 23 Aug 2025 05:27:13 -0700
Subject: [PATCH 6/9] Add tests exercising DLTI

---
 .../target-to-target-features-dlti-query.mlir | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 mlir/test/Target/LLVMIR/target-to-target-features-dlti-query.mlir

diff --git a/mlir/test/Target/LLVMIR/target-to-target-features-dlti-query.mlir b/mlir/test/Target/LLVMIR/target-to-target-features-dlti-query.mlir
new file mode 100644
index 0000000000000..da2455a33859f
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/target-to-target-features-dlti-query.mlir
@@ -0,0 +1,50 @@
+// REQUIRES: target=x86{{.*}}
+
+// RUN: mlir-opt -transform-interpreter -split-input-file %s | FileCheck %s
+
+// Check that processor features, like AVX, are appropriated derived and queryable.
+
+// expected-remark @+2 {{attr associated to ["features", "+avx"] = unit}}
+// expected-remark @below {{attr associated to ["features", "avx"] = true}}
+module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
+                                               chip = "skylake">,
+                    test.dl_spec = #dlti.dl_spec<index = 32> } {
+  func.func private @f()
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg: !transform.any_op) {
+    %funcs = transform.structured.match ops{["func.func"]} in %arg : (!transform.any_op) -> !transform.any_op
+    %module = transform.get_parent_op %funcs : (!transform.any_op) -> !transform.any_op
+    %mod = transform.apply_registered_pass "llvm-target-to-target-features" to %module : (!transform.any_op) -> !transform.any_op
+    %plus_avx = transform.dlti.query ["features", "+avx"] at %mod : (!transform.any_op) -> !transform.any_param
+    transform.debug.emit_param_as_remark %plus_avx, "attr associated to [\"features\", \"+avx\"] =" at %mod : !transform.any_param, !transform.any_op
+    %avx = transform.dlti.query ["features", "avx"] at %mod : (!transform.any_op) -> !transform.any_param
+    transform.debug.emit_param_as_remark %avx, "attr associated to [\"features\", \"avx\"] =" at %mod : !transform.any_param, !transform.any_op
+    transform.yield
+  }
+}
+
+// -----
+
+// Check that features that a processor does not have, AVX512f in this case,
+// aren't derived and hence that querying for them will fail.
+
+// expected-error @+2 {{target op of failed DLTI query}}
+// expected-note @below {{key "+avx512f" has no DLTI-mapping per attr: #llvm.target_features<[}}
+module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
+                                               chip = "skylake">,
+                    test.dl_spec = #dlti.dl_spec<index = 32> } {
+  func.func private @f()
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg: !transform.any_op) {
+    %funcs = transform.structured.match ops{["func.func"]} in %arg : (!transform.any_op) -> !transform.any_op
+    %module = transform.get_parent_op %funcs : (!transform.any_op) -> !transform.any_op
+    %mod = transform.apply_registered_pass "llvm-target-to-target-features" to %module : (!transform.any_op) -> !transform.any_op
+    // expected-error @below {{'transform.dlti.query' op failed to apply}}
+    %param = transform.dlti.query ["features", "+avx512f"] at %mod : (!transform.any_op) -> !transform.any_param
+    transform.yield
+  }
+}

>From b3e91bf7a82af38338ffd8cf208afc1efc1ec0e1 Mon Sep 17 00:00:00 2001
From: Rolf Morel <rolf.morel at intel.com>
Date: Sat, 23 Aug 2025 05:37:51 -0700
Subject: [PATCH 7/9] Update DLTI tests

---
 .../target-to-target-features-dlti-query.mlir | 34 ++++++++++++++++---
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/mlir/test/Target/LLVMIR/target-to-target-features-dlti-query.mlir b/mlir/test/Target/LLVMIR/target-to-target-features-dlti-query.mlir
index da2455a33859f..b21a4ea8446e2 100644
--- a/mlir/test/Target/LLVMIR/target-to-target-features-dlti-query.mlir
+++ b/mlir/test/Target/LLVMIR/target-to-target-features-dlti-query.mlir
@@ -1,6 +1,6 @@
 // REQUIRES: target=x86{{.*}}
 
-// RUN: mlir-opt -transform-interpreter -split-input-file %s | FileCheck %s
+// RUN: mlir-opt -transform-interpreter -split-input-file %s --verify-diagnostics
 
 // Check that processor features, like AVX, are appropriated derived and queryable.
 
@@ -25,13 +25,39 @@ module attributes {transform.with_named_sequence} {
   }
 }
 
+
+// -----
+
+// Check that newer processor features, like AMX, are appropriated derived and queryable.
+
+// expected-remark @+2 {{attr associated to ["features", "+amx-bf16"] = unit}}
+// expected-remark @below {{attr associated to ["features", "amx-bf16"] = true}}
+module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
+                                               chip = "sapphirerapids">,
+                    test.dl_spec = #dlti.dl_spec<index = 32> } {
+  func.func private @f()
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg: !transform.any_op) {
+    %funcs = transform.structured.match ops{["func.func"]} in %arg : (!transform.any_op) -> !transform.any_op
+    %module = transform.get_parent_op %funcs : (!transform.any_op) -> !transform.any_op
+    %mod = transform.apply_registered_pass "llvm-target-to-target-features" to %module : (!transform.any_op) -> !transform.any_op
+    %plus_avx = transform.dlti.query ["features", "+amx-bf16"] at %mod : (!transform.any_op) -> !transform.any_param
+    transform.debug.emit_param_as_remark %plus_avx, "attr associated to [\"features\", \"+amx-bf16\"] =" at %mod : !transform.any_param, !transform.any_op
+    %avx = transform.dlti.query ["features", "amx-bf16"] at %mod : (!transform.any_op) -> !transform.any_param
+    transform.debug.emit_param_as_remark %avx, "attr associated to [\"features\", \"amx-bf16\"] =" at %mod : !transform.any_param, !transform.any_op
+    transform.yield
+  }
+}
+
 // -----
 
-// Check that features that a processor does not have, AVX512f in this case,
+// Check that features that a processor does not have, AMX in this case,
 // aren't derived and hence that querying for them will fail.
 
 // expected-error @+2 {{target op of failed DLTI query}}
-// expected-note @below {{key "+avx512f" has no DLTI-mapping per attr: #llvm.target_features<[}}
+// expected-note @below {{key "+amx-bf16" has no DLTI-mapping per attr: #llvm.target_features}}
 module attributes { llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
                                                chip = "skylake">,
                     test.dl_spec = #dlti.dl_spec<index = 32> } {
@@ -44,7 +70,7 @@ module attributes {transform.with_named_sequence} {
     %module = transform.get_parent_op %funcs : (!transform.any_op) -> !transform.any_op
     %mod = transform.apply_registered_pass "llvm-target-to-target-features" to %module : (!transform.any_op) -> !transform.any_op
     // expected-error @below {{'transform.dlti.query' op failed to apply}}
-    %param = transform.dlti.query ["features", "+avx512f"] at %mod : (!transform.any_op) -> !transform.any_param
+    %param = transform.dlti.query ["features", "+amx-bf16"] at %mod : (!transform.any_op) -> !transform.any_param
     transform.yield
   }
 }

>From 27a974909ef3b194e113d2da76a88f97274d5aa3 Mon Sep 17 00:00:00 2001
From: Rolf Morel <rolf.morel at intel.com>
Date: Sat, 23 Aug 2025 06:35:30 -0700
Subject: [PATCH 8/9] Address Mehdi's comments

---
 .../mlir/Target/LLVMIR/Transforms/Passes.h        | 15 ---------------
 .../mlir/Target/LLVMIR/Transforms/Passes.td       |  7 +++++--
 .../LLVMIR/Transforms/TargetToDataLayout.cpp      |  1 +
 .../LLVMIR/Transforms/TargetToTargetFeatures.cpp  |  1 +
 mlir/lib/Target/LLVMIR/Transforms/TargetUtils.cpp |  7 +++----
 5 files changed, 10 insertions(+), 21 deletions(-)

diff --git a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h
index db8feb3ae2396..22e6fadfb37e9 100644
--- a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h
+++ b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h
@@ -9,26 +9,11 @@
 #ifndef MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES_H
 #define MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES_H
 
-#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
 #include "mlir/Pass/Pass.h"
-#include "llvm/Support/Threading.h"
-#include "llvm/Target/TargetMachine.h"
 
 namespace mlir {
-
 namespace LLVM {
 
-namespace detail {
-
-void initializeBackendsOnce();
-
-FailureOr<std::unique_ptr<llvm::TargetMachine>>
-getTargetMachine(mlir::LLVM::TargetAttrInterface attr);
-
-FailureOr<llvm::DataLayout> getDataLayout(mlir::LLVM::TargetAttrInterface attr);
-
-} // namespace detail
-
 #define GEN_PASS_DECL
 #define GEN_PASS_REGISTRATION
 #include "mlir/Target/LLVMIR/Transforms/Passes.h.inc"
diff --git a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
index b01baa8744ee3..843ac7cac4b87 100644
--- a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
+++ b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
@@ -28,10 +28,13 @@ def LLVMTargetToDataLayout : Pass<"llvm-target-to-data-layout"> {
 }
 
 def LLVMTargetToTargetFeatures : Pass<"llvm-target-to-target-features"> {
-  let summary = "TODO";
+  let summary = "Update attached #llvm.target's features per the described target";
   let dependentDialects = ["mlir::DLTIDialect"];
   let description = [{
-    TODO
+    Obtain the TargetMachine specified by the attached #llvm.target's attributes
+    and obtain from it the full list of features of the selected target. Updates
+    the attached #llvm.target so that its features reflect the full list of
+    features.
   }];
   let options = [
     Option<"initializeLLVMTargets", "initialize-llvm-targets", "bool",
diff --git a/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp b/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
index 250d6162fd780..c0f9ceb6313d0 100644
--- a/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
+++ b/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Target/LLVMIR/Transforms/Passes.h"
+#include "mlir/Target/LLVMIR/Transforms/TargetUtils.h"
 
 #include "mlir/Dialect/DLTI/DLTI.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
diff --git a/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp b/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp
index 34d1981ee11df..4a1ca46af0f2a 100644
--- a/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp
+++ b/mlir/lib/Target/LLVMIR/Transforms/TargetToTargetFeatures.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Target/LLVMIR/Transforms/Passes.h"
+#include "mlir/Target/LLVMIR/Transforms/TargetUtils.h"
 
 #include "mlir/Dialect/DLTI/DLTI.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
diff --git a/mlir/lib/Target/LLVMIR/Transforms/TargetUtils.cpp b/mlir/lib/Target/LLVMIR/Transforms/TargetUtils.cpp
index 5c12ec125c845..2b77b7d135047 100644
--- a/mlir/lib/Target/LLVMIR/Transforms/TargetUtils.cpp
+++ b/mlir/lib/Target/LLVMIR/Transforms/TargetUtils.cpp
@@ -13,12 +13,11 @@
 
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/DebugLog.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Target/TargetMachine.h"
 
 #define DEBUG_TYPE "mlir-llvm-target-utils"
-#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ")
-#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n")
 
 llvm::once_flag initializeBackendsOnce;
 
@@ -46,7 +45,7 @@ getTargetMachine(mlir::LLVM::TargetAttrInterface attr) {
   const llvm::Target *target =
       llvm::TargetRegistry::lookupTarget(triple, error);
   if (!target || !error.empty()) {
-    LDBG("Looking up target '" << triple << "' failed: " << error << "\n");
+    LDBG() << "Looking up target '" << triple << "' failed: " << error << "\n";
     return failure();
   }
 
@@ -59,7 +58,7 @@ getDataLayout(mlir::LLVM::TargetAttrInterface attr) {
   FailureOr<std::unique_ptr<llvm::TargetMachine>> targetMachine =
       getTargetMachine(attr);
   if (failed(targetMachine)) {
-    LDBG("Failed to retrieve the target machine for data layout.\n");
+    LDBG() << "Failed to retrieve the target machine for data layout.\n";
     return failure();
   }
   return (targetMachine.value())->createDataLayout();

>From 1f2967518ab0ef92b8d2d0ea53e7abde9d376857 Mon Sep 17 00:00:00 2001
From: Rolf Morel <rolf.morel at intel.com>
Date: Sat, 23 Aug 2025 07:35:11 -0700
Subject: [PATCH 9/9] Add missing file

---
 .../Target/LLVMIR/Transforms/TargetUtils.h    | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 mlir/include/mlir/Target/LLVMIR/Transforms/TargetUtils.h

diff --git a/mlir/include/mlir/Target/LLVMIR/Transforms/TargetUtils.h b/mlir/include/mlir/Target/LLVMIR/Transforms/TargetUtils.h
new file mode 100644
index 0000000000000..2930733ee83d9
--- /dev/null
+++ b/mlir/include/mlir/Target/LLVMIR/Transforms/TargetUtils.h
@@ -0,0 +1,35 @@
+//===- TargetUtils.h - Utils to obtain LLVM's TargetMachine and DataLayout ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_TARGET_LLVMIR_TRANSFORMS_TARGETUTILS_H
+#define MLIR_TARGET_LLVMIR_TRANSFORMS_TARGETUTILS_H
+
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace mlir {
+namespace LLVM {
+namespace detail {
+/// Idempotent helper to register/initialize all backends that LLVM has been
+/// configured to support. Only runs the first time it is called.
+void initializeBackendsOnce();
+
+/// Helper to obtain the TargetMachine specified by the properties of the
+/// TargetAttrInterface-implementing attribute.
+FailureOr<std::unique_ptr<llvm::TargetMachine>>
+getTargetMachine(mlir::LLVM::TargetAttrInterface attr);
+
+/// Helper to obtain the DataLayout of the target specified by the properties of
+/// the TargetAttrInterface-implementing attribute.
+FailureOr<llvm::DataLayout> getDataLayout(mlir::LLVM::TargetAttrInterface attr);
+} // namespace detail
+} // namespace LLVM
+} // namespace mlir
+
+#endif // MLIR_TARGET_LLVMIR_TRANSFORMS_TARGETUTILS_H



More information about the Mlir-commits mailing list