Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement WGSL abstract types for global const declarations and constructor calls. #4743

Merged
merged 9 commits into from
Nov 29, 2023
Merged
40 changes: 38 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,44 @@ Passing an owned value `window` to `Surface` will return a `Surface<'static>`. S
- Introduce a new `Scalar` struct type for use in Naga's IR, and update all frontend, middle, and backend code appropriately. By @jimblandy in [#4673](https://github.com/gfx-rs/wgpu/pull/4673).
- Add more metal keywords. By @fornwall in [#4707](https://github.com/gfx-rs/wgpu/pull/4707).

- Implement WGSL abstract types (by @jimblandy):
- Add a new `naga::Literal` variant, `I64`, for signed 64-bit literals. [#4711](https://github.com/gfx-rs/wgpu/pull/4711)
- Add partial support for WGSL abstract types (@jimblandy in [#4743](https://github.com/gfx-rs/wgpu/pull/4743)).

Abstract types make numeric literals easier to use, by
automatically converting literals and other constant expressions
from abstract numeric types to concrete types when safe and
necessary. For example, to build a vector of floating-point
numbers, Naga previously made you write:

vec3<f32>(1.0, 2.0, 3.0)

With this change, you can now simply write:

vec3<f32>(1, 2, 3)

Even though the literals are abstract integers, Naga recognizes
that it is safe and necessary to convert them to `f32` values in
order to build the vector. You can also use abstract values as
initializers for global constants, like this:

const unit_x: vec2<f32> = vec2(1, 0);

The literals `1` and `0` are abstract integers, and the expression
`vec2(1, 0)` is an abstract vector. However, Naga recognizes that
it can convert that to the concrete type `vec2<f32>` to satisfy
the given type of `unit_x`.

The WGSL specification permits abstract integers and
floating-point values in almost all contexts, but Naga's support
for this is still incomplete. Many WGSL operators and builtin
functions are specified to produce abstract results when applied
to abstract inputs, but for now Naga simply concretizes them all
before applying the operation. We will expand Naga's abstract type
support in subsequent pull requests.

As part of this work, the public types `naga::ScalarKind` and
`naga::Literal` now have new variants, `AbstractInt` and `AbstractFloat`.

- Add a new `naga::Literal` variant, `I64`, for signed 64-bit literals. [#4711](https://github.com/gfx-rs/wgpu/pull/4711)

- Emit and init `struct` member padding always. By @ErichDonGubler in [#4701](https://github.com/gfx-rs/wgpu/pull/4701).

Expand Down
2 changes: 1 addition & 1 deletion naga/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ deserialize = ["serde", "bitflags/serde", "indexmap/serde"]
arbitrary = ["dep:arbitrary", "bitflags/arbitrary", "indexmap/arbitrary"]
spv-in = ["petgraph", "spirv"]
spv-out = ["spirv"]
wgsl-in = ["hexf-parse", "unicode-xid"]
wgsl-in = ["hexf-parse", "unicode-xid", "compact"]
wgsl-out = []
hlsl-out = []
compact = []
Expand Down
16 changes: 16 additions & 0 deletions naga/src/back/glsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2451,6 +2451,11 @@ impl<'a, W: Write> Writer<'a, W> {
crate::Literal::I64(_) => {
return Err(Error::Custom("GLSL has no 64-bit integer type".into()));
}
crate::Literal::AbstractInt(_) | crate::Literal::AbstractFloat(_) => {
return Err(Error::Custom(
"Abstract types should not appear in IR presented to backends".into(),
));
}
}
}
Expression::Constant(handle) => {
Expand Down Expand Up @@ -3555,6 +3560,9 @@ impl<'a, W: Write> Writer<'a, W> {
(Sk::Sint | Sk::Uint | Sk::Float, Sk::Bool, None) => {
write!(self.out, "bool")?
}

(Sk::AbstractInt | Sk::AbstractFloat, _, _)
| (_, Sk::AbstractInt | Sk::AbstractFloat, _) => unreachable!(),
};

write!(self.out, "(")?;
Expand Down Expand Up @@ -4117,6 +4125,11 @@ impl<'a, W: Write> Writer<'a, W> {
crate::ScalarKind::Uint => write!(self.out, "0u")?,
crate::ScalarKind::Float => write!(self.out, "0.0")?,
crate::ScalarKind::Sint => write!(self.out, "0")?,
crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat => {
return Err(Error::Custom(
"Abstract types should not appear in IR presented to backends".to_string(),
))
}
}

Ok(())
Expand Down Expand Up @@ -4345,6 +4358,9 @@ const fn glsl_scalar(scalar: crate::Scalar) -> Result<ScalarString<'static>, Err
prefix: "b",
full: "bool",
},
Sk::AbstractInt | Sk::AbstractFloat => {
return Err(Error::UnsupportedScalar(scalar));
}
})
}

Expand Down
5 changes: 4 additions & 1 deletion naga/src/back/hlsl/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ impl crate::ScalarKind {
Self::Float => "asfloat",
Self::Sint => "asint",
Self::Uint => "asuint",
Self::Bool => unreachable!(),
Self::Bool | Self::AbstractInt | Self::AbstractFloat => unreachable!(),
}
}
}
Expand All @@ -30,6 +30,9 @@ impl crate::Scalar {
_ => Err(Error::UnsupportedScalar(self)),
},
crate::ScalarKind::Bool => Ok("bool"),
crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat => {
Err(Error::UnsupportedScalar(self))
}
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions naga/src/back/hlsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2040,6 +2040,11 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
crate::Literal::I32(value) => write!(self.out, "{}", value)?,
crate::Literal::I64(value) => write!(self.out, "{}L", value)?,
crate::Literal::Bool(value) => write!(self.out, "{}", value)?,
crate::Literal::AbstractInt(_) | crate::Literal::AbstractFloat(_) => {
return Err(Error::Custom(
"Abstract types should not appear in IR presented to backends".into(),
));
}
},
Expression::Constant(handle) => {
let constant = &module.constants[handle];
Expand Down
7 changes: 7 additions & 0 deletions naga/src/back/msl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ impl crate::Scalar {
kind: Sk::Bool,
width: _,
} => "bool",
Self {
kind: Sk::AbstractInt | Sk::AbstractFloat,
width: _,
} => unreachable!(),
}
}
}
Expand Down Expand Up @@ -1275,6 +1279,9 @@ impl<W: Write> Writer<W> {
crate::Literal::Bool(value) => {
write!(self.out, "{value}")?;
}
crate::Literal::AbstractInt(_) | crate::Literal::AbstractFloat(_) => {
return Err(Error::Validation);
}
},
crate::Expression::Constant(handle) => {
let constant = &module.constants[handle];
Expand Down
2 changes: 1 addition & 1 deletion naga/src/back/spv/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,7 @@ impl<'w> BlockContext<'w> {
let op = match src_scalar.kind {
Sk::Sint | Sk::Uint => spirv::Op::INotEqual,
Sk::Float => spirv::Op::FUnordNotEqual,
Sk::Bool => unreachable!(),
Sk::Bool | Sk::AbstractInt | Sk::AbstractFloat => unreachable!(),
};
let zero_scalar_id =
self.writer.get_constant_scalar_with(0, src_scalar)?;
Expand Down
4 changes: 4 additions & 0 deletions naga/src/back/spv/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ impl<'w> BlockContext<'w> {
(_, crate::ScalarKind::Bool | crate::ScalarKind::Float) => {
unreachable!("we don't allow bool or float for array index")
}
(crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat, _)
| (_, crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat) => {
unreachable!("abstract types should never reach backends")
}
};
let reconciled_array_index_id = if let Some(cast) = cast {
let component_ty_id = self.get_type_id(LookupType::Local(LocalType::Value {
Expand Down
11 changes: 11 additions & 0 deletions naga/src/back/spv/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,9 @@ impl Writer {
Instruction::type_float(id, bits)
}
Sk::Bool => Instruction::type_bool(id),
Sk::AbstractInt | Sk::AbstractFloat => {
unreachable!("abstract types should never reach the backend");
}
}
}

Expand Down Expand Up @@ -1184,6 +1187,9 @@ impl Writer {
}
crate::Literal::Bool(true) => Instruction::constant_true(type_id, id),
crate::Literal::Bool(false) => Instruction::constant_false(type_id, id),
crate::Literal::AbstractInt(_) | crate::Literal::AbstractFloat(_) => {
unreachable!("Abstract types should not appear in IR presented to backends");
}
};

instruction.to_words(&mut self.logical_layout.declarations);
Expand Down Expand Up @@ -1591,6 +1597,11 @@ impl Writer {
| crate::TypeInner::Vector { scalar, .. } => match scalar.kind {
Sk::Uint | Sk::Sint | Sk::Bool => true,
Sk::Float => false,
Sk::AbstractInt | Sk::AbstractFloat => {
return Err(Error::Validation(
"Abstract types should not appear in IR presented to backends",
))
}
},
_ => false,
};
Expand Down
5 changes: 5 additions & 0 deletions naga/src/back/wgsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,11 @@ impl<W: Write> Writer<W> {
crate::Literal::I64(_) => {
return Err(Error::Custom("unsupported i64 literal".to_string()));
}
crate::Literal::AbstractInt(_) | crate::Literal::AbstractFloat(_) => {
return Err(Error::Custom(
"Abstract types should not appear in IR presented to backends".into(),
));
}
}
}
Expression::Constant(handle) => {
Expand Down
2 changes: 1 addition & 1 deletion naga/src/front/glsl/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ pub const fn type_power(scalar: Scalar) -> Option<u32> {
ScalarKind::Uint => 1,
ScalarKind::Float if scalar.width == 4 => 2,
ScalarKind::Float => 3,
ScalarKind::Bool => return None,
ScalarKind::Bool | ScalarKind::AbstractInt | ScalarKind::AbstractFloat => return None,
})
}

Expand Down
20 changes: 20 additions & 0 deletions naga/src/front/wgsl/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ pub enum Error<'a> {
ExpectedPositiveArrayLength(Span),
MissingWorkgroupSize(Span),
ConstantEvaluatorError(ConstantEvaluatorError, Span),
AutoConversion {
dest_span: Span,
dest_type: String,
source_span: Span,
source_type: String,
},
}

impl<'a> Error<'a> {
Expand Down Expand Up @@ -712,6 +718,20 @@ impl<'a> Error<'a> {
)],
notes: vec![],
},
Error::AutoConversion { dest_span, ref dest_type, source_span, ref source_type } => ParseError {
message: format!("automatic conversions cannot convert `{source_type}` to `{dest_type}`"),
labels: vec![
(
dest_span,
format!("a value of type {dest_type} is required here").into(),
),
(
source_span,
format!("this expression has type {source_type}").into(),
)
],
notes: vec![],
}
}
}
}
Loading
Loading