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

Set the bake count for loads back to 2 #6605

Closed
wants to merge 2 commits into from

Conversation

magcius
Copy link
Contributor

@magcius magcius commented Nov 24, 2024

Connections
Fixes #4349.

Description
This effectively reverts gfx-rs/naga#925. In the time since that PR was filed, WGSL's semantics of var and let were changed, and naga was updated as well. It seems this workaround is no longer necessary to fix the original reordering bug experienced.

I've put this branch on top of #6604 but only because of generated shader text conflicts.

Testing
It wasn't lol. There are no changes to test passing/failing for me, but you can see that the original test added is still there in tact.

ba6e67f#diff-35d9e1ad09eda0153ca42ac8a28ac2383f4dc01c5c4043f4dd4fb87f24ffadb6R182-R186

Checklist

  • Run cargo fmt.
  • Run taplo format.
  • Run cargo clippy. If applicable, add:
    • --target wasm32-unknown-unknown
    • --target wasm32-unknown-emscripten
  • Run cargo xtask test to run tests.
  • Add change to CHANGELOG.md. See simple instructions inside file.

We already lowered the function expression if it's a normal in argument; no need to do it again. This eliminates an unused variable and expression. With chained function calls, this could lead to a lot of waste.

There's still an extra unused expression in the case of an out/inout argument; ideally we'd remove these expressions, but it might be tricky.

Fixes gfx-rs#6602
This effectively reverts gfx-rs/naga#925. In the time since that PR was filed, WGSL's semantics of var and let were changed, and naga was updated as well. It seems this workaround is no longer necessary to fix the original reordering bug experienced.

Fixes gfx-rs#4349.

This is still a bit scary, so I've left it as a draft.
@jimblandy
Copy link
Member

jimblandy commented Nov 25, 2024

I don't think this is right.

For the most part, Naga backends just walk the statement tree, and generate code for expressions as they appear as statement operands. This generates natural-looking code.

But there are certain cases where this isn't good enough. For example:

var<private> x: u32 = 0;

fn f() -> u32 {
    x = 1;
    return 1000;
}

fn g() -> u32 {
    return x +f() + x;
}

The first call to g must return 1001: the first reference to x returns 0, f() returns 1000, and then the next reference to x returns 1.

Naga's handling of this is overly delicate but correct. The representation of g's body is basically the expressions:

0 = Load(x)
1 = CallResult
2 = Load(x)
3 = Add(0, 1)
4 = Add(3, 2)

and the statements:

Emit 0
Call(f, result 1)
Emit 1..4
Return 4

Any naive traversal of the Return statement's operand expression will produce something like x + temp + x, which is incorrect, because the two references to x will happen after the call, not one before and one after.

The Emit statements are meant to tell us exactly when each expression needs to be evaluated. But if we simply emit all expressions when they're visited by an Emit statement, we don't know exactly which ones are going to be used by other statements, versus which ones are merely subexpressions consumed by other expressions. So we would need to generate a temporary variable for every statement:

int temp0 = x;
int call_result_1 = f();
int temp2 = x
int temp3 = temp0 + call_result_1;
int temp4 = temp3 + temp2;

This would be correct, and basically what Tint does. But Naga wants to generate smaller and more legible output, like this:

int temp0 = x;
int call_result_1 = f();
int temp2 = x;
return temp0 + call_result_1 + temp2;

The 'baking' logic is supposed to identify exactly which expressions need temporaries, and let Naga generate ordinary nested expressions for everything else, integrated into the statements that actually need them, like the addition expressions in the return statement.

Any expression whose value is used more than once (generated only by let statements) needs to have its value saved in a temporary, so we don't repeat its text in each place that uses it.

Loads and ImageLoads need to be saved in temporaries, so that they are evaluated at the right time relative to side effects that could influence their value, like the call to f.

Raising the Load bake count to 2 means they're treated just like any other expression, which can't be right.

@magcius
Copy link
Contributor Author

magcius commented Nov 26, 2024

Yes, I think your analysis is correct, and this PR is invalid. It would be nice if we could have a slightly better heuristic so that we don't make temporaries for everything, because that hurts code size and readability, but that would require more sophistication than what's provided here.

@magcius magcius closed this Nov 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Many redundant assignments in produced shaders
2 participants