8 ms·
Zig – SPIR-V Backend Progress
- Gerharddc 3mo agoReally cool to see work progressing on this! It would be awesome to one day be able to use Zig for serious shader work
- laszlojamf 3mo agoI really love everything about zig except the language itself. The governance, the culture, all of it seem really cool, but reading https://ziglang.org/learn/why_zig_rust_d_cpp/ https://ziglang.org/learn/why_zig_rust_d_cpp/ I still don't get _why_ I would use it. To an untrained eye, it seems like go, but with manual allocation. Or an imperative-only rust. Like it has some features of all the languages it competes with, but not the ones that would make me reach for them. What do people use zig for, and why zig and not one of the others?
- Cloudef 3mo agoTry reading zig code. For me its much more readable than the other languages, and does not suffer the fact go doesnt have language level errors. Local allocators are very useful and if you dont think so, perhaps you havent dwelved too deeply into systems programming or the language isnt targeted for you.
- laszlojamf 3mo agoI get the usefulness of allocators, I just don't see them as useful enough where I'd pick zig over another established systems programming language. Do you have an example?
- chaz72 3mo agoI think Zig would do better than Go at things like kernels, drivers, game engines, lower level sorts of things. Edited to add the obvious: SPIR-V, for instance. Of course there’s lots of programming that can afford to pay for GC side effects, if there weren’t we wouldn’t have invented GC, but it’s a little less universal, a little less ‘system’. For me, I came to Zig after horrible cross-platform experiences led me to try going all the way back to C and I found that I was spending way too much time learning to deal with accidental complexity instead of essential complexity. (Respect to the C masters but I failed to adapt.)
- PunchyHamster 3mo ago>I think Zig would do better than Go at things like kernels, drivers, game engines, lower level sorts of things. Edited to add the obvious: SPIR-V, for instance. But people don't write those in Go, they use Rust for it
- chaz72 3mo agoMy specific reply was to laszlojamf saying “it seems like go, but with manual allocation”. To your point though, if Rust is getting it done, go for it. A lot of people still write those in C though.
- pjmlp 3mo agoYes they do. Only those with anti-GC bias don't. Which is why TamaGo, TinyGo and gVisor exist.
- dnautics 3mo agoa lot of heavy duty systems have multiple allocator systems. the erlang virtual machine has 12: https://www.erlang.org/docs/25/man/erts_alloc.html https://www.erlang.org/docs/25/man/erts_alloc.html jvm has at least 5: https://github.com/openjdk/jdk/blob/master/src/hotspot/share/memory/allocation.hpp https://github.com/openjdk/jdk/blob/master/src/hotspot/share... postgres has at least 8: https://github.com/postgres/postgres/blob/master/src/backend/utils/mmgr/README https://github.com/postgres/postgres/blob/master/src/backend... since zig anoints an allocator interface in its stdlib, your (and the stdlib's) data structures which use allocators can be trivially reused across different allocation strategies without rewriting code; and very likely (not guaranteed ofc) if you bring in someone else's code they will cleave to convention.
- nesarkvechnep 3mo agoJust yesterday I was thinking about the BEAM and would it be tidier if it were written in Zig.
- pjmlp 3mo agoJVM has surely more than 5, because the ecosystem enjoys multiple implementations.
- coxmi 3mo agoThe dot syntax used everywhere really confuses me. I get its use in struct fields, or for defining anonymous structs, but what is this one for? (Some kind of module-level enum space, where .sampler and .unknown are defined previously?) const Sampler = @SpirvType(.sampler); ^ const Image = @SpirvType(.{ .image = .{ .usage = .{ .sampled = u32 }, .format = .unknown, ^ } }); Everything else about zig is quite readable, but this gets me every time. Maybe I'm being dumb though.
- thrwyexecbrain 3mo ago"Dot" in zig is a placeholder for types that can be unambigously inferred from the surrounding expression. So ".unknown" is a standin for "SomeEnum.unknown" or "SomeStruct.unknown", depending on what .format is.
- coxmi 3mo agoYeah, after looking it up, it looks like it is basically only used as either field access or an 'infer operator', is that right? I thought it was used in four completely separate ways: · normal struct field access · anonymous struct definition · field definition within structs (for reasons to do with the parser) · an extra 'infer operator' for syntactic sugar But there's no support for anonymous structs/fields, and all structs and fields require a type somewhere for it to be inferred. Which is why this is invalid zig: const test = .{ .x = 0, .y = 1 }; (It would need the type to be specified in the called function definition, or inline when assigning) Correct me if I'm wrong here! (And thank you)
- tremon 3mo agoI don't think that "infer operator" is a special case of field access, to me it feels like regular known-type elision similar to how C# and C++ use the var keyword if the data type can be inferred from the rhs expression: const Enum = enum {one, two, five}; const t: Enum = .one; // Enum.one, but the type was inferred from lhs std.debug.print("{t}\n", .{t}); Defining an anonymous struct is valid in zig; your example is only invalid because "test" is a reserved keyword. But you are correct that it reifies into a concrete type, and after initialization it doesn't coerce into other types because zig doesn't do structural typing: const anonymous = .{ .x = 0, .y = 1 }; std.debug.print("{}\n", .{@TypeOf(anonymous)}); // will output something like test_0__struct_45138 const Point = struct { x: i32, y: i32 }; const p1 = Point{ .x = 0, .y = 1 }; // valid, explicit struct literal const p2: Point = .{ .x = 0, .y = 1 }; // valid, anonymous struct will coerce to Point //const pt: Point = anonymous; // error: expected type 'test_0.Point', found 'test_0__struct_45138' And then there's fieldless anonymous structs aka tuples. I'm including them because they were used in the print statements above: const tuple = .{ 0, "1", true }; std.debug.print("{}\n", .{@TypeOf(tuple)}); // struct { comptime comptime_int = 0, comptime *const [1:0]u8 = "1", comptime bool = true }
- nnevatie 3mo ago> why zig and not one of the others? I think one of the selling points is that the language does not come to your way and allows unsafe constructs. So, I think the target audience is roughly at C and C++ users.
- austin-schick 3mo agoI think this blog post has a great description of the "Modern C" niche Zig fills: https://vfoley.xyz/hare/ https://vfoley.xyz/hare/. I tend to think of Zig in this way. If you found yourself reaching for C, you could instead reach for Zig. You'd get optionals instead of null pointers, comptime instead of macros, a real facility for handling errors, etc. It's like C but with some of the sharp edges sanded off.
- deleted 3mo ago[deleted]
- dnautics 3mo ago> What do people use zig for, and why zig and not one of the others? I'm the maintainer of zigler (https://zigler.hexdocs.pm/Zig.html https://zigler.hexdocs.pm/Zig.html), and I have my own pharma startup. I currently use zig in two contexts: 1) wraps a proprietary .so file that is used to communicate with a scientific (microscope) digital camera, in a nice BEAM-module-shaped interface. Sorry, code is private. 2) I have a vue.js component that does DNA editing, and one of the features is DNA sequence alignment, and so I had claude write the smith-waterman lalign algorithm in zig, and it compiles to wasm, and this plus going from O(N^2) to O(N) dropped the runtime of an alignment from 30s to a few hundred ms, in both cases so much better than ~5m using a web SAAS, good enough that I can render alignments on-demand, and I don't have to do a storage layer for alignments. https://github.com/Vidala-Labs/opengenepool/tree/master/src/wasm https://github.com/Vidala-Labs/opengenepool/tree/master/src/... you can play with it at: https://opengenepool.vidalalabs.com https://opengenepool.vidalalabs.com Two sequences may be aligned by right-clicking a sequence name when a sequence is loaded, it will align the two sequences (you'll have to create a second sequence as it forbids aligning a sequence with itself). Why zig? Because it just makes things like cross-compilation easier (microscope is mounted on a elixir nerves deployment!), and has less footguns, and doesn't hide away things you might care about. Most of the things i build with zig don't really have a concern about memory safety, or have such trivial memory patterns that it's easy to verify by eye that they're memory safe.
- auraham 3mo agoCan you give more details about using zig along with elixir? > microscope is mounted on a elixir nerves deployment! What do you mean? I imagine that there is an Elixir application running on an embedded system and maybe it relies on an external binary application (compiled using zig). If so, how do you manage the communication between them?
- dnautics 3mo agono, it mounts a .so file using dlload, and itself is a NIF. Incidentally there is a second proprietary industrial camera on there that I have running as a different NIF built in zig, but truth be told I probably could have had claude do that one in pure elixir. However, claude did write a harness that I used to inspect the usbpcap dumps (and create the camera interface), that was done in zig for simplicity and turning it into a nif using zigler was a trivial transformation for claude to do.
- applfanboysbgon 3mo agoC is over 50 years old, but it is still more or less the lingua franca of computing. The world benefits from having "C with some improvements from 50 years of learning". The world also benefits from having featureful languages that are a huge divergence from C, but it also just needs a language that provides a thin cross-hardware abstraction over the asm layer and some conveniences over writing raw asm. We don't need every language to be massively featureful, and we hopefully won't all have to reach for C for the rest of human civilization when we need a language that isn't massively featureful.
- pjmlp 3mo agoThose improvements were already available in languages that predated C, but were seen as programming with straightjacket from UNIX crowds. Note that even C creators proposed changes to WG 14 (not accepted), and later on moved on with their own approaches with Alef, Limbo and finally Go.
- epolanski 3mo agoThe problem with this is imho that for a C replacement it doesn't offer enough to C programmers to switch. If you're comfortable with C you will stick with C and benefit from it being the lingua franca, and not struggle to find support or talent. This is true both at work or OS. As a very talented C dev told me, I can see the point or go or Rust that would solve some of my issues, Zig while being an improvement doesn't solve any of my real pain points.
- pjmlp 3mo agoExample, Zig's solution to use after free is the same kind of debug allocators that have existed for C since the last 40 years.
- auraham 3mo agoI have the same feeling about Zig. In this interview [1], Andrew Kelley, creator of Zig, explains a lot of the features of the language; compares it against c, rust, go; and explains why he created the language. According to him, the killer feature of zig is the tool chain (compiler, linker, build system) since it has no dependencies. So, it will work in any OS/target you choose. It is a really interesting interview. However, Zig code is a bit hard for me to read. [1] https://www.youtube.com/watch?v=iqddnwKF8HQ&t=10s https://www.youtube.com/watch?v=iqddnwKF8HQ&t=10s
- fuzztester 3mo agoI saw that video just a few days ago and agree that it is quite a good one. I liked the way Andy talked throughout the video, and also thought the interviewer's questions were very good.
- audunw 3mo agoI really think the best way to describe it is an attempt to replace C. Go is only like C in that it's simple. But it's clearly not a direct C replacement. It's not a great language for writing an OS or embedded code. Rust may replace C in many contexts, but Rust is much more like C++. It adds a lot of complexity to the language and the compiler. I think it does it in a much better way than C++ so I think it is more likely to replace C in certain contexts where C++ did not replace C. But Zig really is a much more direct replacement for C. It's aiming at the same niche, but in a different way. And considering how much C still dominates systems programming, it should be pretty clear that if Zig succeeds in become a good replacement, the answer to your question is: you'd reach for it whenever you'd have reached for C before. The only question at this time is if Rust will eat so much into that niche that what's left for Zig becomes too small. Though it could go the other way. Zig is simpler and easier, and you can iterate really quickly with it. There's even incremental compilation now. I suspect tests with debug allocators, the integrated fuzzing, static analysis and LLM assisted reviews, can make Zig just as safe as Rust in practice, with far less complexity. So maybe Zig will eat into Rusts niche (whenever Zig is mature, right now it's going the other way as seen with Bun)
- geokon 3mo agoI think there are very few places where C makes sense and C++ doesn't. Its mostly legacy things like the Linux Kernel, or more aesthetic projects like demoscene or suckless. Where its easier to agree to write C instead of trying to agree on what subset of C++ to use (even then its usually C with a mishmash of C++ ergonomics) That said, leafing through the first chapters of "Expert C Programming" should dissuade anyone of the idea that C is a simple language. It'll leave you amazed anyone's been able to write working programs in it
- lelanthran 3mo ago> That said, leafing through the first chapters of "Expert C Programming" should dissuade anyone of the idea that C is a simple language. It'll leave you amazed anyone's been able to write working programs in it What footguns are present in C bit not in C++? C++ has all the footguns from C and adds multiple more. C++ is not a replacement for C, in the same way that a spacecraft is not a replacement for a Cessna.
- lelanthran 3mo agoIf you want something better than C you aren't going to reach for Go (GC) or Rust (complexity). Zig looks like a good middle ground.
- _bohm 3mo agoI’m writing a game engine in Zig and after tens of thousands of lines written, I have to say my mind has totally melded to the language. It really hits a sweet spot for me between being expressive enough, and there only being one way to do something most of the time.
- Zambyte 3mo ago> To an untrained eye, it seems like go, but with manual allocation. I've written a decent amount of Zig, Go, and C, and I often describe Zig as in between Go and C. So your untrained eye seems pretty accurate. Maybe it's just not the tool you need, and that's fine! I could get excited about a new tractor that is well built and leans heavily into right to repair activism, but I live in a city and wouldn't use it.
- weitzj 3mo agoSide question as I am following zig only losely and do Go Programming: Zig has the feature that you can drop in your allocator from the caller. Now with 0.16 you also "bring your own IO" implementation with you. And for my understanding this looks like the pattern Go uses with its Context package, where you pass in transitive data, cancellation signals and timers to for example stop an SQL query in server B, since a user canceled a web request in their browser before hitting server A, whilst all elements delegate the Context. Then yesterday was total unrelated article about NUMA architecture, and I remember somewhere that the creator of Erlang mentioned (Joe Armstrong) that you cannot get around physics and it takes time to call a function between servers, therefore so not try to hide the latency between the calls. And now to my question: Would that in any way make sense for zig to go even more in this direction, where you pass in your allocator, IO, but now with something similar to Google Go context, but have it even more fine grained? So that your functions could actually in their interface expose somehow the time in between CPU cores (NUMA) up to the request cancellation as Google go context is used for timeout signals, cancellation signals. Also probably making time an external dependency as well. So in essence , every function would be treated as a remote procedure calls, whereas remote would mean: "other cpu", other server/service
- dnautics 3mo agonot really sure what you're asking. but time is now part of the io interface, so you can pretty easily write your own io implementation that just stubs out to the stdlib's default io content and has custom time functions if you want to try something funky. This is pretty close to what you are asking for (and in terms of functionality, equivalent). I say go for it and see what happens, report back!
- weitzj 3mo agoThank you for your response. So time as you mentioned can be made explicit. I am probably looking for something like the request context with timers and cancellation signals propagating through the call chain like in gRPC but more fine granular. So you could implement arbitrary response times of functions. So you could say like: This whole request must finish in 5 seconds, otherwise abort. And these 5 seconds can be made very low so that you reach latency of NUMA vs Single CPU. I don't know how you call this, maybe "latency budget"
- joshsyn 3mo ago[dead]
- LegNeato 3mo agoSee also the rust spir-v backend: https://github.com/Rust-GPU/rust-gpu/ https://github.com/Rust-GPU/rust-gpu/
- mccoyb 3mo agoThis is inspiring! At the same time, it’s not exactly clear to me how this is going to work in the long term without changes to the Zig language itself, questions below. Assuming the goal is to be able to write compute kernels and shaders in Zig - the concerns of writing (and especially optimizing) these programs are significantly different from high-performance CPU execution. Mojo, for instance, has seemed to solve this problem (presumably: I haven’t studied the compiler myself, but this is a claim of theirs) but the community has implied that solving this problem required semantic and compiler design decisions different from the Zig compiler, especially around memory spaces, pointers, and origins. Further: if you open up a modern tensor / GPU compiler (Triton, XLA, logical / scheduled kernel systems like Halide or Exo, or low-level kernel compilers like Mojo) — the optimizations and analyses which are performed on GPU kernel code are significantly different than CPU code Is the end goal to write such a pipeline into the Zig compiler? It seems possible to do this - but I’m not sure … it seems a bit hacky, or like one has to coerce existing Zig semantics to be repurposed for a job it was not designed for in the first place? One alternative might be to use comptime to expose a kernel builder DSL, followed by a GPU compiler pipeline implemented in Zig (a completely separate compiler). This seems straightforward and allows you to implement and gain access to the specialized semantics / optimizations that you’d need for high-performance kernels? I could absolutely be wrong, interested in thoughts.
- flohofwoe 3mo agoZig's SPIRV support is on the same abstraction level as GPU shading languages (GLSL, MSL, HLSL, WGSL, ...), there's nothing particularly "magic" about turning imperative source code (no matter if Zig or any other language) into a sequence of SPIRV instructions, it's not all that much different from generating x86 or ARM instructions. The main difference to 'traditional' CPU programming is that you don't write an entire 'application' with a single main function, but instead many small-ish self-contained functions that will run 'per vertex', 'per pixel' or 'per compute invocation' on the GPU. The Zig toolchain is only concerned about how to compile Zig code into SPIRV blobs, but not about how that code is then 'uploaded' and 'orchestrated' on the GPU, instead this is the job of APIs like Vulkan (e.g. there is no magic integration between CPU- and GPU-side code in the Zig toolchain like in the CUDA toolchain). SPIRV's specification basically defines what features Zig needs to expose as specialized builtins or language features (e.g. things like `@SpirvType(.sampler);` or `@SpirvType(.{ .image = .{...` or `@extern(*addrspace(.constant)` map directly to SPIRV concepts (the same concepts that dedicated shading languages had to add on top of C or C++).
- sylware 3mo agoLLVM? Ok it is over. Bye.
- Zambyte 3mo agohttps://ziglang.org/devlog/2025/#2025-06-08 https://ziglang.org/devlog/2025/#2025-06-08
- flohofwoe 3mo agoWhat's that even supposed to mean? LLVM isn't mentioned once in the post, instead it's about updates to Zig's "inhouse" SPIRV backend, not the LLVM SPIRV backend.
- sylware 3mo agoWhile browsing the articel, I saw a big title with LLVM: insta good bye, no thanks.
- flohofwoe 3mo ago> While browsing the articel, I saw a big title with LLVM ...that's an entirely different article. But if it makes you feel any better (and at the risk of trying to talk to a troll because you sure sound like one): Zig is in the process of getting rid of the integrated LLVM backend - the compiler will still be able to emit LLVM bitcode as an option though which then can be fed into an externally provided LLVM backend (LLVM's optimizer passes are still hard to beat).
- sylware 3mo agoHave a look at QBE.
- flohofwoe 3mo agoFirst sentence on https://c9x.me/compile/ https://c9x.me/compile/: "QBE is a compiler backend that aims to provide 70% of the performance of industrial optimizing compilers in 10% of the code." That doesn't sound like QBE wants to compete with LLVM when it comes to optimizations.
- z0ltan 3mo ago[dead]
- PunchyHamster 3mo agoAdding some particular graphics related type as builtin seems a bit weird
- flohofwoe 3mo agoI think it's an elegant solution. SPIR-V requires this sort of type annotations, and a builtin like `@SpirvType()` is quite 'Zig idiomatic' and looks to me like the right way to do it since it doesn't "pollute" the language with a dozen new keywords. In C/C++ and MSL that information would be provided via `[[ ... ]]` attributes (which may look even messier), and other shading languages usually have dedicated keywords (most readable, but it 'pollutes' the entire language for what in Zig would be a niche use case).
- fuzztester 3mo agoI've read some part of this thread, but I didn't see anyone mentioning D as a better C.
- fuzztester 3mo agoah, downvoter fuckster hners who cant handle anyone who thinks differently from their shitty hive mind ...
- pjmlp 3mo agoWelcome to the club, according to those folks this is impossible. "Eric Bier Demonstrates Cedar" https://www.youtube.com/watch?v=z_dt7NG38V4 https://www.youtube.com/watch?v=z_dt7NG38V4 https://worrydream.com/refs/Swinehart_1985_-_The_Structure_of_Cedar.pdf https://worrydream.com/refs/Swinehart_1985_-_The_Structure_o...
- fuzztester 3mo agoThanks, will check out those links.
- pjmlp 3mo agoSome people cannot take systems languages with automatic resource management.
- fuzztester 3mo agoyep. it's their loss. sad sacks. https://en.wikipedia.org/wiki/Sad_Sack https://en.wikipedia.org/wiki/Sad_Sack I read many of those sad sack comic strips, and many others, like dennis the menace, richie rich, archie (archie, betty, veronica, reggie, moose, midge and jughead), casper the friendly ghost, phantom, etc., in paper comic books, as a kid. somewhat or quite entertaining, depending on which strip, i gotta say. the image of sad sack sitting on a stool n peeling potatoes is imprinted in my memory, ha ha. hey sarge. good times ...
- flohofwoe 3mo ago