Skip to content
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

Capability computation UX #42

Closed
khyperia opened this issue Oct 1, 2020 · 3 comments · Fixed by #630
Closed

Capability computation UX #42

khyperia opened this issue Oct 1, 2020 · 3 comments · Fixed by #630
Labels
t: design Design of our rust-gpu language and std

Comments

@khyperia
Copy link
Contributor

khyperia commented Oct 1, 2020

Design and implement what I've been calling "capability computation":

  1. Let the user specify what capabilities to allow. Exactly how they do it is open right now - e.g. attributes, or just a -C target-feature temp hack.
  2. Validate those capabilities are correct. Error on missing capability, warning on not-needed capability?

Note validation is surprisingly complex, e.g. some capabilities say "you can't opbitcast this particular type to that particular type", it's not just simple "this instruction is/isn't allowed" rules.

@Jasper-Bekkers is working on part 2 right now.

@khyperia
Copy link
Contributor Author

khyperia commented Mar 22, 2021

I really like the system that @XAMPPRocky came up with, although there's a chunk of bikeshedding left to do. The system goes something roughly like this:

  1. Functions that require capabilities declare that they need specific capabilities:
    #[spirv(needs_capability = "DerivativeControl")]
    fn derivative(x: f32) -> f32 { ... }
  2. End-user modules (the crate that builds a binary, not an rlib) declare that they have capabilities:
    #![spirv(declare_capability = "DerivativeControl")]
  3. If a module uses a function that needs_capability that it does not declare_capability, an error occurs ("ya need to add declare_capability = "blah" to your module", etc.)
  4. The capabilities declared by declare_capability (and only those capabilities) are emitted to the SPIR-V binary.

This prevents issues like #468 being extremely confusing - if you accidentally use some function (in the case of #468, deep within a library) that needs_capability = Int64 (perhaps functions using u64 are automatically declared with needs_capability = Int64 implicitly, to avoid needing to modify libraries), then you get a compiler error, rather than silently adding OpCapibility Int64 to your module.

Bikesheddy questions:

  1. If a() calls b() calls c(), and c has #[spirv(needs_capability = "blah")], does b also need to declare needs_capability = "blah"? It's annoying to do so, but would be more clear.
  2. needs_capability and declare_capability and the = syntax are temporary placeholders, what should they actually be?
  3. What happens if you declare_capability something that isn't used? (IMO this is fine, no harm comes out of it - a warning might be nice)
  4. What happens if you use a capability (in asm! or something) but don't needs_capability? (IMO the validator will barf on it, writing our own validator is too difficult)

@XAMPPRocky
Copy link
Member

XAMPPRocky commented Mar 22, 2021

For declaring capabilities I was thinking more about it and I think it could be good if we attached the declaring of capabilities to entrypoint functions. That way if you use cfg to remove that entrypoint, you cfg out all of the capabilities it uses as well.

#[spirv(fragment)]
#[spirv(capabilities(kernel))]
pub fn main() {}

@khyperia
Copy link
Contributor Author

Hmm, in the SPIR-V, they're part of the module, not entry point, so there's potentially weird cases. For example:

  1. Entry point A uses a function that improperly did not declare needs_capability
  2. Entry point B declares that same capability, which applies to the module, and makes entry point A silently work
  3. Entry point B is removed, suddenly A doesn't work anymore

but that's a pretty esoteric weird case that's easily resolved, and I think I agree with you that declaring them on the entry point would be the way to go (it also handily solves the "what if a library does #![declares_capability]" issue).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
t: design Design of our rust-gpu language and std
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants