写点什么

spirv 的指针

作者:Miracle
  • 2025-09-25
    四川
  • 本文字数:1854 字

    阅读完需:约 6 分钟

spirv 的指针

在 spirv 的类型系统中,指针是一个非常重要的环节,简单来说,对结构体成员的访问,对 Array 成员的访问 都是先构造一个指针,然后通过 Store 和 Load 指令完成的

这两个概念特别容易混淆

简单来说 数值到指针的 是 store

指针到数组的 是 load

self.builder.store(var.id, dest.id, None, None)?;
复制代码

这是将 var.id 的 SSA 符号 存储到 dest.id 所代表的数组中

所以在我们的 SSA 动态分配的 vars 列表中需要区分 指针类型和 SSA 类型,指针由于是地址属性,还包括了存储属性 我们常用的 存储属性有四种

pub enum StorageClass {    UniformConstant = 0u32,    Input = 1u32,    Uniform = 2u32,    Workgroup = 4u32,    Function = 7u32,  	StorageBuffer = 12u32,  
复制代码

UniformConstant 外部传入的常量

Input 系统内建量

unitform 外部传入只读

Workgroup 工作组共享

Function 函数内独有

StorageBuffer 这种最常见 宿主程序和 Shader 读写数据


所以我们之前的 Type 不够用了,但是我们又不想把通用的 没有指针的类型系统加上指针这个概念 所以我们为 spirv 后端单独设定一个 SpirvType 类型


#[derive(Debug, Default, Clone, PartialEq, Eq)]pub enum SpirvType {#[default]    Empty,    Var(Type),    Pointer(Type, StorageClass)}
#[derive(Debug, Default, Clone)]pub struct Var { pub id : u32, pub ty : SpirvType,}
复制代码

这样 拿到一个 Var 的时候就包括了存储类 知道如何操作了


#[derive(Debug, Default, Clone)]pub struct Var { pub id : u32, pub ty : SpirvType,}
复制代码


下面是针对 不同个指针和数据类型的 索引操作实现

pub fn extract(&mut self, obj: &Symbol, idx: &Symbol)-> Result<Var>{        let obj = self.get(&obj)?;        match obj.ty.clone() {            SpirvType::Var(ty) => {                match ty {                    Type::Array(ty, num)=> {                        panic!("{:?}", ty)                    }                    Type::Vec(ty, num)=> {          //注意 Vec 只能支持简单类型                        let idx = self.get_const(idx).unwrap();                        let ty = SpirvType::Var((*ty).clone());                        let ty_id = self.get_type(ty.clone());                        let id = self.builder.composite_extract(ty_id, None, obj.id, vec![idx.id])?;                        return Ok(Var{id, ty});                    }                    Type::Struct(def)=> {                        panic!("{:?}", def)                    }                    _=> {                        panic!("{:?}", obj)                    }                }            }            SpirvType::Pointer(ty, cls)=> {                if let Type::Struct(def) = ty {                    let def = self.get_def(&def.name.as_str());                    let name = SmolStr::try_from(self.get_const(idx).unwrap().val).unwrap();                    let (idx, field_ty) = def.get_field(name.as_str()).unwrap();                    let idx = Symbol::Const(self.add_const(Dynamic::U32(idx as u32)));                    let field_ty = SpirvType::Pointer(field_ty, cls);                    let pt_id = self.get_type(field_ty.clone());                    let id = self.builder.access_chain(pt_id, None, obj.id, vec![self.get_const(&idx).unwrap().id])?;                    return Ok(Var{id, ty: field_ty});                } else if let Type::Array(elem_ty, num) = ty {                    let pt_ty = SpirvType::Pointer((*elem_ty).clone(), cls);                    let pt_id = self.get_type(pt_ty.clone());                    let idx = self.get(idx)?;                    let id = self.builder.access_chain(pt_id, None, obj.id, vec![idx.id])?;                    return Ok(Var{id, ty: pt_ty});                }            }            _=> {                panic!("{:?}", obj)            }        }        panic!("")    }
复制代码


大家看到 我们 为没有实现的 case 都写了 panic! 这样碰到没有实现的代码 会 panic! 当然 Rust 的标准做法是 unimple.... 太长了 还是 panic! 方便


用户头像

Miracle

关注

三十年资深码农 2019-10-25 加入

还未添加个人简介

评论

发布
暂无评论
spirv 的指针_Miracle_InfoQ写作社区