[wgsl] remove fallthrough statement

also add support for default to be used with other case selectors
This commit is contained in:
teoxoy
2022-11-15 14:29:11 +01:00
committed by Jim Blandy
parent 8405e387d8
commit e05706bc48
10 changed files with 139 additions and 139 deletions

View File

@@ -880,25 +880,47 @@ impl<W: Write> Writer<W> {
};
let l2 = level.next();
if !cases.is_empty() {
for case in cases {
match case.value {
crate::SwitchValue::Integer(value) => {
writeln!(self.out, "{}case {}{}: {{", l2, value, type_postfix)?;
let mut new_case = true;
for case in cases {
if case.fall_through && !case.body.is_empty() {
// TODO: we could do the same workaround as we did for the HLSL backend
return Err(Error::Unimplemented(
"fall-through switch case block".into(),
));
}
match case.value {
crate::SwitchValue::Integer(value) => {
if new_case {
write!(self.out, "{}case ", l2)?;
}
crate::SwitchValue::Default => {
writeln!(self.out, "{}default: {{", l2)?;
write!(self.out, "{}{}", value, type_postfix)?;
}
crate::SwitchValue::Default => {
if new_case {
if case.fall_through {
write!(self.out, "{}case ", l2)?;
} else {
write!(self.out, "{}", l2)?;
}
}
write!(self.out, "default")?;
}
}
for sta in case.body.iter() {
self.write_stmt(module, sta, func_ctx, l2.next())?;
}
new_case = !case.fall_through;
if case.fall_through {
writeln!(self.out, "{}fallthrough;", l2.next())?;
}
if case.fall_through {
write!(self.out, ", ")?;
} else {
writeln!(self.out, ": {{")?;
}
for sta in case.body.iter() {
self.write_stmt(module, sta, func_ctx, l2.next())?;
}
if !case.fall_through {
writeln!(self.out, "{}}}", l2)?;
}
}

View File

@@ -1513,13 +1513,20 @@ impl Parser {
lexer.span_from(initial)
}
fn parse_switch_value<'a>(lexer: &mut Lexer<'a>, uint: bool) -> Result<i32, Error<'a>> {
let token_span = lexer.next();
match token_span.0 {
Token::Number(Ok(Number::U32(num))) if uint => Ok(num as i32),
Token::Number(Ok(Number::I32(num))) if !uint => Ok(num),
Token::Number(Err(e)) => Err(Error::BadNumber(token_span.1, e)),
_ => Err(Error::Unexpected(token_span.1, ExpectedToken::Integer)),
fn parse_switch_value<'a>(
lexer: &mut Lexer<'a>,
uint: bool,
) -> Result<crate::SwitchValue, Error<'a>> {
match lexer.next() {
(Token::Word("default"), _) => Ok(crate::SwitchValue::Default),
(Token::Number(Ok(Number::U32(num))), _) if uint => {
Ok(crate::SwitchValue::Integer(num as i32))
}
(Token::Number(Ok(Number::I32(num))), _) if !uint => {
Ok(crate::SwitchValue::Integer(num))
}
(Token::Number(Err(e)), span) => Err(Error::BadNumber(span, e)),
(_, span) => Err(Error::Unexpected(span, ExpectedToken::Integer)),
}
}
@@ -3576,34 +3583,6 @@ impl Parser {
Ok(())
}
fn parse_switch_case_body<'a, 'out>(
&mut self,
lexer: &mut Lexer<'a>,
mut context: StatementContext<'a, '_, 'out>,
) -> Result<(bool, crate::Block), Error<'a>> {
let mut body = crate::Block::new();
// Push a new lexical scope for the switch case body
context.symbol_table.push_scope();
lexer.expect(Token::Paren('{'))?;
let fall_through = loop {
// default statements
if lexer.skip(Token::Word("fallthrough")) {
lexer.expect(Token::Separator(';'))?;
lexer.expect(Token::Paren('}'))?;
break true;
}
if lexer.skip(Token::Paren('}')) {
break false;
}
self.parse_statement(lexer, context.reborrow(), &mut body, false)?;
};
// Pop the switch case body lexical scope
context.symbol_table.pop_scope();
Ok((fall_through, body))
}
fn parse_statement<'a, 'out>(
&mut self,
lexer: &mut Lexer<'a>,
@@ -3928,37 +3907,34 @@ impl Parser {
break value;
}
cases.push(crate::SwitchCase {
value: crate::SwitchValue::Integer(value),
value,
body: crate::Block::new(),
fall_through: true,
});
};
let (fall_through, body) =
self.parse_switch_case_body(lexer, context.reborrow())?;
let body =
self.parse_block(lexer, context.reborrow(), false)?;
cases.push(crate::SwitchCase {
value: crate::SwitchValue::Integer(value),
value,
body,
fall_through,
fall_through: false,
});
}
(Token::Word("default"), _) => {
lexer.skip(Token::Separator(':'));
let (fall_through, body) =
self.parse_switch_case_body(lexer, context.reborrow())?;
let body =
self.parse_block(lexer, context.reborrow(), false)?;
cases.push(crate::SwitchCase {
value: crate::SwitchValue::Default,
body,
fall_through,
fall_through: false,
});
}
(Token::Paren('}'), _) => break,
other => {
return Err(Error::Unexpected(
other.1,
ExpectedToken::SwitchItem,
))
(_, span) => {
return Err(Error::Unexpected(span, ExpectedToken::SwitchItem))
}
}
}

View File

@@ -249,8 +249,7 @@ fn parse_switch() {
var pos: f32;
switch (3) {
case 0, 1: { pos = 0.0; }
case 2: { pos = 1.0; fallthrough; }
case 3: {}
case 2: { pos = 1.0; }
default: { pos = 3.0; }
}
}
@@ -267,8 +266,7 @@ fn parse_switch_optional_colon_in_case() {
var pos: f32;
switch (3) {
case 0, 1 { pos = 0.0; }
case 2 { pos = 1.0; fallthrough; }
case 3 {}
case 2 { pos = 1.0; }
default { pos = 3.0; }
}
}
@@ -277,6 +275,23 @@ fn parse_switch_optional_colon_in_case() {
.unwrap();
}
#[test]
fn parse_switch_default_in_case() {
parse_str(
"
fn main() {
var pos: f32;
switch (3) {
case 0, 1: { pos = 0.0; }
case 2: {}
case default, 3: { pos = 3.0; }
}
}
",
)
.unwrap();
}
#[test]
fn parse_parentheses_switch() {
parse_str(

View File

@@ -22,15 +22,13 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
case 2: {
pos = 1;
}
case 3: {
case 3, 4: {
pos = 2;
fallthrough;
}
case 4: {
case 5: {
pos = 3;
fallthrough;
}
default: {
case default, 6: {
pos = 4;
}
}
@@ -54,7 +52,6 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
}
case 3: {
pos = 2;
fallthrough;
}
case 4: {}
default: {

View File

@@ -56,12 +56,16 @@ void main() {
pos = 1;
break;
case 3:
pos = 2;
/* fallthrough */
case 4:
pos = 2;
break;
case 5:
pos = 3;
/* fallthrough */
break;
default:
/* fallthrough */
case 6:
pos = 4;
break;
}
@@ -81,7 +85,7 @@ void main() {
return;
case 3:
pos = 2;
/* fallthrough */
return;
case 4:
return;
default:

View File

@@ -60,27 +60,30 @@ void main(uint3 global_id : SV_DispatchThreadID)
break;
}
case 3: {
{
}
{
pos = 2;
}
{
pos = 3;
}
{
pos = 4;
}
break;
}
case 4: {
pos = 2;
break;
}
case 5: {
pos = 3;
break;
}
default: {
{
pos = 3;
}
{
pos = 4;
}
break;
}
default: {
case 6: {
pos = 4;
break;
}
@@ -104,12 +107,8 @@ void main(uint3 global_id : SV_DispatchThreadID)
return;
}
case 3: {
{
pos = 2;
}
{
return;
}
pos = 2;
return;
}
case 4: {
return;

View File

@@ -69,12 +69,18 @@ kernel void main_(
break;
}
case 3: {
pos = 2;
}
case 4: {
pos = 2;
break;
}
case 5: {
pos = 3;
break;
}
default: {
}
case 6: {
pos = 4;
break;
}
@@ -99,6 +105,7 @@ kernel void main_(
}
case 3: {
pos = 2;
return;
}
case 4: {
return;

View File

@@ -1,7 +1,7 @@
; SPIR-V
; Version: 1.1
; Generator: rspirv
; Bound: 69
; Bound: 71
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@@ -92,7 +92,7 @@ OpBranch %50
%50 = OpLabel
%52 = OpLoad %4 %37
OpSelectionMerge %53 None
OpSwitch %52 %54 1 %55 2 %56 3 %57 4 %58
OpSwitch %52 %54 1 %55 2 %56 3 %57 4 %58 5 %59
%55 = OpLabel
OpStore %37 %5
OpBranch %53
@@ -100,39 +100,43 @@ OpBranch %53
OpStore %37 %3
OpBranch %53
%57 = OpLabel
OpStore %37 %6
OpBranch %58
%58 = OpLabel
OpStore %37 %6
OpBranch %53
%59 = OpLabel
OpStore %37 %7
OpBranch %54
OpBranch %53
%54 = OpLabel
OpBranch %60
%60 = OpLabel
OpStore %37 %8
OpBranch %53
%53 = OpLabel
OpSelectionMerge %59 None
OpSwitch %9 %60 0 %61
OpSelectionMerge %61 None
OpSwitch %9 %62 0 %63
%63 = OpLabel
OpBranch %61
%62 = OpLabel
OpBranch %61
%61 = OpLabel
OpBranch %59
%60 = OpLabel
OpBranch %59
%59 = OpLabel
%62 = OpLoad %4 %37
OpSelectionMerge %63 None
OpSwitch %62 %64 1 %65 2 %66 3 %67 4 %68
%65 = OpLabel
%64 = OpLoad %4 %37
OpSelectionMerge %65 None
OpSwitch %64 %66 1 %67 2 %68 3 %69 4 %70
%67 = OpLabel
OpStore %37 %5
OpBranch %63
%66 = OpLabel
OpBranch %65
%68 = OpLabel
OpStore %37 %3
OpReturn
%67 = OpLabel
%69 = OpLabel
OpStore %37 %6
OpBranch %68
%68 = OpLabel
OpReturn
%64 = OpLabel
%70 = OpLabel
OpReturn
%66 = OpLabel
OpStore %37 %7
OpReturn
%63 = OpLabel
%65 = OpLabel
OpReturn
OpFunctionEnd

View File

@@ -50,15 +50,13 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
case 2: {
pos = 1;
}
case 3: {
case 3, 4: {
pos = 2;
fallthrough;
}
case 4: {
case 5: {
pos = 3;
fallthrough;
}
default: {
case default, 6: {
pos = 4;
}
}
@@ -80,7 +78,7 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
}
case 3: {
pos = 2;
fallthrough;
return;
}
case 4: {
return;

View File

@@ -1370,28 +1370,6 @@ fn select() {
}
}
#[test]
fn last_case_falltrough() {
check_validation! {
"
fn test_falltrough() {
switch(0) {
default: {}
case 0: {
fallthrough;
}
}
}
":
Err(
naga::valid::ValidationError::Function {
source: naga::valid::FunctionError::LastCaseFallTrough,
..
},
)
}
}
#[test]
fn missing_default_case() {
check_validation! {