diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index da589937f4f..0eb0a2722c2 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -4,7 +4,7 @@ use crate::attr::{AggregatedSpirvAttributes, IntrinsicType}; use crate::codegen_cx::CodegenCx; use crate::maybe_pqp_cg_ssa::traits::ConstCodegenMethods as _; -use crate::spirv_type::SpirvType; +use crate::spirv_type::{SpirvType, name_type_id}; use itertools::Itertools; use rspirv::spirv::{Dim, ImageFormat, StorageClass, Word}; use rustc_abi::ExternAbi as Abi; @@ -322,6 +322,33 @@ impl<'tcx> ConvSpirvType<'tcx> for FnAbi<'tcx, Ty<'tcx>> { } } +/// If `layout` has exactly one non-ZST field positioned at offset 0 with size and +/// alignment matching the outer layout, returns that field. +/// +/// This captures the structural shape of a "newtype wrapper" — a single meaningful +/// field padded out to the outer type, which can be substituted for the outer type +/// in a SPIR-V type graph as long as the caller has *independently* verified that +/// the ABIs match (either via `BackendRepr::eq_up_to_validity`, or via +/// `#[repr(transparent)]`, which guarantees full ABI identity by construction). +fn sole_structural_newtype_field<'tcx>( + cx: &CodegenCx<'tcx>, + layout: TyAndLayout<'tcx>, +) -> Option> { + let mut non_zst = (0..layout.fields.count()).filter(|&i| !layout.field(cx, i).is_zst()); + let i = non_zst.next()?; + if non_zst.next().is_some() { + return None; + } + let field = layout.field(cx, i); + // Only unpack a newtype if the field and the newtype line up + // perfectly, in every way that could potentially affect ABI. + (layout.fields.offset(i) == Size::ZERO + && field.size == layout.size + && field.align.abi == layout.align.abi + && field.backend_repr.eq_up_to_validity(&layout.backend_repr)) + .then_some(field) +} + impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> { fn spirv_type(&self, mut span: Span, cx: &CodegenCx<'tcx>) -> Word { if let TyKind::Adt(adt, args) = *self.ty.kind() { @@ -380,23 +407,8 @@ impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> { // a new one, offering the `(a, b)` shape `rustc_codegen_ssa` // expects, while letting noop pointercasts access the sole // `BackendRepr::ScalarPair` field - this is the approach taken here - let mut non_zst_fields = (0..self.fields.count()) - .map(|i| (i, self.field(cx, i))) - .filter(|(_, field)| !field.is_zst()); - let sole_non_zst_field = match (non_zst_fields.next(), non_zst_fields.next()) { - (Some(field), None) => Some(field), - _ => None, - }; - if let Some((i, field)) = sole_non_zst_field { - // Only unpack a newtype if the field and the newtype line up - // perfectly, in every way that could potentially affect ABI. - if self.fields.offset(i) == Size::ZERO - && field.size == self.size - && field.align.abi == self.align.abi - && field.backend_repr.eq_up_to_validity(&self.backend_repr) - { - return field.spirv_type(span, cx); - } + if let Some(field) = sole_structural_newtype_field(cx, *self) { + return field.spirv_type(span, cx); } // Note: We can't use auto_struct_layout here because the spirv types here might be undefined due to @@ -448,7 +460,24 @@ impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> { .tcx .dcx() .fatal("scalable vectors are not supported in SPIR-V backend"), - BackendRepr::Memory { sized: _ } => trans_aggregate(cx, span, *self), + BackendRepr::Memory { sized: _ } => { + // For `#[repr(transparent)]` newtypes, reuse the single non-ZST + // field's SPIR-V type directly instead of wrapping it in an + // `OpTypeStruct`, if the type is `#[repr(transparent)]`. + // Otherwise, we're manipulating the abi too much and the + // format args decompiler fails. + if let TyKind::Adt(adt, _) = self.ty.kind() + && adt.repr().transparent() + && let Some(field) = sole_structural_newtype_field(cx, *self) + { + let inner_id = field.spirv_type(span, cx); + // Preserve the wrapper's name as an `OpName` alias on the + // inner SPIR-V type so disassembly still shows it. + name_type_id(cx, inner_id, TyLayoutNameKey::from(*self)); + return inner_id; + } + trans_aggregate(cx, span, *self) + } } } } diff --git a/crates/rustc_codegen_spirv/src/spirv_type.rs b/crates/rustc_codegen_spirv/src/spirv_type.rs index feedf0778ff..262538fb29f 100644 --- a/crates/rustc_codegen_spirv/src/spirv_type.rs +++ b/crates/rustc_codegen_spirv/src/spirv_type.rs @@ -99,6 +99,17 @@ pub enum SpirvType<'tcx> { }, } +/// Emit an `OpName` for a type `id`, deduplicated per `(id, name_key)` pair. +/// Unlike [`SpirvType::def_with_name`], this operates on an existing `id` - useful +/// for types reused across multiple Rust types (e.g. `#[repr(transparent)]` +/// newtype collapse, where the wrapper's name is attached to the inner's id). +pub fn name_type_id<'tcx>(cx: &CodegenCx<'tcx>, id: Word, name_key: TyLayoutNameKey<'tcx>) { + let mut type_names = cx.type_cache.type_names.borrow_mut(); + if type_names.entry(id).or_default().insert(name_key) { + cx.emit_global().name(id, name_key.to_string()); + } +} + impl SpirvType<'_> { /// Note: `Builder::type_*` should be called *nowhere else* but here, to ensure /// `CodegenCx::type_defs` stays up-to-date @@ -287,13 +298,7 @@ impl SpirvType<'_> { name_key: TyLayoutNameKey<'tcx>, ) -> Word { let id = self.def(def_span, cx); - - // Only emit `OpName` if this is the first time we see this name. - let mut type_names = cx.type_cache.type_names.borrow_mut(); - if type_names.entry(id).or_default().insert(name_key) { - cx.emit_global().name(id, name_key.to_string()); - } - + name_type_id(cx, id, name_key); id } diff --git a/tests/compiletests/ui/lang/abi/transparent_array.rs b/tests/compiletests/ui/lang/abi/transparent_array.rs new file mode 100644 index 00000000000..1b129c942e6 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_array.rs @@ -0,0 +1,33 @@ +// build-pass +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "\n\W*OpLine .*" -> "" +// normalize-stderr-test "\n\W*OpSource .*" -> "" +// normalize-stderr-test "\n\W*%\d+ = OpString .*" -> "" +// normalize-stderr-test "\n\W*OpCapability VulkanMemoryModel" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use core::marker::PhantomData; +use spirv_std::glam::*; +use spirv_std::spirv; + +#[derive(Default)] +pub struct A([u32; 3]); +#[repr(transparent)] +#[derive(Default)] +pub struct AT([u32; 3]); + +#[spirv(vertex)] +pub fn main(a: &mut A, at: &mut AT, #[spirv(local_invocation_index)] tid: u32) { + *a = A([tid, 1, 2]); + a.0 = [tid, 1, 2]; + a.0[2] += 4; + *at = AT([tid, 1, 2]); + at.0 = [tid, 1, 2]; + at.0[2] += 5; +} diff --git a/tests/compiletests/ui/lang/abi/transparent_array.stderr b/tests/compiletests/ui/lang/abi/transparent_array.stderr new file mode 100644 index 00000000000..5a814ba069a --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_array.stderr @@ -0,0 +1,74 @@ + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Vertex %1 "main" %tid %a %at + OpName %AT "AT" + OpName %A "A" + OpMemberName %A 0 "0" + OpName %tid "tid" + OpName %AT "AT" + OpName %a "a" + OpName %at "at" + OpDecorate %tid BuiltIn LocalInvocationIndex + OpDecorate %AT ArrayStride 4 + OpDecorate %a Location 0 + OpDecorate %at Location 3 + %u32 = OpTypeInt 32 0 + %u32_3 = OpConstant %u32 3 + %AT = OpTypeArray %u32 %u32_3 + %A = OpTypeStruct %AT +%_ptr_Output_A = OpTypePointer Output %A +%_ptr_Output_AT = OpTypePointer Output %AT +%_ptr_Input_u32 = OpTypePointer Input %u32 + %void = OpTypeVoid + %15 = OpTypeFunction %void + %tid = OpVariable %_ptr_Input_u32 Input + %AT = OpTypeArray %u32 %u32_3 + %u32_1 = OpConstant %u32 1 + %u32_2 = OpConstant %u32 2 + %a = OpVariable %_ptr_Output_A Output + %u32_0 = OpConstant %u32 0 +%_ptr_Output_u32 = OpTypePointer Output %u32 + %u32_4 = OpConstant %u32 4 + %at = OpVariable %_ptr_Output_AT Output + %u32_5 = OpConstant %u32 5 + %1 = OpFunction %void None %15 + %22 = OpLabel + %23 = OpLoad %u32 %tid + %24 = OpCompositeConstruct %AT %23 %u32_1 %u32_2 + %25 = OpInBoundsAccessChain %_ptr_Output_AT %a %u32_0 + %26 = OpCompositeExtract %u32 %24 0 + %27 = OpCompositeExtract %u32 %24 1 + %28 = OpCompositeExtract %u32 %24 2 + %29 = OpCompositeConstruct %AT %26 %27 %28 + OpStore %25 %29 + %30 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_0 + OpStore %30 %23 + %31 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_1 + OpStore %31 %u32_1 + %32 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_2 + OpStore %32 %u32_2 + %33 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_2 + %34 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_2 + %35 = OpLoad %u32 %34 + %36 = OpIAdd %u32 %35 %u32_4 + OpStore %33 %36 + %37 = OpCompositeConstruct %AT %23 %u32_1 %u32_2 + %38 = OpCompositeExtract %u32 %37 0 + %39 = OpCompositeExtract %u32 %37 1 + %40 = OpCompositeExtract %u32 %37 2 + %41 = OpCompositeConstruct %AT %38 %39 %40 + OpStore %at %41 + %42 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 + OpStore %42 %23 + %43 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_1 + OpStore %43 %u32_1 + %44 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_2 + OpStore %44 %u32_2 + %45 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_2 + %46 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_2 + %47 = OpLoad %u32 %46 + %48 = OpIAdd %u32 %47 %u32_5 + OpStore %45 %48 + OpNoLine + OpReturn + OpFunctionEnd diff --git a/tests/compiletests/ui/lang/abi/transparent_nested.rs b/tests/compiletests/ui/lang/abi/transparent_nested.rs new file mode 100644 index 00000000000..fdd96fda213 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_nested.rs @@ -0,0 +1,43 @@ +// build-pass +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "\n\W*OpLine .*" -> "" +// normalize-stderr-test "\n\W*OpSource .*" -> "" +// normalize-stderr-test "\n\W*%\d+ = OpString .*" -> "" +// normalize-stderr-test "\n\W*OpCapability VulkanMemoryModel" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use core::marker::PhantomData; +use spirv_std::glam::*; +use spirv_std::spirv; + +#[repr(C)] +#[derive(Default)] +pub struct A(UVec3); + +#[repr(C)] +#[derive(Default)] +pub struct B(A); + +#[repr(transparent)] +#[derive(Default)] +pub struct AT(UVec3); + +#[repr(transparent)] +#[derive(Default)] +pub struct BT(AT); + +#[spirv(vertex)] +pub fn main(a: &mut B, at: &mut BT, #[spirv(local_invocation_index)] tid: u32) { + *a = B(A(UVec3::new(tid, 1, 2))); + a.0.0.y = tid + 1; + a.0.0.x += 4; + *at = BT(AT(UVec3::new(tid, 1, 2))); + at.0.0.y = tid + 2; + at.0.0.x += 5; +} diff --git a/tests/compiletests/ui/lang/abi/transparent_nested.stderr b/tests/compiletests/ui/lang/abi/transparent_nested.stderr new file mode 100644 index 00000000000..cee72e7fcd0 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_nested.stderr @@ -0,0 +1,70 @@ + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Vertex %1 "main" %tid %a %at + OpName %AT "AT" + OpName %A "A" + OpMemberName %A 0 "0" + OpName %B "B" + OpMemberName %B 0 "0" + OpName %tid "tid" + OpName %A "A" + OpMemberName %A 0 "0" + OpName %B "B" + OpMemberName %B 0 "0" + OpName %a "a" + OpName %at "at" + OpDecorate %tid BuiltIn LocalInvocationIndex + OpMemberDecorate %A 0 Offset 0 + OpMemberDecorate %B 0 Offset 0 + OpDecorate %a Location 0 + OpDecorate %at Location 1 + %u32 = OpTypeInt 32 0 + %AT = OpTypeVector %u32 3 + %A = OpTypeStruct %AT + %B = OpTypeStruct %A +%_ptr_Output_B = OpTypePointer Output %B +%_ptr_Output_AT = OpTypePointer Output %AT +%_ptr_Input_u32 = OpTypePointer Input %u32 + %void = OpTypeVoid + %17 = OpTypeFunction %void + %tid = OpVariable %_ptr_Input_u32 Input + %u32_1 = OpConstant %u32 1 + %u32_2 = OpConstant %u32 2 + %A = OpTypeStruct %AT + %B = OpTypeStruct %A + %20 = OpUndef %B + %a = OpVariable %_ptr_Output_B Output + %u32_0 = OpConstant %u32 0 +%_ptr_Output_u32 = OpTypePointer Output %u32 + %u32_4 = OpConstant %u32 4 + %at = OpVariable %_ptr_Output_AT Output + %u32_5 = OpConstant %u32 5 + %1 = OpFunction %void None %17 + %25 = OpLabel + %26 = OpLoad %u32 %tid + %27 = OpCompositeConstruct %AT %26 %u32_1 %u32_2 + %28 = OpCompositeInsert %B %27 %20 0 0 + %29 = OpInBoundsAccessChain %_ptr_Output_AT %a %u32_0 %u32_0 + %30 = OpCompositeExtract %AT %28 0 0 + OpStore %29 %30 + %31 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_0 %u32_1 + %32 = OpIAdd %u32 %26 %u32_1 + OpStore %31 %32 + %33 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_0 %u32_0 + %34 = OpLoad %u32 %33 + %35 = OpIAdd %u32 %34 %u32_4 + %36 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_0 %u32_0 + OpStore %36 %35 + %37 = OpCompositeConstruct %AT %26 %u32_1 %u32_2 + OpStore %at %37 + %38 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_1 + %39 = OpIAdd %u32 %26 %u32_2 + OpStore %38 %39 + %40 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 + %41 = OpLoad %u32 %40 + %42 = OpIAdd %u32 %41 %u32_5 + %43 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 + OpStore %43 %42 + OpNoLine + OpReturn + OpFunctionEnd diff --git a/tests/compiletests/ui/lang/abi/transparent_u32.rs b/tests/compiletests/ui/lang/abi/transparent_u32.rs new file mode 100644 index 00000000000..5518f64da25 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_u32.rs @@ -0,0 +1,35 @@ +// build-pass +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "\n\W*OpLine .*" -> "" +// normalize-stderr-test "\n\W*OpSource .*" -> "" +// normalize-stderr-test "\n\W*%\d+ = OpString .*" -> "" +// normalize-stderr-test "\n\W*OpCapability VulkanMemoryModel" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use core::marker::PhantomData; +use spirv_std::glam::*; +use spirv_std::spirv; + +#[repr(C)] +#[derive(Default)] +pub struct A(u32); + +#[repr(transparent)] +#[derive(Default)] +pub struct AT(u32); + +#[spirv(vertex)] +pub fn main(a: &mut A, at: &mut AT, #[spirv(local_invocation_index)] tid: u32) { + *a = A(tid); + a.0 = tid + 1; + a.0 += 4; + *at = AT(tid); + at.0 = tid + 2; + at.0 += 5; +} diff --git a/tests/compiletests/ui/lang/abi/transparent_u32.stderr b/tests/compiletests/ui/lang/abi/transparent_u32.stderr new file mode 100644 index 00000000000..cb5f2b66afa --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_u32.stderr @@ -0,0 +1,48 @@ + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Vertex %1 "main" %tid %a %at + OpName %A "A" + OpMemberName %A 0 "0" + OpName %tid "tid" + OpName %a "a" + OpName %at "at" + OpDecorate %tid BuiltIn LocalInvocationIndex + OpDecorate %a Location 0 + OpDecorate %at Location 1 + %u32 = OpTypeInt 32 0 + %A = OpTypeStruct %u32 +%_ptr_Output_A = OpTypePointer Output %A +%_ptr_Output_u32 = OpTypePointer Output %u32 +%_ptr_Input_u32 = OpTypePointer Input %u32 + %void = OpTypeVoid + %12 = OpTypeFunction %void + %tid = OpVariable %_ptr_Input_u32 Input + %a = OpVariable %_ptr_Output_A Output + %u32_0 = OpConstant %u32 0 + %u32_1 = OpConstant %u32 1 + %u32_4 = OpConstant %u32 4 + %at = OpVariable %_ptr_Output_u32 Output + %u32_2 = OpConstant %u32 2 + %u32_5 = OpConstant %u32 5 + %1 = OpFunction %void None %12 + %18 = OpLabel + %19 = OpLoad %u32 %tid + %20 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 + OpStore %20 %19 + %21 = OpIAdd %u32 %19 %u32_1 + %22 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 + OpStore %22 %21 + %23 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 + %24 = OpLoad %u32 %23 + %25 = OpIAdd %u32 %24 %u32_4 + %26 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 + OpStore %26 %25 + OpStore %at %19 + %27 = OpIAdd %u32 %19 %u32_2 + OpStore %at %27 + %28 = OpLoad %u32 %at + %29 = OpIAdd %u32 %28 %u32_5 + OpStore %at %29 + OpNoLine + OpReturn + OpFunctionEnd diff --git a/tests/compiletests/ui/lang/abi/transparent_vec.rs b/tests/compiletests/ui/lang/abi/transparent_vec.rs new file mode 100644 index 00000000000..fb8691dfb25 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_vec.rs @@ -0,0 +1,35 @@ +// build-pass +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "\n\W*OpLine .*" -> "" +// normalize-stderr-test "\n\W*OpSource .*" -> "" +// normalize-stderr-test "\n\W*%\d+ = OpString .*" -> "" +// normalize-stderr-test "\n\W*OpCapability VulkanMemoryModel" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use core::marker::PhantomData; +use spirv_std::glam::*; +use spirv_std::spirv; + +#[repr(C)] +#[derive(Default)] +pub struct A(UVec3); + +#[repr(transparent)] +#[derive(Default)] +pub struct AT(UVec3); + +#[spirv(vertex)] +pub fn main(a: &mut A, at: &mut AT, #[spirv(local_invocation_index)] tid: u32) { + *a = A(UVec3::new(tid, 1, 2)); + a.0 = UVec3::new(tid, 1, 3); + a.0.y += 10; + *at = AT(UVec3::new(tid, 1, 4)); + at.0 = UVec3::new(tid, 1, 5); + at.0.y += 11; +} diff --git a/tests/compiletests/ui/lang/abi/transparent_vec.stderr b/tests/compiletests/ui/lang/abi/transparent_vec.stderr new file mode 100644 index 00000000000..f00d00206b8 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_vec.stderr @@ -0,0 +1,58 @@ + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Vertex %1 "main" %tid %a %at + OpName %AT "AT" + OpName %A "A" + OpMemberName %A 0 "0" + OpName %tid "tid" + OpName %a "a" + OpName %at "at" + OpDecorate %tid BuiltIn LocalInvocationIndex + OpDecorate %a Location 0 + OpDecorate %at Location 1 + %u32 = OpTypeInt 32 0 + %AT = OpTypeVector %u32 3 + %A = OpTypeStruct %AT +%_ptr_Output_A = OpTypePointer Output %A +%_ptr_Output_AT = OpTypePointer Output %AT +%_ptr_Input_u32 = OpTypePointer Input %u32 + %void = OpTypeVoid + %14 = OpTypeFunction %void + %tid = OpVariable %_ptr_Input_u32 Input + %u32_1 = OpConstant %u32 1 + %u32_2 = OpConstant %u32 2 + %a = OpVariable %_ptr_Output_A Output + %u32_0 = OpConstant %u32 0 + %u32_3 = OpConstant %u32 3 +%_ptr_Output_u32 = OpTypePointer Output %u32 + %u32_10 = OpConstant %u32 10 + %u32_4 = OpConstant %u32 4 + %at = OpVariable %_ptr_Output_AT Output + %u32_5 = OpConstant %u32 5 + %u32_11 = OpConstant %u32 11 + %1 = OpFunction %void None %14 + %24 = OpLabel + %25 = OpLoad %u32 %tid + %26 = OpCompositeConstruct %AT %25 %u32_1 %u32_2 + %27 = OpInBoundsAccessChain %_ptr_Output_AT %a %u32_0 + OpStore %27 %26 + %28 = OpCompositeConstruct %AT %25 %u32_1 %u32_3 + %29 = OpInBoundsAccessChain %_ptr_Output_AT %a %u32_0 + OpStore %29 %28 + %30 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_1 + %31 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_1 + %32 = OpLoad %u32 %31 + %33 = OpIAdd %u32 %32 %u32_10 + OpStore %30 %33 + %34 = OpCompositeConstruct %AT %25 %u32_1 %u32_4 + OpStore %at %34 + %35 = OpCompositeConstruct %AT %25 %u32_1 %u32_5 + OpStore %at %35 + %36 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_1 + %37 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_1 + %38 = OpLoad %u32 %37 + %39 = OpIAdd %u32 %38 %u32_11 + OpStore %36 %39 + OpNoLine + OpReturn + OpFunctionEnd diff --git a/tests/compiletests/ui/lang/abi/transparent_zst.rs b/tests/compiletests/ui/lang/abi/transparent_zst.rs new file mode 100644 index 00000000000..ecff534dac2 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_zst.rs @@ -0,0 +1,31 @@ +// build-pass +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "\n\W*OpLine .*" -> "" +// normalize-stderr-test "\n\W*OpSource .*" -> "" +// normalize-stderr-test "\n\W*%\d+ = OpString .*" -> "" +// normalize-stderr-test "\n\W*OpCapability VulkanMemoryModel" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use core::marker::PhantomData; +use spirv_std::glam::*; +use spirv_std::spirv; + +#[derive(Default)] +pub struct A(()); +#[repr(transparent)] +#[derive(Default)] +pub struct AT(()); + +#[spirv(vertex)] +pub fn main(a: &mut A, at: &mut AT) { + *a = A(()); + a.0 = (); + *at = AT(()); + at.0 = (); +} diff --git a/tests/compiletests/ui/lang/abi/transparent_zst.stderr b/tests/compiletests/ui/lang/abi/transparent_zst.stderr new file mode 100644 index 00000000000..eb469a7e19d --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_zst.stderr @@ -0,0 +1,9 @@ + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Vertex %1 "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %4 = OpLabel + OpReturn + OpFunctionEnd diff --git a/tests/compiletests/ui/spirv-attr/location_assignment/mesh_shader.stderr b/tests/compiletests/ui/spirv-attr/location_assignment/mesh_shader.stderr index b23e21f526c..241d2f518ff 100644 --- a/tests/compiletests/ui/spirv-attr/location_assignment/mesh_shader.stderr +++ b/tests/compiletests/ui/spirv-attr/location_assignment/mesh_shader.stderr @@ -7,6 +7,7 @@ OpExecutionMode %1 OutputVertices 9 OpExecutionMode %1 OutputPrimitivesEXT 3 OpExecutionMode %1 OutputTrianglesEXT + OpName %ops__try_trait__NeverShortCircuit__char__3__ "ops::try_trait::NeverShortCircuit<[char; 3]>" OpName %core__ops__Range_usize_ "core::ops::Range" OpMemberName %core__ops__Range_usize_ 0 "start" OpMemberName %core__ops__Range_usize_ 1 "end" @@ -30,18 +31,18 @@ %v4f32 = OpTypeVector %f32 4 %u32 = OpTypeInt 32 0 %u32_9 = OpConstant %u32 9 - %21 = OpTypeArray %v4f32 %u32_9 -%_ptr_Output_21 = OpTypePointer Output %21 + %22 = OpTypeArray %v4f32 %u32_9 +%_ptr_Output_22 = OpTypePointer Output %22 %v3u32 = OpTypeVector %u32 3 %u32_3 = OpConstant %u32 3 - %25 = OpTypeArray %v3u32 %u32_3 -%_ptr_Output_25 = OpTypePointer Output %25 - %27 = OpTypeArray %u32 %u32_9 -%_ptr_Output_27 = OpTypePointer Output %27 - %29 = OpTypeArray %f32 %u32_9 -%_ptr_Output_29 = OpTypePointer Output %29 - %31 = OpTypeArray %u32 %u32_3 -%_ptr_Output_31 = OpTypePointer Output %31 + %26 = OpTypeArray %v3u32 %u32_3 +%_ptr_Output_26 = OpTypePointer Output %26 + %28 = OpTypeArray %u32 %u32_9 +%_ptr_Output_28 = OpTypePointer Output %28 + %30 = OpTypeArray %f32 %u32_9 +%_ptr_Output_30 = OpTypePointer Output %30 +%ops__try_trait__NeverShortCircuit__char__3__ = OpTypeArray %u32 %u32_3 +%_ptr_Output_ops__try_trait__NeverShortCircuit__char__3__ = OpTypePointer Output %ops__try_trait__NeverShortCircuit__char__3__ %33 = OpTypeArray %f32 %u32_3 %_ptr_Output_33 = OpTypePointer Output %33 %void = OpTypeVoid @@ -59,15 +60,15 @@ %f32_0 = OpConstant %f32 0 %f32_1 = OpConstant %f32 1 %_ptr_Output_v4f32 = OpTypePointer Output %v4f32 - %positions = OpVariable %_ptr_Output_21 Output + %positions = OpVariable %_ptr_Output_22 Output %u32_2 = OpConstant %u32 2 %_ptr_Output_u32 = OpTypePointer Output %u32 -%out_per_vertex = OpVariable %_ptr_Output_27 Output +%out_per_vertex = OpVariable %_ptr_Output_28 Output %_ptr_Output_f32 = OpTypePointer Output %f32 -%out_per_vertex2 = OpVariable %_ptr_Output_29 Output +%out_per_vertex2 = OpVariable %_ptr_Output_30 Output %_ptr_Output_v3u32 = OpTypePointer Output %v3u32 - %indices = OpVariable %_ptr_Output_25 Output -%out_per_primitive = OpVariable %_ptr_Output_31 Output + %indices = OpVariable %_ptr_Output_26 Output +%out_per_primitive = OpVariable %_ptr_Output_ops__try_trait__NeverShortCircuit__char__3__ Output %u32_42 = OpConstant %u32 42 %out_per_primitive2 = OpVariable %_ptr_Output_33 Output %f32_69 = OpConstant %f32 69