mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Proof of concept for "span" feature, with WGSL & GLSL parsing augmented. (#1092)
* Proof of concept for "span" feature, with WGSL parsing augmented. * Review: 1) add_span was actually a bad idea, make it set_span and add set_span_if_unknown too. 2) panics on getting/setting span for invalid handles. 3) only set span for constants with a name 4) don't overwrite spans for types. * Added spans to blocks & more expressions getting spans in frontends. Definitely the shotgunny type of commit, but what can you do. The design I went with made spans mandatory to specify, so I had to go and wire them through wherever I could. * Moved Block to a separate module, +clippy * More spans for types in GLSL. * Remove pointless body method. * Make Arena interface require spans. Another shotgun commit, oh boy... * Fix tests. My loathsome habit to "quickly fix things along the way" made a lot of extra work for me here, having to fix my "fixes" for WGSL parser. * Rustfmt + clippy. * Fix compile-errors with span feature enabled. * Nuked set_span* from orbit. Deleting code feels great! * Code review - move feature flags inside functions. * Fix build with "deserialize" feature enabled.
This commit is contained in:
@@ -42,6 +42,7 @@ spv-out = ["spirv"]
|
||||
wgsl-in = ["codespan-reporting"]
|
||||
wgsl-out = []
|
||||
hlsl-out = []
|
||||
span = ["codespan-reporting"]
|
||||
|
||||
[dev-dependencies]
|
||||
diff = "0.1"
|
||||
|
||||
90
src/arena.rs
90
src/arena.rs
@@ -5,6 +5,8 @@ use std::{cmp::Ordering, fmt, hash, marker::PhantomData, num::NonZeroU32, ops};
|
||||
/// the same size and representation as `Handle<T>`.
|
||||
type Index = NonZeroU32;
|
||||
|
||||
use crate::Span;
|
||||
|
||||
/// A strongly typed reference to an arena item.
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
|
||||
@@ -123,7 +125,6 @@ impl<T> Iterator for Range<T> {
|
||||
/// The arena can be indexed using the given handle to obtain
|
||||
/// a reference to the stored item.
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
|
||||
#[cfg_attr(
|
||||
any(feature = "serialize", feature = "deserialize"),
|
||||
serde(transparent)
|
||||
@@ -132,6 +133,9 @@ impl<T> Iterator for Range<T> {
|
||||
pub struct Arena<T> {
|
||||
/// Values of this arena.
|
||||
data: Vec<T>,
|
||||
#[cfg(feature = "span")]
|
||||
#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))]
|
||||
span_info: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<T> Default for Arena<T> {
|
||||
@@ -148,7 +152,11 @@ impl<T: fmt::Debug> fmt::Debug for Arena<T> {
|
||||
impl<T> Arena<T> {
|
||||
/// Create a new arena with no initial capacity allocated.
|
||||
pub fn new() -> Self {
|
||||
Arena { data: Vec::new() }
|
||||
Arena {
|
||||
data: Vec::new(),
|
||||
#[cfg(feature = "span")]
|
||||
span_info: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the inner vector.
|
||||
@@ -187,11 +195,15 @@ impl<T> Arena<T> {
|
||||
}
|
||||
|
||||
/// Adds a new value to the arena, returning a typed handle.
|
||||
pub fn append(&mut self, value: T) -> Handle<T> {
|
||||
pub fn append(&mut self, value: T, span: Span) -> Handle<T> {
|
||||
#[cfg(not(feature = "span"))]
|
||||
let _ = span;
|
||||
let position = self.data.len() + 1;
|
||||
let index =
|
||||
Index::new(position as u32).expect("Failed to append to Arena. Handle overflows");
|
||||
self.data.push(value);
|
||||
#[cfg(feature = "span")]
|
||||
self.span_info.push(span);
|
||||
Handle::new(index)
|
||||
}
|
||||
|
||||
@@ -207,30 +219,35 @@ impl<T> Arena<T> {
|
||||
/// returns a handle pointing to
|
||||
/// an existing element if the check succeeds, or adds a new
|
||||
/// element otherwise.
|
||||
pub fn fetch_if_or_append<F: Fn(&T, &T) -> bool>(&mut self, value: T, fun: F) -> Handle<T> {
|
||||
pub fn fetch_if_or_append<F: Fn(&T, &T) -> bool>(
|
||||
&mut self,
|
||||
value: T,
|
||||
span: Span,
|
||||
fun: F,
|
||||
) -> Handle<T> {
|
||||
if let Some(index) = self.data.iter().position(|d| fun(d, &value)) {
|
||||
let index = unsafe { Index::new_unchecked((index + 1) as u32) };
|
||||
Handle::new(index)
|
||||
} else {
|
||||
self.append(value)
|
||||
self.append(value, span)
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a value with a check for uniqueness, where the check is plain comparison.
|
||||
pub fn fetch_or_append(&mut self, value: T) -> Handle<T>
|
||||
pub fn fetch_or_append(&mut self, value: T, span: Span) -> Handle<T>
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
self.fetch_if_or_append(value, T::eq)
|
||||
self.fetch_if_or_append(value, span, T::eq)
|
||||
}
|
||||
|
||||
pub fn try_get(&self, handle: Handle<T>) -> Option<&T> {
|
||||
self.data.get(handle.index.get() as usize - 1)
|
||||
self.data.get(handle.index())
|
||||
}
|
||||
|
||||
/// Get a mutable reference to an element in the arena.
|
||||
pub fn get_mut(&mut self, handle: Handle<T>) -> &mut T {
|
||||
self.data.get_mut(handle.index.get() as usize - 1).unwrap()
|
||||
self.data.get_mut(handle.index()).unwrap()
|
||||
}
|
||||
|
||||
/// Get the range of handles from a particular number of elements to the end.
|
||||
@@ -245,6 +262,39 @@ impl<T> Arena<T> {
|
||||
pub fn clear(&mut self) {
|
||||
self.data.clear()
|
||||
}
|
||||
|
||||
pub fn get_span(&self, handle: Handle<T>) -> &Span {
|
||||
#[cfg(feature = "span")]
|
||||
{
|
||||
return self.span_info.get(handle.index()).unwrap_or(&Span::Unknown);
|
||||
}
|
||||
#[cfg(not(feature = "span"))]
|
||||
{
|
||||
let _ = handle;
|
||||
&Span::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize")]
|
||||
impl<'de, T> serde::Deserialize<'de> for Arena<T>
|
||||
where
|
||||
T: serde::Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let data = Vec::deserialize(deserializer)?;
|
||||
#[cfg(feature = "span")]
|
||||
let span_info = std::iter::repeat(Span::Unknown).take(data.len()).collect();
|
||||
|
||||
Ok(Self {
|
||||
data,
|
||||
#[cfg(feature = "span")]
|
||||
span_info,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Index<Handle<T>> for Arena<T> {
|
||||
@@ -254,6 +304,12 @@ impl<T> ops::Index<Handle<T>> for Arena<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::IndexMut<Handle<T>> for Arena<T> {
|
||||
fn index_mut(&mut self, handle: Handle<T>) -> &mut T {
|
||||
&mut self.data[handle.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Index<Range<T>> for Arena<T> {
|
||||
type Output = [T];
|
||||
fn index(&self, range: Range<T>) -> &[T] {
|
||||
@@ -268,8 +324,8 @@ mod tests {
|
||||
#[test]
|
||||
fn append_non_unique() {
|
||||
let mut arena: Arena<u8> = Arena::new();
|
||||
let t1 = arena.append(0);
|
||||
let t2 = arena.append(0);
|
||||
let t1 = arena.append(0, Default::default());
|
||||
let t2 = arena.append(0, Default::default());
|
||||
assert!(t1 != t2);
|
||||
assert!(arena[t1] == arena[t2]);
|
||||
}
|
||||
@@ -277,8 +333,8 @@ mod tests {
|
||||
#[test]
|
||||
fn append_unique() {
|
||||
let mut arena: Arena<u8> = Arena::new();
|
||||
let t1 = arena.append(0);
|
||||
let t2 = arena.append(1);
|
||||
let t1 = arena.append(0, Default::default());
|
||||
let t2 = arena.append(1, Default::default());
|
||||
assert!(t1 != t2);
|
||||
assert!(arena[t1] != arena[t2]);
|
||||
}
|
||||
@@ -286,8 +342,8 @@ mod tests {
|
||||
#[test]
|
||||
fn fetch_or_append_non_unique() {
|
||||
let mut arena: Arena<u8> = Arena::new();
|
||||
let t1 = arena.fetch_or_append(0);
|
||||
let t2 = arena.fetch_or_append(0);
|
||||
let t1 = arena.fetch_or_append(0, Default::default());
|
||||
let t2 = arena.fetch_or_append(0, Default::default());
|
||||
assert!(t1 == t2);
|
||||
assert!(arena[t1] == arena[t2])
|
||||
}
|
||||
@@ -295,8 +351,8 @@ mod tests {
|
||||
#[test]
|
||||
fn fetch_or_append_unique() {
|
||||
let mut arena: Arena<u8> = Arena::new();
|
||||
let t1 = arena.fetch_or_append(0);
|
||||
let t2 = arena.fetch_or_append(1);
|
||||
let t1 = arena.fetch_or_append(0, Default::default());
|
||||
let t2 = arena.fetch_or_append(1, Default::default());
|
||||
assert!(t1 != t2);
|
||||
assert!(arena[t1] != arena[t2]);
|
||||
}
|
||||
|
||||
@@ -2555,30 +2555,41 @@ fn test_stack_size() {
|
||||
use crate::valid::{Capabilities, ValidationFlags};
|
||||
// create a module with at least one expression nested
|
||||
let mut module = crate::Module::default();
|
||||
let constant = module.constants.append(crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
value: crate::ScalarValue::Float(1.0),
|
||||
width: 4,
|
||||
let constant = module.constants.append(
|
||||
crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
value: crate::ScalarValue::Float(1.0),
|
||||
width: 4,
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
let mut fun = crate::Function::default();
|
||||
let const_expr = fun
|
||||
.expressions
|
||||
.append(crate::Expression::Constant(constant));
|
||||
let nested_expr = fun.expressions.append(crate::Expression::Unary {
|
||||
op: crate::UnaryOperator::Negate,
|
||||
expr: const_expr,
|
||||
});
|
||||
fun.body
|
||||
.push(crate::Statement::Emit(fun.expressions.range_from(1)));
|
||||
fun.body.push(crate::Statement::If {
|
||||
condition: nested_expr,
|
||||
accept: Vec::new(),
|
||||
reject: Vec::new(),
|
||||
});
|
||||
let _ = module.functions.append(fun);
|
||||
.append(crate::Expression::Constant(constant), Default::default());
|
||||
let nested_expr = fun.expressions.append(
|
||||
crate::Expression::Unary {
|
||||
op: crate::UnaryOperator::Negate,
|
||||
expr: const_expr,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
fun.body.push(
|
||||
crate::Statement::Emit(fun.expressions.range_from(1)),
|
||||
Default::default(),
|
||||
);
|
||||
fun.body.push(
|
||||
crate::Statement::If {
|
||||
condition: nested_expr,
|
||||
accept: crate::Block::new(),
|
||||
reject: crate::Block::new(),
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
let _ = module.functions.append(fun, Default::default());
|
||||
// analyse the module
|
||||
let info = crate::valid::Validator::new(ValidationFlags::empty(), Capabilities::empty())
|
||||
.validate(&module)
|
||||
|
||||
@@ -119,13 +119,12 @@ impl<'w> BlockContext<'w> {
|
||||
Some(ix) => ix,
|
||||
};
|
||||
let array_index_u32_id = self.cached[array_index];
|
||||
let coordinate_scalar_type_id =
|
||||
self.get_type_id(LookupType::Local(LocalType::Value {
|
||||
vector_size: None,
|
||||
kind: crate::ScalarKind::Float,
|
||||
width: 4,
|
||||
pointer_class: None,
|
||||
}))?;
|
||||
let coordinate_scalar_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
|
||||
vector_size: None,
|
||||
kind: crate::ScalarKind::Float,
|
||||
width: 4,
|
||||
pointer_class: None,
|
||||
}))?;
|
||||
let array_index_f32_id = self.gen_id();
|
||||
block.body.push(Instruction::unary(
|
||||
spirv::Op::ConvertUToF,
|
||||
@@ -161,7 +160,7 @@ impl<'w> BlockContext<'w> {
|
||||
block.body.push(Instruction::composite_construct(
|
||||
extended_coordinate_type_id,
|
||||
id,
|
||||
&[coordinate_id, array_index_f32_id]
|
||||
&[coordinate_id, array_index_f32_id],
|
||||
));
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
131
src/block.rs
Normal file
131
src/block.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
use crate::{Span, Statement};
|
||||
use std::ops::{Deref, DerefMut, RangeBounds};
|
||||
|
||||
/// A code block is a vector of statements, with maybe a vector of spans.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(
|
||||
any(feature = "serialize", feature = "deserialize"),
|
||||
serde(transparent)
|
||||
)]
|
||||
pub struct Block {
|
||||
body: Vec<Statement>,
|
||||
#[cfg(feature = "span")]
|
||||
#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))]
|
||||
span_info: Vec<Span>,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
body: Vec::new(),
|
||||
#[cfg(feature = "span")]
|
||||
span_info: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_vec(body: Vec<Statement>) -> Self {
|
||||
#[cfg(feature = "span")]
|
||||
let span_info = std::iter::repeat(Span::Unknown).take(body.len()).collect();
|
||||
Self {
|
||||
body,
|
||||
#[cfg(feature = "span")]
|
||||
span_info,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
body: Vec::with_capacity(capacity),
|
||||
#[cfg(feature = "span")]
|
||||
span_info: Vec::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn push(&mut self, end: Statement, span: Span) {
|
||||
self.body.push(end);
|
||||
#[cfg(feature = "span")]
|
||||
self.span_info.push(span);
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, item: Option<(Statement, Span)>) {
|
||||
if let Some((end, span)) = item {
|
||||
self.push(end, span)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extend_block(&mut self, other: Self) {
|
||||
#[cfg(feature = "span")]
|
||||
self.span_info.extend(other.span_info);
|
||||
self.body.extend(other.body);
|
||||
}
|
||||
|
||||
pub fn cull<R: RangeBounds<usize> + Clone>(&mut self, range: R) {
|
||||
#[cfg(feature = "span")]
|
||||
self.span_info.drain(range.clone());
|
||||
self.body.drain(range);
|
||||
}
|
||||
|
||||
pub fn splice<R: RangeBounds<usize> + Clone>(&mut self, range: R, other: Self) {
|
||||
#[cfg(feature = "span")]
|
||||
self.span_info
|
||||
.splice(range.clone(), other.span_info.into_iter());
|
||||
self.body.splice(range, other.body.into_iter());
|
||||
}
|
||||
|
||||
pub fn span_iter_mut(&mut self) -> impl Iterator<Item = (&mut Statement, Option<&mut Span>)> {
|
||||
#[cfg(feature = "span")]
|
||||
let span_iter = self.span_info.iter_mut().map(Some);
|
||||
#[cfg(not(feature = "span"))]
|
||||
let span_iter = std::iter::repeat_with(|| None);
|
||||
|
||||
self.body.iter_mut().zip(span_iter)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.body.is_empty()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.body.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Block {
|
||||
type Target = [Statement];
|
||||
fn deref(&self) -> &[Statement] {
|
||||
&self.body
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Block {
|
||||
fn deref_mut(&mut self) -> &mut [Statement] {
|
||||
&mut self.body
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Block {
|
||||
type Item = &'a Statement;
|
||||
type IntoIter = std::slice::Iter<'a, Statement>;
|
||||
|
||||
fn into_iter(self) -> std::slice::Iter<'a, Statement> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize")]
|
||||
impl<'de> serde::Deserialize<'de> for Block {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
Ok(Self::from_vec(Vec::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Statement>> for Block {
|
||||
fn from(body: Vec<Statement>) -> Self {
|
||||
Self::from_vec(body)
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,7 @@ impl<'a> ConstantSolver<'a> {
|
||||
&mut self,
|
||||
expr: Handle<Expression>,
|
||||
) -> Result<Handle<Constant>, ConstantSolvingError> {
|
||||
let span = self.expressions.get_span(expr).clone();
|
||||
match self.expressions[expr] {
|
||||
Expression::Constant(constant) => Ok(constant),
|
||||
Expression::AccessIndex { base, index } => self.access(base, index as usize),
|
||||
@@ -88,14 +89,17 @@ impl<'a> ConstantSolver<'a> {
|
||||
|
||||
//TODO: register the new type if needed
|
||||
let ty = ty.ok_or(ConstantSolvingError::DestinationTypeNotFound)?;
|
||||
Ok(self.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty,
|
||||
components: vec![value_constant; size as usize],
|
||||
Ok(self.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty,
|
||||
components: vec![value_constant; size as usize],
|
||||
},
|
||||
},
|
||||
}))
|
||||
span,
|
||||
))
|
||||
}
|
||||
Expression::Swizzle {
|
||||
size,
|
||||
@@ -129,11 +133,14 @@ impl<'a> ConstantSolver<'a> {
|
||||
.map(|&sc| src_components[sc as usize])
|
||||
.collect();
|
||||
|
||||
Ok(self.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite { ty, components },
|
||||
}))
|
||||
Ok(self.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite { ty, components },
|
||||
},
|
||||
span,
|
||||
))
|
||||
}
|
||||
Expression::Compose { ty, ref components } => {
|
||||
let components = components
|
||||
@@ -141,22 +148,25 @@ impl<'a> ConstantSolver<'a> {
|
||||
.map(|c| self.solve(*c))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(self.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite { ty, components },
|
||||
}))
|
||||
Ok(self.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite { ty, components },
|
||||
},
|
||||
span,
|
||||
))
|
||||
}
|
||||
Expression::Unary { expr, op } => {
|
||||
let expr_constant = self.solve(expr)?;
|
||||
|
||||
self.unary_op(op, expr_constant)
|
||||
self.unary_op(op, expr_constant, span)
|
||||
}
|
||||
Expression::Binary { left, right, op } => {
|
||||
let left_constant = self.solve(left)?;
|
||||
let right_constant = self.solve(right)?;
|
||||
|
||||
self.binary_op(op, left_constant, right_constant)
|
||||
self.binary_op(op, left_constant, right_constant, span)
|
||||
}
|
||||
Expression::Math { fun, arg, arg1, .. } => {
|
||||
let arg = self.solve(arg)?;
|
||||
@@ -192,11 +202,14 @@ impl<'a> ConstantSolver<'a> {
|
||||
_ => return Err(ConstantSolvingError::InvalidMathArg),
|
||||
};
|
||||
|
||||
Ok(self.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar { width, value },
|
||||
}))
|
||||
Ok(self.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar { width, value },
|
||||
},
|
||||
span,
|
||||
))
|
||||
}
|
||||
_ => Err(ConstantSolvingError::NotImplemented(format!("{:?}", fun))),
|
||||
}
|
||||
@@ -209,7 +222,7 @@ impl<'a> ConstantSolver<'a> {
|
||||
let expr_constant = self.solve(expr)?;
|
||||
|
||||
match convert {
|
||||
Some(width) => self.cast(expr_constant, kind, width),
|
||||
Some(width) => self.cast(expr_constant, kind, width, span),
|
||||
None => Err(ConstantSolvingError::Bitcast),
|
||||
}
|
||||
}
|
||||
@@ -288,6 +301,7 @@ impl<'a> ConstantSolver<'a> {
|
||||
constant: Handle<Constant>,
|
||||
kind: ScalarKind,
|
||||
target_width: crate::Bytes,
|
||||
span: crate::Span,
|
||||
) -> Result<Handle<Constant>, ConstantSolvingError> {
|
||||
fn inner_cast<A: num_traits::FromPrimitive>(value: ScalarValue) -> A {
|
||||
match value {
|
||||
@@ -324,22 +338,26 @@ impl<'a> ConstantSolver<'a> {
|
||||
}
|
||||
|
||||
for component in components {
|
||||
*component = self.cast(*component, kind, target_width)?;
|
||||
*component = self.cast(*component, kind, target_width, span.clone())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
}))
|
||||
Ok(self.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
},
|
||||
span,
|
||||
))
|
||||
}
|
||||
|
||||
fn unary_op(
|
||||
&mut self,
|
||||
op: UnaryOperator,
|
||||
constant: Handle<Constant>,
|
||||
span: crate::Span,
|
||||
) -> Result<Handle<Constant>, ConstantSolvingError> {
|
||||
let mut inner = self.constants[constant].inner.clone();
|
||||
|
||||
@@ -367,16 +385,19 @@ impl<'a> ConstantSolver<'a> {
|
||||
}
|
||||
|
||||
for component in components {
|
||||
*component = self.unary_op(op, *component)?
|
||||
*component = self.unary_op(op, *component, span.clone())?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
}))
|
||||
Ok(self.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
},
|
||||
span,
|
||||
))
|
||||
}
|
||||
|
||||
fn binary_op(
|
||||
@@ -384,6 +405,7 @@ impl<'a> ConstantSolver<'a> {
|
||||
op: BinaryOperator,
|
||||
left: Handle<Constant>,
|
||||
right: Handle<Constant>,
|
||||
span: crate::Span,
|
||||
) -> Result<Handle<Constant>, ConstantSolvingError> {
|
||||
let left_inner = &self.constants[left].inner;
|
||||
let right_inner = &self.constants[right].inner;
|
||||
@@ -464,25 +486,28 @@ impl<'a> ConstantSolver<'a> {
|
||||
(&ConstantInner::Composite { ref components, ty }, &ConstantInner::Scalar { .. }) => {
|
||||
let mut components = components.clone();
|
||||
for comp in components.iter_mut() {
|
||||
*comp = self.binary_op(op, *comp, right)?;
|
||||
*comp = self.binary_op(op, *comp, right, span.clone())?;
|
||||
}
|
||||
ConstantInner::Composite { ty, components }
|
||||
}
|
||||
(&ConstantInner::Scalar { .. }, &ConstantInner::Composite { ref components, ty }) => {
|
||||
let mut components = components.clone();
|
||||
for comp in components.iter_mut() {
|
||||
*comp = self.binary_op(op, left, *comp)?;
|
||||
*comp = self.binary_op(op, left, *comp, span.clone())?;
|
||||
}
|
||||
ConstantInner::Composite { ty, components }
|
||||
}
|
||||
_ => return Err(ConstantSolvingError::InvalidBinaryOpArgs),
|
||||
};
|
||||
|
||||
Ok(self.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
}))
|
||||
Ok(self.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
},
|
||||
span,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,59 +528,80 @@ mod tests {
|
||||
let mut expressions = Arena::new();
|
||||
let mut constants = Arena::new();
|
||||
|
||||
let vec_ty = types.append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Bi,
|
||||
kind: ScalarKind::Sint,
|
||||
width: 4,
|
||||
let vec_ty = types.append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Bi,
|
||||
kind: ScalarKind::Sint,
|
||||
width: 4,
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let h = constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Sint(4),
|
||||
let h = constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Sint(4),
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let h1 = constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Sint(8),
|
||||
let h1 = constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Sint(8),
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let vec_h = constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty: vec_ty,
|
||||
components: vec![h, h1],
|
||||
let vec_h = constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty: vec_ty,
|
||||
components: vec![h, h1],
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let expr = expressions.append(Expression::Constant(h));
|
||||
let expr1 = expressions.append(Expression::Constant(vec_h));
|
||||
let expr = expressions.append(Expression::Constant(h), Default::default());
|
||||
let expr1 = expressions.append(Expression::Constant(vec_h), Default::default());
|
||||
|
||||
let root1 = expressions.append(Expression::Unary {
|
||||
op: UnaryOperator::Negate,
|
||||
expr,
|
||||
});
|
||||
let root1 = expressions.append(
|
||||
Expression::Unary {
|
||||
op: UnaryOperator::Negate,
|
||||
expr,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let root2 = expressions.append(Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
});
|
||||
let root2 = expressions.append(
|
||||
Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let root3 = expressions.append(Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr: expr1,
|
||||
});
|
||||
let root3 = expressions.append(
|
||||
Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr: expr1,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let mut solver = ConstantSolver {
|
||||
types: &types,
|
||||
@@ -614,22 +660,28 @@ mod tests {
|
||||
let mut expressions = Arena::new();
|
||||
let mut constants = Arena::new();
|
||||
|
||||
let h = constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Sint(4),
|
||||
let h = constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Sint(4),
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let expr = expressions.append(Expression::Constant(h));
|
||||
let expr = expressions.append(Expression::Constant(h), Default::default());
|
||||
|
||||
let root = expressions.append(Expression::As {
|
||||
expr,
|
||||
kind: ScalarKind::Bool,
|
||||
convert: Some(crate::BOOL_WIDTH),
|
||||
});
|
||||
let root = expressions.append(
|
||||
Expression::As {
|
||||
expr,
|
||||
kind: ScalarKind::Bool,
|
||||
convert: Some(crate::BOOL_WIDTH),
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let mut solver = ConstantSolver {
|
||||
types: &Arena::new(),
|
||||
@@ -654,86 +706,113 @@ mod tests {
|
||||
let mut expressions = Arena::new();
|
||||
let mut constants = Arena::new();
|
||||
|
||||
let matrix_ty = types.append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Matrix {
|
||||
columns: VectorSize::Bi,
|
||||
rows: VectorSize::Tri,
|
||||
width: 4,
|
||||
let matrix_ty = types.append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Matrix {
|
||||
columns: VectorSize::Bi,
|
||||
rows: VectorSize::Tri,
|
||||
width: 4,
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let vec_ty = types.append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 4,
|
||||
let vec_ty = types.append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 4,
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let mut vec1_components = Vec::with_capacity(3);
|
||||
let mut vec2_components = Vec::with_capacity(3);
|
||||
|
||||
for i in 0..3 {
|
||||
let h = constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Float(i as f64),
|
||||
let h = constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Float(i as f64),
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
vec1_components.push(h)
|
||||
}
|
||||
|
||||
for i in 3..6 {
|
||||
let h = constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Float(i as f64),
|
||||
let h = constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Float(i as f64),
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
vec2_components.push(h)
|
||||
}
|
||||
|
||||
let vec1 = constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty: vec_ty,
|
||||
components: vec1_components,
|
||||
let vec1 = constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty: vec_ty,
|
||||
components: vec1_components,
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let vec2 = constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty: vec_ty,
|
||||
components: vec2_components,
|
||||
let vec2 = constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty: vec_ty,
|
||||
components: vec2_components,
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let h = constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty: matrix_ty,
|
||||
components: vec![vec1, vec2],
|
||||
let h = constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Composite {
|
||||
ty: matrix_ty,
|
||||
components: vec![vec1, vec2],
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let base = expressions.append(Expression::Constant(h));
|
||||
let root1 = expressions.append(Expression::AccessIndex { base, index: 1 });
|
||||
let root2 = expressions.append(Expression::AccessIndex {
|
||||
base: root1,
|
||||
index: 2,
|
||||
});
|
||||
let base = expressions.append(Expression::Constant(h), Default::default());
|
||||
let root1 = expressions.append(
|
||||
Expression::AccessIndex { base, index: 1 },
|
||||
Default::default(),
|
||||
);
|
||||
let root2 = expressions.append(
|
||||
Expression::AccessIndex {
|
||||
base: root1,
|
||||
index: 2,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let mut solver = ConstantSolver {
|
||||
types: &types,
|
||||
|
||||
@@ -79,8 +79,9 @@ impl Context {
|
||||
self.emit_flush(body);
|
||||
let (expr, load) = match kind {
|
||||
GlobalLookupKind::Variable(v) => {
|
||||
let span = parser.module.global_variables.get_span(v).clone();
|
||||
let res = (
|
||||
self.expressions.append(Expression::GlobalVariable(v)),
|
||||
self.expressions.append(Expression::GlobalVariable(v), span),
|
||||
parser.module.global_variables[v].class != StorageClass::Handle,
|
||||
);
|
||||
self.emit_start();
|
||||
@@ -88,11 +89,14 @@ impl Context {
|
||||
res
|
||||
}
|
||||
GlobalLookupKind::BlockSelect(handle, index) => {
|
||||
let base = self.expressions.append(Expression::GlobalVariable(handle));
|
||||
let span = parser.module.global_variables.get_span(handle).clone();
|
||||
let base = self
|
||||
.expressions
|
||||
.append(Expression::GlobalVariable(handle), span.clone());
|
||||
self.emit_start();
|
||||
let expr = self
|
||||
.expressions
|
||||
.append(Expression::AccessIndex { base, index });
|
||||
.append(Expression::AccessIndex { base, index }, span);
|
||||
|
||||
(expr, {
|
||||
let ty = parser.module.global_variables[handle].ty;
|
||||
@@ -114,7 +118,11 @@ impl Context {
|
||||
})
|
||||
}
|
||||
GlobalLookupKind::Constant(v) => {
|
||||
let res = (self.expressions.append(Expression::Constant(v)), false);
|
||||
let span = parser.module.constants.get_span(v).clone();
|
||||
let res = (
|
||||
self.expressions.append(Expression::Constant(v), span),
|
||||
false,
|
||||
);
|
||||
self.emit_start();
|
||||
res
|
||||
}
|
||||
@@ -138,15 +146,21 @@ impl Context {
|
||||
body.extend(self.emitter.finish(&self.expressions))
|
||||
}
|
||||
|
||||
pub fn add_expression(&mut self, expr: Expression, body: &mut Block) -> Handle<Expression> {
|
||||
if expr.needs_pre_emit() {
|
||||
pub fn add_expression(
|
||||
&mut self,
|
||||
expr: Expression,
|
||||
meta: SourceMetadata,
|
||||
body: &mut Block,
|
||||
) -> Handle<Expression> {
|
||||
let needs_pre_emit = expr.needs_pre_emit();
|
||||
if needs_pre_emit {
|
||||
self.emit_flush(body);
|
||||
let handle = self.expressions.append(expr);
|
||||
self.emit_start();
|
||||
handle
|
||||
} else {
|
||||
self.expressions.append(expr)
|
||||
}
|
||||
let handle = self.expressions.append(expr, meta.as_span());
|
||||
if needs_pre_emit {
|
||||
self.emit_start();
|
||||
}
|
||||
handle
|
||||
}
|
||||
|
||||
pub fn lookup_local_var(&self, name: &str) -> Option<VariableReference> {
|
||||
@@ -191,13 +205,13 @@ impl Context {
|
||||
&mut self,
|
||||
parser: &mut Parser,
|
||||
body: &mut Block,
|
||||
name: Option<String>,
|
||||
name_meta: Option<(String, SourceMetadata)>,
|
||||
ty: Handle<Type>,
|
||||
qualifier: ParameterQualifier,
|
||||
) {
|
||||
let index = self.arguments.len();
|
||||
let mut arg = FunctionArgument {
|
||||
name: name.clone(),
|
||||
name: name_meta.as_ref().map(|&(ref name, _)| name.clone()),
|
||||
ty,
|
||||
binding: None,
|
||||
};
|
||||
@@ -209,13 +223,17 @@ impl Context {
|
||||
};
|
||||
|
||||
if qualifier.is_lhs() {
|
||||
arg.ty = parser.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Pointer {
|
||||
base: arg.ty,
|
||||
class: StorageClass::Function,
|
||||
let span = parser.module.types.get_span(arg.ty).clone();
|
||||
arg.ty = parser.module.types.fetch_or_append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Pointer {
|
||||
base: arg.ty,
|
||||
class: StorageClass::Function,
|
||||
},
|
||||
},
|
||||
})
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
self.arguments.push(arg);
|
||||
@@ -225,26 +243,32 @@ impl Context {
|
||||
depth: false,
|
||||
});
|
||||
|
||||
if let Some(name) = name {
|
||||
let expr = self.add_expression(Expression::FunctionArgument(index as u32), body);
|
||||
if let Some((name, meta)) = name_meta {
|
||||
let expr = self.add_expression(Expression::FunctionArgument(index as u32), meta, body);
|
||||
let mutable = qualifier != ParameterQualifier::Const && !opaque;
|
||||
let load = qualifier.is_lhs();
|
||||
|
||||
if mutable && !load {
|
||||
let handle = self.locals.append(LocalVariable {
|
||||
name: Some(name.clone()),
|
||||
ty,
|
||||
init: None,
|
||||
});
|
||||
let local_expr = self.add_expression(Expression::LocalVariable(handle), body);
|
||||
let handle = self.locals.append(
|
||||
LocalVariable {
|
||||
name: Some(name.clone()),
|
||||
ty,
|
||||
init: None,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
let local_expr = self.add_expression(Expression::LocalVariable(handle), meta, body);
|
||||
|
||||
self.emit_flush(body);
|
||||
self.emit_start();
|
||||
|
||||
body.push(Statement::Store {
|
||||
pointer: local_expr,
|
||||
value: expr,
|
||||
});
|
||||
body.push(
|
||||
Statement::Store {
|
||||
pointer: local_expr,
|
||||
value: expr,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
if let Some(current) = self.scopes.last_mut() {
|
||||
(*current).insert(
|
||||
@@ -395,18 +419,19 @@ impl Context {
|
||||
_ => return None,
|
||||
},
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
self.add_expression(Expression::Access { base, index }, body)
|
||||
self.add_expression(Expression::Access { base, index }, meta, body)
|
||||
});
|
||||
|
||||
if !lhs {
|
||||
let resolved = parser.resolve_type(self, pointer, meta)?;
|
||||
if resolved.pointer_class().is_some() {
|
||||
return Ok((
|
||||
Some(self.add_expression(Expression::Load { pointer }, body)),
|
||||
Some(self.add_expression(Expression::Load { pointer }, meta, body)),
|
||||
meta,
|
||||
));
|
||||
}
|
||||
@@ -420,7 +445,7 @@ impl Context {
|
||||
parser.field_selection(self, lhs, body, base, field, meta)?
|
||||
}
|
||||
HirExprKind::Constant(constant) if !lhs => {
|
||||
self.add_expression(Expression::Constant(constant), body)
|
||||
self.add_expression(Expression::Constant(constant), meta, body)
|
||||
}
|
||||
HirExprKind::Binary { left, op, right } if !lhs => {
|
||||
let (mut left, left_meta) =
|
||||
@@ -453,13 +478,19 @@ impl Context {
|
||||
false => (BinaryOperator::NotEqual, RelationalFunction::Any),
|
||||
};
|
||||
|
||||
let argument =
|
||||
self.expressions
|
||||
.append(Expression::Binary { op, left, right });
|
||||
let argument = self
|
||||
.expressions
|
||||
.append(Expression::Binary { op, left, right }, meta.as_span());
|
||||
|
||||
self.add_expression(Expression::Relational { fun, argument }, body)
|
||||
self.add_expression(
|
||||
Expression::Relational { fun, argument },
|
||||
meta,
|
||||
body,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
self.add_expression(Expression::Binary { left, op, right }, meta, body)
|
||||
}
|
||||
_ => self.add_expression(Expression::Binary { left, op, right }, body),
|
||||
},
|
||||
(&TypeInner::Vector { size, .. }, &TypeInner::Scalar { .. }) => match op {
|
||||
BinaryOperator::Add
|
||||
@@ -467,8 +498,11 @@ impl Context {
|
||||
| BinaryOperator::Divide
|
||||
| BinaryOperator::ShiftLeft
|
||||
| BinaryOperator::ShiftRight => {
|
||||
let scalar_vector =
|
||||
self.add_expression(Expression::Splat { size, value: right }, body);
|
||||
let scalar_vector = self.add_expression(
|
||||
Expression::Splat { size, value: right },
|
||||
meta,
|
||||
body,
|
||||
);
|
||||
|
||||
self.add_expression(
|
||||
Expression::Binary {
|
||||
@@ -476,15 +510,21 @@ impl Context {
|
||||
left,
|
||||
right: scalar_vector,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)
|
||||
}
|
||||
_ => self.add_expression(Expression::Binary { left, op, right }, body),
|
||||
_ => {
|
||||
self.add_expression(Expression::Binary { left, op, right }, meta, body)
|
||||
}
|
||||
},
|
||||
(&TypeInner::Scalar { .. }, &TypeInner::Vector { size, .. }) => match op {
|
||||
BinaryOperator::Add | BinaryOperator::Subtract | BinaryOperator::Divide => {
|
||||
let scalar_vector =
|
||||
self.add_expression(Expression::Splat { size, value: left }, body);
|
||||
let scalar_vector = self.add_expression(
|
||||
Expression::Splat { size, value: left },
|
||||
meta,
|
||||
body,
|
||||
);
|
||||
|
||||
self.add_expression(
|
||||
Expression::Binary {
|
||||
@@ -492,18 +532,21 @@ impl Context {
|
||||
left: scalar_vector,
|
||||
right,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)
|
||||
}
|
||||
_ => self.add_expression(Expression::Binary { left, op, right }, body),
|
||||
_ => {
|
||||
self.add_expression(Expression::Binary { left, op, right }, meta, body)
|
||||
}
|
||||
},
|
||||
_ => self.add_expression(Expression::Binary { left, op, right }, body),
|
||||
_ => self.add_expression(Expression::Binary { left, op, right }, meta, body),
|
||||
}
|
||||
}
|
||||
HirExprKind::Unary { op, expr } if !lhs => {
|
||||
let expr = self.lower_expect_inner(stmt, parser, expr, false, body)?.0;
|
||||
|
||||
self.add_expression(Expression::Unary { op, expr }, body)
|
||||
self.add_expression(Expression::Unary { op, expr }, meta, body)
|
||||
}
|
||||
HirExprKind::Variable(ref var) => {
|
||||
if lhs {
|
||||
@@ -518,7 +561,7 @@ impl Context {
|
||||
|
||||
var.expr
|
||||
} else if var.load {
|
||||
self.add_expression(Expression::Load { pointer: var.expr }, body)
|
||||
self.add_expression(Expression::Load { pointer: var.expr }, meta, body)
|
||||
} else {
|
||||
var.expr
|
||||
}
|
||||
@@ -561,6 +604,7 @@ impl Context {
|
||||
accept,
|
||||
reject,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)
|
||||
}
|
||||
@@ -600,6 +644,7 @@ impl Context {
|
||||
base: vector,
|
||||
index: pattern[index].index(),
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
);
|
||||
let src = self.add_expression(
|
||||
@@ -607,22 +652,26 @@ impl Context {
|
||||
base: value,
|
||||
index: index as u32,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
);
|
||||
|
||||
self.emit_flush(body);
|
||||
self.emit_start();
|
||||
|
||||
body.push(Statement::Store {
|
||||
pointer: dst,
|
||||
value: src,
|
||||
});
|
||||
body.push(
|
||||
Statement::Store {
|
||||
pointer: dst,
|
||||
value: src,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.emit_flush(body);
|
||||
self.emit_start();
|
||||
|
||||
body.push(Statement::Store { pointer, value });
|
||||
body.push(Statement::Store { pointer, value }, meta.as_span());
|
||||
}
|
||||
|
||||
value
|
||||
@@ -638,7 +687,7 @@ impl Context {
|
||||
};
|
||||
|
||||
let pointer = self.lower_expect_inner(stmt, parser, expr, true, body)?.0;
|
||||
let left = self.add_expression(Expression::Load { pointer }, body);
|
||||
let left = self.add_expression(Expression::Load { pointer }, meta, body);
|
||||
|
||||
let uint = match parser.resolve_type(self, left, meta)?.scalar_kind() {
|
||||
Some(ScalarKind::Sint) => false,
|
||||
@@ -654,59 +703,71 @@ impl Context {
|
||||
}
|
||||
};
|
||||
|
||||
let one = parser.module.constants.append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: match uint {
|
||||
true => crate::ScalarValue::Uint(1),
|
||||
false => crate::ScalarValue::Sint(1),
|
||||
let one = parser.module.constants.append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: match uint {
|
||||
true => crate::ScalarValue::Uint(1),
|
||||
false => crate::ScalarValue::Sint(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
let right = self.add_expression(Expression::Constant(one), body);
|
||||
Default::default(),
|
||||
);
|
||||
let right = self.add_expression(Expression::Constant(one), meta, body);
|
||||
|
||||
let value = self.add_expression(Expression::Binary { op, left, right }, body);
|
||||
let value = self.add_expression(Expression::Binary { op, left, right }, meta, body);
|
||||
|
||||
if postfix {
|
||||
let local = self.locals.append(LocalVariable {
|
||||
name: None,
|
||||
ty: parser.module.types.fetch_or_append(Type {
|
||||
let local = self.locals.append(
|
||||
LocalVariable {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: match uint {
|
||||
true => ScalarKind::Uint,
|
||||
false => ScalarKind::Sint,
|
||||
ty: parser.module.types.fetch_or_append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: match uint {
|
||||
true => ScalarKind::Uint,
|
||||
false => ScalarKind::Sint,
|
||||
},
|
||||
width: 4,
|
||||
},
|
||||
},
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
init: None,
|
||||
});
|
||||
meta.as_span(),
|
||||
),
|
||||
init: None,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
let expr = self.add_expression(Expression::LocalVariable(local), body);
|
||||
let load = self.add_expression(Expression::Load { pointer: expr }, body);
|
||||
let expr = self.add_expression(Expression::LocalVariable(local), meta, body);
|
||||
let load = self.add_expression(Expression::Load { pointer: expr }, meta, body);
|
||||
|
||||
self.emit_flush(body);
|
||||
self.emit_start();
|
||||
|
||||
body.push(Statement::Store {
|
||||
pointer: expr,
|
||||
value: left,
|
||||
});
|
||||
body.push(
|
||||
Statement::Store {
|
||||
pointer: expr,
|
||||
value: left,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
self.emit_flush(body);
|
||||
self.emit_start();
|
||||
|
||||
body.push(Statement::Store { pointer, value });
|
||||
body.push(Statement::Store { pointer, value }, meta.as_span());
|
||||
|
||||
load
|
||||
} else {
|
||||
self.emit_flush(body);
|
||||
self.emit_start();
|
||||
|
||||
body.push(Statement::Store { pointer, value });
|
||||
body.push(Statement::Store { pointer, value }, meta.as_span());
|
||||
|
||||
left
|
||||
}
|
||||
@@ -758,11 +819,14 @@ impl Context {
|
||||
(type_power(kind), self.expr_power(parser, *expr, meta)?)
|
||||
{
|
||||
if tgt_power > expr_power {
|
||||
*expr = self.expressions.append(Expression::As {
|
||||
expr: *expr,
|
||||
kind,
|
||||
convert: Some(width),
|
||||
})
|
||||
*expr = self.expressions.append(
|
||||
Expression::As {
|
||||
expr: *expr,
|
||||
kind,
|
||||
convert: Some(width),
|
||||
},
|
||||
meta.as_span(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -789,19 +853,25 @@ impl Context {
|
||||
) {
|
||||
match left_power.cmp(&right_power) {
|
||||
std::cmp::Ordering::Less => {
|
||||
*left = self.expressions.append(Expression::As {
|
||||
expr: *left,
|
||||
kind: right_kind,
|
||||
convert: Some(right_width),
|
||||
})
|
||||
*left = self.expressions.append(
|
||||
Expression::As {
|
||||
expr: *left,
|
||||
kind: right_kind,
|
||||
convert: Some(right_width),
|
||||
},
|
||||
left_meta.as_span(),
|
||||
)
|
||||
}
|
||||
std::cmp::Ordering::Equal => {}
|
||||
std::cmp::Ordering::Greater => {
|
||||
*right = self.expressions.append(Expression::As {
|
||||
expr: *right,
|
||||
kind: left_kind,
|
||||
convert: Some(left_width),
|
||||
})
|
||||
*right = self.expressions.append(
|
||||
Expression::As {
|
||||
expr: *right,
|
||||
kind: left_kind,
|
||||
convert: Some(left_width),
|
||||
},
|
||||
right_meta.as_span(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -822,7 +892,7 @@ impl Context {
|
||||
if let (&TypeInner::Scalar { .. }, Some(size)) = (expr_type, vector_size) {
|
||||
*expr = self
|
||||
.expressions
|
||||
.append(Expression::Splat { size, value: *expr })
|
||||
.append(Expression::Splat { size, value: *expr }, meta.as_span())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -832,6 +902,7 @@ impl Context {
|
||||
&mut self,
|
||||
size: VectorSize,
|
||||
vector: Handle<Expression>,
|
||||
meta: SourceMetadata,
|
||||
body: &mut Block,
|
||||
) -> Handle<Expression> {
|
||||
self.add_expression(
|
||||
@@ -840,6 +911,7 @@ impl Context {
|
||||
vector,
|
||||
pattern: crate::SwizzleComponent::XYZW,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,12 @@ struct CoordComponents {
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
fn add_constant_value(&mut self, scalar_kind: ScalarKind, value: u64) -> Handle<Constant> {
|
||||
fn add_constant_value(
|
||||
&mut self,
|
||||
scalar_kind: ScalarKind,
|
||||
value: u64,
|
||||
meta: SourceMetadata,
|
||||
) -> Handle<Constant> {
|
||||
let value = match scalar_kind {
|
||||
ScalarKind::Uint => ScalarValue::Uint(value),
|
||||
ScalarKind::Sint => ScalarValue::Sint(value as i64),
|
||||
@@ -31,11 +36,14 @@ impl Parser {
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
self.module.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar { width: 4, value },
|
||||
})
|
||||
self.module.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar { width: 4, value },
|
||||
},
|
||||
meta.as_span(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn function_or_constructor_call(
|
||||
@@ -68,10 +76,13 @@ impl Parser {
|
||||
if expr_type.scalar_kind() == Some(ScalarKind::Bool)
|
||||
&& result_scalar_kind != ScalarKind::Bool =>
|
||||
{
|
||||
let c0 = self.add_constant_value(result_scalar_kind, 0u64);
|
||||
let c1 = self.add_constant_value(result_scalar_kind, 1u64);
|
||||
let mut reject = ctx.add_expression(Expression::Constant(c0), body);
|
||||
let mut accept = ctx.add_expression(Expression::Constant(c1), body);
|
||||
let (condition, expr_meta) = args[0];
|
||||
let c0 = self.add_constant_value(result_scalar_kind, 0u64, meta);
|
||||
let c1 = self.add_constant_value(result_scalar_kind, 1u64, meta);
|
||||
let mut reject =
|
||||
ctx.add_expression(Expression::Constant(c0), expr_meta, body);
|
||||
let mut accept =
|
||||
ctx.add_expression(Expression::Constant(c1), expr_meta, body);
|
||||
|
||||
ctx.implicit_splat(self, &mut reject, meta, vector_size)?;
|
||||
ctx.implicit_splat(self, &mut accept, meta, vector_size)?;
|
||||
@@ -80,8 +91,9 @@ impl Parser {
|
||||
Expression::Select {
|
||||
accept,
|
||||
reject,
|
||||
condition: args[0].0,
|
||||
condition,
|
||||
},
|
||||
expr_meta,
|
||||
body,
|
||||
);
|
||||
|
||||
@@ -95,7 +107,7 @@ impl Parser {
|
||||
let (mut value, meta) = args[0];
|
||||
ctx.implicit_conversion(self, &mut value, meta, kind, width)?;
|
||||
|
||||
ctx.add_expression(Expression::Splat { size, value }, body)
|
||||
ctx.add_expression(Expression::Splat { size, value }, meta, body)
|
||||
}
|
||||
TypeInner::Scalar { kind, width } => ctx.add_expression(
|
||||
Expression::As {
|
||||
@@ -103,13 +115,14 @@ impl Parser {
|
||||
expr: args[0].0,
|
||||
convert: Some(width),
|
||||
},
|
||||
args[0].1,
|
||||
body,
|
||||
),
|
||||
TypeInner::Vector { size, kind, width } => {
|
||||
let mut expr = args[0].0;
|
||||
|
||||
if vector_size.map_or(true, |s| s != size) {
|
||||
expr = ctx.vector_resize(size, expr, body);
|
||||
expr = ctx.vector_resize(size, expr, args[0].1, body);
|
||||
}
|
||||
|
||||
ctx.add_expression(
|
||||
@@ -118,6 +131,7 @@ impl Parser {
|
||||
expr,
|
||||
convert: Some(width),
|
||||
},
|
||||
args[0].1,
|
||||
body,
|
||||
)
|
||||
}
|
||||
@@ -144,25 +158,33 @@ impl Parser {
|
||||
// value is used to initialize all the values along the diagonal of
|
||||
// the matrix; the rest are given zeros.
|
||||
let mut components = Vec::with_capacity(columns as usize);
|
||||
let vector_ty = self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: rows,
|
||||
kind: ScalarKind::Float,
|
||||
width,
|
||||
let vector_ty = self.module.types.fetch_or_append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: rows,
|
||||
kind: ScalarKind::Float,
|
||||
width,
|
||||
},
|
||||
},
|
||||
});
|
||||
let zero_constant =
|
||||
self.module.constants.fetch_or_append(Constant {
|
||||
meta.as_span(),
|
||||
);
|
||||
let zero_constant = self.module.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width,
|
||||
value: ScalarValue::Float(0.0),
|
||||
},
|
||||
});
|
||||
let zero = ctx
|
||||
.add_expression(Expression::Constant(zero_constant), body);
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
let zero = ctx.add_expression(
|
||||
Expression::Constant(zero_constant),
|
||||
meta,
|
||||
body,
|
||||
);
|
||||
|
||||
for i in 0..columns as u32 {
|
||||
components.push(
|
||||
@@ -177,12 +199,17 @@ impl Parser {
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
ctx.add_expression(Expression::Compose { ty, components }, body)
|
||||
ctx.add_expression(
|
||||
Expression::Compose { ty, components },
|
||||
meta,
|
||||
body,
|
||||
)
|
||||
}
|
||||
TypeInner::Matrix { rows: ori_rows, .. } => {
|
||||
let mut components = Vec::new();
|
||||
@@ -193,17 +220,22 @@ impl Parser {
|
||||
base: value,
|
||||
index: n,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
);
|
||||
|
||||
if ori_rows != rows {
|
||||
vector = ctx.vector_resize(rows, vector, body);
|
||||
vector = ctx.vector_resize(rows, vector, meta, body);
|
||||
}
|
||||
|
||||
components.push(vector)
|
||||
}
|
||||
|
||||
ctx.add_expression(Expression::Compose { ty, components }, body)
|
||||
ctx.add_expression(
|
||||
Expression::Compose { ty, components },
|
||||
meta,
|
||||
body,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let columns =
|
||||
@@ -214,6 +246,7 @@ impl Parser {
|
||||
ty,
|
||||
components: columns,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)
|
||||
}
|
||||
@@ -224,6 +257,7 @@ impl Parser {
|
||||
ty,
|
||||
components: args.into_iter().map(|arg| arg.0).collect(),
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
),
|
||||
_ => {
|
||||
@@ -262,6 +296,7 @@ impl Parser {
|
||||
base: arg,
|
||||
index: i,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
))
|
||||
}
|
||||
@@ -270,14 +305,17 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
let ty = self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: rows,
|
||||
kind: ScalarKind::Float,
|
||||
width,
|
||||
let ty = self.module.types.fetch_or_append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: rows,
|
||||
kind: ScalarKind::Float,
|
||||
width,
|
||||
},
|
||||
},
|
||||
});
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
for chunk in flattened.chunks(rows as usize) {
|
||||
components.push(ctx.add_expression(
|
||||
@@ -285,6 +323,7 @@ impl Parser {
|
||||
ty,
|
||||
components: Vec::from(chunk),
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
))
|
||||
}
|
||||
@@ -302,7 +341,7 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.add_expression(Expression::Compose { ty, components }, body)
|
||||
ctx.add_expression(Expression::Compose { ty, components }, meta, body)
|
||||
};
|
||||
|
||||
Ok(Some(h))
|
||||
@@ -371,6 +410,7 @@ impl Parser {
|
||||
}),
|
||||
depth_ref: comps.depth_ref,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
),
|
||||
))
|
||||
@@ -401,6 +441,7 @@ impl Parser {
|
||||
level: SampleLevel::Exact(args[2].0),
|
||||
depth_ref: comps.depth_ref,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
} else {
|
||||
@@ -437,17 +478,19 @@ impl Parser {
|
||||
base,
|
||||
index: size as u32 - 1,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
);
|
||||
let left = if let VectorSize::Bi = size {
|
||||
ctx.add_expression(Expression::AccessIndex { base, index: 0 }, body)
|
||||
ctx.add_expression(Expression::AccessIndex { base, index: 0 }, meta, body)
|
||||
} else {
|
||||
let size = match size {
|
||||
VectorSize::Tri => VectorSize::Bi,
|
||||
_ => VectorSize::Tri,
|
||||
};
|
||||
right = ctx.add_expression(Expression::Splat { size, value: right }, body);
|
||||
ctx.vector_resize(size, base, body)
|
||||
right =
|
||||
ctx.add_expression(Expression::Splat { size, value: right }, meta, body);
|
||||
ctx.vector_resize(size, base, meta, body)
|
||||
};
|
||||
let coords = ctx.add_expression(
|
||||
Expression::Binary {
|
||||
@@ -455,6 +498,7 @@ impl Parser {
|
||||
left,
|
||||
right,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
);
|
||||
let comps = self.coordinate_components(ctx, args[0], (coords, base_meta), body)?;
|
||||
@@ -469,6 +513,7 @@ impl Parser {
|
||||
level,
|
||||
depth_ref: comps.depth_ref,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
} else {
|
||||
@@ -503,6 +548,7 @@ impl Parser {
|
||||
},
|
||||
depth_ref: comps.depth_ref,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
} else {
|
||||
@@ -526,6 +572,7 @@ impl Parser {
|
||||
level: args.get(1).map(|e| e.0),
|
||||
},
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
}
|
||||
@@ -546,6 +593,7 @@ impl Parser {
|
||||
array_index: comps.array_index,
|
||||
index: Some(args[2].0),
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
} else {
|
||||
@@ -599,6 +647,7 @@ impl Parser {
|
||||
arg1: None,
|
||||
arg2: None,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
}
|
||||
@@ -618,7 +667,7 @@ impl Parser {
|
||||
},
|
||||
_ => return Err(Error::wrong_function_args(name, 2, args.len(), meta)),
|
||||
};
|
||||
Ok(Some(ctx.add_expression(expr, body)))
|
||||
Ok(Some(ctx.add_expression(expr, meta, body)))
|
||||
}
|
||||
"mod" => {
|
||||
if args.len() != 2 {
|
||||
@@ -636,6 +685,7 @@ impl Parser {
|
||||
left,
|
||||
right,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
}
|
||||
@@ -667,6 +717,7 @@ impl Parser {
|
||||
arg1: Some(arg1),
|
||||
arg2: None,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
}
|
||||
@@ -700,6 +751,7 @@ impl Parser {
|
||||
arg1: Some(arg1),
|
||||
arg2: None,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
}
|
||||
@@ -739,6 +791,7 @@ impl Parser {
|
||||
size,
|
||||
value: selector,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)
|
||||
}
|
||||
@@ -771,7 +824,7 @@ impl Parser {
|
||||
},
|
||||
};
|
||||
|
||||
Ok(Some(ctx.add_expression(expr, body)))
|
||||
Ok(Some(ctx.add_expression(expr, meta, body)))
|
||||
}
|
||||
"clamp" => {
|
||||
if args.len() != 3 {
|
||||
@@ -801,6 +854,7 @@ impl Parser {
|
||||
arg1: Some(arg1),
|
||||
arg2: Some(arg2),
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
}
|
||||
@@ -821,6 +875,7 @@ impl Parser {
|
||||
arg1: Some(args[1].0),
|
||||
arg2: Some(args[2].0),
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
}
|
||||
@@ -843,6 +898,7 @@ impl Parser {
|
||||
left: args[0].0,
|
||||
right: args[1].0,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
)))
|
||||
}
|
||||
@@ -986,22 +1042,31 @@ impl Parser {
|
||||
if parameter_info.qualifier.is_lhs()
|
||||
&& matches!(ctx[handle], Expression::Swizzle { .. })
|
||||
{
|
||||
let ty = self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector { size, kind, width },
|
||||
});
|
||||
let temp_var = ctx.locals.append(LocalVariable {
|
||||
name: None,
|
||||
ty,
|
||||
init: None,
|
||||
});
|
||||
let ty = self.module.types.fetch_or_append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector { size, kind, width },
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
let temp_var = ctx.locals.append(
|
||||
LocalVariable {
|
||||
name: None,
|
||||
ty,
|
||||
init: None,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
let temp_expr =
|
||||
ctx.add_expression(Expression::LocalVariable(temp_var), body);
|
||||
ctx.add_expression(Expression::LocalVariable(temp_var), meta, body);
|
||||
|
||||
body.push(Statement::Store {
|
||||
pointer: temp_expr,
|
||||
value: handle,
|
||||
});
|
||||
body.push(
|
||||
Statement::Store {
|
||||
pointer: temp_expr,
|
||||
value: handle,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
arguments.push(temp_expr);
|
||||
proxy_writes.push((*expr, temp_expr));
|
||||
@@ -1020,27 +1085,33 @@ impl Parser {
|
||||
ctx.emit_flush(body);
|
||||
|
||||
let result = if !is_void {
|
||||
Some(ctx.add_expression(Expression::CallResult(function), body))
|
||||
Some(ctx.add_expression(Expression::CallResult(function), meta, body))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
body.push(crate::Statement::Call {
|
||||
function,
|
||||
arguments,
|
||||
result,
|
||||
});
|
||||
body.push(
|
||||
crate::Statement::Call {
|
||||
function,
|
||||
arguments,
|
||||
result,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
ctx.emit_start();
|
||||
for (tgt, pointer) in proxy_writes {
|
||||
let value = ctx.add_expression(Expression::Load { pointer }, body);
|
||||
let value = ctx.add_expression(Expression::Load { pointer }, meta, body);
|
||||
let target = ctx.lower_expect_inner(stmt, self, tgt, true, body)?.0;
|
||||
|
||||
ctx.emit_flush(body);
|
||||
body.push(Statement::Store {
|
||||
pointer: target,
|
||||
value,
|
||||
});
|
||||
body.push(
|
||||
Statement::Store {
|
||||
pointer: target,
|
||||
value,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
ctx.emit_start();
|
||||
}
|
||||
|
||||
@@ -1067,6 +1138,7 @@ impl Parser {
|
||||
fun,
|
||||
argument: args[0].0,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
))
|
||||
}
|
||||
@@ -1135,7 +1207,7 @@ impl Parser {
|
||||
return;
|
||||
}
|
||||
|
||||
let handle = module.functions.append(function);
|
||||
let handle = module.functions.append(function, meta.as_span());
|
||||
declarations.push(FunctionDeclaration {
|
||||
parameters,
|
||||
parameters_info,
|
||||
@@ -1195,7 +1267,7 @@ impl Parser {
|
||||
});
|
||||
}
|
||||
|
||||
let handle = module.functions.append(function);
|
||||
let handle = module.functions.append(function, meta.as_span());
|
||||
declarations.push(FunctionDeclaration {
|
||||
parameters,
|
||||
parameters_info,
|
||||
@@ -1208,7 +1280,7 @@ impl Parser {
|
||||
pub(crate) fn add_entry_point(
|
||||
&mut self,
|
||||
function: Handle<Function>,
|
||||
mut global_init_body: Block,
|
||||
global_init_body: Block,
|
||||
mut expressions: Arena<Expression>,
|
||||
) {
|
||||
let mut arguments = Vec::new();
|
||||
@@ -1235,19 +1307,23 @@ impl Parser {
|
||||
binding: Some(arg.binding.clone()),
|
||||
});
|
||||
|
||||
let pointer = expressions.append(Expression::GlobalVariable(arg.handle));
|
||||
let value = expressions.append(Expression::FunctionArgument(idx));
|
||||
let pointer =
|
||||
expressions.append(Expression::GlobalVariable(arg.handle), Default::default());
|
||||
let value = expressions.append(Expression::FunctionArgument(idx), Default::default());
|
||||
|
||||
body.push(Statement::Store { pointer, value });
|
||||
body.push(Statement::Store { pointer, value }, Default::default());
|
||||
}
|
||||
|
||||
body.append(&mut global_init_body);
|
||||
body.extend_block(global_init_body);
|
||||
|
||||
body.push(Statement::Call {
|
||||
function,
|
||||
arguments: Vec::new(),
|
||||
result: None,
|
||||
});
|
||||
body.push(
|
||||
Statement::Call {
|
||||
function,
|
||||
arguments: Vec::new(),
|
||||
result: None,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let mut span = 0;
|
||||
let mut members = Vec::new();
|
||||
@@ -1269,33 +1345,44 @@ impl Parser {
|
||||
|
||||
span += self.module.types[ty].inner.span(&self.module.constants);
|
||||
|
||||
let pointer = expressions.append(Expression::GlobalVariable(arg.handle));
|
||||
let pointer =
|
||||
expressions.append(Expression::GlobalVariable(arg.handle), Default::default());
|
||||
let len = expressions.len();
|
||||
let load = expressions.append(Expression::Load { pointer });
|
||||
body.push(Statement::Emit(expressions.range_from(len)));
|
||||
let load = expressions.append(Expression::Load { pointer }, Default::default());
|
||||
body.push(
|
||||
Statement::Emit(expressions.range_from(len)),
|
||||
Default::default(),
|
||||
);
|
||||
components.push(load)
|
||||
}
|
||||
|
||||
let (ty, value) = if !components.is_empty() {
|
||||
let ty = self.module.types.append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Struct {
|
||||
top_level: false,
|
||||
members,
|
||||
span,
|
||||
let ty = self.module.types.append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Struct {
|
||||
top_level: false,
|
||||
members,
|
||||
span,
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let len = expressions.len();
|
||||
let res = expressions.append(Expression::Compose { ty, components });
|
||||
body.push(Statement::Emit(expressions.range_from(len)));
|
||||
let res =
|
||||
expressions.append(Expression::Compose { ty, components }, Default::default());
|
||||
body.push(
|
||||
Statement::Emit(expressions.range_from(len)),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
(Some(ty), Some(res))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
body.push(Statement::Return { value });
|
||||
body.push(Statement::Return { value }, Default::default());
|
||||
|
||||
self.module.entry_points.push(EntryPoint {
|
||||
name: "main".to_string(),
|
||||
@@ -1344,13 +1431,14 @@ impl Parser {
|
||||
|
||||
let coordinate = match (image_size, coord_size) {
|
||||
(Some(size), Some(coord_s)) if size != coord_s => {
|
||||
ctx.vector_resize(size, coord, body)
|
||||
ctx.vector_resize(size, coord, coord_meta, body)
|
||||
}
|
||||
(None, Some(_)) => ctx.add_expression(
|
||||
Expression::AccessIndex {
|
||||
base: coord,
|
||||
index: 0,
|
||||
},
|
||||
coord_meta,
|
||||
body,
|
||||
),
|
||||
_ => coord,
|
||||
@@ -1362,7 +1450,11 @@ impl Parser {
|
||||
false => image_size.map_or(0, |s| s as u32),
|
||||
};
|
||||
|
||||
Some(ctx.add_expression(Expression::AccessIndex { base: coord, index }, body))
|
||||
Some(ctx.add_expression(
|
||||
Expression::AccessIndex { base: coord, index },
|
||||
coord_meta,
|
||||
body,
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
@@ -1370,7 +1462,11 @@ impl Parser {
|
||||
true => {
|
||||
let index = image_size.map_or(0, |s| s as u32);
|
||||
|
||||
Some(ctx.add_expression(Expression::AccessIndex { base: coord, index }, body))
|
||||
Some(ctx.add_expression(
|
||||
Expression::AccessIndex { base: coord, index },
|
||||
coord_meta,
|
||||
body,
|
||||
))
|
||||
}
|
||||
false => None,
|
||||
};
|
||||
@@ -1423,14 +1519,17 @@ fn sampled_to_depth(
|
||||
arrayed,
|
||||
} => match class {
|
||||
ImageClass::Sampled { multi, .. } => {
|
||||
*ty = module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Image {
|
||||
dim,
|
||||
arrayed,
|
||||
class: ImageClass::Depth { multi },
|
||||
*ty = module.types.fetch_or_append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Image {
|
||||
dim,
|
||||
arrayed,
|
||||
class: ImageClass::Depth { multi },
|
||||
},
|
||||
},
|
||||
})
|
||||
module.types.get_span(*ty).clone(),
|
||||
)
|
||||
}
|
||||
ImageClass::Depth { .. } => {}
|
||||
_ => errors.push(Error {
|
||||
|
||||
@@ -84,14 +84,18 @@ pub fn calculate_offset(
|
||||
crate::ArraySize::Dynamic => stride,
|
||||
};
|
||||
|
||||
ty = types.fetch_or_append(Type {
|
||||
name,
|
||||
inner: TypeInner::Array {
|
||||
base: info.ty,
|
||||
size,
|
||||
stride,
|
||||
let ty_span = types.get_span(ty).clone();
|
||||
ty = types.fetch_or_append(
|
||||
Type {
|
||||
name,
|
||||
inner: TypeInner::Array {
|
||||
base: info.ty,
|
||||
size,
|
||||
stride,
|
||||
},
|
||||
},
|
||||
});
|
||||
ty_span,
|
||||
);
|
||||
|
||||
(align, span)
|
||||
}
|
||||
@@ -138,14 +142,18 @@ pub fn calculate_offset(
|
||||
span += info.span;
|
||||
}
|
||||
|
||||
ty = types.fetch_or_append(Type {
|
||||
name,
|
||||
inner: TypeInner::Struct {
|
||||
top_level,
|
||||
members,
|
||||
span,
|
||||
let ty_span = types.get_span(ty).clone();
|
||||
ty = types.fetch_or_append(
|
||||
Type {
|
||||
name,
|
||||
inner: TypeInner::Struct {
|
||||
top_level,
|
||||
members,
|
||||
span,
|
||||
},
|
||||
},
|
||||
});
|
||||
ty_span,
|
||||
);
|
||||
|
||||
(align, span)
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ impl<'ctx> DeclarationContext<'ctx> {
|
||||
GlobalOrConstant::Global(handle) => Expression::GlobalVariable(handle),
|
||||
GlobalOrConstant::Constant(handle) => Expression::Constant(handle),
|
||||
};
|
||||
Ok(self.ctx.add_expression(expr, self.body))
|
||||
Ok(self.ctx.add_expression(expr, meta, self.body))
|
||||
}
|
||||
false => parser.add_local_var(self.ctx, self.body, decl),
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ impl<'source> ParsingContext<'source> {
|
||||
global_ctx: &mut Context,
|
||||
global_body: &mut Block,
|
||||
) -> Result<()> {
|
||||
if !self.parse_declaration(parser, global_ctx, global_body, true)? {
|
||||
if self
|
||||
.parse_declaration(parser, global_ctx, global_body, true)?
|
||||
.is_none()
|
||||
{
|
||||
let token = self.bump(parser)?;
|
||||
match token.value {
|
||||
TokenValue::Semicolon if parser.meta.version == 460 => Ok(()),
|
||||
@@ -94,7 +97,7 @@ impl<'source> ParsingContext<'source> {
|
||||
}
|
||||
|
||||
Ok((
|
||||
ctx.add_expression(Expression::Compose { ty, components }, body),
|
||||
ctx.add_expression(Expression::Compose { ty, components }, meta, body),
|
||||
meta,
|
||||
))
|
||||
} else {
|
||||
@@ -173,7 +176,7 @@ impl<'source> ParsingContext<'source> {
|
||||
// NOTE: unlike other parse methods this one doesn't expect an array specifier and
|
||||
// returns Ok(None) rather than an error if there is not one
|
||||
let array_specifier = self.parse_array_specifier(parser)?;
|
||||
let ty = parser.maybe_array(ty, array_specifier);
|
||||
let ty = parser.maybe_array(ty, meta, array_specifier);
|
||||
|
||||
let init = self
|
||||
.bump_if(parser, TokenValue::Assign)
|
||||
@@ -203,7 +206,8 @@ impl<'source> ParsingContext<'source> {
|
||||
|
||||
if let Some((value, _)) = init.filter(|_| maybe_constant.is_none()) {
|
||||
ctx.flush_expressions();
|
||||
ctx.body.push(Statement::Store { pointer, value });
|
||||
ctx.body
|
||||
.push(Statement::Store { pointer, value }, meta.as_span());
|
||||
}
|
||||
|
||||
let token = self.bump(parser)?;
|
||||
@@ -232,7 +236,7 @@ impl<'source> ParsingContext<'source> {
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
external: bool,
|
||||
) -> Result<bool> {
|
||||
) -> Result<Option<SourceMetadata>> {
|
||||
//declaration:
|
||||
// function_prototype SEMICOLON
|
||||
//
|
||||
@@ -276,7 +280,7 @@ impl<'source> ParsingContext<'source> {
|
||||
// This branch handles function prototypes
|
||||
parser.add_prototype(context, name, result, meta);
|
||||
|
||||
Ok(true)
|
||||
Ok(Some(meta))
|
||||
}
|
||||
TokenValue::LeftBrace if external => {
|
||||
// This branch handles function definitions
|
||||
@@ -284,11 +288,16 @@ impl<'source> ParsingContext<'source> {
|
||||
// only happens if external is also true
|
||||
|
||||
// parse the body
|
||||
self.parse_compound_statement(parser, &mut context, &mut body)?;
|
||||
self.parse_compound_statement(
|
||||
token.meta,
|
||||
parser,
|
||||
&mut context,
|
||||
&mut body,
|
||||
)?;
|
||||
|
||||
parser.add_function(context, name, result, body, meta);
|
||||
|
||||
Ok(true)
|
||||
Ok(Some(meta))
|
||||
}
|
||||
_ if external => Err(Error {
|
||||
kind: ErrorKind::InvalidToken(
|
||||
@@ -338,7 +347,7 @@ impl<'source> ParsingContext<'source> {
|
||||
})
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
Ok(Some(meta))
|
||||
} else {
|
||||
// This branch handles struct definitions and modifiers like
|
||||
// ```glsl
|
||||
@@ -356,6 +365,7 @@ impl<'source> ParsingContext<'source> {
|
||||
ty_name,
|
||||
token.meta,
|
||||
)
|
||||
.map(Some)
|
||||
} else {
|
||||
//TODO: declaration
|
||||
// type_qualifier IDENTIFIER SEMICOLON
|
||||
@@ -367,7 +377,9 @@ impl<'source> ParsingContext<'source> {
|
||||
}
|
||||
}
|
||||
TokenValue::Semicolon => {
|
||||
let mut meta_all = token.meta;
|
||||
for &(ref qualifier, meta) in qualifiers.iter() {
|
||||
meta_all = meta_all.union(&meta);
|
||||
match *qualifier {
|
||||
TypeQualifier::WorkGroupSize(i, value) => {
|
||||
parser.meta.workgroup_size[i] = value
|
||||
@@ -391,7 +403,7 @@ impl<'source> ParsingContext<'source> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
Ok(Some(meta_all))
|
||||
}
|
||||
_ => Err(Error {
|
||||
kind: ErrorKind::InvalidToken(
|
||||
@@ -447,9 +459,9 @@ impl<'source> ParsingContext<'source> {
|
||||
|
||||
self.expect(parser, TokenValue::Semicolon)?;
|
||||
|
||||
Ok(true)
|
||||
Ok(Some(meta))
|
||||
}
|
||||
_ => Ok(false),
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -461,8 +473,8 @@ impl<'source> ParsingContext<'source> {
|
||||
body: &mut Block,
|
||||
qualifiers: &[(TypeQualifier, SourceMetadata)],
|
||||
ty_name: String,
|
||||
mut meta: SourceMetadata,
|
||||
) -> Result<bool> {
|
||||
meta: SourceMetadata,
|
||||
) -> Result<SourceMetadata> {
|
||||
let mut storage = None;
|
||||
let mut layout = None;
|
||||
|
||||
@@ -486,29 +498,24 @@ impl<'source> ParsingContext<'source> {
|
||||
let span = self.parse_struct_declaration_list(parser, &mut members, layout)?;
|
||||
self.expect(parser, TokenValue::RightBrace)?;
|
||||
|
||||
let mut ty = parser.module.types.append(Type {
|
||||
name: Some(ty_name),
|
||||
inner: TypeInner::Struct {
|
||||
top_level: true,
|
||||
members: members.clone(),
|
||||
span,
|
||||
let mut ty = parser.module.types.append(
|
||||
Type {
|
||||
name: Some(ty_name),
|
||||
inner: TypeInner::Struct {
|
||||
top_level: true,
|
||||
members: members.clone(),
|
||||
span,
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let token = self.bump(parser)?;
|
||||
let name = match token.value {
|
||||
TokenValue::Semicolon => None,
|
||||
TokenValue::Identifier(name) => {
|
||||
if let Some(size) = self.parse_array_specifier(parser)? {
|
||||
ty = parser.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Array {
|
||||
base: ty,
|
||||
size,
|
||||
stride: parser.module.types[ty].inner.span(&parser.module.constants),
|
||||
},
|
||||
});
|
||||
}
|
||||
let array_specifier = self.parse_array_specifier(parser)?;
|
||||
ty = parser.maybe_array(ty, token.meta, array_specifier);
|
||||
|
||||
self.expect(parser, TokenValue::Semicolon)?;
|
||||
|
||||
@@ -524,7 +531,6 @@ impl<'source> ParsingContext<'source> {
|
||||
})
|
||||
}
|
||||
};
|
||||
meta = meta.union(&token.meta);
|
||||
|
||||
let global = parser.add_global_var(
|
||||
ctx,
|
||||
@@ -556,7 +562,7 @@ impl<'source> ParsingContext<'source> {
|
||||
parser.global_variables.push((k, lookup));
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
Ok(meta)
|
||||
}
|
||||
|
||||
// TODO: Accept layout arguments
|
||||
@@ -578,7 +584,7 @@ impl<'source> ParsingContext<'source> {
|
||||
meta = meta.union(&end_meta);
|
||||
|
||||
let array_specifier = self.parse_array_specifier(parser)?;
|
||||
let ty = parser.maybe_array(ty, array_specifier);
|
||||
let ty = parser.maybe_array(ty, meta, array_specifier);
|
||||
|
||||
self.expect(parser, TokenValue::Semicolon)?;
|
||||
|
||||
|
||||
@@ -59,16 +59,22 @@ impl<'source> ParsingContext<'source> {
|
||||
}
|
||||
};
|
||||
|
||||
let handle = parser.module.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar { width, value },
|
||||
});
|
||||
let handle = parser.module.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar { width, value },
|
||||
},
|
||||
token.meta.as_span(),
|
||||
);
|
||||
|
||||
Ok(stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::Constant(handle),
|
||||
meta: token.meta,
|
||||
}))
|
||||
Ok(stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::Constant(handle),
|
||||
meta: token.meta,
|
||||
},
|
||||
Default::default(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn parse_function_call_args(
|
||||
@@ -133,7 +139,7 @@ impl<'source> ParsingContext<'source> {
|
||||
meta,
|
||||
}
|
||||
} else {
|
||||
let var = match parser.lookup_variable(ctx, body, &name) {
|
||||
let var = match parser.lookup_variable(ctx, body, &name, meta) {
|
||||
Some(var) => var,
|
||||
None => {
|
||||
return Err(Error {
|
||||
@@ -149,13 +155,17 @@ impl<'source> ParsingContext<'source> {
|
||||
}
|
||||
};
|
||||
|
||||
stmt.hir_exprs.append(expr)
|
||||
stmt.hir_exprs.append(expr, Default::default())
|
||||
}
|
||||
TokenValue::TypeName(_) => {
|
||||
let Token { value, mut meta } = self.bump(parser)?;
|
||||
let Token {
|
||||
value,
|
||||
meta: name_meta,
|
||||
} = self.bump(parser)?;
|
||||
let mut meta = name_meta;
|
||||
|
||||
let mut handle = if let TokenValue::TypeName(ty) = value {
|
||||
parser.module.types.fetch_or_append(ty)
|
||||
parser.module.types.fetch_or_append(ty, name_meta.as_span())
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
@@ -165,7 +175,7 @@ impl<'source> ParsingContext<'source> {
|
||||
self.expect(parser, TokenValue::LeftParen)?;
|
||||
let args = self.parse_function_call_args(parser, ctx, stmt, body, &mut meta)?;
|
||||
|
||||
if let Some(array_size) = maybe_size {
|
||||
if let Some((array_size, array_meta)) = maybe_size {
|
||||
let stride = parser.module.types[handle]
|
||||
.inner
|
||||
.span(&parser.module.constants);
|
||||
@@ -173,36 +183,45 @@ impl<'source> ParsingContext<'source> {
|
||||
let size = match array_size {
|
||||
ArraySize::Constant(size) => ArraySize::Constant(size),
|
||||
ArraySize::Dynamic => {
|
||||
let constant = parser.module.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Sint(args.len() as i64),
|
||||
let constant = parser.module.constants.fetch_or_append(
|
||||
Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: ScalarValue::Sint(args.len() as i64),
|
||||
},
|
||||
},
|
||||
});
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
ArraySize::Constant(constant)
|
||||
}
|
||||
};
|
||||
|
||||
handle = parser.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Array {
|
||||
base: handle,
|
||||
size,
|
||||
stride,
|
||||
handle = parser.module.types.fetch_or_append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Array {
|
||||
base: handle,
|
||||
size,
|
||||
stride,
|
||||
},
|
||||
},
|
||||
})
|
||||
name_meta.union(&array_meta).as_span(),
|
||||
);
|
||||
}
|
||||
|
||||
stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::Call(FunctionCall {
|
||||
kind: FunctionCallKind::TypeConstructor(handle),
|
||||
args,
|
||||
}),
|
||||
meta,
|
||||
})
|
||||
stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::Call(FunctionCall {
|
||||
kind: FunctionCallKind::TypeConstructor(handle),
|
||||
args,
|
||||
}),
|
||||
meta,
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
_ => self.parse_primary(parser, ctx, stmt, body)?,
|
||||
};
|
||||
@@ -219,38 +238,50 @@ impl<'source> ParsingContext<'source> {
|
||||
let index = self.parse_expression(parser, ctx, stmt, body)?;
|
||||
let end_meta = self.expect(parser, TokenValue::RightBracket)?.meta;
|
||||
|
||||
base = stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::Access { base, index },
|
||||
meta: meta.union(&end_meta),
|
||||
})
|
||||
base = stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::Access { base, index },
|
||||
meta: meta.union(&end_meta),
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
TokenValue::Dot => {
|
||||
let (field, end_meta) = self.expect_ident(parser)?;
|
||||
|
||||
base = stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::Select { base, field },
|
||||
meta: meta.union(&end_meta),
|
||||
})
|
||||
base = stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::Select { base, field },
|
||||
meta: meta.union(&end_meta),
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
TokenValue::Increment => {
|
||||
base = stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::IncDec {
|
||||
increment: true,
|
||||
postfix: true,
|
||||
expr: base,
|
||||
base = stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::IncDec {
|
||||
increment: true,
|
||||
postfix: true,
|
||||
expr: base,
|
||||
},
|
||||
meta,
|
||||
},
|
||||
meta,
|
||||
})
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
TokenValue::Decrement => {
|
||||
base = stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::IncDec {
|
||||
increment: false,
|
||||
postfix: true,
|
||||
expr: base,
|
||||
base = stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::IncDec {
|
||||
increment: false,
|
||||
postfix: true,
|
||||
expr: base,
|
||||
},
|
||||
meta,
|
||||
},
|
||||
meta,
|
||||
})
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
@@ -286,28 +317,34 @@ impl<'source> ParsingContext<'source> {
|
||||
_ => return Ok(expr),
|
||||
};
|
||||
|
||||
stmt.hir_exprs.append(HirExpr {
|
||||
kind,
|
||||
meta: meta.union(&end_meta),
|
||||
})
|
||||
stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind,
|
||||
meta: meta.union(&end_meta),
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
TokenValue::Increment | TokenValue::Decrement => {
|
||||
let Token { value, meta } = self.bump(parser)?;
|
||||
|
||||
let expr = self.parse_unary(parser, ctx, stmt, body)?;
|
||||
|
||||
stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::IncDec {
|
||||
increment: match value {
|
||||
TokenValue::Increment => true,
|
||||
TokenValue::Decrement => false,
|
||||
_ => unreachable!(),
|
||||
stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::IncDec {
|
||||
increment: match value {
|
||||
TokenValue::Increment => true,
|
||||
TokenValue::Decrement => false,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
postfix: false,
|
||||
expr,
|
||||
},
|
||||
postfix: false,
|
||||
expr,
|
||||
meta,
|
||||
},
|
||||
meta,
|
||||
})
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
_ => self.parse_postfix(parser, ctx, stmt, body)?,
|
||||
})
|
||||
@@ -337,35 +374,38 @@ impl<'source> ParsingContext<'source> {
|
||||
let right = self.parse_binary(parser, ctx, stmt, body, None, r_bp)?;
|
||||
let end_meta = stmt.hir_exprs[right].meta;
|
||||
|
||||
left = stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::Binary {
|
||||
left,
|
||||
op: match value {
|
||||
TokenValue::LogicalOr => BinaryOperator::LogicalOr,
|
||||
TokenValue::LogicalXor => BinaryOperator::NotEqual,
|
||||
TokenValue::LogicalAnd => BinaryOperator::LogicalAnd,
|
||||
TokenValue::VerticalBar => BinaryOperator::InclusiveOr,
|
||||
TokenValue::Caret => BinaryOperator::ExclusiveOr,
|
||||
TokenValue::Ampersand => BinaryOperator::And,
|
||||
TokenValue::Equal => BinaryOperator::Equal,
|
||||
TokenValue::NotEqual => BinaryOperator::NotEqual,
|
||||
TokenValue::GreaterEqual => BinaryOperator::GreaterEqual,
|
||||
TokenValue::LessEqual => BinaryOperator::LessEqual,
|
||||
TokenValue::LeftAngle => BinaryOperator::Less,
|
||||
TokenValue::RightAngle => BinaryOperator::Greater,
|
||||
TokenValue::LeftShift => BinaryOperator::ShiftLeft,
|
||||
TokenValue::RightShift => BinaryOperator::ShiftRight,
|
||||
TokenValue::Plus => BinaryOperator::Add,
|
||||
TokenValue::Dash => BinaryOperator::Subtract,
|
||||
TokenValue::Star => BinaryOperator::Multiply,
|
||||
TokenValue::Slash => BinaryOperator::Divide,
|
||||
TokenValue::Percent => BinaryOperator::Modulo,
|
||||
_ => unreachable!(),
|
||||
left = stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::Binary {
|
||||
left,
|
||||
op: match value {
|
||||
TokenValue::LogicalOr => BinaryOperator::LogicalOr,
|
||||
TokenValue::LogicalXor => BinaryOperator::NotEqual,
|
||||
TokenValue::LogicalAnd => BinaryOperator::LogicalAnd,
|
||||
TokenValue::VerticalBar => BinaryOperator::InclusiveOr,
|
||||
TokenValue::Caret => BinaryOperator::ExclusiveOr,
|
||||
TokenValue::Ampersand => BinaryOperator::And,
|
||||
TokenValue::Equal => BinaryOperator::Equal,
|
||||
TokenValue::NotEqual => BinaryOperator::NotEqual,
|
||||
TokenValue::GreaterEqual => BinaryOperator::GreaterEqual,
|
||||
TokenValue::LessEqual => BinaryOperator::LessEqual,
|
||||
TokenValue::LeftAngle => BinaryOperator::Less,
|
||||
TokenValue::RightAngle => BinaryOperator::Greater,
|
||||
TokenValue::LeftShift => BinaryOperator::ShiftLeft,
|
||||
TokenValue::RightShift => BinaryOperator::ShiftRight,
|
||||
TokenValue::Plus => BinaryOperator::Add,
|
||||
TokenValue::Dash => BinaryOperator::Subtract,
|
||||
TokenValue::Star => BinaryOperator::Multiply,
|
||||
TokenValue::Slash => BinaryOperator::Divide,
|
||||
TokenValue::Percent => BinaryOperator::Modulo,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
right,
|
||||
},
|
||||
right,
|
||||
meta: start_meta.union(&end_meta),
|
||||
},
|
||||
meta: start_meta.union(&end_meta),
|
||||
})
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
Ok(left)
|
||||
@@ -388,14 +428,17 @@ impl<'source> ParsingContext<'source> {
|
||||
let reject = self.parse_assignment(parser, ctx, stmt, body)?;
|
||||
let end_meta = stmt.hir_exprs[reject].meta;
|
||||
|
||||
condition = stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::Conditional {
|
||||
condition,
|
||||
accept,
|
||||
reject,
|
||||
condition = stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::Conditional {
|
||||
condition,
|
||||
accept,
|
||||
reject,
|
||||
},
|
||||
meta: start_meta.union(&end_meta),
|
||||
},
|
||||
meta: start_meta.union(&end_meta),
|
||||
})
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
Ok(condition)
|
||||
@@ -417,10 +460,13 @@ impl<'source> ParsingContext<'source> {
|
||||
let value = self.parse_assignment(parser, ctx, stmt, body)?;
|
||||
let end_meta = stmt.hir_exprs[value].meta;
|
||||
|
||||
stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::Assign { tgt, value },
|
||||
meta: start_meta.union(&end_meta),
|
||||
})
|
||||
stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::Assign { tgt, value },
|
||||
meta: start_meta.union(&end_meta),
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
TokenValue::OrAssign
|
||||
| TokenValue::AndAssign
|
||||
@@ -436,31 +482,37 @@ impl<'source> ParsingContext<'source> {
|
||||
let right = self.parse_assignment(parser, ctx, stmt, body)?;
|
||||
let end_meta = stmt.hir_exprs[right].meta;
|
||||
|
||||
let value = stmt.hir_exprs.append(HirExpr {
|
||||
meta: start_meta.union(&end_meta),
|
||||
kind: HirExprKind::Binary {
|
||||
left: tgt,
|
||||
op: match token.value {
|
||||
TokenValue::OrAssign => BinaryOperator::InclusiveOr,
|
||||
TokenValue::AndAssign => BinaryOperator::And,
|
||||
TokenValue::AddAssign => BinaryOperator::Add,
|
||||
TokenValue::DivAssign => BinaryOperator::Divide,
|
||||
TokenValue::ModAssign => BinaryOperator::Modulo,
|
||||
TokenValue::SubAssign => BinaryOperator::Subtract,
|
||||
TokenValue::MulAssign => BinaryOperator::Multiply,
|
||||
TokenValue::LeftShiftAssign => BinaryOperator::ShiftLeft,
|
||||
TokenValue::RightShiftAssign => BinaryOperator::ShiftRight,
|
||||
TokenValue::XorAssign => BinaryOperator::ExclusiveOr,
|
||||
_ => unreachable!(),
|
||||
let value = stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
meta: start_meta.union(&end_meta),
|
||||
kind: HirExprKind::Binary {
|
||||
left: tgt,
|
||||
op: match token.value {
|
||||
TokenValue::OrAssign => BinaryOperator::InclusiveOr,
|
||||
TokenValue::AndAssign => BinaryOperator::And,
|
||||
TokenValue::AddAssign => BinaryOperator::Add,
|
||||
TokenValue::DivAssign => BinaryOperator::Divide,
|
||||
TokenValue::ModAssign => BinaryOperator::Modulo,
|
||||
TokenValue::SubAssign => BinaryOperator::Subtract,
|
||||
TokenValue::MulAssign => BinaryOperator::Multiply,
|
||||
TokenValue::LeftShiftAssign => BinaryOperator::ShiftLeft,
|
||||
TokenValue::RightShiftAssign => BinaryOperator::ShiftRight,
|
||||
TokenValue::XorAssign => BinaryOperator::ExclusiveOr,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
right,
|
||||
},
|
||||
right,
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
stmt.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::Assign { tgt, value },
|
||||
meta: start_meta.union(&end_meta),
|
||||
})
|
||||
stmt.hir_exprs.append(
|
||||
HirExpr {
|
||||
kind: HirExprKind::Assign { tgt, value },
|
||||
meta: start_meta.union(&end_meta),
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
_ => self.parse_conditional(parser, ctx, stmt, body, Some(tgt))?,
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::front::glsl::SourceMetadata;
|
||||
use crate::{
|
||||
front::glsl::{
|
||||
ast::ParameterQualifier,
|
||||
@@ -38,7 +39,7 @@ impl<'source> ParsingContext<'source> {
|
||||
parser: &mut Parser,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
) -> Result<()> {
|
||||
) -> Result<Option<SourceMetadata>> {
|
||||
// TODO: This prevents snippets like the following from working
|
||||
// ```glsl
|
||||
// vec4(1.0);
|
||||
@@ -47,55 +48,60 @@ impl<'source> ParsingContext<'source> {
|
||||
// declarations and since this statement is very unlikely and most
|
||||
// likely an error, for now we don't support it
|
||||
if self.peek_type_name(parser) || self.peek_type_qualifier(parser) {
|
||||
self.parse_declaration(parser, ctx, body, false)?;
|
||||
return Ok(());
|
||||
return self.parse_declaration(parser, ctx, body, false);
|
||||
}
|
||||
|
||||
match self.expect_peek(parser)?.value {
|
||||
let new_break = || {
|
||||
let mut block = Block::new();
|
||||
block.push(Statement::Break, crate::Span::Unknown);
|
||||
block
|
||||
};
|
||||
|
||||
let &Token { ref value, meta } = self.expect_peek(parser)?;
|
||||
|
||||
let meta_rest = match *value {
|
||||
TokenValue::Continue => {
|
||||
self.bump(parser)?;
|
||||
body.push(Statement::Continue);
|
||||
self.expect(parser, TokenValue::Semicolon)?;
|
||||
body.push(Statement::Continue, self.bump(parser)?.meta.as_span());
|
||||
self.expect(parser, TokenValue::Semicolon)?.meta
|
||||
}
|
||||
TokenValue::Break => {
|
||||
self.bump(parser)?;
|
||||
body.push(Statement::Break);
|
||||
self.expect(parser, TokenValue::Semicolon)?;
|
||||
body.push(Statement::Break, self.bump(parser)?.meta.as_span());
|
||||
self.expect(parser, TokenValue::Semicolon)?.meta
|
||||
}
|
||||
TokenValue::Return => {
|
||||
self.bump(parser)?;
|
||||
let value = match self.expect_peek(parser)?.value {
|
||||
TokenValue::Semicolon => {
|
||||
self.bump(parser)?;
|
||||
None
|
||||
}
|
||||
let (value, meta) = match self.expect_peek(parser)?.value {
|
||||
TokenValue::Semicolon => (None, self.bump(parser)?.meta),
|
||||
_ => {
|
||||
// TODO: Implicit conversions
|
||||
let mut stmt = ctx.stmt_ctx();
|
||||
let expr = self.parse_expression(parser, ctx, &mut stmt, body)?;
|
||||
self.expect(parser, TokenValue::Semicolon)?;
|
||||
Some(ctx.lower_expect(stmt, parser, expr, false, body)?.0)
|
||||
let (handle, meta) = ctx.lower_expect(stmt, parser, expr, false, body)?;
|
||||
(Some(handle), meta)
|
||||
}
|
||||
};
|
||||
|
||||
ctx.emit_flush(body);
|
||||
ctx.emit_start();
|
||||
|
||||
body.push(Statement::Return { value })
|
||||
body.push(Statement::Return { value }, meta.as_span());
|
||||
meta
|
||||
}
|
||||
TokenValue::Discard => {
|
||||
self.bump(parser)?;
|
||||
body.push(Statement::Kill);
|
||||
self.expect(parser, TokenValue::Semicolon)?;
|
||||
body.push(Statement::Kill, self.bump(parser)?.meta.as_span());
|
||||
self.expect(parser, TokenValue::Semicolon)?.meta
|
||||
}
|
||||
TokenValue::If => {
|
||||
self.bump(parser)?;
|
||||
let mut meta = self.bump(parser)?.meta;
|
||||
|
||||
self.expect(parser, TokenValue::LeftParen)?;
|
||||
let condition = {
|
||||
let mut stmt = ctx.stmt_ctx();
|
||||
let expr = self.parse_expression(parser, ctx, &mut stmt, body)?;
|
||||
ctx.lower_expect(stmt, parser, expr, false, body)?.0
|
||||
let (handle, more_meta) = ctx.lower_expect(stmt, parser, expr, false, body)?;
|
||||
meta = meta.union(&more_meta);
|
||||
handle
|
||||
};
|
||||
self.expect(parser, TokenValue::RightParen)?;
|
||||
|
||||
@@ -103,21 +109,30 @@ impl<'source> ParsingContext<'source> {
|
||||
ctx.emit_start();
|
||||
|
||||
let mut accept = Block::new();
|
||||
self.parse_statement(parser, ctx, &mut accept)?;
|
||||
if let Some(more_meta) = self.parse_statement(parser, ctx, &mut accept)? {
|
||||
meta = meta.union(&more_meta)
|
||||
}
|
||||
|
||||
let mut reject = Block::new();
|
||||
if self.bump_if(parser, TokenValue::Else).is_some() {
|
||||
self.parse_statement(parser, ctx, &mut reject)?;
|
||||
if let Some(more_meta) = self.parse_statement(parser, ctx, &mut reject)? {
|
||||
meta = meta.union(&more_meta);
|
||||
}
|
||||
}
|
||||
|
||||
body.push(Statement::If {
|
||||
condition,
|
||||
accept,
|
||||
reject,
|
||||
});
|
||||
body.push(
|
||||
Statement::If {
|
||||
condition,
|
||||
accept,
|
||||
reject,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
meta
|
||||
}
|
||||
TokenValue::Switch => {
|
||||
self.bump(parser)?;
|
||||
let start_meta = self.bump(parser)?.meta;
|
||||
let end_meta;
|
||||
|
||||
self.expect(parser, TokenValue::LeftParen)?;
|
||||
// TODO: Implicit conversions
|
||||
@@ -177,7 +192,9 @@ impl<'source> ParsingContext<'source> {
|
||||
TokenValue::Case
|
||||
| TokenValue::Default
|
||||
| TokenValue::RightBrace => break,
|
||||
_ => self.parse_statement(parser, ctx, &mut body)?,
|
||||
_ => {
|
||||
self.parse_statement(parser, ctx, &mut body)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +203,7 @@ impl<'source> ParsingContext<'source> {
|
||||
for (i, stmt) in body.iter().enumerate() {
|
||||
if let Statement::Break = *stmt {
|
||||
fall_through = false;
|
||||
body.drain(i..);
|
||||
body.cull(i..);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -214,19 +231,21 @@ impl<'source> ParsingContext<'source> {
|
||||
loop {
|
||||
match self.expect_peek(parser)?.value {
|
||||
TokenValue::Case | TokenValue::RightBrace => break,
|
||||
_ => self.parse_statement(parser, ctx, &mut default)?,
|
||||
_ => {
|
||||
self.parse_statement(parser, ctx, &mut default)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i, stmt) in default.iter().enumerate() {
|
||||
if let Statement::Break = *stmt {
|
||||
default.drain(i..);
|
||||
default.cull(i..);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
TokenValue::RightBrace => {
|
||||
self.bump(parser)?;
|
||||
end_meta = self.bump(parser)?.meta;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
@@ -246,51 +265,67 @@ impl<'source> ParsingContext<'source> {
|
||||
}
|
||||
}
|
||||
|
||||
body.push(Statement::Switch {
|
||||
selector,
|
||||
cases,
|
||||
default,
|
||||
});
|
||||
let meta = start_meta.union(&end_meta);
|
||||
body.push(
|
||||
Statement::Switch {
|
||||
selector,
|
||||
cases,
|
||||
default,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
meta
|
||||
}
|
||||
TokenValue::While => {
|
||||
self.bump(parser)?;
|
||||
let meta = self.bump(parser)?.meta;
|
||||
|
||||
let mut loop_body = Block::new();
|
||||
|
||||
let mut stmt = ctx.stmt_ctx();
|
||||
self.expect(parser, TokenValue::LeftParen)?;
|
||||
let root = self.parse_expression(parser, ctx, &mut stmt, &mut loop_body)?;
|
||||
self.expect(parser, TokenValue::RightParen)?;
|
||||
let meta = meta.union(&self.expect(parser, TokenValue::RightParen)?.meta);
|
||||
|
||||
let expr = ctx
|
||||
.lower_expect(stmt, parser, root, false, &mut loop_body)?
|
||||
.0;
|
||||
let (expr, expr_meta) =
|
||||
ctx.lower_expect(stmt, parser, root, false, &mut loop_body)?;
|
||||
let condition = ctx.add_expression(
|
||||
Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
},
|
||||
expr_meta,
|
||||
&mut loop_body,
|
||||
);
|
||||
|
||||
ctx.emit_flush(&mut loop_body);
|
||||
ctx.emit_start();
|
||||
|
||||
loop_body.push(Statement::If {
|
||||
condition,
|
||||
accept: vec![Statement::Break],
|
||||
reject: Block::new(),
|
||||
});
|
||||
loop_body.push(
|
||||
Statement::If {
|
||||
condition,
|
||||
accept: new_break(),
|
||||
reject: Block::new(),
|
||||
},
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
|
||||
self.parse_statement(parser, ctx, &mut loop_body)?;
|
||||
let mut meta = meta.union(&expr_meta);
|
||||
|
||||
body.push(Statement::Loop {
|
||||
body: loop_body,
|
||||
continuing: Block::new(),
|
||||
})
|
||||
if let Some(body_meta) = self.parse_statement(parser, ctx, &mut loop_body)? {
|
||||
meta = meta.union(&body_meta);
|
||||
}
|
||||
|
||||
body.push(
|
||||
Statement::Loop {
|
||||
body: loop_body,
|
||||
continuing: Block::new(),
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
meta
|
||||
}
|
||||
TokenValue::Do => {
|
||||
self.bump(parser)?;
|
||||
let start_meta = self.bump(parser)?.meta;
|
||||
|
||||
let mut loop_body = Block::new();
|
||||
self.parse_statement(parser, ctx, &mut loop_body)?;
|
||||
@@ -300,35 +335,44 @@ impl<'source> ParsingContext<'source> {
|
||||
self.expect(parser, TokenValue::While)?;
|
||||
self.expect(parser, TokenValue::LeftParen)?;
|
||||
let root = self.parse_expression(parser, ctx, &mut stmt, &mut loop_body)?;
|
||||
self.expect(parser, TokenValue::RightParen)?;
|
||||
let end_meta = self.expect(parser, TokenValue::RightParen)?.meta;
|
||||
|
||||
let expr = ctx
|
||||
.lower_expect(stmt, parser, root, false, &mut loop_body)?
|
||||
.0;
|
||||
let meta = start_meta.union(&end_meta);
|
||||
|
||||
let (expr, expr_meta) =
|
||||
ctx.lower_expect(stmt, parser, root, false, &mut loop_body)?;
|
||||
let condition = ctx.add_expression(
|
||||
Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
},
|
||||
expr_meta,
|
||||
&mut loop_body,
|
||||
);
|
||||
|
||||
ctx.emit_flush(&mut loop_body);
|
||||
ctx.emit_start();
|
||||
|
||||
loop_body.push(Statement::If {
|
||||
condition,
|
||||
accept: vec![Statement::Break],
|
||||
reject: Block::new(),
|
||||
});
|
||||
loop_body.push(
|
||||
Statement::If {
|
||||
condition,
|
||||
accept: new_break(),
|
||||
reject: Block::new(),
|
||||
},
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
|
||||
body.push(Statement::Loop {
|
||||
body: loop_body,
|
||||
continuing: Block::new(),
|
||||
})
|
||||
body.push(
|
||||
Statement::Loop {
|
||||
body: loop_body,
|
||||
continuing: Block::new(),
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
meta
|
||||
}
|
||||
TokenValue::For => {
|
||||
self.bump(parser)?;
|
||||
let meta = self.bump(parser)?.meta;
|
||||
|
||||
ctx.push_scope();
|
||||
self.expect(parser, TokenValue::LeftParen)?;
|
||||
@@ -347,54 +391,60 @@ impl<'source> ParsingContext<'source> {
|
||||
let (mut block, mut continuing) = (Block::new(), Block::new());
|
||||
|
||||
if self.bump_if(parser, TokenValue::Semicolon).is_none() {
|
||||
let expr = if self.peek_type_name(parser) || self.peek_type_qualifier(parser) {
|
||||
let qualifiers = self.parse_type_qualifiers(parser)?;
|
||||
let (ty, meta) = self.parse_type_non_void(parser)?;
|
||||
let name = self.expect_ident(parser)?.0;
|
||||
let (expr, expr_meta) =
|
||||
if self.peek_type_name(parser) || self.peek_type_qualifier(parser) {
|
||||
let qualifiers = self.parse_type_qualifiers(parser)?;
|
||||
let (ty, meta) = self.parse_type_non_void(parser)?;
|
||||
let name = self.expect_ident(parser)?.0;
|
||||
|
||||
self.expect(parser, TokenValue::Assign)?;
|
||||
self.expect(parser, TokenValue::Assign)?;
|
||||
|
||||
let (value, end_meta) =
|
||||
self.parse_initializer(parser, ty, ctx, &mut block)?;
|
||||
let (value, end_meta) =
|
||||
self.parse_initializer(parser, ty, ctx, &mut block)?;
|
||||
let meta = meta.union(&end_meta);
|
||||
|
||||
let decl = VarDeclaration {
|
||||
qualifiers: &qualifiers,
|
||||
ty,
|
||||
name: Some(name),
|
||||
init: None,
|
||||
meta: meta.union(&end_meta),
|
||||
let decl = VarDeclaration {
|
||||
qualifiers: &qualifiers,
|
||||
ty,
|
||||
name: Some(name),
|
||||
init: None,
|
||||
meta,
|
||||
};
|
||||
|
||||
let pointer = parser.add_local_var(ctx, &mut block, decl)?;
|
||||
|
||||
ctx.emit_flush(&mut block);
|
||||
ctx.emit_start();
|
||||
|
||||
block.push(Statement::Store { pointer, value }, meta.as_span());
|
||||
|
||||
(value, end_meta)
|
||||
} else {
|
||||
let mut stmt = ctx.stmt_ctx();
|
||||
let root = self.parse_expression(parser, ctx, &mut stmt, &mut block)?;
|
||||
ctx.lower_expect(stmt, parser, root, false, &mut block)?
|
||||
};
|
||||
|
||||
let pointer = parser.add_local_var(ctx, &mut block, decl)?;
|
||||
|
||||
ctx.emit_flush(&mut block);
|
||||
ctx.emit_start();
|
||||
|
||||
block.push(Statement::Store { pointer, value });
|
||||
|
||||
value
|
||||
} else {
|
||||
let mut stmt = ctx.stmt_ctx();
|
||||
let root = self.parse_expression(parser, ctx, &mut stmt, &mut block)?;
|
||||
ctx.lower_expect(stmt, parser, root, false, &mut block)?.0
|
||||
};
|
||||
|
||||
let condition = ctx.add_expression(
|
||||
Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
},
|
||||
expr_meta,
|
||||
&mut block,
|
||||
);
|
||||
|
||||
ctx.emit_flush(&mut block);
|
||||
ctx.emit_start();
|
||||
|
||||
block.push(Statement::If {
|
||||
condition,
|
||||
accept: vec![Statement::Break],
|
||||
reject: Block::new(),
|
||||
});
|
||||
block.push(
|
||||
Statement::If {
|
||||
condition,
|
||||
accept: new_break(),
|
||||
reject: Block::new(),
|
||||
},
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
|
||||
self.expect(parser, TokenValue::Semicolon)?;
|
||||
}
|
||||
@@ -409,27 +459,36 @@ impl<'source> ParsingContext<'source> {
|
||||
}
|
||||
}
|
||||
|
||||
self.expect(parser, TokenValue::RightParen)?;
|
||||
let mut meta = meta.union(&self.expect(parser, TokenValue::RightParen)?.meta);
|
||||
|
||||
self.parse_statement(parser, ctx, &mut block)?;
|
||||
if let Some(stmt_meta) = self.parse_statement(parser, ctx, &mut block)? {
|
||||
meta = meta.union(&stmt_meta);
|
||||
}
|
||||
|
||||
body.push(Statement::Loop {
|
||||
body: block,
|
||||
continuing,
|
||||
});
|
||||
body.push(
|
||||
Statement::Loop {
|
||||
body: block,
|
||||
continuing,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
ctx.remove_current_scope();
|
||||
|
||||
meta
|
||||
}
|
||||
TokenValue::LeftBrace => {
|
||||
self.bump(parser)?;
|
||||
let meta = self.bump(parser)?.meta;
|
||||
|
||||
let mut block = Block::new();
|
||||
ctx.push_scope();
|
||||
|
||||
self.parse_compound_statement(parser, ctx, &mut block)?;
|
||||
let meta = self.parse_compound_statement(meta, parser, ctx, &mut block)?;
|
||||
|
||||
ctx.remove_current_scope();
|
||||
body.push(Statement::Block(block));
|
||||
body.push(Statement::Block(block), meta.as_span());
|
||||
|
||||
meta
|
||||
}
|
||||
TokenValue::Plus
|
||||
| TokenValue::Dash
|
||||
@@ -444,32 +503,37 @@ impl<'source> ParsingContext<'source> {
|
||||
let mut stmt = ctx.stmt_ctx();
|
||||
let expr = self.parse_expression(parser, ctx, &mut stmt, body)?;
|
||||
ctx.lower(stmt, parser, expr, false, body)?;
|
||||
self.expect(parser, TokenValue::Semicolon)?;
|
||||
self.expect(parser, TokenValue::Semicolon)?.meta
|
||||
}
|
||||
TokenValue::Semicolon => {
|
||||
self.bump(parser)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
TokenValue::Semicolon => self.bump(parser)?.meta,
|
||||
_ => meta,
|
||||
};
|
||||
|
||||
Ok(())
|
||||
Ok(Some(meta.union(&meta_rest)))
|
||||
}
|
||||
|
||||
pub fn parse_compound_statement(
|
||||
&mut self,
|
||||
mut meta: SourceMetadata,
|
||||
parser: &mut Parser,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
) -> Result<()> {
|
||||
) -> Result<SourceMetadata> {
|
||||
loop {
|
||||
if self.bump_if(parser, TokenValue::RightBrace).is_some() {
|
||||
if let Some(Token {
|
||||
meta: brace_meta, ..
|
||||
}) = self.bump_if(parser, TokenValue::RightBrace)
|
||||
{
|
||||
meta = meta.union(&brace_meta);
|
||||
break;
|
||||
}
|
||||
|
||||
self.parse_statement(parser, ctx, body)?;
|
||||
if let Some(stmt_meta) = self.parse_statement(parser, ctx, body)? {
|
||||
meta = meta.union(&stmt_meta);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(meta)
|
||||
}
|
||||
|
||||
pub fn parse_function_args(
|
||||
@@ -490,12 +554,12 @@ impl<'source> ParsingContext<'source> {
|
||||
continue;
|
||||
}
|
||||
TokenValue::Identifier(_) => {
|
||||
let name = self.expect_ident(parser)?.0;
|
||||
let name_meta = self.expect_ident(parser)?;
|
||||
|
||||
let size = self.parse_array_specifier(parser)?;
|
||||
let ty = parser.maybe_array(ty, size);
|
||||
let array_specifier = self.parse_array_specifier(parser)?;
|
||||
let ty = parser.maybe_array(ty, name_meta.1, array_specifier);
|
||||
|
||||
context.add_function_arg(parser, body, Some(name), ty, qualifier);
|
||||
context.add_function_arg(parser, body, Some(name_meta), ty, qualifier);
|
||||
|
||||
if self.bump_if(parser, TokenValue::Comma).is_some() {
|
||||
continue;
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{
|
||||
ast::{StorageQualifier, StructLayout, TypeQualifier},
|
||||
error::ExpectedToken,
|
||||
parser::ParsingContext,
|
||||
token::{SourceMetadata, TokenValue},
|
||||
token::{SourceMetadata, Token, TokenValue},
|
||||
Error, ErrorKind, Parser, Result,
|
||||
},
|
||||
ArraySize, Handle, StorageClass, Type, TypeInner,
|
||||
@@ -12,15 +12,20 @@ use crate::{
|
||||
impl<'source> ParsingContext<'source> {
|
||||
/// Parses an optional array_specifier returning `Ok(None)` if there is no
|
||||
/// LeftBracket
|
||||
pub fn parse_array_specifier(&mut self, parser: &mut Parser) -> Result<Option<ArraySize>> {
|
||||
if self.bump_if(parser, TokenValue::LeftBracket).is_some() {
|
||||
if self.bump_if(parser, TokenValue::RightBracket).is_some() {
|
||||
return Ok(Some(ArraySize::Dynamic));
|
||||
pub fn parse_array_specifier(
|
||||
&mut self,
|
||||
parser: &mut Parser,
|
||||
) -> Result<Option<(ArraySize, SourceMetadata)>> {
|
||||
if let Some(Token { meta, .. }) = self.bump_if(parser, TokenValue::LeftBracket) {
|
||||
if let Some(Token { meta: end_meta, .. }) =
|
||||
self.bump_if(parser, TokenValue::RightBracket)
|
||||
{
|
||||
return Ok(Some((ArraySize::Dynamic, meta.union(&end_meta))));
|
||||
}
|
||||
|
||||
let (constant, _) = self.parse_constant_expression(parser)?;
|
||||
self.expect(parser, TokenValue::RightBracket)?;
|
||||
Ok(Some(ArraySize::Constant(constant)))
|
||||
let end_meta = self.expect(parser, TokenValue::RightBracket)?.meta;
|
||||
Ok(Some((ArraySize::Constant(constant), meta.union(&end_meta))))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -33,23 +38,32 @@ impl<'source> ParsingContext<'source> {
|
||||
let token = self.bump(parser)?;
|
||||
let handle = match token.value {
|
||||
TokenValue::Void => None,
|
||||
TokenValue::TypeName(ty) => Some(parser.module.types.fetch_or_append(ty)),
|
||||
TokenValue::TypeName(ty) => Some(
|
||||
parser
|
||||
.module
|
||||
.types
|
||||
.fetch_or_append(ty, token.meta.as_span()),
|
||||
),
|
||||
TokenValue::Struct => {
|
||||
let meta = token.meta;
|
||||
let ty_name = self.expect_ident(parser)?.0;
|
||||
self.expect(parser, TokenValue::LeftBrace)?;
|
||||
let mut members = Vec::new();
|
||||
let span =
|
||||
self.parse_struct_declaration_list(parser, &mut members, StructLayout::Std140)?;
|
||||
self.expect(parser, TokenValue::RightBrace)?;
|
||||
let end_meta = self.expect(parser, TokenValue::RightBrace)?.meta;
|
||||
|
||||
let ty = parser.module.types.append(Type {
|
||||
name: Some(ty_name.clone()),
|
||||
inner: TypeInner::Struct {
|
||||
top_level: false,
|
||||
members,
|
||||
span,
|
||||
let ty = parser.module.types.append(
|
||||
Type {
|
||||
name: Some(ty_name.clone()),
|
||||
inner: TypeInner::Struct {
|
||||
top_level: false,
|
||||
members,
|
||||
span,
|
||||
},
|
||||
},
|
||||
});
|
||||
meta.union(&end_meta).as_span(),
|
||||
);
|
||||
parser.lookup_type.insert(ty_name, ty);
|
||||
Some(ty)
|
||||
}
|
||||
@@ -77,8 +91,11 @@ impl<'source> ParsingContext<'source> {
|
||||
}
|
||||
};
|
||||
|
||||
let size = self.parse_array_specifier(parser)?;
|
||||
Ok((handle.map(|ty| parser.maybe_array(ty, size)), token.meta))
|
||||
let token_meta = token.meta;
|
||||
let array_specifier = self.parse_array_specifier(parser)?;
|
||||
let handle = handle.map(|ty| parser.maybe_array(ty, token_meta, array_specifier));
|
||||
let meta = array_specifier.map_or(token_meta, |(_, meta)| meta.union(&token_meta));
|
||||
Ok((handle, meta))
|
||||
}
|
||||
|
||||
pub fn parse_type_non_void(
|
||||
|
||||
@@ -56,6 +56,10 @@ impl SourceMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_span(&self) -> crate::Span {
|
||||
crate::Span::ByteRange(self.start..self.end)
|
||||
}
|
||||
|
||||
pub(crate) fn none() -> Self {
|
||||
SourceMetadata::default()
|
||||
}
|
||||
|
||||
@@ -257,18 +257,23 @@ impl Parser {
|
||||
pub(crate) fn maybe_array(
|
||||
&mut self,
|
||||
base: Handle<Type>,
|
||||
size: Option<ArraySize>,
|
||||
meta: SourceMetadata,
|
||||
array_specifier: Option<(ArraySize, SourceMetadata)>,
|
||||
) -> Handle<Type> {
|
||||
size.map(|size| {
|
||||
self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Array {
|
||||
base,
|
||||
size,
|
||||
stride: self.module.types[base].inner.span(&self.module.constants),
|
||||
},
|
||||
array_specifier
|
||||
.map(|(size, size_meta)| {
|
||||
self.module.types.fetch_or_append(
|
||||
Type {
|
||||
name: None,
|
||||
inner: TypeInner::Array {
|
||||
base,
|
||||
size,
|
||||
stride: self.module.types[base].inner.span(&self.module.constants),
|
||||
},
|
||||
},
|
||||
meta.union(&size_meta).as_span(),
|
||||
)
|
||||
})
|
||||
})
|
||||
.unwrap_or(base)
|
||||
.unwrap_or(base)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ impl Parser {
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
name: &str,
|
||||
meta: SourceMetadata,
|
||||
) -> Option<VariableReference> {
|
||||
if let Some(local_var) = ctx.lookup_local_var(name) {
|
||||
return Some(local_var);
|
||||
@@ -54,15 +55,18 @@ impl Parser {
|
||||
let ty = self
|
||||
.module
|
||||
.types
|
||||
.fetch_or_append(Type { name: None, inner });
|
||||
.fetch_or_append(Type { name: None, inner }, meta.as_span());
|
||||
|
||||
let handle = self.module.global_variables.append(GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: StorageClass::Private,
|
||||
binding: None,
|
||||
ty,
|
||||
init: None,
|
||||
});
|
||||
let handle = self.module.global_variables.append(
|
||||
GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: StorageClass::Private,
|
||||
binding: None,
|
||||
ty,
|
||||
init: None,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
let idx = self.entry_args.len();
|
||||
self.entry_args.push(EntryArg {
|
||||
@@ -81,7 +85,7 @@ impl Parser {
|
||||
},
|
||||
));
|
||||
|
||||
let expr = ctx.add_expression(Expression::GlobalVariable(handle), body);
|
||||
let expr = ctx.add_expression(Expression::GlobalVariable(handle), meta, body);
|
||||
ctx.lookup_global_var_exps.insert(
|
||||
name.into(),
|
||||
VariableReference {
|
||||
@@ -201,6 +205,7 @@ impl Parser {
|
||||
base: expression,
|
||||
index: index as u32,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
))
|
||||
}
|
||||
@@ -273,6 +278,7 @@ impl Parser {
|
||||
base: expression,
|
||||
index: pattern[0].index(),
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
));
|
||||
}
|
||||
@@ -299,6 +305,7 @@ impl Parser {
|
||||
Expression::Load {
|
||||
pointer: expression,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
);
|
||||
}
|
||||
@@ -309,6 +316,7 @@ impl Parser {
|
||||
vector: expression,
|
||||
pattern,
|
||||
},
|
||||
meta,
|
||||
body,
|
||||
))
|
||||
} else {
|
||||
@@ -483,13 +491,16 @@ impl Parser {
|
||||
})
|
||||
});
|
||||
|
||||
let handle = self.module.global_variables.append(GlobalVariable {
|
||||
name: name.clone(),
|
||||
class: StorageClass::Private,
|
||||
binding: None,
|
||||
ty,
|
||||
init,
|
||||
});
|
||||
let handle = self.module.global_variables.append(
|
||||
GlobalVariable {
|
||||
name: name.clone(),
|
||||
class: StorageClass::Private,
|
||||
binding: None,
|
||||
ty,
|
||||
init,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
let idx = self.entry_args.len();
|
||||
self.entry_args.push(EntryArg {
|
||||
@@ -548,16 +559,19 @@ impl Parser {
|
||||
}
|
||||
};
|
||||
|
||||
let handle = self.module.global_variables.append(GlobalVariable {
|
||||
name: name.clone(),
|
||||
class,
|
||||
binding: binding.map(|binding| ResourceBinding {
|
||||
group: set.unwrap_or(0),
|
||||
binding,
|
||||
}),
|
||||
ty,
|
||||
init,
|
||||
});
|
||||
let handle = self.module.global_variables.append(
|
||||
GlobalVariable {
|
||||
name: name.clone(),
|
||||
class,
|
||||
binding: binding.map(|binding| ResourceBinding {
|
||||
group: set.unwrap_or(0),
|
||||
binding,
|
||||
}),
|
||||
ty,
|
||||
init,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
|
||||
if let Some(name) = name {
|
||||
let lookup = GlobalLookup {
|
||||
@@ -628,12 +642,15 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
let handle = ctx.locals.append(LocalVariable {
|
||||
name: name.clone(),
|
||||
ty,
|
||||
init,
|
||||
});
|
||||
let expr = ctx.add_expression(Expression::LocalVariable(handle), body);
|
||||
let handle = ctx.locals.append(
|
||||
LocalVariable {
|
||||
name: name.clone(),
|
||||
ty,
|
||||
init,
|
||||
},
|
||||
meta.as_span(),
|
||||
);
|
||||
let expr = ctx.add_expression(Expression::LocalVariable(handle), meta, body);
|
||||
|
||||
if let Some(name) = name {
|
||||
ctx.add_local_var(name, expr, mutable);
|
||||
|
||||
@@ -29,10 +29,20 @@ impl Emitter {
|
||||
self.start_len = Some(arena.len());
|
||||
}
|
||||
#[must_use]
|
||||
fn finish(&mut self, arena: &Arena<crate::Expression>) -> Option<crate::Statement> {
|
||||
fn finish(
|
||||
&mut self,
|
||||
arena: &Arena<crate::Expression>,
|
||||
) -> Option<(crate::Statement, crate::span::Span)> {
|
||||
let start_len = self.start_len.take().unwrap();
|
||||
if start_len != arena.len() {
|
||||
Some(crate::Statement::Emit(arena.range_from(start_len)))
|
||||
#[allow(unused_mut)]
|
||||
let mut span = crate::span::Span::Unknown;
|
||||
let range = arena.range_from(start_len);
|
||||
#[cfg(feature = "span")]
|
||||
for handle in range.clone() {
|
||||
span.subsume(arena.get_span(handle))
|
||||
}
|
||||
Some((crate::Statement::Emit(range), span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -527,10 +527,13 @@ impl FlowGraph {
|
||||
let variable = &lookup_expression[&variable_id];
|
||||
let parent_node = &mut self.flow[self.block_to_node[&parent_id]];
|
||||
|
||||
parent_node.block.push(crate::Statement::Store {
|
||||
pointer: phi.pointer,
|
||||
value: variable.handle,
|
||||
});
|
||||
parent_node.block.push(
|
||||
crate::Statement::Store {
|
||||
pointer: phi.pointer,
|
||||
value: variable.handle,
|
||||
},
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
}
|
||||
}
|
||||
self.flow[node_index].phis = phis;
|
||||
@@ -548,7 +551,7 @@ impl FlowGraph {
|
||||
stop_nodes: std::collections::HashSet<BlockNodeIndex>,
|
||||
) -> Result<crate::Block, Error> {
|
||||
if stop_nodes.contains(&node_index) {
|
||||
return Ok(vec![]);
|
||||
return Ok(crate::Block::new());
|
||||
}
|
||||
|
||||
if self.flow[node_index].visited {
|
||||
@@ -647,21 +650,25 @@ impl FlowGraph {
|
||||
|| edge == ControlFlowEdgeType::LoopBreak
|
||||
{
|
||||
// Do not add break if already has one as the last statement
|
||||
if let Some(&crate::Statement::Break) = statements.last() {
|
||||
if let Some(&crate::Statement::Break) = statements.as_ref().last() {
|
||||
} else {
|
||||
statements.push(crate::Statement::Break);
|
||||
statements.push(crate::Statement::Break, crate::Span::Unknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.push(crate::Statement::If {
|
||||
condition,
|
||||
accept,
|
||||
reject,
|
||||
});
|
||||
result.push(
|
||||
crate::Statement::If {
|
||||
condition,
|
||||
accept,
|
||||
reject,
|
||||
},
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
|
||||
result.extend(self.convert_to_naga_traverse(merge_node_index, stop_nodes)?);
|
||||
result
|
||||
.extend_block(self.convert_to_naga_traverse(merge_node_index, stop_nodes)?);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@@ -703,16 +710,20 @@ impl FlowGraph {
|
||||
});
|
||||
}
|
||||
|
||||
result.push(crate::Statement::Switch {
|
||||
selector,
|
||||
cases,
|
||||
default: self.convert_to_naga_traverse(
|
||||
self.block_to_node[&default_id],
|
||||
stop_nodes_cases,
|
||||
)?,
|
||||
});
|
||||
result.push(
|
||||
crate::Statement::Switch {
|
||||
selector,
|
||||
cases,
|
||||
default: self.convert_to_naga_traverse(
|
||||
self.block_to_node[&default_id],
|
||||
stop_nodes_cases,
|
||||
)?,
|
||||
},
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
|
||||
result.extend(self.convert_to_naga_traverse(merge_node_index, stop_nodes)?);
|
||||
result
|
||||
.extend_block(self.convert_to_naga_traverse(merge_node_index, stop_nodes)?);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@@ -745,25 +756,31 @@ impl FlowGraph {
|
||||
let true_node_index = self.block_to_node[&true_id];
|
||||
let false_node_index = self.block_to_node[&false_id];
|
||||
|
||||
body.push(crate::Statement::If {
|
||||
condition,
|
||||
accept: if true_node_index == merge_node_index {
|
||||
vec![crate::Statement::Break]
|
||||
} else {
|
||||
self.convert_to_naga_traverse(
|
||||
true_node_index,
|
||||
stop_nodes_merge.clone(),
|
||||
)?
|
||||
body.push(
|
||||
crate::Statement::If {
|
||||
condition,
|
||||
accept: if true_node_index == merge_node_index {
|
||||
crate::Block::from_vec(vec![crate::Statement::Break])
|
||||
} else {
|
||||
self.convert_to_naga_traverse(
|
||||
true_node_index,
|
||||
stop_nodes_merge.clone(),
|
||||
)?
|
||||
},
|
||||
reject: if false_node_index == merge_node_index {
|
||||
crate::Block::from_vec(vec![crate::Statement::Break])
|
||||
} else {
|
||||
self.convert_to_naga_traverse(
|
||||
false_node_index,
|
||||
stop_nodes_merge,
|
||||
)?
|
||||
},
|
||||
},
|
||||
reject: if false_node_index == merge_node_index {
|
||||
vec![crate::Statement::Break]
|
||||
} else {
|
||||
self.convert_to_naga_traverse(false_node_index, stop_nodes_merge)?
|
||||
},
|
||||
});
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
}
|
||||
Terminator::Branch { target_id } => {
|
||||
body.extend(self.convert_to_naga_traverse(
|
||||
body.extend_block(self.convert_to_naga_traverse(
|
||||
self.block_to_node[&target_id],
|
||||
stop_nodes_merge,
|
||||
)?)
|
||||
@@ -771,8 +788,9 @@ impl FlowGraph {
|
||||
_ => return Err(Error::InvalidTerminator),
|
||||
};
|
||||
|
||||
let mut result = vec![crate::Statement::Loop { body, continuing }];
|
||||
result.extend(self.convert_to_naga_traverse(merge_node_index, stop_nodes)?);
|
||||
let mut result =
|
||||
crate::Block::from_vec(vec![crate::Statement::Loop { body, continuing }]);
|
||||
result.extend_block(self.convert_to_naga_traverse(merge_node_index, stop_nodes)?);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@@ -795,27 +813,35 @@ impl FlowGraph {
|
||||
if true_edge == ControlFlowEdgeType::LoopBreak
|
||||
|| true_edge == ControlFlowEdgeType::IfBreak
|
||||
{
|
||||
result.push(crate::Statement::If {
|
||||
condition,
|
||||
accept: if true_edge == ControlFlowEdgeType::LoopBreak {
|
||||
vec![crate::Statement::Break]
|
||||
} else {
|
||||
vec![]
|
||||
result.push(
|
||||
crate::Statement::If {
|
||||
condition,
|
||||
accept: if true_edge == ControlFlowEdgeType::LoopBreak {
|
||||
crate::Block::from_vec(vec![crate::Statement::Break])
|
||||
} else {
|
||||
crate::Block::new()
|
||||
},
|
||||
reject: self
|
||||
.convert_to_naga_traverse(false_node_id, stop_nodes)?,
|
||||
},
|
||||
reject: self.convert_to_naga_traverse(false_node_id, stop_nodes)?,
|
||||
});
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
} else if false_edge == ControlFlowEdgeType::LoopBreak
|
||||
|| false_edge == ControlFlowEdgeType::IfBreak
|
||||
{
|
||||
result.push(crate::Statement::If {
|
||||
condition,
|
||||
accept: self.convert_to_naga_traverse(true_node_id, stop_nodes)?,
|
||||
reject: if false_edge == ControlFlowEdgeType::LoopBreak {
|
||||
vec![crate::Statement::Break]
|
||||
} else {
|
||||
vec![]
|
||||
result.push(
|
||||
crate::Statement::If {
|
||||
condition,
|
||||
accept: self
|
||||
.convert_to_naga_traverse(true_node_id, stop_nodes)?,
|
||||
reject: if false_edge == ControlFlowEdgeType::LoopBreak {
|
||||
crate::Block::from_vec(vec![crate::Statement::Break])
|
||||
} else {
|
||||
crate::Block::new()
|
||||
},
|
||||
},
|
||||
});
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
} else {
|
||||
return Err(Error::InvalidEdgeClassification);
|
||||
}
|
||||
@@ -827,7 +853,7 @@ impl FlowGraph {
|
||||
self.flow[self.flow.find_edge(node_index, target_index).unwrap()];
|
||||
|
||||
if edge == ControlFlowEdgeType::LoopBreak {
|
||||
result.push(crate::Statement::Break);
|
||||
result.push(crate::Statement::Break, crate::Span::Unknown);
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::InvalidTerminator),
|
||||
@@ -839,7 +865,7 @@ impl FlowGraph {
|
||||
}
|
||||
Some(ControlFlowNodeType::Kill) => {
|
||||
let mut result: crate::Block = std::mem::take(&mut self.flow[node_index].block);
|
||||
result.push(crate::Statement::Kill);
|
||||
result.push(crate::Statement::Kill, crate::Span::Unknown);
|
||||
Ok(result)
|
||||
}
|
||||
Some(ControlFlowNodeType::Return) => {
|
||||
@@ -848,13 +874,13 @@ impl FlowGraph {
|
||||
_ => return Err(Error::InvalidTerminator),
|
||||
};
|
||||
let mut result: crate::Block = std::mem::take(&mut self.flow[node_index].block);
|
||||
result.push(crate::Statement::Return { value });
|
||||
result.push(crate::Statement::Return { value }, crate::Span::Unknown);
|
||||
Ok(result)
|
||||
}
|
||||
Some(ControlFlowNodeType::Merge) | None => match self.flow[node_index].terminator {
|
||||
Terminator::Branch { target_id } => {
|
||||
let mut result: crate::Block = std::mem::take(&mut self.flow[node_index].block);
|
||||
result.extend(
|
||||
let mut result = std::mem::take(&mut self.flow[node_index].block);
|
||||
result.extend_block(
|
||||
self.convert_to_naga_traverse(self.block_to_node[&target_id], stop_nodes)?,
|
||||
);
|
||||
Ok(result)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::arena::{Arena, Handle};
|
||||
|
||||
use super::{flow::*, Error, FunctionInfo, Instruction, LookupExpression, LookupHelper as _};
|
||||
use crate::front::Emitter;
|
||||
|
||||
pub type BlockId = u32;
|
||||
|
||||
@@ -56,13 +57,16 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
from: spirv::Word,
|
||||
to: spirv::Word,
|
||||
) -> Handle<crate::Function> {
|
||||
let dummy_handle = self.dummy_functions.append(crate::Function::default());
|
||||
let dummy_handle = self
|
||||
.dummy_functions
|
||||
.append(crate::Function::default(), Default::default());
|
||||
self.deferred_function_calls.push(to);
|
||||
self.function_call_graph.add_edge(from, to, ());
|
||||
dummy_handle
|
||||
}
|
||||
|
||||
pub(super) fn parse_function(&mut self, module: &mut crate::Module) -> Result<(), Error> {
|
||||
let start = self.data_offset;
|
||||
self.lookup_expression.clear();
|
||||
self.lookup_load_override.clear();
|
||||
self.lookup_sampled_image.clear();
|
||||
@@ -90,14 +94,16 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
})
|
||||
},
|
||||
local_variables: Arena::new(),
|
||||
expressions: self.make_expression_storage(),
|
||||
expressions: self
|
||||
.make_expression_storage(&module.global_variables, &module.constants),
|
||||
named_expressions: crate::FastHashMap::default(),
|
||||
body: Vec::new(),
|
||||
body: crate::Block::new(),
|
||||
}
|
||||
};
|
||||
|
||||
// read parameters
|
||||
for i in 0..fun.arguments.capacity() {
|
||||
let start = self.data_offset;
|
||||
match self.next_inst()? {
|
||||
Instruction {
|
||||
op: spirv::Op::FunctionParameter,
|
||||
@@ -105,9 +111,10 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
} => {
|
||||
let type_id = self.next()?;
|
||||
let id = self.next()?;
|
||||
let handle = fun
|
||||
.expressions
|
||||
.append(crate::Expression::FunctionArgument(i as u32));
|
||||
let handle = fun.expressions.append(
|
||||
crate::Expression::FunctionArgument(i as u32),
|
||||
self.span_from(start),
|
||||
);
|
||||
self.lookup_expression
|
||||
.insert(id, LookupExpression { handle, type_id });
|
||||
//Note: we redo the lookup in order to work around `self` borrowing
|
||||
@@ -192,7 +199,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
fun.body = flow_graph.convert_to_naga()?;
|
||||
|
||||
// done
|
||||
let fun_handle = module.functions.append(fun);
|
||||
let fun_handle = module.functions.append(fun, self.span_from_with_op(start));
|
||||
self.lookup_function.insert(fun_id, fun_handle);
|
||||
self.function_info.push(function_info);
|
||||
if let Some(ep) = self.lookup_entry_point.remove(&fun_id) {
|
||||
@@ -204,41 +211,46 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
local_variables: Arena::new(),
|
||||
expressions: Arena::new(),
|
||||
named_expressions: crate::FastHashMap::default(),
|
||||
body: Vec::new(),
|
||||
body: crate::Block::new(),
|
||||
};
|
||||
|
||||
// 1. copy the inputs from arguments to privates
|
||||
for &v_id in ep.variable_ids.iter() {
|
||||
let lvar = self.lookup_variable.lookup(v_id)?;
|
||||
if let super::Variable::Input(ref arg) = lvar.inner {
|
||||
let arg_expr =
|
||||
function
|
||||
.expressions
|
||||
.append(crate::Expression::FunctionArgument(
|
||||
function.arguments.len() as u32,
|
||||
));
|
||||
let span = module.global_variables.get_span(lvar.handle).clone();
|
||||
let arg_expr = function.expressions.append(
|
||||
crate::Expression::FunctionArgument(function.arguments.len() as u32),
|
||||
span.clone(),
|
||||
);
|
||||
let load_expr = if arg.ty == module.global_variables[lvar.handle].ty {
|
||||
arg_expr
|
||||
} else {
|
||||
// The only case where the type is different is if we need to treat
|
||||
// unsigned integer as signed.
|
||||
let old_len = function.expressions.len();
|
||||
let handle = function.expressions.append(crate::Expression::As {
|
||||
expr: arg_expr,
|
||||
kind: crate::ScalarKind::Sint,
|
||||
convert: Some(4),
|
||||
});
|
||||
function.body.push(crate::Statement::Emit(
|
||||
function.expressions.range_from(old_len),
|
||||
));
|
||||
let mut emitter = Emitter::default();
|
||||
emitter.start(&function.expressions);
|
||||
let handle = function.expressions.append(
|
||||
crate::Expression::As {
|
||||
expr: arg_expr,
|
||||
kind: crate::ScalarKind::Sint,
|
||||
convert: Some(4),
|
||||
},
|
||||
span.clone(),
|
||||
);
|
||||
function.body.extend(emitter.finish(&function.expressions));
|
||||
handle
|
||||
};
|
||||
function.body.push(crate::Statement::Store {
|
||||
pointer: function
|
||||
.expressions
|
||||
.append(crate::Expression::GlobalVariable(lvar.handle)),
|
||||
value: load_expr,
|
||||
});
|
||||
function.body.push(
|
||||
crate::Statement::Store {
|
||||
pointer: function.expressions.append(
|
||||
crate::Expression::GlobalVariable(lvar.handle),
|
||||
span.clone(),
|
||||
),
|
||||
value: load_expr,
|
||||
},
|
||||
span,
|
||||
);
|
||||
|
||||
let mut arg = arg.clone();
|
||||
if ep.stage == crate::ShaderStage::Fragment {
|
||||
@@ -257,11 +269,14 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
// 2. call the wrapped function
|
||||
let fake_id = !(module.entry_points.len() as u32); // doesn't matter, as long as it's not a collision
|
||||
let dummy_handle = self.add_call(fake_id, fun_id);
|
||||
function.body.push(crate::Statement::Call {
|
||||
function: dummy_handle,
|
||||
arguments: Vec::new(),
|
||||
result: None,
|
||||
});
|
||||
function.body.push(
|
||||
crate::Statement::Call {
|
||||
function: dummy_handle,
|
||||
arguments: Vec::new(),
|
||||
result: None,
|
||||
},
|
||||
crate::Span::Unknown,
|
||||
);
|
||||
|
||||
// 3. copy the outputs from privates to the result
|
||||
let mut members = Vec::new();
|
||||
@@ -269,9 +284,10 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
for &v_id in ep.variable_ids.iter() {
|
||||
let lvar = self.lookup_variable.lookup(v_id)?;
|
||||
if let super::Variable::Output(ref result) = lvar.inner {
|
||||
let span = module.global_variables.get_span(lvar.handle).clone();
|
||||
let expr_handle = function
|
||||
.expressions
|
||||
.append(crate::Expression::GlobalVariable(lvar.handle));
|
||||
.append(crate::Expression::GlobalVariable(lvar.handle), span.clone());
|
||||
match module.types[result.ty].inner {
|
||||
crate::TypeInner::Struct {
|
||||
members: ref sub_members,
|
||||
@@ -288,6 +304,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
base: expr_handle,
|
||||
index: index as u32,
|
||||
},
|
||||
span.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -311,72 +328,94 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
Some(crate::Binding::BuiltIn(crate::BuiltIn::Position))
|
||||
if self.options.adjust_coordinate_space =>
|
||||
{
|
||||
let old_len = function.expressions.len();
|
||||
let mut emitter = Emitter::default();
|
||||
emitter.start(&function.expressions);
|
||||
let global_expr = components[member_index];
|
||||
let access_expr =
|
||||
function.expressions.append(crate::Expression::AccessIndex {
|
||||
let span = function.expressions.get_span(global_expr).clone();
|
||||
let access_expr = function.expressions.append(
|
||||
crate::Expression::AccessIndex {
|
||||
base: global_expr,
|
||||
index: 1,
|
||||
});
|
||||
let load_expr = function.expressions.append(crate::Expression::Load {
|
||||
pointer: access_expr,
|
||||
});
|
||||
let neg_expr = function.expressions.append(crate::Expression::Unary {
|
||||
op: crate::UnaryOperator::Negate,
|
||||
expr: load_expr,
|
||||
});
|
||||
function.body.push(crate::Statement::Emit(
|
||||
function.expressions.range_from(old_len),
|
||||
));
|
||||
function.body.push(crate::Statement::Store {
|
||||
pointer: access_expr,
|
||||
value: neg_expr,
|
||||
});
|
||||
},
|
||||
span.clone(),
|
||||
);
|
||||
let load_expr = function.expressions.append(
|
||||
crate::Expression::Load {
|
||||
pointer: access_expr,
|
||||
},
|
||||
span.clone(),
|
||||
);
|
||||
let neg_expr = function.expressions.append(
|
||||
crate::Expression::Unary {
|
||||
op: crate::UnaryOperator::Negate,
|
||||
expr: load_expr,
|
||||
},
|
||||
span.clone(),
|
||||
);
|
||||
function.body.extend(emitter.finish(&function.expressions));
|
||||
function.body.push(
|
||||
crate::Statement::Store {
|
||||
pointer: access_expr,
|
||||
value: neg_expr,
|
||||
},
|
||||
span,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let old_len = function.expressions.len();
|
||||
let mut emitter = Emitter::default();
|
||||
emitter.start(&function.expressions);
|
||||
for component in components.iter_mut() {
|
||||
let load_expr = crate::Expression::Load {
|
||||
pointer: *component,
|
||||
};
|
||||
*component = function.expressions.append(load_expr);
|
||||
let span = function.expressions.get_span(*component).clone();
|
||||
*component = function.expressions.append(load_expr, span);
|
||||
}
|
||||
|
||||
match &members[..] {
|
||||
[] => {}
|
||||
[member] => {
|
||||
function.body.push(crate::Statement::Emit(
|
||||
function.expressions.range_from(old_len),
|
||||
));
|
||||
function.body.push(crate::Statement::Return {
|
||||
value: components.first().cloned(),
|
||||
});
|
||||
function.body.extend(emitter.finish(&function.expressions));
|
||||
let span = function.expressions.get_span(components[0]).clone();
|
||||
function.body.push(
|
||||
crate::Statement::Return {
|
||||
value: components.first().cloned(),
|
||||
},
|
||||
span,
|
||||
);
|
||||
function.result = Some(crate::FunctionResult {
|
||||
ty: member.ty,
|
||||
binding: member.binding.clone(),
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
let ty = module.types.append(crate::Type {
|
||||
name: None,
|
||||
inner: crate::TypeInner::Struct {
|
||||
top_level: false,
|
||||
members,
|
||||
span: 0xFFFF, // shouldn't matter
|
||||
let span = crate::Span::total_span(
|
||||
components.iter().map(|h| function.expressions.get_span(*h)),
|
||||
);
|
||||
let ty = module.types.append(
|
||||
crate::Type {
|
||||
name: None,
|
||||
inner: crate::TypeInner::Struct {
|
||||
top_level: false,
|
||||
members,
|
||||
span: 0xFFFF, // shouldn't matter
|
||||
},
|
||||
},
|
||||
});
|
||||
span.clone(),
|
||||
);
|
||||
let result_expr = function
|
||||
.expressions
|
||||
.append(crate::Expression::Compose { ty, components });
|
||||
function.body.push(crate::Statement::Emit(
|
||||
function.expressions.range_from(old_len),
|
||||
));
|
||||
function.body.push(crate::Statement::Return {
|
||||
value: Some(result_expr),
|
||||
});
|
||||
.append(crate::Expression::Compose { ty, components }, span.clone());
|
||||
function.body.extend(emitter.finish(&function.expressions));
|
||||
function.body.push(
|
||||
crate::Statement::Return {
|
||||
value: Some(result_expr),
|
||||
},
|
||||
span,
|
||||
);
|
||||
function.result = Some(crate::FunctionResult { ty, binding: None });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,59 +89,85 @@ fn extract_image_coordinates(
|
||||
index: required_size.map_or(1, |size| size as u32),
|
||||
};
|
||||
|
||||
let base_span = expressions.get_span(base).clone();
|
||||
|
||||
match extra_coordinate {
|
||||
ExtraCoordinate::ArrayLayer => {
|
||||
let extracted = match required_size {
|
||||
None => expressions.append(crate::Expression::AccessIndex { base, index: 0 }),
|
||||
None => expressions.append(
|
||||
crate::Expression::AccessIndex { base, index: 0 },
|
||||
base_span.clone(),
|
||||
),
|
||||
Some(size) => {
|
||||
let mut components = Vec::with_capacity(size as usize);
|
||||
for index in 0..size as u32 {
|
||||
let comp =
|
||||
expressions.append(crate::Expression::AccessIndex { base, index });
|
||||
let comp = expressions.append(
|
||||
crate::Expression::AccessIndex { base, index },
|
||||
base_span.clone(),
|
||||
);
|
||||
components.push(comp);
|
||||
}
|
||||
expressions.append(crate::Expression::Compose {
|
||||
ty: required_ty.unwrap(),
|
||||
components,
|
||||
})
|
||||
expressions.append(
|
||||
crate::Expression::Compose {
|
||||
ty: required_ty.unwrap(),
|
||||
components,
|
||||
},
|
||||
base_span.clone(),
|
||||
)
|
||||
}
|
||||
};
|
||||
let array_index_f32 = expressions.append(extra_expr);
|
||||
let array_index = expressions.append(crate::Expression::As {
|
||||
kind: crate::ScalarKind::Sint,
|
||||
expr: array_index_f32,
|
||||
convert: Some(4),
|
||||
});
|
||||
let array_index_f32 = expressions.append(extra_expr, base_span.clone());
|
||||
let array_index = expressions.append(
|
||||
crate::Expression::As {
|
||||
kind: crate::ScalarKind::Sint,
|
||||
expr: array_index_f32,
|
||||
convert: Some(4),
|
||||
},
|
||||
base_span,
|
||||
);
|
||||
(extracted, Some(array_index))
|
||||
}
|
||||
ExtraCoordinate::Projection => {
|
||||
let projection = expressions.append(extra_expr);
|
||||
let projection = expressions.append(extra_expr, base_span.clone());
|
||||
let divided = match required_size {
|
||||
None => {
|
||||
let temp =
|
||||
expressions.append(crate::Expression::AccessIndex { base, index: 0 });
|
||||
expressions.append(crate::Expression::Binary {
|
||||
op: crate::BinaryOperator::Divide,
|
||||
left: temp,
|
||||
right: projection,
|
||||
})
|
||||
let temp = expressions.append(
|
||||
crate::Expression::AccessIndex { base, index: 0 },
|
||||
base_span.clone(),
|
||||
);
|
||||
expressions.append(
|
||||
crate::Expression::Binary {
|
||||
op: crate::BinaryOperator::Divide,
|
||||
left: temp,
|
||||
right: projection,
|
||||
},
|
||||
base_span,
|
||||
)
|
||||
}
|
||||
Some(size) => {
|
||||
let mut components = Vec::with_capacity(size as usize);
|
||||
for index in 0..size as u32 {
|
||||
let temp =
|
||||
expressions.append(crate::Expression::AccessIndex { base, index });
|
||||
let comp = expressions.append(crate::Expression::Binary {
|
||||
op: crate::BinaryOperator::Divide,
|
||||
left: temp,
|
||||
right: projection,
|
||||
});
|
||||
let temp = expressions.append(
|
||||
crate::Expression::AccessIndex { base, index },
|
||||
base_span.clone(),
|
||||
);
|
||||
let comp = expressions.append(
|
||||
crate::Expression::Binary {
|
||||
op: crate::BinaryOperator::Divide,
|
||||
left: temp,
|
||||
right: projection,
|
||||
},
|
||||
base_span.clone(),
|
||||
);
|
||||
components.push(comp);
|
||||
}
|
||||
expressions.append(crate::Expression::Compose {
|
||||
ty: required_ty.unwrap(),
|
||||
components,
|
||||
})
|
||||
expressions.append(
|
||||
crate::Expression::Compose {
|
||||
ty: required_ty.unwrap(),
|
||||
components,
|
||||
},
|
||||
base_span,
|
||||
)
|
||||
}
|
||||
};
|
||||
(divided, None)
|
||||
@@ -157,7 +183,7 @@ fn extract_image_coordinates(
|
||||
pattern: [Sc::X, Sc::Y, Sc::Z, Sc::W],
|
||||
},
|
||||
};
|
||||
(expressions.append(cut_expr), None)
|
||||
(expressions.append(cut_expr, base_span), None)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,6 +202,7 @@ pub(super) fn patch_comparison_type(
|
||||
|
||||
log::debug!("Flipping comparison for {:?}", var);
|
||||
let original_ty = &arena[var.ty];
|
||||
let original_ty_span = arena.get_span(var.ty).clone();
|
||||
let ty_inner = match original_ty.inner {
|
||||
crate::TypeInner::Image {
|
||||
class: crate::ImageClass::Sampled { multi, .. },
|
||||
@@ -191,10 +218,13 @@ pub(super) fn patch_comparison_type(
|
||||
};
|
||||
|
||||
let name = original_ty.name.clone();
|
||||
var.ty = arena.append(crate::Type {
|
||||
name,
|
||||
inner: ty_inner,
|
||||
});
|
||||
var.ty = arena.append(
|
||||
crate::Type {
|
||||
name,
|
||||
inner: ty_inner,
|
||||
},
|
||||
original_ty_span,
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
@@ -295,6 +325,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
arguments: &[FunctionArgument],
|
||||
expressions: &mut Arena<crate::Expression>,
|
||||
) -> Result<(), Error> {
|
||||
let start = self.data_offset;
|
||||
let result_type_id = self.next()?;
|
||||
let result_id = self.next()?;
|
||||
let image_id = self.next()?;
|
||||
@@ -368,7 +399,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
self.lookup_expression.insert(
|
||||
result_id,
|
||||
LookupExpression {
|
||||
handle: expressions.append(expr),
|
||||
handle: expressions.append(expr, self.span_from_with_op(start)),
|
||||
type_id: result_type_id,
|
||||
},
|
||||
);
|
||||
@@ -386,6 +417,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
expressions: &mut Arena<crate::Expression>,
|
||||
function_info: &mut FunctionInfo,
|
||||
) -> Result<(), Error> {
|
||||
let start = self.data_offset;
|
||||
let result_type_id = self.next()?;
|
||||
let result_id = self.next()?;
|
||||
let sampled_image_id = self.next()?;
|
||||
@@ -522,7 +554,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
self.lookup_expression.insert(
|
||||
result_id,
|
||||
LookupExpression {
|
||||
handle: expressions.append(expr),
|
||||
handle: expressions.append(expr, self.span_from_with_op(start)),
|
||||
type_id: result_type_id,
|
||||
},
|
||||
);
|
||||
@@ -534,6 +566,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
at_level: bool,
|
||||
expressions: &mut Arena<crate::Expression>,
|
||||
) -> Result<(), Error> {
|
||||
let start = self.data_offset;
|
||||
let result_type_id = self.next()?;
|
||||
let result_id = self.next()?;
|
||||
let image_id = self.next()?;
|
||||
@@ -555,7 +588,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
self.lookup_expression.insert(
|
||||
result_id,
|
||||
LookupExpression {
|
||||
handle: expressions.append(expr),
|
||||
handle: expressions.append(expr, self.span_from_with_op(start)),
|
||||
type_id: result_type_id,
|
||||
},
|
||||
);
|
||||
@@ -567,6 +600,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
query: crate::ImageQuery,
|
||||
expressions: &mut Arena<crate::Expression>,
|
||||
) -> Result<(), Error> {
|
||||
let start = self.data_offset;
|
||||
let result_type_id = self.next()?;
|
||||
let result_id = self.next()?;
|
||||
let image_id = self.next()?;
|
||||
@@ -580,7 +614,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
self.lookup_expression.insert(
|
||||
result_id,
|
||||
LookupExpression {
|
||||
handle: expressions.append(expr),
|
||||
handle: expressions.append(expr, self.span_from_with_op(start)),
|
||||
type_id: result_type_id,
|
||||
},
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,19 +15,23 @@ fn make_scalar_inner(kind: crate::ScalarKind, width: crate::Bytes) -> crate::Con
|
||||
|
||||
pub fn generate_null_constant(
|
||||
ty: Handle<crate::Type>,
|
||||
type_arena: &mut Arena<crate::Type>,
|
||||
type_arena: &Arena<crate::Type>,
|
||||
constant_arena: &mut Arena<crate::Constant>,
|
||||
span: crate::Span,
|
||||
) -> Result<crate::ConstantInner, Error> {
|
||||
let inner = match type_arena[ty].inner {
|
||||
crate::TypeInner::Scalar { kind, width } => make_scalar_inner(kind, width),
|
||||
crate::TypeInner::Vector { size, kind, width } => {
|
||||
let mut components = Vec::with_capacity(size as usize);
|
||||
for _ in 0..size as usize {
|
||||
components.push(constant_arena.fetch_or_append(crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: make_scalar_inner(kind, width),
|
||||
}));
|
||||
components.push(constant_arena.fetch_or_append(
|
||||
crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: make_scalar_inner(kind, width),
|
||||
},
|
||||
span.clone(),
|
||||
));
|
||||
}
|
||||
crate::ConstantInner::Composite { ty, components }
|
||||
}
|
||||
@@ -36,20 +40,27 @@ pub fn generate_null_constant(
|
||||
rows,
|
||||
width,
|
||||
} => {
|
||||
let vector_ty = type_arena.fetch_or_append(crate::Type {
|
||||
name: None,
|
||||
inner: crate::TypeInner::Vector {
|
||||
kind: crate::ScalarKind::Float,
|
||||
size: rows,
|
||||
width,
|
||||
// If we successfully declared a matrix type, we have declared a vector type for it too.
|
||||
let vector_ty = type_arena
|
||||
.fetch_if(|t| {
|
||||
t.inner
|
||||
== crate::TypeInner::Vector {
|
||||
kind: crate::ScalarKind::Float,
|
||||
size: rows,
|
||||
width,
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
let vector_inner =
|
||||
generate_null_constant(vector_ty, type_arena, constant_arena, span.clone())?;
|
||||
let vector_handle = constant_arena.fetch_or_append(
|
||||
crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: vector_inner,
|
||||
},
|
||||
});
|
||||
let vector_inner = generate_null_constant(vector_ty, type_arena, constant_arena)?;
|
||||
let vector_handle = constant_arena.fetch_or_append(crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: vector_inner,
|
||||
});
|
||||
span,
|
||||
);
|
||||
crate::ConstantInner::Composite {
|
||||
ty,
|
||||
components: vec![vector_handle; columns as usize],
|
||||
@@ -60,12 +71,16 @@ pub fn generate_null_constant(
|
||||
// copy out the types to avoid borrowing `members`
|
||||
let member_tys = members.iter().map(|member| member.ty).collect::<Vec<_>>();
|
||||
for member_ty in member_tys {
|
||||
let inner = generate_null_constant(member_ty, type_arena, constant_arena)?;
|
||||
components.push(constant_arena.fetch_or_append(crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
}));
|
||||
let inner =
|
||||
generate_null_constant(member_ty, type_arena, constant_arena, span.clone())?;
|
||||
components.push(constant_arena.fetch_or_append(
|
||||
crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
},
|
||||
span.clone(),
|
||||
));
|
||||
}
|
||||
crate::ConstantInner::Composite { ty, components }
|
||||
}
|
||||
@@ -77,12 +92,15 @@ pub fn generate_null_constant(
|
||||
let size = constant_arena[handle]
|
||||
.to_array_length()
|
||||
.ok_or(Error::InvalidArraySize(handle))?;
|
||||
let inner = generate_null_constant(base, type_arena, constant_arena)?;
|
||||
let value = constant_arena.fetch_or_append(crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
});
|
||||
let inner = generate_null_constant(base, type_arena, constant_arena, span.clone())?;
|
||||
let value = constant_arena.fetch_or_append(
|
||||
crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
},
|
||||
span,
|
||||
);
|
||||
crate::ConstantInner::Composite {
|
||||
ty,
|
||||
components: vec![value; size as usize],
|
||||
@@ -100,27 +118,34 @@ pub fn generate_null_constant(
|
||||
pub fn generate_default_built_in(
|
||||
built_in: Option<crate::BuiltIn>,
|
||||
ty: Handle<crate::Type>,
|
||||
type_arena: &mut Arena<crate::Type>,
|
||||
type_arena: &Arena<crate::Type>,
|
||||
constant_arena: &mut Arena<crate::Constant>,
|
||||
span: crate::Span,
|
||||
) -> Result<Handle<crate::Constant>, Error> {
|
||||
let inner = match built_in {
|
||||
Some(crate::BuiltIn::Position) => {
|
||||
let zero = constant_arena.fetch_or_append(crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
value: crate::ScalarValue::Float(0.0),
|
||||
width: 4,
|
||||
let zero = constant_arena.fetch_or_append(
|
||||
crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
value: crate::ScalarValue::Float(0.0),
|
||||
width: 4,
|
||||
},
|
||||
},
|
||||
});
|
||||
let one = constant_arena.fetch_or_append(crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
value: crate::ScalarValue::Float(1.0),
|
||||
width: 4,
|
||||
span.clone(),
|
||||
);
|
||||
let one = constant_arena.fetch_or_append(
|
||||
crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
value: crate::ScalarValue::Float(1.0),
|
||||
width: 4,
|
||||
},
|
||||
},
|
||||
});
|
||||
span.clone(),
|
||||
);
|
||||
crate::ConstantInner::Composite {
|
||||
ty,
|
||||
components: vec![zero, zero, zero, one],
|
||||
@@ -139,11 +164,14 @@ pub fn generate_default_built_in(
|
||||
width: 4,
|
||||
},
|
||||
//Note: `crate::BuiltIn::ClipDistance` is intentionally left for the default path
|
||||
_ => generate_null_constant(ty, type_arena, constant_arena)?,
|
||||
_ => generate_null_constant(ty, type_arena, constant_arena, span.clone())?,
|
||||
};
|
||||
Ok(constant_arena.fetch_or_append(crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
}))
|
||||
Ok(constant_arena.fetch_or_append(
|
||||
crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
},
|
||||
span,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -201,6 +201,10 @@ impl<'a> Lexer<'a> {
|
||||
self.source.len() - self.input.len()
|
||||
}
|
||||
|
||||
pub(super) fn span_from(&self, offset: usize) -> Span {
|
||||
offset..self.current_byte_offset()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(super) fn next(&mut self) -> TokenSpan<'a> {
|
||||
let mut start_byte_offset = self.current_byte_offset();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
10
src/lib.rs
10
src/lib.rs
@@ -29,8 +29,8 @@ A Naga backend can generate code to evaluate an `Expression` however and
|
||||
whenever it pleases, as long as it is certain to observe the side effects of all
|
||||
previously executed `Statement`s.
|
||||
|
||||
Many `Statement` variants use the [`Block`] type, which is simply `Vec<Statement>`,
|
||||
representing a series of statements executed in order. The body of an
|
||||
Many `Statement` variants use the [`Block`] type, which is `Vec<Statement>`,
|
||||
with optional span info, representing a series of statements executed in order. The body of an
|
||||
`EntryPoint`s or `Function` is a `Block`, and `Statement` has a
|
||||
[`Block`][Statement::Block] variant.
|
||||
|
||||
@@ -151,8 +151,10 @@ tree.
|
||||
|
||||
mod arena;
|
||||
pub mod back;
|
||||
mod block;
|
||||
pub mod front;
|
||||
pub mod proc;
|
||||
mod span;
|
||||
pub mod valid;
|
||||
|
||||
pub use crate::arena::{Arena, Handle, Range};
|
||||
@@ -162,6 +164,7 @@ use std::{
|
||||
hash::BuildHasherDefault,
|
||||
};
|
||||
|
||||
pub use crate::span::Span;
|
||||
#[cfg(feature = "deserialize")]
|
||||
use serde::Deserialize;
|
||||
#[cfg(feature = "serialize")]
|
||||
@@ -1175,8 +1178,7 @@ pub enum Expression {
|
||||
ArrayLength(Handle<Expression>),
|
||||
}
|
||||
|
||||
/// A code block is just a vector of statements.
|
||||
pub type Block = Vec<Statement>;
|
||||
pub use block::Block;
|
||||
|
||||
/// A case for a switch statement.
|
||||
// Clone is used only for error reporting and is not intended for end users
|
||||
|
||||
@@ -41,6 +41,6 @@ pub fn ensure_block_returns(block: &mut crate::Block) {
|
||||
| Some(&mut S::Call { .. })
|
||||
| Some(&mut S::Atomic { .. })
|
||||
| Some(&mut S::Barrier(_))
|
||||
| None => block.push(S::Return { value: None }),
|
||||
| None => block.push(S::Return { value: None }, Default::default()),
|
||||
}
|
||||
}
|
||||
|
||||
38
src/span.rs
Normal file
38
src/span.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use std::ops::Range;
|
||||
|
||||
// A source code span, used for error reporting.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Span {
|
||||
// Span is unknown - no source information.
|
||||
Unknown,
|
||||
// Byte range.
|
||||
ByteRange(Range<usize>),
|
||||
}
|
||||
|
||||
impl Default for Span {
|
||||
fn default() -> Self {
|
||||
Self::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl Span {
|
||||
pub fn subsume(&mut self, other: &Self) {
|
||||
match *self {
|
||||
Self::Unknown => self.clone_from(other),
|
||||
Self::ByteRange(ref mut self_range) => {
|
||||
if let Self::ByteRange(ref other_range) = *other {
|
||||
self_range.start = self_range.start.min(other_range.start);
|
||||
self_range.end = self_range.end.max(other_range.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn total_span<'a, T: Iterator<Item = &'a Self>>(from: T) -> Self {
|
||||
let mut span: Self = Default::default();
|
||||
for other in from {
|
||||
span.subsume(other);
|
||||
}
|
||||
span
|
||||
}
|
||||
}
|
||||
@@ -857,59 +857,79 @@ fn uniform_control_flow() {
|
||||
use crate::{Expression as E, Statement as S};
|
||||
|
||||
let mut constant_arena = Arena::new();
|
||||
let constant = constant_arena.append(crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: crate::ScalarValue::Uint(0),
|
||||
let constant = constant_arena.append(
|
||||
crate::Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Scalar {
|
||||
width: 4,
|
||||
value: crate::ScalarValue::Uint(0),
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
let mut type_arena = Arena::new();
|
||||
let ty = type_arena.append(crate::Type {
|
||||
name: None,
|
||||
inner: crate::TypeInner::Vector {
|
||||
size: crate::VectorSize::Bi,
|
||||
kind: crate::ScalarKind::Float,
|
||||
width: 4,
|
||||
let ty = type_arena.append(
|
||||
crate::Type {
|
||||
name: None,
|
||||
inner: crate::TypeInner::Vector {
|
||||
size: crate::VectorSize::Bi,
|
||||
kind: crate::ScalarKind::Float,
|
||||
width: 4,
|
||||
},
|
||||
},
|
||||
});
|
||||
Default::default(),
|
||||
);
|
||||
let mut global_var_arena = Arena::new();
|
||||
let non_uniform_global = global_var_arena.append(crate::GlobalVariable {
|
||||
name: None,
|
||||
init: None,
|
||||
ty,
|
||||
class: crate::StorageClass::Handle,
|
||||
binding: None,
|
||||
});
|
||||
let uniform_global = global_var_arena.append(crate::GlobalVariable {
|
||||
name: None,
|
||||
init: None,
|
||||
ty,
|
||||
binding: None,
|
||||
class: crate::StorageClass::Uniform,
|
||||
});
|
||||
let non_uniform_global = global_var_arena.append(
|
||||
crate::GlobalVariable {
|
||||
name: None,
|
||||
init: None,
|
||||
ty,
|
||||
class: crate::StorageClass::Handle,
|
||||
binding: None,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
let uniform_global = global_var_arena.append(
|
||||
crate::GlobalVariable {
|
||||
name: None,
|
||||
init: None,
|
||||
ty,
|
||||
binding: None,
|
||||
class: crate::StorageClass::Uniform,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let mut expressions = Arena::new();
|
||||
// checks the uniform control flow
|
||||
let constant_expr = expressions.append(E::Constant(constant));
|
||||
let constant_expr = expressions.append(E::Constant(constant), Default::default());
|
||||
// checks the non-uniform control flow
|
||||
let derivative_expr = expressions.append(E::Derivative {
|
||||
axis: crate::DerivativeAxis::X,
|
||||
expr: constant_expr,
|
||||
});
|
||||
let derivative_expr = expressions.append(
|
||||
E::Derivative {
|
||||
axis: crate::DerivativeAxis::X,
|
||||
expr: constant_expr,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
let emit_range_constant_derivative = expressions.range_from(0);
|
||||
let non_uniform_global_expr = expressions.append(E::GlobalVariable(non_uniform_global));
|
||||
let uniform_global_expr = expressions.append(E::GlobalVariable(uniform_global));
|
||||
let non_uniform_global_expr =
|
||||
expressions.append(E::GlobalVariable(non_uniform_global), Default::default());
|
||||
let uniform_global_expr =
|
||||
expressions.append(E::GlobalVariable(uniform_global), Default::default());
|
||||
let emit_range_globals = expressions.range_from(2);
|
||||
|
||||
// checks the QUERY flag
|
||||
let query_expr = expressions.append(E::ArrayLength(uniform_global_expr));
|
||||
let query_expr = expressions.append(E::ArrayLength(uniform_global_expr), Default::default());
|
||||
// checks the transitive WRITE flag
|
||||
let access_expr = expressions.append(E::AccessIndex {
|
||||
base: non_uniform_global_expr,
|
||||
index: 1,
|
||||
});
|
||||
let access_expr = expressions.append(
|
||||
E::AccessIndex {
|
||||
base: non_uniform_global_expr,
|
||||
index: 1,
|
||||
},
|
||||
Default::default(),
|
||||
);
|
||||
let emit_range_query_access_globals = expressions.range_from(2);
|
||||
|
||||
let mut info = FunctionInfo {
|
||||
@@ -944,14 +964,15 @@ fn uniform_control_flow() {
|
||||
let stmt_emit1 = S::Emit(emit_range_globals.clone());
|
||||
let stmt_if_uniform = S::If {
|
||||
condition: uniform_global_expr,
|
||||
accept: Vec::new(),
|
||||
accept: crate::Block::new(),
|
||||
reject: vec![
|
||||
S::Emit(emit_range_constant_derivative.clone()),
|
||||
S::Store {
|
||||
pointer: constant_expr,
|
||||
value: derivative_expr,
|
||||
},
|
||||
],
|
||||
]
|
||||
.into(),
|
||||
};
|
||||
assert_eq!(
|
||||
info.process_block(&[stmt_emit1, stmt_if_uniform], &[], None, &expressions),
|
||||
@@ -975,8 +996,9 @@ fn uniform_control_flow() {
|
||||
pointer: constant_expr,
|
||||
value: derivative_expr,
|
||||
},
|
||||
],
|
||||
reject: Vec::new(),
|
||||
]
|
||||
.into(),
|
||||
reject: crate::Block::new(),
|
||||
};
|
||||
assert_eq!(
|
||||
info.process_block(&[stmt_emit2, stmt_if_non_uniform], &[], None, &expressions),
|
||||
|
||||
Reference in New Issue
Block a user