← 返回信息流
AI 资讯Hacker News·1 天前

Julia 推出统一中间表示 UnifiedIR

原标题:UnifiedIR for Julia

速览

UnifiedIR 是 Julia 语言引入的一种统一中间表示,用于替代原有多种 IR,简化编译流程并提升代码优化效率。该设计有望降低 Julia 在机器学习、科学计算等场景下的运行时开销,并增强跨平台兼容性。此更新对 Julia 生态的发展具有重要意义,尤其有助于高性能计算与 AI 模型的部署。

AI 深度解读

背景

Julia 语言的基础 IR(中间表示)数据结构已经使用了大约十年。虽然它们整体上运行良好,但存在三个主要问题:一是 IR 难以使用(既有通用 API 设计上的原因,也有与所有权和失效相关的语义原因);二是无法扩展以支持生态系统中涌现的各种其他用例,导致开发者要么忍受 hack 式的解决方案,要么自行构建自己的 IR 数据结构;三是它从一开始就不是为外部使用而设计的系统。

为了解决这些问题,社区提出了一个全新的顶层包——UnifiedIR,与 Compiler、JuliaSyntax 和 JuliaLowering 并列,并被这三个包所依赖。UnifiedIR 提供一套自包含、可扩展的 IR 数据结构与操作,既可用于 Julia 基础库,也可用于更广泛的生态系统。

核心内容

UnifiedIR 是一个方言感知的、基于区域(region-based)的 IR 表示,类似于 MLIR,但保留了原始 Julia IR(以及 JuliaLowering 表示)中许多设计良好的部分。它旨在替代以下现有数据结构:

  • SyntaxTree(来自 JuliaSyntax)
  • SyntaxGraph(来自 JuliaSyntax/Lowering)
  • CodeInfo(用于推理目的;代码生成/解释器暂时不在范围之内,但未来应适配)
  • IRCode
  • 生态系统中的各种其他 IR

为了实现这一目标,UnifiedIR 提供了一个核心数据结构,以高效的方式表示 IR,同时附带核心工具。该核心数据结构的任何使用者都可以通过添加额外的列(每个语句一条记录)来扩展它,并且引入了“分层视图”(layered views)的概念,以便在特定应用中更轻松地操作 IR。

当前定义的分层视图包括:

  • IncrementalCompact 风格扩展:允许快速单遍替换(one-pass replacement)的扩展。
  • LLVM 风格视图:通过链表维护顺序,使得复杂的 CFG 变换变得容易得多。为了避免 LLVM 中常见的二次复杂度维护问题(这对于某些下游应用很重要),作者与 Claude 共同设计了一种奇特的有序维护算法(仍需验证)。
  • 图嵌入视图:供数组编译器以及 lowering 阶段使用(图是没有控制流依赖的 IR)。
  • 树状编码:供 lowering 阶段使用(树是 IR 中每个语句只有一个使用者,根节点除外,根节点有零个使用者)。

主要特性包括:

  • 对区域的一流支持:使得像 #58532 这样的功能更容易实现,并能更好地与 MLIR 集成。
  • 对方言扩展的一流支持:通过命名空间化的种类注册表(kind registry),为引导堆栈预留了静态方言 ID。

UnifiedIR 的设计规格在 UnifiedIR/docs/design.md 中有详细描述,核心思路是:一个扁平的语句表,带有位于共享存储核心上的混合区域(hybrid regions)。该存储核心称为 AttrGraph,包含一个种类列、打包的两模式操作数字段、一个带标签的操作数池以及开放的属性列宇宙。布局状态(builder/dense/editable/floating)恰好有两个重命名点。此外还提供了命名空间化的种类注册表、通用树状处理接口(Tree/NodeList 游标、构造、mapchildren/copy_ast、通过图限定的 :source 链进行来源遍历)、compact! 作为垃圾回收机制(compact_graph!/collect_syntax!)、验证器、打印/解析器以及一个参考解释器。UnifiedIR 零依赖。

与其他包的集成方式

  • JuliaSyntax:SyntaxGraph 直接包装 UnifiedIR.AttrGraph。种类是真正的核心列,子节点是共享操作数池中标记为 STMT 的单词,由打包的范围字寻址。历史属性(edge_rangesedgesattributes)被精确保留(保持 identity 稳定的视图和 is_compatible_graph 语义)。compact_graph! 为 lowering 提供了其一直想要的语法图 GC。

  • SyntaxTreeSyntaxTree{Attrs} = UnifiedIR.Tree{SyntaxGraph{Attrs}}SyntaxList = UnifiedIR.NodeList。子节点索引、属性属性、newnode/newleaf/mknode/mkleaf/mktreecopy_attrs!/mapchildren/copy_ast、来源遍历、结构化的 isapprox 和打印都是 UnifiedIR 的通用函数。JuliaSyntax 仅保留真正语法相关的部分(种类注册表包装器、SourceRef/源码文本机制、叶节点载荷约定、解析器集成、prune/unalias/@stm)。

  • 种类注册表:历史的模块 ID 机制通过 register_kinds! 重新接入共享的 UnifiedIR 注册表。种类模块成为方言,声明连续的 opcode 块(保留范围谓词和 BEGIN_/END_ 标记)。引导栈声明了静态预留的方言 ID:JuliaSyntax=1,JuliaLowering=2,formatter=3,core=0。这样 K"..." 字面量保持编译时常量。语法 K"call" 和核心 K"call" 是不同的种类,共享同一编号空间。种类在 __init__ 中重新注册(注册表是 UnifiedIR 会话状态);编号是确定性的,保持烘焙常量有效。双模式:引导时作为 Base 的一部分绑定 Base.UnifiedIR;作为包时依赖 UnifiedIR 包。

  • JuliaLowering.UnifiedBackend(纯增量,零改动现有源码):重用前端不变的部分——宏展开、脱糖、作用域分析、闭包转换——然后直接生成结构化的 UnifiedIR 区域形式(if/loop/try 区域操作、用于帧变量的 cells、密封出口终结符),而不是 goto 线性 IR。同时带有图限定的来源信息:每个发射的语句携带一个 :source 列条目,指向原始语法树游标,因此通用的来源遍历可以从优化后的 IR 语句回溯到源码文本(支持高亮诊断)。collect_syntax! 可以针对活 IR 对 lowering 图进行 GC。该后端是纯定义,在引导期间不会被调用,在可选的 sys-JL 系统映像阶段可以干净地烘焙。绑定通过外层 JuliaLowering 解析(在 Base 烘焙模式和包模式下使用相同的 JuliaSyntax 和相同的 UnifiedIR 实例)。

关于编译管道(仅包模式,系统映像引导永远不会看到它):

  • CodeInfo <-> UnifiedIR 边界转换器:包括 CFG 包装入口(含异常处理)、goto/typed 出口与 phi 合成。
  • 推理端口:原生运行在 UnifiedIR 上,通过差异验证 100% 相等或更好的返回类型,与标准管道在会话的 MethodInstances 上比较。
  • 优化器 passes:SROA、内联(通过 splice_body!)、ADCE、结构化、单元提升。
  • Queries API:通过普通的编译器替换机制激活(Core.OptimizedGenerics.CompilerPlugins.typeinf owner hook + with_unified_compiler)。每个缓存结果都会通过已验证的 UnifiedIR 影子对象往返。
  • 加载机制Compiler.load_unified!() 按需将端口载入到以 Main 为根的载体模块中,并绑定为 Compiler

当前 PR 已经将推理、优化器和 JuliaLowering 移植到了新数据结构上,但尚未启用 bootstrap。作者运行了大约一半的测试套件,一切正常。这应被视为预览 PR 和讨论基础,还有许多工作待完成。

关键要点

  • UnifiedIR 是一个统一的、方言感知的、基于区域的 IR 表示,旨在替代 Julia 基础库和生态系统中多个分散的 IR 数据结构。
  • 核心数据结构是一个扁平语句表,带有一个共享存储核心(AttrGraph),支持通过
查看原文 →github.com