Skip to content

Commit 7ce0316

Browse files
committed
Make Statement::Atomic::result optional.
Rather than introducing an entirely new statement variant `AtomicNoResult`, make `Statement::Atomic::result` an `Option`. This reduces the patch size by about a third, and has no effect on snapshot output other than the direct IR dumps. In HLSL output, don't bother to generated "discard" temporaries for functions where the final `original_value` parameter is not required. This improves snapshot output. Improve documentation for `Expression::AtomicResult`, `Statement::Atomic`, and the new `valid::Capabilities` flags. Rewrite `Atomic` statement validation. Consolidate validation of `AtomicResult` expressions with this; gfx-rs#5771 ensures that there is indeed some `Atomic` statement referring to every `AtomicResult` expression, so we can be sure it will be validated. Fixes gfx-rs#5742.
1 parent abad44a commit 7ce0316

26 files changed

+412
-619
lines changed

naga/src/back/dot/mod.rs

+3-10
Original file line numberDiff line numberDiff line change
@@ -244,23 +244,16 @@ impl StatementGraph {
244244
value,
245245
result,
246246
} => {
247-
self.emits.push((id, result));
247+
if let Some(result) = result {
248+
self.emits.push((id, result));
249+
}
248250
self.dependencies.push((id, pointer, "pointer"));
249251
self.dependencies.push((id, value, "value"));
250252
if let crate::AtomicFunction::Exchange { compare: Some(cmp) } = *fun {
251253
self.dependencies.push((id, cmp, "cmp"));
252254
}
253255
"Atomic"
254256
}
255-
S::AtomicNoReturn {
256-
pointer,
257-
fun: _,
258-
value,
259-
} => {
260-
self.dependencies.push((id, pointer, "pointer"));
261-
self.dependencies.push((id, value, "value"));
262-
"AtomicNoReturn"
263-
}
264257
S::WorkGroupUniformLoad { pointer, result } => {
265258
self.emits.push((id, result));
266259
self.dependencies.push((id, pointer, "pointer"));

naga/src/back/glsl/mod.rs

+7-28
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,6 @@ impl crate::AtomicFunction {
9696
}
9797
}
9898

99-
impl crate::AtomicFunctionNoReturn {
100-
const fn to_glsl(self) -> &'static str {
101-
match self {
102-
Self::Min => "Min",
103-
Self::Max => "Max",
104-
}
105-
}
106-
}
107-
10899
impl crate::AddressSpace {
109100
const fn is_buffer(&self) -> bool {
110101
match *self {
@@ -2377,11 +2368,13 @@ impl<'a, W: Write> Writer<'a, W> {
23772368
result,
23782369
} => {
23792370
write!(self.out, "{level}")?;
2380-
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
2381-
let res_ty = ctx.resolve_type(result, &self.module.types);
2382-
self.write_value_type(res_ty)?;
2383-
write!(self.out, " {res_name} = ")?;
2384-
self.named_expressions.insert(result, res_name);
2371+
if let Some(result) = result {
2372+
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
2373+
let res_ty = ctx.resolve_type(result, &self.module.types);
2374+
self.write_value_type(res_ty)?;
2375+
write!(self.out, " {res_name} = ")?;
2376+
self.named_expressions.insert(result, res_name);
2377+
}
23852378

23862379
let fun_str = fun.to_glsl();
23872380
write!(self.out, "atomic{fun_str}(")?;
@@ -2403,20 +2396,6 @@ impl<'a, W: Write> Writer<'a, W> {
24032396
self.write_expr(value, ctx)?;
24042397
writeln!(self.out, ");")?;
24052398
}
2406-
Statement::AtomicNoReturn {
2407-
pointer,
2408-
ref fun,
2409-
value,
2410-
} => {
2411-
write!(self.out, "{level}")?;
2412-
2413-
let fun_str = fun.to_glsl();
2414-
write!(self.out, "atomic{fun_str}(")?;
2415-
self.write_expr(pointer, ctx)?;
2416-
write!(self.out, ", ")?;
2417-
self.write_expr(value, ctx)?;
2418-
writeln!(self.out, ");")?;
2419-
}
24202399
Statement::RayQuery { .. } => unreachable!(),
24212400
Statement::SubgroupBallot { result, predicate } => {
24222401
write!(self.out, "{level}")?;

naga/src/back/hlsl/conv.rs

-10
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,3 @@ impl crate::AtomicFunction {
233233
}
234234
}
235235
}
236-
237-
impl crate::AtomicFunctionNoReturn {
238-
/// Return the HLSL suffix for the `InterlockedXxx` method.
239-
pub(super) const fn to_hlsl_suffix(self) -> &'static str {
240-
match self {
241-
Self::Min => "Min",
242-
Self::Max => "Max",
243-
}
244-
}
245-
}

naga/src/back/hlsl/writer.rs

+22-54
Original file line numberDiff line numberDiff line change
@@ -1919,11 +1919,20 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
19191919
result,
19201920
} => {
19211921
write!(self.out, "{level}")?;
1922-
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
1923-
match func_ctx.info[result].ty {
1924-
proc::TypeResolution::Handle(handle) => self.write_type(module, handle)?,
1925-
proc::TypeResolution::Value(ref value) => {
1926-
self.write_value_type(module, value)?
1922+
let res_name = match result {
1923+
None => None,
1924+
Some(result) => {
1925+
let name = format!("{}{}", back::BAKE_PREFIX, result.index());
1926+
match func_ctx.info[result].ty {
1927+
proc::TypeResolution::Handle(handle) => {
1928+
self.write_type(module, handle)?
1929+
}
1930+
proc::TypeResolution::Value(ref value) => {
1931+
self.write_value_type(module, value)?
1932+
}
1933+
};
1934+
write!(self.out, " {name}; ")?;
1935+
Some((result, name))
19271936
}
19281937
};
19291938

@@ -1934,7 +1943,6 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
19341943
.unwrap();
19351944

19361945
let fun_str = fun.to_hlsl_suffix();
1937-
write!(self.out, " {res_name}; ")?;
19381946
match pointer_space {
19391947
crate::AddressSpace::WorkGroup => {
19401948
write!(self.out, "Interlocked{fun_str}(")?;
@@ -1970,56 +1978,16 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
19701978
_ => {}
19711979
}
19721980
self.write_expr(module, value, func_ctx)?;
1973-
writeln!(self.out, ", {res_name});")?;
1974-
self.named_expressions.insert(result, res_name);
1975-
}
1976-
Statement::AtomicNoReturn {
1977-
pointer,
1978-
ref fun,
1979-
value,
1980-
} => {
1981-
write!(self.out, "{level}")?;
1982-
let res_name = format!("{}_discard{}", back::BAKE_PREFIX, pointer.index());
1983-
match func_ctx.info[value].ty {
1984-
proc::TypeResolution::Handle(handle) => self.write_type(module, handle)?,
1985-
proc::TypeResolution::Value(ref value) => {
1986-
self.write_value_type(module, value)?
1987-
}
1988-
};
1989-
1990-
// Validation ensures that `pointer` has a `Pointer` type.
1991-
let pointer_space = func_ctx
1992-
.resolve_type(pointer, &module.types)
1993-
.pointer_space()
1994-
.unwrap();
19951981

1996-
let fun_str = fun.to_hlsl_suffix();
1997-
write!(self.out, " {res_name}; ")?;
1998-
match pointer_space {
1999-
crate::AddressSpace::WorkGroup => {
2000-
write!(self.out, "Interlocked{fun_str}(")?;
2001-
self.write_expr(module, pointer, func_ctx)?;
2002-
}
2003-
crate::AddressSpace::Storage { .. } => {
2004-
let var_handle = self.fill_access_chain(module, pointer, func_ctx)?;
2005-
// The call to `self.write_storage_address` wants
2006-
// mutable access to all of `self`, so temporarily take
2007-
// ownership of our reusable access chain buffer.
2008-
let chain = mem::take(&mut self.temp_access_chain);
2009-
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
2010-
write!(self.out, "{var_name}.Interlocked{fun_str}(")?;
2011-
self.write_storage_address(module, &chain, func_ctx)?;
2012-
self.temp_access_chain = chain;
2013-
}
2014-
ref other => {
2015-
return Err(Error::Custom(format!(
2016-
"invalid address space {other:?} for atomic statement"
2017-
)))
2018-
}
1982+
// The `original_value` out parameter is optional for all the
1983+
// `Interlocked` functions we generate other than
1984+
// `InterlockedExchange`.
1985+
if let Some((result, name)) = res_name {
1986+
write!(self.out, ", {name}")?;
1987+
self.named_expressions.insert(result, name);
20191988
}
2020-
write!(self.out, ", ")?;
2021-
self.write_expr(module, value, func_ctx)?;
2022-
writeln!(self.out, ", {res_name});")?;
1989+
1990+
writeln!(self.out, ");")?;
20231991
}
20241992
Statement::WorkGroupUniformLoad { pointer, result } => {
20251993
self.write_barrier(crate::Barrier::WORK_GROUP, level)?;

naga/src/back/msl/mod.rs

+5-27
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/*!
22
Backend for [MSL][msl] (Metal Shading Language).
33
4+
This backend does not support the [`SHADER_INT64_ATOMIC_ALL_OPS`][all-atom]
5+
capability.
6+
47
## Binding model
58
69
Metal's bindings are flat per resource. Since there isn't an obvious mapping
@@ -24,6 +27,8 @@ For the result type, if it's a structure, we re-compose it with a temporary valu
2427
holding the result.
2528
2629
[msl]: https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
30+
[all-atom]: crate::valid::Capabilities::SHADER_INT64_ATOMIC_ALL_OPS
31+
2732
*/
2833

2934
use crate::{arena::Handle, proc::index, valid::ModuleInfo};
@@ -661,30 +666,3 @@ fn test_error_size() {
661666
use std::mem::size_of;
662667
assert_eq!(size_of::<Error>(), 32);
663668
}
664-
665-
impl crate::AtomicFunction {
666-
fn to_msl(self) -> Result<&'static str, Error> {
667-
Ok(match self {
668-
Self::Add => "fetch_add",
669-
Self::Subtract => "fetch_sub",
670-
Self::And => "fetch_and",
671-
Self::InclusiveOr => "fetch_or",
672-
Self::ExclusiveOr => "fetch_xor",
673-
Self::Min => "fetch_min",
674-
Self::Max => "fetch_max",
675-
Self::Exchange { compare: None } => "exchange",
676-
Self::Exchange { compare: Some(_) } => Err(Error::FeatureNotImplemented(
677-
"atomic CompareExchange".to_string(),
678-
))?,
679-
})
680-
}
681-
}
682-
683-
impl crate::AtomicFunctionNoReturn {
684-
const fn to_msl(self) -> &'static str {
685-
match self {
686-
Self::Min => "min",
687-
Self::Max => "max",
688-
}
689-
}
690-
}

naga/src/back/msl/writer.rs

+42-20
Original file line numberDiff line numberDiff line change
@@ -3058,27 +3058,21 @@ impl<W: Write> Writer<W> {
30583058
value,
30593059
result,
30603060
} => {
3061+
// This backend supports `SHADER_INT64_ATOMIC_MIN_MAX` but not
3062+
// `SHADER_INT64_ATOMIC_ALL_OPS`, so we can assume that if `result` is
3063+
// `Some`, we are not operating on a 64-bit value, and that if we are
3064+
// operating on a 64-bit value, `result` is `None`.
30613065
write!(self.out, "{level}")?;
3062-
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
3063-
self.start_baking_expression(result, &context.expression, &res_name)?;
3064-
self.named_expressions.insert(result, res_name);
3065-
let fun_str = fun.to_msl()?;
3066-
self.put_atomic_operation(pointer, fun_str, value, &context.expression)?;
3067-
// done
3068-
writeln!(self.out, ";")?;
3069-
}
3070-
crate::Statement::AtomicNoReturn {
3071-
pointer,
3072-
ref fun,
3073-
value,
3074-
} => {
3075-
write!(self.out, "{level}")?;
3076-
let fun_str =
3077-
if context.expression.resolve_type(value).scalar_width() != Some(8) {
3078-
fun.with_return().to_msl()?
3079-
} else {
3080-
fun.to_msl()
3081-
};
3066+
let fun_str = if let Some(result) = result {
3067+
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
3068+
self.start_baking_expression(result, &context.expression, &res_name)?;
3069+
self.named_expressions.insert(result, res_name);
3070+
fun.to_msl()?
3071+
} else if context.expression.resolve_type(value).scalar_width() == Some(8) {
3072+
fun.to_msl_64_bit()?
3073+
} else {
3074+
fun.to_msl()?
3075+
};
30823076

30833077
self.put_atomic_operation(pointer, fun_str, value, &context.expression)?;
30843078
// done
@@ -5931,3 +5925,31 @@ fn test_stack_size() {
59315925
}
59325926
}
59335927
}
5928+
5929+
impl crate::AtomicFunction {
5930+
fn to_msl(self) -> Result<&'static str, Error> {
5931+
Ok(match self {
5932+
Self::Add => "fetch_add",
5933+
Self::Subtract => "fetch_sub",
5934+
Self::And => "fetch_and",
5935+
Self::InclusiveOr => "fetch_or",
5936+
Self::ExclusiveOr => "fetch_xor",
5937+
Self::Min => "fetch_min",
5938+
Self::Max => "fetch_max",
5939+
Self::Exchange { compare: None } => "exchange",
5940+
Self::Exchange { compare: Some(_) } => Err(Error::FeatureNotImplemented(
5941+
"atomic CompareExchange".to_string(),
5942+
))?,
5943+
})
5944+
}
5945+
5946+
fn to_msl_64_bit(self) -> Result<&'static str, Error> {
5947+
Ok(match self {
5948+
Self::Min => "min",
5949+
Self::Max => "max",
5950+
_ => Err(Error::FeatureNotImplemented(
5951+
"64-bit atomic operation other than min/max".to_string(),
5952+
))?,
5953+
})
5954+
}
5955+
}

naga/src/back/pipeline_constants.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,9 @@ fn adjust_stmt(new_pos: &[Handle<Expression>], stmt: &mut Statement) {
617617
} => {
618618
adjust(pointer);
619619
adjust(value);
620-
adjust(result);
620+
if let Some(ref mut result) = *result {
621+
adjust(result);
622+
}
621623
match *fun {
622624
crate::AtomicFunction::Exchange {
623625
compare: Some(ref mut compare),
@@ -634,14 +636,6 @@ fn adjust_stmt(new_pos: &[Handle<Expression>], stmt: &mut Statement) {
634636
| crate::AtomicFunction::Exchange { compare: None } => {}
635637
}
636638
}
637-
crate::Statement::AtomicNoReturn {
638-
ref mut pointer,
639-
ref mut value,
640-
fun: _,
641-
} => {
642-
adjust(pointer);
643-
adjust(value);
644-
}
645639
Statement::WorkGroupUniformLoad {
646640
ref mut pointer,
647641
ref mut result,

0 commit comments

Comments
 (0)