MLIR Op-Model 契约
本页中的所有地址、符号和计数均适用于来自
libtpu-0.0.40-cp314wheel 的libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d,构建libtpu_lts_20260413_b_RC00)。.symtab未被 stripped(1,233,709 个符号);每个断言都锚定到 demangled 符号、重定位 addend 或反编译主体。其他版本会不同,尤其是 23-slot 顺序被固定到此二进制捆绑的 LLVM SHA。
摘要
libtpu 中的每个 MLIR 方言,包括 tpu、llo、sparse_core、mosaic_sc、xtile 以及另外 56 个输入/旁路方言(共 61 个 namespace),都通过一个共享的、版本固定的 ABI 注册其操作。本页以通用方式记录该 ABI:OperationName::Impl interned-op 记录、填充它的 RegisteredOperationName::Model<Op> 类型擦除 concept、每个 Model<Op> 暴露的 23-slot vtable 契约,以及一次 op-dispatch 调用(fold、verify、getInherentAttr)如何通过该 vtable 解析到具体操作的 ODS 生成静态函数。它是契约;实例化该契约的逐方言操作名册位于各自页面。tpu 方言页面拥有 86 个 tpu 操作、它们的接口 fan-out,以及 fold/canonicalize 统计,并引用本页作为 23-slot 契约的所有者。
该机制是经典的 C++ 类型擦除,任何读过 MLIR 上游代码的人都会熟悉。OperationName 是指向一个 interned、逐操作种类 OperationName::Impl 的句柄。Impl 是抽象接口,即一张操作 hook(fold、verify、parse/print、属性和 property 管理)的 vtable;二进制中有两个具体实现:RegisteredOperationName::Model<Op>,一个 CRTP 模板,每个注册操作实例化一次,把每个 hook 转发到该操作的编译器生成静态函数;以及 OperationName::UnregisteredOpModel,它是从文本解析但没有方言声明的操作的单一 fallback。该二进制持有 6,050 个不同的 Model<Op> 实例,正好等于 61 个方言 namespace 的注册操作总数。
本页依次说明:OperationName::Impl 记录和 Concept/Model<Op> CRTP 对;逐符号遍历的 23-slot vtable;一个具体操作如何绑定到其 Model(addOperations → insert 注册路径,以及从 Model thunk 到 ODS static 的三级委托);接口调用如何解析,包括 23-slot vtable 只作为闸门进入的第二类型擦除层(<Iface>InterfaceTraits::Model<Op>);以及调用方侧的 dispatch 点。全文中,参考操作是 xla::PureCallOp,并在 tpu::IotaOp、llo::ConstantOp 和 mosaic_sc::RelayoutOp 上复现:三个方言,一个 ABI。
对于重新实现,契约是:
OperationName::Impl记录和Concept/Model<Op>CRTP:抽象接口基类、其注册(Model<Op>)和未注册(UnregisteredOpModel)具体子类,以及解析它们的 Itanium PIE vtable 布局。- 23-slot dispatch 契约:每个 slot 都标注到其 demangled
Model<Op>::<method>符号、1 个共享 + 22 个逐操作的结构,以及四个功能性 slot 分组。 - Op↔Model 绑定:
Dialect::addOperations<Op…>→RegisteredOperationName::insert,以及三级委托(Model thunk → inline-property 解包 → ODS static /UniqueFunctionholder)。 - 接口解析:slot-4
hasTrait作为成员资格闸门,以及承载接口主体的独立<Iface>InterfaceTraits::Model<Op>concept 层。
| Interned-op 记录 | mlir::OperationName::Impl,抽象 op-hook 接口基类 |
| 注册的具体 impl | mlir::RegisteredOperationName::Model<Op>(CRTP,每个注册操作一个) |
| 未注册 fallback impl | mlir::OperationName::UnregisteredOpModel(单例,文本解析操作) |
| Model vtable 数量(所有方言) | 6,050,跨 61 个 namespace(= 注册操作总数) |
| 每个 Model 的 vtable slot | 23 = slot 0 共享基类 dtor + slot 1 逐操作 dtor + slots 2–22 dispatch |
| 共享 slot-0 dtor | mlir::OperationName::Impl::~Impl @ 0xfea8820(D2;所有 Model 的 addend 相同) |
| 注册 sink | RegisteredOperationName::insert(unique_ptr<OperationName::Impl>, ArrayRef<StringRef>) @ 0x1d8c57a0 |
| 逐方言 registrar | addOperations<Op…> 家族;二进制全局 243 个符号(224 个 Dialect::addOperations + 19 个 TransformDialect::addOperationsChecked);243 个都 demangle 为不同签名 |
| 参考 Model 遍历 | Model<xla::PureCallOp> slots @ 0x150d56c0…0x150d5c20 |
| 调用方侧 dispatch | mlir::Operation::fold @ 0x1d8cd480 → call *0x10(vptr) = slot 2 |
| 第二接口层 | mlir::detail::<Iface>InterfaceTraits::Model<Op>(基于 Concept) |
| 置信度 | 已确认(字节锚定),除非某行或标注另有说明 |
OperationName::Impl 记录和 Concept/Model CRTP
MLIR 通过 OperationName 标识一种操作,后者是一个轻量句柄,包装指向 interned、逐种类 OperationName::Impl 的指针。Impl 持有操作名字符串、拥有方言的 Dialect*、TypeID 和 InterfaceMap(操作实现的接口 concept 集合);关键的是,它就是 dispatch vtable:MLIR 需要的每个操作 hook(fold、verify、print、属性/property 管理)都是 Impl 上的 virtual。构造函数签名被完整恢复:
mlir::OperationName::Impl::Impl(
llvm::StringRef name, mlir::Dialect*, mlir::TypeID,
mlir::detail::InterfaceMap) @ 0x1d8c4d80
```text
`Impl` 是抽象的;二进制对其 21-hook 接口恰好带有**两个**具体实现:
```text
mlir::OperationName::Impl (abstract interface)
~Impl @ 0xfea8820 (D2) · 21 pure-virtual op hooks
│
┌─────────────────┴──────────────────┐
▼ ▼
RegisteredOperationName::Model<Op> OperationName::UnregisteredOpModel
CRTP, one instantiation per single instance, the fallback for
registered op (6,050 total) ops parsed from text without a
each hook forwards to Op's ODS registered dialect; each hook is a
statics / UniqueFunction holder generic no-op / diagnostic stubModel<Op> 是教科书式的类型擦除 Concept/Model 对:Impl 是 Concept(抽象接口),Model<Op> 是 Model(逐类型具体实现),以具体操作类型为模板参数,让编译器在实例化时为每个 hook 生成转发 thunk。这与 MLIR 用于 OpInterface dispatch 的惯用法相同;事实上,下面的接口层显式把其类型命名为 Concept 和 Model<Op>。下一节记录的 23-slot vtable 就是一个 Model<Op> 实现的布局。
注意:
UnregisteredOpModel承载相同的 21-hook 表面。 未注册(文本解析)操作的 fallbackmlir::OperationName::UnregisteredOpModel实现了注册Model<Op>所有的 hook:foldHook、hasTrait、getCanonicalizationPatterns、printAssembly、verifyInvariants、verifyRegionInvariants、四个 inherent-attr 访问器、九个 property slot、getParseAssemblyFn、populateDefaultAttrs。这确认该表面是抽象Impl接口,而不是Model专属扩展。重新实现者的Impl基类必须把全部 21 个都声明为 virtual;两个子类都覆盖全部 21 个。
23-Slot Model<Op> Vtable
对于注册操作,interned 的 OperationName::Impl 是一个 RegisteredOperationName::Model<Op>,其 vtable 遵循 Itanium PIE 布局:vtable+0x00 是 offset-to-top(0),vtable+0x08 指向 _ZTI…Model<Op>… typeinfo,vtable+0x10 是地址点,也就是对象 vptr 存储的值以及 slot 0 的位置。Slot i 位于 vtable+0x10+8i。在磁盘镜像中,slot word 为零;加载时由 R_X86_64_RELATIVE 重定位填充,其 addend 为方法地址。将每个 addend 与排序后的符号表解析即可恢复每个 slot 的方法。
参考遍历对象是 Model<xla::PureCallOp>;同样的 23 个标签以字节级相同的顺序和签名出现在 Model<mlir::tpu::IotaOp>、Model<mlir::llo::ConstantOp> 和 Model<mlir::mosaic_sc::RelayoutOp> 上。右列中的 slot addend 是 PureCallOp 的(来自反编译符号集合 @ 0x150d56c0…0x150d5c20)。
RegisteredOperationName::Model<Op> vtable (address point = +0x10 = slot 0)
slot off method (Model<Op>::…) PureCallOp addend
---- ---- ------------------------------------------ -----------------
0 0x00 OperationName::Impl::~Impl 0xfea8820 (SHARED ∀ ops)
1 0x08 ~Model [deleting] per-op (D0)
2 0x10 foldHook(Operation*, ArrayRef<Attribute>, 0x150d56c0
SmallVectorImpl<OpFoldResult>&)
3 0x18 getCanonicalizationPatterns( 0x150d5740
RewritePatternSet&, MLIRContext*)
4 0x20 hasTrait(TypeID) 0x150d5760
5 0x28 getParseAssemblyFn() 0x150d57e0
6 0x30 populateDefaultAttrs(OperationName const&, 0x150d5800
NamedAttrList&)
7 0x38 printAssembly(Operation*, OpAsmPrinter&, 0x150d5820
StringRef)
8 0x40 verifyInvariants(Operation*) 0x150d58a0
9 0x48 verifyRegionInvariants(Operation*) 0x150d5940
10 0x50 getInherentAttr(Operation*, StringRef) 0x150d59e0
11 0x58 setInherentAttr(Operation*, StringAttr, 0x150d5a40
Attribute)
12 0x60 populateInherentAttrs(Operation*, 0x150d5aa0
NamedAttrList&)
13 0x68 verifyInherentAttrs(OperationName, 0x150d5ae0
NamedAttrList&, function_ref<…>)
14 0x70 getOpPropertyByteSize() 0x150d5b00
15 0x78 initProperties(OperationName, PropertyRef, 0x150d5b20
PropertyRef)
16 0x80 deleteProperties(PropertyRef) 0x150d5b40
17 0x88 populateDefaultProperties(OperationName, 0x150d5b60
PropertyRef)
18 0x90 setPropertiesFromAttr(OperationName, 0x150d5b80
PropertyRef, Attribute, fn_ref<…>)
19 0x98 getPropertiesAsAttr(Operation*) 0x150d5ba0
20 0xa0 copyProperties(PropertyRef, PropertyRef) 0x150d5be0
21 0xa8 compareProperties(PropertyRef,PropertyRef) 0x150d5c00
22 0xb0 hashProperties(PropertyRef) 0x150d5c20
```text
这 23 个 slot 聚为四个功能组,每组都有不同的绑定形态(见下一节):
- **Slots 2–9:dispatch 表面。** Folding、canonicalization、trait/interface 闸门(`hasTrait`)、自定义 parse/print、默认属性填充,以及两个 verifier。Slots 2、3、7、8 以及 4 是*间接*的:每个操作都有这些 slot,但会路由通过一个 `UniqueFunction` holder;除非操作定义了该 hook,否则 holder 包装的是 no-op。
- **Slots 10–13:inherent-attribute 访问器。** Inherent attributes 是操作的*声明*属性(例如 `iota` 的 `dimensions`),区别于 discardable 属性。这四个 slot 计算 inline-property 偏移,然后直接 tail-jump 到该操作的 ODS 静态函数。
- **Slots 14–22:property 管理。** MLIR 的 `Properties` 是操作 inherent attribute 和 variadic operand-segment size 的内联存储。这九个 slot 负责大小、构造、析构、复制、比较、哈希和序列化/反序列化该存储。
> **细节:"23-slot Model" 在结构上是 1 个共享 + 22 个逐操作,而不是 23 个逐操作。** Slot 0,也就是每个对象 vptr 存储的地址点,在所有 6,050 个 Model 中都是*相同*的重定位 addend `0xfea8820`(`mlir::OperationName::Impl::~Impl`,D2 基类子对象析构函数)。它是公共 `OperationName::Impl` 基类子对象的析构函数,按构造共享,而不是为每个操作复制。只有 slots 1–22 是逐操作模板实例:slot 1 是 `Model<Op>::~Model`(D0 deleting dtor),slots 2–22 是 dispatch thunk。重新实现者应把 `Model<Op>` 建模为*一个共享基类析构函数加 22 个操作专属条目*。(直接验证:`OperationName::Impl::~Impl` 解析为 `0xfea8820`;不同 `Model<…>::~Model` D0 符号的计数正好为 6,050。)
>
> **细节:`getOpPropertyByteSize`(slot 14)是内联的 `sizeof(Op::Properties)` 常量,不是计算。** 编译器把该 slot 折叠为字面量 `return`。`Model<mlir::tpu::IotaOp>::getOpPropertyByteSize`(@ `0x14ac19c0`)反编译为 `return 8;`,即 8 字节,单个 `dimensions` `DenseArrayAttr` 句柄。对于没有 `Properties` 的操作,它返回 0(`xor %eax,%eax; ret`)。这个双指令主体是判断“此操作是否有 inline properties”的最低成本诊断;九个 property slot(14–22)只有在该值非零时才做实际工作。
---
## Op↔Model 绑定
一个具体操作绑定到其 23-slot Model,不是通过手写子类覆盖 virtual,而是通过**模板实例化 + 委托**,分三层完成。
### Level 1:注册:addOperations → insert
每个方言用一个 variadic `Dialect::addOperations<Op…>` 模板实例注册其操作,该实例从方言的 `initialize()` 调用。实例的*arity* 就是方言操作数量,应从符号读出,而不是字符串扫描。恢复出的 `tpu` registrar 头部如下:
```text
mlir::Dialect::addOperations<
mlir::tpu::AllReduceOp, mlir::tpu::AllocaSemaphoreOp,
mlir::tpu::AssumeLayoutOp, mlir::tpu::AssumeMultipleOp,
mlir::tpu::BarrierOp, mlir::tpu::BitcastOp, …> @ 0x14aa2c40对于 pack 中的每个 Op,addOperations 物化一个 Model<Op>(其实例 vtable 持有 23 个 Model<Op>::* thunk),并把它交给单一的非模板注册 sink:
mlir::RegisteredOperationName::insert(
std::unique_ptr<mlir::OperationName::Impl, …>, ← the Model IS the Impl
llvm::ArrayRef<llvm::StringRef>) @ 0x1d8c57a0
```text
`Model<Op>` *就是* `OperationName::Impl`;注册的含义是“把这个 Impl 以操作名 intern 进去”。二进制全局有 **243** 个不同的 `addOperations<…>` 家族符号,其中 224 个为 `mlir::Dialect::addOperations<…>`,19 个为 `mlir::transform::TransformDialect::addOperationsChecked<…>`;243 个全部 demangle 为**不同**签名(没有折叠),每个注册方言一个(有些方言分成多个批次)。重新实现者的方言初始化路径是:为每个操作构建一个 `Model<Op>`,按 mnemonic `insert`;`Impl` 的所有权通过 `unique_ptr` 转移到 context 的 interning map 中。
### Level 2:逐 slot 委托到 ODS statics
每个 `Model<Op>::slotN` thunk 做两件事:定位操作的 `Properties` 存储(inline 还是 out-of-line,由 `Operation` flag word 选择),然后 tail-call 到 ODS 生成的静态函数。inline-property-offset 惯用法在所有操作以及 slots 10–13 中都相同。`Model<tpu::IotaOp>::getInherentAttr`(slot 10 @ `0x14ac18a0`)的反编译主体正是这个形状:
```c
// Model<mlir::tpu::IotaOp>::getInherentAttr (slot 10 @ 0x14ac18a0)
Attr getInherentAttr(Operation* op, StringRef name):
ctx = Attribute::getContext(op->result_type_attr); // op + 24
props = op + ((op->flags >> 19) & 0x10) + 64; // flags @ op+0x2c (44):
// bit 19 picks inline (+0x10)
// vs out-of-line storage;
// inline base is op+0x40 (64)
return mlir::tpu::IotaOp::getInherentAttr(ctx, *props, name); // TAIL-CALLtail-call 目标是具体操作的 ODS static,恢复为 demangled 符号:
mlir::tpu::IotaOp::getInherentAttr(
mlir::MLIRContext*,
mlir::tpu::detail::IotaOpGenericAdaptorBase::Properties const&,
llvm::StringRef) @ 0x14b220e0
```text
四个 inherent-attribute slot(10–13)都使用这种直接 tail-call 形态;property slot(14–22)同样转发到逐操作的 `readProperties`/`writeProperties`/`computePropertiesHash` ODS static,并且 slot 14 如上所述被折叠为内联 `sizeof` 常量。
### Level 3:通过 UniqueFunction callback-holder 的间接 hook
*间接* hook,即 `foldHook`(2)、`getCanonicalizationPatterns`(3)、`hasTrait`(4)、`printAssembly`(7)、`verifyInvariants`(8),会再包一层 indirection,位于 `llvm::detail::UniqueFunctionBase<…>::CallbacksHolder<Op<Op,Traits…>::get<Hook>Fn()::lambda>` 中。slot 加载 holder 指针并执行 `call *(%rax)`(或对更大的 holder 执行 `call *0x10(%rax)`)。`Model<tpu::IotaOp>::hasTrait`(slot 4 @ `0x14ac1620`)的反编译结果明确命名了 holder:
```text
llvm::detail::UniqueFunctionBase<bool, mlir::TypeID>::CallbacksHolder<
mlir::Op<mlir::tpu::IotaOp,
mlir::OpTrait::ZeroRegions, mlir::OpTrait::OneResult,
mlir::OpTrait::OneTypedResult<mlir::VectorType>::Impl,
mlir::OpTrait::ZeroSuccessors, mlir::OpTrait::ZeroOperands,
mlir::OpTrait::OpInvariants,
mlir::BytecodeOpInterface::Trait,
mlir::ConditionallySpeculatable::Trait,
mlir::OpTrait::AlwaysSpeculatableImplTrait,
mlir::MemoryEffectOpInterface::Trait>::getHasTraitFn()::lambda, …>第三层就是操作完整 trait 和接口列表被编码的位置:holder 符号携带完整的 Op<OpName, Trait1, …, Interface::Trait, …> 模板签名。对于上面的 IotaOp,可以直接读出接口 trait:BytecodeOpInterface、ConditionallySpeculatable、MemoryEffectOpInterface。从逐操作 getFoldHookFn/getHasTraitFn holder 读取这些模板参数,是各方言页面恢复每个操作接口 fan-out 的方法,并且会与第二层接口 Model(见下)交叉验证。
陷阱:间接 hook 默认是 no-op,不是崩溃。
foldHook和getCanonicalizationPatterns出现在全部 6,050 个 Model 上,但每个都包装一个UniqueFunction;除非操作定义了该方法(存在真实的Op::fold/Op::getCanonicalizationPatternsstatic),否则其 callable 是通用 no-op。重新实现者不能假设 slot 已填充就意味着有真实 folder,slot 总是已填充。哪些操作实际 fold/canonicalize 的统计是各方言页面拥有的逐方言事实(对于tpu方言:6 个真实fold()+ 9 个真实getCanonicalizationPatterns();见 tpu 方言)。
接口解析
23-slot Model 回答的是“这种操作是否存在以及它的注册 hook 是什么”。它不承载 OpInterface 主体,即“此操作有什么副作用”“它推断出什么类型”。这些会通过第二类型擦除层路由。
两层
Layer 1 — op registration Layer 2 — interface dispatch
───────────────────────── ───────────────────────────
RegisteredOperationName::Model<Op> mlir::detail::<Iface>InterfaceTraits
slot 4: hasTrait(TypeID) ───gates──▶ ::Concept (abstract)
::Model<Op> (per-(op,iface))
e.g. getEffects(Concept const*,
Operation*, …)
```text
Slot 4(`hasTrait`)只是**闸门**:给定某个接口的 `TypeID`,它回答此操作是否实现该接口(通过 `Op<…>::getHasTraitFn` lambda,该 lambda 闭包捕获操作的编译期 trait 列表)。当答案为 yes 时,实际调用会 dispatch 到按 `(op, interface)` 键控的*独立* concept 表:
```text
mlir::detail::MemoryEffectOpInterfaceInterfaceTraits::Model<xla::PureCallOp>::getEffects
mlir::detail::CallOpInterfaceInterfaceTraits::Model<xla::PureCallOp>::resolveCallable
mlir::detail::InterfaceMap::insertModel<CallOpInterfaceInterfaceTraits::Model<PureCallOp>>这些第二层 Model 遵循相同的 Concept/Model 惯用法:每个方法都把 Concept const* self-pointer 作为第一个参数(demangled 签名显示 …::getEffects(Concept const*, Operation*, …))。它们存储在操作的 InterfaceMap 中(在上文的 OperationName::Impl::Impl 中构造),并按接口 TypeID 查找。仅 PureCallOp 就携带 CallOpInterface、MemoryEffectOpInterface、ConditionallySpeculatable、OpAsmOpInterface、BytecodeOpInterface、SymbolUserOpInterface 和 ArgAndResultAttrsOpInterface 的 Model,确认该层是完整填充且逐操作的。
注意:重新实现者必须构建两层。 23-slot Model 提供操作注册和
hasTrait闸门;接口语义位于<Iface>InterfaceTraits::Model<Op>表中。这些第二层 vtable 的 slot 布局(例如MemoryEffectOpInterface::getEffects、InferTypeOpInterface::inferReturnTypes、Bytecoderead/write 对)是独立的 concept 表面,不在本文范围内;本页建立的是闸门和查找路径,而不是逐接口主体。
调用方侧 dispatch
Layer-1 dispatch 的消费者例如 mlir::Operation::fold @ 0x1d8cd480,它从操作加载 Impl/Model,再加载 vptr,然后调用 slot 2:
mov 0x30(%rdi),%rdi ; %rdi = OperationName::Impl (= the Model)
mov (%rdi),%rax ; %rax = vptr (address point)
call *0x10(%rax) ; +0x10 from address point = slot 2 = foldHook (@ 0x1d8cd4ad)
```text
地址点后的 `+0x10` 偏移正好是 slot 索引 2(`0x10 / 8`),确认了 slot 编号。MLIR 中每个 op-dispatch 点,包括 verification、parsing、attribute access、property serialisation,都是这种形状:在 `op+0x30` 加载 `Impl`,解引用 vptr,间接调用相应 slot。
---
## 跨方言契约
23-slot 契约与方言无关:二进制中每个注册操作都由相同的 vtable 形状支撑。因此,`Model<Op>` 实例化计数*等于*注册操作计数,跨 61 个方言 namespace 求和得到 **6,050**。与 TPU 相关的方言及其名册归属如下:
```text
dialect Models contract owner / roster page
------------------ ------ --------------------------------------------------
sparse_core 1471 SparseCore (115 ScDialect + 1356 LlvmTpu tpu_* intrinsics)
llo 325 LLO — TensorCore low-level machine ops
tpu 86 tpu Dialect — TensorCore high-level (Mosaic) target
xtile 6 XLA CPU/GPU tile IR (off the TPU device path)
mosaic_sc 1 SparseCore Mosaic — RelayoutOp only
(+ 56 more: TF 834, spirv 376, ROCDL 350, … — input/off-path dialects)本页拥有契约;方言页面拥有实例化,即操作名册、逐操作接口 fan-out、fold/canonicalize 统计,以及哪些操作承载非平凡 Properties。tpu 方言页面是完整示例:它用本契约遍历 Model<mlir::tpu::IotaOp>,按接口签名列出 86 个 tpu 操作,并将 9 个带 property 的操作关联到 slots 14–22。已确认 Model<llo::ConstantOp>(@ 0x13e71420 附近的 slot)、Model<mosaic_sc::RelayoutOp>(@ 0x132faba0…)和 1356 个 sparse_core::tpu_* Model 均携带相同的 23-slot 布局。
注意:版本固定的顺序。 Slot 索引(foldHook = 2、hasTrait = 4、getInherentAttr = 10 等)特定于此二进制捆绑的 LLVM SHA。Slot 集合是稳定的 MLIR API,但顺序是某个构建的 ABI 细节。面向不同 MLIR 版本的重新实现者必须重新遍历一个 Model vtable 来恢复顺序;不要未经验证就把这些索引硬编码到上游 MLIR。
置信度摘要
| 断言 | 证据 |
|---|---|
OperationName::Impl 是抽象 op 记录;ctor 接受 (StringRef, Dialect*, TypeID, InterfaceMap) | demangled OperationName::Impl::Impl(StringRef, Dialect*, TypeID, detail::InterfaceMap) @ 0x1d8c4d80 |
Impl 有两个具体 impl:Model<Op> 和 UnregisteredOpModel | 两者都承载完整 21-hook 表面(存在 UnregisteredOpModel::{foldHook,hasTrait,…} 符号) |
Model<Op> 是 23-slot vtable;二进制全局 6,050 个实例 | 不同 Model<…>::~Model(D0)符号计数 = 6,050;对 Model<xla::PureCallOp> slots 0x150d56c0…0x150d5c20 的参考遍历 |
| 每个操作都存在全部 21 个 dispatch-slot 符号,跨方言顺序相同 | Model<{PureCallOp, tpu::IotaOp, llo::ConstantOp, mosaic_sc::RelayoutOp}>::<method> 解析结果一致 |
| Slot 0 是所有 Model 共享的一个基类 dtor | OperationName::Impl::~Impl(D2)= addend 0xfea8820;30-Model 分层样本共享它 |
注册 sink 是 RegisteredOperationName::insert | demangled insert(unique_ptr<OperationName::Impl,…>, ArrayRef<StringRef>) @ 0x1d8c57a0;243 个 addOperations<…> 家族符号(224 个 Dialect::addOperations + 19 个 addOperationsChecked),243 个都 demangle 为不同签名 |
| Inherent-attr slot 通过 inline-prop 解包 tail-call ODS statics | Model<IotaOp>::getInherentAttr 主体计算 op + ((flags>>19)&0x10) + 64,随后调用 IotaOp::getInherentAttr(...) @ 0x14b220e0 |
间接 hook(2、3、4、7、8)包装在携带 Op<…> trait 列表的 UniqueFunction callback-holder 中 | Model<IotaOp>::hasTrait holder 命名 Op<tpu::IotaOp, …, MemoryEffectOpInterface::Trait>::getHasTraitFn()::lambda |
getOpPropertyByteSize 是内联的 sizeof(Properties) | Model<IotaOp>::getOpPropertyByteSize @ 0x14ac19c0 反编译为 return 8;;零 property 操作返回 0 |
第二接口层 <Iface>InterfaceTraits::Model<Op> 承载接口主体;slot-4 hasTrait 对其 gating | MemoryEffectOpInterfaceInterfaceTraits::Model<PureCallOp>::getEffects、InterfaceMap::insertModel<…> 符号;Concept const* self 参数 |
调用方 dispatch 在 op+0x30 加载 Impl、vptr、call *0x10 = slot 2 | Operation::fold @ 0x1d8cd480,间接调用 @ 0x1d8cd4ad |
| Slot 顺序固定到此二进制的 LLVM SHA | 索引特定于一个构建;未与上游 MLIR 交叉验证 |
交叉引用
- tpu 方言:操作和 Op-Model 契约:本契约的完整实例化:86 个
tpu操作、它们的接口 fan-out、fold/canonicalize 统计,以及 9 个带 property 的操作。该页应用契约;本页拥有契约。 - 编译器概览:MLIR 层位于五阶段下降和六级 IR 栈中的位置;optimizer 和 Mosaic 路径的汇合点。
- tpu → LLO 降低:
tpu下方的llo方言(325 个操作),通过相同的 23-slot 契约注册;它是转换大多数操作而非原地 fold 的结构性降低。 - MHLO → XTile → tpu:产生这些 Model 所注册
tpu操作的中层降低。 - DialectConversion Legalizer:降低期间消费注册操作的 conversion-pattern 机制;它查询同一组
OperationName/Impl记录。 - 二进制:
extracted/libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/libtpu/libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d) - 索引项: Part V — Compiler: Lowering & Optimization Passes / MLIR lowering chain — 返回索引