ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Mojo 编译器内幕:Witness Elaboration 中的一致性表(Conformance Table)与见证条目(Witness Entry)展开机制

Mojo 编译器内幕:Witness Elaboration 中的一致性表(Conformance Table)与见证条目(Witness Entry)展开机制 Mojo 编译器内幕Witness Elaboration 中的一致性表Conformance Table与见证条目Witness Entry展开机制【免费下载链接】mojoThe Modular Platform (includes MAX Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo导读本文深入 Mojo 编译器Modular 开源仓库中的Mojo/目录的核心编译流程围绕 WitnessElaboration.md 展开讲解在 elaboration展开/泛型实例化阶段编译器如何表示结构体的一致性表Conformance Table、如何通过GetWitnessAttr在参数级求值parameter evaluation时查找见证条目Witness Entry以及在编译卸载compile-offload模块切片场景下WEASOOM如何保持同样的查找语义。读完本文你将掌握StructGeneratorOp/ConformanceOp/WitnessOp/StructInstanceOp四个核心操作的职责划分理解TypeGeneratorRefAttr与TypeInstanceRefAttr的求值关系并能在 KGENDialect 的源码中快速定位相关实现。背景为什么泛型类型需要见证表在 Mojo 的结构化泛型设计中一个 trait如Printable、Boolable、Movable声明了一组需求requirement而一个具体结构体通过声明自己符合conform某个 trait 来承诺提供这些需求的实现。编译器必须回答一个核心问题给定一个类型值type value如何找到它为某个 trait 提供的某个需求实现答案就是本文的主题——一致性表Conformance Table与见证条目Witness Entry。这个机制被 Mojo 编译器称为Witness Elaboration其完整说明位于 Mojo/docs/compiler/arcana/WitnessElaboration.md是 arcana 系列文档还包括 Generics.md、Conformance.md 等中专门讲述见证表如何在展开阶段被处理的一篇。核心概念六个关键实体原文档用六个概念勾勒出整个机制的骨架它们在 KGENDialect 的 TableGen 定义 与 KGENAttrs.td 中均有对应的实际定义。实体一句话职责运行时域是否保留StructGeneratorOp泛型结构体声明类型的制造模板携带类型构成与全部一致性表是作为生成器存在ConformanceOp针对某个 trait 的一张一致性表为 trait 的每个需求提供一个见证条目是WitnessOp单个见证条目为某个以名称和类型标识的需求提供参数值是StructInstanceOp具体结构体实例声明不含一致性表是但表被丢弃TypeGeneratorRefAttr对StructGeneratorOp的引用可携带参数绑定展开时求值为TypeInstanceRefAttr—GetWitnessAttr参数级运算符从一个结构体类型中取回某个见证条目—StructGeneratorOp类型与表的母体StructGeneratorOp是一个泛型结构体声明它描述了两类内容该类型的构成字段等该类型所符合的全部 trait 的一致性表每个表由ConformanceOp表示。它等价于源码中带类型参数的struct声明。凡是类型未知、待参数化的结构信息都集中在这里。ConformanceOp 与 WitnessOp表与行ConformanceOp代表该结构体符合 traitT这一事实对应的一致性表表头是 trait 名表中为 trait 的每个需求requirement放置一条WitnessOp记录。WitnessOp是表的行它为某个以名称和类型双重标识的需求提供参数值。典型场景是方法trait 声明了一个方法需求例如printWitnessOp就会提供指向实际实现函数的引用在 MLIR 中以SymbolConstantAttr符号常量属性形式给出GeneratorOp/FuncOp引用。StructInstanceOp为什么实例不含一致性表StructInstanceOp是具体化之后的结构体声明例如MyStructInt。原文档明确说明在当前阶段实例不包含一致性表原因是运行时域run-time domain目前没有使用一致性表的场景如果在展开阶段急切地eagerly展开所有 conformances会大幅增加 elaboration 的工作量而它们最终在 elaboration 结束后又会被丢弃。这是一个典型的为了效率刻意延迟/丢弃的工程决策——泛型结构体的身份由生成器StructGeneratorOp保留实例只是它的具体化投影。TypeGeneratorRefAttr 与 TypeInstanceRefAttr引用与求值TypeGeneratorRefAttr对类型生成器的符号引用可以附带参数绑定。它在 KGENAttrs.td 中定义实现ContextuallyEvaluatedAttrInterface与DeclRefAttrInterface其描述明确写道如果类型值是参数化的可以额外绑定参数值。展开过程中它会被求值为TypeInstanceRefAttr。TypeInstanceRefAttr对具体类型实例的符号引用见 KGENAttrs.td其类型是类型值的元类型metatype。GetWitnessAttr见证查找的参数运算符GetWitnessAttr是这次机制的核心枢纽定义为 KGEN_GetWitnessAttrsummmary 为 Get a witness entry from a witness table。它有三个操作数类型引用参数值TypedAttr字段名typeValuetrait 名常量字符串字段traitSymbol类型为TraitSymbolAttr见证名常量字符串字段witnessName。TableGen 中还给出了它的典型文本形式示例#kgen.get_witness#Int, Boolable, __bool__ : !kgen.generator(self: !Int) - i1即对类型#Int在其Boolable一致性表中查找名为__bool__的见证条目结果为(self: !Int) - i1类型的生成器。GetWitnessAttr还实现了ContextuallyEvaluatedAttrInterface并声明了两个关键方法见 KGENAttrs.td#L972-L986getTypeRefIfResolved()若类型值字段已解析提取类型引用返回TypeGeneratorRefAttr或TypeInstanceRefAttrsimplify(ConformanceOp, ParameterEvaluator*)给定一致性表完成折叠/求值找不到见证条目时返回 failure。另外该属性只在提供了全局符号表的情况下才能折叠因为类型值定义是符号symbol。展开流程GetWitnessAttr 的 IREvaluator 求值原文档用一张 ASCII 图完整刻画了求值前后两个阶段的状态变化这里完整保留并逐段解读。展开之前引用停留在生成器层面在 elaboration 之前GetWitnessAttr中的类型引用通常是TypeGeneratorRefAttr直接指向StructGeneratorOp。此时查找是直接的顺着StructGeneratorOp → ConformanceOptrait: Printable→ WitnessOpname: print, value: func_x一路取回见证条目即可。GetWitnessAttr EVALUATION PROCESS ┌─────────────────────────────────────────────────────────────────────────────┐ │ BEFORE ELABORATION │ │ │ │ GetWitnessAttr( │ │ type_ref: TypeGeneratorRefAttr ──────┐ │ │ trait_name: Printable │ │ │ witness_name: print │ │ │ ) │ │ │ │ │ │ ▼ │ │ ┌─────────────────────────┐ │ │ │ StructGeneratorOp │ │ │ │ MyStructT │ │ │ │ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ ConformanceOp │ │ │ │ │ │ trait: Printable │ │ │ │ │ │ │ │ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ │ │ WitnessOp │ │ │◄──── Direct lookup │ │ │ │ │ name: print │ │ │ │ │ │ │ │ value: func_x │ │ │ │ │ │ │ └─────────────────┘ │ │ │ │ │ └─────────────────────┘ │ │ │ └─────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘展开之中引用被具体化查找回溯到父节点elaboration 开始后TypeGeneratorRefAttr会被自动解析为具体的TypeInstanceRefAttr。但问题随之而来新的引用指向的是刚创建的StructInstanceOp而如上一节所述实例中没有任何一致性表无法直接在其上做 witness 查找。解决方案是回溯trace backelaborator 维护了实例 ← 生成器的父子节点关系parent node relationship因此可以沿着父指针找回当初生成该实例的StructGeneratorOp在生成器上完成 witness 查找。┌─────────────────────────────────────────────────────────────────────────────┐ │ DURING ELABORATION │ │ │ │ GetWitnessAttr( │ │ type_ref: TypeInstanceRefAttr ───────┐ │ │ trait_name: Printable │ │ │ witness_name: print │ │ │ ) │ │ │ │ │ │ ▼ │ │ ┌─────────────────────────┐ │ │ │ StructInstanceOp │ │ │ │ MyStructInt │ │ │ │ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ Concrete Fields │ │ │ │ │ │ (No conformance │ │ │ │ │ │ tables!) │ │ │ │ │ └─────────────────────┘ │ │ │ └─────────────────────────┘ │ │ │ │ │ │ TRACE BACK via │ │ │ parent relationship │ │ ▼ │ │ ┌─────────────────────────┐ │ │ │ StructGeneratorOp │ │ │ │ MyStructT │ │ │ │ (Original parent) │ │ │ │ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ ConformanceOp │ │ │ │ │ │ trait: Printable │ │ │ │ │ │ │ │ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ │ │ WitnessOp │ │ │◄──── Lookup here! │ │ │ │ │ name: print │ │ │ │ │ │ │ │ value: func_x │ │ │ │ │ │ │ └─────────────────┘ │ │ │ │ │ └─────────────────────┘ │ │ │ └─────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘一句话总结引用指向实例查找落在生成器——这是整套机制最关键的设计约束也是理解下文 WEASOOM 的前提。源码佐证查找语义在实现中的落点属性定义KGEN_GetWitnessAttrKGENAttrs.td#L926-L987中simplify()直接以ConformanceOp为输入印证查找对象是一致性表挂在生成器上。求值环境IREvaluatorContext的注释明确提到参数运算符例如闭包场景下的GetWitnessAttr需要上下文求值见 IREvaluatorContext.h#L200对应ContextuallyEvaluatedAttrInterface的evaluateWithContext接口方法。实际构造点MojoParser 在生成结构体字段/闭包相关代码时通过shared.getEvaluationContext().getAndFoldGetWitnessAttr(...)构造并折叠该属性见 StructEmitter.cpp#L1146-L1168传入的是字段类型PValue(fieldOp.getType())、traitSymbol、witnessName与返回类型。相关旁证KGENOps.h中也有注释说明某些属性值是参数表达式——例如GetWitnessAttr见 KGENOps.h#L77。WEASOOM编译卸载模块切片中的同一套流程WEASOOMWitness Elaboration As Slicing Out Offload Modules 的缩写即展开过程切出卸载模块解决的是当编译器为了编译卸载compile-offload把模块的一部分切片slice出去单独编译时witness 查找必须保持同样语义。原文档给出两个必须遵守的规则切片对象是生成器而非实例遇到参数值中携带的TypeInstanceRefAttr时不能把该实例StructInstanceOp切出去而应取其父级StructGeneratorOp切出——因为实例上没有一致性表切出去就是空壳卸载侧无法完成 witness 查找。引用还原切片完成后把参数值中的TypeInstanceRefAttr替换回原来的TypeGeneratorRefAttr。这样卸载模块offload module中一切都会自然而然地发生引用重新指回生成器查找重新落在生成器的一致性表上与主模块的 elaboration 行为完全一致。这与上一节回溯父节点是同一设计哲学在不同编译阶段模块切分的延续。设计要点小结设计决策动机以文档与源码为准实例不携带一致性表运行时域暂不需要避免 elaboration 工作量暴增后被丢弃查找回溯到生成器引用指向实例、表挂在生成器靠 parent relationship 衔接GetWitnessAttr仅在有全局符号表时可折叠类型值定义是符号折叠依赖符号表见 KGENAttrs.td#L934-L935WEASOOM 切片生成器、还原生成器引用保证卸载模块中 witness 查找语义与主模块一致延伸阅读本主题的源头文档Mojo/docs/compiler/arcana/WitnessElaboration.md配套机制Generics.md结构化泛型、Conformance.md一致性建模、Closures.md闭包中的参数求值、Thunks.md属性与操作定义Mojo/include/Mojo/KGENDialect/KGENAttrs.td、Mojo/include/Mojo/KGENDialect/KGENOps.td、Mojo/include/Mojo/KGENDialect/KGENInterfaces.td求值器与解析器实现Mojo/lib/Elaborator/IREvaluatorContext.h、Mojo/lib/MojoParser/StructEmitter.cpp、Mojo/lib/MojoParser/ParamBindings.cpp字节码序列化支持Mojo/include/Mojo/KGENDialect/KGENDialectBytecode.td其中定义了GetWitnessAttr的 dialect attribute 编码【免费下载链接】mojoThe Modular Platform (includes MAX Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表