MLIR数据布局建模
参考文献链接
https://mlir.llvm.org/docs/DataLayout/
数据布局信息允许编译器回答与如何 特定类型的值存储在内存中。例如,值的大小 或其地址对齐要求。除其他外,它使一代人能够 抽象类型容器的各种线性内存寻址方案,以及关于向量的更深入的推理。
数据布局子系统旨在扩展到 MLIR 的开放类型和操作系统。在顶层,它包括:
- 可通过具体数据布局实现的属性接口规格;
- 应由受数据布局约束的类型实现的类型接口;
- 必须由可提供服务的操作实现的操作接口作为数据布局范围(例如模块);
- 以及与特定无关的数据布局属性的方言接口类型。
专门处理内置类型以降低总体查询成本。 同样,ModuleOp内置支持数据布局,而无需通过接口。
- 用法
- 自定义实现
- DataLayoutEntryInterface(DataLayoutEntryInterface)
- DataLayoutSpecInterface (DataLayoutSpecInterface)
- DataLayoutOpInterface (DataLayoutOpInterface)
- DataLayoutTypeInterface (DataLayoutTypeInterface)
- 默认实现
用法
范围
遵循 MLIR 的嵌套结构,数据布局属性的范围为 属于实现DataLayoutOpInterface理论操作的任一操作的区域。此类范围界定操作部分控制数据布局属性,并且可能具有影响的属性,通常组织在数据布局规范中。
类型在不同的作用域(包括作用域)中可能具有不同的数据布局嵌套在其他作用域中,例如其他模块中包含的模块。同时,在给定范围内(不包括任何嵌套范围),给定类型具有固定的数据布局属性。类型也应具有默认值, “自然”数据布局,以防它们在任何操作之外使用提供数据布局范围。这可确保数据布局查询始终有一个有效的结果。
兼容性和转换
计算布局属性所需的信息可以组合自嵌套范围。例如,外部作用域可以定义类型的子集,而内部作用域为不相交的子集或作用域定义它们 可以逐步放宽对类型的对齐要求。此机制是数据布局兼容性概念支持:在嵌套作用域应与外部作用域兼容。没有规定兼容性对特定操作和类型意味着什么,但为它们提供挂钩,以提供特定于目标和类型的检查。例如,可能希望只允许放宽对齐约束(即 较小的对齐方式)在嵌套模块中,或者,可能需要嵌套模块来完全重新定义外部作用域的所有约束。
在 IR 转换期间,数据布局兼容性也很重要。任何影响数据布局范围操作的转换应保持数据布局兼容性。由转型以确保确实如此。
查询
可以对特殊对象执行数据布局属性查询 – 可以为给定的范围操作创建该对象。这些 DataLayout对象允许与数据布局基础结构和查询进行交互DataLayout对象范围内给定类型的属性。类的签名如下。
class DataLayout {
public:
explicit DataLayout(DataLayoutOpInterface scope);
unsigned getTypeSize(Type type) const;
unsigned getTypeSizeInBits(Type type) const;
unsigned getTypeABIAlignment(Type type) const;
unsigned getTypePreferredAlignment(Type type) const;
};
用户可以为感兴趣的范围构造对象。因为 数据布局属性在作用域中是固定的,它们将仅计算 第一次请求并缓存一次以供进一步使用。因此,DataLayout(op.getParentOfType<DataLayoutOpInterface>()).getTypeSize(type)被认为是一种反模式,因为它在使用后会丢弃缓存。以 缓存,只要数据布局,就会返回有效的结果,封闭作用域的属性保持不变,也就是说,只要没有修改祖先操作的方式会影响数据布局。在这样的之后修改时,用户应创建一个新对象。为了帮助DataLayout以此断言,如果 MLIR 是DataLayout在启用断言的情况下编译。
自定义实现
数据布局建模的可扩展性通过一组 MLIR接口提供。
数据布局规范
数据布局规范是一个属性,即 从概念上讲,称为数据布局规范条目的键值对集合。数据布局规范属性实现DataLayoutSpecInterface,如下所述。每个条目本身就是一个属性 实现的DataLayoutSpecInterface。条目具有键(aor a)和值。键用于将条目与 特定类型或方言:处理数据布局属性请求时,一个 类型或方言只能看到与其相关的规范条目,并且 必须通过提供的对象进行任何递归查询。支持并强制实施更好的可组合性,因为类型不能(也不应该) 了解其他类型的布局详细信息。条目值是任意属性, 特定于类型。
例如,数据布局规范可能是具有 类似于以下内容的简单自定义语法:
#my_dialect.layout_spec<
#my_dialect.layout_entry<!my_dialect.type, size=42>,
#my_dialect.layout_entry<"my_dialect.endianness", "little">,
#my_dialect.layout_entry<!my_dialect.vector, prefer_large_alignment>>
规范和条目属性的确切详细信息,以及它们 语法,取决于实现。
我们在整个数据布局子系统中使用类型类的概念。它 对应于给定类型的C++类,例如,对于内置 整数。MLIR 没有在 IR 中表示类型类的机制。 相反,数据布局条目包含类型类的特定实例,用于 例如,IntegerType{signedness=signless, bitwidth=8}
(or i8
in the IR) or IntegerType{signedness=unsigned, bitwidth=32}
(or ui32
in the IR)。什么时候 处理数据布局属性查询时,将为类型类提供具有属于此类型类的键的所有条目。例如,将f32
or memref<?xi32>
请参阅条目,但不会看到那些(也不会看到条目)。这允许类型类可以计算的特定类型的“插值”行为 给定其他属性的任何特定类型实例的数据布局属性 实例。再次以整数为例,可以计算它们的对齐方式 通过取上面最接近的整数类型,具有 2 的幂 位宽。
DataLayoutEntryInterface (DataLayoutEntryInterface)
描述数据布局规范中的条目的属性接口。
DataLayoutEntryKey数据布局规范条目是一个键值对。它的关键是 类型,当条目与类型或类型类相关时,或者 标识符,当它 not.is 允许的别名时 以同时使用这两种密钥类型。它的值是一个任意属性,即 由键入键的类型或包含的方言解释 标识符键的标识符。该接口提供了一个钩子 可由特定实现用于委托验证 将特定键的适用性归因于相关类型或方言。
方法:
getKey
::mlir::DataLayoutEntryKey getKey();
返回此布局项的键。 注意:此方法必须由用户实现。
getValue
::mlir::Attribute getValue();
返回此布局项的值。 注意:此方法必须由用户实现。
verifyEntry
::mlir::LogicalResult verifyEntry(::mlir::Location loc);
检查条目的格式是否正确,在提供的位置报告错误。 注意:此方法必须由用户实现。
DataLayoutSpecInterface (DataLayoutSpecInterface)
描述数据布局规范的属性接口。
数据布局规范被视为一系列条目,每个条目 是实现数据布局入口接口的属性。它假设 条目的连续基础存储。接口提供了一个钩子 用于验证规范格式良好的实现, 使用默认实现来验证缺少条目 重复键和之前每个条目的良好格式 调度到与条目关联的类型或方言。
数据布局规范可能需要合并,以防它们出现在 嵌套操作受制于布局,或保证布局的有效性 修改。具体规范属性必须实现 相应的钩子。
方法:
combineWith
::mlir::DataLayoutSpecInterface combineWith(::llvm::ArrayRef<::mlir::DataLayoutSpecInterface> specs);
将当前布局与给定的布局列表相结合,从最外面(最旧)到最里面(最新)提供。失败时返回 null。 注意:此方法必须由用户实现。
getEntries
::mlir::DataLayoutEntryListRef getEntries();
返回布局条目的列表。 注意:此方法必须由用户实现。
getSpecForType
::mlir::DataLayoutEntryList getSpecForType(::mlir::TypeID type);
返回与类型参数的特定类型类相关的条目的副本。 注意:此方法必须由用户实现。
getSpecForIdentifier
::mlir::DataLayoutEntryInterface getSpecForIdentifier(::mlir::StringAttr identifier);
返回与给定标识符相关的条目(如果存在)。 注意:此方法必须由用户实现。
verifySpec
::mlir::LogicalResult verifySpec(::mlir::Location loc);
验证规范的有效性,并在给定位置报告任何错误。 注意:此方法必须由用户实现。
数据布局范围操作
定义数据布局查询范围的操作,可用于 创建对象,都期望实现DataLayoutOpInterface。此类操作必须至少提供一种获取 数据布局规范。规范不必附加到 操作作为属性,可以动态构造;它只是每个DataLayout对象获取一次并缓存。此类操作还可以提供 数据布局查询的自定义处理程序,无需转发即可提供结果 查询到特定类型或对返回的结果进行后处理 以特定于目标或范围的方式键入类型。这些自定义处理程序使之成为可能 用于范围操作,以(重新)定义类型的数据布局属性,而无需 必须修改类型本身,例如,当类型在另一个中定义时 方言。
DataLayoutOpInterface (DataLayoutOpInterface)
用于可附加数据布局规范的操作的接口。
可用于数据布局查询的对象可以是为此类操作而构建。缺少数据布局规范 必须处理不失败。
具体操作必须实现返回数据布局的钩子 规范。它们可以选择重写数据布局中使用的方法查询,其默认实现提供预定义的答案 内置类型,并调度到所有其他类型的类型接口。这些方法必须是幂等的,即重复返回相同的结果 具有相同参数的查询。它们被声明为静态的,因此 无权访问操作或其属性。相反,他们会收到一个 与请求相关的数据布局条目列表。条目已知已通过规范和条目验证程序。
方法:
getDataLayoutSpec
::mlir::DataLayoutSpecInterface getDataLayoutSpec();
返回此操作的数据布局规范,如果不存在,则返回 null。 注意:此方法必须由用户实现。
getTypeSize
static unsigned getTypeSize(::mlir::Type type, const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
返回使用相关条目计算的给定类型的大小。数据布局对象可用于递归查询。 注意:此方法必须由用户实现。
getTypeSizeInBits
static unsigned getTypeSizeInBits(::mlir::Type type, const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
返回给定类型的大小(以使用相关条目计算的位数为单位)。数据布局对象可用于递归查询。 注意:此方法必须由用户实现。
getTypeABIAlignment
static unsigned getTypeABIAlignment(::mlir::Type type, const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
返回 ABI 对使用相关条目计算的给定类型所需的对齐方式。数据布局对象可用于递归查询。 注意:此方法必须由用户实现。
getTypePreferredAlignment
static unsigned getTypePreferredAlignment(::mlir::Type type, const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
返回使用相关条目计算的给定类型首选的对齐方式。数据布局对象可用于递归查询。 注意:此方法必须由用户实现。
具有数据布局的类型
预期打算自行处理数据布局查询的类型类来实施DataLayoutTypeInterface。此接口提供可覆盖的 每个数据布局查询的挂钩。这些钩子中的每一个都提供类型实例、DataLayout适用于递归查询的对象,以及与类型类相关的数据布局查询。预计将提供一个 即使条目列表为空,结果也有效。这些钩子没有 访问处理查询的范围内的操作,并且应该 请改用提供的条目。
DataLayoutTypeInterface (DataLayoutTypeInterface)
受数据布局约束的类型的接口。
愿意由数据布局子系统支持的类型应实现 此接口通过提供查询其函数的实现 大小、所需和首选对齐方式。这些函数中的每一个都接受为 参数 可用于执行递归查询的数据布局对象 在同一范围内,以及与此类型相关的数据布局条目列表。 具体来说,这些条目是那些将 与当前类型相同的类型类。例如,如果 IntegerType 有实现了这个接口,它将接收带有键 i1 的条目, i2、i8 等,无论此类型的位宽如何。此机制允许类型,以特定于类型的方式“插值”结果,而不是列出 规范中的所有可能类型。
条目列表可能为空,在这种情况下,类型必须提供 合理的默认值。已知列表中的条目已通过规范和条目验证程序,以及类型指定的验证程序(如果) 提供。
在嵌套布局规范或规范更改的情况下,类型可以覆盖挂钩 指示外部(旧)和内部(新)规范是否兼容。
方法:
getTypeSize
unsigned getTypeSize(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
返回此类型的大小(以字节为单位)。 注意:此方法必须由用户实现。
getTypeSizeInBits
unsigned getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
返回此类型的大小(以位为单位)。 注意:此方法必须由用户实现。
getABIAlignment
unsigned getABIAlignment(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
返回此类型所需的对齐方式(以字节为单位) 注意:此方法必须由用户实现。
getPreferredAlignment
unsigned getPreferredAlignment(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
返回此类型的首选对齐方式(以字节为单位)。 注意:此方法必须由用户实现。
areCompatible
bool areCompatible(::mlir::DataLayoutEntryListRef oldLayout, ::mlir::DataLayoutEntryListRef newLayout);
如果两个条目列表兼容,则返回 true,也就是说,newLayout spec 条目可以嵌套在具有oldLayout规范的操作条目中。 注意:此方法必须由用户实现。
verifyEntries
::mlir::LogicalResult verifyEntries(::mlir::DataLayoutEntryListRef entries, ::mlir::Location loc);
验证给定的条目列表是否对此类型有效。 注意:此方法必须由用户实现。
具有数据布局标识符的方言
对于与特定类型类无关的数据布局条目,键的条目是属于某种方言的标识符。在这种情况下, 方言有望实现DataLayoutDialectInterface。这种方言提供用于验证条目值属性有效性的钩子和以及嵌套条目的兼容性。
位和字节
为大小提供了两个版本的钩子:以位为单位和以字节为单位。版本 (以字节为单位)有一个默认实现,该实现通过舍入来派生大小(以字节为单位) 将大小(以位为单位)除以 8 的结果向上。专门定位的类型 具有不同假设的体系结构可以覆盖这一点。操作可以 为所有类型重新定义此值,为字节大小的情况提供作用域版本,无需修改类型,包括内置类型。
查询调度
数据布局属性查询的整体流程如下所示。
- 用户在给定的DataLayout范围内构造。构造函数获取数据布局规范并将其与 封闭范围(布局应兼容)。
- 用户调用DataLayout::query(Type ty) 。
- 如果DataLayout有缓存的响应,则返回此马上响应。
- 否则,查询将传递到最接近的布局 范围操作。如果它实现了DataLayoutOpInterface,则查询DataLayoutOpInterface::query(ty, *this, relevantEntries)被转发到如上所述计算相关条目的位置。如果没有 实现,它必须是DataLayoutTypeInterface::query(dataLayout, relevantEntries),并且查询是 转发到后转换到类型接口。
- 除非 op 接口重新实现钩子,否则查询是 进一步处理DataLayoutTypeInterface::query(dataLayout, relevantEntries)到转换ty到类型接口之后。如果类型符合 不实现接口,会产生无法恢复的致命错误。
- 该类型应始终提供响应,该响应返回并由DataLayout调用堆栈.
默认实现
数据布局接口的默认实现直接处理查询内置类型的子集。
内置模块
内置ModuleOp最多允许一个实现DataLayoutSpecInterface的属性。它不实现整个接口 效率和分层原因。相反,DataLayout可以与其他操作一起透明地构建ModuleOp和处理模块 实现接口。
内置类型
下面介绍内置类型的默认属性。
内置整数和浮点数(以字节为单位)的大小计算为。位宽低于的整数类型的 ABI 对齐方式 浮点数的 64 和浮点类型是最接近的 2 的幂数 字节。位宽为 64 及以上的整数类型的 ABI 对齐方式为 4 个字节 (32 位)。ceildiv(bitwidth, 8)
内置向量的大小是通过首先将其数量四舍五入来计算的 最内层维度中的元素与上方最接近的二的幂, 然后得到元素的总数,最后乘以 元素大小。例如,vector<3xi32>
与 vector<4xi32>
并且具有相同的大小。所以vector<2x3xf32>
and vector<2x4xf32>
, but vector<3x4xf32>
and vector<4x4xf32>
,但有不同的大小。ABI 和首选对齐方式 向量类型是通过取向量的最内层维度来计算的, 将其四舍五入到最接近的 2 次方,取其乘积 元素大小(以字节为单位),并将结果再次向上舍入到最接近的 二的幂。
注意:选择这些值是为了与LLVM中的默认数据布局保持一致, 在引入适当的数据布局建模之前,MLIR假设了这一点,以及与n-D 向量建模。
index类型
索引类型是用于目标特定大小信息的整数类型, 例如,操作。其数据布局由单个整数参数化 指定其位宽的数据布局条目。例如memref
module attributes { dlti.dl_spec = #dlti.dl_spec<
#dlti.dl_entry<index, 32>
>} {}
指定有 32 位。匹配的所有其他布局属性index具有上面定义的相同位宽的整数类型的那些index。
在没有相应条目的情况下,index假定为 64 位整数。
complex类型
默认情况下,复杂类型被视为其给定的 2 元素结构元素类型。也就是说,每个元素都与它们的首选对齐,整个复杂类型也与此首选项对齐,复杂类型大小包括元素之间可能的填充以强制实施对准。
字节大小
默认数据布局假定为 8 位字节。
DLTI方言
DLTI方言提供属性实现DataLayoutSpecInterface
和 DataLayoutEntryInterface
,以及方言。可用于将规范附加到给定操作的属性。属性的验证程序触发规范的验证程序并检查嵌套规范的兼容性。
参考文献链接
https://mlir.llvm.org/docs/DataLayout/
标签:DataLayout,布局,建模,mlir,条目,MLIR,类型,数据 From: https://www.cnblogs.com/wujianming-110117/p/16862531.html