7 个版本
0.2.5 | 2024年1月28日 |
---|---|
0.2.4 | 2024年1月23日 |
0.1.0 | 2024年1月3日 |
#231 in 游戏
555KB
19K SLoC
DPC
DPC 实质上是 Minecraft 数据包的 LLVM:一个将通用输入语言转换为 Minecraft 函数文件的编译后端。它不打算用作直接编写数据包的高级语言。相反,具有更多有用特性的前端语言将创建该项目可以轻松优化并转换为针对目标版本的数据包的 IR。
架构
DPC 首先处理 IR,这可以是作为库使用时提供的代码,也可以从文本中解析。文本表示形式看起来(将会看起来)像这样
"foo:main/main" {
let x: score = val 7s;
let y: score = %x;
sub %y, %x;
if eq %x, 8s: call run "foo:main/bar";
}
"foo:main/bar" {
say "hello";
}
IR 将支持
- 不同数据类型的寄存器
- 具有返回值和参数的函数调用
- if/else 逻辑
- 执行修饰符
- 循环
IR 设计得尽可能简单,以便创建并保持更新之间的稳定接口,但它并不总是最易于优化的。因此,IR 会迅速降低到 MIR,这是一种非常相似的格式,略微不那么方便,但大多数优化都发生在这里。在 MIR 内部,运行多个遍历指令,如
- 函数内联
- 循环优化
- 数学优化
- 修饰符组合
- 逻辑优化
- 宏优化
- 移除死代码
- 合并/缓存 NBT 操作
接下来,MIR 再次降低到 LIR,这尽可能接近实际的命令。虽然一些 IR 和 MIR 指令可能最终表示多个命令,但 LIR 指令基本上是 1:1 的。另一个区别是类型的表示。虽然 IR 和 MIR 指令适用于多种类型,并且只为不支持的数据类型提供错误,但 LIR 为不同类型的数据提供单独的指令。在 LIR 中,运行更多更针对 Minecraft 的遍历,例如
- 重新排序选择器参数
- 优化执行修饰符
- 重新格式化以执行存储
- 准备代码生成的值,具体取决于目标
最后,在代码生成阶段,将 LIR 处理成 Minecraft 命令。代码生成一次只查看一条指令,选择最佳和最小的变体以减少输出大小。
进度
目前,主要需要完成的事情是将游戏中的所有命令实现为指令。这,再加上实现其他优化和功能,如自定义指令、宏和覆盖。
- IR 功能
- 类型
- NBT 类型指令
- 寄存器
- 具有注解的函数
- 参数和返回值
- 数学和逻辑指令
- 自定义命令
- 自定义命令访问寄存器、参数等
- 如果
- 嵌套块
- 循环
- 查找表
- 否则
- 逆二进制操作
- 函数标签声明
- 递归
- 宏类型
- 全局存储
- 结构化类型
- 返回值传播
- Minecraft指令和功能
- 命令指令
- 大多数命令
-
/tellraw
和/title
-
/damage
-
/random
-
/advancement
和/recipe
-
/schedule
-
/particle
-
/bossbar
-
/team modify
,/scoreboard objectives/players modify
- 一些选择器参数
- 一些修饰符
- 命令指令
- 编译/使用
- 数据包目标
- 对运行的遍历进行精细控制
- 命令方块目标
- 版本目标
- 覆盖
- 自动插入溢出检查/断言
- 调试/断点指令
- 优化
- 指令简化
- 函数内联
- 死存储消除
- 死代码消除
- 常量传播、折叠和评估
- 函数简化
- 智能寄存器分配
- 计分板数据流
- 指令模式匹配
- 指令组合
- 赋值模式匹配
- 数学模式匹配
- 条件模式匹配
- 逻辑模式匹配
- 函数特殊化
- 更智能/不那么激进的内联
- 宏优化
- 修饰符合并
- 修饰符简化
- 成本分析
- 修饰符组合
- 移除空修饰符
- 修饰符-选择器优化
- NBT访问合并/缓存
- 值编号
- 类型缩小
- 范围传播
- 尾调用优化
- 函数合并
- 循环优化
- 高级选择器优化
- 块操作组合
- 控制流优化
- 参数/返回值复制省略
- 实用工具
- 大多数IR功能的解析(主要用于测试)
- 代码生成测试套件
- 基本的Python绑定
- 数据包前端(来自类似mecha的工具)以允许数据包 -> 数据包编译
依赖
~2.6–3.5MB
~76K SLoC