[Mlir-commits] [mlir] abd9534 - Reimplementing target description concept using DLTI attribute (#92138)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Jun 19 11:40:12 PDT 2024
Author: Niranjan Hasabnis
Date: 2024-06-19T19:40:08+01:00
New Revision: abd95342f0b94e140b36ac954b8f8c29b1393861
URL: https://github.com/llvm/llvm-project/commit/abd95342f0b94e140b36ac954b8f8c29b1393861
DIFF: https://github.com/llvm/llvm-project/commit/abd95342f0b94e140b36ac954b8f8c29b1393861.diff
LOG: Reimplementing target description concept using DLTI attribute (#92138)
and Interfaces. This is a newer implementation of PR
https://github.com/llvm/llvm-project/pull/85141 and
[RFC](https://discourse.llvm.org/t/rfc-target-description-and-cost-model-in-mlir/76990)
by considering reviews and comments on the original PR.
As an example of attributes supported by this commit:
```
module attributes {
dlti.target_system_spec =
#dlti.target_device_spec<
#dlti.dl_entry<"dlti.device_id", 0: ui32>,
#dlti.dl_entry<"dlti.device_type", "CPU">,
#dlti.dl_entry<"dlti.L1_cache_size_in_bytes", 8192 : ui32>>,
#dlti.target_device_spec <
#dlti.dl_entry<"dlti.device_id", 1: ui32>,
#dlti.dl_entry<"dlti.device_type", "GPU">,
#dlti.dl_entry<"dlti.max_vector_op_width", 64 : ui32>>,
#dlti.target_device_spec <
#dlti.dl_entry<"dlti.device_id", 2: ui32>,
#dlti.dl_entry<"dlti.device_type", "XPU">>>
}
```
Added:
mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
mlir/test/Dialect/DLTI/valid.mlir
Modified:
mlir/include/mlir/Dialect/DLTI/CMakeLists.txt
mlir/include/mlir/Dialect/DLTI/DLTI.h
mlir/include/mlir/Dialect/DLTI/DLTIBase.td
mlir/include/mlir/Dialect/DLTI/Traits.h
mlir/include/mlir/IR/BuiltinOps.td
mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
mlir/lib/Dialect/DLTI/DLTI.cpp
mlir/lib/Dialect/DLTI/Traits.cpp
mlir/lib/IR/BuiltinDialect.cpp
mlir/lib/Interfaces/DataLayoutInterfaces.cpp
mlir/test/Dialect/DLTI/invalid.mlir
mlir/test/Dialect/DLTI/roundtrip.mlir
mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/DLTI/CMakeLists.txt b/mlir/include/mlir/Dialect/DLTI/CMakeLists.txt
index e0b18b12cda34..44a814f1c8e82 100644
--- a/mlir/include/mlir/Dialect/DLTI/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/DLTI/CMakeLists.txt
@@ -1,2 +1,8 @@
add_mlir_dialect(DLTI dlti)
add_mlir_doc(DLTI DLTIDialect Dialects/ -gen-dialect-doc)
+
+set(LLVM_TARGET_DEFINITIONS DLTIAttrs.td)
+mlir_tablegen(DLTIAttrs.h.inc -gen-attrdef-decls -attrdefs-dialect=dlti)
+mlir_tablegen(DLTIAttrs.cpp.inc -gen-attrdef-defs -attrdefs-dialect=dlti)
+add_public_tablegen_target(MLIRDLTIAttrsIncGen)
+add_dependencies(mlir-headers MLIRDLTIAttrsIncGen)
diff --git a/mlir/include/mlir/Dialect/DLTI/DLTI.h b/mlir/include/mlir/Dialect/DLTI/DLTI.h
index 5ac7c11e6ffee..f50a654f3885d 100644
--- a/mlir/include/mlir/Dialect/DLTI/DLTI.h
+++ b/mlir/include/mlir/Dialect/DLTI/DLTI.h
@@ -18,114 +18,13 @@
#include "mlir/Interfaces/DataLayoutInterfaces.h"
namespace mlir {
-namespace impl {
-class DataLayoutEntryStorage;
-class DataLayoutSpecStorage;
-} // namespace impl
-
-//===----------------------------------------------------------------------===//
-// DataLayoutEntryAttr
-//===----------------------------------------------------------------------===//
-
-/// A data layout entry attribute is a key-value pair where the key is a type or
-/// an identifier and the value is another attribute. These entries form a data
-/// layout specification.
-class DataLayoutEntryAttr
- : public Attribute::AttrBase<DataLayoutEntryAttr, Attribute,
- impl::DataLayoutEntryStorage,
- DataLayoutEntryInterface::Trait> {
-public:
- using Base::Base;
-
- /// The keyword used for this attribute in custom syntax.
- constexpr const static llvm::StringLiteral kAttrKeyword = "dl_entry";
-
- /// Returns the entry with the given key and value.
- static DataLayoutEntryAttr get(StringAttr key, Attribute value);
- static DataLayoutEntryAttr get(Type key, Attribute value);
-
- /// Returns the key of this entry.
- DataLayoutEntryKey getKey() const;
-
- /// Returns the value of this entry.
- Attribute getValue() const;
-
- /// Parses an instance of this attribute.
- static DataLayoutEntryAttr parse(AsmParser &parser);
-
- /// Prints this attribute.
- void print(AsmPrinter &os) const;
-
- static constexpr StringLiteral name = "builtin.data_layout_entry";
-};
-
-//===----------------------------------------------------------------------===//
-// DataLayoutSpecAttr
-//===----------------------------------------------------------------------===//
-
-/// A data layout specification is a list of entries that specify (partial) data
-/// layout information. It is expected to be attached to operations that serve
-/// as scopes for data layout requests.
-class DataLayoutSpecAttr
- : public Attribute::AttrBase<DataLayoutSpecAttr, Attribute,
- impl::DataLayoutSpecStorage,
- DataLayoutSpecInterface::Trait> {
-public:
- using Base::Base;
-
- /// The keyword used for this attribute in custom syntax.
- constexpr const static StringLiteral kAttrKeyword = "dl_spec";
-
- /// Returns the specification containing the given list of keys.
- static DataLayoutSpecAttr get(MLIRContext *ctx,
- ArrayRef<DataLayoutEntryInterface> entries);
-
- /// Returns the specification containing the given list of keys. If the list
- /// contains duplicate keys or is otherwise invalid, reports errors using the
- /// given callback and returns null.
- static DataLayoutSpecAttr
- getChecked(function_ref<InFlightDiagnostic()> emitError, MLIRContext *context,
- ArrayRef<DataLayoutEntryInterface> entries);
-
- /// Checks that the given list of entries does not contain duplicate keys.
- static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
- ArrayRef<DataLayoutEntryInterface> entries);
-
- /// Combines this specification with `specs`, enclosing specifications listed
- /// from outermost to innermost. This overwrites the older entries with the
- /// 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 list of entries.
- DataLayoutEntryListRef getEntries() const;
-
- /// Returns the endiannes identifier.
- StringAttr getEndiannessIdentifier(MLIRContext *context) const;
-
- /// Returns the alloca memory space identifier.
- StringAttr getAllocaMemorySpaceIdentifier(MLIRContext *context) const;
-
- /// Returns the program memory space identifier.
- StringAttr getProgramMemorySpaceIdentifier(MLIRContext *context) const;
-
- /// Returns the global memory space identifier.
- StringAttr getGlobalMemorySpaceIdentifier(MLIRContext *context) const;
-
- /// Returns the stack alignment identifier.
- StringAttr getStackAlignmentIdentifier(MLIRContext *context) const;
-
- /// Parses an instance of this attribute.
- static DataLayoutSpecAttr parse(AsmParser &parser);
-
- /// Prints this attribute.
- void print(AsmPrinter &os) const;
-
- static constexpr StringLiteral name = "builtin.data_layout_spec";
-};
-
+namespace detail {
+class DataLayoutEntryAttrStorage;
+} // namespace detail
} // namespace mlir
+#define GET_ATTRDEF_CLASSES
+#include "mlir/Dialect/DLTI/DLTIAttrs.h.inc"
#include "mlir/Dialect/DLTI/DLTIDialect.h.inc"
#endif // MLIR_DIALECT_DLTI_DLTI_H
diff --git a/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td b/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
new file mode 100644
index 0000000000000..b3849e9b5be62
--- /dev/null
+++ b/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
@@ -0,0 +1,188 @@
+//===- DLTIAttrs.td - DLTI dialect attributes definition --*- 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 MLIR_DIALECT_DLTI_DLTIATTRS_TD
+#define MLIR_DIALECT_DLTI_DLTIATTRS_TD
+
+include "mlir/Dialect/DLTI/DLTI.td"
+include "mlir/IR/AttrTypeBase.td"
+
+class DLTIAttr<string name, list<Trait> traits = [],
+ string baseCppClass = "::mlir::Attribute">
+ : AttrDef<DLTI_Dialect, name, traits, baseCppClass> { }
+
+//===----------------------------------------------------------------------===//
+// DataLayoutEntryAttr
+//===----------------------------------------------------------------------===//
+
+def DataLayoutEntryTrait
+ : NativeAttrTrait<"DataLayoutEntryInterface::Trait"> {
+ let cppNamespace = "::mlir";
+}
+
+def DLTI_DataLayoutEntryAttr :
+ DLTIAttr<"DataLayoutEntry", [DataLayoutEntryTrait]> {
+ 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
+ an identifier and the value is another attribute. These entries form a data
+ layout specification.
+ }];
+ let parameters = (ins
+ "DataLayoutEntryKey":$key, "Attribute":$value
+ );
+ // TODO: We do not generate storage class because llvm::PointerUnion
+ // does not work with hash_key method.
+ let genStorageClass = 0;
+ let mnemonic = "dl_entry";
+ let genVerifyDecl = 0;
+ let hasCustomAssemblyFormat = 1;
+ let extraClassDeclaration = [{
+ /// Returns the entry with the given key and value.
+ static DataLayoutEntryAttr get(StringAttr key, Attribute value);
+ static DataLayoutEntryAttr get(MLIRContext *context, Type key, Attribute value);
+ static DataLayoutEntryAttr get(Type key, Attribute value);
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// DataLayoutSpecAttr
+//===----------------------------------------------------------------------===//
+def DataLayoutSpecTrait
+ : NativeAttrTrait<"DataLayoutSpecInterface::Trait"> {
+ let cppNamespace = "::mlir";
+}
+
+def DLTI_DataLayoutSpecAttr :
+ DLTIAttr<"DataLayoutSpec", [DataLayoutSpecTrait]> {
+ 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
+ layout information. It is expected to be attached to operations that serve
+ as scopes for data layout requests.
+ }];
+ let parameters = (ins
+ ArrayRefParameter<"DataLayoutEntryInterface", "">:$entries
+ );
+ let mnemonic = "dl_spec";
+ let genVerifyDecl = 1;
+ let hasCustomAssemblyFormat = 1;
+ let extraClassDeclaration = [{
+ /// Combines this specification with `specs`, enclosing specifications listed
+ /// from outermost to innermost. This overwrites the older entries with the
+ /// 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;
+
+ /// Returns the alloca memory space identifier.
+ StringAttr getAllocaMemorySpaceIdentifier(MLIRContext *context) const;
+
+ /// Returns the program memory space identifier.
+ StringAttr getProgramMemorySpaceIdentifier(MLIRContext *context) const;
+
+ /// Returns the global memory space identifier.
+ StringAttr getGlobalMemorySpaceIdentifier(MLIRContext *context) const;
+
+ /// Returns the stack alignment identifier.
+ StringAttr getStackAlignmentIdentifier(MLIRContext *context) const;
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// TargetSystemSpecAttr
+//===----------------------------------------------------------------------===//
+
+def TargetSystemSpecTrait
+ : NativeAttrTrait<"TargetSystemSpecInterface::Trait"> {
+ let cppNamespace = "::mlir";
+}
+
+def DLTI_TargetSystemSpecAttr :
+ DLTIAttr<"TargetSystemSpec", [TargetSystemSpecTrait]> {
+ let summary = [{
+ An attribute to represent target system specification.
+ }];
+ let description = [{
+ A system specification describes the overall system containing
+ multiple devices, with each device having a unique ID (string)
+ and its corresponding TargetDeviceSpec object.
+
+ Example:
+ dlti.target_system_spec =
+ #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"dlti.L1_cache_size_in_bytes", 4096: ui32>>,
+ "GPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"dlti.max_vector_op_width", 64 : ui32>>,
+ "XPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"dlti.max_vector_op_width", 4096 : ui32>>>
+ }];
+ let parameters = (ins
+ ArrayRefParameter<"DeviceIDTargetDeviceSpecPair", "">:$entries
+ );
+ let mnemonic = "target_system_spec";
+ let genVerifyDecl = 1;
+ let assemblyFormat = "`<` $entries `>`";
+ let extraClassDeclaration = [{
+ /// Return the device specification that matches the given device ID
+ std::optional<TargetDeviceSpecInterface>
+ getDeviceSpecForDeviceID(
+ TargetSystemSpecInterface::DeviceID deviceID);
+ }];
+ let extraClassDefinition = [{
+ std::optional<TargetDeviceSpecInterface>
+ $cppClass::getDeviceSpecForDeviceID(
+ TargetSystemSpecInterface::DeviceID deviceID) {
+ for (const auto& entry : getEntries()) {
+ if (entry.first == deviceID)
+ return entry.second;
+ }
+ return std::nullopt;
+ }
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// TargetDeviceSpecAttr
+//===----------------------------------------------------------------------===//
+
+def TargetDeviceSpecTrait
+ : NativeAttrTrait<"TargetDeviceSpecInterface::Trait"> {
+ let cppNamespace = "::mlir";
+}
+
+def DLTI_TargetDeviceSpecAttr :
+ DLTIAttr<"TargetDeviceSpec", [TargetDeviceSpecTrait]> {
+ let summary = [{
+ An attribute to represent target device specification.
+ }];
+ let description = [{
+ Each device specification describes a single device and its
+ hardware properties. Each device specification can contain any number
+ of optional hardware properties (e.g., max_vector_op_width below).
+
+ Example:
+ #dlti.target_device_spec<
+ #dlti.dl_entry<"dlti.max_vector_op_width", 64 : ui32>>
+ }];
+ let parameters = (ins
+ ArrayRefParameter<"DataLayoutEntryInterface", "">:$entries
+ );
+ let mnemonic = "target_device_spec";
+ let genVerifyDecl = 1;
+ let assemblyFormat = "`<` $entries `>`";
+}
+
+#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 3572a99fad874..e26fbdb146645 100644
--- a/mlir/include/mlir/Dialect/DLTI/DLTIBase.td
+++ b/mlir/include/mlir/Dialect/DLTI/DLTIBase.td
@@ -27,6 +27,13 @@ def DLTI_Dialect : Dialect {
constexpr const static ::llvm::StringLiteral
kDataLayoutAttrName = "dlti.dl_spec";
+ // Top level attribute name for target system description
+ constexpr const static ::llvm::StringLiteral
+ kTargetSystemDescAttrName = "dlti.target_system_spec";
+
+ constexpr const static ::llvm::StringLiteral
+ kTargetDeviceDescAttrName = "dlti.target_device_spec";
+
// Constants used in entries.
constexpr const static ::llvm::StringLiteral
kDataLayoutEndiannessKey = "dlti.endianness";
@@ -53,24 +60,6 @@ def DLTI_Dialect : Dialect {
let useDefaultAttributePrinterParser = 1;
}
-def DLTI_DataLayoutEntryAttr : DialectAttr<
- DLTI_Dialect,
- CPred<"::llvm::isa<::mlir::DataLayoutEntryAttr>($_self)">,
- "Target data layout entry"> {
- let storageType = "::mlir::DataLayoutEntryAttr";
- let returnType = "::mlir::DataLayoutEntryAttr";
- let convertFromStorage = "$_self";
-}
-
-def DLTI_DataLayoutSpecAttr : DialectAttr<
- DLTI_Dialect,
- CPred<"::llvm::isa<::mlir::DataLayoutSpecAttr>($_self)">,
- "Target data layout specification"> {
- let storageType = "::mlir::DataLayoutSpecAttr";
- let returnType = "::mlir::DataLayoutSpecAttr";
- let convertFromStorage = "$_self";
-}
-
def HasDefaultDLTIDataLayout : NativeOpTrait<"HasDefaultDLTIDataLayout"> {
let cppNamespace = "::mlir";
}
diff --git a/mlir/include/mlir/Dialect/DLTI/Traits.h b/mlir/include/mlir/Dialect/DLTI/Traits.h
index 5d86195305a95..edfbdffbd1ba1 100644
--- a/mlir/include/mlir/Dialect/DLTI/Traits.h
+++ b/mlir/include/mlir/Dialect/DLTI/Traits.h
@@ -18,6 +18,7 @@ class DataLayoutSpecAttr;
namespace impl {
LogicalResult verifyHasDefaultDLTIDataLayoutTrait(Operation *op);
DataLayoutSpecInterface getDataLayoutSpec(Operation *op);
+TargetSystemSpecInterface getTargetSystemSpec(Operation *op);
} // namespace impl
/// Trait to be used by operations willing to use the implementation of the
@@ -37,6 +38,12 @@ class HasDefaultDLTIDataLayout
DataLayoutSpecInterface getDataLayoutSpec() {
return impl::getDataLayoutSpec(this->getOperation());
}
+
+ /// Returns the target system description specification as provided by DLTI
+ /// dialect
+ TargetSystemSpecInterface getTargetSystemSpec() {
+ return impl::getTargetSystemSpec(this->getOperation());
+ }
};
} // namespace mlir
diff --git a/mlir/include/mlir/IR/BuiltinOps.td b/mlir/include/mlir/IR/BuiltinOps.td
index eda24615c71ea..56edd7519cd67 100644
--- a/mlir/include/mlir/IR/BuiltinOps.td
+++ b/mlir/include/mlir/IR/BuiltinOps.td
@@ -78,6 +78,7 @@ def ModuleOp : Builtin_Op<"module", [
//===------------------------------------------------------------------===//
DataLayoutSpecInterface getDataLayoutSpec();
+ TargetSystemSpecInterface getTargetSystemSpec();
//===------------------------------------------------------------------===//
// OpAsmOpInterface Methods
diff --git a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
index 76bf33e89a716..4cbad38df42ba 100644
--- a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
+++ b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
@@ -23,11 +23,18 @@
namespace mlir {
class DataLayout;
class DataLayoutEntryInterface;
+class TargetDeviceSpecInterface;
+class TargetSystemSpecInterface;
using DataLayoutEntryKey = llvm::PointerUnion<Type, StringAttr>;
// Using explicit SmallVector size because we cannot infer the size from the
// forward declaration, and we need the typedef in the actual declaration.
using DataLayoutEntryList = llvm::SmallVector<DataLayoutEntryInterface, 4>;
using DataLayoutEntryListRef = llvm::ArrayRef<DataLayoutEntryInterface>;
+using TargetDeviceSpecListRef = llvm::ArrayRef<TargetDeviceSpecInterface>;
+using DeviceIDTargetDeviceSpecPair =
+ std::pair<StringAttr, TargetDeviceSpecInterface>;
+using DeviceIDTargetDeviceSpecPairListRef =
+ llvm::ArrayRef<DeviceIDTargetDeviceSpecPair>;
class DataLayoutOpInterface;
class DataLayoutSpecInterface;
class ModuleOp;
@@ -84,6 +91,11 @@ Attribute getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry);
/// DataLayoutInterface if specified, otherwise returns the default.
uint64_t getDefaultStackAlignment(DataLayoutEntryInterface entry);
+/// Returns the value of the property from the specified DataLayoutEntry. If the
+/// property is missing from the entry, returns std::nullopt.
+std::optional<int64_t>
+getDevicePropertyValueAsInt(DataLayoutEntryInterface entry);
+
/// Given a list of data layout entries, returns a new list containing the
/// entries with keys having the given type ID, i.e. belonging to the same type
/// class.
@@ -95,6 +107,11 @@ DataLayoutEntryList filterEntriesForType(DataLayoutEntryListRef entries,
DataLayoutEntryInterface
filterEntryForIdentifier(DataLayoutEntryListRef entries, StringAttr id);
+/// Given a list of target device entries, returns the entry that has the given
+/// identifier as key, if such an entry exists in the list.
+TargetDeviceSpecInterface
+filterEntryForIdentifier(TargetDeviceSpecListRef entries, StringAttr id);
+
/// Verifies that the operation implementing the data layout interface, or a
/// module operation, is valid. This calls the verifier of the spec attribute
/// and checks if the layout is compatible with specs attached to the enclosing
@@ -106,6 +123,12 @@ LogicalResult verifyDataLayoutOp(Operation *op);
/// and dialect interfaces for type and identifier keys respectively.
LogicalResult verifyDataLayoutSpec(DataLayoutSpecInterface spec, Location loc);
+/// Verifies that a target system desc spec is valid. This dispatches to
+/// individual entry verifiers, and then to the verifiers implemented by the
+/// relevant dialect interfaces for identifier keys.
+LogicalResult verifyTargetSystemSpec(TargetSystemSpecInterface spec,
+ Location loc);
+
/// Divides the known min value of the numerator by the denominator and rounds
/// the result up to the next integer. Preserves the scalable flag.
llvm::TypeSize divideCeil(llvm::TypeSize numerator, uint64_t denominator);
@@ -137,6 +160,13 @@ class DataLayoutDialectInterface
return success();
}
+ /// Checks whether the given data layout entry is valid and reports any errors
+ /// at the provided location. Derived classes should override this.
+ virtual LogicalResult verifyEntry(TargetDeviceSpecInterface entry,
+ Location loc) const {
+ return success();
+ }
+
/// Default implementation of entry combination that combines identical
/// entries and returns null otherwise.
static DataLayoutEntryInterface
@@ -214,10 +244,19 @@ class DataLayout {
/// unspecified.
uint64_t getStackAlignment() const;
+ /// Returns the value of the specified property if the property is defined for
+ /// the given device ID, otherwise returns std::nullopt.
+ std::optional<int64_t>
+ getDevicePropertyValueAsInt(TargetSystemSpecInterface::DeviceID,
+ StringAttr propertyName) const;
+
private:
/// Combined layout spec at the given scope.
const DataLayoutSpecInterface originalLayout;
+ /// Combined target system desc spec at the given scope.
+ const TargetSystemSpecInterface originalTargetSystemDesc;
+
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
/// List of enclosing layout specs.
SmallVector<DataLayoutSpecInterface, 2> layoutStack;
diff --git a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
index 9edc885b9c5a9..8ff0e3f5f863b 100644
--- a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
+++ b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
@@ -194,6 +194,102 @@ def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface"> {
}];
}
+def TargetDeviceSpecInterface : AttrInterface<"TargetDeviceSpecInterface"> {
+ let cppNamespace = "::mlir";
+
+ let description = [{
+ Attribute interface describing a target device description specification.
+
+ A target device description specification is a list of device properties (key)
+ and their values for a specific device. The device is identified using "device_id"
+ (as a key and ui32 value) and "device_type" key which must have a string value.
+ Both "device_id" and "device_type" are mandatory keys. As an example, L1 cache
+ size could be a device property, and its value would be a device specific size.
+
+ A target device description specification is attached to a module as a module level
+ attribute.
+ }];
+
+ let methods = [
+ InterfaceMethod<
+ /*description=*/"Returns the list of layout entries.",
+ /*retTy=*/"::mlir::DataLayoutEntryListRef",
+ /*methodName=*/"getEntries",
+ /*args=*/(ins)
+ >,
+ InterfaceMethod<
+ /*description=*/"Returns the entry related to the given identifier, if "
+ "present.",
+ /*retTy=*/"::mlir::DataLayoutEntryInterface",
+ /*methodName=*/"getSpecForIdentifier",
+ /*args=*/(ins "::mlir::StringAttr":$identifier),
+ /*methodBody=*/"",
+ /*defaultImplementation=*/[{
+ return ::mlir::detail::filterEntryForIdentifier($_attr.getEntries(),
+ identifier);
+ }]
+ >,
+ InterfaceMethod<
+ /*description=*/"Checks that the entry is well-formed, reports errors "
+ "at the provided location.",
+ /*retTy=*/"::mlir::LogicalResult",
+ /*methodName=*/"verifyEntry",
+ /*args=*/(ins "::mlir::Location":$loc),
+ /*methodBody=*/"",
+ /*defaultImplementation=*/[{ return ::mlir::success(); }]
+ >
+ ];
+}
+
+def TargetSystemSpecInterface : AttrInterface<"TargetSystemSpecInterface"> {
+ let cppNamespace = "::mlir";
+
+ let description = [{
+ Attribute interface describing a target system description specification.
+
+ A target system description specification is a list of target device
+ specifications, with one device specification for a device in the system. As
+ such, a target system description specification allows specifying a heterogenous
+ system, with devices of
diff erent types (e.g., CPU, GPU, etc.)
+
+ The only requirement on a valid target system description specification is that
+ the "device_id" in every target device description specification needs to be
+ unique. This is because, ultimately, this "device_id" is used by the user to
+ query a value of a device property.
+ }];
+
+ let methods = [
+ InterfaceMethod<
+ /*description=*/"Returns the list of layout entries.",
+ /*retTy=*/"llvm::ArrayRef<DeviceIDTargetDeviceSpecPair>",
+ /*methodName=*/"getEntries",
+ /*args=*/(ins)
+ >,
+ InterfaceMethod<
+ /*description=*/"Returns the device description spec for given device "
+ "ID",
+ /*retTy=*/"std::optional<::mlir::TargetDeviceSpecInterface>",
+ /*methodName=*/"getDeviceSpecForDeviceID",
+ /*args=*/(ins "StringAttr":$deviceID)
+ >,
+ InterfaceMethod<
+ /*description=*/"Verifies the validity of the specification and "
+ "reports any errors at the given location.",
+ /*retTy=*/"::mlir::LogicalResult",
+ /*methodName=*/"verifySpec",
+ /*args=*/(ins "::mlir::Location":$loc),
+ /*methodBody=*/"",
+ /*defaultImplementation=*/[{
+ return ::mlir::detail::verifyTargetSystemSpec($_attr, loc);
+ }]
+ >
+ ];
+
+ let extraClassDeclaration = [{
+ using DeviceID = StringAttr;
+ }];
+}
+
//===----------------------------------------------------------------------===//
// Operation interface
//===----------------------------------------------------------------------===//
@@ -227,6 +323,13 @@ def DataLayoutOpInterface : OpInterface<"DataLayoutOpInterface"> {
/*methodName=*/"getDataLayoutSpec",
/*args=*/(ins)
>,
+ InterfaceMethod<
+ /*description=*/"Returns the target system desc specification for this "
+ "op, or null if it does not exist.",
+ /*retTy=*/"::mlir::TargetSystemSpecInterface",
+ /*methodName=*/"getTargetSystemSpec",
+ /*args=*/(ins)
+ >,
StaticInterfaceMethod<
/*description=*/"Returns the size of the given type computed using the "
"relevant entries. The data layout object can be used "
@@ -362,6 +465,17 @@ def DataLayoutOpInterface : OpInterface<"DataLayoutOpInterface"> {
return ::mlir::detail::getDefaultStackAlignment(entry);
}]
>,
+ StaticInterfaceMethod<
+ /*description=*/"Returns the value of the property, if the property is "
+ "defined. Otherwise, it returns std::nullopt.",
+ /*retTy=*/"std::optional<int64_t>",
+ /*methodName=*/"getDevicePropertyValueAsInt",
+ /*args=*/(ins "::mlir::DataLayoutEntryInterface":$entry),
+ /*methodBody=*/"",
+ /*defaultImplementation=*/[{
+ return ::mlir::detail::getDevicePropertyValueAsInt(entry);
+ }]
+ >
];
let verify = [{ return ::mlir::detail::verifyDataLayoutOp($_op); }];
diff --git a/mlir/lib/Dialect/DLTI/DLTI.cpp b/mlir/lib/Dialect/DLTI/DLTI.cpp
index 98a8865ef4da3..592fced0b2abd 100644
--- a/mlir/lib/Dialect/DLTI/DLTI.cpp
+++ b/mlir/lib/Dialect/DLTI/DLTI.cpp
@@ -10,33 +10,40 @@
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinDialect.h"
#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/DialectImplementation.h"
#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+
using namespace mlir;
#include "mlir/Dialect/DLTI/DLTIDialect.cpp.inc"
+#define GET_ATTRDEF_CLASSES
+#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
+
+#define DEBUG_TYPE "dlti"
+
//===----------------------------------------------------------------------===//
// DataLayoutEntryAttr
//===----------------------------------------------------------------------===//
-//
-constexpr const StringLiteral mlir::DataLayoutEntryAttr::kAttrKeyword;
-
namespace mlir {
-namespace impl {
-class DataLayoutEntryStorage : public AttributeStorage {
+namespace detail {
+class DataLayoutEntryAttrStorage : public AttributeStorage {
public:
using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
- DataLayoutEntryStorage(DataLayoutEntryKey entryKey, Attribute value)
+ DataLayoutEntryAttrStorage(DataLayoutEntryKey entryKey, Attribute value)
: entryKey(entryKey), value(value) {}
- static DataLayoutEntryStorage *construct(AttributeStorageAllocator &allocator,
- const KeyTy &key) {
- return new (allocator.allocate<DataLayoutEntryStorage>())
- DataLayoutEntryStorage(key.first, key.second);
+ static DataLayoutEntryAttrStorage *
+ construct(AttributeStorageAllocator &allocator, const KeyTy &key) {
+ return new (allocator.allocate<DataLayoutEntryAttrStorage>())
+ DataLayoutEntryAttrStorage(key.first, key.second);
}
bool operator==(const KeyTy &other) const {
@@ -46,7 +53,7 @@ class DataLayoutEntryStorage : public AttributeStorage {
DataLayoutEntryKey entryKey;
Attribute value;
};
-} // namespace impl
+} // namespace detail
} // namespace mlir
DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key, Attribute value) {
@@ -65,7 +72,7 @@ Attribute DataLayoutEntryAttr::getValue() const { return getImpl()->value; }
/// Parses an attribute with syntax:
/// attr ::= `#target.` `dl_entry` `<` (type | quoted-string) `,` attr `>`
-DataLayoutEntryAttr DataLayoutEntryAttr::parse(AsmParser &parser) {
+Attribute DataLayoutEntryAttr::parse(AsmParser &parser, Type ty) {
if (failed(parser.parseLess()))
return {};
@@ -93,7 +100,7 @@ DataLayoutEntryAttr DataLayoutEntryAttr::parse(AsmParser &parser) {
}
void DataLayoutEntryAttr::print(AsmPrinter &os) const {
- os << DataLayoutEntryAttr::kAttrKeyword << "<";
+ os << "<";
if (auto type = llvm::dyn_cast_if_present<Type>(getKey()))
os << type;
else
@@ -104,51 +111,6 @@ void DataLayoutEntryAttr::print(AsmPrinter &os) const {
//===----------------------------------------------------------------------===//
// DataLayoutSpecAttr
//===----------------------------------------------------------------------===//
-//
-constexpr const StringLiteral mlir::DataLayoutSpecAttr::kAttrKeyword;
-constexpr const StringLiteral
- mlir::DLTIDialect::kDataLayoutAllocaMemorySpaceKey;
-constexpr const StringLiteral
- mlir::DLTIDialect::kDataLayoutProgramMemorySpaceKey;
-constexpr const StringLiteral
- mlir::DLTIDialect::kDataLayoutGlobalMemorySpaceKey;
-
-constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutStackAlignmentKey;
-
-namespace mlir {
-namespace impl {
-class DataLayoutSpecStorage : public AttributeStorage {
-public:
- using KeyTy = ArrayRef<DataLayoutEntryInterface>;
-
- DataLayoutSpecStorage(ArrayRef<DataLayoutEntryInterface> entries)
- : entries(entries) {}
-
- bool operator==(const KeyTy &key) const { return key == entries; }
-
- static DataLayoutSpecStorage *construct(AttributeStorageAllocator &allocator,
- const KeyTy &key) {
- return new (allocator.allocate<DataLayoutSpecStorage>())
- DataLayoutSpecStorage(allocator.copyInto(key));
- }
-
- ArrayRef<DataLayoutEntryInterface> entries;
-};
-} // namespace impl
-} // namespace mlir
-
-DataLayoutSpecAttr
-DataLayoutSpecAttr::get(MLIRContext *ctx,
- ArrayRef<DataLayoutEntryInterface> entries) {
- return Base::get(ctx, entries);
-}
-
-DataLayoutSpecAttr
-DataLayoutSpecAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
- MLIRContext *context,
- ArrayRef<DataLayoutEntryInterface> entries) {
- return Base::getChecked(emitError, context, entries);
-}
LogicalResult
DataLayoutSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
@@ -277,10 +239,6 @@ DataLayoutSpecAttr::combineWith(ArrayRef<DataLayoutSpecInterface> specs) const {
return DataLayoutSpecAttr::get(getContext(), entries);
}
-DataLayoutEntryListRef DataLayoutSpecAttr::getEntries() const {
- return getImpl()->entries;
-}
-
StringAttr
DataLayoutSpecAttr::getEndiannessIdentifier(MLIRContext *context) const {
return Builder(context).getStringAttr(DLTIDialect::kDataLayoutEndiannessKey);
@@ -303,6 +261,7 @@ DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(MLIRContext *context) const {
return Builder(context).getStringAttr(
DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
}
+
StringAttr
DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
return Builder(context).getStringAttr(
@@ -313,7 +272,7 @@ DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
/// attr ::= `#target.` `dl_spec` `<` attr-list? `>`
/// attr-list ::= attr
/// | attr `,` attr-list
-DataLayoutSpecAttr DataLayoutSpecAttr::parse(AsmParser &parser) {
+Attribute DataLayoutSpecAttr::parse(AsmParser &parser, Type type) {
if (failed(parser.parseLess()))
return {};
@@ -332,11 +291,103 @@ DataLayoutSpecAttr DataLayoutSpecAttr::parse(AsmParser &parser) {
}
void DataLayoutSpecAttr::print(AsmPrinter &os) const {
- os << DataLayoutSpecAttr::kAttrKeyword << "<";
+ os << "<";
llvm::interleaveComma(getEntries(), os);
os << ">";
}
+//===----------------------------------------------------------------------===//
+// TargetDeviceSpecAttr
+//===----------------------------------------------------------------------===//
+
+namespace mlir {
+/// A FieldParser for key-value pairs of DeviceID-target device spec pairs that
+/// make up a target system spec.
+template <>
+struct FieldParser<DeviceIDTargetDeviceSpecPair> {
+ static FailureOr<DeviceIDTargetDeviceSpecPair> parse(AsmParser &parser) {
+ std::string deviceID;
+
+ if (failed(parser.parseString(&deviceID))) {
+ parser.emitError(parser.getCurrentLocation())
+ << "DeviceID is missing, or is not of string type";
+ return failure();
+ }
+
+ if (failed(parser.parseColon())) {
+ parser.emitError(parser.getCurrentLocation()) << "Missing colon";
+ return failure();
+ }
+
+ auto target_device_spec =
+ FieldParser<TargetDeviceSpecInterface>::parse(parser);
+ if (failed(target_device_spec)) {
+ parser.emitError(parser.getCurrentLocation())
+ << "Error in parsing target device spec";
+ return failure();
+ }
+
+ return std::make_pair(parser.getBuilder().getStringAttr(deviceID),
+ *target_device_spec);
+ }
+};
+
+inline AsmPrinter &operator<<(AsmPrinter &printer,
+ DeviceIDTargetDeviceSpecPair param) {
+ return printer << param.first << " : " << param.second;
+}
+
+} // namespace mlir
+
+LogicalResult
+TargetDeviceSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+ ArrayRef<DataLayoutEntryInterface> entries) {
+ // Entries in a target device spec can only have StringAttr as key. It does
+ // not support type as a key. Hence not reusing
+ // DataLayoutEntryInterface::verify.
+ DenseSet<StringAttr> ids;
+ for (DataLayoutEntryInterface entry : entries) {
+ if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
+ return emitError()
+ << "dlti.target_device_spec does not allow type as a key: "
+ << type;
+ } else {
+ auto id = entry.getKey().get<StringAttr>();
+ if (!ids.insert(id).second)
+ return emitError() << "repeated layout entry key: " << id.getValue();
+ }
+ }
+
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// TargetSystemSpecAttr
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+TargetSystemSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+ ArrayRef<DeviceIDTargetDeviceSpecPair> entries) {
+ DenseSet<TargetSystemSpecInterface::DeviceID> device_ids;
+
+ for (const auto &entry : entries) {
+ TargetDeviceSpecInterface target_device_spec = entry.second;
+
+ // First verify that a target device spec is valid.
+ if (failed(TargetDeviceSpecAttr::verify(emitError,
+ target_device_spec.getEntries())))
+ return failure();
+
+ // Check that device IDs are unique across all entries.
+ TargetSystemSpecInterface::DeviceID device_id = entry.first;
+ if (!device_ids.insert(device_id).second) {
+ return emitError() << "repeated Device ID in dlti.target_system_spec: "
+ << device_id;
+ }
+ }
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// DLTIDialect
//===----------------------------------------------------------------------===//
@@ -376,33 +427,13 @@ class TargetDataLayoutInterface : public DataLayoutDialectInterface {
} // namespace
void DLTIDialect::initialize() {
- addAttributes<DataLayoutEntryAttr, DataLayoutSpecAttr>();
+ addAttributes<
+#define GET_ATTRDEF_LIST
+#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
+ >();
addInterfaces<TargetDataLayoutInterface>();
}
-Attribute DLTIDialect::parseAttribute(DialectAsmParser &parser,
- Type type) const {
- StringRef attrKind;
- if (parser.parseKeyword(&attrKind))
- return {};
-
- if (attrKind == DataLayoutEntryAttr::kAttrKeyword)
- return DataLayoutEntryAttr::parse(parser);
- if (attrKind == DataLayoutSpecAttr::kAttrKeyword)
- return DataLayoutSpecAttr::parse(parser);
-
- parser.emitError(parser.getNameLoc(), "unknown attrribute type: ")
- << attrKind;
- return {};
-}
-
-void DLTIDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
- llvm::TypeSwitch<Attribute>(attr)
- .Case<DataLayoutEntryAttr, DataLayoutSpecAttr>(
- [&](auto a) { a.print(os); })
- .Default([](Attribute) { llvm_unreachable("unknown attribute kind"); });
-}
-
LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
NamedAttribute attr) {
if (attr.getName() == DLTIDialect::kDataLayoutAttrName) {
@@ -413,6 +444,13 @@ LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
if (isa<ModuleOp>(op))
return detail::verifyDataLayoutOp(op);
return success();
+ } else if (attr.getName() == DLTIDialect::kTargetSystemDescAttrName) {
+ if (!llvm::isa<TargetSystemSpecAttr>(attr.getValue())) {
+ return op->emitError()
+ << "'" << DLTIDialect::kTargetSystemDescAttrName
+ << "' is expected to be a #dlti.target_system_spec attribute";
+ }
+ return success();
}
return op->emitError() << "attribute '" << attr.getName().getValue()
diff --git a/mlir/lib/Dialect/DLTI/Traits.cpp b/mlir/lib/Dialect/DLTI/Traits.cpp
index 85acbee46defd..34f2dd5896083 100644
--- a/mlir/lib/Dialect/DLTI/Traits.cpp
+++ b/mlir/lib/Dialect/DLTI/Traits.cpp
@@ -27,3 +27,8 @@ DataLayoutSpecInterface mlir::impl::getDataLayoutSpec(Operation *op) {
return op->getAttrOfType<DataLayoutSpecAttr>(
DLTIDialect::kDataLayoutAttrName);
}
+
+TargetSystemSpecInterface mlir::impl::getTargetSystemSpec(Operation *op) {
+ return op->getAttrOfType<TargetSystemSpecAttr>(
+ DLTIDialect::kTargetSystemDescAttrName);
+}
diff --git a/mlir/lib/IR/BuiltinDialect.cpp b/mlir/lib/IR/BuiltinDialect.cpp
index dcb1119fe5207..99796c5f1c371 100644
--- a/mlir/lib/IR/BuiltinDialect.cpp
+++ b/mlir/lib/IR/BuiltinDialect.cpp
@@ -155,6 +155,16 @@ DataLayoutSpecInterface ModuleOp::getDataLayoutSpec() {
return {};
}
+TargetSystemSpecInterface ModuleOp::getTargetSystemSpec() {
+ // Take the first and only (if present) attribute that implements the
+ // interface. This needs a linear search, but is called only once per data
+ // layout object construction that is used for repeated queries.
+ for (NamedAttribute attr : getOperation()->getAttrs())
+ if (auto spec = llvm::dyn_cast<TargetSystemSpecInterface>(attr.getValue()))
+ return spec;
+ return {};
+}
+
LogicalResult ModuleOp::verify() {
// Check that none of the attributes are non-dialect attributes, except for
// the symbol related attributes.
diff --git a/mlir/lib/Interfaces/DataLayoutInterfaces.cpp b/mlir/lib/Interfaces/DataLayoutInterfaces.cpp
index 15cfb3dbaf745..df86bd757b628 100644
--- a/mlir/lib/Interfaces/DataLayoutInterfaces.cpp
+++ b/mlir/lib/Interfaces/DataLayoutInterfaces.cpp
@@ -293,6 +293,15 @@ mlir::detail::getDefaultStackAlignment(DataLayoutEntryInterface entry) {
return value.getValue().getZExtValue();
}
+std::optional<int64_t>
+mlir::detail::getDevicePropertyValueAsInt(DataLayoutEntryInterface entry) {
+ if (entry == DataLayoutEntryInterface())
+ return std::nullopt;
+
+ auto value = cast<IntegerAttr>(entry.getValue());
+ return value.getValue().getZExtValue();
+}
+
DataLayoutEntryList
mlir::detail::filterEntriesForType(DataLayoutEntryListRef entries,
TypeID typeID) {
@@ -324,6 +333,16 @@ static DataLayoutSpecInterface getSpec(Operation *operation) {
});
}
+static TargetSystemSpecInterface getTargetSystemSpec(Operation *operation) {
+ if (operation) {
+ ModuleOp moduleOp = dyn_cast<ModuleOp>(operation);
+ if (!moduleOp)
+ moduleOp = operation->getParentOfType<ModuleOp>();
+ return moduleOp.getTargetSystemSpec();
+ }
+ return TargetSystemSpecInterface();
+}
+
/// Populates `opsWithLayout` with the list of proper ancestors of `leaf` that
/// are either modules or implement the `DataLayoutOpInterface`.
static void
@@ -433,7 +452,8 @@ void checkMissingLayout(DataLayoutSpecInterface originalLayout, OpTy op) {
mlir::DataLayout::DataLayout() : DataLayout(ModuleOp()) {}
mlir::DataLayout::DataLayout(DataLayoutOpInterface op)
- : originalLayout(getCombinedDataLayout(op)), scope(op),
+ : originalLayout(getCombinedDataLayout(op)),
+ originalTargetSystemDesc(getTargetSystemSpec(op)), scope(op),
allocaMemorySpace(std::nullopt), programMemorySpace(std::nullopt),
globalMemorySpace(std::nullopt), stackAlignment(std::nullopt) {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
@@ -443,7 +463,8 @@ mlir::DataLayout::DataLayout(DataLayoutOpInterface op)
}
mlir::DataLayout::DataLayout(ModuleOp op)
- : originalLayout(getCombinedDataLayout(op)), scope(op),
+ : originalLayout(getCombinedDataLayout(op)),
+ originalTargetSystemDesc(getTargetSystemSpec(op)), scope(op),
allocaMemorySpace(std::nullopt), programMemorySpace(std::nullopt),
globalMemorySpace(std::nullopt), stackAlignment(std::nullopt) {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
@@ -640,6 +661,26 @@ uint64_t mlir::DataLayout::getStackAlignment() const {
return *stackAlignment;
}
+std::optional<int64_t> mlir::DataLayout::getDevicePropertyValueAsInt(
+ TargetSystemSpecInterface::DeviceID deviceID,
+ StringAttr propertyName) const {
+ checkValid();
+ DataLayoutEntryInterface entry;
+ if (originalTargetSystemDesc) {
+ if (std::optional<TargetDeviceSpecInterface> device =
+ originalTargetSystemDesc.getDeviceSpecForDeviceID(deviceID))
+ entry = device->getSpecForIdentifier(propertyName);
+ }
+ // Currently I am not caching the results because we do not return
+ // default values of these properties. Instead if the property is
+ // missing, we return std::nullopt so that the users can resort to
+ // the default value however they want.
+ if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
+ return iface.getDevicePropertyValueAsInt(entry);
+ else
+ return detail::getDevicePropertyValueAsInt(entry);
+}
+
//===----------------------------------------------------------------------===//
// DataLayoutSpecInterface
//===----------------------------------------------------------------------===//
@@ -744,6 +785,55 @@ LogicalResult mlir::detail::verifyDataLayoutSpec(DataLayoutSpecInterface spec,
return success();
}
+LogicalResult
+mlir::detail::verifyTargetSystemSpec(TargetSystemSpecInterface spec,
+ Location loc) {
+ DenseMap<StringAttr, DataLayoutEntryInterface> deviceDescKeys;
+ DenseSet<TargetSystemSpecInterface::DeviceID> deviceIDs;
+ for (const auto &entry : spec.getEntries()) {
+ TargetDeviceSpecInterface targetDeviceSpec = entry.second;
+ // First, verify individual target device desc specs.
+ if (failed(targetDeviceSpec.verifyEntry(loc)))
+ return failure();
+
+ // Check that device IDs are unique across all entries.
+ TargetSystemSpecInterface::DeviceID deviceID = entry.first;
+ if (!deviceIDs.insert(deviceID).second) {
+ return failure();
+ }
+
+ // collect all the keys used by all the target device specs.
+ for (DataLayoutEntryInterface entry : targetDeviceSpec.getEntries()) {
+ if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
+ // targetDeviceSpec does not support Type as a key.
+ return failure();
+ } else {
+ deviceDescKeys[entry.getKey().get<StringAttr>()] = entry;
+ }
+ }
+ }
+
+ for (const auto &[keyName, keyVal] : deviceDescKeys) {
+ Dialect *dialect = keyName.getReferencedDialect();
+
+ // Ignore attributes that belong to an unknown dialect, the dialect may
+ // actually implement the relevant interface but we don't know about that.
+ if (!dialect)
+ return failure();
+
+ const auto *iface = dyn_cast<DataLayoutDialectInterface>(dialect);
+ if (!iface) {
+ return emitError(loc)
+ << "the '" << dialect->getNamespace()
+ << "' dialect does not support identifier data layout entries";
+ }
+ if (failed(iface->verifyEntry(keyVal, loc)))
+ return failure();
+ }
+
+ return success();
+}
+
#include "mlir/Interfaces/DataLayoutAttrInterface.cpp.inc"
#include "mlir/Interfaces/DataLayoutOpInterface.cpp.inc"
#include "mlir/Interfaces/DataLayoutTypeInterface.cpp.inc"
diff --git a/mlir/test/Dialect/DLTI/invalid.mlir b/mlir/test/Dialect/DLTI/invalid.mlir
index 465ec72106f70..d732fb462e68e 100644
--- a/mlir/test/Dialect/DLTI/invalid.mlir
+++ b/mlir/test/Dialect/DLTI/invalid.mlir
@@ -36,7 +36,7 @@
// -----
-// expected-error at below {{unknown attrribute type: unknown}}
+// expected-error at below {{unknown attribute `unknown` in dialect `dlti`}}
"test.unknown_op"() { test.unknown_attr = #dlti.unknown } : () -> ()
// -----
@@ -90,3 +90,68 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"unknown.unknown
// expected-note at above {{enclosing op with data layout}}
"test.op_with_data_layout"() { dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"unknown.unknown", 32>>} : () -> ()
}
+
+// -----
+
+// expected-error at below {{'dlti.target_system_spec' is expected to be a #dlti.target_system_spec attribute}}
+"test.unknown_op"() { dlti.target_system_spec = 42 } : () -> ()
+
+// -----
+
+// expected-error at below {{expected string}}
+// expected-error at below {{DeviceID is missing, or is not of string type}}
+// expected-error at below {{failed to parse DLTI_TargetSystemSpecAttr parameter 'entries' which is to be a `::llvm::ArrayRef<DeviceIDTargetDeviceSpecPair>`}}
+"test.unknown_op"() { dlti.target_system_spec = #dlti.target_system_spec<[]> } : () -> ()
+
+// -----
+
+module attributes {
+ // Device ID is missing
+ //
+ // expected-error at +4 {{expected string}}
+ // expected-error at +3 {{DeviceID is missing, or is not of string type}}
+ // expected-error at +2 {{failed to parse DLTI_TargetSystemSpecAttr parameter 'entries' which is to be a `::llvm::ArrayRef<DeviceIDTargetDeviceSpecPair>`}}
+ dlti.target_system_spec = #dlti.target_system_spec<
+ : #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 4096 : i32>>
+ >} {}
+
+// -----
+
+module attributes {
+ // Device ID is wrong type
+ //
+ // expected-error at +4 {{expected string}}
+ // expected-error at +3 {{DeviceID is missing, or is not of string type}}
+ // expected-error at +2 {{failed to parse DLTI_TargetSystemSpecAttr parameter 'entries' which is to be a `::llvm::ArrayRef<DeviceIDTargetDeviceSpecPair>`}}
+ dlti.target_system_spec = #dlti.target_system_spec<
+ 0: #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 4096: i32>>
+ >} {}
+
+// -----
+
+module attributes {
+ // Repeated Device ID
+ //
+ // expected-error at below {{repeated Device ID in dlti.target_system_spec: "CPU"}}
+ dlti.target_system_spec = #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 4096>>,
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 8192>>
+ >} {}
+
+// -----
+
+module attributes {
+ // Repeated DLTI entry
+ //
+ // expected-error at +4 {{repeated layout entry key: L1_cache_size_in_bytes}}
+ // expected-error at +6 {{Error in parsing target device spec}}
+ // expected-error at +5 {{failed to parse DLTI_TargetSystemSpecAttr parameter 'entries' which is to be a `::llvm::ArrayRef<DeviceIDTargetDeviceSpecPair>`}}
+ dlti.target_system_spec = #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 4096>,
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 8192>>
+ >} {}
diff --git a/mlir/test/Dialect/DLTI/roundtrip.mlir b/mlir/test/Dialect/DLTI/roundtrip.mlir
index 613dc354d895d..7b8255ad71d4d 100644
--- a/mlir/test/Dialect/DLTI/roundtrip.mlir
+++ b/mlir/test/Dialect/DLTI/roundtrip.mlir
@@ -53,3 +53,21 @@
}) { dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"unknown.unknown", 32>> } : () -> ()
"test.maybe_terminator_op"() : () -> ()
}) { dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"unknown.unknown", 32>> } : () -> ()
+
+// A valid target system description
+// CHECK: module attributes {
+// CHECK: dlti.target_system_spec = #dlti.target_system_spec<
+// CHECK: "CPU" : #dlti.target_device_spec<
+// CHECK: #dlti.dl_entry<"dlti.L1_cache_size_in_bytes", 4096 : ui32>>,
+// CHECK: "GPU" : #dlti.target_device_spec<
+// CHECK: #dlti.dl_entry<"dlti.max_vector_op_width", 128 : ui32>>
+// CHECK: >} {
+// CHECK: }
+module attributes {
+ dlti.target_system_spec = #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"dlti.L1_cache_size_in_bytes", 4096: ui32>>,
+ "GPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"dlti.max_vector_op_width", 128: ui32>>
+ >} {}
+
diff --git a/mlir/test/Dialect/DLTI/valid.mlir b/mlir/test/Dialect/DLTI/valid.mlir
new file mode 100644
index 0000000000000..98e9d0b8de491
--- /dev/null
+++ b/mlir/test/Dialect/DLTI/valid.mlir
@@ -0,0 +1,109 @@
+// RUN: mlir-opt -split-input-file %s | FileCheck %s
+
+// -----
+
+// CHECK: module attributes {
+// CHECK-SAME: dlti.target_system_spec = #dlti.target_system_spec<
+// CHECK-SAME: "CPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"L1_cache_size_in_bytes", 4096 : i32>>,
+// CHECK-SAME: "GPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"max_vector_op_width", 128 : i32>>
+// CHECK-SAME: >} {
+// CHECK: }
+module attributes {
+ dlti.target_system_spec = #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 4096: i32>>,
+ "GPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"max_vector_op_width", 128: i32>>
+ >} {}
+
+// -----
+
+// CHECK: module attributes {
+// CHECK-SAME: dlti.target_system_spec = #dlti.target_system_spec<
+// CHECK-SAME: "CPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"L1_cache_size_in_bytes", 4096 : i32>>,
+// CHECK-SAME: "GPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"L1_cache_size_in_bytes", 8192 : i32>>
+// CHECK-SAME: >} {
+// CHECK: }
+module attributes {
+ dlti.target_system_spec = #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 4096: i32>>,
+ "GPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 8192: i32>>
+ >} {}
+
+// -----
+
+// CHECK: module attributes {
+// CHECK-SAME: dlti.target_system_spec = #dlti.target_system_spec<
+// CHECK-SAME: "CPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"L1_cache_size_in_bytes", 4096 : i64>>,
+// CHECK-SAME: "GPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"L1_cache_size_in_bytes", 8192 : i64>>
+// CHECK-SAME: >} {
+// CHECK: }
+module attributes {
+ dlti.target_system_spec = #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 4096: i64>>,
+ "GPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 8192: i64>>
+ >} {}
+
+// -----
+
+// CHECK: module attributes {
+// CHECK-SAME: dlti.target_system_spec = #dlti.target_system_spec<
+// CHECK-SAME: "CPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"max_vector_op_width", 64 : i32>>,
+// CHECK-SAME: "GPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"max_vector_op_width", 128 : i32>>
+// CHECK-SAME: >} {
+// CHECK: }
+module attributes {
+ dlti.target_system_spec = #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"max_vector_op_width", 64: i32>>,
+ "GPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"max_vector_op_width", 128: i32>>
+ >} {}
+
+// -----
+
+// CHECK: module attributes {
+// CHECK-SAME: dlti.target_system_spec = #dlti.target_system_spec<
+// CHECK-SAME: "CPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"max_vector_op_width", 64 : i64>>,
+// CHECK-SAME: "GPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"max_vector_op_width", 128 : i64>>
+// CHECK-SAME: >} {
+// CHECK: }
+module attributes {
+ dlti.target_system_spec = #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"max_vector_op_width", 64: i64>>,
+ "GPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"max_vector_op_width", 128: i64>>
+ >} {}
+
+// -----
+
+// CHECK: module attributes {
+// CHECK-SAME: dlti.target_system_spec = #dlti.target_system_spec<
+// CHECK-SAME: "CPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"max_vector_op_width", 64 : i64>>,
+// CHECK-SAME: "GPU" : #dlti.target_device_spec<
+// CHECK-SAME: #dlti.dl_entry<"max_vector_op_width", 128 : i64>>
+// CHECK-SAME: >} {
+// CHECK: }
+module attributes {
+ dlti.target_system_spec = #dlti.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"max_vector_op_width", 64>>,
+ "GPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"max_vector_op_width", 128>>
+ >} {}
diff --git a/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp b/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
index 5f484294268ab..bcbfa88c5d815 100644
--- a/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
+++ b/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
@@ -32,6 +32,9 @@ constexpr static llvm::StringLiteral kGlobalKeyName =
constexpr static llvm::StringLiteral kStackAlignmentKeyName =
"dltest.stack_alignment";
+constexpr static llvm::StringLiteral kTargetSystemDescAttrName =
+ "dl_target_sys_desc_test.target_system_spec";
+
/// Trivial array storage for the custom data layout spec attribute, just a list
/// of entries.
class DataLayoutSpecStorage : public AttributeStorage {
@@ -91,6 +94,52 @@ struct CustomDataLayoutSpec
}
};
+class TargetSystemSpecStorage : public AttributeStorage {
+public:
+ using KeyTy = ArrayRef<DeviceIDTargetDeviceSpecPair>;
+
+ TargetSystemSpecStorage(ArrayRef<DeviceIDTargetDeviceSpecPair> entries)
+ : entries(entries) {}
+
+ bool operator==(const KeyTy &key) const { return key == entries; }
+
+ static TargetSystemSpecStorage *
+ construct(AttributeStorageAllocator &allocator, const KeyTy &key) {
+ return new (allocator.allocate<TargetSystemSpecStorage>())
+ TargetSystemSpecStorage(allocator.copyInto(key));
+ }
+
+ ArrayRef<DeviceIDTargetDeviceSpecPair> entries;
+};
+
+struct CustomTargetSystemSpec
+ : public Attribute::AttrBase<CustomTargetSystemSpec, Attribute,
+ TargetSystemSpecStorage,
+ TargetSystemSpecInterface::Trait> {
+ MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CustomDataLayoutSpec)
+
+ using Base::Base;
+
+ static constexpr StringLiteral name = "test.custom_target_system_spec";
+
+ static CustomTargetSystemSpec
+ get(MLIRContext *ctx, ArrayRef<DeviceIDTargetDeviceSpecPair> entries) {
+ return Base::get(ctx, entries);
+ }
+ DeviceIDTargetDeviceSpecPairListRef getEntries() const {
+ return getImpl()->entries;
+ }
+ LogicalResult verifySpec(Location loc) { return success(); }
+ std::optional<TargetDeviceSpecInterface>
+ getDeviceSpecForDeviceID(TargetSystemSpecInterface::DeviceID deviceID) {
+ for (const auto &entry : getEntries()) {
+ if (entry.first == deviceID)
+ return entry.second;
+ }
+ return std::nullopt;
+ }
+};
+
/// A type subject to data layout that exits the program if it is queried more
/// than once. Handy to check if the cache works.
struct SingleQueryType
@@ -197,6 +246,11 @@ struct OpWithLayout : public Op<OpWithLayout, DataLayoutOpInterface::Trait> {
return getOperation()->getAttrOfType<DataLayoutSpecInterface>(kAttrName);
}
+ TargetSystemSpecInterface getTargetSystemSpec() {
+ return getOperation()->getAttrOfType<TargetSystemSpecInterface>(
+ kTargetSystemDescAttrName);
+ }
+
static llvm::TypeSize getTypeSizeInBits(Type type,
const DataLayout &dataLayout,
DataLayoutEntryListRef params) {
@@ -244,6 +298,11 @@ struct OpWith7BitByte
return getOperation()->getAttrOfType<DataLayoutSpecInterface>(kAttrName);
}
+ TargetSystemSpecInterface getTargetSystemSpec() {
+ return getOperation()->getAttrOfType<TargetSystemSpecInterface>(
+ kTargetSystemDescAttrName);
+ }
+
// Bytes are assumed to be 7-bit here.
static llvm::TypeSize getTypeSize(Type type, const DataLayout &dataLayout,
DataLayoutEntryListRef params) {
@@ -308,6 +367,74 @@ struct DLTestDialect : Dialect {
}
};
+/// A dialect to test DLTI's target system spec and related attributes
+struct DLTargetSystemDescTestDialect : public Dialect {
+ MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(DLTargetSystemDescTestDialect)
+
+ explicit DLTargetSystemDescTestDialect(MLIRContext *ctx)
+ : Dialect(getDialectNamespace(), ctx,
+ TypeID::get<DLTargetSystemDescTestDialect>()) {
+ ctx->getOrLoadDialect<DLTIDialect>();
+ addAttributes<CustomTargetSystemSpec>();
+ }
+ static StringRef getDialectNamespace() { return "dl_target_sys_desc_test"; }
+
+ void printAttribute(Attribute attr,
+ DialectAsmPrinter &printer) const override {
+ printer << "target_system_spec<";
+ llvm::interleaveComma(
+ cast<CustomTargetSystemSpec>(attr).getEntries(), printer,
+ [&](const auto &it) { printer << it.first << ":" << it.second; });
+ printer << ">";
+ }
+
+ Attribute parseAttribute(DialectAsmParser &parser, Type type) const override {
+ bool ok = succeeded(parser.parseKeyword("target_system_spec")) &&
+ succeeded(parser.parseLess());
+ (void)ok;
+ assert(ok);
+ if (succeeded(parser.parseOptionalGreater()))
+ return CustomTargetSystemSpec::get(parser.getContext(), {});
+
+ auto parseDeviceIDTargetDeviceSpecPair =
+ [&](AsmParser &parser) -> FailureOr<DeviceIDTargetDeviceSpecPair> {
+ std::string deviceID;
+ if (failed(parser.parseString(&deviceID))) {
+ parser.emitError(parser.getCurrentLocation())
+ << "DeviceID is missing, or is not of string type";
+ return failure();
+ }
+ if (failed(parser.parseColon())) {
+ parser.emitError(parser.getCurrentLocation()) << "Missing colon";
+ return failure();
+ }
+
+ TargetDeviceSpecInterface targetDeviceSpec;
+ if (failed(parser.parseAttribute(targetDeviceSpec))) {
+ parser.emitError(parser.getCurrentLocation())
+ << "Error in parsing target device spec";
+ return failure();
+ }
+ return std::make_pair(parser.getBuilder().getStringAttr(deviceID),
+ targetDeviceSpec);
+ };
+
+ SmallVector<DeviceIDTargetDeviceSpecPair> entries;
+ ok = succeeded(parser.parseCommaSeparatedList([&]() {
+ auto deviceIDAndTargetDeviceSpecPair =
+ parseDeviceIDTargetDeviceSpecPair(parser);
+ ok = succeeded(deviceIDAndTargetDeviceSpecPair);
+ assert(ok);
+ entries.push_back(*deviceIDAndTargetDeviceSpecPair);
+ return success();
+ }));
+ assert(ok);
+ ok = succeeded(parser.parseGreater());
+ assert(ok);
+ return CustomTargetSystemSpec::get(parser.getContext(), entries);
+ }
+};
+
} // namespace
TEST(DataLayout, FallbackDefault) {
@@ -367,6 +494,15 @@ TEST(DataLayout, NullSpec) {
EXPECT_EQ(layout.getProgramMemorySpace(), Attribute());
EXPECT_EQ(layout.getGlobalMemorySpace(), Attribute());
EXPECT_EQ(layout.getStackAlignment(), 0u);
+
+ EXPECT_EQ(layout.getDevicePropertyValueAsInt(
+ Builder(&ctx).getStringAttr("CPU" /* device ID*/),
+ Builder(&ctx).getStringAttr("L1_cache_size_in_bytes")),
+ std::nullopt);
+ EXPECT_EQ(layout.getDevicePropertyValueAsInt(
+ Builder(&ctx).getStringAttr("CPU" /* device ID*/),
+ Builder(&ctx).getStringAttr("max_vector_width")),
+ std::nullopt);
}
TEST(DataLayout, EmptySpec) {
@@ -398,6 +534,15 @@ TEST(DataLayout, EmptySpec) {
EXPECT_EQ(layout.getProgramMemorySpace(), Attribute());
EXPECT_EQ(layout.getGlobalMemorySpace(), Attribute());
EXPECT_EQ(layout.getStackAlignment(), 0u);
+
+ EXPECT_EQ(layout.getDevicePropertyValueAsInt(
+ Builder(&ctx).getStringAttr("CPU" /* device ID*/),
+ Builder(&ctx).getStringAttr("L1_cache_size_in_bytes")),
+ std::nullopt);
+ EXPECT_EQ(layout.getDevicePropertyValueAsInt(
+ Builder(&ctx).getStringAttr("CPU" /* device ID*/),
+ Builder(&ctx).getStringAttr("max_vector_width")),
+ std::nullopt);
}
TEST(DataLayout, SpecWithEntries) {
@@ -449,6 +594,32 @@ TEST(DataLayout, SpecWithEntries) {
EXPECT_EQ(layout.getStackAlignment(), 128u);
}
+TEST(DataLayout, SpecWithTargetSystemDescEntries) {
+ const char *ir = R"MLIR(
+ module attributes { dl_target_sys_desc_test.target_system_spec =
+ #dl_target_sys_desc_test.target_system_spec<
+ "CPU": #dlti.target_device_spec<
+ #dlti.dl_entry<"L1_cache_size_in_bytes", 4096 : ui32>,
+ #dlti.dl_entry<"max_vector_op_width", 128 : ui32>>
+ > } {}
+ )MLIR";
+
+ DialectRegistry registry;
+ registry.insert<DLTIDialect, DLTargetSystemDescTestDialect>();
+ MLIRContext ctx(registry);
+
+ OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(ir, &ctx);
+ DataLayout layout(*module);
+ EXPECT_EQ(layout.getDevicePropertyValueAsInt(
+ Builder(&ctx).getStringAttr("CPU") /* device ID*/,
+ Builder(&ctx).getStringAttr("L1_cache_size_in_bytes")),
+ std::optional<int64_t>(4096));
+ EXPECT_EQ(layout.getDevicePropertyValueAsInt(
+ Builder(&ctx).getStringAttr("CPU") /* device ID*/,
+ Builder(&ctx).getStringAttr("max_vector_op_width")),
+ std::optional<int64_t>(128));
+}
+
TEST(DataLayout, Caching) {
const char *ir = R"MLIR(
"dltest.op_with_layout"() { dltest.layout = #dltest.spec<> } : () -> ()
More information about the Mlir-commits
mailing list