diff --git a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index a86f34ab6ab..25cd1c66ce1 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -431,7 +431,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .def(self), _ => self.fatal(format!("memset on float width {width} not implemented yet")), }, - SpirvType::Adt { .. } => self.fatal("memset on structs not implemented yet"), + SpirvType::Adt { field_types, .. } => { + let field_pats: Vec<_> = field_types + .iter() + .map(|&field_ty| { + self.memset_const_pattern(&self.lookup_type(field_ty), fill_byte) + }) + .collect(); + self.constant_composite(ty.def(self.span(), self), field_pats.into_iter()) + .def(self) + } SpirvType::Vector { element, count, .. } | SpirvType::Matrix { element, count } => { let elem_pat = self.memset_const_pattern(&self.lookup_type(element), fill_byte); self.constant_composite( @@ -485,7 +494,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 64 => memset_dynamic_scalar(self, fill_var, 8, true), _ => self.fatal(format!("memset on float width {width} not implemented yet")), }, - SpirvType::Adt { .. } => self.fatal("memset on structs not implemented yet"), + SpirvType::Adt { field_types, .. } => { + let field_pats: Vec<_> = field_types + .iter() + .map(|&field_ty| { + self.memset_dynamic_pattern(&self.lookup_type(field_ty), fill_var) + }) + .collect(); + self.emit() + .composite_construct(ty.def(self.span(), self), None, field_pats) + .unwrap() + } SpirvType::Array { element, count } => { let elem_pat = self.memset_dynamic_pattern(&self.lookup_type(element), fill_var); let count = self.builder.lookup_const_scalar(count).unwrap() as usize; diff --git a/tests/compiletests/ui/lang/core/struct/init_struct_zeroed.rs b/tests/compiletests/ui/lang/core/struct/init_struct_zeroed.rs new file mode 100644 index 00000000000..1953182c965 --- /dev/null +++ b/tests/compiletests/ui/lang/core/struct/init_struct_zeroed.rs @@ -0,0 +1,39 @@ +// build-pass + +use spirv_std::spirv; + +/// Regression test for `memset` on structs, which used to `fatal!("memset on structs not +/// implemented yet")`. `core::ptr::write_bytes` on a struct-typed pointer (as used internally +/// by e.g. `core::mem::zeroed::()`) lowers to a single `memset` whose pointee type is the +/// struct itself, rather than one of its fields. +/// +/// +#[derive(Clone, Copy)] +pub struct Foo { + a: u32, + b: [u8; 7], + c: u64, +} + +/// Exercises `memset_const_pattern` for `SpirvType::Adt`, since both the fill byte and the size +/// are known at compile time. +pub fn zeroed_struct() -> Foo { + unsafe { core::mem::zeroed() } +} + +/// Exercises `memset_dynamic_pattern` for `SpirvType::Adt`, since the fill byte is not known at +/// compile time. +pub fn filled_struct(byte: u8) -> Foo { + let mut foo = Foo { + a: 0, + b: [0; 7], + c: 0, + }; + unsafe { + core::ptr::write_bytes(&mut foo, byte, 1); + } + foo +} + +#[spirv(fragment)] +pub fn main() {}