From c22fa546421c0f6aeffbe34355a43f9e7889287d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Capucho?= Date: Thu, 20 May 2021 21:14:49 +0100 Subject: [PATCH] [glsl-in] Expression emitting --- src/front/glsl/ast.rs | 176 +++++++++++++----------- src/front/glsl/functions.rs | 260 +++++++++++++++++++++--------------- src/front/glsl/parser.rs | 190 ++++++++++++++++---------- src/front/glsl/variables.rs | 246 ++++++++++++++++------------------ src/front/mod.rs | 4 +- 5 files changed, 482 insertions(+), 394 deletions(-) diff --git a/src/front/glsl/ast.rs b/src/front/glsl/ast.rs index f54abf72e8..0de03552b4 100644 --- a/src/front/glsl/ast.rs +++ b/src/front/glsl/ast.rs @@ -1,12 +1,12 @@ use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind, SourceMetadata}; use crate::{ - proc::ResolveContext, Arena, BinaryOperator, Binding, Block, Constant, Expression, FastHashMap, - Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable, Module, - RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass, Type, - TypeInner, UnaryOperator, + front::Emitter, proc::ResolveContext, Arena, BinaryOperator, Binding, Block, Constant, + Expression, FastHashMap, Function, FunctionArgument, GlobalVariable, Handle, Interpolation, + LocalVariable, Module, RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, + StorageClass, Type, TypeInner, UnaryOperator, }; -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub enum GlobalLookup { Variable(Handle), BlockSelect(Handle, u32), @@ -34,8 +34,9 @@ pub struct Program<'a> { pub lookup_function: FastHashMap, pub lookup_type: FastHashMap>, - pub lookup_global_variables: FastHashMap, - pub lookup_constants: FastHashMap>, + + pub global_variables: Vec<(String, GlobalLookup)>, + pub constants: Vec<(String, Handle)>, pub entry_args: Vec<(Binding, bool, Handle)>, pub entries: Vec<(String, ShaderStage, Handle)>, @@ -52,8 +53,8 @@ impl<'a> Program<'a> { lookup_function: FastHashMap::default(), lookup_type: FastHashMap::default(), - lookup_global_variables: FastHashMap::default(), - lookup_constants: FastHashMap::default(), + global_variables: Vec::new(), + constants: Vec::new(), entry_args: Vec::new(), entries: Vec::new(), @@ -120,13 +121,13 @@ impl<'a> Program<'a> { pub fn solve_constant( &mut self, - expressions: &Arena, + ctx: &Context, root: Handle, meta: SourceMetadata, ) -> Result, ErrorKind> { let mut solver = ConstantSolver { types: &self.module.types, - expressions, + expressions: ctx.expressions, constants: &mut self.module.constants, }; @@ -141,38 +142,98 @@ pub enum Profile { #[derive(Debug)] pub struct Context<'function> { - pub expressions: &'function mut Arena, + expressions: &'function mut Arena, pub locals: &'function mut Arena, pub arguments: &'function mut Vec, //TODO: Find less allocation heavy representation pub scopes: Vec>, pub lookup_global_var_exps: FastHashMap, - pub lookup_constant_exps: FastHashMap, - pub typifier: Typifier, pub samplers: FastHashMap, Handle>, + pub typifier: Typifier, pub hir_exprs: Arena, + emitter: Emitter, } impl<'function> Context<'function> { pub fn new( + program: &mut Program, + body: &mut Block, expressions: &'function mut Arena, locals: &'function mut Arena, arguments: &'function mut Vec, ) -> Self { - Context { + let mut this = Context { expressions, locals, arguments, scopes: vec![FastHashMap::default()], - lookup_global_var_exps: FastHashMap::default(), - lookup_constant_exps: FastHashMap::default(), + lookup_global_var_exps: FastHashMap::with_capacity_and_hasher( + program.constants.len() + program.global_variables.len(), + Default::default(), + ), typifier: Typifier::new(), samplers: FastHashMap::default(), hir_exprs: Arena::default(), + emitter: Emitter::default(), + }; + + this.emit_start(); + + for &(ref name, lookup) in program.global_variables.iter() { + let expr = match lookup { + GlobalLookup::Variable(v) => Expression::GlobalVariable(v), + GlobalLookup::BlockSelect(handle, index) => { + let base = this.add_expression(Expression::GlobalVariable(handle), body); + + Expression::AccessIndex { base, index } + } + }; + + let expr = this.add_expression(expr, body); + let var = VariableReference { + expr, + load: Some(this.add_expression(Expression::Load { pointer: expr }, body)), + // TODO: respect constant qualifier + mutable: true, + }; + + this.lookup_global_var_exps.insert(name.into(), var); + } + + for &(ref name, handle) in program.constants.iter() { + let expr = this.add_expression(Expression::Constant(handle), body); + let var = VariableReference { + expr, + load: None, + mutable: false, + }; + + this.lookup_global_var_exps.insert(name.into(), var); + } + + this + } + + pub fn emit_start(&mut self) { + self.emitter.start(&self.expressions) + } + + pub fn emit_flush(&mut self, body: &mut Block) { + body.extend(self.emitter.finish(&self.expressions)) + } + + pub fn add_expression(&mut self, expr: Expression, body: &mut Block) -> Handle { + if expr.needs_pre_emit() { + self.emit_flush(body); + let expr = self.expressions.append(expr); + self.emit_start(); + expr + } else { + self.expressions.append(expr) } } @@ -185,55 +246,8 @@ impl<'function> Context<'function> { None } - pub fn lookup_global_var( - &mut self, - program: &mut Program, - name: &str, - ) -> Option { - self.lookup_global_var_exps.get(name).cloned().or_else(|| { - let expr = match *program.lookup_global_variables.get(name)? { - GlobalLookup::Variable(v) => Expression::GlobalVariable(v), - GlobalLookup::BlockSelect(handle, index) => { - let base = self.expressions.append(Expression::GlobalVariable(handle)); - - Expression::AccessIndex { base, index } - } - }; - - let expr = self.expressions.append(expr); - let var = VariableReference { - expr, - load: Some(self.expressions.append(Expression::Load { pointer: expr })), - // TODO: respect constant qualifier - mutable: true, - }; - - self.lookup_global_var_exps.insert(name.into(), var.clone()); - - Some(var) - }) - } - - pub fn lookup_constants_var( - &mut self, - program: &mut Program, - name: &str, - ) -> Option { - self.lookup_constant_exps.get(name).cloned().or_else(|| { - let expr = self - .expressions - .append(Expression::Constant(*program.lookup_constants.get(name)?)); - - let var = VariableReference { - expr, - load: None, - mutable: false, - }; - - self.lookup_constant_exps.insert(name.into(), var.clone()); - - Some(var) - }) + pub fn lookup_global_var(&mut self, name: &str) -> Option { + self.lookup_global_var_exps.get(name).cloned() } #[cfg(feature = "glsl-validate")] @@ -311,15 +325,15 @@ impl<'function> Context<'function> { let base = self.lower(program, base, lhs, body)?.0; let index = self.lower(program, index, false, body)?.0; - self.expressions.append(Expression::Access { base, index }) + self.add_expression(Expression::Access { base, index }, body) } HirExprKind::Select { base, field } => { let base = self.lower(program, base, lhs, body)?.0; - program.field_selection(self, base, &field, meta)? + program.field_selection(self, body, base, &field, meta)? } HirExprKind::Constant(constant) if !lhs => { - self.expressions.append(Expression::Constant(constant)) + self.add_expression(Expression::Constant(constant), body) } HirExprKind::Binary { left, op, right } if !lhs => { let (left, left_meta) = self.lower(program, left, false, body)?; @@ -353,20 +367,18 @@ impl<'function> Context<'function> { if left_dims != right_dims { return Err(ErrorKind::SemanticError(meta, "Cannot compare".into())); } else if left_is_vector && right_is_vector { - self.expressions - .append(Expression::Relational { fun, argument }) + self.add_expression(Expression::Relational { fun, argument }, body) } else { argument } } else { - self.expressions - .append(Expression::Binary { left, op, right }) + self.add_expression(Expression::Binary { left, op, right }, body) } } HirExprKind::Unary { op, expr } if !lhs => { let expr = self.lower(program, expr, false, body)?.0; - self.expressions.append(Expression::Unary { op, expr }) + self.add_expression(Expression::Unary { op, expr }, body) } HirExprKind::Variable(var) => { if lhs { @@ -394,16 +406,22 @@ impl<'function> Context<'function> { let accept = self.lower(program, accept, false, body)?.0; let reject = self.lower(program, reject, false, body)?.0; - self.expressions.append(Expression::Select { - condition, - accept, - reject, - }) + self.add_expression( + Expression::Select { + condition, + accept, + reject, + }, + body, + ) } HirExprKind::Assign { tgt, value } if !lhs => { let pointer = self.lower(program, tgt, true, body)?.0; let value = self.lower(program, value, false, body)?.0; + self.emit_flush(body); + self.emit_start(); + body.push(Statement::Store { pointer, value }); value diff --git a/src/front/glsl/functions.rs b/src/front/glsl/functions.rs index d0128dc81c..766f255e12 100644 --- a/src/front/glsl/functions.rs +++ b/src/front/glsl/functions.rs @@ -30,53 +30,63 @@ impl Program<'_> { }; match self.module.types[ty].inner { - TypeInner::Vector { size, .. } if !is_vec => { - ctx.expressions.append(Expression::Splat { + TypeInner::Vector { size, .. } if !is_vec => ctx.add_expression( + Expression::Splat { size, value: args[0].0, - }) - } + }, + body, + ), TypeInner::Scalar { kind, width } - | TypeInner::Vector { kind, width, .. } => { - ctx.expressions.append(Expression::As { + | TypeInner::Vector { kind, width, .. } => ctx.add_expression( + Expression::As { kind, expr: args[0].0, convert: Some(width), - }) - } + }, + body, + ), TypeInner::Matrix { columns, rows, width, } => { - let value = ctx.expressions.append(Expression::As { - kind: ScalarKind::Float, - expr: args[0].0, - convert: Some(width), - }); + let value = ctx.add_expression( + Expression::As { + kind: ScalarKind::Float, + expr: args[0].0, + convert: Some(width), + }, + body, + ); let column = if is_vec { value } else { - ctx.expressions - .append(Expression::Splat { size: rows, value }) + ctx.add_expression(Expression::Splat { size: rows, value }, body) }; let columns = std::iter::repeat(column).take(columns as usize).collect(); - ctx.expressions.append(Expression::Compose { - ty, - components: columns, - }) + ctx.add_expression( + Expression::Compose { + ty, + components: columns, + }, + body, + ) } _ => return Err(ErrorKind::SemanticError(meta, "Bad cast".into())), } } else { - ctx.expressions.append(Expression::Compose { - ty, - components: args.iter().map(|e| e.0).collect(), - }) + ctx.add_expression( + Expression::Compose { + ty, + components: args.iter().map(|e| e.0).collect(), + }, + body, + ) }; Ok(h) @@ -95,15 +105,18 @@ impl Program<'_> { return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); } if let Some(sampler) = ctx.samplers.get(&args[0].0).copied() { - Ok(ctx.expressions.append(Expression::ImageSample { - image: args[0].0, - sampler, - coordinate: args[1].0, - array_index: None, //TODO - offset: None, //TODO - level: SampleLevel::Auto, - depth_ref: None, - })) + Ok(ctx.add_expression( + Expression::ImageSample { + image: args[0].0, + sampler, + coordinate: args[1].0, + array_index: None, //TODO + offset: None, //TODO + level: SampleLevel::Auto, + depth_ref: None, + }, + body, + )) } else { Err(ErrorKind::SemanticError(meta, "Bad call to texture".into())) } @@ -113,15 +126,18 @@ impl Program<'_> { return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta)); } if let Some(sampler) = ctx.samplers.get(&args[0].0).copied() { - Ok(ctx.expressions.append(Expression::ImageSample { - image: args[0].0, - sampler, - coordinate: args[1].0, - array_index: None, //TODO - offset: None, //TODO - level: SampleLevel::Exact(args[2].0), - depth_ref: None, - })) + Ok(ctx.add_expression( + Expression::ImageSample { + image: args[0].0, + sampler, + coordinate: args[1].0, + array_index: None, //TODO + offset: None, //TODO + level: SampleLevel::Exact(args[2].0), + depth_ref: None, + }, + body, + )) } else { Err(ErrorKind::SemanticError( meta, @@ -135,91 +151,102 @@ impl Program<'_> { if args.len() != 1 { return Err(ErrorKind::wrong_function_args(name, 1, args.len(), meta)); } - Ok(ctx.expressions.append(Expression::Math { - fun: match name.as_str() { - "ceil" => MathFunction::Ceil, - "round" => MathFunction::Round, - "floor" => MathFunction::Floor, - "fract" => MathFunction::Fract, - "trunc" => MathFunction::Trunc, - "sin" => MathFunction::Sin, - "abs" => MathFunction::Abs, - "sqrt" => MathFunction::Sqrt, - "inversesqrt" => MathFunction::InverseSqrt, - "exp" => MathFunction::Exp, - "exp2" => MathFunction::Exp2, - "sign" => MathFunction::Sign, - "transpose" => MathFunction::Transpose, - "inverse" => MathFunction::Inverse, - "normalize" => MathFunction::Normalize, - _ => unreachable!(), + Ok(ctx.add_expression( + Expression::Math { + fun: match name.as_str() { + "ceil" => MathFunction::Ceil, + "round" => MathFunction::Round, + "floor" => MathFunction::Floor, + "fract" => MathFunction::Fract, + "trunc" => MathFunction::Trunc, + "sin" => MathFunction::Sin, + "abs" => MathFunction::Abs, + "sqrt" => MathFunction::Sqrt, + "inversesqrt" => MathFunction::InverseSqrt, + "exp" => MathFunction::Exp, + "exp2" => MathFunction::Exp2, + "sign" => MathFunction::Sign, + "transpose" => MathFunction::Transpose, + "inverse" => MathFunction::Inverse, + "normalize" => MathFunction::Normalize, + _ => unreachable!(), + }, + arg: args[0].0, + arg1: None, + arg2: None, }, - arg: args[0].0, - arg1: None, - arg2: None, - })) + body, + )) } "pow" | "dot" | "max" => { if args.len() != 2 { return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); } - Ok(ctx.expressions.append(Expression::Math { - fun: match name.as_str() { - "pow" => MathFunction::Pow, - "dot" => MathFunction::Dot, - "max" => MathFunction::Max, - _ => unreachable!(), + Ok(ctx.add_expression( + Expression::Math { + fun: match name.as_str() { + "pow" => MathFunction::Pow, + "dot" => MathFunction::Dot, + "max" => MathFunction::Max, + _ => unreachable!(), + }, + arg: args[0].0, + arg1: Some(args[1].0), + arg2: None, }, - arg: args[0].0, - arg1: Some(args[1].0), - arg2: None, - })) + body, + )) } "mix" | "clamp" => { if args.len() != 3 { return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta)); } - Ok(ctx.expressions.append(Expression::Math { - fun: match name.as_str() { - "mix" => MathFunction::Mix, - "clamp" => MathFunction::Clamp, - _ => unreachable!(), + Ok(ctx.add_expression( + Expression::Math { + fun: match name.as_str() { + "mix" => MathFunction::Mix, + "clamp" => MathFunction::Clamp, + _ => unreachable!(), + }, + arg: args[0].0, + arg1: Some(args[1].0), + arg2: Some(args[2].0), }, - arg: args[0].0, - arg1: Some(args[1].0), - arg2: Some(args[2].0), - })) + body, + )) } "lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" | "equal" | "notEqual" => { if args.len() != 2 { return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); } - Ok(ctx.expressions.append(Expression::Binary { - op: match name.as_str() { - "lessThan" => BinaryOperator::Less, - "greaterThan" => BinaryOperator::Greater, - "lessThanEqual" => BinaryOperator::LessEqual, - "greaterThanEqual" => BinaryOperator::GreaterEqual, - "equal" => BinaryOperator::Equal, - "notEqual" => BinaryOperator::NotEqual, - _ => unreachable!(), + Ok(ctx.add_expression( + Expression::Binary { + op: match name.as_str() { + "lessThan" => BinaryOperator::Less, + "greaterThan" => BinaryOperator::Greater, + "lessThanEqual" => BinaryOperator::LessEqual, + "greaterThanEqual" => BinaryOperator::GreaterEqual, + "equal" => BinaryOperator::Equal, + "notEqual" => BinaryOperator::NotEqual, + _ => unreachable!(), + }, + left: args[0].0, + right: args[1].0, }, - left: args[0].0, - right: args[1].0, - })) + body, + )) } - "isinf" => { - self.parse_relational_fun(ctx, name, &args, RelationalFunction::IsInf, meta) - } - "isnan" => { - self.parse_relational_fun(ctx, name, &args, RelationalFunction::IsNan, meta) - } - "all" => { - self.parse_relational_fun(ctx, name, &args, RelationalFunction::All, meta) - } - "any" => { - self.parse_relational_fun(ctx, name, &args, RelationalFunction::Any, meta) + "isinf" | "isnan" | "all" | "any" => { + let fun = match name.as_str() { + "isinf" => RelationalFunction::IsInf, + "isnan" => RelationalFunction::IsNan, + "all" => RelationalFunction::All, + "any" => RelationalFunction::Any, + _ => unreachable!(), + }; + + self.parse_relational_fun(ctx, body, name, &args, fun, meta) } _ => { let mut parameters = Vec::new(); @@ -250,12 +277,17 @@ impl Program<'_> { arguments.push(handle) } - let expression = ctx.expressions.append(Expression::Call(fun.handle)); + ctx.emit_flush(body); + + let expression = ctx.add_expression(Expression::Call(fun.handle), body); body.push(crate::Statement::Call { function: fun.handle, arguments, result: Some(expression), }); + + ctx.emit_start(); + Ok(expression) } } @@ -266,6 +298,7 @@ impl Program<'_> { pub fn parse_relational_fun( &mut self, ctx: &mut Context, + body: &mut Block, name: String, args: &[(Handle, SourceMetadata)], fun: RelationalFunction, @@ -275,10 +308,13 @@ impl Program<'_> { return Err(ErrorKind::wrong_function_args(name, 1, args.len(), meta)); } - Ok(ctx.expressions.append(Expression::Relational { - fun, - argument: args[0].0, - })) + Ok(ctx.add_expression( + Expression::Relational { + fun, + argument: args[0].0, + }, + body, + )) } pub fn add_function( @@ -438,7 +474,9 @@ impl Program<'_> { span += self.module.types[ty].inner.span(&self.module.constants); let pointer = expressions.append(Expression::GlobalVariable(handle)); + let len = expressions.len(); let load = expressions.append(Expression::Load { pointer }); + body.push(Statement::Emit(expressions.range_from(len))); components.push(load) } @@ -451,7 +489,9 @@ impl Program<'_> { }, }); + let len = expressions.len(); let res = expressions.append(Expression::Compose { ty, components }); + body.push(Statement::Emit(expressions.range_from(len))); body.push(Statement::Return { value: Some(res) }); self.module.entry_points.push(EntryPoint { diff --git a/src/front/glsl/parser.rs b/src/front/glsl/parser.rs index 1e7236056a..0283fb1c57 100644 --- a/src/front/glsl/parser.rs +++ b/src/front/glsl/parser.rs @@ -319,13 +319,20 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { let mut expressions = Arena::new(); let mut locals = Arena::new(); let mut arguments = Vec::new(); + let mut block = Block::new(); - let mut ctx = Context::new(&mut expressions, &mut locals, &mut arguments); + let mut ctx = Context::new( + self.program, + &mut block, + &mut expressions, + &mut locals, + &mut arguments, + ); - let expr = self.parse_conditional(&mut ctx, None)?; - let (root, meta) = ctx.lower(self.program, expr, false, &mut Block::new())?; + let expr = self.parse_conditional(&mut ctx, &mut block, None)?; + let (root, meta) = ctx.lower(self.program, expr, false, &mut block)?; - Ok((self.program.solve_constant(&expressions, root, meta)?, meta)) + Ok((self.program.solve_constant(&ctx, root, meta)?, meta)) } fn parse_external_declaration(&mut self) -> Result<()> { @@ -339,8 +346,8 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { // void main() {} // ``` let (mut e, mut l, mut a) = (Arena::new(), Arena::new(), Vec::new()); - let mut ctx = Context::new(&mut e, &mut l, &mut a); let mut body = Block::new(); + let mut ctx = Context::new(self.program, &mut body, &mut e, &mut l, &mut a); if !self.parse_declaration(&mut ctx, &mut body, true)? { let token = self.bump()?; @@ -422,12 +429,11 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { } Ok(( - ctx.expressions - .append(Expression::Compose { ty, components }), + ctx.add_expression(Expression::Compose { ty, components }, body), meta, )) } else { - let expr = self.parse_assignment(ctx)?; + let expr = self.parse_assignment(ctx, body)?; Ok(ctx.lower(self.program, expr, false, body)?) } } @@ -499,15 +505,15 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { // TODO: Should we try to make constants here? // This is mostly a hack because we don't yet support adding // bodies to entry points for variable initialization - let maybe_constant = init.clone().and_then(|(root, meta)| { - self.program - .solve_constant(ctx.ctx.expressions, root, meta) - .ok() - }); + let maybe_constant = init + .clone() + .and_then(|(root, meta)| self.program.solve_constant(ctx.ctx, root, meta).ok()); let pointer = ctx.add_var(self.program, ty, name, maybe_constant, meta)?; if let Some((value, _)) = init { + ctx.ctx.emit_flush(ctx.body); + ctx.ctx.emit_start(); ctx.body.push(Statement::Store { pointer, value }); } @@ -561,8 +567,11 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { let mut local_variables = Arena::new(); let mut arguments = Vec::new(); let mut parameters = Vec::new(); + let mut body = Block::new(); let mut context = Context::new( + self.program, + &mut body, &mut expressions, &mut local_variables, &mut arguments, @@ -594,10 +603,10 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { // This branch handles function definitions // as you can see by the guard this branch // only happens if external is also true - let mut body = Block::new(); // parse the body self.parse_compound_statement(&mut context, &mut body)?; + self.program.add_function( Function { name: Some(name), @@ -773,8 +782,8 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { if let Some(k) = name { self.program - .lookup_global_variables - .insert(k, GlobalLookup::Variable(handle)); + .global_variables + .push((k, GlobalLookup::Variable(handle))); } for (i, k) in members @@ -783,8 +792,8 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { .filter_map(|(i, m)| m.name.map(|s| (i as u32, s))) { self.program - .lookup_global_variables - .insert(k, GlobalLookup::BlockSelect(handle, i)); + .global_variables + .push((k, GlobalLookup::BlockSelect(handle, i))); } Ok(true) @@ -819,7 +828,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { Ok(span) } - fn parse_primary(&mut self, ctx: &mut Context) -> Result> { + fn parse_primary(&mut self, ctx: &mut Context, body: &mut Block) -> Result> { let mut token = self.bump()?; let (width, value) = match token.value { @@ -837,7 +846,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { ), TokenValue::BoolConstant(value) => (1, ScalarValue::Bool(value)), TokenValue::LeftParen => { - let expr = self.parse_expression(ctx)?; + let expr = self.parse_expression(ctx, body)?; let meta = self.expect(TokenValue::RightParen)?.meta; token.meta = token.meta.union(&meta); @@ -862,6 +871,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { fn parse_function_call_args( &mut self, ctx: &mut Context, + body: &mut Block, meta: &mut SourceMetadata, ) -> Result>> { let mut args = Vec::new(); @@ -869,7 +879,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { *meta = meta.union(&token.meta); } else { loop { - args.push(self.parse_assignment(ctx)?); + args.push(self.parse_assignment(ctx, body)?); let token = self.bump()?; match token.value { @@ -886,13 +896,13 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { Ok(args) } - fn parse_postfix(&mut self, ctx: &mut Context) -> Result> { + fn parse_postfix(&mut self, ctx: &mut Context, body: &mut Block) -> Result> { let mut base = match self.expect_peek()?.value { TokenValue::Identifier(_) => { let (name, mut meta) = self.expect_ident()?; let expr = if self.bump_if(TokenValue::LeftParen).is_some() { - let args = self.parse_function_call_args(ctx, &mut meta)?; + let args = self.parse_function_call_args(ctx, body, &mut meta)?; HirExpr { kind: HirExprKind::Call(FunctionCall { @@ -902,7 +912,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { meta, } } else { - let var = match self.program.lookup_variable(ctx, &name)? { + let var = match self.program.lookup_variable(ctx, body, &name)? { Some(var) => var, None => return Err(ErrorKind::UnknownVariable(meta, name)), }; @@ -925,7 +935,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { }; self.expect(TokenValue::LeftParen)?; - let args = self.parse_function_call_args(ctx, &mut meta)?; + let args = self.parse_function_call_args(ctx, body, &mut meta)?; ctx.hir_exprs.append(HirExpr { kind: HirExprKind::Call(FunctionCall { @@ -935,7 +945,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { meta, }) } - _ => self.parse_primary(ctx)?, + _ => self.parse_primary(ctx, body)?, }; // TODO: postfix inc/dec @@ -944,7 +954,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { match value { TokenValue::LeftBracket => { - let index = self.parse_expression(ctx)?; + let index = self.parse_expression(ctx, body)?; let end_meta = self.expect(TokenValue::RightBracket)?.meta; base = ctx.hir_exprs.append(HirExpr { @@ -967,13 +977,13 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { Ok(base) } - fn parse_unary(&mut self, ctx: &mut Context) -> Result> { + fn parse_unary(&mut self, ctx: &mut Context, body: &mut Block) -> Result> { // TODO: prefix inc/dec Ok(match self.expect_peek()?.value { TokenValue::Plus | TokenValue::Dash | TokenValue::Bang | TokenValue::Tilde => { let Token { value, meta } = self.bump()?; - let expr = self.parse_unary(ctx)?; + let expr = self.parse_unary(ctx, body)?; let end_meta = ctx.hir_exprs[expr].meta; let kind = match value { @@ -993,19 +1003,20 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { meta: meta.union(&end_meta), }) } - _ => self.parse_postfix(ctx)?, + _ => self.parse_postfix(ctx, body)?, }) } fn parse_binary( &mut self, ctx: &mut Context, + body: &mut Block, passtrough: Option>, min_bp: u8, ) -> Result> { let mut left = passtrough .ok_or(ErrorKind::EndOfFile /* Dummy error */) - .or_else(|_| self.parse_unary(ctx))?; + .or_else(|_| self.parse_unary(ctx, body))?; let start_meta = ctx.hir_exprs[left].meta; while let Some((l_bp, r_bp)) = binding_power(&self.expect_peek()?.value) { @@ -1015,7 +1026,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { let Token { value, .. } = self.bump()?; - let right = self.parse_binary(ctx, None, r_bp)?; + let right = self.parse_binary(ctx, body, None, r_bp)?; let end_meta = ctx.hir_exprs[right].meta; left = ctx.hir_exprs.append(HirExpr { @@ -1055,15 +1066,16 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { fn parse_conditional( &mut self, ctx: &mut Context, + body: &mut Block, passtrough: Option>, ) -> Result> { - let mut condition = self.parse_binary(ctx, passtrough, 0)?; + let mut condition = self.parse_binary(ctx, body, passtrough, 0)?; let start_meta = ctx.hir_exprs[condition].meta; if self.bump_if(TokenValue::Question).is_some() { - let accept = self.parse_expression(ctx)?; + let accept = self.parse_expression(ctx, body)?; self.expect(TokenValue::Colon)?; - let reject = self.parse_assignment(ctx)?; + let reject = self.parse_assignment(ctx, body)?; let end_meta = ctx.hir_exprs[reject].meta; condition = ctx.hir_exprs.append(HirExpr { @@ -1079,14 +1091,14 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { Ok(condition) } - fn parse_assignment(&mut self, ctx: &mut Context) -> Result> { - let tgt = self.parse_unary(ctx)?; + fn parse_assignment(&mut self, ctx: &mut Context, body: &mut Block) -> Result> { + let tgt = self.parse_unary(ctx, body)?; let start_meta = ctx.hir_exprs[tgt].meta; Ok(match self.expect_peek()?.value { TokenValue::Assign => { self.bump()?; - let value = self.parse_assignment(ctx)?; + let value = self.parse_assignment(ctx, body)?; let end_meta = ctx.hir_exprs[value].meta; ctx.hir_exprs.append(HirExpr { @@ -1105,7 +1117,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { | TokenValue::RightShiftAssign | TokenValue::XorAssign => { let token = self.bump()?; - let right = self.parse_assignment(ctx)?; + let right = self.parse_assignment(ctx, body)?; let end_meta = ctx.hir_exprs[right].meta; let value = ctx.hir_exprs.append(HirExpr { @@ -1134,16 +1146,16 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { meta: start_meta.union(&end_meta), }) } - _ => self.parse_conditional(ctx, Some(tgt))?, + _ => self.parse_conditional(ctx, body, Some(tgt))?, }) } - fn parse_expression(&mut self, ctx: &mut Context) -> Result> { - let mut expr = self.parse_assignment(ctx)?; + fn parse_expression(&mut self, ctx: &mut Context, body: &mut Block) -> Result> { + let mut expr = self.parse_assignment(ctx, body)?; while let TokenValue::Comma = self.expect_peek()?.value { self.bump()?; - expr = self.parse_assignment(ctx)?; + expr = self.parse_assignment(ctx, body)?; } Ok(expr) @@ -1169,12 +1181,15 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { None } _ => { - let expr = self.parse_expression(ctx)?; + let expr = self.parse_expression(ctx, body)?; self.expect(TokenValue::Semicolon)?; Some(ctx.lower(self.program, expr, false, body)?.0) } }; + ctx.emit_flush(body); + ctx.emit_start(); + body.push(Statement::Return { value }) } TokenValue::Discard => { @@ -1187,11 +1202,14 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { self.expect(TokenValue::LeftParen)?; let condition = { - let expr = self.parse_expression(ctx)?; + let expr = self.parse_expression(ctx, body)?; ctx.lower(self.program, expr, false, body)?.0 }; self.expect(TokenValue::RightParen)?; + ctx.emit_flush(body); + ctx.emit_start(); + let mut accept = Block::new(); self.parse_statement(ctx, &mut accept)?; @@ -1211,11 +1229,14 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { self.expect(TokenValue::LeftParen)?; let selector = { - let expr = self.parse_expression(ctx)?; + let expr = self.parse_expression(ctx, body)?; ctx.lower(self.program, expr, false, body)?.0 }; self.expect(TokenValue::RightParen)?; + ctx.emit_flush(body); + ctx.emit_start(); + let mut cases = Vec::new(); let mut default = Block::new(); @@ -1225,10 +1246,9 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { TokenValue::Case => { self.bump()?; let value = { - let expr = self.parse_expression(ctx)?; + let expr = self.parse_expression(ctx, body)?; let (root, meta) = ctx.lower(self.program, expr, false, body)?; - let constant = - self.program.solve_constant(&ctx.expressions, root, meta)?; + let constant = self.program.solve_constant(&ctx, root, meta)?; match self.program.module.constants[constant].inner { ConstantInner::Scalar { @@ -1306,17 +1326,23 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { TokenValue::While => { self.bump()?; - self.expect(TokenValue::LeftParen)?; - let root = self.parse_expression(ctx)?; - self.expect(TokenValue::RightParen)?; - let mut loop_body = Block::new(); + self.expect(TokenValue::LeftParen)?; + let root = self.parse_expression(ctx, &mut loop_body)?; + self.expect(TokenValue::RightParen)?; + let expr = ctx.lower(self.program, root, false, &mut loop_body)?.0; - let condition = ctx.expressions.append(Expression::Unary { - op: UnaryOperator::Not, - expr, - }); + let condition = ctx.add_expression( + Expression::Unary { + op: UnaryOperator::Not, + expr, + }, + &mut loop_body, + ); + + ctx.emit_flush(&mut loop_body); + ctx.emit_start(); loop_body.push(Statement::If { condition, @@ -1339,14 +1365,20 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { self.expect(TokenValue::While)?; self.expect(TokenValue::LeftParen)?; - let root = self.parse_expression(ctx)?; + let root = self.parse_expression(ctx, &mut loop_body)?; self.expect(TokenValue::RightParen)?; let expr = ctx.lower(self.program, root, false, &mut loop_body)?.0; - let condition = ctx.expressions.append(Expression::Unary { - op: UnaryOperator::Not, - expr, - }); + let condition = ctx.add_expression( + Expression::Unary { + op: UnaryOperator::Not, + expr, + }, + &mut loop_body, + ); + + ctx.emit_flush(&mut loop_body); + ctx.emit_start(); loop_body.push(Statement::If { condition, @@ -1369,11 +1401,14 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { if self.peek_type_name() || self.peek_type_qualifier() { self.parse_declaration(ctx, body, false)?; } else { - self.parse_expression(ctx)?; + self.parse_expression(ctx, body)?; self.expect(TokenValue::Semicolon)?; } } + ctx.emit_flush(body); + ctx.emit_start(); + let (mut block, mut continuing) = (Block::new(), Block::new()); if self.bump_if(TokenValue::Semicolon).is_none() { @@ -1394,21 +1429,32 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { meta: meta.union(&end_meta), }; - let pointer = self.program.add_local_var(ctx, decl)?; + let pointer = self.program.add_local_var(ctx, &mut block, decl)?; + + ctx.emit_flush(&mut block); + ctx.emit_start(); block.push(Statement::Store { pointer, value }); value } else { - let root = self.parse_expression(ctx)?; + let root = self.parse_expression(ctx, &mut block)?; ctx.lower(self.program, root, false, &mut block)?.0 }; - body.push(Statement::If { - condition: ctx.expressions.append(Expression::Unary { + let condition = ctx.add_expression( + Expression::Unary { op: UnaryOperator::Not, expr, - }), + }, + &mut block, + ); + + ctx.emit_flush(&mut block); + ctx.emit_start(); + + body.push(Statement::If { + condition, accept: vec![Statement::Break], reject: Block::new(), }); @@ -1419,7 +1465,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { match self.expect_peek()?.value { TokenValue::RightParen => {} _ => { - let rest = self.parse_expression(ctx)?; + let rest = self.parse_expression(ctx, &mut continuing)?; ctx.lower(self.program, rest, false, &mut continuing)?; } } @@ -1462,7 +1508,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { | TokenValue::IntConstant(_) | TokenValue::BoolConstant(_) | TokenValue::FloatConstant(_) => { - let expr = self.parse_expression(ctx)?; + let expr = self.parse_expression(ctx, body)?; ctx.lower(self.program, expr, false, body)?; self.expect(TokenValue::Semicolon)?; } @@ -1560,8 +1606,8 @@ impl<'ctx, 'fun> DeclarationContext<'ctx, 'fun> { }; match self.external { - true => program.add_global_var(self.ctx, decl), - false => program.add_local_var(self.ctx, decl), + true => program.add_global_var(self.ctx, self.body, decl), + false => program.add_local_var(self.ctx, self.body, decl), } } } diff --git a/src/front/glsl/variables.rs b/src/front/glsl/variables.rs index d57ce2a7ee..22201b8d24 100644 --- a/src/front/glsl/variables.rs +++ b/src/front/glsl/variables.rs @@ -1,6 +1,6 @@ use crate::{ - Binding, BuiltIn, Constant, Expression, GlobalVariable, Handle, LocalVariable, ScalarKind, - StorageAccess, StorageClass, Type, TypeInner, VectorSize, + Binding, Block, BuiltIn, Constant, Expression, GlobalVariable, Handle, LocalVariable, + ScalarKind, StorageAccess, StorageClass, Type, TypeInner, VectorSize, }; use super::ast::*; @@ -18,119 +18,102 @@ pub struct VarDeclaration<'a> { impl Program<'_> { pub fn lookup_variable( &mut self, - context: &mut Context, + ctx: &mut Context, + body: &mut Block, name: &str, ) -> Result, ErrorKind> { - if let Some(local_var) = context.lookup_local_var(name) { + if let Some(local_var) = ctx.lookup_local_var(name) { return Ok(Some(local_var)); } - if let Some(global_var) = context.lookup_global_var(self, name) { + if let Some(global_var) = ctx.lookup_global_var(name) { return Ok(Some(global_var)); } - if let Some(constant) = context.lookup_constants_var(self, name) { - return Ok(Some(constant)); - } + + let mut add_builtin = |inner, builtin, mutable| { + let ty = self + .module + .types + .fetch_or_append(Type { name: None, inner }); + + let handle = self.module.global_variables.append(GlobalVariable { + name: Some(name.into()), + class: StorageClass::Private, + binding: None, + ty, + init: None, + storage_access: StorageAccess::all(), + }); + + self.entry_args + .push((Binding::BuiltIn(builtin), true, handle)); + + self.global_variables + .push((name.into(), GlobalLookup::Variable(handle))); + + let expr = ctx.add_expression(Expression::GlobalVariable(handle), body); + let load = ctx.add_expression(Expression::Load { pointer: expr }, body); + ctx.lookup_global_var_exps.insert( + name.into(), + VariableReference { + expr, + load: Some(load), + mutable, + }, + ); + + Ok(ctx.lookup_global_var(name)) + }; match name { - "gl_Position" => { - let ty = self.module.types.fetch_or_append(Type { - name: None, - inner: TypeInner::Vector { - size: VectorSize::Quad, - kind: ScalarKind::Float, - width: 4, - }, - }); - - let handle = self.module.global_variables.append(GlobalVariable { - name: Some(name.into()), - class: StorageClass::Private, - binding: None, - ty, - init: None, - storage_access: StorageAccess::all(), - }); - - self.entry_args - .push((Binding::BuiltIn(BuiltIn::Position), true, handle)); - - self.lookup_global_variables - .insert(name.into(), GlobalLookup::Variable(handle)); - - Ok(context.lookup_global_var(self, name)) - } - "gl_VertexIndex" => { - let ty = self.module.types.fetch_or_append(Type { - name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, - }); - - let handle = self.module.global_variables.append(GlobalVariable { - name: Some(name.into()), - class: StorageClass::Private, - binding: None, - ty, - init: None, - storage_access: StorageAccess::all(), - }); - - self.entry_args - .push((Binding::BuiltIn(BuiltIn::VertexIndex), true, handle)); - - self.lookup_global_variables - .insert(name.into(), GlobalLookup::Variable(handle)); - - Ok(context.lookup_global_var(self, name)) - } - "gl_InstanceIndex" => { - let ty = self.module.types.fetch_or_append(Type { - name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, - }); - - let handle = self.module.global_variables.append(GlobalVariable { - name: Some(name.into()), - class: StorageClass::Private, - binding: None, - ty, - init: None, - storage_access: StorageAccess::all(), - }); - - self.entry_args - .push((Binding::BuiltIn(BuiltIn::InstanceIndex), true, handle)); - - self.lookup_global_variables - .insert(name.into(), GlobalLookup::Variable(handle)); - - Ok(context.lookup_global_var(self, name)) - } + "gl_Position" => add_builtin( + TypeInner::Vector { + size: VectorSize::Quad, + kind: ScalarKind::Float, + width: 4, + }, + BuiltIn::Position, + true, + ), + "gl_VertexIndex" => add_builtin( + TypeInner::Scalar { + kind: ScalarKind::Sint, + width: 4, + }, + BuiltIn::VertexIndex, + false, + ), + "gl_InstanceIndex" => add_builtin( + TypeInner::Scalar { + kind: ScalarKind::Sint, + width: 4, + }, + BuiltIn::InstanceIndex, + false, + ), _ => Ok(None), } } pub fn field_selection( &mut self, - context: &mut Context, + ctx: &mut Context, + body: &mut Block, expression: Handle, name: &str, meta: SourceMetadata, ) -> Result, ErrorKind> { - match *self.resolve_type(context, expression, meta)? { + match *self.resolve_type(ctx, expression, meta)? { TypeInner::Struct { ref members, .. } => { let index = members .iter() .position(|m| m.name == Some(name.into())) .ok_or_else(|| ErrorKind::UnknownField(meta, name.into()))?; - Ok(context.expressions.append(Expression::AccessIndex { - base: expression, - index: index as u32, - })) + Ok(ctx.add_expression( + Expression::AccessIndex { + base: expression, + index: index as u32, + }, + body, + )) } // swizzles (xyzw, rgba, stpq) TypeInner::Vector { size, kind, width } => { @@ -159,41 +142,40 @@ impl Program<'_> { let components: Vec> = v .iter() .map(|idx| { - context.expressions.append(Expression::AccessIndex { - base: expression, - index: *idx as u32, - }) + ctx.add_expression( + Expression::AccessIndex { + base: expression, + index: *idx as u32, + }, + body, + ) }) .collect(); if components.len() == 1 { // only single element swizzle, like pos.y, just return that component Ok(components[0]) } else { - Ok(context.expressions.append(Expression::Compose { - ty: self.module.types.fetch_or_append(Type { - name: None, - inner: TypeInner::Vector { - kind, - width, - size: match components.len() { - 2 => VectorSize::Bi, - 3 => VectorSize::Tri, - 4 => VectorSize::Quad, - _ => { - return Err(ErrorKind::SemanticError( - meta, - format!( - "Bad swizzle size for \"{:?}\": {:?}", - name, v - ) - .into(), - )); - } - }, - }, - }), - components, - })) + let size = match components.len() { + 2 => VectorSize::Bi, + 3 => VectorSize::Tri, + 4 => VectorSize::Quad, + _ => { + return Err(ErrorKind::SemanticError( + meta, + format!("Bad swizzle size for \"{:?}\": {:?}", name, v).into(), + )); + } + }; + Ok(ctx.add_expression( + Expression::Compose { + ty: self.module.types.fetch_or_append(Type { + name: None, + inner: TypeInner::Vector { kind, width, size }, + }), + components, + }, + body, + )) } } else { Err(ErrorKind::SemanticError( @@ -212,6 +194,7 @@ impl Program<'_> { pub fn add_global_var( &mut self, ctx: &mut Context, + body: &mut Block, VarDeclaration { qualifiers, ty, @@ -334,18 +317,18 @@ impl Program<'_> { handle, )); - self.lookup_global_variables - .insert(name, GlobalLookup::Variable(handle)); + self.global_variables + .push((name, GlobalLookup::Variable(handle))); - return Ok(ctx.expressions.append(Expression::GlobalVariable(handle))); + return Ok(ctx.add_expression(Expression::GlobalVariable(handle), body)); } else if let StorageQualifier::Const = storage { let handle = init.ok_or_else(|| { ErrorKind::SemanticError(meta, "Constant must have a initializer".into()) })?; - self.lookup_constants.insert(name, handle); + self.constants.push((name, handle)); - return Ok(ctx.expressions.append(Expression::Constant(handle))); + return Ok(ctx.add_expression(Expression::Constant(handle), body)); } let class = match storage { @@ -363,15 +346,16 @@ impl Program<'_> { storage_access: StorageAccess::all(), }); - self.lookup_global_variables - .insert(name, GlobalLookup::Variable(handle)); + self.global_variables + .push((name, GlobalLookup::Variable(handle))); - Ok(ctx.expressions.append(Expression::GlobalVariable(handle))) + Ok(ctx.add_expression(Expression::GlobalVariable(handle), body)) } pub fn add_local_var( &mut self, ctx: &mut Context, + body: &mut Block, VarDeclaration { qualifiers, ty, @@ -413,7 +397,7 @@ impl Program<'_> { ty, init, }); - let expr = ctx.expressions.append(Expression::LocalVariable(handle)); + let expr = ctx.add_expression(Expression::LocalVariable(handle), body); ctx.add_local_var(name, expr, mutable); diff --git a/src/front/mod.rs b/src/front/mod.rs index 72242bbc76..15fcfe4940 100644 --- a/src/front/mod.rs +++ b/src/front/mod.rs @@ -14,8 +14,8 @@ use crate::{ /// Helper class to emit expressions #[allow(dead_code)] -#[derive(Default)] -struct Emitter { +#[derive(Default, Debug)] +pub(crate) struct Emitter { start_len: Option, }