Rename Token/Id to Handle and Storage to Arena consistently

This commit is contained in:
Dzmitry Malyshau
2020-03-11 13:50:02 -04:00
committed by Dzmitry Malyshau
parent 7e0b004c16
commit 5e78c71a44
7 changed files with 409 additions and 410 deletions

155
src/arena.rs Normal file
View File

@@ -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<T> {
index: Index,
marker: PhantomData<T>,
}
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
Handle {
index: self.index,
marker: self.marker,
}
}
}
impl<T> Copy for Handle<T> {}
impl<T> PartialEq for Handle<T> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
impl<T> Eq for Handle<T> {}
impl<T> fmt::Debug for Handle<T> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Handle({})", self.index)
}
}
impl<T> hash::Hash for Handle<T> {
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
self.index.hash(hasher)
}
}
impl<T> Handle<T> {
#[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<T> {
/// Values of this arena.
data: Vec<T>,
}
impl<T> Arena<T> {
pub fn new() -> Self {
Arena {
data: Vec::new(),
}
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (Handle<T>, &'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<T> {
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<T> where T: PartialEq {
if let Some(index) = self.data.iter().position(|d| d == &value) {
Handle::new(index as Index)
} else {
self.append(value)
}
}
}
impl<T> std::ops::Index<Handle<T>> for Arena<T> {
type Output = T;
fn index(&self, handle: Handle<T>) -> &T {
&self.data[handle.index as usize]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn append_non_unique() {
let mut arena: Arena<f64> = 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<f64> = 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<f64> = 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<f64> = 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]);
}
}

View File

@@ -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<crate::Function>),
MissingBinding(crate::Token<crate::GlobalVariable>),
MixedExecutionModels(crate::Handle<crate::Function>),
MissingBinding(crate::Handle<crate::GlobalVariable>),
MissingBindTarget(BindSource),
InvalidImageFlags(crate::ImageFlags),
BadName(String),
@@ -111,15 +111,15 @@ trait Indexed {
fn id(&self) -> usize;
}
impl Indexed for crate::Token<crate::Type> {
impl Indexed for crate::Handle<crate::Type> {
const CLASS: &'static str = "Type";
fn id(&self) -> usize { self.index() }
}
impl Indexed for crate::Token<crate::GlobalVariable> {
impl Indexed for crate::Handle<crate::GlobalVariable> {
const CLASS: &'static str = "global";
fn id(&self) -> usize { self.index() }
}
impl Indexed for crate::Token<crate::Function> {
impl Indexed for crate::Handle<crate::Function> {
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<crate::Function>);
struct InputStructIndex(crate::Handle<crate::Function>);
impl Indexed for InputStructIndex {
const CLASS: &'static str = "Input";
const PREFIX: bool = true;
fn id(&self) -> usize { self.0.index() }
}
struct OutputStructIndex(crate::Token<crate::Function>);
struct OutputStructIndex(crate::Handle<crate::Function>);
impl Indexed for OutputStructIndex {
const CLASS: &'static str = "Output";
const PREFIX: bool = true;
@@ -208,22 +208,22 @@ impl<T: Display> Display for Starred<T> {
struct TypedGlobalVariable<'a> {
module: &'a crate::Module,
token: crate::Token<crate::GlobalVariable>,
handle: crate::Handle<crate::GlobalVariable>,
}
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<T> MaybeOwned<'_, T> {
}
impl crate::Module {
fn borrow_type(&self, token: Token<crate::Type>) -> MaybeOwned<crate::TypeInner> {
MaybeOwned::Borrowed(&self.types[token].inner)
fn borrow_type(&self, handle: Handle<crate::Type>) -> MaybeOwned<crate::TypeInner> {
MaybeOwned::Borrowed(&self.types[handle].inner)
}
}
impl<W: Write> Writer<W> {
fn put_expression<'a>(
&mut self,
expr_token: crate::Token<crate::Expression>,
expressions: &crate::Storage<crate::Expression>,
expr_handle: crate::Handle<crate::Expression>,
expressions: &crate::Arena<crate::Expression>,
module: &'a crate::Module,
) -> Result<MaybeOwned<'a, crate::TypeInner>, 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<W: Write> Writer<W> {
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<W: Write> Writer<W> {
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<W: Write> Writer<W> {
}
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<W: Write> Writer<W> {
}
_ => ()
}
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<W: Write> Writer<W> {
// 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<W: Write> Writer<W> {
// 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<W: Write> Writer<W> {
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<W: Write> Writer<W> {
}
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<W: Write> Writer<W> {
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<W: Write> Writer<W> {
}
}
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<W: Write> Writer<W> {
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, ";")?;

View File

@@ -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(),
}
}

View File

@@ -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<crate::Type>),
UnsupportedType(Handle<crate::Type>),
UnsupportedExecutionModel(u32),
UnsupportedStorageClass(u32),
UnsupportedFunctionControl(u32),
@@ -60,7 +60,7 @@ pub enum Error {
InvalidVectorSize(spirv::Word),
InvalidVariableClass(spirv::StorageClass),
InvalidAccessType(spirv::Word),
InvalidAccessIndex(Token<crate::Expression>),
InvalidAccessIndex(Handle<crate::Expression>),
InvalidLoadType(spirv::Word),
InvalidStoreType(spirv::Word),
InvalidBinding(spirv::Word),
@@ -197,32 +197,32 @@ struct EntryPoint {
#[derive(Debug)]
struct LookupType {
token: Token<crate::Type>,
handle: Handle<crate::Type>,
base_id: Option<spirv::Word>,
}
#[derive(Debug)]
struct LookupConstant {
token: Token<crate::Constant>,
handle: Handle<crate::Constant>,
type_id: spirv::Word,
}
#[derive(Debug)]
struct LookupVariable {
token: Token<crate::GlobalVariable>,
handle: Handle<crate::GlobalVariable>,
type_id: spirv::Word,
}
#[derive(Clone, Debug)]
struct LookupExpression {
token: Token<crate::Expression>,
handle: Handle<crate::Expression>,
type_id: spirv::Word,
}
#[derive(Clone, Debug)]
struct LookupSampledImage {
image: Token<crate::Expression>,
sampler: Token<crate::Expression>,
image: Handle<crate::Expression>,
sampler: Handle<crate::Expression>,
}
pub struct Parser<I> {
@@ -239,7 +239,7 @@ pub struct Parser<I> {
lookup_expression: FastHashMap<spirv::Word, LookupExpression>,
lookup_sampled_image: FastHashMap<spirv::Word, LookupSampledImage>,
lookup_function_type: FastHashMap<spirv::Word, LookupFunctionType>,
lookup_function: FastHashMap<spirv::Word, Token<crate::Function>>,
lookup_function: FastHashMap<spirv::Word, Handle<crate::Function>>,
}
impl<I: Iterator<Item = u32>> Parser<I> {
@@ -354,8 +354,8 @@ impl<I: Iterator<Item = u32>> Parser<I> {
fn next_block(
&mut self,
fun: &mut crate::Function,
type_store: &Storage<crate::Type>,
const_store: &Storage<crate::Constant>,
type_arena: &Arena<crate::Type>,
const_arena: &Arena<crate::Constant>,
) -> Result<(), Error> {
loop {
use spirv::Op;
@@ -364,7 +364,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
match inst.op {
Op::AccessChain => {
struct AccessExpression {
base_token: Token<crate::Expression>,
base_handle: Handle<crate::Expression>,
type_id: spirv::Word,
}
inst.expect_at_least(4)?;
@@ -376,7 +376,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
}
self.lookup_expression.insert(result_id, LookupExpression {
token: lexp.token,
handle: lexp.handle,
type_id: result_type_id,
});
}
@@ -489,14 +489,14 @@ impl<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
}
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
Ok(())
}
fn make_expression_storage(&mut self) -> Storage<crate::Expression> {
let mut expressions = Storage::new();
fn make_expression_storage(&mut self) -> Arena<crate::Expression> {
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<I: Iterator<Item = u32>> Parser<I> {
.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<I: Iterator<Item = u32>> Parser<I> {
.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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
_ => 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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
.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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
.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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
};
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
{
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<I: Iterator<Item = u32>> Parser<I> {
}
}
// 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<I: Iterator<Item = u32>> Parser<I> {
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))
}
}

View File

@@ -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<Self::Value, Error<'a>>;
}
impl<'a> StringValueLookup<'a> for FastHashMap<&'a str, Id<crate::Expression>> {
type Value = Id<crate::Expression>;
impl<'a> StringValueLookup<'a> for FastHashMap<&'a str, Handle<crate::Expression>> {
type Value = Handle<crate::Expression>;
fn lookup(&self, key: &'a str) -> Result<Self::Value, Error<'a>> {
self.get(key)
.cloned()
@@ -188,9 +188,9 @@ impl<'a> StringValueLookup<'a> for FastHashMap<&'a str, Id<crate::Expression>> {
struct ExpressionContext<'input,'temp, 'out> {
function: &'out mut crate::Function,
lookup_ident: &'temp FastHashMap<&'input str, Id<crate::Expression>>,
types: &'out mut Storage<crate::Type>,
constants: &'out mut Storage<crate::Constant>,
lookup_ident: &'temp FastHashMap<&'input str, Handle<crate::Expression>>,
types: &'out mut Arena<crate::Type>,
constants: &'out mut Arena<crate::Constant>,
}
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<Id<crate::Expression>, Error<'a>>,
) -> Result<Id<crate::Expression>, Error<'a>> {
mut parser: impl FnMut(&mut Lexer<'a>, ExpressionContext<'a, '_, '_>) -> Result<Handle<crate::Expression>, Error<'a>>,
) -> Result<Handle<crate::Expression>, 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<Scope>,
lookup_type: FastHashMap<String, Id<crate::Type>>,
lookup_type: FastHashMap<String, Handle<crate::Type>>,
}
impl Parser {
@@ -338,8 +338,8 @@ impl Parser {
fn parse_const_expression<'a>(
&mut self,
lexer: &mut Lexer<'a>,
type_store: &mut Storage<crate::Type>,
const_store: &mut Storage<crate::Constant>,
type_arena: &mut Arena<crate::Type>,
const_arena: &mut Arena<crate::Constant>,
) -> Result<crate::ConstantInner, Error<'a>> {
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<Id<crate::Expression>, Error<'a>> {
) -> Result<Handle<crate::Expression>, 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<Id<crate::Expression>, Error<'a>> {
) -> Result<Handle<crate::Expression>, 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<Id<crate::Expression>, Error<'a>> {
) -> Result<Handle<crate::Expression>, 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<crate::Type>,
) -> Result<(&'a str, Id<crate::Type>), Error<'a>> {
type_arena: &mut Arena<crate::Type>,
) -> Result<(&'a str, Handle<crate::Type>), 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<crate::Type>,
const_store: &mut Storage<crate::Constant>,
) -> Result<(&'a str, Option<spirv::StorageClass>, Id<crate::Type>), Error<'a>> {
type_arena: &mut Arena<crate::Type>,
const_arena: &mut Arena<crate::Constant>,
) -> Result<(&'a str, Option<spirv::StorageClass>, Handle<crate::Type>), 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<crate::Type>,
type_arena: &mut Arena<crate::Type>,
) -> Result<Vec<crate::StructMember>, 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<crate::Type>,
) -> Result<Id<crate::Type>, Error<'a>> {
type_arena: &mut Arena<crate::Type>,
) -> Result<Handle<crate::Type>, 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<Id<crate::Function>, Error<'a>> {
) -> Result<Handle<crate::Function>, 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,

View File

@@ -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<String>,
pub binding: Option<Binding>,
pub ty: Token<Type>,
pub ty: Handle<Type>,
}
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<Type>, class: spirv::StorageClass },
Array { base: Token<Type>, size: ArraySize },
Pointer { base: Handle<Type>, class: spirv::StorageClass },
Array { base: Handle<Type>, size: ArraySize },
Struct { members: Vec<StructMember> },
Image { base: Token<Type>, dim: spirv::Dim, flags: ImageFlags },
Image { base: Handle<Type>, dim: spirv::Dim, flags: ImageFlags },
Sampler,
}
@@ -107,7 +107,7 @@ pub struct GlobalVariable {
pub name: Option<String>,
pub class: spirv::StorageClass,
pub binding: Option<Binding>,
pub ty: Token<Type>,
pub ty: Handle<Type>,
}
#[derive(Clone, Copy, Debug)]
@@ -125,33 +125,33 @@ pub enum BinaryOperator {
#[derive(Clone, Debug)]
pub enum Expression {
Access {
base: Token<Expression>,
index: Token<Expression>, //int
base: Handle<Expression>,
index: Handle<Expression>, //int
},
AccessIndex {
base: Token<Expression>,
base: Handle<Expression>,
index: u32,
},
Constant(Token<Constant>),
Constant(Handle<Constant>),
Compose {
ty: Token<Type>,
components: Vec<Token<Expression>>,
ty: Handle<Type>,
components: Vec<Handle<Expression>>,
},
FunctionParameter(u32),
GlobalVariable(Token<GlobalVariable>),
GlobalVariable(Handle<GlobalVariable>),
Load {
pointer: Token<Expression>,
pointer: Handle<Expression>,
},
Mul(Token<Expression>, Token<Expression>),
Mul(Handle<Expression>, Handle<Expression>),
ImageSample {
image: Token<Expression>,
sampler: Token<Expression>,
coordinate: Token<Expression>,
image: Handle<Expression>,
sampler: Handle<Expression>,
coordinate: Handle<Expression>,
},
Binary {
op: BinaryOperator,
left: Token<Expression>,
right: Token<Expression>,
left: Handle<Expression>,
right: Handle<Expression>,
},
}
@@ -164,26 +164,26 @@ pub enum Statement {
Block(Block),
VariableDeclaration {
name: String,
ty: Token<Type>,
value: Option<Token<Expression>>,
ty: Handle<Type>,
value: Option<Handle<Expression>>,
},
If {
condition: Token<Expression>, //bool
condition: Handle<Expression>, //bool
accept: Block,
reject: Block,
},
Switch {
selector: Token<Expression>, //int
selector: Handle<Expression>, //int
cases: FastHashMap<i32, (Block, Option<FallThrough>)>,
default: Block,
},
Return {
value: Option<Token<Expression>>,
value: Option<Handle<Expression>>,
},
Kill,
Store {
pointer: Token<Expression>,
value: Token<Expression>,
pointer: Handle<Expression>,
value: Handle<Expression>,
},
}
@@ -191,9 +191,9 @@ pub enum Statement {
pub struct Function {
pub name: Option<String>,
pub control: spirv::FunctionControl,
pub parameter_types: Vec<Token<Type>>,
pub return_type: Option<Token<Type>>,
pub expressions: Storage<Expression>,
pub parameter_types: Vec<Handle<Type>>,
pub return_type: Option<Handle<Type>>,
pub expressions: Arena<Expression>,
pub body: Block,
}
@@ -201,17 +201,17 @@ pub struct Function {
pub struct EntryPoint {
pub exec_model: spirv::ExecutionModel,
pub name: String,
pub inputs: Vec<Token<GlobalVariable>>,
pub outputs: Vec<Token<GlobalVariable>>,
pub function: Token<Function>,
pub inputs: Vec<Handle<GlobalVariable>>,
pub outputs: Vec<Handle<GlobalVariable>>,
pub function: Handle<Function>,
}
#[derive(Debug)]
pub struct Module {
pub header: Header,
pub types: Storage<Type>,
pub constants: Storage<Constant>,
pub global_variables: Storage<GlobalVariable>,
pub functions: Storage<Function>,
pub types: Arena<Type>,
pub constants: Arena<Constant>,
pub global_variables: Arena<GlobalVariable>,
pub functions: Arena<Function>,
pub entry_points: Vec<EntryPoint>,
}

View File

@@ -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<T> {
index: Index,
marker: PhantomData<T>,
}
impl<T> Clone for Token<T> {
fn clone(&self) -> Self {
Token {
index: self.index,
marker: self.marker,
}
}
}
impl<T> Copy for Token<T> {}
impl<T> PartialEq for Token<T> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
impl<T> Eq for Token<T> {}
impl<T> fmt::Debug for Token<T> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Token({})", self.index)
}
}
impl<T> hash::Hash for Token<T> {
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
self.index.hash(hasher)
}
}
impl<T> Token<T> {
#[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<T> {
/// Values of this storage.
data: Vec<T>,
}
impl<T> Storage<T> {
pub fn new() -> Self {
Storage {
data: Vec::new(),
}
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (Token<T>, &'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<T> {
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<T> where T: PartialEq {
if let Some(index) = self.data.iter().position(|d| d == &value) {
Token::new(index as Index)
} else {
self.append(value)
}
}
}
impl<T> std::ops::Index<Token<T>> for Storage<T> {
type Output = T;
fn index(&self, token: Token<T>) -> &T {
&self.data[token.index as usize]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn append_non_unique() {
let mut storage: Storage<f64> = 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<f64> = 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<f64> = 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<f64> = 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]);
}
}