-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SPIR-V target? #2683
Comments
adding a custom spir-v target might lay the groundwork for adding other backends to zig. |
The most straightforward way for this to work would be if LLVM supported it directly. However it's still open for discussion to do this even if that scenario does not happen. |
One potential fruitful direction could be to look at how clang does this: It has |
Sorry, this article appears to have some references to the current state of the art: |
Some advice from @paniq about implementing such a backend:
|
Hi @andrewrk -- I think LLVM is well on its way to supporting this, but ISTM that it might be necessary or useful to use MLIR. I'm currently exploring this on my own and it definitely seems like a cool project! Far from groking it just yet, but it should be possible to target other GPU backends besides SPIR-V/Vulkan this way, too. IREE is taking this approach to compile from TensorFlow through LLVM. |
How would this work with defining images, buffers, input/output variables and all the binding slots and stuff? Or would this just be for the OpenCL use case? (Or maybe all of this can be solved 'easily'?) I see they want to compile C++ to SPIR-V 🤦♂ RUN AWAY! 😱 |
I think the focus here should be on generating MLIR / SPIR-V. Tooling and other stuff (like whether / how to use OpenCL types, how to launch and schedule kernels, native GPU types for components, and all that) isn't out of the question, but can hopefully be done as library layers on top of the core functionality. (Counterargument: if the heterogeneous system is all modeled in one IR, LLVM can optimize across the CPU/GPU boundary, as IREE does.) Otherwise it runs the risk of being too much work to implement or to become useful in a reasonable amount of time. If adding a SPIR-V backend requires too many |
With inline assembly, or with target-specific builtin functions. |
https://github.com/EmbarkStudios/rust-gpu does this (its 0.1 release just came out). |
Actually, rust-gpu does not use LLVM's spirv target at all, it manually codegens direct to spirv (the primary motivation for doing it that way is because LLVM's spirv target only supports an opencl/cuda-like execution model, not shader execution models) |
I'm not sure if a SPIR-V target is the best option, since you never actually My workflow with SPIR-V is always something like this:
which makes some sense in this case, since you need extra compiler for the If Zig adds a SPIR-V backend, the workflow would be the same. But I think we I propose that there would be a builtin function that takes a Zig function and This would mean that the same functions can be used by CPU and GPU code, in It also frees the programmer of the cumbersome task of embedding files into I imagine it could look something like this: fn add(a: u32, b: u32) u32 {
return a + b;
}
fn compute(gl_GlobalInvocationID: [3]u32, buf: []u32) {
const idx = gl_GlobalInvocationID[0];
buf[idx] = add(idx, idx);
}
const spirv: [_]u32 = @spirv(compute);
fn main() {
// I can call compute()/add() here on the cpu and at the same time can send
// them to GPU as a compute shader
} In this case the OpEntryPoint is constructed from the compute function Alternatively Zig could just expand the It could then look like this: const spirvc = @import("...");
fn add(a: u32, b: u32) u32 {
return a + b;
}
fn compute(gl_GlobalInvocationID: [3]u32, buf: []u32) {
const idx = gl_GlobalInvocationID[0];
buf[idx] = add(idx, idx);
}
const spirv: [_]u32 = spirvc.compile(@typeInfo(@TypeOf(compute)), ... more arguments specified by the library ...);
fn main() {
// I can call compute()/add() here on the cpu and at the same time can send
// them to GPU as a compute shader
} Should I create a new issue for this proposal? |
Wouldn't this already be possible? In our case the language and the compiler would be the same, but the code would probably be in an external file.
You might be interested in # build our shaders:
# of course this could also just be part of build.zig.
zig build-obj -target spir vert.zig; zig build-obj -target spir frag.zig
# compile and run:
# inside the rest of the codebase we `@embedFile` vert.spv and frag.spv and then send it to the GPU at runtime.
# and in our codebase we can always simply `@import` vert.zig or frag.zig and reuse its code.
zig build run Looks like a pretty nice workflow to me. One less dependency in terms of compiling the shaders as well. |
This is already possible because of Zig's lazy compilation. Just dont reference any of the host functions on the device and vice versa and youre good. The only thing that is required really is conditionally exporting entry points, both for the device and host side: pub fn frag(...) void {
}
pub fn vert(...) void {
}
pub fn realMain(...) void {
}
usingnamespace if (is_shader) struct {} else { pub const main = realMain; };
comptime {
if (is_shader) {
@export("vert", vert, .{});
@export("frag", frag, .{});
}
} (instead of conditionally exporting entry points you could also have multiple files that all |
Yeah you are right. Didn't think of that.
+1
What do you mean by host functions? I didn't find anything in the documentation. |
@ProkopRandacek Host is usually referring to the CPU, while device refers to GPU. Robin is saying that if you write code that should only run on the CPU, then the final spirv output will not contain this code as long as you don't call it from any of your GPU code |
This is implemented. Separate issues can be filed for follow-up enhancements. |
Hello,
What would be involved in adding SPIR-V as a target for Zig? There's a translator from (some subset of?) LLVM to SPIR-V; as I understand it, Zig compiles first to LLVM, so this seems reasonable. There's been some discussion of adding SPIR-V as a Clang target which I'm not sure has materialized further, but I think this would be interesting.
This document goes into detail about the representation of SPIR-V in LLVM:
https://github.com/KhronosGroup/SPIRV-LLVM/blob/khronos/spirv-3.6.1/docs/SPIRVRepresentationInLLVM.rst
The text was updated successfully, but these errors were encountered: