-
Notifications
You must be signed in to change notification settings - Fork 353
WGSL: describe ref ptr #1569
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
WGSL: describe ref ptr #1569
Conversation
wgsl/index.bs
Outdated
| </pre> | ||
|
|
||
| ## Assignment TODO ## {#assignment} | ||
| ## Assignment ## {#assignment} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, I haven't revisited this part since the original #1368 PR
wgsl/index.bs
Outdated
| * The left-hand side of the assignment statement must be of reference type. | ||
| * The right-hand side of the assignment statement must evaluate to the store type of the left-hand side. | ||
| * The <dfn noexport>Load Rule</dfn>: Inside a function, a reference is automatically dereferenced (read from) to satisfy type rules: | ||
| * In a functio, when a reference expression |r| with store type |T| is used in a statement or an expression, where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function
|
I've rebased, and I think have addressed feedback from @alan-baker and @ben-clayton |
alan-baker
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the symmetric pointer operations on . and [] will come in a subsequent PR?
| <tr algorithm="assignment"> | ||
| <td>|r| : ref<|SC|,|T|>,<br> | ||
| |e| : |T|,<br> | ||
| |T| is [=storable=],<br> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and writable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah. this would be "does not have access(read)"
But if it's writing to a part of a storage buffer, it's really talking about the store type of the whole buffer, and that type may include |T|.
Basically, this shows that having access attribute on type is broken. It belongs on the originating variable.
I'll add a TODO for this. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a validation statement immediately after this table:
The [=originating variable=] of the left-hand side must not have an
access(read)access attribute.
But it's really the store type of the originating variable....
|
Discussed in 2021-03-30 meeting
|
WGSL meeting minutes 2021-03-30
|
kvark
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is well-written, thank you!
My main concern about this is inclusion of references in the type system. In theory, we can attempt to express the constraints in either:
- the grammar - #1549, with something like an "addressable_expression" and "pointer_expression"
- the type system - this PR #1569
- neither - just express in words what expressions are assignable, and what can be taken a pointer of.
The downside of going with the type system is that it may not be well-suited to describe this. For example, the approach goes in a bit of conflict with "every expression has a type" rule that we wanted to preserve from a while ago. With this PR, an expression of type ref<X, Y> will go under "Load Rule" and be implicitly converted into X, based on the context...
I'd be more confident accepting this if we at least attempt to see how it would look like outside of the type system, to see if it's feasible, and what the trade-offs are going to look like.
Marking as "Request changes" so that it doesn't get accidentally merged until we properly discuss this. The PR is being rushed a little bit (not even reached the homework deadline), even if I understand the circumstances.
|
|
||
| Note: Pointers are not storable. | ||
| Reference types and pointer types are both sets of memory views: | ||
| a particular memory view is associated with a unique reference value and also a unique pointer value: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't compare pointer values, so does it mean anything to say "unique" here?
It's also unclear if the pointers would be unique if we could compare them, theoretically (i.e.&s.first_member == &s).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're not talking about a comparison being done in WGSL itself, but by the (mathematical) definition of memory views.
A particular "memory view" is a mathematical object that corresponds to two WGSL values: a reference value and a pointer value. Then use duck-uniqueness: if two memory views have the same memory locations and same WGSL interpretation type, then they are the same memory views.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, the colon at the end of that sentence points calls out the block-quote, which ends with " .... where p and r describe the same memory view". I think that's clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I don't get this still. You are saying that this talking about unique memory views, but what is written here is "unique reference value" and "unique pointer value".
Would it be possible to reword this to avoid ambiguity?
| * The right-hand side of the assignment statement must evaluate to the store type of the left-hand side. | ||
| * The <dfn noexport>Load Rule</dfn>: Inside a function, a reference is automatically dereferenced (read from) to satisfy type rules: | ||
| * In a function, when a reference expression |r| with store type |T| is used in a statement or an expression, where | ||
| * The only potentially matching type rules require |r| to have a value of type |T|, then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the scariest part of the PR, which highlights the complexity associated with trying to represent the references with the type system. Just wanted to pin it here for attention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is being honest about when memory is read from a variable's storage.
We need a precise statement like this so we can clearly talk about a memory model, particularly in the presence of multiple invocations executing concurrently.
Regardless of whether we support pointers or references, the spec is missing rules about what operations perform memory accesses. It needs this level of precision.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. As mentioned on the office hours call, it's great to have this explicitly stated in the spec.
What's not clear (and is concerning) is whether having it as a separate type (generic type) is the best way to express this, since it effectively becomes an implicit cast, the first of a kind in WGSL. And implicit casts are one of the things making the type system weaker. There are many sources that describe this, e.g. this one:
The more type coercions (implicit conversions) for built-in operators the language offers, the weaker the typing. (This could also be viewed as more built-in overloading of built-in operators.)
alan-baker
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
That's a non-starter, because "identifier" is deep inside both of them. But identifiers can represent a reference value or a pointer value. You eventually are going to need the type system to kick in. |
- Add "memory view types" section - Defines reference type and pointer type - gives use cases and examples - Compares to other lanaguages - Adds: - composite reference sub-expressions - address-of expression (unary &) - indirection expression (unary *) - variable identifier expression - const identifier expression - formal parmaeter identifier expression TODO: grammar update for unary * and unary & Alternate to gpuweb#1368 Fixes: gpuweb#1456
Addressed feedback from @alan-baker and @ben-clayton Fixed typos, examples, links, and added an example showing what happens when the expression in a return statement is a reference.
- Added the grammar rule for address-of and indirection - Fixed algorithm name text (was copypasta) - Fixed example in the assignment-statement section.
Improve cross-linking.
Applies feedback from @kvark review. Using a complete and valid function definition allows the example to be valid WGSL. - changed the pointer-to-uniform example to pointer-to-function, because pointer-to-uniform arguments won't be valid. (Sorry, that's a restriction from baseline SPIR-V in Vulkan restriction.)
That was pulled out to gpuweb#1586
|
Rebased, fixed conflicts (with the 'let' commit that landed in the meantime). Addressed non-controverisal feedback from @kvark. |
|
I peeked at C11 (draft). From what I can gather quickly:
Observations so far:
So far we see C has a strong orientation to storing things in memory. But for a shader language we want to have values that are never possible to store, particularly pointers. So that is a desired difference. At least, if you want pointer expressions, and all expressions to have types. The next interesting bit is 6.5.16.1 "Simple assignment"
Let's parse that.
The memory consistency model is 5.1.2.4 "Multi-threaded executions and data races". I'll stop there. |
|
@dneto0 I'm going to re-review the PR shortly, thank you for addressing my concerns! Also, thank you for the extensive analysis of the C spec!
To be fair, we are trying to have a system where it might be possible to store pointers at some point in the future. On the important footnote:
This leads us to the idea of having "type qualifiers". A "reference" would be a qualifier on the type. It doesn't have to participate in the "main" type checking pass, but we could have a separate place where we say that:
Sounds not very complicated to me. Am I missing anything? I think the idea of type qualifiers is also needed for #1534, where we could say that the "access" and "stride" are the type qualifiers. |
WGSL meeting minutes 2021-04-06
|
|
Resolution from 2021-04-06 is to let this rest for a day. During offline discussion, the group revisited whether/how read/read-write access qualifier into the type system. Agreed to land this. (including @kvark ) |
This change implements pointers and references as described by the WGSL specification change in gpuweb/gpuweb#1569. reader/spirv: * Now emits address-of `&expr` and indirection `*expr` operators as needed. * As an identifier may now resolve to a pointer or reference type depending on whether the declaration is a `var`, `let` or parameter, `Function::identifier_values_` has been changed from an ID set to an ID -> Type* map. resolver: * Now correctly resolves all expressions to either a value type, reference type or pointer type. * Validates pointer / reference rules on assignment, `var` and `let` construction, and usage. * Handles the address-of and indirection operators. * No longer does any implicit loads of pointer types. * Storage class validation is still TODO (crbug.com/tint/809) writer/spirv: * Correctly handles variables and expressions of pointer and reference types, emitting OpLoads where necessary. test: * Lots of new test cases Fixed: tint:727 Change-Id: I77d3281590e35e5a3122f5b74cdeb71a6fe51f74 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50740 Commit-Queue: Ben Clayton <[email protected]> Kokoro: Kokoro <[email protected]> Reviewed-by: David Neto <[email protected]>
Alternate to #1368
Fixes: #1456
Builds on #1568 (rename "value types" to "plain types")