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.
This commit is contained in:
João Capucho
2022-06-12 17:33:43 +01:00
parent 52bb25179b
commit dab932e8ce
3 changed files with 102 additions and 0 deletions

View File

@@ -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

View File

@@ -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() {}

View File

@@ -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;
}