[Mlir-commits] [mlir] [MLIR][DLTI] Introduce DLTIQueryInterface and impl for DLTI attrs (PR #104595)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Aug 16 07:29:49 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir

@llvm/pr-subscribers-mlir-dlti

Author: Rolf Morel (rolfmorel)

<details>
<summary>Changes</summary>

This new interface is supposed to capture the core functionality of DLTI: querying for values at keys. As such this new interface unifies the ability to query DLTI attributes in a single method: query(). All existing DLTI interfaces exposing their own query methods now 1) now extend this new interface and 2) provide a default implementation for `query()`.

As DLTIQueryInterface::query() returns an attribute, it naturally enables recursive queries on nested DLTI attrs. A utility function, `dlti::query()`, implements the logic for nested lookups.

A new `#dlti.map` attribute is introduced to capture the most generic form of a finite DLTI-mapping. One of the benefits is that it allows for more easily encoding hierachical information that is suitably queryable, i.e. by means of nested attributes.

In line with the above, `transform.query.op` is modified so as to take an arbitrary number of keys and to perform a nested lookup using the above utility function.

---

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


11 Files Affected:

- (modified) mlir/include/mlir/Dialect/DLTI/DLTI.h (+11) 
- (modified) mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td (+66-24) 
- (modified) mlir/include/mlir/Dialect/DLTI/DLTIBase.td (+7-2) 
- (modified) mlir/include/mlir/Dialect/DLTI/TransformOps/DLTITransformOps.td (+24-16) 
- (modified) mlir/include/mlir/Dialect/Transform/Utils/DiagnosedSilenceableFailure.h (+7) 
- (modified) mlir/include/mlir/Interfaces/DataLayoutInterfaces.h (+1) 
- (modified) mlir/include/mlir/Interfaces/DataLayoutInterfaces.td (+56-4) 
- (modified) mlir/lib/Dialect/DLTI/DLTI.cpp (+73-4) 
- (modified) mlir/lib/Dialect/DLTI/TransformOps/DLTITransformOps.cpp (+8-27) 
- (modified) mlir/test/Dialect/DLTI/query.mlir (+119-48) 
- (modified) mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp (+8) 


``````````diff
diff --git a/mlir/include/mlir/Dialect/DLTI/DLTI.h b/mlir/include/mlir/Dialect/DLTI/DLTI.h
index 6e2623e084be52..235961aa97aa93 100644
--- a/mlir/include/mlir/Dialect/DLTI/DLTI.h
+++ b/mlir/include/mlir/Dialect/DLTI/DLTI.h
@@ -33,6 +33,17 @@ DataLayoutSpecInterface getDataLayoutSpec(Operation *op);
 /// DataLayoutOpInterface, a method on ModuleOp, or an attribute implementing
 /// the interface, on `op` and else on `op`'s ancestors in turn.
 TargetSystemSpecInterface getTargetSystemSpec(Operation *op);
+
+/// Retrieve the first `DLTIQueryInterface`-implementing attribute that is
+/// attached to `op` or such an attr on as close as possible an ancestor. The
+/// op the attribute is attached to is returned as well.
+std::pair<DLTIQueryInterface, Operation *> getClosestQueryable(Operation *op);
+
+/// Perform a DLTI-query at `op`, recursively querying each key of `keys` on
+/// `DLTIQueryInterface`-implementing attrs, the first of which is obtained from
+/// `op`. When provided, (nested) lookup failure notes are attached to `diag`.
+FailureOr<Attribute> query(Operation *op, ArrayRef<StringAttr> keys,
+                           InFlightDiagnostic *diag = nullptr);
 } // namespace dlti
 } // namespace mlir
 
diff --git a/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td b/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
index 443e3128b4acb3..9c82e2cf111750 100644
--- a/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
+++ b/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
@@ -10,6 +10,7 @@
 #define MLIR_DIALECT_DLTI_DLTIATTRS_TD
 
 include "mlir/Dialect/DLTI/DLTI.td"
+include "mlir/Interfaces/DataLayoutInterfaces.td"
 include "mlir/IR/AttrTypeBase.td"
 
 class DLTIAttr<string name, list<Trait> traits = [],
@@ -20,13 +21,8 @@ class DLTIAttr<string name, list<Trait> traits = [],
 // DataLayoutEntryAttr
 //===----------------------------------------------------------------------===//
 
-def DataLayoutEntryTrait
-    : NativeAttrTrait<"DataLayoutEntryInterface::Trait"> {
-  let cppNamespace = "::mlir";
-}
-
 def DLTI_DataLayoutEntryAttr :
-    DLTIAttr<"DataLayoutEntry", [DataLayoutEntryTrait]> {
+    DLTIAttr<"DataLayoutEntry", [DataLayoutEntryInterface]> {
   let summary = "An attribute to represent an entry of a data layout specification.";
   let description = [{
     A data layout entry attribute is a key-value pair where the key is a type or
@@ -53,13 +49,9 @@ def DLTI_DataLayoutEntryAttr :
 //===----------------------------------------------------------------------===//
 // DataLayoutSpecAttr
 //===----------------------------------------------------------------------===//
-def DataLayoutSpecTrait
-    : NativeAttrTrait<"DataLayoutSpecInterface::Trait"> {
-  let cppNamespace = "::mlir";
-}
 
 def DLTI_DataLayoutSpecAttr :
-    DLTIAttr<"DataLayoutSpec", [DataLayoutSpecTrait]> {
+    DLTIAttr<"DataLayoutSpec", [DataLayoutSpecInterface]> {
   let summary = "An attribute to represent a data layout specification.";
   let description = [{
     A data layout specification is a list of entries that specify (partial) data
@@ -78,7 +70,7 @@ def DLTI_DataLayoutSpecAttr :
     /// same key as the newer entries if the entries are compatible. Returns null
     /// if the specifications are not compatible.
     DataLayoutSpecAttr combineWith(ArrayRef<DataLayoutSpecInterface> specs) const;
-  
+
     /// Returns the endiannes identifier.
     StringAttr getEndiannessIdentifier(MLIRContext *context) const;
 
@@ -93,6 +85,54 @@ def DLTI_DataLayoutSpecAttr :
 
     /// Returns the stack alignment identifier.
     StringAttr getStackAlignmentIdentifier(MLIRContext *context) const;
+
+    /// Returns the attribute associated with the key.
+    FailureOr<Attribute> query(DataLayoutEntryKey key) {
+      return llvm::cast<mlir::DataLayoutSpecInterface>(*this).queryHelper(key);
+    }
+  }];
+}
+
+def DLTI_MapAttr : DLTIAttr<"Map", [DLTIQueryInterface]> {
+  let summary = "A mapping of DLTI-information by way of key-value pairs";
+  let description = [{
+    A data layout and target information map is a list of entries is
+    effectively a dictionary mapping DLTI-related keys to DLTI-related values.
+
+    Its main purpose is to facilate querying IR for arbitrary DLTI-related
+    key-value associations. Note that facility functions exist to perform
+    nested lookups on nested DLTI map attributes.
+
+    Consider the following shallow usage of a DLTI-map
+    ```
+    #dlti.map<#dlti.dl_entry<"CPU::cache::L1::size_in_bytes", 65536 : i32>>
+    ```
+    versus nested maps, which make it possible to obtain sub-dictionaries of
+    related information (with the following example making use of other
+    attributes that also implement the `DLTIQueryInterface`):
+    ```
+    #dlti.target_system_spec<"CPU":
+      #dlti.target_device_spec<#dlti.dl_entry<"cache",
+        #dlti.map<#dlti.dl_entry<"L1",
+          #dlti.map<#dlti.dl_entry<"size_in_bytes", 65536 : i32>>,
+                  #dlti.dl_entry<"L1d",
+          #dlti.map<#dlti.dl_entry<"size_in_bytes", 32768 : i32>> >>>>
+    ```
+   }];
+  let parameters = (ins
+    ArrayRefParameter<"DataLayoutEntryInterface", "">:$entries
+  );
+  let mnemonic = "map";
+  let genVerifyDecl = 1;
+  let assemblyFormat = "`<` $entries `>`";
+  let extraClassDeclaration = [{
+    /// Returns the attribute associated with the key.
+    FailureOr<Attribute> query(DataLayoutEntryKey key) {
+      for (DataLayoutEntryInterface entry : getEntries())
+        if (entry.getKey() == key)
+            return entry.getValue();
+      return ::mlir::failure();
+    }
   }];
 }
 
@@ -100,13 +140,8 @@ def DLTI_DataLayoutSpecAttr :
 // TargetSystemSpecAttr
 //===----------------------------------------------------------------------===//
 
-def TargetSystemSpecTrait
-    : NativeAttrTrait<"TargetSystemSpecInterface::Trait"> {
-  let cppNamespace = "::mlir";
-}
-
 def DLTI_TargetSystemSpecAttr :
-    DLTIAttr<"TargetSystemSpec", [TargetSystemSpecTrait]> {
+    DLTIAttr<"TargetSystemSpec", [TargetSystemSpecInterface]> {
   let summary = "An attribute to represent target system specification.";
   let description = [{
     A system specification describes the overall system containing
@@ -136,6 +171,11 @@ def DLTI_TargetSystemSpecAttr :
     std::optional<TargetDeviceSpecInterface>
     getDeviceSpecForDeviceID(
       TargetSystemSpecInterface::DeviceID deviceID);
+
+    /// Returns the attribute associated with the key.
+    FailureOr<Attribute> query(DataLayoutEntryKey key) const {
+      return llvm::cast<mlir::TargetSystemSpecInterface>(*this).queryHelper(key);
+    }
   }];
   let extraClassDefinition = [{
     std::optional<TargetDeviceSpecInterface>
@@ -154,13 +194,8 @@ def DLTI_TargetSystemSpecAttr :
 // TargetDeviceSpecAttr
 //===----------------------------------------------------------------------===//
 
-def TargetDeviceSpecTrait
-    : NativeAttrTrait<"TargetDeviceSpecInterface::Trait"> {
-  let cppNamespace = "::mlir";
-}
-
 def DLTI_TargetDeviceSpecAttr :
-    DLTIAttr<"TargetDeviceSpec", [TargetDeviceSpecTrait]> {
+    DLTIAttr<"TargetDeviceSpec", [TargetDeviceSpecInterface]> {
   let summary = "An attribute to represent target device specification.";
   let description = [{
     Each device specification describes a single device and its
@@ -179,6 +214,13 @@ def DLTI_TargetDeviceSpecAttr :
   let mnemonic = "target_device_spec";
   let genVerifyDecl = 1;
   let assemblyFormat = "`<` $entries `>`";
+
+  let extraClassDeclaration = [{
+    /// Returns the attribute associated with the key.
+    FailureOr<Attribute> query(DataLayoutEntryKey key) const {
+      return llvm::cast<mlir::TargetDeviceSpecInterface>(*this).queryHelper(key);
+    }
+  }];
 }
 
 #endif  // MLIR_DIALECT_DLTI_DLTIATTRS_TD
diff --git a/mlir/include/mlir/Dialect/DLTI/DLTIBase.td b/mlir/include/mlir/Dialect/DLTI/DLTIBase.td
index e26fbdb146645c..f84149c43e0fcd 100644
--- a/mlir/include/mlir/Dialect/DLTI/DLTIBase.td
+++ b/mlir/include/mlir/Dialect/DLTI/DLTIBase.td
@@ -23,14 +23,19 @@ def DLTI_Dialect : Dialect {
   }];
 
   let extraClassDeclaration = [{
-    // Top level attribute name.
+    // Top-level attribute name for arbitrary description.
+    constexpr const static ::llvm::StringLiteral
+    kMapAttrName = "dlti.map";
+
+    // Top-level attribute name for data layout description.
     constexpr const static ::llvm::StringLiteral
     kDataLayoutAttrName = "dlti.dl_spec";
 
-    // Top level attribute name for target system description
+    // Top-level attribute name for target system description.
     constexpr const static ::llvm::StringLiteral
     kTargetSystemDescAttrName = "dlti.target_system_spec";
 
+    // Top-level attribute name for target device description.
     constexpr const static ::llvm::StringLiteral
     kTargetDeviceDescAttrName = "dlti.target_device_spec";
 
diff --git a/mlir/include/mlir/Dialect/DLTI/TransformOps/DLTITransformOps.td b/mlir/include/mlir/Dialect/DLTI/TransformOps/DLTITransformOps.td
index 69aacac986ad73..1b1bebfaab4e38 100644
--- a/mlir/include/mlir/Dialect/DLTI/TransformOps/DLTITransformOps.td
+++ b/mlir/include/mlir/Dialect/DLTI/TransformOps/DLTITransformOps.td
@@ -22,32 +22,40 @@ def QueryOp : Op<Transform_Dialect, "dlti.query", [
   let summary = "Return attribute (as param) associated to key via DTLI";
   let description = [{
     This op queries data layout and target information associated to payload
-    IR by way of the DLTI dialect. A lookup is performed for the given `key`
-    at the `target` op, with the DLTI dialect determining which interfaces and
-    attributes are consulted - first checking `target` and then its ancestors.
+    IR by way of the DLTI dialect.
 
-    When only `key` is provided, the lookup occurs with respect to the data
-    layout specification of DLTI. When `device` is provided, the lookup occurs
-    with respect to DLTI's target device specifications associated to a DLTI
-    system device specification.
+    A lookup is performed for the given `keys` at `target` op - or its closest
+    interface-implementing ancestor - by way of the `DLTIQueryInterface`, which
+    returns an attribute for a key. If more than one key is provided, the lookup
+    continues recursively, now on the returned attributes, with the condition
+    that these implement the above interface. For example if the payload IR is
+
+    ```
+    module attributes {#dlti.map = #dlti.map<#dlti.dl_entry<"A",
+                                     #dlti.map<#dlti.dl_entry<"B", 42: int>>>} {
+      func.func private @f()
+    }
+    ```
+    and we have that `%func` is a Tranform handle to op `@f`, then
+    `transform.dlti.query ["A", "B"] at %func` returns 42 as a param and
+    `transform.dlti.query ["A"] at %func` returns the `#dlti.map` attribute
+    containing just the key "B" and its value. Using `["B"]` or `["A","C"]` as
+    `keys` will yield an error.
 
     #### Return modes
 
-    When succesful, the result, `associated_attr`, associates one attribute as a
-    param for each op in `target`'s payload.
+    When successful, the result, `associated_attr`, associates one attribute as
+    a param for each op in `target`'s payload.
 
-    If the lookup fails - as DLTI specifications or entries with the right
-    names are missing (i.e. the values of `device` and `key`) - a definite
-    failure is returned.
+    If the lookup fails - as no DLTI attributes/interfaces are found or entries
+    with the right names are missing - a silenceable failure is returned.
   }];
 
   let arguments = (ins TransformHandleTypeInterface:$target,
-                       OptionalAttr<StrAttr>:$device,
-                       StrAttr:$key);
+                       StrArrayAttr:$keys);
   let results = (outs TransformParamTypeInterface:$associated_attr);
   let assemblyFormat =
-      "(`:``:` $device^ `:``:`)? $key `at` $target attr-dict `:`"
-      "functional-type(operands, results)";
+      "$keys `at` $target attr-dict `:` functional-type(operands, results)";
 
   let extraClassDeclaration = [{
     ::mlir::DiagnosedSilenceableFailure applyToOne(
diff --git a/mlir/include/mlir/Dialect/Transform/Utils/DiagnosedSilenceableFailure.h b/mlir/include/mlir/Dialect/Transform/Utils/DiagnosedSilenceableFailure.h
index fcf422a0b6aa34..917c3826b24465 100644
--- a/mlir/include/mlir/Dialect/Transform/Utils/DiagnosedSilenceableFailure.h
+++ b/mlir/include/mlir/Dialect/Transform/Utils/DiagnosedSilenceableFailure.h
@@ -66,6 +66,13 @@ class [[nodiscard]] DiagnosedSilenceableFailure {
     return DiagnosedSilenceableFailure(
         std::forward<SmallVector<Diagnostic>>(diag));
   }
+  static DiagnosedSilenceableFailure
+  silenceableFailure(InFlightDiagnostic &&diag) {
+    auto consumingFailure = DiagnosedSilenceableFailure(
+        std::forward<Diagnostic>(*diag.getUnderlyingDiagnostic()));
+    diag.abandon(); // consumingFailure takes responsibility for diag's message.
+    return consumingFailure;
+  }
 
   /// Converts all kinds of failure into a LogicalResult failure, emitting the
   /// diagnostic if necessary. Must not be called more than once.
diff --git a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
index ab65f92820a6a8..848d2dee4a6309 100644
--- a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
+++ b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
@@ -23,6 +23,7 @@
 namespace mlir {
 class DataLayout;
 class DataLayoutEntryInterface;
+class DLTIQueryInterface;
 class TargetDeviceSpecInterface;
 class TargetSystemSpecInterface;
 using DataLayoutEntryKey = llvm::PointerUnion<Type, StringAttr>;
diff --git a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
index bc5080c9c6a558..d6e955be4291a3 100644
--- a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
+++ b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
@@ -20,6 +20,29 @@ include "mlir/IR/OpBase.td"
 // Attribute interfaces
 //===----------------------------------------------------------------------===//
 
+def DLTIQueryInterface : AttrInterface<"DLTIQueryInterface"> {
+  let cppNamespace = "::mlir";
+
+  let description = [{
+    Attribute interface exposing querying-mechanism for key-value associations.
+
+    The central feature of DLTI attributes is to allow looking up values at
+    keys. This interface represent the core functionality to do so - as such
+    most DLTI attributes should be implementing this interface.
+
+    Note that as the `query` method returns an attribute, this attribute can
+    be recursively queried when it also implements this interface.
+  }];
+  let methods = [
+    InterfaceMethod<
+      /*description=*/"Returns the attribute associated with the key.",
+      /*retTy=*/"::mlir::FailureOr<::mlir::Attribute>",
+      /*methodName=*/"query",
+      /*args=*/(ins "::mlir::DataLayoutEntryKey":$key)
+    >
+  ];
+}
+
 def DataLayoutEntryInterface : AttrInterface<"DataLayoutEntryInterface"> {
   let cppNamespace = "::mlir";
 
@@ -68,7 +91,7 @@ def DataLayoutEntryInterface : AttrInterface<"DataLayoutEntryInterface"> {
   }];
 }
 
-def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface"> {
+def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface", [DLTIQueryInterface]> {
   let cppNamespace = "::mlir";
 
   let description = [{
@@ -173,7 +196,7 @@ def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface"> {
       /*defaultImplementation=*/[{
         return ::mlir::detail::verifyDataLayoutSpec($_attr, loc);
       }]
-    >,
+    >
   ];
 
   let extraClassDeclaration = [{
@@ -184,6 +207,15 @@ def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface"> {
       return getSpecForType(TypeID::get<Ty>());
     }
 
+    /// Helper for default implementation of `DLTIQueryInterface`'s `query`.
+    inline ::mlir::FailureOr<::mlir::Attribute>
+    queryHelper(::mlir::DataLayoutEntryKey key) const {
+      for (DataLayoutEntryInterface entry : getEntries())
+        if (entry.getKey() == key)
+            return entry.getValue();
+      return ::mlir::failure();
+    }
+
     /// Populates the given maps with lists of entries grouped by the type or
     /// identifier they are associated with. Users are not expected to call this
     /// method directly.
@@ -194,7 +226,7 @@ def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface"> {
   }];
 }
 
-def TargetDeviceSpecInterface : AttrInterface<"TargetDeviceSpecInterface"> {
+def TargetDeviceSpecInterface : AttrInterface<"TargetDeviceSpecInterface", [DLTIQueryInterface]> {
   let cppNamespace = "::mlir";
 
   let description = [{
@@ -239,9 +271,20 @@ def TargetDeviceSpecInterface : AttrInterface<"TargetDeviceSpecInterface"> {
       /*defaultImplementation=*/[{ return ::mlir::success(); }]
     >
   ];
+
+  let extraClassDeclaration = [{
+    /// Helper for default implementation of `DLTIQueryInterface`'s `query`.
+    ::mlir::FailureOr<::mlir::Attribute>
+    queryHelper(::mlir::DataLayoutEntryKey key) const {
+      if (auto strKey = llvm::dyn_cast<StringAttr>(key))
+        if (DataLayoutEntryInterface spec = getSpecForIdentifier(strKey))
+          return spec.getValue();
+      return ::mlir::failure();
+    }
+  }];
 }
 
-def TargetSystemSpecInterface : AttrInterface<"TargetSystemSpecInterface"> {
+def TargetSystemSpecInterface : AttrInterface<"TargetSystemSpecInterface", [DLTIQueryInterface]> {
   let cppNamespace = "::mlir";
 
   let description = [{
@@ -287,6 +330,15 @@ def TargetSystemSpecInterface : AttrInterface<"TargetSystemSpecInterface"> {
 
   let extraClassDeclaration = [{
     using DeviceID = StringAttr;
+
+    /// Helper for default implementation of `DLTIQueryInterface`'s `query`.
+    ::mlir::FailureOr<::mlir::Attribute>
+    queryHelper(::mlir::DataLayoutEntryKey key) const {
+      if (auto strKey = llvm::dyn_cast<::mlir::StringAttr>(key))
+        if (auto deviceSpec = getDeviceSpecForDeviceID(strKey))
+          return *deviceSpec;
+      return ::mlir::failure();
+    }
   }];
 }
 
diff --git a/mlir/lib/Dialect/DLTI/DLTI.cpp b/mlir/lib/Dialect/DLTI/DLTI.cpp
index c995f44c380e57..a849d2b240781f 100644
--- a/mlir/lib/Dialect/DLTI/DLTI.cpp
+++ b/mlir/lib/Dialect/DLTI/DLTI.cpp
@@ -109,11 +109,11 @@ void DataLayoutEntryAttr::print(AsmPrinter &os) const {
 }
 
 //===----------------------------------------------------------------------===//
-// DataLayoutSpecAttr
+// DLTIMapAttr
 //===----------------------------------------------------------------------===//
 
-LogicalResult
-DataLayoutSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+static LogicalResult
+verifyEntries(function_ref<InFlightDiagnostic()> emitError,
                            ArrayRef<DataLayoutEntryInterface> entries) {
   DenseSet<Type> types;
   DenseSet<StringAttr> ids;
@@ -130,6 +130,22 @@ DataLayoutSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
   return success();
 }
 
+LogicalResult
+MapAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+                             ArrayRef<DataLayoutEntryInterface> entries) {
+  return verifyEntries(emitError, entries);
+}
+
+//===----------------------------------------------------------------------===//
+// DataLayoutSpecAttr
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+DataLayoutSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+                           ArrayRef<DataLayoutEntryInterface> entries) {
+  return verifyEntries(emitError, entries);
+}
+
 /// Given a list of old and a list of new entries, overwrites old entries with
 /// new ones if they have matching keys, appends new entries to the old entry
 /// list otherwise.
@@ -393,6 +409,49 @@ TargetSystemSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
 // DLTIDialect
 //===----------------------------------------------------------------------===//
 
+std::pair<DLTIQueryInterface, Operation *>
+dlti::getClosestQueryable(Operation *op) {
+  DLTIQueryInterface queryable = {};
+
+  // Search op and its ancestors for the first attached DLTIQueryInterface attr.
+  do {
+    for (NamedAttribute attr : op->getAttrs())
+      if ((queryable = llvm::dyn_cast<DLTIQueryInterface>(attr.getValue())))
+        break;
+  } while (!queryable && (op = op->getParentOp()));
+
+  return std::pair(queryable, op);
+}
+
+FailureOr<Attribute> dlti::query(Operation *op, ArrayRef<StringAttr> ke...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/104595


More information about the Mlir-commits mailing list