diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d6c62893b..36ad63c4a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -200,6 +200,7 @@ By @Vecvec in [#6905](https://github.com/gfx-rs/wgpu/pull/6905), [#7086](https:/ - Allow template lists to have a trailing comma. By @KentSlaney in [#7142](https://github.com/gfx-rs/wgpu/pull/7142). - Allow WGSL const declarations to have abstract types. By @jamienicol in [#7055](https://github.com/gfx-rs/wgpu/pull/7055) and [#7222](https://github.com/gfx-rs/wgpu/pull/7222). - Allows override-sized arrays to resolve to the same size without causing the type arena to panic. By @KentSlaney in [#7082](https://github.com/gfx-rs/wgpu/pull/7082). +- Allow abstract types to be used for WGSL switch statement selector and case selector expressions. By @jamienicol in [#7250](https://github.com/gfx-rs/wgpu/pull/7250). #### General diff --git a/naga/src/front/wgsl/error.rs b/naga/src/front/wgsl/error.rs index de45cd2812..6bbf9f476c 100644 --- a/naga/src/front/wgsl/error.rs +++ b/naga/src/front/wgsl/error.rs @@ -256,8 +256,13 @@ pub(crate) enum Error<'a> { /// the same identifier as `ident`, above. path: Box<[(Span, Span)]>, }, - InvalidSwitchValue { - uint: bool, + InvalidSwitchSelector { + span: Span, + }, + InvalidSwitchCase { + span: Span, + }, + SwitchCaseTypeMismatch { span: Span, }, CalledEntryPoint(Span), @@ -772,26 +777,32 @@ impl<'a> Error<'a> { .collect(), notes: vec![], }, - Error::InvalidSwitchValue { uint, span } => ParseError { - message: "invalid switch value".to_string(), + Error::InvalidSwitchSelector { span } => ParseError { + message: "invalid `switch` selector".to_string(), labels: vec![( span, - if uint { - "expected unsigned integer" - } else { - "expected signed integer" - } + "`switch` selector must be a scalar integer" .into(), )], - notes: vec![if uint { - format!("suffix the integer with a `u`: `{}u`", &source[span]) - } else { - let span = span.to_range().unwrap(); - format!( - "remove the `u` suffix: `{}`", - &source[span.start..span.end - 1] - ) - }], + notes: vec![], + }, + Error::InvalidSwitchCase { span } => ParseError { + message: "invalid `switch` case selector value".to_string(), + labels: vec![( + span, + "`switch` case selector must be a scalar integer const expression" + .into(), + )], + notes: vec![], + }, + Error::SwitchCaseTypeMismatch { span } => ParseError { + message: "invalid `switch` case selector value".to_string(), + labels: vec![( + span, + "`switch` case selector must have the same type as the `switch` selector expression" + .into(), + )], + notes: vec![], }, Error::CalledEntryPoint(span) => ParseError { message: "entry point cannot be called".to_string(), diff --git a/naga/src/front/wgsl/lower/mod.rs b/naga/src/front/wgsl/lower/mod.rs index 385a59c5b0..96032f8268 100644 --- a/naga/src/front/wgsl/lower/mod.rs +++ b/naga/src/front/wgsl/lower/mod.rs @@ -1630,12 +1630,53 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { emitter.start(&ctx.function.expressions); let mut ectx = ctx.as_expression(block, &mut emitter); - let selector = self.expression(selector, &mut ectx)?; - let uint = - resolve_inner!(ectx, selector).scalar_kind() == Some(crate::ScalarKind::Uint); + // Determine the scalar type of the selector and case expressions, find the + // consensus type for automatic conversion, then convert them. + let (mut exprs, spans) = core::iter::once(selector) + .chain(cases.iter().filter_map(|case| match case.value { + ast::SwitchValue::Expr(expr) => Some(expr), + ast::SwitchValue::Default => None, + })) + .enumerate() + .map(|(i, expr)| { + let span = ectx.ast_expressions.get_span(expr); + let expr = self.expression_for_abstract(expr, &mut ectx)?; + let ty = resolve_inner!(ectx, expr); + match *ty { + crate::TypeInner::Scalar( + crate::Scalar::I32 + | crate::Scalar::U32 + | crate::Scalar::ABSTRACT_INT, + ) => Ok((expr, span)), + _ => match i { + 0 => Err(Error::InvalidSwitchSelector { span }), + _ => Err(Error::InvalidSwitchCase { span }), + }, + } + }) + .collect::, Vec<_>), _>>()?; + + let mut consensus = + ectx.automatic_conversion_consensus(&exprs) + .map_err(|span_idx| Error::SwitchCaseTypeMismatch { + span: spans[span_idx], + })?; + // Concretize to I32 if the selector and all cases were abstract + if consensus == crate::Scalar::ABSTRACT_INT { + consensus = crate::Scalar::I32; + } + for expr in &mut exprs { + ectx.convert_to_leaf_scalar(expr, consensus)?; + } + block.extend(emitter.finish(&ctx.function.expressions)); + let mut exprs = exprs.into_iter(); + let selector = exprs + .next() + .expect("First element should be selector expression"); + let cases = cases .iter() .map(|case| { @@ -1643,17 +1684,22 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { value: match case.value { ast::SwitchValue::Expr(expr) => { let span = ctx.ast_expressions.get_span(expr); - let expr = - self.expression(expr, &mut ctx.as_global().as_const())?; - match ctx.module.to_ctx().eval_expr_to_literal(expr) { - Some(crate::Literal::I32(value)) if !uint => { + let expr = exprs.next().expect( + "Should yield expression for each SwitchValue::Expr case", + ); + match ctx + .module + .to_ctx() + .eval_expr_to_literal_from(expr, &ctx.function.expressions) + { + Some(crate::Literal::I32(value)) => { crate::SwitchValue::I32(value) } - Some(crate::Literal::U32(value)) if uint => { + Some(crate::Literal::U32(value)) => { crate::SwitchValue::U32(value) } _ => { - return Err(Error::InvalidSwitchValue { uint, span }); + return Err(Error::InvalidSwitchCase { span }); } } } diff --git a/naga/src/front/wgsl/tests.rs b/naga/src/front/wgsl/tests.rs index c0a24fbdf7..a0e1d7a3cc 100644 --- a/naga/src/front/wgsl/tests.rs +++ b/naga/src/front/wgsl/tests.rs @@ -322,9 +322,9 @@ fn parse_parentheses_switch() { parse_str( " fn main() { - var pos: f32; - switch pos > 1.0 { - default: { pos = 3.0; } + var pos: i32; + switch pos + 1 { + default: { pos = 3; } } } ", diff --git a/naga/src/proc/mod.rs b/naga/src/proc/mod.rs index 44c76b911d..84b4d1af42 100644 --- a/naga/src/proc/mod.rs +++ b/naga/src/proc/mod.rs @@ -456,7 +456,7 @@ impl GlobalCtx<'_> { self.eval_expr_to_literal_from(handle, self.global_expressions) } - fn eval_expr_to_literal_from( + pub(super) fn eval_expr_to_literal_from( &self, handle: crate::Handle, arena: &crate::Arena, diff --git a/naga/tests/in/wgsl/control-flow.wgsl b/naga/tests/in/wgsl/control-flow.wgsl index 564f1ab2a5..1d5b45555e 100644 --- a/naga/tests/in/wgsl/control-flow.wgsl +++ b/naga/tests/in/wgsl/control-flow.wgsl @@ -79,6 +79,41 @@ fn switch_case_break() { return; } +fn switch_selector_type_conversion() { + switch (0u) { + case 0: { + } + default: { + } + } + + switch (0) { + case 0u: { + } + default: { + } + } +} + +const ONE = 1; +fn switch_const_expr_case_selectors() { + const TWO = 2; + switch (0) { + case i32(): { + } + case ONE: { + } + case TWO: { + } + case 1 + 2: { + } + case vec4(4).x: { + } + default: { + } + } +} + fn loop_switch_continue(x: i32) { loop { switch x { diff --git a/naga/tests/out/glsl/control-flow.main.Compute.glsl b/naga/tests/out/glsl/control-flow.main.Compute.glsl index 48f1bffa30..edf4093e53 100644 --- a/naga/tests/out/glsl/control-flow.main.Compute.glsl +++ b/naga/tests/out/glsl/control-flow.main.Compute.glsl @@ -24,6 +24,48 @@ void switch_case_break() { return; } +void switch_selector_type_conversion() { + switch(0u) { + case 0u: { + break; + } + default: { + break; + } + } + switch(0u) { + case 0u: { + return; + } + default: { + return; + } + } +} + +void switch_const_expr_case_selectors() { + switch(0) { + case 0: { + return; + } + case 1: { + return; + } + case 2: { + return; + } + case 3: { + return; + } + case 4: { + return; + } + default: { + return; + } + } +} + void loop_switch_continue(int x) { while(true) { switch(x) { diff --git a/naga/tests/out/hlsl/control-flow.hlsl b/naga/tests/out/hlsl/control-flow.hlsl index 19e4c8d2a2..396e6bb2c3 100644 --- a/naga/tests/out/hlsl/control-flow.hlsl +++ b/naga/tests/out/hlsl/control-flow.hlsl @@ -18,6 +18,50 @@ void switch_case_break() return; } +void switch_selector_type_conversion() +{ + switch(0u) { + case 0u: { + break; + } + default: { + break; + } + } + switch(0u) { + case 0u: { + return; + } + default: { + return; + } + } +} + +void switch_const_expr_case_selectors() +{ + switch(int(0)) { + case 0: { + return; + } + case 1: { + return; + } + case 2: { + return; + } + case 3: { + return; + } + case 4: { + return; + } + default: { + return; + } + } +} + void loop_switch_continue(int x) { uint2 loop_bound = uint2(0u, 0u); diff --git a/naga/tests/out/msl/control-flow.msl b/naga/tests/out/msl/control-flow.msl index eecf31fb9b..8c373aa8be 100644 --- a/naga/tests/out/msl/control-flow.msl +++ b/naga/tests/out/msl/control-flow.msl @@ -28,6 +28,50 @@ void switch_case_break( return; } +void switch_selector_type_conversion( +) { + switch(0u) { + case 0u: { + break; + } + default: { + break; + } + } + switch(0u) { + case 0u: { + return; + } + default: { + return; + } + } +} + +void switch_const_expr_case_selectors( +) { + switch(0) { + case 0: { + return; + } + case 1: { + return; + } + case 2: { + return; + } + case 3: { + return; + } + case 4: { + return; + } + default: { + return; + } + } +} + void loop_switch_continue( int x ) { diff --git a/naga/tests/out/spv/control-flow.spvasm b/naga/tests/out/spv/control-flow.spvasm index a2d6dc070e..d9db923910 100644 --- a/naga/tests/out/spv/control-flow.spvasm +++ b/naga/tests/out/spv/control-flow.spvasm @@ -1,13 +1,13 @@ ; SPIR-V ; Version: 1.1 ; Generator: rspirv -; Bound: 208 +; Bound: 227 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -OpEntryPoint GLCompute %179 "main" %176 -OpExecutionMode %179 LocalSize 1 1 1 -OpDecorate %176 BuiltIn GlobalInvocationId +OpEntryPoint GLCompute %198 "main" %195 +OpExecutionMode %198 LocalSize 1 1 1 +OpDecorate %195 BuiltIn GlobalInvocationId %2 = OpTypeVoid %4 = OpTypeInt 32 0 %3 = OpTypeVector %4 3 @@ -15,29 +15,29 @@ OpDecorate %176 BuiltIn GlobalInvocationId %9 = OpTypeFunction %2 %5 %15 = OpTypeFunction %2 %16 = OpConstant %5 0 -%29 = OpTypeVector %4 2 -%30 = OpTypePointer Function %29 -%31 = OpTypeBool -%32 = OpTypeVector %31 2 -%33 = OpConstant %4 0 -%34 = OpConstantComposite %29 %33 %33 -%35 = OpConstant %4 1 -%36 = OpConstant %4 4294967295 -%37 = OpConstantComposite %29 %36 %36 -%57 = OpTypeFunction %2 %5 %5 %5 -%126 = OpTypeFunction %2 %5 %5 %5 %5 -%127 = OpConstant %5 1 -%128 = OpConstant %5 2 -%130 = OpTypePointer Function %5 -%177 = OpTypePointer Input %3 -%176 = OpVariable %177 Input -%180 = OpConstant %5 3 -%181 = OpConstant %5 4 -%183 = OpConstantNull %5 -%185 = OpConstant %4 2 -%186 = OpConstant %4 72 -%187 = OpConstant %4 264 -%188 = OpConstant %4 2056 +%23 = OpConstant %4 0 +%49 = OpTypeVector %4 2 +%50 = OpTypePointer Function %49 +%51 = OpTypeBool +%52 = OpTypeVector %51 2 +%53 = OpConstantComposite %49 %23 %23 +%54 = OpConstant %4 1 +%55 = OpConstant %4 4294967295 +%56 = OpConstantComposite %49 %55 %55 +%76 = OpTypeFunction %2 %5 %5 %5 +%145 = OpTypeFunction %2 %5 %5 %5 %5 +%146 = OpConstant %5 1 +%147 = OpConstant %5 2 +%149 = OpTypePointer Function %5 +%196 = OpTypePointer Input %3 +%195 = OpVariable %196 Input +%199 = OpConstant %5 3 +%200 = OpConstant %5 4 +%202 = OpConstantNull %5 +%204 = OpConstant %4 2 +%205 = OpConstant %4 72 +%206 = OpConstant %4 264 +%207 = OpConstant %4 2056 %8 = OpFunction %2 None %9 %7 = OpFunctionParameter %5 %6 = OpLabel @@ -63,312 +63,353 @@ OpBranch %18 %18 = OpLabel OpReturn OpFunctionEnd -%23 = OpFunction %2 None %9 -%22 = OpFunctionParameter %5 +%22 = OpFunction %2 None %15 %21 = OpLabel -%38 = OpVariable %30 Function %34 OpBranch %24 %24 = OpLabel +OpSelectionMerge %25 None +OpSwitch %23 %27 0 %26 +%26 = OpLabel +OpBranch %25 +%27 = OpLabel OpBranch %25 %25 = OpLabel -OpLoopMerge %26 %28 None -OpBranch %39 -%39 = OpLabel -%40 = OpLoad %29 %38 -%41 = OpIEqual %32 %37 %40 -%42 = OpAll %31 %41 -OpSelectionMerge %43 None -OpBranchConditional %42 %26 %43 -%43 = OpLabel -%44 = OpCompositeExtract %4 %40 1 -%45 = OpIEqual %31 %44 %36 -%46 = OpSelect %4 %45 %35 %33 -%47 = OpCompositeConstruct %29 %46 %35 -%48 = OpIAdd %29 %40 %47 -OpStore %38 %48 -OpBranch %27 -%27 = OpLabel -OpSelectionMerge %49 None -OpSwitch %22 %51 1 %50 -%50 = OpLabel -OpBranch %28 -%51 = OpLabel -OpBranch %49 -%49 = OpLabel -OpBranch %28 +OpSelectionMerge %28 None +OpSwitch %23 %30 0 %29 +%29 = OpLabel +OpReturn +%30 = OpLabel +OpReturn %28 = OpLabel -OpBranch %25 -%26 = OpLabel OpReturn OpFunctionEnd -%56 = OpFunction %2 None %57 -%53 = OpFunctionParameter %5 -%54 = OpFunctionParameter %5 -%55 = OpFunctionParameter %5 -%52 = OpLabel -%63 = OpVariable %30 Function %34 -%85 = OpVariable %30 Function %34 -%105 = OpVariable %30 Function %34 +%32 = OpFunction %2 None %15 +%31 = OpLabel +OpBranch %33 +%33 = OpLabel +OpSelectionMerge %34 None +OpSwitch %16 %40 0 %35 1 %36 2 %37 3 %38 4 %39 +%35 = OpLabel +OpReturn +%36 = OpLabel +OpReturn +%37 = OpLabel +OpReturn +%38 = OpLabel +OpReturn +%39 = OpLabel +OpReturn +%40 = OpLabel +OpReturn +%34 = OpLabel +OpReturn +OpFunctionEnd +%43 = OpFunction %2 None %9 +%42 = OpFunctionParameter %5 +%41 = OpLabel +%57 = OpVariable %50 Function %53 +OpBranch %44 +%44 = OpLabel +OpBranch %45 +%45 = OpLabel +OpLoopMerge %46 %48 None OpBranch %58 %58 = OpLabel -OpBranch %59 -%59 = OpLabel -OpLoopMerge %60 %62 None -OpBranch %64 -%64 = OpLabel -%65 = OpLoad %29 %63 -%66 = OpIEqual %32 %37 %65 -%67 = OpAll %31 %66 -OpSelectionMerge %68 None -OpBranchConditional %67 %60 %68 -%68 = OpLabel -%69 = OpCompositeExtract %4 %65 1 -%70 = OpIEqual %31 %69 %36 -%71 = OpSelect %4 %70 %35 %33 -%72 = OpCompositeConstruct %29 %71 %35 -%73 = OpIAdd %29 %65 %72 -OpStore %63 %73 -OpBranch %61 -%61 = OpLabel -OpSelectionMerge %74 None -OpSwitch %53 %77 1 %75 2 %76 -%75 = OpLabel -OpBranch %62 -%76 = OpLabel -OpSelectionMerge %78 None -OpSwitch %54 %80 1 %79 -%79 = OpLabel -OpBranch %62 -%80 = OpLabel -OpBranch %81 -%81 = OpLabel -OpLoopMerge %82 %84 None -OpBranch %86 -%86 = OpLabel -%87 = OpLoad %29 %85 -%88 = OpIEqual %32 %37 %87 -%89 = OpAll %31 %88 -OpSelectionMerge %90 None -OpBranchConditional %89 %82 %90 -%90 = OpLabel -%91 = OpCompositeExtract %4 %87 1 -%92 = OpIEqual %31 %91 %36 -%93 = OpSelect %4 %92 %35 %33 -%94 = OpCompositeConstruct %29 %93 %35 -%95 = OpIAdd %29 %87 %94 -OpStore %85 %95 -OpBranch %83 -%83 = OpLabel -OpSelectionMerge %96 None -OpSwitch %55 %98 1 %97 -%97 = OpLabel -OpBranch %84 -%98 = OpLabel -OpBranch %96 -%96 = OpLabel -OpBranch %84 -%84 = OpLabel -OpBranch %81 -%82 = OpLabel -OpBranch %78 -%78 = OpLabel -OpBranch %74 -%77 = OpLabel -OpBranch %74 -%74 = OpLabel -OpSelectionMerge %99 None -OpSwitch %54 %100 -%100 = OpLabel -OpBranch %62 -%99 = OpLabel -OpBranch %62 +%59 = OpLoad %49 %57 +%60 = OpIEqual %52 %56 %59 +%61 = OpAll %51 %60 +OpSelectionMerge %62 None +OpBranchConditional %61 %46 %62 %62 = OpLabel -OpBranch %59 -%60 = OpLabel -OpBranch %101 -%101 = OpLabel -OpLoopMerge %102 %104 None -OpBranch %106 -%106 = OpLabel -%107 = OpLoad %29 %105 -%108 = OpIEqual %32 %37 %107 -%109 = OpAll %31 %108 -OpSelectionMerge %110 None -OpBranchConditional %109 %102 %110 -%110 = OpLabel -%111 = OpCompositeExtract %4 %107 1 -%112 = OpIEqual %31 %111 %36 -%113 = OpSelect %4 %112 %35 %33 -%114 = OpCompositeConstruct %29 %113 %35 -%115 = OpIAdd %29 %107 %114 -OpStore %105 %115 -OpBranch %103 -%103 = OpLabel -OpSelectionMerge %116 None -OpSwitch %54 %117 1 %117 -%117 = OpLabel -OpSelectionMerge %118 None -OpSwitch %55 %119 -%119 = OpLabel -OpBranch %104 -%118 = OpLabel -OpBranch %116 -%116 = OpLabel -OpBranch %104 -%104 = OpLabel -OpBranch %101 -%102 = OpLabel +%63 = OpCompositeExtract %4 %59 1 +%64 = OpIEqual %51 %63 %55 +%65 = OpSelect %4 %64 %54 %23 +%66 = OpCompositeConstruct %49 %65 %54 +%67 = OpIAdd %49 %59 %66 +OpStore %57 %67 +OpBranch %47 +%47 = OpLabel +OpSelectionMerge %68 None +OpSwitch %42 %70 1 %69 +%69 = OpLabel +OpBranch %48 +%70 = OpLabel +OpBranch %68 +%68 = OpLabel +OpBranch %48 +%48 = OpLabel +OpBranch %45 +%46 = OpLabel OpReturn OpFunctionEnd -%125 = OpFunction %2 None %126 -%121 = OpFunctionParameter %5 -%122 = OpFunctionParameter %5 -%123 = OpFunctionParameter %5 -%124 = OpFunctionParameter %5 +%75 = OpFunction %2 None %76 +%72 = OpFunctionParameter %5 +%73 = OpFunctionParameter %5 +%74 = OpFunctionParameter %5 +%71 = OpLabel +%82 = OpVariable %50 Function %53 +%104 = OpVariable %50 Function %53 +%124 = OpVariable %50 Function %53 +OpBranch %77 +%77 = OpLabel +OpBranch %78 +%78 = OpLabel +OpLoopMerge %79 %81 None +OpBranch %83 +%83 = OpLabel +%84 = OpLoad %49 %82 +%85 = OpIEqual %52 %56 %84 +%86 = OpAll %51 %85 +OpSelectionMerge %87 None +OpBranchConditional %86 %79 %87 +%87 = OpLabel +%88 = OpCompositeExtract %4 %84 1 +%89 = OpIEqual %51 %88 %55 +%90 = OpSelect %4 %89 %54 %23 +%91 = OpCompositeConstruct %49 %90 %54 +%92 = OpIAdd %49 %84 %91 +OpStore %82 %92 +OpBranch %80 +%80 = OpLabel +OpSelectionMerge %93 None +OpSwitch %72 %96 1 %94 2 %95 +%94 = OpLabel +OpBranch %81 +%95 = OpLabel +OpSelectionMerge %97 None +OpSwitch %73 %99 1 %98 +%98 = OpLabel +OpBranch %81 +%99 = OpLabel +OpBranch %100 +%100 = OpLabel +OpLoopMerge %101 %103 None +OpBranch %105 +%105 = OpLabel +%106 = OpLoad %49 %104 +%107 = OpIEqual %52 %56 %106 +%108 = OpAll %51 %107 +OpSelectionMerge %109 None +OpBranchConditional %108 %101 %109 +%109 = OpLabel +%110 = OpCompositeExtract %4 %106 1 +%111 = OpIEqual %51 %110 %55 +%112 = OpSelect %4 %111 %54 %23 +%113 = OpCompositeConstruct %49 %112 %54 +%114 = OpIAdd %49 %106 %113 +OpStore %104 %114 +OpBranch %102 +%102 = OpLabel +OpSelectionMerge %115 None +OpSwitch %74 %117 1 %116 +%116 = OpLabel +OpBranch %103 +%117 = OpLabel +OpBranch %115 +%115 = OpLabel +OpBranch %103 +%103 = OpLabel +OpBranch %100 +%101 = OpLabel +OpBranch %97 +%97 = OpLabel +OpBranch %93 +%96 = OpLabel +OpBranch %93 +%93 = OpLabel +OpSelectionMerge %118 None +OpSwitch %73 %119 +%119 = OpLabel +OpBranch %81 +%118 = OpLabel +OpBranch %81 +%81 = OpLabel +OpBranch %78 +%79 = OpLabel +OpBranch %120 %120 = OpLabel -%129 = OpVariable %130 Function %16 -%136 = OpVariable %30 Function %34 -%154 = OpVariable %30 Function %34 -OpBranch %131 -%131 = OpLabel -OpBranch %132 -%132 = OpLabel -OpLoopMerge %133 %135 None -OpBranch %137 +OpLoopMerge %121 %123 None +OpBranch %125 +%125 = OpLabel +%126 = OpLoad %49 %124 +%127 = OpIEqual %52 %56 %126 +%128 = OpAll %51 %127 +OpSelectionMerge %129 None +OpBranchConditional %128 %121 %129 +%129 = OpLabel +%130 = OpCompositeExtract %4 %126 1 +%131 = OpIEqual %51 %130 %55 +%132 = OpSelect %4 %131 %54 %23 +%133 = OpCompositeConstruct %49 %132 %54 +%134 = OpIAdd %49 %126 %133 +OpStore %124 %134 +OpBranch %122 +%122 = OpLabel +OpSelectionMerge %135 None +OpSwitch %73 %136 1 %136 +%136 = OpLabel +OpSelectionMerge %137 None +OpSwitch %74 %138 +%138 = OpLabel +OpBranch %123 %137 = OpLabel -%138 = OpLoad %29 %136 -%139 = OpIEqual %32 %37 %138 -%140 = OpAll %31 %139 -OpSelectionMerge %141 None -OpBranchConditional %140 %133 %141 -%141 = OpLabel -%142 = OpCompositeExtract %4 %138 1 -%143 = OpIEqual %31 %142 %36 -%144 = OpSelect %4 %143 %35 %33 -%145 = OpCompositeConstruct %29 %144 %35 -%146 = OpIAdd %29 %138 %145 -OpStore %136 %146 -OpBranch %134 -%134 = OpLabel -OpSelectionMerge %147 None -OpSwitch %121 %149 1 %148 -%148 = OpLabel -OpStore %129 %127 -OpBranch %147 -%149 = OpLabel -OpBranch %147 -%147 = OpLabel OpBranch %135 %135 = OpLabel -OpBranch %132 -%133 = OpLabel +OpBranch %123 +%123 = OpLabel +OpBranch %120 +%121 = OpLabel +OpReturn +OpFunctionEnd +%144 = OpFunction %2 None %145 +%140 = OpFunctionParameter %5 +%141 = OpFunctionParameter %5 +%142 = OpFunctionParameter %5 +%143 = OpFunctionParameter %5 +%139 = OpLabel +%148 = OpVariable %149 Function %16 +%155 = OpVariable %50 Function %53 +%173 = OpVariable %50 Function %53 OpBranch %150 %150 = OpLabel -OpLoopMerge %151 %153 None -OpBranch %155 -%155 = OpLabel -%156 = OpLoad %29 %154 -%157 = OpIEqual %32 %37 %156 -%158 = OpAll %31 %157 -OpSelectionMerge %159 None -OpBranchConditional %158 %151 %159 -%159 = OpLabel -%160 = OpCompositeExtract %4 %156 1 -%161 = OpIEqual %31 %160 %36 -%162 = OpSelect %4 %161 %35 %33 -%163 = OpCompositeConstruct %29 %162 %35 -%164 = OpIAdd %29 %156 %163 -OpStore %154 %164 -OpBranch %152 -%152 = OpLabel -OpSelectionMerge %165 None -OpSwitch %121 %168 1 %166 2 %167 -%166 = OpLabel -OpBranch %165 -%167 = OpLabel -OpSelectionMerge %169 None -OpSwitch %122 %171 1 %170 -%170 = OpLabel +OpBranch %151 +%151 = OpLabel +OpLoopMerge %152 %154 None +OpBranch %156 +%156 = OpLabel +%157 = OpLoad %49 %155 +%158 = OpIEqual %52 %56 %157 +%159 = OpAll %51 %158 +OpSelectionMerge %160 None +OpBranchConditional %159 %152 %160 +%160 = OpLabel +%161 = OpCompositeExtract %4 %157 1 +%162 = OpIEqual %51 %161 %55 +%163 = OpSelect %4 %162 %54 %23 +%164 = OpCompositeConstruct %49 %163 %54 +%165 = OpIAdd %49 %157 %164 +OpStore %155 %165 OpBranch %153 -%171 = OpLabel -OpSelectionMerge %172 None -OpSwitch %123 %174 1 %173 -%173 = OpLabel -OpStore %129 %128 -OpBranch %172 +%153 = OpLabel +OpSelectionMerge %166 None +OpSwitch %140 %168 1 %167 +%167 = OpLabel +OpStore %148 %146 +OpBranch %166 +%168 = OpLabel +OpBranch %166 +%166 = OpLabel +OpBranch %154 +%154 = OpLabel +OpBranch %151 +%152 = OpLabel +OpBranch %169 +%169 = OpLabel +OpLoopMerge %170 %172 None +OpBranch %174 %174 = OpLabel +%175 = OpLoad %49 %173 +%176 = OpIEqual %52 %56 %175 +%177 = OpAll %51 %176 +OpSelectionMerge %178 None +OpBranchConditional %177 %170 %178 +%178 = OpLabel +%179 = OpCompositeExtract %4 %175 1 +%180 = OpIEqual %51 %179 %55 +%181 = OpSelect %4 %180 %54 %23 +%182 = OpCompositeConstruct %49 %181 %54 +%183 = OpIAdd %49 %175 %182 +OpStore %173 %183 +OpBranch %171 +%171 = OpLabel +OpSelectionMerge %184 None +OpSwitch %140 %187 1 %185 2 %186 +%185 = OpLabel +OpBranch %184 +%186 = OpLabel +OpSelectionMerge %188 None +OpSwitch %141 %190 1 %189 +%189 = OpLabel +OpBranch %172 +%190 = OpLabel +OpSelectionMerge %191 None +OpSwitch %142 %193 1 %192 +%192 = OpLabel +OpStore %148 %147 +OpBranch %191 +%193 = OpLabel +OpBranch %191 +%191 = OpLabel +OpBranch %188 +%188 = OpLabel +OpBranch %184 +%187 = OpLabel +OpBranch %184 +%184 = OpLabel OpBranch %172 %172 = OpLabel OpBranch %169 -%169 = OpLabel -OpBranch %165 -%168 = OpLabel -OpBranch %165 -%165 = OpLabel -OpBranch %153 -%153 = OpLabel -OpBranch %150 -%151 = OpLabel +%170 = OpLabel OpReturn OpFunctionEnd -%179 = OpFunction %2 None %15 -%175 = OpLabel -%182 = OpVariable %130 Function %183 -%178 = OpLoad %3 %176 -OpBranch %184 -%184 = OpLabel -OpControlBarrier %185 %35 %186 -OpControlBarrier %185 %185 %187 -OpControlBarrier %185 %185 %188 -OpSelectionMerge %189 None -OpSwitch %127 %190 -%190 = OpLabel -OpStore %182 %127 -OpBranch %189 -%189 = OpLabel -%191 = OpLoad %5 %182 -OpSelectionMerge %192 None -OpSwitch %191 %197 1 %193 2 %194 3 %195 4 %195 5 %196 6 %197 -%193 = OpLabel -OpStore %182 %16 -OpBranch %192 +%198 = OpFunction %2 None %15 %194 = OpLabel -OpStore %182 %127 -OpBranch %192 -%195 = OpLabel -OpStore %182 %128 -OpBranch %192 -%196 = OpLabel -OpStore %182 %180 -OpBranch %192 -%197 = OpLabel -OpStore %182 %181 -OpBranch %192 -%192 = OpLabel -OpSelectionMerge %198 None -OpSwitch %33 %200 0 %199 -%199 = OpLabel -OpBranch %198 -%200 = OpLabel -OpBranch %198 -%198 = OpLabel -%201 = OpLoad %5 %182 -OpSelectionMerge %202 None -OpSwitch %201 %207 1 %203 2 %204 3 %205 4 %206 +%201 = OpVariable %149 Function %202 +%197 = OpLoad %3 %195 +OpBranch %203 %203 = OpLabel -OpStore %182 %16 -OpBranch %202 -%204 = OpLabel -OpStore %182 %127 +OpControlBarrier %204 %54 %205 +OpControlBarrier %204 %204 %206 +OpControlBarrier %204 %204 %207 +OpSelectionMerge %208 None +OpSwitch %146 %209 +%209 = OpLabel +OpStore %201 %146 +OpBranch %208 +%208 = OpLabel +%210 = OpLoad %5 %201 +OpSelectionMerge %211 None +OpSwitch %210 %216 1 %212 2 %213 3 %214 4 %214 5 %215 6 %216 +%212 = OpLabel +OpStore %201 %16 +OpBranch %211 +%213 = OpLabel +OpStore %201 %146 +OpBranch %211 +%214 = OpLabel +OpStore %201 %147 +OpBranch %211 +%215 = OpLabel +OpStore %201 %199 +OpBranch %211 +%216 = OpLabel +OpStore %201 %200 +OpBranch %211 +%211 = OpLabel +OpSelectionMerge %217 None +OpSwitch %23 %219 0 %218 +%218 = OpLabel +OpBranch %217 +%219 = OpLabel +OpBranch %217 +%217 = OpLabel +%220 = OpLoad %5 %201 +OpSelectionMerge %221 None +OpSwitch %220 %226 1 %222 2 %223 3 %224 4 %225 +%222 = OpLabel +OpStore %201 %16 +OpBranch %221 +%223 = OpLabel +OpStore %201 %146 OpReturn -%205 = OpLabel -OpStore %182 %128 +%224 = OpLabel +OpStore %201 %147 OpReturn -%206 = OpLabel +%225 = OpLabel OpReturn -%207 = OpLabel -OpStore %182 %180 +%226 = OpLabel +OpStore %201 %199 OpReturn -%202 = OpLabel +%221 = OpLabel OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/wgsl/control-flow.wgsl b/naga/tests/out/wgsl/control-flow.wgsl index eaee5aa214..48a5ae5825 100644 --- a/naga/tests/out/wgsl/control-flow.wgsl +++ b/naga/tests/out/wgsl/control-flow.wgsl @@ -17,6 +17,46 @@ fn switch_case_break() { return; } +fn switch_selector_type_conversion() { + switch 0u { + case 0u: { + } + default: { + } + } + switch 0u { + case 0u: { + return; + } + default: { + return; + } + } +} + +fn switch_const_expr_case_selectors() { + switch 0i { + case 0: { + return; + } + case 1: { + return; + } + case 2: { + return; + } + case 3: { + return; + } + case 4: { + return; + } + default: { + return; + } + } +} + fn loop_switch_continue(x: i32) { loop { switch x { diff --git a/naga/tests/wgsl_errors.rs b/naga/tests/wgsl_errors.rs index 7d459dd7ad..9b2392857b 100644 --- a/naga/tests/wgsl_errors.rs +++ b/naga/tests/wgsl_errors.rs @@ -1905,18 +1905,16 @@ fn switch_signed_unsigned_mismatch() { check( " fn x(y: u32) { - switch y { - case 1: {} - } + switch y { + case 1i: {} + } } ", - r###"error: invalid switch value - ┌─ wgsl:4:16 + r###"error: invalid `switch` case selector value + ┌─ wgsl:4:22 │ -4 │ case 1: {} - │ ^ expected unsigned integer - │ - = note: suffix the integer with a `u`: `1u` +4 │ case 1i: {} + │ ^^ `switch` case selector must have the same type as the `switch` selector expression "###, ); @@ -1924,18 +1922,90 @@ fn switch_signed_unsigned_mismatch() { check( " fn x(y: i32) { - switch y { - case 1u: {} - } + switch y { + case 1u: {} + } } ", - r###"error: invalid switch value - ┌─ wgsl:4:16 + r###"error: invalid `switch` case selector value + ┌─ wgsl:4:22 │ 4 │ case 1u: {} - │ ^^ expected signed integer + │ ^^ `switch` case selector must have the same type as the `switch` selector expression + +"###, + ); +} + +#[test] +fn switch_invalid_type() { + check( + " + fn x(y: f32) { + switch y { + case 1: {} + } + } + ", + r###"error: invalid `switch` selector + ┌─ wgsl:3:20 │ - = note: remove the `u` suffix: `1` +3 │ switch y { + │ ^ `switch` selector must be a scalar integer + +"###, + ); + + check( + " + fn x(y: vec2) { + switch y { + case 1: {} + } + } + ", + r###"error: invalid `switch` selector + ┌─ wgsl:3:20 + │ +3 │ switch y { + │ ^ `switch` selector must be a scalar integer + +"###, + ); + + check( + " + fn x() { + switch 0 { + case 1.0: {} + } + } + ", + r###"error: invalid `switch` case selector value + ┌─ wgsl:4:22 + │ +4 │ case 1.0: {} + │ ^^^ `switch` case selector must be a scalar integer const expression + +"###, + ); +} + +#[test] +fn switch_non_const_case() { + check( + " + fn x(y: i32) { + switch 0 { + case y: {} + } + } + ", + r###"error: invalid `switch` case selector value + ┌─ wgsl:4:22 + │ +4 │ case y: {} + │ ^ `switch` case selector must be a scalar integer const expression "###, );