From 5e78c71a4443b09e29d2832bdf84d932508db0e7 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 11 Mar 2020 13:50:02 -0400 Subject: [PATCH] Rename Token/Id to Handle and Storage to Arena consistently --- src/arena.rs | 155 ++++++++++++++++++++++++++++++++ src/back/msl.rs | 100 ++++++++++----------- src/front/mod.rs | 10 +-- src/front/spirv.rs | 215 ++++++++++++++++++++++----------------------- src/front/wgsl.rs | 108 +++++++++++------------ src/lib.rs | 76 ++++++++-------- src/storage.rs | 155 -------------------------------- 7 files changed, 409 insertions(+), 410 deletions(-) create mode 100644 src/arena.rs delete mode 100644 src/storage.rs diff --git a/src/arena.rs b/src/arena.rs new file mode 100644 index 0000000000..0ccf0fae63 --- /dev/null +++ b/src/arena.rs @@ -0,0 +1,155 @@ +use std::{ + fmt, + hash, + marker::PhantomData, +}; + +/// An unique index in the arena array that a handle points to. +/// +/// This type is independent of `spirv::Word`. `spirv::Word` is used in data +/// representation. It holds a SPIR-V and refers to that instruction. In +/// structured representation, we use Handle to refer to an SPIR-V instruction. +/// Index is an implementation detail to Handle. +type Index = u32; + +/// A strongly typed reference to a SPIR-V element. +pub struct Handle { + index: Index, + marker: PhantomData, +} + +impl Clone for Handle { + fn clone(&self) -> Self { + Handle { + index: self.index, + marker: self.marker, + } + } +} +impl Copy for Handle {} +impl PartialEq for Handle { + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } +} +impl Eq for Handle {} +impl fmt::Debug for Handle { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Handle({})", self.index) + } +} +impl hash::Hash for Handle { + fn hash(&self, hasher: &mut H) { + self.index.hash(hasher) + } +} + +impl Handle { + #[cfg(test)] + pub const DUMMY: Self = Handle { + index: !0, + marker: PhantomData, + }; + + pub(crate) fn new(index: Index) -> Self { + Handle { + index, + marker: PhantomData, + } + } + + pub fn index(&self) -> usize { + self.index as usize + } +} + +/// An arena holding some kind of component (e.g., type, constant, +/// instruction, etc.) that can be referenced. +#[derive(Debug)] +pub struct Arena { + /// Values of this arena. + data: Vec, +} + +impl Arena { + pub fn new() -> Self { + Arena { + data: Vec::new(), + } + } + + pub fn iter<'a>(&'a self) -> impl Iterator, &'a T)> { + self.data + .iter() + .enumerate() + .map(|(i, v)| (Handle::new(i as Index), v)) + } + + /// Adds a new value to the arena, returning a typed handle. + /// + /// The value is not linked to any SPIR-V module. + pub fn append(&mut self, value: T) -> Handle { + let index = self.data.len() as Index; + self.data.push(value); + Handle::new(index) + } + + /// Adds a value with a check for uniqueness: returns a handle pointing to + /// an existing element if its value matches the given one, or adds a new + /// element otherwise. + pub fn fetch_or_append(&mut self, value: T) -> Handle where T: PartialEq { + if let Some(index) = self.data.iter().position(|d| d == &value) { + Handle::new(index as Index) + } else { + self.append(value) + } + } +} + +impl std::ops::Index> for Arena { + type Output = T; + fn index(&self, handle: Handle) -> &T { + &self.data[handle.index as usize] + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn append_non_unique() { + let mut arena: Arena = Arena::new(); + let t1 = arena.append(0.0); + let t2 = arena.append(0.0); + assert!(t1 != t2); + assert!(arena[t1] == arena[t2]); + } + + #[test] + fn append_unique() { + let mut arena: Arena = Arena::new(); + let t1 = arena.append(std::f64::NAN); + let t2 = arena.append(std::f64::NAN); + assert!(t1 != t2); + assert!(arena[t1] != arena[t2]); + } + + #[test] + fn fetch_or_append_non_unique() { + let mut arena: Arena = Arena::new(); + let t1 = arena.fetch_or_append(0.0); + let t2 = arena.fetch_or_append(0.0); + assert!(t1 == t2); + assert!(arena[t1] == arena[t2]) + } + + #[test] + fn fetch_or_append_unique() { + let mut arena: Arena = Arena::new(); + let t1 = arena.fetch_or_append(std::f64::NAN); + let t2 = arena.fetch_or_append(std::f64::NAN); + assert!(t1 != t2); + assert!(arena[t1] != arena[t2]); + } +} diff --git a/src/back/msl.rs b/src/back/msl.rs index 10336b7823..4152245b6e 100644 --- a/src/back/msl.rs +++ b/src/back/msl.rs @@ -21,7 +21,7 @@ use std::{ }; use crate::{ - storage::Token, + arena::Handle, FastHashMap, FastHashSet }; @@ -53,8 +53,8 @@ pub enum Error { Format(FmtError), UnsupportedExecutionModel(spirv::ExecutionModel), UnexpectedLocation, - MixedExecutionModels(crate::Token), - MissingBinding(crate::Token), + MixedExecutionModels(crate::Handle), + MissingBinding(crate::Handle), MissingBindTarget(BindSource), InvalidImageFlags(crate::ImageFlags), BadName(String), @@ -111,15 +111,15 @@ trait Indexed { fn id(&self) -> usize; } -impl Indexed for crate::Token { +impl Indexed for crate::Handle { const CLASS: &'static str = "Type"; fn id(&self) -> usize { self.index() } } -impl Indexed for crate::Token { +impl Indexed for crate::Handle { const CLASS: &'static str = "global"; fn id(&self) -> usize { self.index() } } -impl Indexed for crate::Token { +impl Indexed for crate::Handle { const CLASS: &'static str = "function"; fn id(&self) -> usize { self.index() } } @@ -134,13 +134,13 @@ impl Indexed for ParameterIndex { const CLASS: &'static str = "param"; fn id(&self) -> usize { self.0 } } -struct InputStructIndex(crate::Token); +struct InputStructIndex(crate::Handle); impl Indexed for InputStructIndex { const CLASS: &'static str = "Input"; const PREFIX: bool = true; fn id(&self) -> usize { self.0.index() } } -struct OutputStructIndex(crate::Token); +struct OutputStructIndex(crate::Handle); impl Indexed for OutputStructIndex { const CLASS: &'static str = "Output"; const PREFIX: bool = true; @@ -208,22 +208,22 @@ impl Display for Starred { struct TypedGlobalVariable<'a> { module: &'a crate::Module, - token: crate::Token, + handle: crate::Handle, } impl Display for TypedGlobalVariable<'_> { fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), FmtError> { - let var = &self.module.global_variables[self.token]; - let name = var.name.or_index(self.token); + let var = &self.module.global_variables[self.handle]; + let name = var.name.or_index(self.handle); let ty = &self.module.types[var.ty]; match ty.inner { crate::TypeInner::Pointer { base, class } => { - let ty_token = match class { + let ty_handle= match class { spirv::StorageClass::Input | spirv::StorageClass::Output | spirv::StorageClass::UniformConstant => base, _ => var.ty }; - let ty_name = self.module.types[ty_token].name.or_index(ty_token); + let ty_name = self.module.types[ty_handle].name.or_index(ty_handle); write!(formatter, "{} {}", ty_name, name) } _ => panic!("Unexpected global type {:?}", var.ty), @@ -308,19 +308,19 @@ impl MaybeOwned<'_, T> { } impl crate::Module { - fn borrow_type(&self, token: Token) -> MaybeOwned { - MaybeOwned::Borrowed(&self.types[token].inner) + fn borrow_type(&self, handle: Handle) -> MaybeOwned { + MaybeOwned::Borrowed(&self.types[handle].inner) } } impl Writer { fn put_expression<'a>( &mut self, - expr_token: crate::Token, - expressions: &crate::Storage, + expr_handle: crate::Handle, + expressions: &crate::Arena, module: &'a crate::Module, ) -> Result, Error> { - let expression = &expressions[expr_token]; + let expression = &expressions[expr_handle]; log::trace!("expression {:?}", expression); match *expression { crate::Expression::AccessIndex { base, index } => { @@ -349,8 +349,8 @@ impl Writer { ref other => panic!("Unexpected indexing of {:?}", other), } } - crate::Expression::Constant(token) => { - let kind = match module.constants[token].inner { + crate::Expression::Constant(handle) => { + let kind = match module.constants[handle].inner { crate::ConstantInner::Sint(value) => { write!(self.out, "{}", value)?; crate::ScalarKind::Sint @@ -376,11 +376,11 @@ impl Writer { match *inner { crate::TypeInner::Vector { size, kind, .. } => { write!(self.out, "{}{}(", scalar_kind_string(kind), vector_size_string(size))?; - for (i, &token) in components.iter().enumerate() { + for (i, &handle) in components.iter().enumerate() { if i != 0 { write!(self.out, ",")?; } - self.put_expression(token, expressions, module)?; + self.put_expression(handle, expressions, module)?; } write!(self.out, ")")?; } @@ -388,8 +388,8 @@ impl Writer { } Ok(MaybeOwned::Borrowed(inner)) } - crate::Expression::GlobalVariable(token) => { - let var = &module.global_variables[token]; + crate::Expression::GlobalVariable(handle) => { + let var = &module.global_variables[handle]; let inner = &module.types[var.ty].inner; match var.class { spirv::StorageClass::Output => { @@ -407,7 +407,7 @@ impl Writer { } _ => () } - let name = var.name.or_index(token); + let name = var.name.or_index(handle); write!(self.out, "{}", name)?; Ok(MaybeOwned::Borrowed(inner)) } @@ -455,8 +455,8 @@ impl Writer { // write down complex types writeln!(self.out, "")?; - for (token, ty) in module.types.iter() { - let name = ty.name.or_index(token); + for (handle, ty) in module.types.iter() { + let name = ty.name.or_index(handle); match ty.inner { crate::TypeInner::Scalar { kind, .. } => { write!(self.out, "typedef {} {}", scalar_kind_string(kind), name)?; @@ -537,27 +537,27 @@ impl Writer { // write down functions let mut uniforms_used = FastHashSet::default(); writeln!(self.out, "")?; - for (fun_token, fun) in module.functions.iter() { - let fun_name = fun.name.or_index(fun_token); + for (fun_handle, fun) in module.functions.iter() { + let fun_name = fun.name.or_index(fun_handle); // find the entry point(s) and inputs/outputs let mut exec_model = None; let mut var_inputs = FastHashSet::default(); let mut var_outputs = FastHashSet::default(); for ep in module.entry_points.iter() { - if ep.function == fun_token { + if ep.function == fun_handle{ var_inputs.extend(ep.inputs.iter().cloned()); var_outputs.extend(ep.outputs.iter().cloned()); if exec_model.is_some() { if exec_model != Some(ep.exec_model) { - return Err(Error::MixedExecutionModels(fun_token)); + return Err(Error::MixedExecutionModels(fun_handle)); } } else { exec_model = Some(ep.exec_model); } } } - let input_name = fun.name.or_index(InputStructIndex(fun_token)); - let output_name = fun.name.or_index(OutputStructIndex(fun_token)); + let input_name = fun.name.or_index(InputStructIndex(fun_handle)); + let output_name = fun.name.or_index(OutputStructIndex(fun_handle)); // make dedicated input/output structs if let Some(em) = exec_model { writeln!(self.out, "struct {} {{", input_name)?; @@ -567,9 +567,9 @@ impl Writer { spirv::ExecutionModel::GLCompute => ("compute", LocationMode::Uniform, LocationMode::Uniform), _ => return Err(Error::UnsupportedExecutionModel(em)), }; - for &token in var_inputs.iter() { - let var = &module.global_variables[token]; - let tyvar = TypedGlobalVariable { module, token }; + for &handle in var_inputs.iter() { + let var = &module.global_variables[handle]; + let tyvar = TypedGlobalVariable { module, handle }; write!(self.out, "\t{}", tyvar)?; if let Some(ref binding) = var.binding { let resolved = options.resolve_binding(binding, in_mode)?; @@ -579,8 +579,8 @@ impl Writer { } writeln!(self.out, "}};")?; writeln!(self.out, "struct {} {{", output_name)?; - for &token in var_outputs.iter() { - let var = &module.global_variables[token]; + for &handle in var_outputs.iter() { + let var = &module.global_variables[handle]; // if it's a struct, lift all the built-in contents up to the root if let crate::TypeInner::Pointer { base, .. } = module.types[var.ty].inner { if let crate::TypeInner::Struct { ref members } = module.types[base].inner { @@ -589,14 +589,14 @@ impl Writer { let ty_name = module.types[member.ty].name.or_index(member.ty); let binding = member.binding .as_ref() - .ok_or(Error::MissingBinding(token))?; + .ok_or(Error::MissingBinding(handle))?; let resolved = options.resolve_binding(binding, out_mode)?; writeln!(self.out, "\t{} {} [[{}]];", ty_name, name, resolved)?; } continue } } - let tyvar = TypedGlobalVariable { module, token }; + let tyvar = TypedGlobalVariable { module, handle }; write!(self.out, "\t{}", tyvar)?; if let Some(ref binding) = var.binding { let resolved = options.resolve_binding(binding, out_mode)?; @@ -623,15 +623,15 @@ impl Writer { } } for (_, expr) in fun.expressions.iter() { - if let crate::Expression::GlobalVariable(token) = *expr { - let var = &module.global_variables[token]; - if var.class == spirv::StorageClass::UniformConstant && !uniforms_used.contains(&token) { - uniforms_used.insert(token); + if let crate::Expression::GlobalVariable(handle) = *expr { + let var = &module.global_variables[handle]; + if var.class == spirv::StorageClass::UniformConstant && !uniforms_used.contains(&handle) { + uniforms_used.insert(handle); let binding = var.binding .as_ref() - .ok_or(Error::MissingBinding(token))?; + .ok_or(Error::MissingBinding(handle))?; let resolved = options.resolve_binding(binding, LocationMode::Uniform)?; - let var = TypedGlobalVariable { module, token }; + let var = TypedGlobalVariable { module, handle }; writeln!(self.out, "\t{} [[{}]],", var, resolved)?; } } @@ -672,11 +672,11 @@ impl Writer { match (value, exec_model) { (None, None) => (), (None, Some(_)) => self.out.write_str(NAME_OUTPUT)?, - (Some(expr_token), None) => { - self.put_expression(expr_token, &fun.expressions, module)?; + (Some(expr_handle), None) => { + self.put_expression(expr_handle, &fun.expressions, module)?; } - (Some(expr_token), Some(_)) => { - panic!("Unable to return value {:?} from an entry point!", expr_token) + (Some(expr_handle), Some(_)) => { + panic!("Unable to return value {:?} from an entry point!", expr_handle) } } writeln!(self.out, ";")?; diff --git a/src/front/mod.rs b/src/front/mod.rs index 484df8f3ce..36c1b701e3 100644 --- a/src/front/mod.rs +++ b/src/front/mod.rs @@ -1,7 +1,7 @@ pub mod spirv; pub mod wgsl; -use crate::storage::Storage; +use crate::arena::Arena; pub const GENERATOR: u32 = 0; @@ -9,10 +9,10 @@ impl crate::Module { fn from_header(header: crate::Header) -> Self { crate::Module { header, - types: Storage::new(), - constants: Storage::new(), - global_variables: Storage::new(), - functions: Storage::new(), + types: Arena::new(), + constants: Arena::new(), + global_variables: Arena::new(), + functions: Arena::new(), entry_points: Vec::new(), } } diff --git a/src/front/spirv.rs b/src/front/spirv.rs index 0c7e4db63f..4c922257a3 100644 --- a/src/front/spirv.rs +++ b/src/front/spirv.rs @@ -2,16 +2,16 @@ ## ID lookups -Our IR links to everything with `Token`, while SPIR-V uses IDs. +Our IR links to everything with `Handle`, while SPIR-V uses IDs. In order to keep track of the associations, the parser has many lookup tables. -There map `spirv::Word` into a specific IR token, plus potentially a bit of +There map `spirv::Word` into a specific IR handle, plus potentially a bit of extra info, such as the related SPIR-V type ID. TODO: would be nice to find ways that avoid looking up as much !*/ use crate::{ - storage::{Storage, Token}, + arena::{Arena, Handle}, FastHashMap, FastHashSet, }; @@ -44,7 +44,7 @@ pub enum Error { UnsupportedCapability(spirv::Capability), UnsupportedExtension(String), UnsupportedExtSet(String), - UnsupportedType(Token), + UnsupportedType(Handle), UnsupportedExecutionModel(u32), UnsupportedStorageClass(u32), UnsupportedFunctionControl(u32), @@ -60,7 +60,7 @@ pub enum Error { InvalidVectorSize(spirv::Word), InvalidVariableClass(spirv::StorageClass), InvalidAccessType(spirv::Word), - InvalidAccessIndex(Token), + InvalidAccessIndex(Handle), InvalidLoadType(spirv::Word), InvalidStoreType(spirv::Word), InvalidBinding(spirv::Word), @@ -197,32 +197,32 @@ struct EntryPoint { #[derive(Debug)] struct LookupType { - token: Token, + handle: Handle, base_id: Option, } #[derive(Debug)] struct LookupConstant { - token: Token, + handle: Handle, type_id: spirv::Word, } #[derive(Debug)] struct LookupVariable { - token: Token, + handle: Handle, type_id: spirv::Word, } #[derive(Clone, Debug)] struct LookupExpression { - token: Token, + handle: Handle, type_id: spirv::Word, } #[derive(Clone, Debug)] struct LookupSampledImage { - image: Token, - sampler: Token, + image: Handle, + sampler: Handle, } pub struct Parser { @@ -239,7 +239,7 @@ pub struct Parser { lookup_expression: FastHashMap, lookup_sampled_image: FastHashMap, lookup_function_type: FastHashMap, - lookup_function: FastHashMap>, + lookup_function: FastHashMap>, } impl> Parser { @@ -354,8 +354,8 @@ impl> Parser { fn next_block( &mut self, fun: &mut crate::Function, - type_store: &Storage, - const_store: &Storage, + type_arena: &Arena, + const_arena: &Arena, ) -> Result<(), Error> { loop { use spirv::Op; @@ -364,7 +364,7 @@ impl> Parser { match inst.op { Op::AccessChain => { struct AccessExpression { - base_token: Token, + base_handle: Handle, type_id: spirv::Word, } inst.expect_at_least(4)?; @@ -376,7 +376,7 @@ impl> Parser { let expr = self.lookup_expression.lookup(base_id)?; let ptr_type = self.lookup_type.lookup(expr.type_id)?; AccessExpression { - base_token: expr.token, + base_handle: expr.handle, type_id: ptr_type.base_id.unwrap(), } }; @@ -384,29 +384,29 @@ impl> Parser { let access_id = self.next()?; log::trace!("\t\t\tlooking up expr {:?}", access_id); let index_expr = self.lookup_expression.lookup(access_id)?.clone(); - let index_type_token = self.lookup_type.lookup(index_expr.type_id)?.token; - match type_store[index_type_token].inner { + let index_type_handle = self.lookup_type.lookup(index_expr.type_id)?.handle; + match type_arena[index_type_handle].inner { crate::TypeInner::Scalar { kind: crate::ScalarKind::Uint, .. } | crate::TypeInner::Scalar { kind: crate::ScalarKind::Sint, .. } => (), - _ => return Err(Error::UnsupportedType(index_type_token)), + _ => return Err(Error::UnsupportedType(index_type_handle)), } log::trace!("\t\t\tlooking up type {:?}", acex.type_id); let type_lookup = self.lookup_type.lookup(acex.type_id)?; - acex = match type_store[type_lookup.token].inner { + acex = match type_arena[type_lookup.handle].inner { crate::TypeInner::Struct { .. } => { - let index = match fun.expressions[index_expr.token] { - crate::Expression::Constant(const_token) => { - match const_store[const_token].inner { + let index = match fun.expressions[index_expr.handle] { + crate::Expression::Constant(const_handle) => { + match const_arena[const_handle].inner { crate::ConstantInner::Uint(v) => v as u32, crate::ConstantInner::Sint(v) => v as u32, - _ => return Err(Error::InvalidAccessIndex(index_expr.token)), + _ => return Err(Error::InvalidAccessIndex(index_expr.handle)), } } - _ => return Err(Error::InvalidAccessIndex(index_expr.token)) + _ => return Err(Error::InvalidAccessIndex(index_expr.handle)) }; AccessExpression { - base_token: fun.expressions.append(crate::Expression::AccessIndex { - base: acex.base_token, + base_handle: fun.expressions.append(crate::Expression::AccessIndex { + base: acex.base_handle, index, }), type_id: *self.lookup_member_type_id @@ -418,20 +418,20 @@ impl> Parser { crate::TypeInner::Vector { .. } | crate::TypeInner::Matrix { .. } => { AccessExpression { - base_token: fun.expressions.append(crate::Expression::Access { - base: acex.base_token, - index: index_expr.token, + base_handle: fun.expressions.append(crate::Expression::Access { + base: acex.base_handle, + index: index_expr.handle, }), type_id: type_lookup.base_id .ok_or(Error::InvalidAccessType(acex.type_id))?, } } - _ => return Err(Error::UnsupportedType(type_lookup.token)), + _ => return Err(Error::UnsupportedType(type_lookup.handle)), }; } self.lookup_expression.insert(result_id, LookupExpression { - token: acex.base_token, + handle: acex.base_handle, type_id: result_type_id, }); } @@ -444,7 +444,7 @@ impl> Parser { let mut lexp = { let expr = self.lookup_expression.lookup(base_id)?; LookupExpression { - token: expr.token, + handle: expr.handle, type_id: expr.type_id, } }; @@ -452,7 +452,7 @@ impl> Parser { let index = self.next()?; log::trace!("\t\t\tlooking up type {:?}", lexp.type_id); let type_lookup = self.lookup_type.lookup(lexp.type_id)?; - let type_id = match type_store[type_lookup.token].inner { + let type_id = match type_arena[type_lookup.handle].inner { crate::TypeInner::Struct { .. } => { *self.lookup_member_type_id .get(&(lexp.type_id, index)) @@ -464,11 +464,11 @@ impl> Parser { type_lookup.base_id .ok_or(Error::InvalidAccessType(lexp.type_id))? } - _ => return Err(Error::UnsupportedType(type_lookup.token)), + _ => return Err(Error::UnsupportedType(type_lookup.handle)), }; lexp = LookupExpression { - token: fun.expressions.append(crate::Expression::AccessIndex { - base: lexp.token, + handle: fun.expressions.append(crate::Expression::AccessIndex { + base: lexp.handle, index, }), type_id, @@ -476,7 +476,7 @@ impl> Parser { } self.lookup_expression.insert(result_id, LookupExpression { - token: lexp.token, + handle: lexp.handle, type_id: result_type_id, }); } @@ -489,14 +489,14 @@ impl> Parser { let comp_id = self.next()?; log::trace!("\t\t\tlooking up expr {:?}", comp_id); let lexp = self.lookup_expression.lookup(comp_id)?; - components.push(lexp.token); + components.push(lexp.handle); } let expr = crate::Expression::Compose { - ty: self.lookup_type.lookup(result_type_id)?.token, + ty: self.lookup_type.lookup(result_type_id)?.handle, components, }; self.lookup_expression.insert(id, LookupExpression { - token: fun.expressions.append(expr), + handle: fun.expressions.append(expr), type_id: result_type_id, }); } @@ -514,15 +514,15 @@ impl> Parser { if base_type.base_id != Some(result_type_id) { return Err(Error::InvalidLoadType(result_type_id)); } - match type_store[base_type.token].inner { + match type_arena[base_type.handle].inner { crate::TypeInner::Pointer { .. } => (), - _ => return Err(Error::UnsupportedType(base_type.token)), + _ => return Err(Error::UnsupportedType(base_type.handle)), } let expr = crate::Expression::Load { - pointer: base_expr.token, + pointer: base_expr.handle, }; self.lookup_expression.insert(result_id, LookupExpression { - token: fun.expressions.append(expr), + handle: fun.expressions.append(expr), type_id: result_type_id, }); } @@ -536,17 +536,17 @@ impl> Parser { } let base_expr = self.lookup_expression.lookup(pointer_id)?; let base_type = self.lookup_type.lookup(base_expr.type_id)?; - match type_store[base_type.token].inner { + match type_arena[base_type.handle].inner { crate::TypeInner::Pointer { .. } => (), - _ => return Err(Error::UnsupportedType(base_type.token)), + _ => return Err(Error::UnsupportedType(base_type.handle)), }; let value_expr = self.lookup_expression.lookup(value_id)?; if base_type.base_id != Some(value_expr.type_id) { return Err(Error::InvalidStoreType(value_expr.type_id)); } fun.body.push(crate::Statement::Store { - pointer: base_expr.token, - value: value_expr.token, + pointer: base_expr.handle, + value: value_expr.handle, }) } Op::Return => { @@ -558,28 +558,28 @@ impl> Parser { inst.expect(5)?; let result_type_id = self.next()?; let result_type_loookup = self.lookup_type.lookup(result_type_id)?; - let (res_size, res_width) = match type_store[result_type_loookup.token].inner { + let (res_size, res_width) = match type_arena[result_type_loookup.handle].inner { crate::TypeInner::Vector { size, kind: crate::ScalarKind::Float, width } => (size, width), - _ => return Err(Error::UnsupportedType(result_type_loookup.token)), + _ => return Err(Error::UnsupportedType(result_type_loookup.handle)), }; let result_id = self.next()?; let vector_id = self.next()?; let scalar_id = self.next()?; let vector_lexp = self.lookup_expression.lookup(vector_id)?; let vector_type_lookup = self.lookup_type.lookup(vector_lexp.type_id)?; - match type_store[vector_type_lookup.token].inner { + match type_arena[vector_type_lookup.handle].inner { crate::TypeInner::Vector { size, kind: crate::ScalarKind::Float, width } if size == res_size && width == res_width => (), - _ => return Err(Error::UnsupportedType(vector_type_lookup.token)), + _ => return Err(Error::UnsupportedType(vector_type_lookup.handle)), }; let scalar_lexp = self.lookup_expression.lookup(scalar_id)?.clone(); let scalar_type_lookup = self.lookup_type.lookup(scalar_lexp.type_id)?; - match type_store[scalar_type_lookup.token].inner { + match type_arena[scalar_type_lookup.handle].inner { crate::TypeInner::Scalar { kind: crate::ScalarKind::Float, width } if width == res_width => (), - _ => return Err(Error::UnsupportedType(scalar_type_lookup.token)), + _ => return Err(Error::UnsupportedType(scalar_type_lookup.handle)), }; - let expr = crate::Expression::Mul(vector_lexp.token, scalar_lexp.token); + let expr = crate::Expression::Mul(vector_lexp.handle, scalar_lexp.handle); self.lookup_expression.insert(result_id, LookupExpression { - token: fun.expressions.append(expr), + handle: fun.expressions.append(expr), type_id: result_type_id, }); } @@ -587,28 +587,28 @@ impl> Parser { inst.expect(5)?; let result_type_id = self.next()?; let result_type_loookup = self.lookup_type.lookup(result_type_id)?; - let (res_size, res_width) = match type_store[result_type_loookup.token].inner { + let (res_size, res_width) = match type_arena[result_type_loookup.handle].inner { crate::TypeInner::Vector { size, kind: crate::ScalarKind::Float, width } => (size, width), - _ => return Err(Error::UnsupportedType(result_type_loookup.token)), + _ => return Err(Error::UnsupportedType(result_type_loookup.handle)), }; let result_id = self.next()?; let matrix_id = self.next()?; let vector_id = self.next()?; let matrix_lexp = self.lookup_expression.lookup(matrix_id)?; let matrix_type_lookup = self.lookup_type.lookup(matrix_lexp.type_id)?; - let columns = match type_store[matrix_type_lookup.token].inner { + let columns = match type_arena[matrix_type_lookup.handle].inner { crate::TypeInner::Matrix { columns, rows, kind: crate::ScalarKind::Float, width } if rows == res_size && width == res_width => columns, - _ => return Err(Error::UnsupportedType(matrix_type_lookup.token)), + _ => return Err(Error::UnsupportedType(matrix_type_lookup.handle)), }; let vector_lexp = self.lookup_expression.lookup(vector_id)?.clone(); let vector_type_lookup = self.lookup_type.lookup(vector_lexp.type_id)?; - match type_store[vector_type_lookup.token].inner { + match type_arena[vector_type_lookup.handle].inner { crate::TypeInner::Vector { size, kind: crate::ScalarKind::Float, width } if size == columns && width == res_width => (), - _ => return Err(Error::UnsupportedType(vector_type_lookup.token)), + _ => return Err(Error::UnsupportedType(vector_type_lookup.handle)), }; - let expr = crate::Expression::Mul(matrix_lexp.token, vector_lexp.token); + let expr = crate::Expression::Mul(matrix_lexp.handle, vector_lexp.handle); self.lookup_expression.insert(result_id, LookupExpression { - token: fun.expressions.append(expr), + handle: fun.expressions.append(expr), type_id: result_type_id, }); } @@ -622,8 +622,8 @@ impl> Parser { let sampler_lexp = self.lookup_expression.lookup(sampler_id)?; //TODO: compare the result type self.lookup_sampled_image.insert(result_id, LookupSampledImage { - image: image_lexp.token, - sampler: sampler_lexp.token, + image: image_lexp.handle, + sampler: sampler_lexp.handle, }); } Op::ImageSampleImplicitLod => { @@ -635,19 +635,19 @@ impl> Parser { let si_lexp = self.lookup_sampled_image.lookup(sampled_image_id)?; let coord_lexp = self.lookup_expression.lookup(coordinate_id)?; let coord_type_lookup = self.lookup_type.lookup(coord_lexp.type_id)?; - match type_store[coord_type_lookup.token].inner { + match type_arena[coord_type_lookup.handle].inner { crate::TypeInner::Scalar { kind: crate::ScalarKind::Float, .. } | crate::TypeInner::Vector { kind: crate::ScalarKind::Float, .. } => (), - _ => return Err(Error::UnsupportedType(coord_type_lookup.token)), + _ => return Err(Error::UnsupportedType(coord_type_lookup.handle)), } //TODO: compare the result type let expr = crate::Expression::ImageSample { image: si_lexp.image, sampler: si_lexp.sampler, - coordinate: coord_lexp.token, + coordinate: coord_lexp.handle, }; self.lookup_expression.insert(result_id, LookupExpression { - token: fun.expressions.append(expr), + handle: fun.expressions.append(expr), type_id: result_type_id, }); } @@ -657,21 +657,21 @@ impl> Parser { Ok(()) } - fn make_expression_storage(&mut self) -> Storage { - let mut expressions = Storage::new(); + fn make_expression_storage(&mut self) -> Arena { + let mut expressions = Arena::new(); assert!(self.lookup_expression.is_empty()); // register global variables for (&id, var) in self.lookup_variable.iter() { self.lookup_expression.insert(id, LookupExpression { type_id: var.type_id, - token: expressions.append(crate::Expression::GlobalVariable(var.token)), + handle: expressions.append(crate::Expression::GlobalVariable(var.handle)), }); } // register constants for (&id, con) in self.lookup_constant.iter() { self.lookup_expression.insert(id, LookupExpression { type_id: con.type_id, - token: expressions.append(crate::Expression::Constant(con.token)), + handle: expressions.append(crate::Expression::Constant(con.handle)), }); } // done @@ -863,7 +863,7 @@ impl> Parser { .map_err(|_| Error::InvalidTypeWidth(width))?, }; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: self.future_decor .remove(&id) .and_then(|dec| dec.name), @@ -884,7 +884,7 @@ impl> Parser { .map_err(|_| Error::InvalidTypeWidth(width))?, }; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: self.future_decor .remove(&id) .and_then(|dec| dec.name), @@ -899,7 +899,7 @@ impl> Parser { let id = self.next()?; let type_id = self.next()?; let type_lookup = self.lookup_type.lookup(type_id)?; - let (kind, width) = match module.types[type_lookup.token].inner { + let (kind, width) = match module.types[type_lookup.handle].inner { crate::TypeInner::Scalar { kind, width } => (kind, width), _ => return Err(Error::InvalidInnerType(type_id)), }; @@ -910,7 +910,7 @@ impl> Parser { width, }; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: self.future_decor .remove(&id) .and_then(|dec| dec.name), @@ -926,7 +926,7 @@ impl> Parser { let vector_type_id = self.next()?; let num_columns = self.next()?; let vector_type_lookup = self.lookup_type.lookup(vector_type_id)?; - let inner = match module.types[vector_type_lookup.token].inner { + let inner = match module.types[vector_type_lookup.handle].inner { crate::TypeInner::Vector { size, kind, width } => crate::TypeInner::Matrix { columns: map_vector_size(num_columns)?, rows: size, @@ -936,7 +936,7 @@ impl> Parser { _ => return Err(Error::InvalidInnerType(vector_type_id)), }; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: self.future_decor .remove(&id) .and_then(|dec| dec.name), @@ -966,11 +966,11 @@ impl> Parser { let storage = self.next()?; let type_id = self.next()?; let inner = crate::TypeInner::Pointer { - base: self.lookup_type.lookup(type_id)?.token, + base: self.lookup_type.lookup(type_id)?.handle, class: map_storage_class(storage)?, }; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: self.future_decor .remove(&id) .and_then(|dec| dec.name), @@ -986,11 +986,11 @@ impl> Parser { let type_id = self.next()?; let length = self.next()?; let inner = crate::TypeInner::Array { - base: self.lookup_type.lookup(type_id)?.token, + base: self.lookup_type.lookup(type_id)?.handle, size: crate::ArraySize::Static(length), }; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: self.future_decor .remove(&id) .and_then(|dec| dec.name), @@ -1005,11 +1005,11 @@ impl> Parser { let id = self.next()?; let type_id = self.next()?; let inner = crate::TypeInner::Array { - base: self.lookup_type.lookup(type_id)?.token, + base: self.lookup_type.lookup(type_id)?.handle, size: crate::ArraySize::Dynamic, }; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: self.future_decor .remove(&id) .and_then(|dec| dec.name), @@ -1025,7 +1025,7 @@ impl> Parser { let mut members = Vec::with_capacity(inst.wc as usize - 2); for i in 0 .. inst.wc as u32 - 2 { let type_id = self.next()?; - let ty = self.lookup_type.lookup(type_id)?.token; + let ty = self.lookup_type.lookup(type_id)?.handle; self.lookup_member_type_id.insert((id, i), type_id); let decor = self.future_member_decor .remove(&(id, i)) @@ -1041,7 +1041,7 @@ impl> Parser { members }; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: self.future_decor .remove(&id) .and_then(|dec| dec.name), @@ -1086,7 +1086,7 @@ impl> Parser { .unwrap_or_default(); let inner = crate::TypeInner::Image { - base: self.lookup_type.lookup(sample_type_id)?.token, + base: self.lookup_type.lookup(sample_type_id)?.handle, dim: if dim > LAST_KNOWN_DIM as u32 { return Err(Error::UnsupportedDim(dim)); } else { @@ -1095,7 +1095,7 @@ impl> Parser { flags, }; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: decor.name, inner, }), @@ -1108,7 +1108,7 @@ impl> Parser { let id = self.next()?; let image_id = self.next()?; self.lookup_type.insert(id, LookupType { - token: self.lookup_type.lookup(image_id)?.token, + handle: self.lookup_type.lookup(image_id)?.handle, base_id: Some(image_id), }); } @@ -1121,7 +1121,7 @@ impl> Parser { .unwrap_or_default(); let inner = crate::TypeInner::Sampler; self.lookup_type.insert(id, LookupType { - token: module.types.append(crate::Type { + handle: module.types.append(crate::Type { name: decor.name, inner, }), @@ -1135,7 +1135,7 @@ impl> Parser { let type_id = self.next()?; let id = self.next()?; let type_lookup = self.lookup_type.lookup(type_id)?; - let inner = match module.types[type_lookup.token].inner { + let inner = match module.types[type_lookup.handle].inner { crate::TypeInner::Scalar { kind: crate::ScalarKind::Uint, width } => { let low = self.next()?; let high = if width > 32 { @@ -1177,10 +1177,10 @@ impl> Parser { }; crate::ConstantInner::Float(extended) } - _ => return Err(Error::UnsupportedType(type_lookup.token)) + _ => return Err(Error::UnsupportedType(type_lookup.handle)) }; self.lookup_constant.insert(id, LookupConstant { - token: module.constants.append(crate::Constant { + handle: module.constants.append(crate::Constant { name: self.future_decor .remove(&id) .and_then(|dec| dec.name), @@ -1204,7 +1204,7 @@ impl> Parser { let dec = self.future_decor .remove(&id) .ok_or(Error::InvalidBinding(id))?; - let binding = match module.types[lookup_type.token].inner { + let binding = match module.types[lookup_type.handle].inner { crate::TypeInner::Pointer { base, class: spirv::StorageClass::Input } | crate::TypeInner::Pointer { base, class: spirv::StorageClass::Output } => { match module.types[base].inner { @@ -1238,11 +1238,10 @@ impl> Parser { name: dec.name, class: map_storage_class(storage)?, binding, - ty: lookup_type.token, + ty: lookup_type.handle, }; - let token = module.global_variables.append(var); self.lookup_variable.insert(id, LookupVariable { - token, + handle: module.global_variables.append(var), type_id, }); } @@ -1268,7 +1267,7 @@ impl> Parser { return_type: if self.lookup_void_type.contains(&result_type) { None } else { - Some(self.lookup_type.lookup(result_type)?.token) + Some(self.lookup_type.lookup(result_type)?.handle) }, expressions: self.make_expression_storage(), body: Vec::new(), @@ -1287,7 +1286,7 @@ impl> Parser { { return Err(Error::WrongFunctionParameterType(type_id)) } - let ty = self.lookup_type.lookup(type_id)?.token; + let ty = self.lookup_type.lookup(type_id)?.handle; fun.parameter_types.push(ty); } Instruction { op, .. } => return Err(Error::InvalidParameter(op)), @@ -1311,8 +1310,8 @@ impl> Parser { } } // done - let token = module.functions.append(fun); - self.lookup_function.insert(fun_id, token); + let handle = module.functions.append(fun); + self.lookup_function.insert(fun_id, handle); self.lookup_expression.clear(); self.lookup_sampled_image.clear(); } @@ -1340,10 +1339,10 @@ impl> Parser { outputs: Vec::new(), }; for var_id in raw.variable_ids { - let token = self.lookup_variable.lookup(var_id)?.token; - match module.global_variables[token].class { - spirv::StorageClass::Input => ep.inputs.push(token), - spirv::StorageClass::Output => ep.outputs.push(token), + let handle = self.lookup_variable.lookup(var_id)?.handle; + match module.global_variables[handle].class { + spirv::StorageClass::Input => ep.inputs.push(handle), + spirv::StorageClass::Output => ep.outputs.push(handle), other => return Err(Error::InvalidVariableClass(other)) } } diff --git a/src/front/wgsl.rs b/src/front/wgsl.rs index 1ed8d18aad..a2d4ebc3d0 100644 --- a/src/front/wgsl.rs +++ b/src/front/wgsl.rs @@ -1,5 +1,5 @@ use crate::{ - storage::{Storage, Token as Id}, + arena::{Arena, Handle}, FastHashMap, }; @@ -177,8 +177,8 @@ trait StringValueLookup<'a> { type Value; fn lookup(&self, key: &'a str) -> Result>; } -impl<'a> StringValueLookup<'a> for FastHashMap<&'a str, Id> { - type Value = Id; +impl<'a> StringValueLookup<'a> for FastHashMap<&'a str, Handle> { + type Value = Handle; fn lookup(&self, key: &'a str) -> Result> { self.get(key) .cloned() @@ -188,9 +188,9 @@ impl<'a> StringValueLookup<'a> for FastHashMap<&'a str, Id> { struct ExpressionContext<'input,'temp, 'out> { function: &'out mut crate::Function, - lookup_ident: &'temp FastHashMap<&'input str, Id>, - types: &'out mut Storage, - constants: &'out mut Storage, + lookup_ident: &'temp FastHashMap<&'input str, Handle>, + types: &'out mut Arena, + constants: &'out mut Arena, } impl<'a> ExpressionContext<'a, '_, '_> { @@ -208,8 +208,8 @@ impl<'a> ExpressionContext<'a, '_, '_> { lexer: &mut Lexer<'a>, middle: Token<'a>, op: crate::BinaryOperator, - mut parser: impl FnMut(&mut Lexer<'a>, ExpressionContext<'a, '_, '_>) -> Result, Error<'a>>, - ) -> Result, Error<'a>> { + mut parser: impl FnMut(&mut Lexer<'a>, ExpressionContext<'a, '_, '_>) -> Result, Error<'a>>, + ) -> Result, Error<'a>> { let mut left = parser(lexer, self.reborrow())?; while lexer.peek() == middle { let _ = lexer.next(); @@ -233,7 +233,7 @@ pub struct ParseError<'a> { pub struct Parser { scopes: Vec, - lookup_type: FastHashMap>, + lookup_type: FastHashMap>, } impl Parser { @@ -338,8 +338,8 @@ impl Parser { fn parse_const_expression<'a>( &mut self, lexer: &mut Lexer<'a>, - type_store: &mut Storage, - const_store: &mut Storage, + type_arena: &mut Arena, + const_arena: &mut Arena, ) -> Result> { self.scopes.push(Scope::ConstantExpr); let inner = match lexer.peek() { @@ -356,10 +356,10 @@ impl Parser { Self::get_constant_inner(word)? } _ => { - let _ty = self.parse_type_decl(lexer, type_store); + let _ty = self.parse_type_decl(lexer, type_arena); Self::expect(lexer, Token::Paren('('))?; while lexer.peek() != Token::Paren(')') { - let _ = self.parse_const_expression(lexer, type_store, const_store)?; + let _ = self.parse_const_expression(lexer, type_arena, const_arena)?; } let _ = lexer.next(); unimplemented!() @@ -373,7 +373,7 @@ impl Parser { &mut self, lexer: &mut Lexer<'a>, mut ctx: ExpressionContext<'a, '_, '_>, - ) -> Result, Error<'a>> { + ) -> Result, Error<'a>> { self.scopes.push(Scope::PrimaryExpr); let backup = lexer.clone(); let expression = match lexer.next() { @@ -384,33 +384,33 @@ impl Parser { return Ok(expr); } Token::Word("true") => { - let id = ctx.constants.append(crate::Constant { + let handle = ctx.constants.append(crate::Constant { name: None, specialization: None, inner: crate::ConstantInner::Bool(true), }); - crate::Expression::Constant(id) + crate::Expression::Constant(handle) } Token::Word("false") => { - let id = ctx.constants.append(crate::Constant { + let handle = ctx.constants.append(crate::Constant { name: None, specialization: None, inner: crate::ConstantInner::Bool(false), }); - crate::Expression::Constant(id) + crate::Expression::Constant(handle) } Token::Number(word) => { - let id = ctx.constants.append(crate::Constant { + let handle = ctx.constants.append(crate::Constant { name: None, specialization: None, inner: Self::get_constant_inner(word)?, }); - crate::Expression::Constant(id) + crate::Expression::Constant(handle) } Token::Word(word) => { - if let Some(id) = ctx.lookup_ident.get(word) { + if let Some(handle) = ctx.lookup_ident.get(word) { self.scopes.pop(); - return Ok(*id); + return Ok(*handle); } *lexer = backup; let ty = self.parse_type_decl(lexer, ctx.types)?; @@ -436,7 +436,7 @@ impl Parser { &mut self, lexer: &mut Lexer<'a>, mut context: ExpressionContext<'a, '_, '_>, - ) -> Result, Error<'a>> { + ) -> Result, Error<'a>> { context.parse_binary_op( lexer, Token::Operation('+'), @@ -454,9 +454,9 @@ impl Parser { &mut self, lexer: &mut Lexer<'a>, mut context: ExpressionContext<'a, '_, '_>, - ) -> Result, Error<'a>> { + ) -> Result, Error<'a>> { self.scopes.push(Scope::GeneralExpr); - let id = context.parse_binary_op( + let handle = context.parse_binary_op( lexer, Token::LogicalOperation('|'), crate::BinaryOperator::LogicalOr, @@ -488,26 +488,26 @@ impl Parser { ), )?; self.scopes.pop(); - Ok(id) + Ok(handle) } fn parse_variable_ident_decl<'a>( &mut self, lexer: &mut Lexer<'a>, - type_store: &mut Storage, - ) -> Result<(&'a str, Id), Error<'a>> { + type_arena: &mut Arena, + ) -> Result<(&'a str, Handle), Error<'a>> { let name = Self::parse_ident(lexer)?; Self::expect(lexer, Token::Separator(':'))?; - let ty = self.parse_type_decl(lexer, type_store)?; + let ty = self.parse_type_decl(lexer, type_arena)?; Ok((name, ty)) } fn parse_variable_decl<'a>( &mut self, lexer: &mut Lexer<'a>, - type_store: &mut Storage, - const_store: &mut Storage, - ) -> Result<(&'a str, Option, Id), Error<'a>> { + type_arena: &mut Arena, + const_arena: &mut Arena, + ) -> Result<(&'a str, Option, Handle), Error<'a>> { self.scopes.push(Scope::VariableDecl); let mut class = None; if let Token::Paren('<') = lexer.peek() { @@ -518,10 +518,10 @@ impl Parser { } let name = Self::parse_ident(lexer)?; Self::expect(lexer, Token::Separator(':'))?; - let ty = self.parse_type_decl(lexer, type_store)?; + let ty = self.parse_type_decl(lexer, type_arena)?; if let Token::Operation('=') = lexer.peek() { let _ = lexer.next(); - let _inner = self.parse_const_expression(lexer, type_store, const_store)?; + let _inner = self.parse_const_expression(lexer, type_arena, const_arena)?; //TODO } Self::expect(lexer, Token::Separator(';'))?; @@ -532,7 +532,7 @@ impl Parser { fn parse_struct_body<'a>( &mut self, lexer: &mut Lexer<'a>, - type_store: &mut Storage, + type_arena: &mut Arena, ) -> Result, Error<'a>> { let mut members = Vec::new(); Self::expect(lexer, Token::Paren('{'))?; @@ -563,7 +563,7 @@ impl Parser { other => return Err(Error::Unexpected(other)), }; Self::expect(lexer, Token::Separator(':'))?; - let ty = self.parse_type_decl(lexer, type_store)?; + let ty = self.parse_type_decl(lexer, type_arena)?; Self::expect(lexer, Token::Separator(';'))?; members.push(crate::StructMember { name: Some(name.to_owned()), @@ -576,8 +576,8 @@ impl Parser { fn parse_type_decl<'a>( &mut self, lexer: &mut Lexer<'a>, - type_store: &mut Storage, - ) -> Result, Error<'a>> { + type_arena: &mut Arena, + ) -> Result, Error<'a>> { self.scopes.push(Scope::TypeDecl); let inner = match lexer.next() { Token::Word("f32") => { @@ -653,13 +653,13 @@ impl Parser { Self::expect(lexer, Token::Paren('<'))?; let class = Self::get_storage_class(Self::parse_ident(lexer)?)?; Self::expect(lexer, Token::Separator(','))?; - let base = self.parse_type_decl(lexer, type_store)?; + let base = self.parse_type_decl(lexer, type_arena)?; Self::expect(lexer, Token::Paren('>'))?; crate::TypeInner::Pointer { base, class } } Token::Word("array") => { Self::expect(lexer, Token::Paren('<'))?; - let base = self.parse_type_decl(lexer, type_store)?; + let base = self.parse_type_decl(lexer, type_arena)?; let size = match lexer.next() { Token::Separator(',') => { let value = Self::parse_uint_literal(lexer)?; @@ -672,20 +672,20 @@ impl Parser { crate::TypeInner::Array { base, size } } Token::Word("struct") => { - let members = self.parse_struct_body(lexer, type_store)?; + let members = self.parse_struct_body(lexer, type_arena)?; crate::TypeInner::Struct { members } } other => return Err(Error::Unexpected(other)), }; self.scopes.pop(); - if let Some((token, _)) = type_store + if let Some((token, _)) = type_arena .iter() .find(|(_, ty)| ty.inner == inner) { return Ok(token); } - Ok(type_store.append(crate::Type { + Ok(type_arena.append(crate::Type { name: None, inner, })) @@ -696,7 +696,7 @@ impl Parser { lexer: &mut Lexer<'a>, module: &mut crate::Module, lookup_global_expression: &FastHashMap<&'a str, crate::Expression>, - ) -> Result, Error<'a>> { + ) -> Result, Error<'a>> { self.scopes.push(Scope::FunctionDecl); // read function name let mut lookup_ident = FastHashMap::default(); @@ -706,13 +706,13 @@ impl Parser { control: spirv::FunctionControl::empty(), parameter_types: Vec::new(), return_type: None, - expressions: Storage::new(), + expressions: Arena::new(), body: Vec::new(), }; // populare initial expressions for (&name, expression) in lookup_global_expression.iter() { - let expr_id = fun.expressions.append(expression.clone()); - lookup_ident.insert(name, expr_id); + let expr_handle = fun.expressions.append(expression.clone()); + lookup_ident.insert(name, expr_handle); } // read parameter list Self::expect(lexer, Token::Paren('('))?; @@ -721,8 +721,8 @@ impl Parser { Self::expect(lexer, Token::Separator(','))?; } let (param_name, param_type) = self.parse_variable_ident_decl(lexer, &mut module.types)?; - let param_id = fun.parameter_types.len() as u32; - let expression_token = fun.expressions.append(crate::Expression::FunctionParameter(param_id)); + let param_index = fun.parameter_types.len() as u32; + let expression_token = fun.expressions.append(crate::Expression::FunctionParameter(param_index)); lookup_ident.insert(param_name, expression_token); fun.parameter_types.push(param_type); } @@ -856,22 +856,22 @@ impl Parser { Self::expect(lexer, Token::Operation('='))?; let inner = self.parse_const_expression(lexer, &mut module.types, &mut module.constants)?; Self::expect(lexer, Token::Separator(';'))?; - let const_id = module.constants.append(crate::Constant { + let const_handle = module.constants.append(crate::Constant { name: Some(name.to_owned()), specialization: None, inner, }); - lookup_global_expression.insert(name, crate::Expression::Constant(const_id)); + lookup_global_expression.insert(name, crate::Expression::Constant(const_handle)); } Token::Word("var") => { let (name, class, ty) = self.parse_variable_decl(lexer, &mut module.types, &mut module.constants)?; - let var_id = module.global_variables.append(crate::GlobalVariable { + let var_handle = module.global_variables.append(crate::GlobalVariable { name: Some(name.to_owned()), class: class.unwrap_or(spirv::StorageClass::Private), binding: binding.take(), ty, }); - lookup_global_expression.insert(name, crate::Expression::GlobalVariable(var_id)); + lookup_global_expression.insert(name, crate::Expression::GlobalVariable(var_handle)); } Token::Word("fn") => { self.parse_function_decl(lexer, module, &lookup_global_expression)?; @@ -893,7 +893,7 @@ impl Parser { let function = module.functions .iter() .find(|(_, fun)| fun.name.as_ref().map(|s| s.as_str()) == Some(fun_ident)) - .map(|(id, _)| id) + .map(|(handle, _)| handle) .ok_or(Error::UnknownFunction(fun_ident))?; module.entry_points.push(crate::EntryPoint { exec_model, diff --git a/src/lib.rs b/src/lib.rs index 71957a1f96..dfaf896261 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ +mod arena; pub mod back; pub mod front; -mod storage; -use crate::storage::{Storage, Token}; +use crate::arena::{Arena, Handle}; use std::{ collections::{HashMap, HashSet}, @@ -49,7 +49,7 @@ pub enum ArraySize { pub struct StructMember { pub name: Option, pub binding: Option, - pub ty: Token, + pub ty: Handle, } bitflags::bitflags! { @@ -73,10 +73,10 @@ pub enum TypeInner { Scalar { kind: ScalarKind, width: Bytes }, Vector { size: VectorSize, kind: ScalarKind, width: Bytes }, Matrix { columns: VectorSize, rows: VectorSize, kind: ScalarKind, width: Bytes }, - Pointer { base: Token, class: spirv::StorageClass }, - Array { base: Token, size: ArraySize }, + Pointer { base: Handle, class: spirv::StorageClass }, + Array { base: Handle, size: ArraySize }, Struct { members: Vec }, - Image { base: Token, dim: spirv::Dim, flags: ImageFlags }, + Image { base: Handle, dim: spirv::Dim, flags: ImageFlags }, Sampler, } @@ -107,7 +107,7 @@ pub struct GlobalVariable { pub name: Option, pub class: spirv::StorageClass, pub binding: Option, - pub ty: Token, + pub ty: Handle, } #[derive(Clone, Copy, Debug)] @@ -125,33 +125,33 @@ pub enum BinaryOperator { #[derive(Clone, Debug)] pub enum Expression { Access { - base: Token, - index: Token, //int + base: Handle, + index: Handle, //int }, AccessIndex { - base: Token, + base: Handle, index: u32, }, - Constant(Token), + Constant(Handle), Compose { - ty: Token, - components: Vec>, + ty: Handle, + components: Vec>, }, FunctionParameter(u32), - GlobalVariable(Token), + GlobalVariable(Handle), Load { - pointer: Token, + pointer: Handle, }, - Mul(Token, Token), + Mul(Handle, Handle), ImageSample { - image: Token, - sampler: Token, - coordinate: Token, + image: Handle, + sampler: Handle, + coordinate: Handle, }, Binary { op: BinaryOperator, - left: Token, - right: Token, + left: Handle, + right: Handle, }, } @@ -164,26 +164,26 @@ pub enum Statement { Block(Block), VariableDeclaration { name: String, - ty: Token, - value: Option>, + ty: Handle, + value: Option>, }, If { - condition: Token, //bool + condition: Handle, //bool accept: Block, reject: Block, }, Switch { - selector: Token, //int + selector: Handle, //int cases: FastHashMap)>, default: Block, }, Return { - value: Option>, + value: Option>, }, Kill, Store { - pointer: Token, - value: Token, + pointer: Handle, + value: Handle, }, } @@ -191,9 +191,9 @@ pub enum Statement { pub struct Function { pub name: Option, pub control: spirv::FunctionControl, - pub parameter_types: Vec>, - pub return_type: Option>, - pub expressions: Storage, + pub parameter_types: Vec>, + pub return_type: Option>, + pub expressions: Arena, pub body: Block, } @@ -201,17 +201,17 @@ pub struct Function { pub struct EntryPoint { pub exec_model: spirv::ExecutionModel, pub name: String, - pub inputs: Vec>, - pub outputs: Vec>, - pub function: Token, + pub inputs: Vec>, + pub outputs: Vec>, + pub function: Handle, } #[derive(Debug)] pub struct Module { pub header: Header, - pub types: Storage, - pub constants: Storage, - pub global_variables: Storage, - pub functions: Storage, + pub types: Arena, + pub constants: Arena, + pub global_variables: Arena, + pub functions: Arena, pub entry_points: Vec, } diff --git a/src/storage.rs b/src/storage.rs deleted file mode 100644 index b56c426ca2..0000000000 --- a/src/storage.rs +++ /dev/null @@ -1,155 +0,0 @@ -use std::{ - fmt, - hash, - marker::PhantomData, -}; - -/// An unique index in the storage array that a token points to. -/// -/// This type is independent of `spirv::Word`. `spirv::Word` is used in data -/// representation. It holds a SPIR-V and refers to that instruction. In -/// structured representation, we use Token to refer to an SPIR-V instruction. -/// Index is an implementation detail to Token. -type Index = u32; - -/// A strongly typed reference to a SPIR-V element. -pub struct Token { - index: Index, - marker: PhantomData, -} - -impl Clone for Token { - fn clone(&self) -> Self { - Token { - index: self.index, - marker: self.marker, - } - } -} -impl Copy for Token {} -impl PartialEq for Token { - fn eq(&self, other: &Self) -> bool { - self.index == other.index - } -} -impl Eq for Token {} -impl fmt::Debug for Token { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "Token({})", self.index) - } -} -impl hash::Hash for Token { - fn hash(&self, hasher: &mut H) { - self.index.hash(hasher) - } -} - -impl Token { - #[cfg(test)] - pub const DUMMY: Self = Token { - index: !0, - marker: PhantomData, - }; - - pub(crate) fn new(index: Index) -> Self { - Token { - index, - marker: PhantomData, - } - } - - pub fn index(&self) -> usize { - self.index as usize - } -} - -/// A structure holding some kind of SPIR-V entity (e.g., type, constant, -/// instruction, etc.) that can be referenced. -#[derive(Debug)] -pub struct Storage { - /// Values of this storage. - data: Vec, -} - -impl Storage { - pub fn new() -> Self { - Storage { - data: Vec::new(), - } - } - - pub fn iter<'a>(&'a self) -> impl Iterator, &'a T)> { - self.data - .iter() - .enumerate() - .map(|(i, v)| (Token::new(i as Index), v)) - } - - /// Adds a new value to the storage, returning a typed token. - /// - /// The value is not linked to any SPIR-V module. - pub fn append(&mut self, value: T) -> Token { - let index = self.data.len() as Index; - self.data.push(value); - Token::new(index) - } - - /// Adds a value with a check for uniqueness: returns a token pointing to - /// an existing element if its value matches the given one, or adds a new - /// element otherwise. - pub fn fetch_or_append(&mut self, value: T) -> Token where T: PartialEq { - if let Some(index) = self.data.iter().position(|d| d == &value) { - Token::new(index as Index) - } else { - self.append(value) - } - } -} - -impl std::ops::Index> for Storage { - type Output = T; - fn index(&self, token: Token) -> &T { - &self.data[token.index as usize] - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn append_non_unique() { - let mut storage: Storage = Storage::new(); - let t1 = storage.append(0.0); - let t2 = storage.append(0.0); - assert!(t1 != t2); - assert!(storage[t1] == storage[t2]); - } - - #[test] - fn append_unique() { - let mut storage: Storage = Storage::new(); - let t1 = storage.append(std::f64::NAN); - let t2 = storage.append(std::f64::NAN); - assert!(t1 != t2); - assert!(storage[t1] != storage[t2]); - } - - #[test] - fn fetch_or_append_non_unique() { - let mut storage: Storage = Storage::new(); - let t1 = storage.fetch_or_append(0.0); - let t2 = storage.fetch_or_append(0.0); - assert!(t1 == t2); - assert!(storage[t1] == storage[t2]) - } - - #[test] - fn fetch_or_append_unique() { - let mut storage: Storage = Storage::new(); - let t1 = storage.fetch_or_append(std::f64::NAN); - let t2 = storage.fetch_or_append(std::f64::NAN); - assert!(t1 != t2); - assert!(storage[t1] != storage[t2]); - } -}