Skip to content

Commit 7d7d1fa

Browse files
andyleisersonVecvec
authored andcommitted
[naga wgsl-in] vecN() constructors and let type conversions (gfx-rs#7367)
* Support `vecN()` constructors (fixes gfx-rs#7356) * Apply automatic conversions to the initializer for `let` bindings
1 parent f53f8c5 commit 7d7d1fa

40 files changed

+2028
-751
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ By @wumpf in [#7144](https://github.com/gfx-rs/wgpu/pull/7144)
239239
- 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).
240240
- 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).
241241
- 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).
242+
- Apply automatic conversions to `let` declarations, and accept `vecN()` as a constructor for vectors (in any context). By @andyleiserson in [#7367](https://github.com/gfx-rs/wgpu/pull/7367).
242243
243244
#### General
244245

naga/src/front/wgsl/lower/construction.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,25 @@ impl<'source> Lowerer<'source, '_> {
167167
// Empty constructor
168168
(Components::None, dst_ty) => match dst_ty {
169169
Constructor::Type((result_ty, _)) => {
170-
return ctx.append_expression(crate::Expression::ZeroValue(result_ty), span)
170+
expr = crate::Expression::ZeroValue(result_ty);
171171
}
172-
Constructor::PartialVector { .. }
173-
| Constructor::PartialMatrix { .. }
174-
| Constructor::PartialArray => {
172+
Constructor::PartialVector { size } => {
173+
// vec2(), vec3(), vec4() return vectors of abstractInts; the same
174+
// is not true of the similar constructors for matrices or arrays.
175+
// See https://www.w3.org/TR/WGSL/#vec2-builtin et seq.
176+
let result_ty = ctx.module.types.insert(
177+
crate::Type {
178+
name: None,
179+
inner: crate::TypeInner::Vector {
180+
size,
181+
scalar: crate::Scalar::ABSTRACT_INT,
182+
},
183+
},
184+
span,
185+
);
186+
expr = crate::Expression::ZeroValue(result_ty);
187+
}
188+
Constructor::PartialMatrix { .. } | Constructor::PartialArray => {
175189
// We have no arguments from which to infer the result type, so
176190
// partial constructors aren't acceptable here.
177191
return Err(Box::new(Error::TypeNotInferable(ty_span)));

naga/src/front/wgsl/lower/mod.rs

+23-25
Original file line numberDiff line numberDiff line change
@@ -1490,41 +1490,39 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
14901490
let mut emitter = Emitter::default();
14911491
emitter.start(&ctx.function.expressions);
14921492

1493-
let value =
1494-
self.expression(l.init, &mut ctx.as_expression(block, &mut emitter))?;
1493+
let explicit_ty = l
1494+
.ty
1495+
.map(|ty| self.resolve_ast_type(ty, &mut ctx.as_const(block, &mut emitter)))
1496+
.transpose()?;
1497+
1498+
let mut ectx = ctx.as_expression(block, &mut emitter);
1499+
1500+
let (_ty, initializer) = self.type_and_init(
1501+
l.name,
1502+
Some(l.init),
1503+
explicit_ty,
1504+
AbstractRule::Concretize,
1505+
&mut ectx,
1506+
)?;
1507+
1508+
// We passed `Some()` to `type_and_init`, so we
1509+
// will get a lowered initializer expression back.
1510+
let initializer =
1511+
initializer.expect("type_and_init did not return an initializer");
14951512

14961513
// The WGSL spec says that any expression that refers to a
14971514
// `let`-bound variable is not a const expression. This
14981515
// affects when errors must be reported, so we can't even
14991516
// treat suitable `let` bindings as constant as an
15001517
// optimization.
1501-
ctx.local_expression_kind_tracker.force_non_const(value);
1502-
1503-
let explicit_ty = l
1504-
.ty
1505-
.map(|ty| self.resolve_ast_type(ty, &mut ctx.as_const(block, &mut emitter)))
1506-
.transpose()?;
1507-
1508-
if let Some(ty) = explicit_ty {
1509-
let mut ctx = ctx.as_expression(block, &mut emitter);
1510-
let init_ty = ctx.register_type(value)?;
1511-
if !ctx.module.types[ty]
1512-
.inner
1513-
.equivalent(&ctx.module.types[init_ty].inner, &ctx.module.types)
1514-
{
1515-
return Err(Box::new(Error::InitializationTypeMismatch {
1516-
name: l.name.span,
1517-
expected: ctx.type_to_string(ty),
1518-
got: ctx.type_to_string(init_ty),
1519-
}));
1520-
}
1521-
}
1518+
ctx.local_expression_kind_tracker
1519+
.force_non_const(initializer);
15221520

15231521
block.extend(emitter.finish(&ctx.function.expressions));
15241522
ctx.local_table
1525-
.insert(l.handle, Declared::Runtime(Typed::Plain(value)));
1523+
.insert(l.handle, Declared::Runtime(Typed::Plain(initializer)));
15261524
ctx.named_expressions
1527-
.insert(value, (l.name.name.to_string(), l.name.span));
1525+
.insert(initializer, (l.name.name.to_string(), l.name.span));
15281526

15291527
return Ok(());
15301528
}

naga/src/proc/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ impl crate::Literal {
119119
(value, crate::ScalarKind::Sint, 8) => Some(Self::I64(value as _)),
120120
(1, crate::ScalarKind::Bool, crate::BOOL_WIDTH) => Some(Self::Bool(true)),
121121
(0, crate::ScalarKind::Bool, crate::BOOL_WIDTH) => Some(Self::Bool(false)),
122+
(value, crate::ScalarKind::AbstractInt, 8) => Some(Self::AbstractInt(value as _)),
123+
(value, crate::ScalarKind::AbstractFloat, 8) => Some(Self::AbstractFloat(value as _)),
122124
_ => None,
123125
}
124126
}

naga/tests/in/wgsl/abstract-types-const.wgsl

+23-4
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,23 @@
1212
// - all parameters' types are considered.
1313
// - all parameters are converted to the consensus type.
1414

15-
const xvupaiai: vec2<u32> = vec2(42, 43);
16-
const xvfpaiai: vec2<f32> = vec2(44, 45);
15+
const xvipaiai: vec2<i32> = vec2(42, 43);
16+
const xvupaiai: vec2<u32> = vec2(44, 45);
17+
const xvfpaiai: vec2<f32> = vec2(46, 47);
18+
const xvfpafaf: vec2<f32> = vec2(48.0, 49.0);
19+
const xvfpaiaf: vec2<f32> = vec2(48, 49.0);
1720

1821
const xvupuai: vec2<u32> = vec2(42u, 43);
1922
const xvupaiu: vec2<u32> = vec2(42, 43u);
2023

2124
const xvuuai: vec2<u32> = vec2<u32>(42u, 43);
2225
const xvuaiu: vec2<u32> = vec2<u32>(42, 43u);
2326

27+
const xvip____: vec2<i32> = vec2();
28+
const xvup____: vec2<u32> = vec2();
29+
const xvfp____: vec2<f32> = vec2();
30+
const xmfp____: mat2x2f = mat2x2(vec2(), vec2());
31+
2432
const xmfpaiaiaiai: mat2x2<f32> = mat2x2(1, 2, 3, 4);
2533
const xmfpafaiaiai: mat2x2<f32> = mat2x2(1.0, 2, 3, 4);
2634
const xmfpaiafaiai: mat2x2<f32> = mat2x2(1, 2.0, 3, 4);
@@ -41,9 +49,15 @@ const ivfs_af = vec2<f32>(1.0);
4149
const iafafaf = array<f32, 2>(1.0, 2.0);
4250
const iafaiai = array<f32, 2>(1, 2);
4351

44-
const iafpafaf = array(1.0, 2.0);
45-
const iafpaiaf = array(1, 2.0);
52+
const iaipaiai = array(1, 2);
53+
const iafpaiaf = array(1, 2.0);
4654
const iafpafai = array(1.0, 2);
55+
const iafpafaf = array(1.0, 2.0);
56+
57+
const xaipaiai: array<i32, 2> = array(1, 2);
58+
const xaupaiai: array<u32, 2> = array(1, 2);
59+
const xafpaiaf: array<f32, 2> = array(1, 2.0);
60+
const xafpafai: array<f32, 2> = array(1.0, 2);
4761
const xafpafaf: array<f32, 2> = array(1.0, 2.0);
4862

4963
struct S {
@@ -61,6 +75,11 @@ const saf_iai: S = S(1.0, 1i, 1);
6175
const safai_u: S = S(1.0, 1, 1u);
6276
const safaiai: S = S(1.0, 1, 1);
6377

78+
const xvisai: vec2<i32> = vec2(1);
79+
const xvusai: vec2<u32> = vec2(1);
80+
const xvfsai: vec2<f32> = vec2(1);
81+
const xvfsaf: vec2<f32> = vec2(1.0);
82+
6483
// Vector construction with spreads
6584
const ivfr_f__f = vec3<f32>(vec2<f32>(1.0f, 2.0f), 3.0f);
6685
const ivfr_f_af = vec3<f32>(vec2<f32>(1.0f, 2.0f), 3.0 );
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
targets = "SPIRV | METAL | GLSL | WGSL"
+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// i/x: type inferred / explicit
2+
// vX/mX/aX: vector / matrix / array of X
3+
// where X: u/i/f: u32 / i32 / f32
4+
// s: vector splat
5+
// r: vector spread (vector arg to vector constructor)
6+
// p: "partial" constructor (type parameter inferred)
7+
// u/i/f/ai/af: u32 / i32 / f32 / abstract float / abstract integer as parameter
8+
// _: just for alignment
9+
10+
// Ensure that:
11+
// - the inferred type is correct.
12+
// - all parameters' types are considered.
13+
// - all parameters are converted to the consensus type.
14+
15+
fn all_constant_arguments() {
16+
let xvipaiai: vec2<i32> = vec2(42, 43);
17+
let xvupaiai: vec2<u32> = vec2(44, 45);
18+
let xvfpaiai: vec2<f32> = vec2(46, 47);
19+
let xvfpafaf: vec2<f32> = vec2(48.0, 49.0);
20+
let xvfpaiaf: vec2<f32> = vec2(48, 49.0);
21+
22+
let xvupuai: vec2<u32> = vec2(42u, 43);
23+
let xvupaiu: vec2<u32> = vec2(42, 43u);
24+
25+
let xvuuai: vec2<u32> = vec2<u32>(42u, 43);
26+
let xvuaiu: vec2<u32> = vec2<u32>(42, 43u);
27+
28+
let xvip____: vec2<i32> = vec2();
29+
let xvup____: vec2<u32> = vec2();
30+
let xvfp____: vec2<f32> = vec2();
31+
let xmfp____: mat2x2f = mat2x2(vec2(), vec2());
32+
33+
let xmfpaiaiaiai: mat2x2<f32> = mat2x2(1, 2, 3, 4);
34+
let xmfpafaiaiai: mat2x2<f32> = mat2x2(1.0, 2, 3, 4);
35+
let xmfpaiafaiai: mat2x2<f32> = mat2x2(1, 2.0, 3, 4);
36+
let xmfpaiaiafai: mat2x2<f32> = mat2x2(1, 2, 3.0, 4);
37+
let xmfpaiaiaiaf: mat2x2<f32> = mat2x2(1, 2, 3, 4.0);
38+
39+
let xmfp_faiaiai: mat2x2<f32> = mat2x2(1.0f, 2, 3, 4);
40+
let xmfpai_faiai: mat2x2<f32> = mat2x2(1, 2.0f, 3, 4);
41+
let xmfpaiai_fai: mat2x2<f32> = mat2x2(1, 2, 3.0f, 4);
42+
let xmfpaiaiai_f: mat2x2<f32> = mat2x2(1, 2, 3, 4.0f);
43+
44+
let xvispai: vec2<i32> = vec2(1);
45+
let xvfspaf: vec2<f32> = vec2(1.0);
46+
let xvis_ai: vec2<i32> = vec2<i32>(1);
47+
let xvus_ai: vec2<u32> = vec2<u32>(1);
48+
let xvfs_ai: vec2<f32> = vec2<f32>(1);
49+
let xvfs_af: vec2<f32> = vec2<f32>(1.0);
50+
51+
let xafafaf: array<f32, 2> = array<f32, 2>(1.0, 2.0);
52+
let xaf_faf: array<f32, 2> = array<f32, 2>(1.0f, 2.0);
53+
let xafaf_f: array<f32, 2> = array<f32, 2>(1.0, 2.0f);
54+
let xafaiai: array<f32, 2> = array<f32, 2>(1, 2);
55+
let xai_iai: array<i32, 2> = array<i32, 2>(1i, 2);
56+
let xaiai_i: array<i32, 2> = array<i32, 2>(1, 2i);
57+
58+
let xaipaiai: array<i32, 2> = array(1, 2);
59+
let xafpaiai: array<f32, 2> = array(1, 2);
60+
let xafpaiaf: array<f32, 2> = array(1, 2.0);
61+
let xafpafai: array<f32, 2> = array(1.0, 2);
62+
let xafpafaf: array<f32, 2> = array(1.0, 2.0);
63+
64+
let xavipai: array<vec3<i32>, 1> = array(vec3(1));
65+
let xavfpai: array<vec3<f32>, 1> = array(vec3(1));
66+
let xavfpaf: array<vec3<f32>, 1> = array(vec3(1.0));
67+
68+
// Construction with splats
69+
let xvisai: vec2<i32> = vec2(1);
70+
let xvusai: vec2<u32> = vec2(1);
71+
let xvfsai: vec2<f32> = vec2(1);
72+
let xvfsaf: vec2<f32> = vec2(1.0);
73+
74+
let iaipaiai = array(1, 2);
75+
let iafpaiaf = array(1, 2.0);
76+
let iafpafai = array(1.0, 2);
77+
let iafpafaf = array(1.0, 2.0);
78+
}
79+
80+
fn mixed_constant_and_runtime_arguments() {
81+
var u: u32;
82+
var i: i32;
83+
var f: f32;
84+
85+
let xvupuai: vec2<u32> = vec2(u, 43);
86+
let xvupaiu: vec2<u32> = vec2(42, u);
87+
let xvfpfai: vec2<f32> = vec2(f, 47); // differs slightly from const version
88+
let xvfpfaf: vec2<f32> = vec2(f, 49.0);
89+
90+
let xvuuai: vec2<u32> = vec2<u32>(u, 43);
91+
let xvuaiu: vec2<u32> = vec2<u32>(42, u);
92+
93+
let xmfp_faiaiai: mat2x2<f32> = mat2x2(f, 2, 3, 4);
94+
let xmfpai_faiai: mat2x2<f32> = mat2x2(1, f, 3, 4);
95+
let xmfpaiai_fai: mat2x2<f32> = mat2x2(1, 2, f, 4);
96+
let xmfpaiaiai_f: mat2x2<f32> = mat2x2(1, 2, 3, f);
97+
98+
let xaf_faf: array<f32, 2> = array<f32, 2>(f, 2.0);
99+
let xafaf_f: array<f32, 2> = array<f32, 2>(1.0, f);
100+
let xaf_fai: array<f32, 2> = array<f32, 2>(f, 2);
101+
let xafai_f: array<f32, 2> = array<f32, 2>(1, f);
102+
let xai_iai: array<i32, 2> = array<i32, 2>(i, 2);
103+
let xaiai_i: array<i32, 2> = array<i32, 2>(1, i);
104+
105+
let xafp_faf: array<f32, 2> = array(f, 2.0);
106+
let xafpaf_f: array<f32, 2> = array(1.0, f);
107+
let xafp_fai: array<f32, 2> = array(f, 2);
108+
let xafpai_f: array<f32, 2> = array(1, f);
109+
let xaip_iai: array<i32, 2> = array(i, 2);
110+
let xaipai_i: array<i32, 2> = array(1, i);
111+
112+
let xvisi: vec2<i32> = vec2(i);
113+
let xvusu: vec2<u32> = vec2(u);
114+
let xvfsf: vec2<f32> = vec2(f);
115+
}

0 commit comments

Comments
 (0)