Skip to content

MLIR Op-Model 契约

本页中的所有地址、符号和计数均适用于来自 libtpu-0.0.40-cp314 wheel 的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d,构建 libtpu_lts_20260413_b_RC00)。.symtab 未被 stripped(1,233,709 个符号);每个断言都锚定到 demangled 符号、重定位 addend 或反编译主体。其他版本会不同,尤其是 23-slot 顺序被固定到此二进制捆绑的 LLVM SHA。

摘要

libtpu 中的每个 MLIR 方言,包括 tpullosparse_coremosaic_scxtile 以及另外 56 个输入/旁路方言(共 61 个 namespace),都通过一个共享的、版本固定的 ABI 注册其操作。本页以通用方式记录该 ABI:OperationName::Impl interned-op 记录、填充它的 RegisteredOperationName::Model<Op> 类型擦除 concept、每个 Model<Op> 暴露的 23-slot vtable 契约,以及一次 op-dispatch 调用(foldverifygetInherentAttr)如何通过该 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(addOperationsinsert 注册路径,以及从 Model thunk 到 ODS static 的三级委托);接口调用如何解析,包括 23-slot vtable 只作为闸门进入的第二类型擦除层(<Iface>InterfaceTraits::Model<Op>);以及调用方侧的 dispatch 点。全文中,参考操作是 xla::PureCallOp,并在 tpu::IotaOpllo::ConstantOpmosaic_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 / UniqueFunction holder)。
  • 接口解析:slot-4 hasTrait 作为成员资格闸门,以及承载接口主体的独立 <Iface>InterfaceTraits::Model<Op> concept 层。
Interned-op 记录mlir::OperationName::Impl,抽象 op-hook 接口基类
注册的具体 implmlir::RegisteredOperationName::Model<Op>(CRTP,每个注册操作一个)
未注册 fallback implmlir::OperationName::UnregisteredOpModel(单例,文本解析操作)
Model vtable 数量(所有方言)6,050,跨 61 个 namespace(= 注册操作总数)
每个 Model 的 vtable slot23 = slot 0 共享基类 dtor + slot 1 逐操作 dtor + slots 2–22 dispatch
共享 slot-0 dtormlir::OperationName::Impl::~Impl @ 0xfea8820(D2;所有 Model 的 addend 相同)
注册 sinkRegisteredOperationName::insert(unique_ptr<OperationName::Impl>, ArrayRef<StringRef>) @ 0x1d8c57a0
逐方言 registraraddOperations<Op…> 家族;二进制全局 243 个符号(224 个 Dialect::addOperations + 19 个 TransformDialect::addOperationsChecked);243 个都 demangle 为不同签名
参考 Model 遍历Model<xla::PureCallOp> slots @ 0x150d56c0…0x150d5c20
调用方侧 dispatchmlir::Operation::fold @ 0x1d8cd480call *0x10(vptr) = slot 2
第二接口层mlir::detail::<Iface>InterfaceTraits::Model<Op>(基于 Concept
置信度已确认(字节锚定),除非某行或标注另有说明

OperationName::Impl 记录和 Concept/Model CRTP

MLIR 通过 OperationName 标识一种操作,后者是一个轻量句柄,包装指向 interned、逐种类 OperationName::Impl 的指针。Impl 持有操作名字符串、拥有方言的 Dialect*TypeIDInterfaceMap(操作实现的接口 concept 集合);关键的是,它就是 dispatch vtable:MLIR 需要的每个操作 hook(fold、verify、print、属性/property 管理)都是 Impl 上的 virtual。构造函数签名被完整恢复:

text
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 stub

Model<Op> 是教科书式的类型擦除 Concept/Model 对:ImplConcept(抽象接口),Model<Op>Model(逐类型具体实现),以具体操作类型为模板参数,让编译器在实例化时为每个 hook 生成转发 thunk。这与 MLIR 用于 OpInterface dispatch 的惯用法相同;事实上,下面的接口层显式把其类型命名为 ConceptModel<Op>。下一节记录的 23-slot vtable 就是一个 Model<Op> 实现的布局。

注意:UnregisteredOpModel 承载相同的 21-hook 表面。 未注册(文本解析)操作的 fallback mlir::OperationName::UnregisteredOpModel 实现了注册 Model<Op> 所有的 hook:foldHookhasTraitgetCanonicalizationPatternsprintAssemblyverifyInvariantsverifyRegionInvariants、四个 inherent-attr 访问器、九个 property slot、getParseAssemblyFnpopulateDefaultAttrs。这确认该表面是抽象 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)。

text
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 中的每个 OpaddOperations 物化一个 Model<Op>(其实例 vtable 持有 23 个 Model<Op>::* thunk),并把它交给单一的非模板注册 sink:

text
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-CALL

tail-call 目标是具体操作的 ODS static,恢复为 demangled 符号:

text
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:BytecodeOpInterfaceConditionallySpeculatableMemoryEffectOpInterface。从逐操作 getFoldHookFn/getHasTraitFn holder 读取这些模板参数,是各方言页面恢复每个操作接口 fan-out 的方法,并且会与第二层接口 Model(见下)交叉验证。

陷阱:间接 hook 默认是 no-op,不是崩溃。 foldHookgetCanonicalizationPatterns 出现在全部 6,050 个 Model 上,但每个都包装一个 UniqueFunction;除非操作定义了该方法(存在真实的 Op::fold / Op::getCanonicalizationPatterns static),否则其 callable 是通用 no-op。重新实现者不能假设 slot 已填充就意味着有真实 folder,slot 总是已填充。哪些操作实际 fold/canonicalize 的统计是各方言页面拥有的逐方言事实(对于 tpu 方言:6 个真实 fold() + 9 个真实 getCanonicalizationPatterns();见 tpu 方言)。


接口解析

23-slot Model 回答的是“这种操作是否存在以及它的注册 hook 是什么”。它承载 OpInterface 主体,即“此操作有什么副作用”“它推断出什么类型”。这些会通过第二类型擦除层路由。

两层

text
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 就携带 CallOpInterfaceMemoryEffectOpInterfaceConditionallySpeculatableOpAsmOpInterfaceBytecodeOpInterfaceSymbolUserOpInterfaceArgAndResultAttrsOpInterface 的 Model,确认该层是完整填充且逐操作的。

注意:重新实现者必须构建两层。 23-slot Model 提供操作注册和 hasTrait 闸门;接口语义位于 <Iface>InterfaceTraits::Model<Op> 表中。这些第二层 vtable 的 slot 布局(例如 MemoryEffectOpInterface::getEffectsInferTypeOpInterface::inferReturnTypesBytecode read/write 对)是独立的 concept 表面,不在本文范围内;本页建立的是闸门和查找路径,而不是逐接口主体。

调用方侧 dispatch

Layer-1 dispatch 的消费者例如 mlir::Operation::fold @ 0x1d8cd480,它从操作加载 Impl/Model,再加载 vptr,然后调用 slot 2:

asm
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 统计,以及哪些操作承载非平凡 Propertiestpu 方言页面是完整示例:它用本契约遍历 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 共享的一个基类 dtorOperationName::Impl::~Impl(D2)= addend 0xfea8820;30-Model 分层样本共享它
注册 sink 是 RegisteredOperationName::insertdemangled 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 staticsModel<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 对其 gatingMemoryEffectOpInterfaceInterfaceTraits::Model<PureCallOp>::getEffectsInterfaceMap::insertModel<…> 符号;Concept const* self 参数
调用方 dispatch 在 op+0x30 加载 Impl、vptr、call *0x10 = slot 2Operation::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-id 89edbbe81c5b328a958fe628a9f2207d
  • 索引项: Part V — Compiler: Lowering & Optimization Passes / MLIR lowering chain — 返回索引