- 参考 MLIR 官网、MLIR 技术细节整理以及 MLIR 源码完成。其中一些细节可能随 LLVM 版本变化而变化。
- 学到哪里写到哪里。
文章目录
IR 结构
MLIR 结构按照 mlir::Operation
-> mlir::Region
-> mlir::Block
-> mlir::Operation
规则循环嵌套。一般情况下 mlir::ModuleOp
为最外层。
mlir::Operation
MLIR 所有操作的基础
可以视作有如下域 | 说明 | 方法 |
---|---|---|
parent | 父节点 | Block *getBlock() |
name | 名称 | OperationName getName() |
location | 位置 | Location getLoc() |
discardableAttrs/attrs | 普通属性 | ArrayRef<NamedAttribute> getDiscardableAttrs() |
inherentAttrs/properties | 固有属性 | std::optional<Attribute> getInherentAttr(StringRef name) |
operands | 操作数 | operand_range getOperands() |
results | 返回值 | result_range getResults() |
regions | 子区域 | MutableArrayRef<Region> getRegions() |
successors | 后继(仅 terminator) | SuccessorRange getSuccessors() |
uses/users | 使用关系 | use_range getUses(); user_range getUsers() |
注:
-
inherentAttrs/properties
主要由 tablegen 定义,主要包括arguments
中的Attr
类型参数以及部分Trait
生成,用于与普通属性(attribute)区分。而ArrayRef<NamedAttribute> getAttrs()
方法可以同时获得两种属性。// 示例 // 使用<{...}>表示固有属性 // 使用{...}表示普通属性 %1 = "func.call"(%0) <{callee = @func}> {newattr = "test"} : (i32) -> i32
-
使用
walk
函数遍历 -
可定义
RegionKindInterface
,默认情况下Region
为RegionKind::SSACFG
模式,表示存在 SSA 格式的控制流;也可以设置为RegionKind::Graph
模式 ,表示Region
内无控制流。
mlir::Op
tablegen 中继承 Op
时生成的基类,MLIR中的绝大多数操作都通过它来生成。可以视为 mlir::Operation
的某种封装?根据不同操作的实际需要,可以在tablegen文件中自定义。
可以视作有如下域 | 说明 | 方法 |
---|---|---|
Operation *state | 操作 | Operation *getOperation() |
Properties(实际储存在 state 中) | 固有属性 | InferredProperties &getProperties() |
注:
-
mlir::Op
定义了操作*
和->
,因此既可以使用op.func
访问mlir::Op
及其子类封装的方法,也可以使用op->func
访问mlir::Operation
类的方法。 -
MLIR 里的模块、函数、控制流等等结构实际上都可以定义为
mlir::Op
。
mlir::Block
用于包裹一组 mlir::Operation
可以视作有如下域 | 说明 | 方法 |
---|---|---|
parent | 父节点 | Region *getParent() |
operations | 一组操作 | OpListType &getOperations() |
arguments | 参数 | BlockArgListType getArguments() |
terminator | 终结符操作 | Operation *getTerminator() |
successors | 前驱(由 terminator 计算) | SuccessorRange getSuccessors() |
predecessors | 后继(由 terminator 计算) | iterator_range<pred_iterator> getPredecessors() |
注:
- 使用
walk
函数遍历 - 与
llvm::Block
的定义不同,默认情况下mlir::Block
内定义的值,可视范围仅为当前 Block 及其嵌套子结构,无法跨越 Block 边界,因此无法像 LLVM IR 中一样通过 Phi 节点实现跨 Block 的 SSA 结构,而是必须要通过参数传递的方式显示传递所有的值。
mlir::Region
用于包裹一组 mlir::Block
可以视作有如下域 | 说明 | 方法 |
---|---|---|
blocks | 一组 Block | BlockListType &getBlocks() |
arguments | 首个 Block 的参数 | BlockArgListType getArguments() |
parent/container | 父节点 | Operation *getParentOp() |
CFG | 调试用 | void viewGraph() |
注:
- 使用
walk
函数遍历
mlir::Value
类似 llvm::Value
作用,表示值。
// TODO SSA 模式与图模式
mlir::Type
// TODO
mlir::Attribute
// TODO
操作定义规范(ODS)
使用 TableGen 自动生成 C++ 代码的方法(文件名以 .inc
为结尾),这些代码需要手动导入。
TableGen语法
与 C++ 语法类似,文件名以 .td
结尾,需要使用专门的后端编译。详细语法参考 TableGen Programmer’s Reference。(需要注意,这一套规则仅供语法参考,实际的 MLIR 方言生成大多使用特殊规则,需要看特定注释,简单的建议只使用 let)
class
可以继承,使用如下。TableGenclass
的作用类似于 C++ 中的模板,需要def
才会实际生成 C++ 类。class A<Type1 t1, Type2 t2 = ""> : B<t2> { let x = t1; // 覆盖父类的字段 Type3 y = ?; // 定义新的字段 code z = [{ ... }]; // 强调该字段是代码, [{ ... }]包裹一段字符串,可以转行。 defvar t = 0; // 定义一个局部变量(不是字段),例如 defvar t = !ne(t2, "b"); assert condition, message; // 若条件为假,打印一条非致命错误信息 ... }
def
生成对应的 C++ 类。def a: A<"name", "size">{ ... }
dag
td参数可以是有向无环图(DAG),使用(operator arg0, arg1, argN)
表示,operator
可以是任何def
,常用的有ins outs region
等
注:
- 在 CMakeLists.txt 中可以很方便地使用 MLIR 提供的方法生成
.inc
:- 使用
add_circt_dialect(dialect dialect_namespace)
生成六个常用文件${dialect}.h.inc
,${dialect}.cpp.inc
,${dialect}Types.h.inc
,${dialect}Types.cpp.inc
,${dialect}Dialect.h.inc
,${dialect}Dialect.cpp.inc
。 - 使用
add_mlir_interface(interface)
生成两个常用文件${interface}.h.inc
,${interface}.cpp.inc
。
- 使用
Op
定义文件 mlir/include/mlir/IR/OpBase.td
,专门用于生成 mlir::Op
派生类的模板,挑一些我觉得重要的列出
字段 | 说明 | 生成C++类方法 |
---|---|---|
string summary | 简短描述 | |
string description | 详细描述 | |
dag arguments | 操作的参数,分操作数与属性(固有属性)两种。操作数为运行时值,属性为编译时常量 | 每个命名参数的 getter |
dag results | 返回值 | 每个命名返回值的 getter |
dag regions | 定义操作的子域 | 每个命名域的 getter |
list<OpBuilder> builders | 使用 mlir::OpBuilder::create 函数生成对应 Op 时,会调用 build 函数 | 默认生成两种常用的builder,在这里可以声明其他 builder |
string assemblyFormat | 自定义汇编格式,可通过设置 hasCustomAssemblyFormat 在 C++ 文件中自定义 | 生成 parser 与 print 两个函数 |
list<Trait> traits | traits, interfaces, and constraints 都被定义在这里,似乎可以从 InterfaceMap 中看到所有的内容。有点乱还没完全搞清楚 | |
code extraClassDeclaration | 额外的成员函数声明 | |
code extraClassDefinition | 额外的成员函数定义 |
其中汇编格式查询文档参考。
Conversion 方言转换
基于 pattern-match 模式的规则转换,基于 target
, patterns
, config
等定义的 mlir::OperationConverter
,通常有 Partial
,Full
与 Analysis
三种模式。三者均会以先序遍历的方式遍历控制树(包括嵌套子结构),并进行相应的类型转换。
注意:
- 遍历的顺序可能会被改变,详见下文 生成器 章节
Pattern 模式匹配
所有匹配都需要重写 match
与 rewrite
,或重写 matchAndRewrite
函数实现。需要满足以下约束:
match
阶段 IR 不应发生变化- 所有的 IR 改变均需要通过给定的
rewriter
修改 - 匹配分为两种模式,即字符串匹配与按照标签匹配,其中标签有任意、
interfaceID
、traitID
三种
类型 | 说明 | 注意事项 |
---|---|---|
mlir::RewritePattern | 虚基类 | |
mlir::ConversionPattern | 方言转换的基类 | 封装 matchAndRewrite ,暴露操作数映射后的值;可添加类型转换器; |
mlir::OpConversionPattern<SourceOp> | 针对 mlir::Op 派生类的封装 | 依据操作名进行字符串匹配; |
mlir::OpInterfaceConversionPattern<SourceOp> | 针对 mlir::OpInterface 派生类的封装 | 依据 interfaceID 进行匹配 |
mlir::OpTraitConversionPattern<TraitType> | 几乎没人用? | 依据 TraitType 进行匹配 |
Builder 生成器 / PatternRewriter / ConversionPatternRewriter
类型 | 说明 |
---|---|
mlir::Builder | 生成器的基类,管理内置的类型、属性、与 affine 表达式; |
mlir::OpBuilder | 提供基本的 IR 生成、克隆功能;内置 InsertPoint ;内置 Listener ,用于通知 IR 的变更 |
mlir::RewriterBase/mlir::PatternRewriter | 重写器的基类,提供大量 IR 重写方法 |
mlir::ConversionPatternRewriter | 提供大量 IR 转换的方法;内置 ConversionPatternRewriterImpl ,记录所有的 IRRewrite 过程 |
其中 mlir::detail::ConversionPatternRewriterImpl
常用的记录状态如下
域 | 说明 |
---|---|
mapping | 记录 Value ,Block ,Operation 三种映射关系 |
rewrites | 记录所有 IRRewrite 过程 |
replacedOps | 记录删除/替换的操作 |
regionToConverter | 记录每个 Region 使用的类型转换器 |
其中 IRRewrite
分为如下几类,可能会对 matchAndRewrite
的遍历顺序有一定影响:
类型 | 说明 | 对遍历的影响 |
---|---|---|
BlockRewrite | 直接反映到 IR 上,不可回退 | 会检查 block 参数;并立刻遍历父节点 |
MoveOperationRewrite | 直接反映到 IR 上,不可回退 | |
ModifyOperationRewrite | 直接反映到 IR 上,但修改前操作会记录,可回退 | 立刻遍历修改后的节点 |
ReplaceOperationRewrite | 删除/替换均记录为 ReplaceOperationRewrite ,不直接反映到 IR 上,直到调用 commit 方法才会真实修改 IR,可回退 | |
CreateOperationRewrite | 直接反映到 IR,不可回退 | 立刻遍历新生成的节点 |
UnresolvedMaterializationRewrite | - |