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

wgsl: remove ignore, add phony-assignment #2127

Merged
merged 4 commits into from Oct 6, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
121 changes: 89 additions & 32 deletions wgsl/index.bs
Expand Up @@ -2014,7 +2014,7 @@ memory reference</dfn> is produced.
* if the loaded value is a vector, the value (0, 0, 0, x), where x is:
* 0, 1, or the maximum positive value for integer components
* 0.0 or 1.0 for floating-point components
[=assignment statement|Stores=] to an invalid reference may either:
[=statement/assignment|Stores=] to an invalid reference may either:
* store the value to any [=memory locations|memory location(s)=] of the
[[WebGPU#buffers|WebGPU buffer]] bound to the [=originating variable=]
* not be executed
Expand All @@ -2031,7 +2031,7 @@ References and pointers are distinguished by how they are used:
* The [=indirection=] operation (unary `*`) converts a pointer value to its corresponding reference value.
* A [=let declaration=] can be of pointer type, but not of reference type.
* A [=formal parameter=] can be of pointer type, but not of reference type.
* An [=assignment statement=] performs a [=write access=] to update the contents of memory via a reference, where:
* An [=statement/assignment=] statement performs a [=write access=] to update the contents of memory via a reference, where:
* The left-hand side of the assignment statement must be of reference type, with access mode [=access/write=] or [=access/read_write=].
* 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:
Expand Down Expand Up @@ -4829,25 +4829,35 @@ compound_statement

## Assignment Statement ## {#assignment}

An <dfn noexport>assignment statement</dfn> replaces the contents of a variable,
or a portion of a variable, with a new value.
An <dfn noexport dfn-for="statement">assignment</dfn> evaluates an expression,
and optionally stores it in memory (thus updating the contents of a variable).

The
expression to the left of the equals token is the <dfn noexport>left-hand side</dfn>,
<pre class='def'>
assignment_statement
: (unary_expression | UNDERSCORE) EQUAL short_circuit_or_expression
</pre>


The text to the left of the equals token is the <dfn noexport>left-hand side</dfn>,
and the
expression to the right of the equals token is the <dfn noexport>right-hand side</dfn>.

### Updating Assignment ### {#updating-assignment-section}

When the [=left-hand side=] of an assignment is an expression, the assignment is an <dfn noexport>updating assignment</dfn>:
The value of the right-hand side is written to the memory referenced by the left-hand side.

<table class='data'>
<thead>
<tr><th style="width:40%">Precondition<th>Statement<th>Description
</thead>
<tr algorithm="assignment">
<tr algorithm="updating assignment">
<td>|r|: ref<|SC|,|T|,|A|>,<br>
|A| is [=access/write=] or [=access/read_write=]<br>
|e|: |T|,<br>
|T| is a [=constructible=] type,<br>
|SC| is a writable [=storage class=]
<td class="nowrap">|r| = |e|;
<td class="nowrap">|r| = |e|
<td>Evaluates |e|, evaluates |r|, then writes the value computed for |e| into
the [=memory locations=] referenced by |r|.

Expand All @@ -4858,8 +4868,8 @@ expression to the right of the equals token is the <dfn noexport>right-hand side
(OpStore)
</table>

In the simplest case, the left hand side of the assignment statement is the
name of a variable. See [[#forming-references-and-pointers]] for other cases.
In the simplest case, the left hand side is the name of a variable.
See [[#forming-references-and-pointers]] for other cases.

<div class='example wgsl' heading='Assignments'>
<xmp highlight='rust'>
Expand Down Expand Up @@ -4888,13 +4898,74 @@ name of a variable. See [[#forming-references-and-pointers]] for other cases.
</xmp>
</div>

<pre class='def'>
assignment_statement
: unary_expression EQUAL short_circuit_or_expression
If unary_expression is a variable, this maps to OpStore to the variable.
Otherwise, unary expression is a pointer expression in an Assigning (L-value) context
which maps to OpAccessChain followed by OpStore
</pre>
### Phony Assignment ### {#phony-assignment-section}

When the [=left-hand side=] of an assignment is an underscore token,
the assignment is an <dfn noexport>phony assignment</dfn>:
The right-hand side is evaluated, and then ignored.

<table class='data'>
<thead>
<tr><th>Precondition<th>Statement<th>Description
</thead>
<tr algorithm="phony-assignment">
<td>|e|: |T|,<br>
|T| is [=constructible=], a [=pointer type=], a [=texture=] type, or a [=sampler=] type
<td class="nowrap">_ = |e|
<td>Evaluates |e|.

Note: The resulting value is not stored.
The `_` token is not an identifier, and therefore cannot be used in an expression.
</table>

A phony-assignment is useful for:
* Calling a function that returns a value, but clearly expressing that the resulting value
is not needed.
* [=statically accessed|Statically accessing=] a variable, thus establishing it as a part of
the [=resource interface of a shader|shader's resource interface=].

Note: A buffer variable's store type may not be constructible, e.g. it contains an atomic type, or a runtime-sized array.
In these cases, use a pointer to the variable's contents instead.

<div class='example wgsl global-scope' heading='Using phony-assignment to throw away an un-needed function result'>
<xmp highlight=rust>
var<private> counter: i32;

fn increment_and_yield_previous() -> i32 {
let previous = counter;
counter = counter + 1;
return previous;
}

fn user() {
// Increment the counter, but don't use the result.
_ = increment_and_yield_previous();
}
</xmp>
</div>


<div class='example wgsl global-scope' heading='Using phony-assignment to occupy bindings without using them'>
<xmp highlight=rust>
[[block]] struct BufferContents {
counter: atomic<u32>;
data: array<vec4<f32>>;
};
[[group(0),binding(0)]] var<storage> buf: BufferContents;
[[group(0),binding(1)]] var t: texture_2d<f32>;
[[group(0),binding(2)]] var s: sampler;

[[stage(fragment)]]
fn shade_it() -> [[location(0)]] vec4<f32> {
// Declare that buf, t, and s are part of the shader interface, without
// using them for anything.
_ = &buf;
_ = t;
_ = s;
return vec4<f32>();
}
</xmp>
</div>

## Control flow TODO ## {#control-flow}

Expand Down Expand Up @@ -6686,6 +6757,7 @@ A <dfn>syntactic token</dfn> is a sequence of special characters, used:
<tr><td>`SEMICOLON`<td>`;`
<tr><td>`STAR`<td>`*`
<tr><td>`TILDE`<td>`~`
<tr><td>`UNDERSCORE`<td>`_`
<tr><td>`XOR`<td>`^`
</table>

Expand Down Expand Up @@ -8279,21 +8351,6 @@ TODO: Add links to the eventual memory model.
</xmp>
</div>

## Value-steering functions ## {#value-steering-functions}

<table class='data'>
<thead>
<tr><th>Conclusion<td>Notes
</thead>
<tr algorithm="compute a value then ignore it">
<td class="nowrap">
`ignore`(|e|: |T|)
<td>Evaluates |e|, and then ignores the result.<br>
Type |T| is any type that is valid as a function parameter.

Note: An argument to `ignore()` cannot have an atomic or runtime-sized array type, but pointers to these types can be used.
</table>


# MATERIAL TO BE MOVED TO A NEW HOME OR DELETED # {#junkyard}

Expand Down