-
Notifications
You must be signed in to change notification settings - Fork 993
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
Mistranslation of loop
with continuing
block
#4558
Comments
continuing
block
Ah, I think I see what the logic is supposed to do - maybe a low-hanging fruit would be something like this? diff --git a/src/back/msl/writer.rs b/src/back/msl/writer.rs
index cfef6645..30df421e 100644
--- a/src/back/msl/writer.rs
+++ b/src/back/msl/writer.rs
@@ -2536,6 +2536,7 @@ impl<W: Write> Writer<W> {
level: back::Level,
statements: &[crate::Statement],
context: &StatementContext,
+ with_scope: impl FnOnce(&mut Self) -> BackendResult
) -> BackendResult {
// Add to the set in order to track the stack size.
#[cfg(test)]
@@ -2685,14 +2686,19 @@ impl<W: Write> Writer<W> {
let lif = level.next();
let lcontinuing = lif.next();
writeln!(self.out, "{lif}if (!{gate_name}) {{")?;
- self.put_block(lcontinuing, continuing, context)?;
- if let Some(condition) = break_if {
- write!(self.out, "{lcontinuing}if (")?;
- self.put_expression(condition, &context.expression, true)?;
- writeln!(self.out, ") {{")?;
- writeln!(self.out, "{}break;", lcontinuing.next())?;
- writeln!(self.out, "{lcontinuing}}}")?;
- }
+
+ self.put_block(lcontinuing, continuing, context, |this| {
+ if let Some(condition) = break_if {
+ write!(this.out, "{lcontinuing}if (")?;
+ this.put_expression(condition, &context.expression, true)?;
+ writeln!(this.out, ") {{")?;
+ writeln!(this.out, "{}break;", lcontinuing.next())?;
+ writeln!(this.out, "{lcontinuing}}}")?;
+ }
+
+ Ok(())
+ })?;
+
writeln!(self.out, "{lif}}}")?;
writeln!(self.out, "{lif}{gate_name} = false;")?;
} else {
@@ -2952,6 +2958,8 @@ impl<W: Write> Writer<W> {
}
}
+ with_scope()?;
+
// un-emit expressions
//TODO: take care of loop/continuing?
for statement in statements { |
Thanks for the report!
It doesn't seem so. diff --git a/t.metal b/t2.metal
index 14e5c6b0..672badfc 100644
--- a/t.metal
+++ b/t2.metal
@@ -19,7 +19,7 @@ void function(
bool unnamed = !(((phi_79_ < 8) ? true : false));
phi_79_ = phi_89_;
bool unnamed_1 = !(((phi_79_ < 8) ? true : false));
- if (!(((phi_79_ < 8) ? true : false))) {
+ if (unnamed_1) {
break;
}
} |
It looks like the HLSL and GLSL backends have the same issue since they all use the same strategy. The SPIR-V backend seems to be behaving properly. |
Whoops, my bad - I've been actually checking conversion from spv (attached below) into msl which does get fixed by commenting that line - but yeah, going spv -> wgsl -> msl remains broken 🤔
fwiw, I've been able to temporarily fix this issue by doing Patryk27/naga@fdcdb4f - though it feels more like a band-aid (plus it should probably call |
continuing
blockloop
with continuing
block
@Patryk27 If you're feeding Naga SPIR-V as input, we recently did some work on the translation of SPIR-V with continuing blocks in gfx-rs/naga#2290. It might be worth dumping the Naga IR (use the cli and ask for a |
@jimblandy: yeah, I saw that - when it comes to bugs, I'm always testing on That being said, it takes a moment to decode how those emits and loops come together, so I'm not really sure whether the output is correct or not - if you'd like to take a look, here it is: |
I do not understand why AIUI it was only added to WGSL to represent SPIR-V conditional backedges. That is, |
@eddyb Agreed - could you file an issue to that effect? |
|
Simpler repro: fn main() {
var a = 0;
loop {
let cmp = a < 8;
if cmp {
a += 1;
}
continuing {
break if cmp;
}
}
} ... gets converted into (invalid): // language: metal1.0
#include <metal_stdlib>
#include <simd/simd.h>
using metal::uint;
void main_(
) {
int a = 0;
bool loop_init = true;
while(true) {
if (!loop_init) {
if (a < 8) { // aii aii
break;
}
}
loop_init = false;
int _e2 = a;
bool cmp = _e2 < 8;
if (cmp) {
int _e6 = a;
a = _e6 + 1;
}
}
return;
} |
Curiously, using fn main() {
var a = 0;
loop {
var cmp = a < 8;
a += 1;
continuing {
break if cmp;
}
}
} ... gets transformed into: // language: metal1.0
#include <metal_stdlib>
#include <simd/simd.h>
using metal::uint;
void main_(
) {
int a = 0;
bool cmp = {};
bool loop_init = true;
while(true) {
if (!loop_init) {
bool _e9 = cmp;
if (cmp) {
break;
}
}
loop_init = false;
int _e2 = a;
cmp = _e2 < 8;
int _e7 = a;
a = _e7 + 1;
}
return;
} |
Also, it's possible to crash the codegen as well 👀 fn main() {
loop {
let cmp = magic();
continuing {
break if cmp;
}
}
}
fn magic() -> bool {
return true;
}
|
Following the discussion in #4982 which seems to be a duplicate of this: This is actually an issue with the WGSL frontend. |
Note that my original bug happens when going directly from spv to msl as well (I just posted wgsl, 'cause I thought it might be easier to debug) - right now I think there's two bugs, actually:
|
I see, reopening. |
Alright, the main culprit seems to be this part: wgpu/naga/src/front/wgsl/lower/mod.rs Line 1158 in 376d901
... which paired with: wgpu/naga/src/front/wgsl/lower/mod.rs Line 1545 in 376d901
... causes it to essentially copy-paste the Perhaps a solution here could be to treat both Currently it looks like there's some special logic in a few places, which seems to treat edit: on a second thought, this pertains the wgsl frontend only, while the issue is present when going directly from spv as well, so the actual bug must be somewhere else. |
Hi,
Converting this wgsl:
... yields an invalid msl:
... with a pretty subtle mistake related to the
if (!loop_init)
part:Note that it uses
phi_79_
with value after the assignment, instead of using the value from-before the assignment, which causes this shader to be effectively an infinite loop (later optimized out by Metal Shader Compiler into a no-op, apparently).I've narrowed down the issue to this place:
https://github.com/gfx-rs/naga/blob/b7f4006e46313da063f8f2f930230767c9740239/src/back/msl/writer.rs#L2960
... which I'm not sure what is supposed to do, but just commenting-out
self.named_expressions.remove(&handle);
generates correct code 👀The text was updated successfully, but these errors were encountered: