Indexing glam vectors: "Using pointers with OpPhi requires capability VariablePointers or VariablePointersStorageBuffer"

Đang mở
#432 2 bình luận 1 reaction 1 người được giao Xem trên GitHub

@eddyb đang làm issue này rồi.

Từ ngày 9/10/2025.

Đánh giá

Issue này chưa được đánh giá.

Mô tả

bug
Compiletest
// build-pass
// compile-flags: -C llvm-args=--disassemble

use spirv_std::glam::*;
use spirv_std::spirv;

#[spirv(compute(threads(32)))]
pub fn main(
    #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] input: &UVec4,
    #[spirv(descriptor_set = 0, binding = 1, storage_buffer)] output: &mut [u32],
) {
    // works
    // output[0] = input.x;
    // fails
    output[0] = input[0];
    // works
    // output[0] = unsafe { spirv_std::arch::vector_extract_dynamic(*input, 0) };
}
Error
error: error:0:0 - Using pointers with OpPhi requires capability VariablePointers or VariablePointersStorageBuffer
         %37 = OpPhi %_ptr_StorageBuffer_uint %33 %29 %34 %30 %35 %31 %36 %32
Full logs and disassembly

; SPIR-V
; Version: 1.5
; Generator: rspirv
; Bound: 44
OpCapability Shader
OpCapability VulkanMemoryModel
OpMemoryModel Logical Vulkan
OpEntryPoint GLCompute %1 "main" %2 %3
OpExecutionMode %1 LocalSize 32 1 1
%4 = OpString "/home/firestar99/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/glam-0.30.5/src/u32/uvec4.rs"
%5 = OpString "$DIR/minify.rs"
OpSource Unknown 0 %4 "<removed>"
OpSource Unknown 0 %5 "<removed>"
OpName %2 "input"
OpName %3 "output"
OpDecorate %6 Block
OpMemberDecorate %6 0 Offset 0
OpDecorate %7 ArrayStride 4
OpDecorate %8 Block
OpMemberDecorate %8 0 Offset 0
OpDecorate %2 NonWritable
OpDecorate %2 Binding 0
OpDecorate %2 DescriptorSet 0
OpDecorate %3 Binding 1
OpDecorate %3 DescriptorSet 0
%9 = OpTypeInt 32 0
%10 = OpTypeVector %9 4
%6 = OpTypeStruct %10
%11 = OpTypePointer StorageBuffer %6
%7 = OpTypeRuntimeArray %9
%8 = OpTypeStruct %7
%12 = OpTypePointer StorageBuffer %8
%13 = OpTypeVoid
%14 = OpTypeFunction %13
%15 = OpTypePointer StorageBuffer %10
%2 = OpVariable  %11  StorageBuffer
%16 = OpConstant  %9  0
%17 = OpTypePointer StorageBuffer %7
%3 = OpVariable  %12  StorageBuffer
%18 = OpTypePointer StorageBuffer %9
%19 = OpConstant  %9  1
%20 = OpConstant  %9  2
%21 = OpConstant  %9  3
%22 = OpTypeBool
%1 = OpFunction  %13  None %14
%23 = OpLabel
OpLine %5 9 4
%24 = OpInBoundsAccessChain  %15  %2 %16
OpLine %5 10 4
%25 = OpInBoundsAccessChain  %17  %3 %16
%26 = OpArrayLength  %9  %3 0
OpNoLine
OpSelectionMerge %27 None
OpSwitch %16 %28 0 %29 1 %30 2 %31 3 %32
%28 = OpLabel
OpReturn
%29 = OpLabel
OpLine %4 2910 17
%33 = OpInBoundsAccessChain  %18  %24 %16
OpNoLine
OpBranch %27
%30 = OpLabel
OpLine %4 2911 17
%34 = OpInBoundsAccessChain  %18  %24 %19
OpNoLine
OpBranch %27
%31 = OpLabel
OpLine %4 2912 17
%35 = OpInBoundsAccessChain  %18  %24 %20
OpNoLine
OpBranch %27
%32 = OpLabel
OpLine %4 2913 17
%36 = OpInBoundsAccessChain  %18  %24 %21
OpNoLine
OpBranch %27
%27 = OpLabel
%37 = OpPhi  %18  %33 %29 %34 %30 %35 %31 %36 %32
OpLine %5 15 16
%38 = OpLoad  %9  %37
OpLine %5 15 4
%39 = OpULessThan  %22  %16 %26
OpNoLine
OpSelectionMerge %40 None
OpBranchConditional %39 %41 %42
%41 = OpLabel
OpBranch %40
%42 = OpLabel
OpReturn
%40 = OpLabel
OpLine %5 15 4
%43 = OpInBoundsAccessChain  %18  %25 %16
OpStore %43 %38
OpNoLine
OpReturn
OpFunctionEnd
error: error:0:0 - Using pointers with OpPhi requires capability VariablePointers or VariablePointersStorageBuffer
         %37 = OpPhi %_ptr_StorageBuffer_uint %33 %29 %34 %30 %35 %31 %36 %32
  |
  = note: spirv-val failed
  = note: module `$TEST_BUILD_DIR/arch/shared/minify.vulkan1.2`

error: aborting due to 1 previous error

Notes
  • was messing around with shared memory to test https://github.com/Rust-GPU/rust-gpu/pull/379, there is no actual practical usecase for this
  • has nothing to do with shared memory itself
  • structurization bug so @eddyb?
  • I don't need this to be fixed anytime soon, feel free to delay it until "qptr will fix"
Analysis
  • The assembly looks very much like this function:
impl Index<usize> for UVec4 {
    type Output = u32;
    #[inline]
    fn index(&self, index: usize) -> &Self::Output {
        match index {
            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            3 => &self.w,
            _ => panic!("index out of bounds"),
        }
    }
}
  • The function is inlined, but the returned &u32 is still forwarded as a pointer
  • The OpPhi is after the switch, merging the different branches all returning the &u32
  • The deref to u32 only happens afterwards

System Info

rust-gpu main dbf373762d29cdcde621ed40de7d53f36a5d783f

More compiletests

vec

// build-pass

use spirv_std::arch::workgroup_memory_barrier_with_group_sync;
use spirv_std::glam::*;
use spirv_std::spirv;

#[spirv(compute(threads(32)))]
pub fn main(
    #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] input: &UVec4,
    #[spirv(descriptor_set = 0, binding = 1, storage_buffer)] output: &mut [u32],
    #[spirv(workgroup)] shared: &mut UVec4,
    #[spirv(local_invocation_index)] inv_id: UVec3,
) {
    unsafe {
        // copy from input to shared
        if (inv_id.x == 0) {
            *shared = *input;
        }
        workgroup_memory_barrier_with_group_sync();

        // accumulate random values
        let mut accum = 0;
        for i in 0..inv_id.x {
            accum += shared[i as usize % 4];
        }

        // write out
        output[inv_id.x as usize] = accum;
    }
}

BigStruct

// build-pass

use spirv_std::arch::workgroup_memory_barrier_with_group_sync;
use spirv_std::glam::*;
use spirv_std::spirv;

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct MyStruct {
    pub a: Nested,
    pub b: Mat4,
    pub c: UVec2,
}

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct Nested(pub f32);

#[spirv(compute(threads(32)))]
pub fn main(
    #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] input: &MyStruct,
    #[spirv(descriptor_set = 0, binding = 1, storage_buffer)] output: &mut [MyStruct],
    #[spirv(workgroup)] shared: &mut MyStruct,
    #[spirv(local_invocation_index)] inv_id: UVec3,
) {
    unsafe {
        // copy from input to shared
        if (inv_id.x == 0) {
            *shared = *input;
        }
        workgroup_memory_barrier_with_group_sync();

        // accumulate random values
        let mut accum = 0.;
        accum += shared.a.0;
        accum += shared.c.x as f32;
        for axis_id in 0..4 {
            let axis = [shared.b.x_axis, shared.b.y_axis, shared.b.z_axis, shared.b.w_axis][axis_id];
            accum += axis[inv_id.x as usize % 4];
        }

        // write out
        output[inv_id.x as usize].a.0 = accum;
    }
}

Ngôn ngữ chính
Rust
Star
3.4k
Fork
126
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của Rust-GPU/rust-gpu

Tất cả issue của Rust-GPU/rust-gpu

Issue tương tự

Thêm issue về Rust

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.