From d5456a3023b144daf3c1006ccba47e9c102a20a9 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 14 Apr 2026 17:37:09 +0200 Subject: [PATCH 1/2] compiletest for repr transparent --- .../ui/lang/abi/transparent_array.rs | 33 +++++++++ .../ui/lang/abi/transparent_array.stderr | 73 +++++++++++++++++++ .../ui/lang/abi/transparent_nested.rs | 43 +++++++++++ .../ui/lang/abi/transparent_nested.stderr | 72 ++++++++++++++++++ .../ui/lang/abi/transparent_u32.rs | 35 +++++++++ .../ui/lang/abi/transparent_u32.stderr | 48 ++++++++++++ .../ui/lang/abi/transparent_vec.rs | 35 +++++++++ .../ui/lang/abi/transparent_vec.stderr | 59 +++++++++++++++ .../ui/lang/abi/transparent_zst.rs | 31 ++++++++ .../ui/lang/abi/transparent_zst.stderr | 9 +++ 10 files changed, 438 insertions(+) create mode 100644 tests/compiletests/ui/lang/abi/transparent_array.rs create mode 100644 tests/compiletests/ui/lang/abi/transparent_array.stderr create mode 100644 tests/compiletests/ui/lang/abi/transparent_nested.rs create mode 100644 tests/compiletests/ui/lang/abi/transparent_nested.stderr create mode 100644 tests/compiletests/ui/lang/abi/transparent_u32.rs create mode 100644 tests/compiletests/ui/lang/abi/transparent_u32.stderr create mode 100644 tests/compiletests/ui/lang/abi/transparent_vec.rs create mode 100644 tests/compiletests/ui/lang/abi/transparent_vec.stderr create mode 100644 tests/compiletests/ui/lang/abi/transparent_zst.rs create mode 100644 tests/compiletests/ui/lang/abi/transparent_zst.stderr 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 0000000000..1b129c942e --- /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 0000000000..5f195873f7 --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_array.stderr @@ -0,0 +1,73 @@ + 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 %7 ArrayStride 4 + OpDecorate %a Location 0 + OpDecorate %at Location 3 + %u32 = OpTypeInt 32 0 + %u32_3 = OpConstant %u32 3 + %10 = OpTypeArray %u32 %u32_3 + %A = OpTypeStruct %10 +%_ptr_Output_A = OpTypePointer Output %A +%_ptr_Input_u32 = OpTypePointer Input %u32 + %void = OpTypeVoid + %14 = OpTypeFunction %void + %tid = OpVariable %_ptr_Input_u32 Input + %7 = OpTypeArray %u32 %u32_3 + %u32_1 = OpConstant %u32 1 + %u32_2 = OpConstant %u32 2 +%_ptr_Output_10 = OpTypePointer Output %10 + %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_A Output + %u32_5 = OpConstant %u32 5 + %1 = OpFunction %void None %14 + %22 = OpLabel + %23 = OpLoad %u32 %tid + %24 = OpCompositeConstruct %7 %23 %u32_1 %u32_2 + %25 = OpInBoundsAccessChain %_ptr_Output_10 %a %u32_0 + %26 = OpCompositeExtract %u32 %24 0 + %27 = OpCompositeExtract %u32 %24 1 + %28 = OpCompositeExtract %u32 %24 2 + %29 = OpCompositeConstruct %10 %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 %7 %23 %u32_1 %u32_2 + %38 = OpInBoundsAccessChain %_ptr_Output_10 %at %u32_0 + %39 = OpCompositeExtract %u32 %37 0 + %40 = OpCompositeExtract %u32 %37 1 + %41 = OpCompositeExtract %u32 %37 2 + %42 = OpCompositeConstruct %10 %39 %40 %41 + OpStore %38 %42 + %43 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_0 + OpStore %43 %23 + %44 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_1 + OpStore %44 %u32_1 + %45 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_2 + OpStore %45 %u32_2 + %46 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_2 + %47 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_2 + %48 = OpLoad %u32 %47 + %49 = OpIAdd %u32 %48 %u32_5 + OpStore %46 %49 + 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 0000000000..fdd96fda21 --- /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 0000000000..4739236e6e --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_nested.stderr @@ -0,0 +1,72 @@ + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Vertex %1 "main" %tid %a %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 + %v3u32 = OpTypeVector %u32 3 + %A = OpTypeStruct %v3u32 + %B = OpTypeStruct %A +%_ptr_Output_B = OpTypePointer Output %B +%_ptr_Input_u32 = OpTypePointer Input %u32 + %void = OpTypeVoid + %16 = OpTypeFunction %void + %tid = OpVariable %_ptr_Input_u32 Input + %u32_1 = OpConstant %u32 1 + %u32_2 = OpConstant %u32 2 + %A = OpTypeStruct %v3u32 + %B = OpTypeStruct %A + %19 = OpUndef %B +%_ptr_Output_v3u32 = OpTypePointer Output %v3u32 + %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_B Output + %u32_5 = OpConstant %u32 5 + %1 = OpFunction %void None %16 + %25 = OpLabel + %26 = OpLoad %u32 %tid + %27 = OpCompositeConstruct %v3u32 %26 %u32_1 %u32_2 + %28 = OpCompositeInsert %B %27 %19 0 0 + %29 = OpInBoundsAccessChain %_ptr_Output_v3u32 %a %u32_0 %u32_0 + %30 = OpCompositeExtract %v3u32 %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 %v3u32 %26 %u32_1 %u32_2 + %38 = OpCompositeInsert %B %37 %19 0 0 + %39 = OpInBoundsAccessChain %_ptr_Output_v3u32 %at %u32_0 %u32_0 + %40 = OpCompositeExtract %v3u32 %38 0 0 + OpStore %39 %40 + %41 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_0 %u32_1 + %42 = OpIAdd %u32 %26 %u32_2 + OpStore %41 %42 + %43 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_0 %u32_0 + %44 = OpLoad %u32 %43 + %45 = OpIAdd %u32 %44 %u32_5 + %46 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_0 %u32_0 + OpStore %46 %45 + 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 0000000000..5518f64da2 --- /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 0000000000..cb5f2b66af --- /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 0000000000..fb8691dfb2 --- /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 0000000000..e2208c0d0c --- /dev/null +++ b/tests/compiletests/ui/lang/abi/transparent_vec.stderr @@ -0,0 +1,59 @@ + 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 + %v3u32 = OpTypeVector %u32 3 + %A = OpTypeStruct %v3u32 +%_ptr_Output_A = OpTypePointer Output %A +%_ptr_Input_u32 = OpTypePointer Input %u32 + %void = OpTypeVoid + %13 = OpTypeFunction %void + %tid = OpVariable %_ptr_Input_u32 Input + %u32_1 = OpConstant %u32 1 + %u32_2 = OpConstant %u32 2 +%_ptr_Output_v3u32 = OpTypePointer Output %v3u32 + %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_A Output + %u32_5 = OpConstant %u32 5 + %u32_11 = OpConstant %u32 11 + %1 = OpFunction %void None %13 + %24 = OpLabel + %25 = OpLoad %u32 %tid + %26 = OpCompositeConstruct %v3u32 %25 %u32_1 %u32_2 + %27 = OpInBoundsAccessChain %_ptr_Output_v3u32 %a %u32_0 + OpStore %27 %26 + %28 = OpCompositeConstruct %v3u32 %25 %u32_1 %u32_3 + %29 = OpInBoundsAccessChain %_ptr_Output_v3u32 %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 %v3u32 %25 %u32_1 %u32_4 + %35 = OpInBoundsAccessChain %_ptr_Output_v3u32 %at %u32_0 + OpStore %35 %34 + %36 = OpCompositeConstruct %v3u32 %25 %u32_1 %u32_5 + %37 = OpInBoundsAccessChain %_ptr_Output_v3u32 %at %u32_0 + OpStore %37 %36 + %38 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_1 + %39 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_1 + %40 = OpLoad %u32 %39 + %41 = OpIAdd %u32 %40 %u32_11 + OpStore %38 %41 + 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 0000000000..ecff534dac --- /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 0000000000..eb469a7e19 --- /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 From dcce08136721954101c90a170821f9db02c6d0ce Mon Sep 17 00:00:00 2001 From: novacrazy Date: Mon, 13 Apr 2026 12:32:03 -0500 Subject: [PATCH 2/2] Collapse `#[repr(transparent)]` newtypes in SPIR-V type translation --- crates/rustc_codegen_spirv/src/abi.rs | 67 +++++++++++++------ crates/rustc_codegen_spirv/src/spirv_type.rs | 19 ++++-- .../ui/lang/abi/transparent_array.stderr | 59 ++++++++-------- .../ui/lang/abi/transparent_nested.stderr | 48 +++++++------ .../ui/lang/abi/transparent_vec.stderr | 41 ++++++------ .../location_assignment/mesh_shader.stderr | 31 ++++----- 6 files changed, 149 insertions(+), 116 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index da589937f4..0eb0a2722c 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 feedf0778f..262538fb29 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.stderr b/tests/compiletests/ui/lang/abi/transparent_array.stderr index 5f195873f7..5a814ba069 100644 --- a/tests/compiletests/ui/lang/abi/transparent_array.stderr +++ b/tests/compiletests/ui/lang/abi/transparent_array.stderr @@ -1,43 +1,45 @@ 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 %7 ArrayStride 4 + OpDecorate %AT ArrayStride 4 OpDecorate %a Location 0 OpDecorate %at Location 3 %u32 = OpTypeInt 32 0 %u32_3 = OpConstant %u32 3 - %10 = OpTypeArray %u32 %u32_3 - %A = OpTypeStruct %10 + %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 - %14 = OpTypeFunction %void + %15 = OpTypeFunction %void %tid = OpVariable %_ptr_Input_u32 Input - %7 = OpTypeArray %u32 %u32_3 + %AT = OpTypeArray %u32 %u32_3 %u32_1 = OpConstant %u32 1 %u32_2 = OpConstant %u32 2 -%_ptr_Output_10 = OpTypePointer Output %10 %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_A Output + %at = OpVariable %_ptr_Output_AT Output %u32_5 = OpConstant %u32 5 - %1 = OpFunction %void None %14 + %1 = OpFunction %void None %15 %22 = OpLabel %23 = OpLoad %u32 %tid - %24 = OpCompositeConstruct %7 %23 %u32_1 %u32_2 - %25 = OpInBoundsAccessChain %_ptr_Output_10 %a %u32_0 + %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 %10 %26 %27 %28 + %29 = OpCompositeConstruct %AT %26 %27 %28 OpStore %25 %29 %30 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_0 OpStore %30 %23 @@ -50,24 +52,23 @@ %35 = OpLoad %u32 %34 %36 = OpIAdd %u32 %35 %u32_4 OpStore %33 %36 - %37 = OpCompositeConstruct %7 %23 %u32_1 %u32_2 - %38 = OpInBoundsAccessChain %_ptr_Output_10 %at %u32_0 - %39 = OpCompositeExtract %u32 %37 0 - %40 = OpCompositeExtract %u32 %37 1 - %41 = OpCompositeExtract %u32 %37 2 - %42 = OpCompositeConstruct %10 %39 %40 %41 - OpStore %38 %42 - %43 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_0 - OpStore %43 %23 - %44 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_1 - OpStore %44 %u32_1 - %45 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_2 - OpStore %45 %u32_2 - %46 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_2 - %47 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_2 - %48 = OpLoad %u32 %47 - %49 = OpIAdd %u32 %48 %u32_5 - OpStore %46 %49 + %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.stderr b/tests/compiletests/ui/lang/abi/transparent_nested.stderr index 4739236e6e..cee72e7fcd 100644 --- a/tests/compiletests/ui/lang/abi/transparent_nested.stderr +++ b/tests/compiletests/ui/lang/abi/transparent_nested.stderr @@ -1,6 +1,7 @@ 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" @@ -18,33 +19,33 @@ OpDecorate %a Location 0 OpDecorate %at Location 1 %u32 = OpTypeInt 32 0 - %v3u32 = OpTypeVector %u32 3 - %A = OpTypeStruct %v3u32 + %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 - %16 = OpTypeFunction %void + %17 = OpTypeFunction %void %tid = OpVariable %_ptr_Input_u32 Input %u32_1 = OpConstant %u32 1 %u32_2 = OpConstant %u32 2 - %A = OpTypeStruct %v3u32 + %A = OpTypeStruct %AT %B = OpTypeStruct %A - %19 = OpUndef %B -%_ptr_Output_v3u32 = OpTypePointer Output %v3u32 + %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_B Output + %at = OpVariable %_ptr_Output_AT Output %u32_5 = OpConstant %u32 5 - %1 = OpFunction %void None %16 + %1 = OpFunction %void None %17 %25 = OpLabel %26 = OpLoad %u32 %tid - %27 = OpCompositeConstruct %v3u32 %26 %u32_1 %u32_2 - %28 = OpCompositeInsert %B %27 %19 0 0 - %29 = OpInBoundsAccessChain %_ptr_Output_v3u32 %a %u32_0 %u32_0 - %30 = OpCompositeExtract %v3u32 %28 0 0 + %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 @@ -54,19 +55,16 @@ %35 = OpIAdd %u32 %34 %u32_4 %36 = OpInBoundsAccessChain %_ptr_Output_u32 %a %u32_0 %u32_0 %u32_0 OpStore %36 %35 - %37 = OpCompositeConstruct %v3u32 %26 %u32_1 %u32_2 - %38 = OpCompositeInsert %B %37 %19 0 0 - %39 = OpInBoundsAccessChain %_ptr_Output_v3u32 %at %u32_0 %u32_0 - %40 = OpCompositeExtract %v3u32 %38 0 0 - OpStore %39 %40 - %41 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_0 %u32_1 - %42 = OpIAdd %u32 %26 %u32_2 - OpStore %41 %42 - %43 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_0 %u32_0 - %44 = OpLoad %u32 %43 - %45 = OpIAdd %u32 %44 %u32_5 - %46 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_0 %u32_0 - OpStore %46 %45 + %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_vec.stderr b/tests/compiletests/ui/lang/abi/transparent_vec.stderr index e2208c0d0c..f00d00206b 100644 --- a/tests/compiletests/ui/lang/abi/transparent_vec.stderr +++ b/tests/compiletests/ui/lang/abi/transparent_vec.stderr @@ -1,6 +1,7 @@ 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" @@ -10,50 +11,48 @@ OpDecorate %a Location 0 OpDecorate %at Location 1 %u32 = OpTypeInt 32 0 - %v3u32 = OpTypeVector %u32 3 - %A = OpTypeStruct %v3u32 + %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 - %13 = OpTypeFunction %void + %14 = OpTypeFunction %void %tid = OpVariable %_ptr_Input_u32 Input %u32_1 = OpConstant %u32 1 %u32_2 = OpConstant %u32 2 -%_ptr_Output_v3u32 = OpTypePointer Output %v3u32 %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_A Output + %at = OpVariable %_ptr_Output_AT Output %u32_5 = OpConstant %u32 5 %u32_11 = OpConstant %u32 11 - %1 = OpFunction %void None %13 + %1 = OpFunction %void None %14 %24 = OpLabel %25 = OpLoad %u32 %tid - %26 = OpCompositeConstruct %v3u32 %25 %u32_1 %u32_2 - %27 = OpInBoundsAccessChain %_ptr_Output_v3u32 %a %u32_0 + %26 = OpCompositeConstruct %AT %25 %u32_1 %u32_2 + %27 = OpInBoundsAccessChain %_ptr_Output_AT %a %u32_0 OpStore %27 %26 - %28 = OpCompositeConstruct %v3u32 %25 %u32_1 %u32_3 - %29 = OpInBoundsAccessChain %_ptr_Output_v3u32 %a %u32_0 + %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 %v3u32 %25 %u32_1 %u32_4 - %35 = OpInBoundsAccessChain %_ptr_Output_v3u32 %at %u32_0 - OpStore %35 %34 - %36 = OpCompositeConstruct %v3u32 %25 %u32_1 %u32_5 - %37 = OpInBoundsAccessChain %_ptr_Output_v3u32 %at %u32_0 - OpStore %37 %36 - %38 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_1 - %39 = OpInBoundsAccessChain %_ptr_Output_u32 %at %u32_0 %u32_1 - %40 = OpLoad %u32 %39 - %41 = OpIAdd %u32 %40 %u32_11 - OpStore %38 %41 + %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/spirv-attr/location_assignment/mesh_shader.stderr b/tests/compiletests/ui/spirv-attr/location_assignment/mesh_shader.stderr index b23e21f526..241d2f518f 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