Zig Refactors LLVM Integer Lowering, Redefines `@bitCast` Semantics, and Revamps SPIR-V Backend
Zig has overhauled its LLVM backend to store arbitrary bit-width integers as ABI-sized types in memory, driving a logical redefinition of the `@bitCast` builtin. Concurrently, the SPIR-V backend has transitioned to multi-threaded codegen, introduced a native `@SpirvType` builtin, and integrated calling-convention-driven execution modes.
LLVM Integer Lowering and the Extension Strategy
The Zig compiler has updated its LLVM backend to alter how arbitrary bit-width integers (such as `u4`, `i13`, and `u40`) are lowered. Historically, Zig lowered these types directly to LLVM IR's corresponding bit-int types (`i4`, `i13`, `i40`) for both SSA registers and memory storage. Because Clang does not emit IR in this manner, this code path was under-tested in LLVM, regularly resulting in missed optimization passes and compiler bugs.
Under the new implementation, arbitrary bit-width integers are lowered to LLVM bit-int types exclusively when manipulated in SSA form. When stored to memory, they are now zero- or sign-extended to ABI-sized types (such as `i8`, `i16`, or `i32`). This alignment matches Clang's lowering strategy for C's `_BitInt(N)` types, utilizing highly optimized and well-tested LLVM execution paths.
Redefining `@bitCast` via Logical Bit Layouts
The change to integer memory storage necessitated a fundamental rewrite of the `@bitCast` builtin. Previously, `@bitCast` acted as syntax sugar for a pointer-cast reinterpretation of memory bytes. This physical-memory definition created regressions when changing integer storage layouts, particularly because the size of certain types like `u24` in memory can exceed their logical size.
To resolve this, Zig has implemented language proposal #19755, redefining `@bitCast` based on logical bit layouts rather than physical memory. Every supported type is mapped to an ordered sequence of logical bits. For example, a `u5` contains 5 logical bits ordered from least- to most-significant, while a `[2]u5` consists of 10 logical bits sequentially concatenated. The builtin now directly translates between these logical bit sequences.
This logical definition enables the compiler’s Legalize pass to lower complex `@bitCast` operations into simpler primitives. This standardization benefits the LLVM, C, and compile-time (comptime) backends. It also ensures consistent behavior across backends, matching the existing implementation in the self-hosted x86_64 backend.
SPIR-V Backend Architecture and `@SpirvType`
The SPIR-V backend has undergone a substantial refactoring to resolve technical debt and align with recent compiler changes. A major addition is the `@SpirvType` builtin, which provides a mechanism to represent hardware-specific types that do not map directly to Zig’s standard type system. This builtin allows the definition of samplers, images, sampled images, and runtime arrays directly within Zig shader code.
Execution mode metadata, such as workgroup sizes and fragment origins, is now declared directly on the calling convention itself. The previous `std.gpu.executionMode()` helper has been deprecated, and the SPIR-V assembler now rejects manual `OpExecutionMode` inline assembly instructions. Two new calling conventions, `spirv_task` and `spirv_mesh`, have been added to support modern mesh shading pipelines.
Additionally, SPIR-V capabilities and extensions are no longer generated ad hoc or via inline assembly. Instead, they are driven by the target CPU feature set, resolving dependency chains directly from `SPIRV-Headers`.
Multi-Threaded Codegen and Object Linking for SPIR-V
The SPIR-V backend has transitioned from a single-threaded execution model running inside the linker thread to a multi-threaded architecture. Each codegen job now produces a Medium Intermediate Representation (Mir) value, which is scheduled concurrently across the compiler’s thread pool.
This architectural change enabled the restoration of two instruction selection (ISel) passes that were previously removed: `dedup_types` (which merges identical type instructions) and `prune_unused` (which strips dead code). Furthermore, `.spv` files are now fully recognized as standard object files. The SPIR-V linker can natively stitch multiple `.zig` source files and external `.spv` objects into a single module. These updates have contributed to a 10% increase in passing behavior tests on the `spirv64-vulkan` target.