#spir-v #ir #shader #compiler

spirt

以着色器为中心的IR,用于目标、转换和翻译

7个不稳定版本 (3个破坏性版本)

0.3.0 2023年7月25日
0.2.0 2023年4月21日
0.1.0 2022年12月16日
0.0.0 2021年8月19日

#89 in 编程语言

Download history 164/week @ 2024-04-01 106/week @ 2024-04-08 128/week @ 2024-04-15 160/week @ 2024-04-22 144/week @ 2024-04-29 117/week @ 2024-05-06 189/week @ 2024-05-13 166/week @ 2024-05-20 129/week @ 2024-05-27 102/week @ 2024-06-03 128/week @ 2024-06-10 117/week @ 2024-06-17 106/week @ 2024-06-24 9/week @ 2024-07-01 114/week @ 2024-07-08 109/week @ 2024-07-15

每月350次下载
3个crate中(通过rustc_codegen_spirv)使用

MIT/Apache

1.5MB
38K SLoC

Rust 16K SLoC // 0.1% comments C++ 6K SLoC // 0.1% comments C# 4.5K SLoC // 0.0% comments Python 4.5K SLoC // 0.0% comments Lua 4.5K SLoC // 0.0% comments D 2K SLoC // 0.0% comments Bazel 142 SLoC

SPIR-🇹

⋯🢒 🇹arget 🠆 🇹ransform 🠆 🇹ranslate ⋯🢒

Embark Crates.io Docs Git Docs dependency status Build status

SPIR-🇹是一个旨在探索由SPIR-V派生出的着色器导向的IR设计的研究项目,并围绕此类IR产生一个框架,以促进高级编译管道,超越现有SPIR-V工具所能提供的。

这种需求在Rust-GPU项目中出现,该项目需要各种合法性传递,以将通用(Rust1)代码从未类型化内存中操作转换为GPU友好的直接数据流。
我们的目标是用1的Rust语言替换现有的Rust-GPU SPIR-V合法性传递,但更重要的是,SPIR-🇹应该允许编写更强大的合法性/优化传递,这在直接SPIR-V操作中是难以想象的。


1 Rust在这里的需求并不独特,更多语言(或IR)最终可以利用这样的框架,但初始设计和实现工作主要集中在Rust-GPU上。

2 并非完全不可能,但需要过度的开发和维护成本,需要不断平衡正确性和性能(更保守的传递更容易信任)等。

免责声明

本项目与Khronos Group Inc.及其子公司或关联公司无关,未获授权、认可或支持。Khronos Group Inc.的官方网站可在https://www.khronos.org找到。
名称SPIR、SPIR-V以及相关名称、商标、徽标和图像是各自所有者的商标。

额外背景:本项目的名称是对SPIR-V的恶搞,与SPIR(较旧的IR标准)完全无关。

状态

🚧 此项目正在积极设计和开发中,许多细节可以且将会发生变化 🚧

如果您有兴趣自己使用 SPIR-🇹,您可能首先想看看相关的问题跟踪器,甚至可以打开新的问题来描述您的用例。
由于最初的关注点是Rust-GPU的用例,因此各种(其他情况下可能希望)功能/API/文档可能不足,或者快速变化——同时,关于长期内扩大SPIR-🇹的适用范围的讨论仍然欢迎。

非目标(至少在短期内)

  • 支持SPIR-V的("OpenCL")Kernel方言
    • Kernel SPIR-V与LLVM IR更接近,而不是Shader SPIR-V,因此围绕LLVM的工具可能更适合
  • 可以解析回文本的语法
    • 即,美化打印输出纯粹是可视化

迄今为止设计和实现

IR数据类型:

  • 允许对任何未识别的操作码使用几乎任意的SPIR-V指令
    • 用interned/"实体"处理程序(见下文)代替ID
  • 对属性(装饰和类似)、类型和常量进行interning
    • 即,自动去重、高效索引,没有“定义”的概念(只有使用的interned处理程序才能使模块被认为是包含特定类型/常量)
  • 例如,模块中的定义、函数中的指令等“实体”系统
    • 禁止迭代,而是强制使用高效的索引
  • 受RVSDG启发的结构化控制流“区域”,比SPIR-V更严格(有关更多信息,请参阅ControlRegionDef的文档)

框架实用工具:

  • visit/transform:不可变/可变IR遍历
  • print:具有(样式化和超链接)HTML输出的美化打印器

传递(到/从/在SPIR-🇹上):

  • spv::lower:“降低”SPIR-V,规范化许多不相关的细节
    • 某些相关信息有损失(这些都是错误,尽管许多是非语义的,因此优先级较低)
  • spv::lift:“提升”回SPIR-V,必要时进行任意选择
    • 类似于例如从SPIR-V生成GLSL语法,只是低一个级别
  • cfg::Structurizer:(重新)结构化,从任意的控制流到更严格的“区域”
  • passes::link:将导入映射到相关的导出

简单示例(具有非平凡的控制流)

GLSLfor-loop.vert.glsl

#version 450
out int output0;
void main() {
    int o = 1;
    for(int i = 1; i < 10; i++)
    	  o *= i;
    output0 = o;
}

WGSLfor-loop.wgsl

@vertex
fn main() -> @location(0) i32 {
    var o: i32 = 1;
    for(var i: i32 = 1; i < 10; i++) {
    	o *= i;
    }
    return o;
}

SPIR-🇹

#[spv.Decoration.Flat]
#[spv.Decoration.Location(Location: 0)]
global_var GV0 in spv.StorageClass.Output: s32

func F0() -> spv.OpTypeVoid {
  loop(v0: s32 <- 1s32, v1: s32 <- 1s32) {
    v2 = spv.OpSLessThan(v1, 10s32): bool
    (v3: bool, v4: s32, v5: s32) = if v2 {
      v6 = spv.OpIMul(v0, v1): s32
      v7 = spv.OpIAdd(v1, 1s32): s32
      (true, v6, v7)
    } else {
      spv.OpStore(Pointer: &GV0, Object: v0)
      (false, spv.OpUndef: s32, spv.OpUndef: s32)
    }
    (v4, v5) -> (v0, v1)
  } while v3
}

SPIR-Vfor-loop.wgsl.spvasm

%typeof_output0 = OpTypePointer Output %i32
%output0 = OpVariable %typeof_output0 Output

%typeof_main = OpTypeFunction %void
%main = OpFunction %void None %typeof_main
  %entry = OpLabel
    OpBranch %bb0
  %bb0 = OpLabel
    OpBranch %bb1
  %bb1 = OpLabel
    %o = OpPhi %i32 %1_i32 %bb0 %o_next %bb5
    %i = OpPhi %i32 %0_i32 %bb0 %i_next %bb5
    OpLoopMerge %bb6 %bb5 None
    OpBranch %bb2
  %bb2 = OpLabel
    %cond = OpSLessThan %bool %i %10_i32
    OpSelectionMerge %bb4 None
  OpBranchConditional %cond %bb4 %bb3
  %bb3 = OpLabel
    OpBranch %bb6
  %bb4 = OpLabel
    %o_next = OpIMul %i32 %o %i
    OpBranch %bb5
  %bb5 = OpLabel
    %i_next = OpIAdd %i32 %i %1_i32
    OpBranch %bb1
  %bb6 = OpLabel
    OpStore %output0 %o
    OpReturn
OpFunctionEnd

GPU(着色器)IR景观概述

(以及SPIR-🇹如何融入其中的愿景)

这里做出的区别是

  • 交互式IR(许多工具可以使用以进行互操作的标准)
    • SPIR-V被设计为一个这样的标准(在GPU空间之外,wasm也是一个很好的例子)
    • 它们只需要编码正确的概念,不要偏离工具理解的太远,但设计工作通常是以“序列化”格式为导向的
  • 编译器中间表示(编译器的非标准化实现细节)
    • LLVM相当知名,但Mesa的NIR更接近于SPIR-🇹(两者都是针对着色器,并且在处理控制流等方面有相似的专业选择)
    • 这些必须很好地处理法律化和优化过程,并且通常有很多即时变换——因为它们的主要目的是为了加速这些操作
    • 这就是SPIR-🇹所处的位置,作为SPIR-V的一种“相对”/方言,但在“编译器内部”使用方面做出了权衡

贡献

Contributor Covenant

我们欢迎社区对这个项目的贡献。

请阅读我们的贡献指南以获取更多关于如何开始的信息。在做出任何贡献之前,也请阅读我们的贡献条款

任何有意提交给Embark Studios项目包含在内的贡献,必须符合Rust标准许可模型(MIT OR Apache 2.0),因此将双重许可,如以下所述,无需任何附加条款或条件

许可

此贡献在以下两者下双重许可:

由您选择。

为了清晰起见,“您的”指的是Embark或任何其他贡献许可方/用户。

依赖关系

~2.4–3.5MB
~65K SLoC