Zig的新@bitCast语义和LLVM后端改进
本页面包含了对主分支Zig最近更改的策划列表。该页面包含了2026年的条目。其他年份的记录可以在Devlog档案页面找到。2026年6月25日 新的@bitCast语义和LLVM后端改进 作者:Matthew Lugg(接下来会有一段很长的开发日志,抱歉——我在这个问题上有点兴奋!)几周前,我开始在一个分支上工作,实施对LLVM后端的改进,这个改进已经计划了很长时间。结果这演变成了一个更大的更改,实现了一些您可能感兴趣的语言提议。 LLVM后端整数降级 Zig一直将任意位宽整数类型(例如u4、i13、u40)直接降级为LLVM IR的位整型(i4、i13、i40)。然而,我们早就知道这种降级并不理想,因为LLVM文档中对这些类型在内存中表示的语义对优化器来说是过于限制的。或许更重要的是,因为Clang从未以这种方式生成LLVM IR,因此LLVM中的这些代码路径从未得到过适当的测试,因此在实践中支持较差——在过去几年中,我们观察到许多简单优化被遗漏,甚至出现了错误编译的情况。因此,该PR的原始目标是仅在操作SSA形式的值时使用这些位整型,并在将它们存储在内存中时将其零扩展或符号扩展到ABI大小的类型(i8, i16, i32等)。这应该是良好支持的,尤其是因为这与Clang降级C的_BitInt(N)的方式相匹配!那次更改实际上相当简单,但我遇到了一个问题,这让我进入了一个小小的兔子洞。 @bitCast的问题 @bitCast是一个有趣的内置函数。在过去,它被定义为等同于以下操作序列:获取操作数值的指针 将其转换为目标类型的指针 从该指针加载 换句话说,这本质上是重新解释内存字节的语法糖。然而,随着时间的推移,我们偏离了这个定义——例如,允许使用@bitCast将[3]u8重新解释为u24,尽管在大多数目标上,@sizeOf(u24)大于@sizeOf([3]u8),因此上述定义将引发未定义行为。直到现在,LLVM后端仍然实现了这些不明确定义的@bitCast内置函数语义。然而,由于该定义涉及重新解释内存,改变我们在内存中存储整数类型的方式最终影响了@bitCast的实现,引入了未定义行为,导致编译器测试套件崩溃。对此最简单的解决方案可能是在LLVM后端实现逻辑,大致匹配旧的行为。相反,我选择了一个更好的解决方案——实现@bitCast的新定义。 重新定义@bitCast 2024年,Jacob Young提出了语言提案#19755,旨在通过准确指定一组新语义来解决@bitCast的问题。该提案在提交后不久获得接受,实际上,它所详细说明的语义已经被自托管的x86_64后端实现!因此,为了解决LLVM后端的问题,我并不一定需要匹配旧的@bitCast语义——相反,这似乎是一个很好的时机,最终在所有地方实现新的语义。作为旁注,另外一个这样做的优势是我们可以利用编译器的合法化处理,该处理将难以降级的操作重写为简单的操作,从而使编译器后端只需支持那些简单操作。合法化处理已经有功能,供自托管的x86_64后端使用,它将复杂的@bitCast操作转换成更简单的操作,并且可以轻松地适应其他编译器后端(主要是LLVM和C后端)——但前提是它们实现了新的语义。无论如何,关键是,我开始了一段支线任务(这最终比原始任务更难)来在整个编译器中实现这些新语义。这不仅包括LLVM和C后端,还包括编译时执行——毕竟,Zig允许您在编译时进行几乎任何操作,包括@bitCast!因为新的语义与旧的有实质性的不同(稍后再说),我还不得不审核许多关于@bitCast的使用,包括标准库、编译器和支持库(例如compiler_rt)。但经过一些对CI失败的几乎无痛修复后,我终于让我的PR通过了,并于昨天合并到了主分支(在此过程中关闭了几个问题!)。 新的@bitCast语义 现在我们已经了解了所有背景,是时候向我解释新的@bitCast行为了。它不再基于重新解释内存中的字节,而是根据逻辑上表示类型的位进行定义。每个支持@bitCast的类型都有...
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡