diff --git a/Cargo.lock b/Cargo.lock index fdc5a17b1c..3f481bcda4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,11 +413,10 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.36" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ - "find-msvc-tools", "jobserver", "libc", "shlex", @@ -1014,12 +1013,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "find-msvc-tools" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" - [[package]] name = "fixedbitset" version = "0.5.7" @@ -1260,8 +1253,7 @@ dependencies = [ [[package]] name = "glam" version = "0.30.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d1aab06663bdce00d6ca5e5ed586ec8d18033a771906c993a1e3755b368d85" +source = "git+https://github.com/bitshifter/glam-rs?rev=d1a2837b080c6443c055b275048d7609dee1bc16#d1a2837b080c6443c055b275048d7609dee1bc16" dependencies = [ "bytemuck", "libm", diff --git a/Cargo.toml b/Cargo.toml index 7cf0998410..226ba77a41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ difftest = { path = "tests/difftests/lib" } tracing = "0.1" tracing-subscriber = { version = "0.3.20", features = ["env-filter", "json"] } num-traits = { version = "0.2.15", default-features = false } -glam = { version = ">=0.22, <=0.30", default-features = false } +glam = { version = ">=0.22, <=0.30", git = "https://github.com/bitshifter/glam-rs", rev = "d1a2837b080c6443c055b275048d7609dee1bc16", default-features = false } libm = { version = "0.2.5", default-features = false } bytemuck = { version = "1.23", features = ["derive"] } diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index 3c0c025845..b89bc65482 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -8,12 +8,10 @@ use itertools::Itertools; use rspirv::spirv::{Dim, ImageFormat, StorageClass, Word}; use rustc_abi::ExternAbi as Abi; use rustc_abi::{ - Align, BackendRepr, FieldIdx, FieldsShape, HasDataLayout as _, LayoutData, Primitive, - ReprFlags, ReprOptions, Scalar, Size, TagEncoding, VariantIdx, Variants, + Align, BackendRepr, FieldIdx, FieldsShape, Primitive, Scalar, Size, VariantIdx, Variants, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; -use rustc_hashes::Hash64; use rustc_index::Idx; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; @@ -98,267 +96,6 @@ pub(crate) fn provide(providers: &mut Providers) { Ok(readjust_fn_abi(tcx, result?)) }; - // FIXME(eddyb) remove this by deriving `Clone` for `LayoutData` upstream. - fn clone_layout( - layout: &LayoutData, - ) -> LayoutData { - let LayoutData { - ref fields, - ref variants, - backend_repr, - largest_niche, - uninhabited, - align, - size, - max_repr_align, - unadjusted_abi_align, - randomization_seed, - } = *layout; - LayoutData { - fields: match *fields { - FieldsShape::Primitive => FieldsShape::Primitive, - FieldsShape::Union(count) => FieldsShape::Union(count), - FieldsShape::Array { stride, count } => FieldsShape::Array { stride, count }, - FieldsShape::Arbitrary { - ref offsets, - ref memory_index, - } => FieldsShape::Arbitrary { - offsets: offsets.clone(), - memory_index: memory_index.clone(), - }, - }, - variants: match *variants { - Variants::Empty => Variants::Empty, - Variants::Single { index } => Variants::Single { index }, - Variants::Multiple { - tag, - ref tag_encoding, - tag_field, - ref variants, - } => Variants::Multiple { - tag, - tag_encoding: match *tag_encoding { - TagEncoding::Direct => TagEncoding::Direct, - TagEncoding::Niche { - untagged_variant, - ref niche_variants, - niche_start, - } => TagEncoding::Niche { - untagged_variant, - niche_variants: niche_variants.clone(), - niche_start, - }, - }, - tag_field, - variants: variants.clone(), - }, - }, - backend_repr, - largest_niche, - uninhabited, - align, - size, - max_repr_align, - unadjusted_abi_align, - randomization_seed, - } - } - - providers.layout_of = |tcx, key| { - // HACK(eddyb) to special-case any types at all, they must be normalized, - // but when normalization would be needed, `layout_of`'s default provider - // recurses (supposedly for caching reasons), i.e. its calls `layout_of` - // w/ the normalized type in input, which once again reaches this hook, - // without ever needing any explicit normalization here. - let ty = key.value; - - // HACK(eddyb) bypassing upstream `#[repr(simd)]` changes (see also - // the later comment above `check_well_formed`, for more details). - let reimplement_old_style_repr_simd = match ty.kind() { - ty::Adt(def, args) if def.repr().simd() && !def.repr().packed() && def.is_struct() => { - Some(def.non_enum_variant()).and_then(|v| { - let (count, e_ty) = v - .fields - .iter() - .map(|f| f.ty(tcx, args)) - .dedup_with_count() - .exactly_one() - .ok()?; - let e_len = u64::try_from(count).ok().filter(|&e_len| e_len > 1)?; - Some((def, e_ty, e_len)) - }) - } - _ => None, - }; - - // HACK(eddyb) tweaked copy of the old upstream logic for `#[repr(simd)]`: - // https://github.com/rust-lang/rust/blob/1.86.0/compiler/rustc_ty_utils/src/layout.rs#L464-L590 - if let Some((adt_def, e_ty, e_len)) = reimplement_old_style_repr_simd { - let cx = rustc_middle::ty::layout::LayoutCx::new( - tcx, - key.typing_env.with_post_analysis_normalized(tcx), - ); - let dl = cx.data_layout(); - - // Compute the ABI of the element type: - let e_ly = cx.layout_of(e_ty)?; - let BackendRepr::Scalar(e_repr) = e_ly.backend_repr else { - // This error isn't caught in typeck, e.g., if - // the element type of the vector is generic. - tcx.dcx().span_fatal( - tcx.def_span(adt_def.did()), - format!( - "SIMD type `{ty}` with a non-primitive-scalar \ - (integer/float/pointer) element type `{}`", - e_ly.ty - ), - ); - }; - - // Compute the size and alignment of the vector: - let size = e_ly.size.checked_mul(e_len, dl).unwrap(); - let align = dl.llvmlike_vector_align(size); - let size = size.align_to(align.abi); - - let layout = tcx.mk_layout(LayoutData { - variants: Variants::Single { - index: rustc_abi::FIRST_VARIANT, - }, - fields: FieldsShape::Array { - stride: e_ly.size, - count: e_len, - }, - backend_repr: BackendRepr::SimdVector { - element: e_repr, - count: e_len, - }, - largest_niche: e_ly.largest_niche, - uninhabited: false, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: e_ly.randomization_seed.wrapping_add(Hash64::new(e_len)), - }); - - return Ok(TyAndLayout { ty, layout }); - } - - let TyAndLayout { ty, mut layout } = - (rustc_interface::DEFAULT_QUERY_PROVIDERS.layout_of)(tcx, key)?; - - #[allow(clippy::match_like_matches_macro)] - let hide_niche = match ty.kind() { - ty::Bool => { - // HACK(eddyb) we can't bypass e.g. `Option` being a byte, - // due to `core` PR https://github.com/rust-lang/rust/pull/138881 - // (which adds a new `transmute`, from `ControlFlow` to `u8`). - let libcore_needs_bool_niche = true; - - !libcore_needs_bool_niche - } - _ => false, - }; - - if hide_niche { - layout = tcx.mk_layout(LayoutData { - largest_niche: None, - ..clone_layout(layout.0.0) - }); - } - - Ok(TyAndLayout { ty, layout }) - }; - - // HACK(eddyb) work around https://github.com/rust-lang/rust/pull/129403 - // banning "struct-style" `#[repr(simd)]` (in favor of "array-newtype-style"), - // by simply bypassing "type definition WF checks" for affected types, which: - // - can only really be sound for types with trivial field types, that are - // either completely non-generic (covering most `#[repr(simd)]` `struct`s), - // or *at most* one generic type parameter with no bounds/where clause - // - relies on upstream `layout_of` not having had the non-array logic removed - // - // FIXME(eddyb) remove this once migrating beyond `#[repr(simd)]` becomes - // an option (may require Rust-GPU distinguishing between "SPIR-V interface" - // and "Rust-facing" types, which is even worse when the `OpTypeVector`s - // may be e.g. nested in `struct`s/arrays/etc. - at least buffers are easy). - // - // FIXME(eddyb) maybe using `#[spirv(vector)]` and `BackendRepr::Memory`, - // no claims at `rustc`-understood SIMD whatsoever, would be enough? - // (i.e. only SPIR-V caring about such a type vs a struct/array) - providers.check_well_formed = |tcx, def_id| { - let trivial_struct = match tcx.hir_node_by_def_id(def_id) { - rustc_hir::Node::Item(item) => match item.kind { - rustc_hir::ItemKind::Struct( - _, - &rustc_hir::Generics { - params: - &[] - | &[ - rustc_hir::GenericParam { - kind: - rustc_hir::GenericParamKind::Type { - default: None, - synthetic: false, - }, - .. - }, - ], - predicates: &[], - has_where_clause_predicates: false, - where_clause_span: _, - span: _, - }, - _, - ) => Some(tcx.adt_def(def_id)), - _ => None, - }, - _ => None, - }; - let valid_non_array_simd_struct = trivial_struct.is_some_and(|adt_def| { - let ReprOptions { - int: None, - align: None, - pack: None, - flags: ReprFlags::IS_SIMD, - field_shuffle_seed: _, - } = adt_def.repr() - else { - return false; - }; - if adt_def.destructor(tcx).is_some() { - return false; - } - - let field_types = adt_def - .non_enum_variant() - .fields - .iter() - .map(|f| tcx.type_of(f.did).instantiate_identity()); - field_types.dedup().exactly_one().is_ok_and(|elem_ty| { - matches!( - elem_ty.kind(), - ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Param(_) - ) - }) - }); - - if valid_non_array_simd_struct { - tcx.dcx() - .struct_span_warn( - tcx.def_span(def_id), - "[Rust-GPU] temporarily re-allowing old-style `#[repr(simd)]` (with fields)", - ) - .with_note("removed upstream by https://github.com/rust-lang/rust/pull/129403") - .with_note("in favor of the new `#[repr(simd)] struct TxN([T; N]);` style") - .with_note("(taking effect since `nightly-2024-09-12` / `1.83.0` stable)") - .emit(); - return Ok(()); - } - - (rustc_interface::DEFAULT_QUERY_PROVIDERS.check_well_formed)(tcx, def_id) - }; - // HACK(eddyb) work around https://github.com/rust-lang/rust/pull/132173 // (and further changes from https://github.com/rust-lang/rust/pull/132843) // starting to ban SIMD ABI misuse (or at least starting to warn about it). @@ -639,6 +376,8 @@ impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> { SpirvType::Vector { element: elem_spirv, count: count as u32, + size: self.size, + align: self.align.abi, } .def(span, cx) } @@ -655,7 +394,7 @@ pub fn scalar_pair_element_backend_type<'tcx>( ty: TyAndLayout<'tcx>, index: usize, ) -> Word { - let [a, b] = match ty.layout.backend_repr() { + let [a, b] = match ty.backend_repr { BackendRepr::ScalarPair(a, b) => [a, b], other => span_bug!( span, @@ -971,6 +710,10 @@ fn def_id_for_spirv_type_adt(layout: TyAndLayout<'_>) -> Option { } } +fn span_for_spirv_type_adt(cx: &CodegenCx<'_>, layout: TyAndLayout<'_>) -> Option { + def_id_for_spirv_type_adt(layout).map(|did| cx.tcx.def_span(did)) +} + /// Minimal and cheaply comparable/hashable subset of the information contained /// in `TyLayout` that can be used to generate a name (assuming a nominal type). #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -1220,43 +963,94 @@ fn trans_intrinsic_type<'tcx>( } } IntrinsicType::Matrix => { - let span = def_id_for_spirv_type_adt(ty) - .map(|did| cx.tcx.def_span(did)) - .expect("#[spirv(matrix)] must be added to a type which has DefId"); - - let field_types = (0..ty.fields.count()) - .map(|i| ty.field(cx, i).spirv_type(span, cx)) - .collect::>(); - if field_types.len() < 2 { - return Err(cx - .tcx - .dcx() - .span_err(span, "#[spirv(matrix)] type must have at least two fields")); - } - let elem_type = field_types[0]; - if !field_types.iter().all(|&ty| ty == elem_type) { - return Err(cx.tcx.dcx().span_err( - span, - "#[spirv(matrix)] type fields must all be the same type", - )); - } - match cx.lookup_type(elem_type) { + let span = span_for_spirv_type_adt(cx, ty).unwrap(); + let (element, count) = + trans_glam_like_struct(cx, span, ty, args, "`#[spirv(matrix)]`")?; + match cx.lookup_type(element) { SpirvType::Vector { .. } => (), ty => { return Err(cx .tcx .dcx() - .struct_span_err(span, "#[spirv(matrix)] type fields must all be vectors") - .with_note(format!("field type is {}", ty.debug(elem_type, cx))) + .struct_span_err(span, "`#[spirv(matrix)]` type fields must all be vectors") + .with_note(format!("field type is {}", ty.debug(element, cx))) .emit()); } } - - Ok(SpirvType::Matrix { - element: elem_type, - count: field_types.len() as u32, + Ok(SpirvType::Matrix { element, count }.def(span, cx)) + } + IntrinsicType::Vector => { + let span = span_for_spirv_type_adt(cx, ty).unwrap(); + let (element, count) = + trans_glam_like_struct(cx, span, ty, args, "`#[spirv(vector)]`")?; + match cx.lookup_type(element) { + SpirvType::Bool | SpirvType::Float { .. } | SpirvType::Integer { .. } => (), + ty => { + return Err(cx + .tcx + .dcx() + .struct_span_err( + span, + "`#[spirv(vector)]` type fields must all be floats, integers or bools", + ) + .with_note(format!("field type is {}", ty.debug(element, cx))) + .emit()); + } + } + Ok(SpirvType::Vector { + element, + count, + size: ty.size, + align: ty.align.abi, } .def(span, cx)) } } } + +/// A struct with multiple fields of the same kind +/// Used for `#[spirv(vector)]` and `#[spirv(matrix)]` +fn trans_glam_like_struct<'tcx>( + cx: &CodegenCx<'tcx>, + span: Span, + ty: TyAndLayout<'tcx>, + args: GenericArgsRef<'tcx>, + err_attr_name: &str, +) -> Result<(Word, u32), ErrorGuaranteed> { + let tcx = cx.tcx; + if let Some(adt) = ty.ty.ty_adt_def() + && adt.is_struct() + { + let (count, element) = adt + .non_enum_variant() + .fields + .iter() + .map(|f| f.ty(tcx, args)) + .dedup_with_count() + .exactly_one() + .map_err(|_e| { + tcx.dcx().span_err( + span, + format!("{err_attr_name} member types must all be the same"), + ) + })?; + + let element = cx.layout_of(element); + let element_word = element.spirv_type(span, cx); + let count = u32::try_from(count) + .ok() + .filter(|count| *count >= 2) + .ok_or_else(|| { + tcx.dcx().span_err( + span, + format!("{err_attr_name} must have at least 2 members"), + ) + })?; + + Ok((element_word, count)) + } else { + Err(tcx + .dcx() + .span_err(span, "#[spirv(vector)] type must be a struct")) + } +} diff --git a/crates/rustc_codegen_spirv/src/attr.rs b/crates/rustc_codegen_spirv/src/attr.rs index b35dbb6c3c..ff77050faa 100644 --- a/crates/rustc_codegen_spirv/src/attr.rs +++ b/crates/rustc_codegen_spirv/src/attr.rs @@ -66,6 +66,7 @@ pub enum IntrinsicType { RuntimeArray, TypedBuffer, Matrix, + Vector, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index 30fc1ae6c9..a8578b485f 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -317,10 +317,12 @@ fn memset_dynamic_scalar( byte_width: usize, is_float: bool, ) -> Word { - let composite_type = SpirvType::Vector { - element: SpirvType::Integer(8, false).def(builder.span(), builder), - count: byte_width as u32, - } + let composite_type = SpirvType::simd_vector( + builder, + builder.span(), + SpirvType::Integer(8, false), + byte_width as u32, + ) .def(builder.span(), builder); let composite = builder .emit() @@ -417,7 +419,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => self.fatal(format!("memset on float width {width} not implemented yet")), }, SpirvType::Adt { .. } => self.fatal("memset on structs not implemented yet"), - SpirvType::Vector { element, count } | SpirvType::Matrix { element, count } => { + SpirvType::Vector { element, count, .. } | SpirvType::Matrix { element, count } => { let elem_pat = self.memset_const_pattern(&self.lookup_type(element), fill_byte); self.constant_composite( ty.def(self.span(), self), @@ -478,7 +480,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) .unwrap() } - SpirvType::Vector { element, count } | SpirvType::Matrix { element, count } => { + SpirvType::Vector { element, count, .. } | SpirvType::Matrix { element, count } => { let elem_pat = self.memset_dynamic_pattern(&self.lookup_type(element), fill_var); self.emit() .composite_construct( @@ -2966,11 +2968,9 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn vector_splat(&mut self, num_elts: usize, elt: Self::Value) -> Self::Value { - let result_type = SpirvType::Vector { - element: elt.ty, - count: num_elts as u32, - } - .def(self.span(), self); + let result_type = + SpirvType::simd_vector(self, self.span(), self.lookup_type(elt.ty), num_elts as u32) + .def(self.span(), self); if self.builder.lookup_const(elt).is_some() { self.constant_composite(result_type, iter::repeat_n(elt.def(self), num_elts)) } else { @@ -3007,6 +3007,9 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { fn insert_value(&mut self, agg_val: Self::Value, elt: Self::Value, idx: u64) -> Self::Value { let field_type = match self.lookup_type(agg_val.ty) { SpirvType::Adt { field_types, .. } => field_types[idx as usize], + SpirvType::Array { element, .. } + | SpirvType::Vector { element, .. } + | SpirvType::Matrix { element, .. } => element, other => self.fatal(format!("insert_value not implemented on type {other:?}")), }; diff --git a/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs b/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs index ab2a78cf65..89c488c082 100644 --- a/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs +++ b/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let val = self.load_u32(array, dynamic_word_index, constant_word_offset); self.bitcast(val, result_type) } - SpirvType::Vector { element, count } | SpirvType::Matrix { element, count } => self + SpirvType::Vector { element, count, .. } | SpirvType::Matrix { element, count } => self .load_vec_mat_arr( original_type, result_type, @@ -312,7 +312,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let value_u32 = self.bitcast(value, u32_ty); self.store_u32(array, dynamic_word_index, constant_word_offset, value_u32) } - SpirvType::Vector { element, count } | SpirvType::Matrix { element, count } => self + SpirvType::Vector { element, count, .. } | SpirvType::Matrix { element, count } => self .store_vec_mat_arr( original_type, value, diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index 8441d74c08..894c5a8d02 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -728,6 +728,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { SpirvType::Vector { element: ty, count: 4, + .. }, ) | ( diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs index eb8783049c..acd9b42172 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs @@ -200,10 +200,12 @@ impl ConstCodegenMethods for CodegenCx<'_> { self.constant_composite(struct_ty, elts.iter().map(|f| f.def_cx(self))) } fn const_vector(&self, elts: &[Self::Value]) -> Self::Value { - let vector_ty = SpirvType::Vector { - element: elts[0].ty, - count: elts.len() as u32, - } + let vector_ty = SpirvType::simd_vector( + self, + DUMMY_SP, + self.lookup_type(elts[0].ty), + elts.len() as u32, + ) .def(DUMMY_SP, self); self.constant_composite(vector_ty, elts.iter().map(|elt| elt.def_cx(self))) } diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs index 5de823d261..786cf50781 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs @@ -11,7 +11,10 @@ use rspirv::dr::Operand; use rspirv::spirv::{ Capability, Decoration, Dim, ExecutionModel, FunctionControl, StorageClass, Word, }; -use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods, MiscCodegenMethods as _}; +use rustc_codegen_ssa::traits::{ + BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods, + MiscCodegenMethods as _, +}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_hir as hir; @@ -86,22 +89,7 @@ impl<'tcx> CodegenCx<'tcx> { }; for (arg_abi, hir_param) in fn_abi.args.iter().zip(hir_params) { match arg_abi.mode { - PassMode::Direct(_) => {} - PassMode::Pair(..) => { - // FIXME(eddyb) implement `ScalarPair` `Input`s, or change - // the `FnAbi` readjustment to only use `PassMode::Pair` for - // pointers to `!Sized` types, but not other `ScalarPair`s. - if !matches!(arg_abi.layout.ty.kind(), ty::Ref(..)) { - self.tcx.dcx().span_err( - hir_param.ty_span, - format!( - "entry point parameter type not yet supported \ - (`{}` has `ScalarPair` ABI but is not a `&T`)", - arg_abi.layout.ty - ), - ); - } - } + PassMode::Direct(_) | PassMode::Pair(..) => {} // FIXME(eddyb) support these (by just ignoring them) - if there // is any validation concern, it should be done on the types. PassMode::Ignore => self.tcx.dcx().span_fatal( @@ -442,6 +430,33 @@ impl<'tcx> CodegenCx<'tcx> { } = self.entry_param_deduce_from_rust_ref_or_value(entry_arg_abi.layout, hir_param, &attrs); let value_spirv_type = value_layout.spirv_type(hir_param.ty_span, self); + // In compute shaders, user-provided data must come from buffers or push + // constants, i.e. by-reference parameters. + if execution_model == ExecutionModel::GLCompute + && matches!(entry_arg_abi.mode, PassMode::Direct(_) | PassMode::Pair(..)) + && !matches!(entry_arg_abi.layout.ty.kind(), ty::Ref(..)) + && attrs.builtin.is_none() + { + let param_name = if let hir::PatKind::Binding(_, _, ident, _) = &hir_param.pat.kind { + ident.name.to_string() + } else { + "parameter".to_string() + }; + self.tcx + .dcx() + .struct_span_err( + hir_param.ty_span, + format!("compute entry parameter `{param_name}` must be by-reference",), + ) + .with_help(format!( + "consider changing the type to `&{}`", + entry_arg_abi.layout.ty + )) + .emit(); + // Keep this a hard error to stop compilation after emitting help. + self.tcx.dcx().abort_if_errors(); + } + let (var_id, spec_const_id) = match storage_class { // Pre-allocate the module-scoped `OpVariable` *Result* ID. Ok(_) => ( @@ -491,14 +506,6 @@ impl<'tcx> CodegenCx<'tcx> { vs layout:\n{value_layout:#?}", entry_arg_abi.layout.ty ); - if is_pair && !is_unsized { - // If PassMode is Pair, then we need to fill in the second part of the pair with a - // value. We currently only do that with unsized types, so if a type is a pair for some - // other reason (e.g. a tuple), we bail. - self.tcx - .dcx() - .span_fatal(hir_param.ty_span, "pair type not supported yet") - } // FIXME(eddyb) should this talk about "typed buffers" instead of "interface blocks"? // FIXME(eddyb) should we talk about "descriptor indexing" or // actually use more reasonable terms like "resource arrays"? @@ -621,8 +628,8 @@ impl<'tcx> CodegenCx<'tcx> { } } - let value_len = if is_pair { - // We've already emitted an error, fill in a placeholder value + let value_len = if is_pair && is_unsized { + // For wide references (e.g., slices), the second component is a length. Some(bx.undef(self.type_isize())) } else { None @@ -645,21 +652,54 @@ impl<'tcx> CodegenCx<'tcx> { _ => unreachable!(), } } else { - assert_matches!(entry_arg_abi.mode, PassMode::Direct(_)); - - let value = match storage_class { - Ok(_) => { + match entry_arg_abi.mode { + PassMode::Direct(_) => { + let value = match storage_class { + Ok(_) => { + assert_eq!(storage_class, Ok(StorageClass::Input)); + bx.load( + entry_arg_abi.layout.spirv_type(hir_param.ty_span, bx), + value_ptr.unwrap(), + entry_arg_abi.layout.align.abi, + ) + } + Err(SpecConstant { .. }) => { + spec_const_id.unwrap().with_type(value_spirv_type) + } + }; + call_args.push(value); + assert_eq!(value_len, None); + } + PassMode::Pair(..) => { + // Load both elements of the scalar pair from the input variable. assert_eq!(storage_class, Ok(StorageClass::Input)); - bx.load( - entry_arg_abi.layout.spirv_type(hir_param.ty_span, bx), - value_ptr.unwrap(), - entry_arg_abi.layout.align.abi, - ) + let layout = entry_arg_abi.layout; + let (a, b) = match layout.backend_repr { + rustc_abi::BackendRepr::ScalarPair(a, b) => (a, b), + other => span_bug!( + hir_param.ty_span, + "ScalarPair expected for entry param, found {other:?}" + ), + }; + let b_offset = a + .primitive() + .size(self) + .align_to(b.primitive().align(self).abi); + + let elem0_ty = self.scalar_pair_element_backend_type(layout, 0, false); + let elem1_ty = self.scalar_pair_element_backend_type(layout, 1, false); + + let base_ptr = value_ptr.unwrap(); + let ptr1 = bx.inbounds_ptradd(base_ptr, self.const_usize(b_offset.bytes())); + + let v0 = bx.load(elem0_ty, base_ptr, layout.align.abi); + let v1 = bx.load(elem1_ty, ptr1, layout.align.restrict_for_offset(b_offset)); + call_args.push(v0); + call_args.push(v1); + assert_eq!(value_len, None); } - Err(SpecConstant { .. }) => spec_const_id.unwrap().with_type(value_spirv_type), - }; - call_args.push(value); - assert_eq!(value_len, None); + _ => unreachable!(), + } } // FIXME(eddyb) check whether the storage class is compatible with the diff --git a/crates/rustc_codegen_spirv/src/spirv_type.rs b/crates/rustc_codegen_spirv/src/spirv_type.rs index 074e5708d1..c2d85dcbac 100644 --- a/crates/rustc_codegen_spirv/src/spirv_type.rs +++ b/crates/rustc_codegen_spirv/src/spirv_type.rs @@ -45,6 +45,8 @@ pub enum SpirvType<'tcx> { element: Word, /// Note: vector count is literal. count: u32, + size: Size, + align: Align, }, Matrix { element: Word, @@ -131,7 +133,9 @@ impl SpirvType<'_> { } result } - Self::Vector { element, count } => cx.emit_global().type_vector_id(id, element, count), + Self::Vector { element, count, .. } => { + cx.emit_global().type_vector_id(id, element, count) + } Self::Matrix { element, count } => cx.emit_global().type_matrix_id(id, element, count), Self::Array { element, count } => { let result = cx @@ -280,9 +284,7 @@ impl SpirvType<'_> { Self::Bool => Size::from_bytes(1), Self::Integer(width, _) | Self::Float(width) => Size::from_bits(width), Self::Adt { size, .. } => size?, - Self::Vector { element, count } => { - cx.lookup_type(element).sizeof(cx)? * count.next_power_of_two() as u64 - } + Self::Vector { size, .. } => size, Self::Matrix { element, count } => cx.lookup_type(element).sizeof(cx)? * count as u64, Self::Array { element, count } => { cx.lookup_type(element).sizeof(cx)? @@ -310,14 +312,7 @@ impl SpirvType<'_> { Self::Bool => Align::from_bytes(1).unwrap(), Self::Integer(width, _) | Self::Float(width) => Align::from_bits(width as u64).unwrap(), - Self::Adt { align, .. } => align, - // Vectors have size==align - Self::Vector { .. } => Align::from_bytes( - self.sizeof(cx) - .expect("alignof: Vectors must be sized") - .bytes(), - ) - .expect("alignof: Vectors must have power-of-2 size"), + Self::Adt { align, .. } | Self::Vector { align, .. } => align, Self::Array { element, .. } | Self::RuntimeArray { element } | Self::Matrix { element, .. } => cx.lookup_type(element).alignof(cx), @@ -382,7 +377,17 @@ impl SpirvType<'_> { SpirvType::Bool => SpirvType::Bool, SpirvType::Integer(width, signedness) => SpirvType::Integer(width, signedness), SpirvType::Float(width) => SpirvType::Float(width), - SpirvType::Vector { element, count } => SpirvType::Vector { element, count }, + SpirvType::Vector { + element, + count, + size, + align, + } => SpirvType::Vector { + element, + count, + size, + align, + }, SpirvType::Matrix { element, count } => SpirvType::Matrix { element, count }, SpirvType::Array { element, count } => SpirvType::Array { element, count }, SpirvType::RuntimeArray { element } => SpirvType::RuntimeArray { element }, @@ -435,6 +440,15 @@ impl SpirvType<'_> { }, } } + + pub fn simd_vector(cx: &CodegenCx<'_>, span: Span, element: SpirvType<'_>, count: u32) -> Self { + Self::Vector { + element: element.def(span, cx), + count, + size: element.sizeof(cx).unwrap() * count as u64, + align: element.alignof(cx), + } + } } impl<'a> SpirvType<'a> { @@ -501,11 +515,18 @@ impl fmt::Debug for SpirvTypePrinter<'_, '_> { .field("field_names", &field_names) .finish() } - SpirvType::Vector { element, count } => f + SpirvType::Vector { + element, + count, + size, + align, + } => f .debug_struct("Vector") .field("id", &self.id) .field("element", &self.cx.debug_type(element)) .field("count", &count) + .field("size", &size) + .field("align", &align) .finish(), SpirvType::Matrix { element, count } => f .debug_struct("Matrix") @@ -668,7 +689,7 @@ impl SpirvTypePrinter<'_, '_> { } f.write_str(" }") } - SpirvType::Vector { element, count } | SpirvType::Matrix { element, count } => { + SpirvType::Vector { element, count, .. } | SpirvType::Matrix { element, count } => { ty(self.cx, stack, f, element)?; write!(f, "x{count}") } diff --git a/crates/rustc_codegen_spirv/src/symbols.rs b/crates/rustc_codegen_spirv/src/symbols.rs index 4dfef5b4d3..92f20ecdf7 100644 --- a/crates/rustc_codegen_spirv/src/symbols.rs +++ b/crates/rustc_codegen_spirv/src/symbols.rs @@ -15,7 +15,7 @@ use std::rc::Rc; /// is to allocate all our keywords up front and intern them all, so we can do comparisons really easily and fast. pub struct Symbols { pub discriminant: Symbol, - pub rust_gpu: Symbol, + pub rustc_codegen_spirv: Symbol, pub spirv: Symbol, pub libm: Symbol, pub entry_point_name: Symbol, @@ -373,6 +373,10 @@ impl Symbols { "matrix", SpirvAttribute::IntrinsicType(IntrinsicType::Matrix), ), + ( + "vector", + SpirvAttribute::IntrinsicType(IntrinsicType::Vector), + ), ("buffer_load_intrinsic", SpirvAttribute::BufferLoadIntrinsic), ( "buffer_store_intrinsic", @@ -406,7 +410,7 @@ impl Symbols { } Self { discriminant: Symbol::intern("discriminant"), - rust_gpu: Symbol::intern("rust_gpu"), + rustc_codegen_spirv: Symbol::intern("rustc_codegen_spirv"), spirv: Symbol::intern("spirv"), libm: Symbol::intern("libm"), entry_point_name: Symbol::intern("entry_point_name"), @@ -450,34 +454,34 @@ pub(crate) fn parse_attrs_for_checking<'a>( Attribute::Unparsed(item) => { // #[...] let s = &item.path.segments; - if s.len() > 1 && s[0].name == sym.rust_gpu { - // #[rust_gpu ...] + if s.len() > 1 && s[0].name == sym.rustc_codegen_spirv { + // #[rustc_codegen_spirv ...] if s.len() != 2 || s[1].name != sym.spirv { - // #[rust_gpu::...] but not #[rust_gpu::spirv] + // #[rustc_codegen_spirv::...] but not #[rustc_codegen_spirv::spirv] ( Some(Err(( attr.span(), - "unknown `rust_gpu` attribute, expected `rust_gpu::spirv`" + "unknown `rustc_codegen_spirv` attribute, expected `rustc_codegen_spirv::spirv`" .to_string(), ))), Default::default(), ) } else if let Some(args) = attr.meta_item_list() { - // #[rust_gpu::spirv(...)] + // #[rustc_codegen_spirv::spirv(...)] (None, args) } else { - // #[rust_gpu::spirv] + // #[rustc_codegen_spirv::spirv] ( Some(Err(( attr.span(), - "#[rust_gpu::spirv(..)] attribute must have at least one argument" + "#[rustc_codegen_spirv::spirv(..)] attribute must have at least one argument" .to_string(), ))), Default::default(), ) } } else { - // #[...] but not #[rust_gpu ...] + // #[...] but not #[rustc_codegen_spirv ...] (None, Default::default()) } } diff --git a/crates/spirv-builder/src/lib.rs b/crates/spirv-builder/src/lib.rs index 51cc8d8f2a..86e1681885 100644 --- a/crates/spirv-builder/src/lib.rs +++ b/crates/spirv-builder/src/lib.rs @@ -862,7 +862,7 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result { "-Zbinary-dep-depinfo".to_string(), "-Csymbol-mangling-version=v0".to_string(), "-Zcrate-attr=feature(register_tool)".to_string(), - "-Zcrate-attr=register_tool(rust_gpu)".to_string(), + "-Zcrate-attr=register_tool(rustc_codegen_spirv)".to_string(), // HACK(eddyb) this is the same configuration that we test with, and // ensures no unwanted surprises from e.g. `core` debug assertions. "-Coverflow-checks=off".to_string(), diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index c1f0d57ab9..b4ccb893b2 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -140,14 +140,14 @@ pub fn Image(item: TokenStream) -> TokenStream { } /// Replaces all (nested) occurrences of the `#[spirv(..)]` attribute with -/// `#[cfg_attr(target_arch="spirv", rust_gpu::spirv(..))]`. +/// `#[cfg_attr(target_arch="spirv", rustc_codegen_spirv::spirv(..))]`. #[proc_macro_attribute] pub fn spirv(attr: TokenStream, item: TokenStream) -> TokenStream { let mut tokens: Vec = Vec::new(); - // prepend with #[rust_gpu::spirv(..)] + // prepend with #[rustc_codegen_spirv::spirv(..)] let attr: proc_macro2::TokenStream = attr.into(); - tokens.extend(quote! { #[cfg_attr(target_arch="spirv", rust_gpu::spirv(#attr))] }); + tokens.extend(quote! { #[cfg_attr(target_arch="spirv", rustc_codegen_spirv::spirv(#attr))] }); let item: proc_macro2::TokenStream = item.into(); for tt in item { @@ -164,7 +164,7 @@ pub fn spirv(attr: TokenStream, item: TokenStream) -> TokenStream { // group matches [spirv ...] let inner = group.stream(); // group stream doesn't include the brackets sub_tokens.extend( - quote! { [cfg_attr(target_arch="spirv", rust_gpu::#inner)] }, + quote! { [cfg_attr(target_arch="spirv", rustc_codegen_spirv::#inner)] }, ); } _ => sub_tokens.push(tt), diff --git a/crates/spirv-std/src/arch/subgroup.rs b/crates/spirv-std/src/arch/subgroup.rs index e9793db114..05798a6f1d 100644 --- a/crates/spirv-std/src/arch/subgroup.rs +++ b/crates/spirv-std/src/arch/subgroup.rs @@ -13,10 +13,7 @@ const SUBGROUP: u32 = Scope::Subgroup as u32; /// `SubgroupMask` is a [`glam::UVec4`] representing a bitmask of all invocations within a subgroup. /// Mostly used in group ballot operations. -#[repr(transparent)] -#[derive(Copy, Clone, Default, Eq, PartialEq)] -#[cfg_attr(feature = "bytemuck", derive(bytemuck::Zeroable, bytemuck::Pod))] -pub struct SubgroupMask(pub glam::UVec4); +pub type SubgroupMask = glam::UVec4; /// Defines the class of group operation. #[non_exhaustive] diff --git a/crates/spirv-std/src/vector.rs b/crates/spirv-std/src/vector.rs index 0385db83ac..7c4943ce17 100644 --- a/crates/spirv-std/src/vector.rs +++ b/crates/spirv-std/src/vector.rs @@ -49,6 +49,7 @@ impl_vector! { f64: glam::DVec2 => 2, glam::DVec3 => 3, glam::DVec4 => 4; u32: glam::UVec2 => 2, glam::UVec3 => 3, glam::UVec4 => 4; i32: glam::IVec2 => 2, glam::IVec3 => 3, glam::IVec4 => 4; + bool: glam::BVec2 => 2, glam::BVec3 => 3, glam::BVec4 => 4; } /// Trait that implements slicing of a vector into a scalar or vector of lower dimensions, by diff --git a/tests/compiletests/ui/arch/all.rs b/tests/compiletests/ui/arch/all.rs index 088e07f0a5..1d99c101cb 100644 --- a/tests/compiletests/ui/arch/all.rs +++ b/tests/compiletests/ui/arch/all.rs @@ -1,36 +1,11 @@ // build-pass -#![feature(repr_simd)] - use core::num::NonZeroUsize; use spirv_std::spirv; use spirv_std::{scalar::Scalar, vector::Vector, vector::VectorOrScalar}; -/// HACK(shesp). Rust doesn't allow us to declare regular (tuple-)structs containing `bool` members -/// as `#[repl(simd)]`. But we need this for `spirv_std::arch::any()` and `spirv_std::arch::all()` -/// to work. -/// Fortunately, this requirement isn't checked on generic structs, so we have a way to work around -/// it (for now at least) -#[repr(simd)] -#[derive(Copy, Clone, Debug)] -struct Vec2(T, T); -unsafe impl VectorOrScalar for Vec2 { - type Scalar = T; - const DIM: NonZeroUsize = match NonZeroUsize::new(2) { - None => panic!(), - Some(n) => n, - }; -} -unsafe impl Vector for Vec2 {} - -impl Default for Vec2 { - fn default() -> Vec2 { - Vec2(T::default(), T::default()) - } -} - #[spirv(fragment)] pub fn main() { - let vector = Vec2(true, true); + let vector = glam::BVec2::new(true, true); assert!(spirv_std::arch::all(vector)); } diff --git a/tests/compiletests/ui/arch/all.stderr b/tests/compiletests/ui/arch/all.stderr deleted file mode 100644 index beed8baf22..0000000000 --- a/tests/compiletests/ui/arch/all.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: [Rust-GPU] temporarily re-allowing old-style `#[repr(simd)]` (with fields) - --> $DIR/all.rs:16:1 - | -16 | struct Vec2(T, T); - | ^^^^^^^^^^^^^^ - | - = note: removed upstream by https://github.com/rust-lang/rust/pull/129403 - = note: in favor of the new `#[repr(simd)] struct TxN([T; N]);` style - = note: (taking effect since `nightly-2024-09-12` / `1.83.0` stable) - -warning: 1 warning emitted - diff --git a/tests/compiletests/ui/arch/any.rs b/tests/compiletests/ui/arch/any.rs index 9e8e1d2f3f..e113927411 100644 --- a/tests/compiletests/ui/arch/any.rs +++ b/tests/compiletests/ui/arch/any.rs @@ -1,36 +1,11 @@ // build-pass -#![feature(repr_simd)] - use core::num::NonZeroUsize; use spirv_std::spirv; use spirv_std::{scalar::Scalar, vector::Vector, vector::VectorOrScalar}; -/// HACK(shesp). Rust doesn't allow us to declare regular (tuple-)structs containing `bool` members -/// as `#[repl(simd)]`. But we need this for `spirv_std::arch::any()` and `spirv_std::arch::all()` -/// to work. -/// Fortunately, this requirement isn't checked on generic structs, so we have a way to work around -/// it (for now at least) -#[repr(simd)] -#[derive(Copy, Clone, Debug)] -struct Vec2(T, T); -unsafe impl VectorOrScalar for Vec2 { - type Scalar = T; - const DIM: NonZeroUsize = match NonZeroUsize::new(2) { - None => panic!(), - Some(n) => n, - }; -} -unsafe impl Vector for Vec2 {} - -impl Default for Vec2 { - fn default() -> Vec2 { - Vec2(T::default(), T::default()) - } -} - #[spirv(fragment)] pub fn main() { - let vector = Vec2(false, true); + let vector = glam::BVec2::new(false, true); assert!(spirv_std::arch::any(vector)); } diff --git a/tests/compiletests/ui/arch/any.stderr b/tests/compiletests/ui/arch/any.stderr deleted file mode 100644 index c01af8f3ba..0000000000 --- a/tests/compiletests/ui/arch/any.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: [Rust-GPU] temporarily re-allowing old-style `#[repr(simd)]` (with fields) - --> $DIR/any.rs:16:1 - | -16 | struct Vec2(T, T); - | ^^^^^^^^^^^^^^ - | - = note: removed upstream by https://github.com/rust-lang/rust/pull/129403 - = note: in favor of the new `#[repr(simd)] struct TxN([T; N]);` style - = note: (taking effect since `nightly-2024-09-12` / `1.83.0` stable) - -warning: 1 warning emitted - diff --git a/tests/compiletests/ui/arch/debug_printf_type_checking.stderr b/tests/compiletests/ui/arch/debug_printf_type_checking.stderr index 5c1b487bde..6ec5956a55 100644 --- a/tests/compiletests/ui/arch/debug_printf_type_checking.stderr +++ b/tests/compiletests/ui/arch/debug_printf_type_checking.stderr @@ -121,15 +121,15 @@ error[E0277]: the trait bound `{float}: Vector` is not satisfied | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Vector` is not implemented for `{float}` | = help: the following other types implement trait `Vector`: + `BVec2` implements `Vector` + `BVec3` implements `Vector` + `BVec4` implements `Vector` `DVec2` implements `Vector` `DVec3` implements `Vector` `DVec4` implements `Vector` `IVec2` implements `Vector` `IVec3` implements `Vector` - `IVec4` implements `Vector` - `UVec2` implements `Vector` - `UVec3` implements `Vector` - and 5 others + and 8 others note: required by a bound in `debug_printf_assert_is_vector` --> $SPIRV_STD_SRC/lib.rs:141:8 | diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_ballot.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_ballot.stderr index ffc7660bb9..a0994f5353 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_ballot.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_ballot.stderr @@ -1,9 +1,9 @@ %1 = OpFunction %2 None %3 %4 = OpFunctionParameter %2 %5 = OpLabel -OpLine %6 367 13 +OpLine %6 364 13 %7 = OpGroupNonUniformBallot %8 %9 %4 -OpLine %6 406 13 +OpLine %6 403 13 %10 = OpGroupNonUniformInverseBallot %2 %9 %7 OpNoLine OpReturnValue %10 diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_ballot_bit_count.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_ballot_bit_count.stderr index 0ecffc39c4..52b6bcf944 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_ballot_bit_count.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_ballot_bit_count.stderr @@ -1,7 +1,7 @@ %1 = OpFunction %2 None %3 %4 = OpFunctionParameter %5 %6 = OpLabel -OpLine %7 501 0 +OpLine %7 498 0 %8 = OpGroupNonUniformBallotBitCount %2 %9 Reduce %4 OpNoLine OpReturnValue %8 diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_first.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_first.stderr index 9bb737c779..44fa624f0e 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_first.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_first.stderr @@ -1,7 +1,7 @@ %1 = OpFunction %2 None %3 %4 = OpFunctionParameter %2 %5 = OpLabel -OpLine %6 334 13 +OpLine %6 331 13 %7 = OpGroupNonUniformBroadcastFirst %2 %8 %4 OpNoLine OpReturnValue %7 diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_0_fail.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_0_fail.stderr index 821239dc33..fe2f180d78 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_0_fail.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_0_fail.stderr @@ -1,27 +1,27 @@ error[E0080]: evaluation panicked: `ClusterSize` must be at least 1 - --> $SPIRV_STD_SRC/arch/subgroup.rs:829:1 + --> $SPIRV_STD_SRC/arch/subgroup.rs:826:1 | -829 | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" -830 | | An integer add group operation of all `value` operands contributed by active invocations in the group. -831 | | -832 | | Result Type must be a scalar or vector of integer type. +826 | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" +827 | | An integer add group operation of all `value` operands contributed by active invocations in the group. +828 | | +829 | | Result Type must be a scalar or vector of integer type. ... | -845 | | * `ClusterSize` must not be greater than the size of the group -846 | | "); +842 | | * `ClusterSize` must not be greater than the size of the group +843 | | "); | |__^ evaluation of `spirv_std::arch::subgroup_clustered_i_add::<0, u32, u32>::{constant#0}` failed here | = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `macro_subgroup_op_clustered` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered - --> $SPIRV_STD_SRC/arch/subgroup.rs:829:1 + --> $SPIRV_STD_SRC/arch/subgroup.rs:826:1 | -829 | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" -830 | | An integer add group operation of all `value` operands contributed by active invocations in the group. -831 | | -832 | | Result Type must be a scalar or vector of integer type. +826 | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" +827 | | An integer add group operation of all `value` operands contributed by active invocations in the group. +828 | | +829 | | Result Type must be a scalar or vector of integer type. ... | -845 | | * `ClusterSize` must not be greater than the size of the group -846 | | "); +842 | | * `ClusterSize` must not be greater than the size of the group +843 | | "); | |__^ | = note: this note originates in the macro `macro_subgroup_op_clustered` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_non_power_of_two_fail.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_non_power_of_two_fail.stderr index 8ef6ee7cb1..40c37e2740 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_non_power_of_two_fail.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_non_power_of_two_fail.stderr @@ -1,27 +1,27 @@ error[E0080]: evaluation panicked: `ClusterSize` must be a power of 2 - --> $SPIRV_STD_SRC/arch/subgroup.rs:829:1 + --> $SPIRV_STD_SRC/arch/subgroup.rs:826:1 | -829 | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" -830 | | An integer add group operation of all `value` operands contributed by active invocations in the group. -831 | | -832 | | Result Type must be a scalar or vector of integer type. +826 | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" +827 | | An integer add group operation of all `value` operands contributed by active invocations in the group. +828 | | +829 | | Result Type must be a scalar or vector of integer type. ... | -845 | | * `ClusterSize` must not be greater than the size of the group -846 | | "); +842 | | * `ClusterSize` must not be greater than the size of the group +843 | | "); | |__^ evaluation of `spirv_std::arch::subgroup_clustered_i_add::<5, u32, u32>::{constant#0}` failed here | = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `macro_subgroup_op_clustered` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered - --> $SPIRV_STD_SRC/arch/subgroup.rs:829:1 + --> $SPIRV_STD_SRC/arch/subgroup.rs:826:1 | -829 | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" -830 | | An integer add group operation of all `value` operands contributed by active invocations in the group. -831 | | -832 | | Result Type must be a scalar or vector of integer type. +826 | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" +827 | | An integer add group operation of all `value` operands contributed by active invocations in the group. +828 | | +829 | | Result Type must be a scalar or vector of integer type. ... | -845 | | * `ClusterSize` must not be greater than the size of the group -846 | | "); +842 | | * `ClusterSize` must not be greater than the size of the group +843 | | "); | |__^ | = note: this note originates in the macro `macro_subgroup_op_clustered` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_elect.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_elect.stderr index d18849b6f6..26a079b145 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_elect.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_elect.stderr @@ -1,6 +1,6 @@ %1 = OpFunction %2 None %3 %4 = OpLabel -OpLine %5 164 13 +OpLine %5 161 13 %6 = OpGroupNonUniformElect %2 %7 OpNoLine OpReturnValue %6 diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_i_add_clustered.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_i_add_clustered.stderr index 4d06f8f632..4c022abaf0 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_i_add_clustered.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_i_add_clustered.stderr @@ -1,7 +1,7 @@ %1 = OpFunction %2 None %3 %4 = OpFunctionParameter %2 %5 = OpLabel -OpLine %6 829 0 +OpLine %6 826 0 %7 = OpGroupNonUniformIAdd %2 %8 ClusteredReduce %4 %9 OpNoLine OpReturnValue %7 diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_i_add_exclusive_scan.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_i_add_exclusive_scan.stderr index 4890551e39..a5ec1af956 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_i_add_exclusive_scan.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_i_add_exclusive_scan.stderr @@ -1,7 +1,7 @@ %1 = OpFunction %2 None %3 %4 = OpFunctionParameter %2 %5 = OpLabel -OpLine %6 816 0 +OpLine %6 813 0 %7 = OpGroupNonUniformIAdd %2 %8 ExclusiveScan %4 OpNoLine OpReturnValue %7 diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_i_add_inclusive_scan.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_i_add_inclusive_scan.stderr index a41a806a40..b6fcceb39f 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_i_add_inclusive_scan.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_i_add_inclusive_scan.stderr @@ -1,7 +1,7 @@ %1 = OpFunction %2 None %3 %4 = OpFunctionParameter %2 %5 = OpLabel -OpLine %6 816 0 +OpLine %6 813 0 %7 = OpGroupNonUniformIAdd %2 %8 InclusiveScan %4 OpNoLine OpReturnValue %7 diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_i_add_reduce.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_i_add_reduce.stderr index 2e8d77e479..73fdd65b86 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_i_add_reduce.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_i_add_reduce.stderr @@ -1,7 +1,7 @@ %1 = OpFunction %2 None %3 %4 = OpFunctionParameter %2 %5 = OpLabel -OpLine %6 816 0 +OpLine %6 813 0 %7 = OpGroupNonUniformIAdd %2 %8 Reduce %4 OpNoLine OpReturnValue %7 diff --git a/tests/compiletests/ui/dis/complex_image_sample_inst.stderr b/tests/compiletests/ui/dis/complex_image_sample_inst.stderr index cde98c1dec..414558e2c5 100644 --- a/tests/compiletests/ui/dis/complex_image_sample_inst.stderr +++ b/tests/compiletests/ui/dis/complex_image_sample_inst.stderr @@ -2,13 +2,17 @@ %4 = OpFunctionParameter %2 %5 = OpFunctionParameter %6 %7 = OpFunctionParameter %6 -%8 = OpLabel -OpLine %9 29 13 -%10 = OpAccessChain %11 %12 %13 -OpLine %9 30 13 -%14 = OpLoad %15 %10 -OpLine %9 34 13 -%16 = OpImageSampleProjExplicitLod %2 %14 %4 Grad %5 %7 +%8 = OpFunctionParameter %6 +%9 = OpFunctionParameter %6 +%10 = OpLabel +%11 = OpCompositeConstruct %12 %5 %7 +%13 = OpCompositeConstruct %12 %8 %9 +OpLine %14 29 13 +%15 = OpAccessChain %16 %17 %18 +OpLine %14 30 13 +%19 = OpLoad %20 %15 +OpLine %14 34 13 +%21 = OpImageSampleProjExplicitLod %2 %19 %4 Grad %11 %13 OpNoLine -OpReturnValue %16 +OpReturnValue %21 OpFunctionEnd diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/compute_value_pair_fail.rs b/tests/compiletests/ui/lang/abi/scalar_pair/compute_value_pair_fail.rs new file mode 100644 index 0000000000..7c6d7eba57 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/compute_value_pair_fail.rs @@ -0,0 +1,12 @@ +// compile-fail +#![no_std] + +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main( + w: (u32, u32), + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32], +) { + out[0] = w.0 + w.1; +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/compute_value_pair_fail.stderr b/tests/compiletests/ui/lang/abi/scalar_pair/compute_value_pair_fail.stderr new file mode 100644 index 0000000000..a6b234b15e --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/compute_value_pair_fail.stderr @@ -0,0 +1,10 @@ +error: compute entry parameter `w` must be by-reference + --> $DIR/compute_value_pair_fail.rs:8:8 + | +8 | w: (u32, u32), + | ^^^^^^^^^^ + | + = help: consider changing the type to `&(u32, u32)` + +error: aborting due to 1 previous error + diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/f32_u32.rs b/tests/compiletests/ui/lang/abi/scalar_pair/f32_u32.rs new file mode 100644 index 0000000000..35c9285324 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/f32_u32.rs @@ -0,0 +1,12 @@ +// build-pass +#![no_std] + +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32], + #[spirv(uniform, descriptor_set = 0, binding = 1)] w: &(f32, u32), +) { + out[0] = w.0.to_bits() ^ w.1; +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/i32_i32.rs b/tests/compiletests/ui/lang/abi/scalar_pair/i32_i32.rs new file mode 100644 index 0000000000..f068febf71 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/i32_i32.rs @@ -0,0 +1,15 @@ +// build-pass +// compile-flags: -C target-feature=+Int64 +#![no_std] + +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32], + #[spirv(uniform, descriptor_set = 0, binding = 1)] w: &(i32, i32), +) { + // Sum and reinterpret as u32 for output + let s = (w.0 as i64 + w.1 as i64) as i32; + out[0] = s as u32; +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/mixed.rs b/tests/compiletests/ui/lang/abi/scalar_pair/mixed.rs new file mode 100644 index 0000000000..685cdb9ffc --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/mixed.rs @@ -0,0 +1,14 @@ +// build-pass +#![no_std] + +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32], + #[spirv(uniform, descriptor_set = 0, binding = 1)] w: &(u32, f32), +) { + let a = w.0; + let b_bits = w.1.to_bits(); + out[0] = a ^ b_bits; +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/newtype.rs b/tests/compiletests/ui/lang/abi/scalar_pair/newtype.rs new file mode 100644 index 0000000000..4655d3acda --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/newtype.rs @@ -0,0 +1,17 @@ +// build-pass +#![no_std] + +use spirv_std::spirv; + +#[repr(transparent)] +pub struct Wrap((u32, u32)); + +#[spirv(compute(threads(1)))] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32], + #[spirv(uniform, descriptor_set = 0, binding = 1)] w: &Wrap, +) { + let a = (w.0).0; + let b = (w.0).1; + out[0] = a + b; +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/newtype_fn.rs b/tests/compiletests/ui/lang/abi/scalar_pair/newtype_fn.rs new file mode 100644 index 0000000000..b5f5e63a0d --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/newtype_fn.rs @@ -0,0 +1,27 @@ +// build-pass +#![no_std] + +use spirv_std::spirv; + +#[repr(transparent)] +pub struct Inner((u32, u32)); + +#[repr(transparent)] +pub struct Outer( + core::mem::ManuallyDrop, + core::marker::PhantomData<()>, +); + +#[inline(never)] +fn sum_outer(o: Outer) -> u32 { + // SAFETY: repr(transparent) guarantees same layout as `Inner`. + let i: Inner = unsafe { core::mem::ManuallyDrop::into_inner((o.0)) }; + (i.0).0 + (i.0).1 +} + +#[spirv(compute(threads(1)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32]) { + let i = Inner((5, 7)); + let o = Outer(core::mem::ManuallyDrop::new(i), core::marker::PhantomData); + out[0] = sum_outer(o); +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/pair_input_fragment.rs b/tests/compiletests/ui/lang/abi/scalar_pair/pair_input_fragment.rs new file mode 100644 index 0000000000..29867b7f2d --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/pair_input_fragment.rs @@ -0,0 +1,12 @@ +// build-pass +#![no_std] + +use spirv_std::spirv; + +#[spirv(fragment)] +pub fn main( + #[spirv(flat)] pi: (u32, u32), + #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] out: &mut [u32], +) { + out[0] = pi.0.wrapping_add(pi.1); +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/pair_input_vertex.rs b/tests/compiletests/ui/lang/abi/scalar_pair/pair_input_vertex.rs new file mode 100644 index 0000000000..daf3ecdb3e --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/pair_input_vertex.rs @@ -0,0 +1,12 @@ +// build-pass +#![no_std] + +use spirv_std::spirv; + +#[spirv(vertex)] +pub fn main( + p: (u32, u32), + #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] out: &mut [u32], +) { + out[0] = p.0.wrapping_add(p.1); +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/tuple.rs b/tests/compiletests/ui/lang/abi/scalar_pair/tuple.rs new file mode 100644 index 0000000000..d989480b07 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/tuple.rs @@ -0,0 +1,12 @@ +// build-pass +#![no_std] + +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32], + #[spirv(uniform, descriptor_set = 0, binding = 1)] w: &(u32, u32), +) { + out[0] = w.0 + w.1; +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/u32_u64.rs b/tests/compiletests/ui/lang/abi/scalar_pair/u32_u64.rs new file mode 100644 index 0000000000..f67ddc5bbf --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/u32_u64.rs @@ -0,0 +1,15 @@ +// build-pass +// compile-flags: -C target-feature=+Int64 +#![no_std] + +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32], + #[spirv(uniform, descriptor_set = 0, binding = 1)] w: &(u32, u64), +) { + let hi = (w.1 >> 32) as u32; + let lo = (w.1 & 0xFFFF_FFFF) as u32; + out[0] = w.0 ^ hi ^ lo; +} diff --git a/tests/compiletests/ui/lang/abi/scalar_pair/u64_u32.rs b/tests/compiletests/ui/lang/abi/scalar_pair/u64_u32.rs new file mode 100644 index 0000000000..69187d10bd --- /dev/null +++ b/tests/compiletests/ui/lang/abi/scalar_pair/u64_u32.rs @@ -0,0 +1,16 @@ +// build-pass +// compile-flags: -C target-feature=+Int64 +#![no_std] + +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32], + #[spirv(uniform, descriptor_set = 0, binding = 1)] w: &(u64, u32), +) { + // Fold 64-bit into 32-bit deterministically + let hi = (w.0 >> 32) as u32; + let lo = (w.0 & 0xFFFF_FFFF) as u32; + out[0] = hi ^ lo ^ w.1; +} diff --git a/tests/compiletests/ui/lang/core/intrinsics/black_box.rs b/tests/compiletests/ui/lang/core/intrinsics/black_box.rs index 4a6c85a76b..676f9177de 100644 --- a/tests/compiletests/ui/lang/core/intrinsics/black_box.rs +++ b/tests/compiletests/ui/lang/core/intrinsics/black_box.rs @@ -5,7 +5,6 @@ use core::hint::black_box; use spirv_std::spirv; -// Minimal kernel that writes the disassembly function result to a buffer #[spirv(compute(threads(1)))] pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32]) { let r = disassemble(); diff --git a/tests/compiletests/ui/lang/core/intrinsics/black_box.stderr b/tests/compiletests/ui/lang/core/intrinsics/black_box.stderr index 192a37e3a3..56700b0e32 100644 --- a/tests/compiletests/ui/lang/core/intrinsics/black_box.stderr +++ b/tests/compiletests/ui/lang/core/intrinsics/black_box.stderr @@ -2,15 +2,15 @@ warning: black_box intrinsic does not prevent optimization in Rust GPU %1 = OpFunction %2 DontInline %3 %4 = OpLabel -OpLine %5 32 17 +OpLine %5 31 17 %6 = OpIAdd %7 %8 %9 -OpLine %5 41 19 +OpLine %5 40 19 %10 = OpIAdd %7 %11 %12 -OpLine %5 47 8 +OpLine %5 46 8 %13 = OpBitcast %7 %14 OpLine %15 1092 17 %16 = OpBitcast %7 %17 -OpLine %5 46 4 +OpLine %5 45 4 %18 = OpCompositeConstruct %2 %13 %16 %19 %20 %21 %22 %6 %23 %10 %24 %24 %24 OpNoLine OpReturnValue %18 diff --git a/tests/compiletests/ui/spirv-attr/invalid-matrix-type-empty.stderr b/tests/compiletests/ui/spirv-attr/invalid-matrix-type-empty.stderr index d34ef0ac5e..45b1139cc0 100644 --- a/tests/compiletests/ui/spirv-attr/invalid-matrix-type-empty.stderr +++ b/tests/compiletests/ui/spirv-attr/invalid-matrix-type-empty.stderr @@ -1,4 +1,4 @@ -error: #[spirv(matrix)] type must have at least two fields +error: `#[spirv(matrix)]` member types must all be the same --> $DIR/invalid-matrix-type-empty.rs:7:1 | 7 | pub struct EmptyStruct {} diff --git a/tests/compiletests/ui/spirv-attr/invalid-matrix-type.stderr b/tests/compiletests/ui/spirv-attr/invalid-matrix-type.stderr index eda87f4c6e..f1dbb5a145 100644 --- a/tests/compiletests/ui/spirv-attr/invalid-matrix-type.stderr +++ b/tests/compiletests/ui/spirv-attr/invalid-matrix-type.stderr @@ -1,10 +1,10 @@ -error: #[spirv(matrix)] type must have at least two fields +error: `#[spirv(matrix)]` must have at least 2 members --> $DIR/invalid-matrix-type.rs:7:1 | 7 | pub struct _FewerFields { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: #[spirv(matrix)] type fields must all be vectors +error: `#[spirv(matrix)]` type fields must all be vectors --> $DIR/invalid-matrix-type.rs:12:1 | 12 | pub struct _NotVectorField { @@ -12,7 +12,7 @@ error: #[spirv(matrix)] type fields must all be vectors | = note: field type is f32 -error: #[spirv(matrix)] type fields must all be the same type +error: `#[spirv(matrix)]` member types must all be the same --> $DIR/invalid-matrix-type.rs:19:1 | 19 | pub struct _DifferentType { diff --git a/tests/difftests/tests/Cargo.lock b/tests/difftests/tests/Cargo.lock index 74d87cce66..64176f3017 100644 --- a/tests/difftests/tests/Cargo.lock +++ b/tests/difftests/tests/Cargo.lock @@ -2,6 +2,56 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "abi-vector-layout-cpu" +version = "0.0.0" +dependencies = [ + "bytemuck", + "difftest", + "glam", + "spirv-std", +] + +[[package]] +name = "abi-vector-layout-cuda-cpu" +version = "0.0.0" +dependencies = [ + "abi-vector-layout-cpu", + "difftest", +] + +[[package]] +name = "abi-vector-layout-cuda-rust-gpu" +version = "0.0.0" +dependencies = [ + "abi-vector-layout-cpu", + "difftest", +] + +[[package]] +name = "abi-vector-layout-rust-gpu" +version = "0.0.0" +dependencies = [ + "abi-vector-layout-cpu", + "difftest", +] + +[[package]] +name = "abi-vector-layout-scalar-math-cpu" +version = "0.0.0" +dependencies = [ + "abi-vector-layout-cpu", + "difftest", +] + +[[package]] +name = "abi-vector-layout-scalar-math-rust-gpu" +version = "0.0.0" +dependencies = [ + "abi-vector-layout-cpu", + "difftest", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -594,8 +644,7 @@ dependencies = [ [[package]] name = "glam" version = "0.30.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d1aab06663bdce00d6ca5e5ed586ec8d18033a771906c993a1e3755b368d85" +source = "git+https://github.com/bitshifter/glam-rs?rev=d1a2837b080c6443c055b275048d7609dee1bc16#d1a2837b080c6443c055b275048d7609dee1bc16" dependencies = [ "libm", ] @@ -1332,6 +1381,23 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "scalar_pair-cpu" +version = "0.0.0" +dependencies = [ + "bytemuck", + "difftest", +] + +[[package]] +name = "scalar_pair-gpu" +version = "0.0.0" +dependencies = [ + "bytemuck", + "difftest", + "spirv-std", +] + [[package]] name = "scopeguard" version = "1.2.0" diff --git a/tests/difftests/tests/Cargo.toml b/tests/difftests/tests/Cargo.toml index 7c74495325..e3d92165ac 100644 --- a/tests/difftests/tests/Cargo.toml +++ b/tests/difftests/tests/Cargo.toml @@ -16,6 +16,12 @@ members = [ "arch/push_constants/push_constants-wgsl", "storage_class/array_access/array_access-rust", "storage_class/array_access/array_access-wgsl", + "lang/abi/vector_layout/cpu", + "lang/abi/vector_layout/rust-gpu", + "lang/abi/vector_layout_cuda/cpu", + "lang/abi/vector_layout_cuda/rust-gpu", + "lang/abi/vector_layout_scalar_math/cpu", + "lang/abi/vector_layout_scalar_math/rust-gpu", "lang/control_flow/control_flow-rust", "lang/control_flow/control_flow-wgsl", "lang/control_flow_complex/control_flow_complex-rust", @@ -40,6 +46,8 @@ members = [ "lang/core/ops/vector_swizzle/vector_swizzle-wgsl", "lang/core/intrinsics/black_box_noop/with-black-box", "lang/core/intrinsics/black_box_noop/without-black-box", + "lang/abi/scalar_pair/scalar_pair-cpu", + "lang/abi/scalar_pair/scalar_pair-gpu", ] [workspace.package] @@ -57,7 +65,7 @@ spirv-std = { path = "../../../crates/spirv-std", version = "=0.9.0" } difftest = { path = "../../../tests/difftests/lib" } # External dependencies that need to be mentioned more than once. num-traits = { version = "0.2.15", default-features = false } -glam = { version = ">=0.22, <=0.30", default-features = false } +glam = { version = ">=0.22, <=0.30", git = "https://github.com/bitshifter/glam-rs", rev = "d1a2837b080c6443c055b275048d7609dee1bc16", default-features = false } bytemuck = { version = "1.14", features = ["derive"] } # Enable incremental by default in release mode. diff --git a/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-cpu/Cargo.toml b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-cpu/Cargo.toml new file mode 100644 index 0000000000..d334ebc35c --- /dev/null +++ b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-cpu/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "scalar_pair-cpu" +edition.workspace = true + +[lints] +workspace = true + +[dependencies] +difftest.workspace = true +bytemuck.workspace = true diff --git a/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-cpu/src/main.rs b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-cpu/src/main.rs new file mode 100644 index 0000000000..dcd1aeb12e --- /dev/null +++ b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-cpu/src/main.rs @@ -0,0 +1,72 @@ +use difftest::config::{Config, TestMetadata}; +use std::{fs, io::Write}; + +fn main() { + let config = Config::from_path(std::env::args().nth(1).unwrap()).unwrap(); + + let a: (u32, u32) = (10, 20); + let b: (u32, f32) = (7, 3.5); + let c: (f32, u32) = (2.25, 9); + let d: (u32, u32) = (0xDEADBEEF, 0x12345678); + let e: (i32, i32) = (-5, 12); + + let sum_a = a.0 + a.1; + let mix_b = b.0 ^ b.1.to_bits(); + let mix_c = c.1 ^ c.0.to_bits(); + let d_and = d.0 & d.1; + let d_or = d.0 | d.1; + let d_xor = d.0 ^ d.1; + let d_sum = d.0.wrapping_add(d.1); + let e_sum_u32 = e.0.wrapping_add(e.1) as u32; + + let w_sum = 3u32 + 4u32; + let reorder_sum = 1u32 + 2u32; + + let mut out = [0u32; 21]; + out[0] = a.0; + out[1] = a.1; + out[2] = sum_a; + out[3] = mix_b; + out[4] = mix_c; + out[5] = d_and; + out[6] = d_or; + out[7] = d_xor; + out[8] = d_sum; + out[9] = e_sum_u32; + out[10] = w_sum; + out[11] = reorder_sum; + + let p: (i32, u32) = (-123, 456); + let p_mix = (p.0 as u32).wrapping_add(p.1); + let q: (f32, f32) = (0.75, -1.5); + let q_mix = q.0.to_bits() ^ q.1.to_bits(); + let r_mix = 8u32 ^ 16u32 ^ 0.5f32.to_bits() ^ (-2.0f32).to_bits(); + out[12] = p_mix; + out[13] = q_mix; + out[14] = r_mix; + + let tt_a_sum = 1u32 + 2 + 3 + 4; + let tt_b_mix = 5u32 ^ 1.5f32.to_bits() ^ 2.25f32.to_bits() ^ 9u32; + out[15] = tt_a_sum; + out[16] = tt_b_mix; + + let call_sum = 11u32.wrapping_add(22u32); + let call_mix = 13u32 ^ (-0.75f32).to_bits(); + out[17] = call_sum; + out[18] = call_mix; + + // Push constants equivalent values (must match GPU push data) + let pc0: u32 = 100; + let pc1: u32 = 200; + let pc_sum = pc0.wrapping_add(pc1); + let pc_xor = pc0 ^ pc1; + out[19] = pc_sum; + out[20] = pc_xor; + + let mut file = fs::File::create(&config.output_path).expect("Failed to create output file"); + file.write_all(bytemuck::cast_slice(&out)) + .expect("Failed to write output"); + config + .write_metadata(&TestMetadata::u32()) + .expect("Failed to write metadata"); +} diff --git a/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-gpu/Cargo.toml b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-gpu/Cargo.toml new file mode 100644 index 0000000000..2b8f3539a6 --- /dev/null +++ b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-gpu/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "scalar_pair-gpu" +edition.workspace = true + +[lints] +workspace = true + +[lib] +crate-type = ["dylib"] + +# GPU deps +[dependencies] +spirv-std.workspace = true + +# CPU deps (for the test harness) +[target.'cfg(not(target_arch = "spirv"))'.dependencies] +difftest.workspace = true +bytemuck.workspace = true diff --git a/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-gpu/src/lib.rs b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-gpu/src/lib.rs new file mode 100644 index 0000000000..90bdb394ef --- /dev/null +++ b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-gpu/src/lib.rs @@ -0,0 +1,81 @@ +#![no_std] + +use spirv_std::spirv; + +#[inline(never)] +fn sum_pair_u32(p: (u32, u32)) -> u32 { + p.0.wrapping_add(p.1) +} + +#[inline(never)] +fn mix_pair_u32_f32(p: (u32, f32)) -> u32 { + p.0 ^ p.1.to_bits() +} + +#[spirv(compute(threads(1)))] +pub fn main_cs( + #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] out: &mut [u32], + #[spirv(push_constant)] pc: &(u32, u32), +) { + let a: (u32, u32) = (10, 20); + let b: (u32, f32) = (7, 3.5); + let c: (f32, u32) = (2.25, 9); + let d: (u32, u32) = (0xDEADBEEF, 0x12345678); + let e: (i32, i32) = (-5, 12); + + let sum_a = a.0 + a.1; + let mix_b = b.0 ^ b.1.to_bits(); + let mix_c = c.1 ^ c.0.to_bits(); + let d_and = d.0 & d.1; + let d_or = d.0 | d.1; + let d_xor = d.0 ^ d.1; + let d_sum = d.0.wrapping_add(d.1); + let e_sum_u32 = e.0.wrapping_add(e.1) as u32; + + #[repr(transparent)] + struct Wrap((u32, u32)); + let w = Wrap((3, 4)); + let w_sum = (w.0).0 + (w.0).1; + + let reorder_sum = (1u32, 2u32).1 + (1u32, 2u32).0; + + out[0] = a.0; + out[1] = a.1; + out[2] = sum_a; + out[3] = mix_b; + out[4] = mix_c; + out[5] = d_and; + out[6] = d_or; + out[7] = d_xor; + out[8] = d_sum; + out[9] = e_sum_u32; + out[10] = w_sum; + out[11] = reorder_sum; + + let p: (i32, u32) = (-123, 456); + let p_mix = (p.0 as u32).wrapping_add(p.1); + let q: (f32, f32) = (0.75, -1.5); + let q_mix = q.0.to_bits() ^ q.1.to_bits(); + let r: ((u32, f32), (u32, f32)) = ((8, 0.5), (16, -2.0)); + let r_mix = (r.0).0 ^ (r.1).0 ^ (r.0).1.to_bits() ^ (r.1).1.to_bits(); + out[12] = p_mix; + out[13] = q_mix; + out[14] = r_mix; + + let tt_a: ((u32, u32), (u32, u32)) = ((1, 2), (3, 4)); + let tt_a_sum = tt_a.0.0 + tt_a.0.1 + tt_a.1.0 + tt_a.1.1; + let tt_b: ((u32, f32), (f32, u32)) = ((5, 1.5), (2.25, 9)); + let tt_b_mix = tt_b.0.0 ^ tt_b.0.1.to_bits() ^ tt_b.1.0.to_bits() ^ tt_b.1.1; + out[15] = tt_a_sum; + out[16] = tt_b_mix; + + let call_sum = sum_pair_u32((11, 22)); + let call_mix = mix_pair_u32_f32((13, -0.75)); + out[17] = call_sum; + out[18] = call_mix; + + let pc_sum = pc.0.wrapping_add(pc.1); + let pc_xor = pc.0 ^ pc.1; + out[19] = pc_sum; + out[20] = pc_xor; +} diff --git a/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-gpu/src/main.rs b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-gpu/src/main.rs new file mode 100644 index 0000000000..b931ffa32e --- /dev/null +++ b/tests/difftests/tests/lang/abi/scalar_pair/scalar_pair-gpu/src/main.rs @@ -0,0 +1,33 @@ +use difftest::config::{Config, TestMetadata}; +use difftest::scaffold::compute::{ + BufferConfig, BufferUsage, RustComputeShader, WgpuComputeTestPushConstants, +}; + +fn main() { + let config = Config::from_path(std::env::args().nth(1).unwrap()).unwrap(); + // One storage buffer (output), plus push constants data (pair of u32) + let sizes = [21 * 4u64]; + let push_data: Vec = { + let a: u32 = 100; + let b: u32 = 200; + let mut v = Vec::with_capacity(8); + v.extend_from_slice(&a.to_le_bytes()); + v.extend_from_slice(&b.to_le_bytes()); + v + }; + let test = WgpuComputeTestPushConstants::new( + RustComputeShader::default(), + [1, 1, 1], + vec![BufferConfig { + size: sizes[0], + usage: BufferUsage::Storage, + initial_data: None, + }], + 8, + push_data, + ); + test.run_test(&config).unwrap(); + config + .write_metadata(&TestMetadata::u32()) + .expect("Failed to write metadata"); +} diff --git a/tests/difftests/tests/lang/abi/vector_layout/cpu/Cargo.toml b/tests/difftests/tests/lang/abi/vector_layout/cpu/Cargo.toml new file mode 100644 index 0000000000..007ef92b04 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/cpu/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "abi-vector-layout-cpu" +edition.workspace = true + +[lints] +workspace = true + +[features] +cuda = ["glam/cuda"] +scalar-math = ["glam/scalar-math"] + +# GPU deps +[dependencies] +spirv-std.workspace = true +glam.workspace = true +bytemuck.workspace = true + +# CPU deps (for the test harness) +[target.'cfg(not(target_arch = "spirv"))'.dependencies] +difftest.workspace = true diff --git a/tests/difftests/tests/lang/abi/vector_layout/cpu/src/cpu_driver.rs b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/cpu_driver.rs new file mode 100644 index 0000000000..87ea655780 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/cpu_driver.rs @@ -0,0 +1,13 @@ +use crate::glam_features::GlamFeatures; +use crate::layout::{LAYOUT_COUNT, LAYOUT_LEN, eval_layouts}; +use difftest::config::Config; + +pub fn run(glam_feature: GlamFeatures) { + glam_feature.assert(); + let config = Config::from_path(std::env::args().nth(1).unwrap()).unwrap(); + let mut out = vec![0; LAYOUT_LEN]; + for gid in 0..LAYOUT_COUNT { + eval_layouts(gid as u32, &mut out); + } + config.write_result(&out).unwrap() +} diff --git a/tests/difftests/tests/lang/abi/vector_layout/cpu/src/glam_features.rs b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/glam_features.rs new file mode 100644 index 0000000000..7259525b71 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/glam_features.rs @@ -0,0 +1,35 @@ +#[repr(u32)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum GlamFeatures { + Default, + Cuda, + ScalarMath, +} + +impl GlamFeatures { + pub fn is(&self) -> bool { + match self { + // cuda: 16 (!) + // cuda + scalar-math: 8 + // scalar-math: (native) 4 + GlamFeatures::Default => align_of::() == 16 && !GlamFeatures::Cuda.is(), + // default, scalar-math: (native) 4 + GlamFeatures::Cuda => align_of::() == 8, + // default, cuda: 16 + GlamFeatures::ScalarMath => align_of::() == 4, + } + } + + pub fn assert(&self) { + for feature in [Self::Default, Self::Cuda, Self::ScalarMath] { + if *self == feature { + assert!(feature.is(), "Expected feature {feature:?} to be enabled"); + } else { + assert!( + !feature.is(), + "Feature {feature:?} mistakenly enabled! Too aggressive feature unification?" + ); + } + } + } +} diff --git a/tests/difftests/tests/lang/abi/vector_layout/cpu/src/layout.rs b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/layout.rs new file mode 100644 index 0000000000..d050e60d5d --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/layout.rs @@ -0,0 +1,162 @@ +use core::mem::offset_of; +use experiments::*; +use spirv_std::glam::*; + +pub struct BumpAlloc(usize); + +impl BumpAlloc { + pub fn inc(&mut self) -> usize { + let old = self.0; + self.0 += 1; + old + } +} + +pub trait WriteLayout { + fn write_layout(offset: &mut BumpAlloc, out: &mut [u32]); +} + +macro_rules! write_layout { + ($out:ident, $offset:ident, $name:ident($($member:ident),*)) => { + { + // offset 0: size + $out[$offset.inc()] = size_of::<$name>() as u32; + // offset 4: alignment + $out[$offset.inc()] = align_of::<$name>() as u32; + // offset 8 onwards: members + $($out[$offset.inc()] = offset_of!($name, $member) as u32;)* + } + }; +} + +/// gid is checked between `0..LAYOUT_COUNT` +pub const LAYOUT_COUNT: usize = 0x60; +/// at byte offset 0x100 * N starts layout N +pub const LAYOUT_MAX_SIZE: usize = 0x100 / 0x4; +pub const LAYOUT_LEN: usize = LAYOUT_COUNT * LAYOUT_MAX_SIZE; + +pub fn eval_layouts(gid: u32, out: &mut [u32]) { + let mut offset = BumpAlloc(gid as usize * LAYOUT_MAX_SIZE); + match gid { + // vec + 0x0 => write_layout!(out, offset, u32()), + 0x1 => write_layout!(out, offset, i32()), + 0x2 => write_layout!(out, offset, f32()), + 0x4 => write_layout!(out, offset, UVec2(x, y)), + 0x5 => write_layout!(out, offset, IVec2(x, y)), + 0x6 => write_layout!(out, offset, Vec2(x, y)), + 0x8 => write_layout!(out, offset, UVec3(x, y, z)), + 0x9 => write_layout!(out, offset, IVec3(x, y, z)), + 0xA => write_layout!(out, offset, Vec3(x, y, z)), + 0xB => write_layout!(out, offset, Vec3A()), // private members + 0xC => write_layout!(out, offset, UVec4(x, y, z, w)), + 0xD => write_layout!(out, offset, IVec4(x, y, z, w)), + 0xE => write_layout!(out, offset, Vec4()), // private members + 0xF => write_layout!(out, offset, Quat()), // private members + + // experiments structs + 0x10 => write_layout!(out, offset, Struct0x10(a, b)), + 0x11 => write_layout!(out, offset, Struct0x11(a, b)), + 0x12 => write_layout!(out, offset, Struct0x12(a, b, c, d, e)), + 0x13 => write_layout!(out, offset, Struct0x13(a)), + + // mat + 0x20 => write_layout!(out, offset, Mat2()), // private members + 0x21 => write_layout!(out, offset, Mat3(x_axis, y_axis, z_axis)), + 0x22 => write_layout!(out, offset, Mat3A(x_axis, y_axis, z_axis)), + 0x23 => write_layout!(out, offset, Mat4(x_axis, y_axis, z_axis, w_axis)), + // f64 + 0x24 => write_layout!(out, offset, f64()), + 0x25 => write_layout!(out, offset, DVec2(x, y)), + 0x26 => write_layout!(out, offset, DVec3(x, y, z)), + 0x27 => write_layout!(out, offset, DVec4(x, y, z, w)), + 0x28 => write_layout!(out, offset, DQuat(x, y, z, w)), + 0x29 => write_layout!(out, offset, DMat2()), // private members + 0x2a => write_layout!(out, offset, DMat3(x_axis, y_axis, z_axis)), + 0x2b => write_layout!(out, offset, DMat4(x_axis, y_axis, z_axis, w_axis)), + + // i8 + 0x30 => write_layout!(out, offset, i8()), + 0x31 => write_layout!(out, offset, I8Vec2(x, y)), + 0x32 => write_layout!(out, offset, I8Vec3(x, y, z)), + 0x33 => write_layout!(out, offset, I8Vec4(x, y, z, w)), + // i16 + 0x34 => write_layout!(out, offset, i16()), + 0x35 => write_layout!(out, offset, I16Vec2(x, y)), + 0x36 => write_layout!(out, offset, I16Vec3(x, y, z)), + 0x37 => write_layout!(out, offset, I16Vec4(x, y, z, w)), + // i64 + 0x38 => write_layout!(out, offset, i64()), + 0x39 => write_layout!(out, offset, I64Vec2(x, y)), + 0x3a => write_layout!(out, offset, I64Vec3(x, y, z)), + 0x3b => write_layout!(out, offset, I64Vec4(x, y, z, w)), + + // u8 + 0x40 => write_layout!(out, offset, u8()), + 0x41 => write_layout!(out, offset, U8Vec2(x, y)), + 0x42 => write_layout!(out, offset, U8Vec3(x, y, z)), + 0x43 => write_layout!(out, offset, U8Vec4(x, y, z, w)), + // u16 + 0x44 => write_layout!(out, offset, u16()), + 0x45 => write_layout!(out, offset, U16Vec2(x, y)), + 0x46 => write_layout!(out, offset, U16Vec3(x, y, z)), + 0x47 => write_layout!(out, offset, U16Vec4(x, y, z, w)), + // u64 + 0x48 => write_layout!(out, offset, u64()), + 0x49 => write_layout!(out, offset, U64Vec2(x, y)), + 0x4a => write_layout!(out, offset, U64Vec3(x, y, z)), + 0x4b => write_layout!(out, offset, U64Vec4(x, y, z, w)), + // Affine + 0x4c => write_layout!(out, offset, Affine2(matrix2, translation)), + 0x4d => write_layout!(out, offset, Affine3A(matrix3, translation)), + 0x4e => write_layout!(out, offset, DAffine2(matrix2, translation)), + 0x4f => write_layout!(out, offset, DAffine3(matrix3, translation)), + + // bool + 0x50 => write_layout!(out, offset, bool()), + 0x51 => write_layout!(out, offset, BVec2(x, y)), + 0x52 => write_layout!(out, offset, BVec3(x, y, z)), + 0x53 => write_layout!(out, offset, BVec3A()), // private members + 0x54 => write_layout!(out, offset, BVec4(x, y, z, w)), + 0x55 => write_layout!(out, offset, BVec4A()), + + _ => {} + } +} + +mod experiments { + use spirv_std::glam::*; + + #[repr(C)] + pub struct Struct0x10 { + pub a: f32, + /// if UVec2 has an alignment of + /// * 4 (CPU): 12 size, 4 alignment, 4 b offset + /// * 8 (GPU): 16 size, 8 alignment, 8 b offset + pub b: UVec2, + } + + #[repr(C)] + pub struct Struct0x11 { + pub a: Vec3, + /// if Vec3 has an alignment of + /// * 4 (CPU): 16 size, 4 alignment, 12 b offset + /// * 16 (GPU): 32 size, 16 alignment, 16 b offset + pub b: f32, + } + + #[repr(C)] + pub struct Struct0x12 { + pub a: BVec3, + pub b: f32, + pub c: BVec2, + pub d: f32, + pub e: BVec4, + } + + #[repr(C)] + #[repr(align(16))] + pub struct Struct0x13 { + pub a: f32, + } +} diff --git a/tests/difftests/tests/lang/abi/vector_layout/cpu/src/lib.rs b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/lib.rs new file mode 100644 index 0000000000..08e80c346f --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/lib.rs @@ -0,0 +1,9 @@ +#![cfg_attr(target_arch = "spirv", no_std)] + +#[cfg(not(target_arch = "spirv"))] +pub mod cpu_driver; +pub mod glam_features; +pub mod layout; +pub mod shader; +#[cfg(not(target_arch = "spirv"))] +pub mod shader_driver; diff --git a/tests/difftests/tests/lang/abi/vector_layout/cpu/src/main.rs b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/main.rs new file mode 100644 index 0000000000..bcd5f7c800 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/main.rs @@ -0,0 +1,5 @@ +use abi_vector_layout_cpu::glam_features::GlamFeatures; + +fn main() { + abi_vector_layout_cpu::cpu_driver::run(GlamFeatures::Default); +} diff --git a/tests/difftests/tests/lang/abi/vector_layout/cpu/src/shader.rs b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/shader.rs new file mode 100644 index 0000000000..4ce4ea67ca --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/shader.rs @@ -0,0 +1,11 @@ +use crate::layout::eval_layouts; +use spirv_std::glam::UVec3; +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main_cs( + #[spirv(workgroup_id)] gid: UVec3, + #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] output: &mut [u32], +) { + eval_layouts(gid.x, output); +} diff --git a/tests/difftests/tests/lang/abi/vector_layout/cpu/src/shader_driver.rs b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/shader_driver.rs new file mode 100644 index 0000000000..4502da3197 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/cpu/src/shader_driver.rs @@ -0,0 +1,15 @@ +use crate::glam_features::GlamFeatures; +use crate::layout::{LAYOUT_COUNT, LAYOUT_LEN}; +use difftest::config::Config; +use difftest::scaffold::compute::{BufferConfig, RustComputeShader, WgpuComputeTestMultiBuffer}; + +pub fn run(glam_feature: GlamFeatures) { + glam_feature.assert(); + let config = Config::from_path(std::env::args().nth(1).unwrap()).unwrap(); + let test = WgpuComputeTestMultiBuffer::new( + RustComputeShader::default(), + [LAYOUT_COUNT as u32, 1, 1], + Vec::from(&[BufferConfig::writeback(LAYOUT_LEN * size_of::())]), + ); + test.run_test(&config).unwrap(); +} diff --git a/tests/difftests/tests/lang/abi/vector_layout/rust-gpu/Cargo.toml b/tests/difftests/tests/lang/abi/vector_layout/rust-gpu/Cargo.toml new file mode 100644 index 0000000000..e178ce6d25 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/rust-gpu/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "abi-vector-layout-rust-gpu" +edition.workspace = true + +[lib] +crate-type = ["lib", "dylib"] + +[lints] +workspace = true + +[dependencies] +abi-vector-layout-cpu = { path = "../cpu" } + +# CPU deps (for the test harness) +[target.'cfg(not(target_arch = "spirv"))'.dependencies] +difftest.workspace = true diff --git a/tests/difftests/tests/lang/abi/vector_layout/rust-gpu/src/lib.rs b/tests/difftests/tests/lang/abi/vector_layout/rust-gpu/src/lib.rs new file mode 100644 index 0000000000..219229aa2e --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/rust-gpu/src/lib.rs @@ -0,0 +1,3 @@ +#![cfg_attr(target_arch = "spirv", no_std)] + +pub use abi_vector_layout_cpu::shader::main_cs; diff --git a/tests/difftests/tests/lang/abi/vector_layout/rust-gpu/src/main.rs b/tests/difftests/tests/lang/abi/vector_layout/rust-gpu/src/main.rs new file mode 100644 index 0000000000..5ab8e426b5 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout/rust-gpu/src/main.rs @@ -0,0 +1,5 @@ +use abi_vector_layout_cpu::glam_features::GlamFeatures; + +fn main() { + abi_vector_layout_cpu::shader_driver::run(GlamFeatures::Default); +} diff --git a/tests/difftests/tests/lang/abi/vector_layout_cuda/cpu/Cargo.toml b/tests/difftests/tests/lang/abi/vector_layout_cuda/cpu/Cargo.toml new file mode 100644 index 0000000000..a81d490023 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_cuda/cpu/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "abi-vector-layout-scalar-math-cpu" +edition.workspace = true + +[lints] +workspace = true + +# GPU deps +[dependencies] +abi-vector-layout-cpu = { path = "../../vector_layout/cpu", features = ["cuda"] } + +# CPU deps (for the test harness) +[target.'cfg(not(target_arch = "spirv"))'.dependencies] +difftest.workspace = true diff --git a/tests/difftests/tests/lang/abi/vector_layout_cuda/cpu/src/main.rs b/tests/difftests/tests/lang/abi/vector_layout_cuda/cpu/src/main.rs new file mode 100644 index 0000000000..84861065a3 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_cuda/cpu/src/main.rs @@ -0,0 +1,5 @@ +use abi_vector_layout_cpu::glam_features::GlamFeatures; + +fn main() { + abi_vector_layout_cpu::cpu_driver::run(GlamFeatures::Cuda); +} diff --git a/tests/difftests/tests/lang/abi/vector_layout_cuda/rust-gpu/Cargo.toml b/tests/difftests/tests/lang/abi/vector_layout_cuda/rust-gpu/Cargo.toml new file mode 100644 index 0000000000..929050dc70 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_cuda/rust-gpu/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "abi-vector-layout-scalar-math-rust-gpu" +edition.workspace = true + +[lib] +crate-type = ["lib", "dylib"] + +[lints] +workspace = true + +[dependencies] +abi-vector-layout-cpu = { path = "../../vector_layout/cpu", features = ["cuda"] } + +# CPU deps (for the test harness) +[target.'cfg(not(target_arch = "spirv"))'.dependencies] +difftest.workspace = true diff --git a/tests/difftests/tests/lang/abi/vector_layout_cuda/rust-gpu/src/lib.rs b/tests/difftests/tests/lang/abi/vector_layout_cuda/rust-gpu/src/lib.rs new file mode 100644 index 0000000000..219229aa2e --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_cuda/rust-gpu/src/lib.rs @@ -0,0 +1,3 @@ +#![cfg_attr(target_arch = "spirv", no_std)] + +pub use abi_vector_layout_cpu::shader::main_cs; diff --git a/tests/difftests/tests/lang/abi/vector_layout_cuda/rust-gpu/src/main.rs b/tests/difftests/tests/lang/abi/vector_layout_cuda/rust-gpu/src/main.rs new file mode 100644 index 0000000000..647d8c3385 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_cuda/rust-gpu/src/main.rs @@ -0,0 +1,5 @@ +use abi_vector_layout_cpu::glam_features::GlamFeatures; + +fn main() { + abi_vector_layout_cpu::shader_driver::run(GlamFeatures::Cuda); +} diff --git a/tests/difftests/tests/lang/abi/vector_layout_scalar_math/cpu/Cargo.toml b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/cpu/Cargo.toml new file mode 100644 index 0000000000..bd7caafbfe --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/cpu/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "abi-vector-layout-cuda-cpu" +edition.workspace = true + +[lints] +workspace = true + +# GPU deps +[dependencies] +abi-vector-layout-cpu = { path = "../../vector_layout/cpu", features = ["scalar-math"] } + +# CPU deps (for the test harness) +[target.'cfg(not(target_arch = "spirv"))'.dependencies] +difftest.workspace = true diff --git a/tests/difftests/tests/lang/abi/vector_layout_scalar_math/cpu/src/main.rs b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/cpu/src/main.rs new file mode 100644 index 0000000000..044b1b025f --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/cpu/src/main.rs @@ -0,0 +1,5 @@ +use abi_vector_layout_cpu::glam_features::GlamFeatures; + +fn main() { + abi_vector_layout_cpu::cpu_driver::run(GlamFeatures::ScalarMath); +} diff --git a/tests/difftests/tests/lang/abi/vector_layout_scalar_math/rust-gpu/Cargo.toml b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/rust-gpu/Cargo.toml new file mode 100644 index 0000000000..60d101e6e3 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/rust-gpu/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "abi-vector-layout-cuda-rust-gpu" +edition.workspace = true + +[lib] +crate-type = ["lib", "dylib"] + +[lints] +workspace = true + +[dependencies] +abi-vector-layout-cpu = { path = "../../vector_layout/cpu", features = ["scalar-math"] } + +# CPU deps (for the test harness) +[target.'cfg(not(target_arch = "spirv"))'.dependencies] +difftest.workspace = true diff --git a/tests/difftests/tests/lang/abi/vector_layout_scalar_math/rust-gpu/src/lib.rs b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/rust-gpu/src/lib.rs new file mode 100644 index 0000000000..219229aa2e --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/rust-gpu/src/lib.rs @@ -0,0 +1,3 @@ +#![cfg_attr(target_arch = "spirv", no_std)] + +pub use abi_vector_layout_cpu::shader::main_cs; diff --git a/tests/difftests/tests/lang/abi/vector_layout_scalar_math/rust-gpu/src/main.rs b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/rust-gpu/src/main.rs new file mode 100644 index 0000000000..c0265cc7e3 --- /dev/null +++ b/tests/difftests/tests/lang/abi/vector_layout_scalar_math/rust-gpu/src/main.rs @@ -0,0 +1,5 @@ +use abi_vector_layout_cpu::glam_features::GlamFeatures; + +fn main() { + abi_vector_layout_cpu::shader_driver::run(GlamFeatures::ScalarMath); +}