1个不稳定版本
0.0.1 | 2019年8月7日 |
---|
#14 在 #spirv
72KB
1.5K SLoC
菊花
这是一项关于制作一个可编译为SPIR-V着色器(用于Vulkan)的玩具编程语言的实验。
基本上,我想创建一个针对SPIRV的编译器,它比shaderc更容易嵌入,并且我想有一个主要是纯函数式的着色语言(因为着色器本质上就是纯函数),所以我们就是在这里。我可能永远也完成不了它。
构建
到目前为止,它只经过Linux测试。由于没有平台特定的依赖项,可能可以在任何东西上正常运行。
运行单元测试需要官方Khronos SPIR-V工具中的命令行程序spirv-val
;在Debian上,你只需运行apt install spirv-tools
。 glslang-tools
可能也有用。
为了真正看到正在发生的事情的细节,还可以使用cargo test -- --nocapture --test-threads=1
进行测试。
设计
这主要是一个关于如何使某种东西编译为SPIR-V的实验,所以。它将是一个强类型、纯函数式语言,可能看起来有点像ML。但现在我正在从IR和后端开始,因为编写解析器既令人沮丧又缓慢。
实际上,没有突变并不会使任何东西更难,因为SPIR-V已经是SSA形式。
尽管在传统上,处理此类语言中的循环的方式是通过递归,而着色器通常不能递归,所以这将是棘手的。我们可能不得不引入具有相应突变的循环(模拟的或真实的),或者只允许可以展平为循环的递归。尽管SPIR-V规范对递归是否允许相当沉默...
我想这甚至还不是一种真正的函数式语言,因为它还没有实现函数作为值,尽管看起来SPIR-V可以支持它。
目标
- 编译为SPIR-V
- 在真实GPU上执行顶点+片段着色器
- 易于使用
- 简单/快速(?)构建
- 作为库或独立程序运行
非目标
- 优化
- 非常完整
- 非常舒适
- 其他类型的着色器
- 类型推断
- 模块
待办事项
实际上要做的
- 将unwrap替换为expect。
- 更好地考虑错误处理。
- 使入口点工作得更好。
- 创建实际的CLI——最终生成的代码测试可能应该包含
spirv-val
? - 命名/标签/更有利于调试的东西。
要考虑的事情
- 向量交错——我们需要它吗?我们能否只通过模式匹配来完成所有操作?让我们试试。
- 向量类型——它们是否可以是结构体?这将很好地与模式匹配配合使用。
- 枚举/选项类型
- 结构体布局和绑定
- 循环(递归?)
- 数学和类型系统
- 尝试模糊测试?
与(希望)已知有效的编译器生成的代码进行比较
# -G for GLSL semantics, -V for Vulkan semantics.
glslangValidator -V test.frag.glsl; spirv-dis frag.spv
暂不执行
- 入口点声明
- 除了f32之外的标量
- 更好的结构体和向量处理
语法注意事项
ML-y语法还是Lispy语法?
让我们先采用ML-y语法,看看它是什么样子。
实际上,我不确定如何处理数学运算;我们没有泛型或特型,所以创建一个Add
特型不起作用。然而,我们也没有类型推断,所以不一定需要OCaml风格的+
与+.
似乎我们可以以C风格完成,将数学运算符作为特殊情况重载,这我不喜欢,但在实践中很容易,或者我们可以以ML风格完成,不重载任何东西,这更简单但更烦人。
但我们可以使其整数加法为+
,浮点数为+.
,向量为+/
,矩阵为++
。这几乎是太可爱而无法抗拒。但目前,未定义。
-- Yes, Lua style comments
-- just to mess with people.
/- Because why not -/
-- DECLARATIONS
-- Anyway, two types of decl's, functions and structs.
fn foo x: F32, y: F32 -> bool
-- ...
end
-- Types must start with a capital letter
struct SomeStruct
x: F32,
y: F32,
end
-- EXPRESSIONS
-- Floats must have a decimal point
let foo: F32 = 10.0
-- Math
x + y
x - y
x * y
x / y
x % y
-- Comparison
x == y
x != y
x > y
x >= y
x < y
x <= y
-- Logic, on booleans. No bitwise stuff yet.
x or y
x and y
x xor y
not x
-- Blocks
do
...
end
-- Function calls
foo(x, y, z)
-- Structure literals
SomeStruct { x: 1.0, y: 2.0 }
-- Pattern matches
match foo
| 1.0 -> foo * 2.0
| 2.0 -> foo / 2.0
| _ -> -9999.0
end
-- Destructuring matches
-- variables always are lowercase.
let SomeStruct { x, _ } = foo
-- x is now bound
依赖关系
~7.5MB
~169K SLoC