From dab932e8ce46eed20989baa2d52f206f97eaf17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Capucho?= Date: Sun, 12 Jun 2022 17:33:43 +0100 Subject: [PATCH] glsl-in: Fix last case falltrough and empty switch GLSL allows the last case of a switch statement to not have a `break` statement causing it to be marked as fall-trough, naga's IR on the other hand doesn't allow the last case to be fall-trough, this is fixed by force marking it in the glsl frontend as not fall-trough. GLSL also allows empty switch statements and without default cases, naga's IR requires there be a default case, this is fixed by adding an empty default case in the glsl frontend if no default case was present in the switch statement. --- src/front/glsl/parser/functions.rs | 25 +++++++++++++++ tests/in/glsl/statements.frag | 27 ++++++++++++++++ tests/out/wgsl/statements-frag.wgsl | 50 +++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 tests/in/glsl/statements.frag create mode 100644 tests/out/wgsl/statements-frag.wgsl diff --git a/src/front/glsl/parser/functions.rs b/src/front/glsl/parser/functions.rs index 8a9487917b..549b73045b 100644 --- a/src/front/glsl/parser/functions.rs +++ b/src/front/glsl/parser/functions.rs @@ -177,6 +177,8 @@ impl<'source> ParsingContext<'source> { ctx.emit_restart(body); let mut cases = Vec::new(); + // Track if any default case is present in the switch statement. + let mut default_present = false; self.expect(parser, TokenValue::LeftBrace)?; loop { @@ -215,6 +217,7 @@ impl<'source> ParsingContext<'source> { } TokenValue::Default => { self.bump(parser)?; + default_present = true; crate::SwitchValue::Default } TokenValue::RightBrace => { @@ -273,6 +276,28 @@ impl<'source> ParsingContext<'source> { meta.subsume(end_meta); + // GLSL allows the last case to not have any `break` statement, + // this would mark it as fall trough but naga's IR requires that + // the last case must not be fall trough, so we mark need to mark + // the last case as not fall trough always. + // + // NOTE: do not unwrap here since a switch statement isn't required + // to have any cases. + if let Some(case) = cases.last_mut() { + case.fall_through = false; + } + + // Add an empty default case in case non was present, this is needed because + // naga's IR requires that all switch statements must have a default case but + // GLSL doesn't require that, so we might need to add an empty default case. + if !default_present { + cases.push(SwitchCase { + value: crate::SwitchValue::Default, + body: Block::new(), + fall_through: false, + }) + } + body.push(Statement::Switch { selector, cases }, meta); meta diff --git a/tests/in/glsl/statements.frag b/tests/in/glsl/statements.frag new file mode 100644 index 0000000000..c9e276c87b --- /dev/null +++ b/tests/in/glsl/statements.frag @@ -0,0 +1,27 @@ +#version 460 core + +void switchEmpty(int a) { + switch (a) {} + + return; +} + +void switchNoDefault(int a) { + switch (a) { + case 0: + break; + } + + return; +} + +void switchNoLastBreak(int a) { + switch (a) { + default: + int b = a; + } + + return; +} + +void main() {} diff --git a/tests/out/wgsl/statements-frag.wgsl b/tests/out/wgsl/statements-frag.wgsl new file mode 100644 index 0000000000..b799959320 --- /dev/null +++ b/tests/out/wgsl/statements-frag.wgsl @@ -0,0 +1,50 @@ +fn switchEmpty(a: i32) { + var a_1: i32; + + a_1 = a; + let _e2 = a_1; + switch _e2 { + default: { + } + } + return; +} + +fn switchNoDefault(a_2: i32) { + var a_3: i32; + + a_3 = a_2; + let _e2 = a_3; + switch _e2 { + case 0: { + } + default: { + } + } + return; +} + +fn switchNoLastBreak(a_4: i32) { + var a_5: i32; + var b: i32; + + a_5 = a_4; + let _e2 = a_5; + switch _e2 { + default: { + let _e3 = a_5; + b = _e3; + } + } + return; +} + +fn main_1() { + return; +} + +@fragment +fn main() { + main_1(); + return; +}