summaryrefslogtreecommitdiffstats
path: root/third_party/rust/naga/src/back/spv/index.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/naga/src/back/spv/index.rs116
1 files changed, 99 insertions, 17 deletions
diff --git a/third_party/rust/naga/src/back/spv/index.rs b/third_party/rust/naga/src/back/spv/index.rs
index 92e0f88d9a..0effb568be 100644
--- a/third_party/rust/naga/src/back/spv/index.rs
+++ b/third_party/rust/naga/src/back/spv/index.rs
@@ -3,8 +3,9 @@ Bounds-checking for SPIR-V output.
*/
use super::{
- helpers::global_needs_wrapper, selection::Selection, Block, BlockContext, Error, IdGenerator,
- Instruction, Word,
+ helpers::{global_needs_wrapper, map_storage_class},
+ selection::Selection,
+ Block, BlockContext, Error, IdGenerator, Instruction, Word,
};
use crate::{arena::Handle, proc::BoundsCheckPolicy};
@@ -42,32 +43,113 @@ impl<'w> BlockContext<'w> {
array: Handle<crate::Expression>,
block: &mut Block,
) -> Result<Word, Error> {
- // Naga IR permits runtime-sized arrays as global variables or as the
- // final member of a struct that is a global variable. SPIR-V permits
- // only the latter, so this back end wraps bare runtime-sized arrays
- // in a made-up struct; see `helpers::global_needs_wrapper` and its uses.
- // This code must handle both cases.
- let (structure_id, last_member_index) = match self.ir_function.expressions[array] {
+ // Naga IR permits runtime-sized arrays as global variables, or as the
+ // final member of a struct that is a global variable, or one of these
+ // inside a buffer that is itself an element in a buffer bindings array.
+ // SPIR-V requires that runtime-sized arrays are wrapped in structs.
+ // See `helpers::global_needs_wrapper` and its uses.
+ let (opt_array_index_id, global_handle, opt_last_member_index) = match self
+ .ir_function
+ .expressions[array]
+ {
crate::Expression::AccessIndex { base, index } => {
match self.ir_function.expressions[base] {
- crate::Expression::GlobalVariable(handle) => (
- self.writer.global_variables[handle.index()].access_id,
- index,
- ),
- _ => return Err(Error::Validation("array length expression")),
+ // The global variable is an array of buffer bindings of structs,
+ // we are accessing one of them with a static index,
+ // and the last member of it.
+ crate::Expression::AccessIndex {
+ base: base_outer,
+ index: index_outer,
+ } => match self.ir_function.expressions[base_outer] {
+ crate::Expression::GlobalVariable(handle) => {
+ let index_id = self.get_index_constant(index_outer);
+ (Some(index_id), handle, Some(index))
+ }
+ _ => return Err(Error::Validation("array length expression case-1a")),
+ },
+ // The global variable is an array of buffer bindings of structs,
+ // we are accessing one of them with a dynamic index,
+ // and the last member of it.
+ crate::Expression::Access {
+ base: base_outer,
+ index: index_outer,
+ } => match self.ir_function.expressions[base_outer] {
+ crate::Expression::GlobalVariable(handle) => {
+ let index_id = self.cached[index_outer];
+ (Some(index_id), handle, Some(index))
+ }
+ _ => return Err(Error::Validation("array length expression case-1b")),
+ },
+ // The global variable is a buffer, and we are accessing the last member.
+ crate::Expression::GlobalVariable(handle) => {
+ let global = &self.ir_module.global_variables[handle];
+ match self.ir_module.types[global.ty].inner {
+ // The global variable is an array of buffer bindings of run-time arrays.
+ crate::TypeInner::BindingArray { .. } => (Some(index), handle, None),
+ // The global variable is a struct, and we are accessing the last member
+ _ => (None, handle, Some(index)),
+ }
+ }
+ _ => return Err(Error::Validation("array length expression case-1c")),
}
}
+ // The global variable is an array of buffer bindings of arrays.
+ crate::Expression::Access { base, index } => match self.ir_function.expressions[base] {
+ crate::Expression::GlobalVariable(handle) => {
+ let index_id = self.cached[index];
+ let global = &self.ir_module.global_variables[handle];
+ match self.ir_module.types[global.ty].inner {
+ crate::TypeInner::BindingArray { .. } => (Some(index_id), handle, None),
+ _ => return Err(Error::Validation("array length expression case-2a")),
+ }
+ }
+ _ => return Err(Error::Validation("array length expression case-2b")),
+ },
+ // The global variable is a run-time array.
crate::Expression::GlobalVariable(handle) => {
let global = &self.ir_module.global_variables[handle];
if !global_needs_wrapper(self.ir_module, global) {
- return Err(Error::Validation("array length expression"));
+ return Err(Error::Validation("array length expression case-3"));
}
-
- (self.writer.global_variables[handle.index()].var_id, 0)
+ (None, handle, None)
}
- _ => return Err(Error::Validation("array length expression")),
+ _ => return Err(Error::Validation("array length expression case-4")),
};
+ let gvar = self.writer.global_variables[global_handle.index()].clone();
+ let global = &self.ir_module.global_variables[global_handle];
+ let (last_member_index, gvar_id) = match opt_last_member_index {
+ Some(index) => (index, gvar.access_id),
+ None => {
+ if !global_needs_wrapper(self.ir_module, global) {
+ return Err(Error::Validation(
+ "pointer to a global that is not a wrapped array",
+ ));
+ }
+ (0, gvar.var_id)
+ }
+ };
+ let structure_id = match opt_array_index_id {
+ // We are indexing inside a binding array, generate the access op.
+ Some(index_id) => {
+ let element_type_id = match self.ir_module.types[global.ty].inner {
+ crate::TypeInner::BindingArray { base, size: _ } => {
+ let class = map_storage_class(global.space);
+ self.get_pointer_id(base, class)?
+ }
+ _ => return Err(Error::Validation("array length expression case-5")),
+ };
+ let structure_id = self.gen_id();
+ block.body.push(Instruction::access_chain(
+ element_type_id,
+ structure_id,
+ gvar_id,
+ &[index_id],
+ ));
+ structure_id
+ }
+ None => gvar_id,
+ };
let length_id = self.gen_id();
block.body.push(Instruction::array_length(
self.writer.get_uint_type_id(),