-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Proposal: Assembly backed opaque types #20550
Comments
Can you explain this a little bit more? What does assembly-backed opaque types have to do with I/O? |
I think it is worded like that too keep this separate from a proposal to allow more I/O for assembly in global contexts, which is currently not allowed I think. |
Unaccepting for further consideration since @Snektron expressed interest in making a counter proposal. |
BackgroundSPIR-V is a strongly typed IR format, like LLVM IR especially before LLVM removed pointee types. Most operations need to be ascribed with their result type. Like LLVM IR, it supports the primitve types you'd expect (ints, floats, bools, ...) and also provide the building blocks for composite and custom types (pointers, structs, ...). The problem is that SPIR-V has additional built-in types for GPU-specific things, for example samplers and images. These are required in practical code, too, for example for textures. When returning a type that is or contains for example an image to there, the generated SPIR-V code needs to refer to that image. For OpenCL, this is not much of a problem: Images are usually supplied as pointers (for example set as a uniform), which we can cast to an opaque type. In this case, we can deal with most of these types from inline assembly. This is not the case for Vulkan, where we are not allowed to perform such casts. Here we need a way to refer to these types from Zig shader code. While I doubt the use case of actually returning images (for example...), a way to refer to these from builtins or function parameters is vital. Additionally, SPIR-V supports optional decorations on types that change them in a non-trivial way: For example the Required SPIR-V TypesConcretely, there should be a way to refer to the following types. Some of these are parameterized, see the linked SPIR-V spec for the parameters that they require. Not all of these are immediately of interest. Note that as far as I can tell, all of these types are opaque. While the OpenCL spec allows implementations to choose a size or Some types are intended to still be used without pointer. For example, to use a cooperative matrix in pseudo code:
Even though the cooperative matrix is an opaque type, they are still allowed to be used like this. This is similar to bools. |
The counterproposal, or rather nullhypothesis, is to simply add the required types as Zig builtins. The main advantage is that its a little bit more straight forward to implement. The drawbacks are that its a lot of baggage to keep around for all the other backends, I don't like that. Its also a lot less flexibly, in contrast to the original proposal. After some additional thought I still think that the original proposal works better. |
One other alternative I've thought of is a special SPIR-V assembly instruction that allows us to "override" a type during linking. We'd specify a dummy type during codegen and then patch it out. For example: // This creates `%Image = OpTypeOpaque`
const Image = opaque {
pub fn whatever(self: *Image) void {
// self is %Self = OpTypePointer %Image Generic
asm volatile (
\\OpDoSomething %Image %self ...
:: [Image] "" (Image), [self] "" (self)
);
}
};
comptime {
asm (
\\%ActualImage = OpTypeImage ...
// Replaces all uses of %Image with %ActualImage, then deletes the %Image declaration from the module.
\\OpZigReplaceAllUses %Image %ActualImage
:: [Image] "" (Image)
);
} The main advantage of this is that we can also create non-opaque types should we need it. Its also easier to implement, and doesn't require any language extensions. Just a temporary SPIR-V instruction that is removed after linking. It does, however, feel like a much bigger hack. |
Motivation
Currently, SPIR-V backend has no way distinguish decorated types (in SPIR-V, decoration instructions modifies types/variables/functions/etc attributes). for example, in the below code
A
andB
are the same type therefore the decoration inarrayStride
is written twice which produces an invalid module.Proposal
There are two most straightforward ways to fix this. either extending the zig syntax to allow something like
[3]stride(10) u32
, or using inline assembly to create opaque types.[3]stride(10) u32
is more pleasing of course, but as there are quite a lot of these decorations, extending the language for every one of them is a bad idea, and they may evolve over time as well. As for inline assembly, after discussions with @Snektron, we reached the conclusion that these types would semantically be an opaque type backed by the assembly written in a typed backend like SPIR-V. so the above example would become:You might have also noticed that the types are created inside a function. the reason is global assembly won't allow I/O but that should probably be discussed in another proposal.
Error Messages
The syntax is useless and the behavior is undefined for other backends so perhaps it should emit an error in any non-typed backend (all backends minus SPIR-V currently)
The text was updated successfully, but these errors were encountered: