[glsl-in] Expression emitting

This commit is contained in:
João Capucho
2021-05-20 21:14:49 +01:00
committed by Dzmitry Malyshau
parent a7100b14eb
commit c22fa54642
5 changed files with 482 additions and 394 deletions

View File

@@ -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<GlobalVariable>),
BlockSelect(Handle<GlobalVariable>, u32),
@@ -34,8 +34,9 @@ pub struct Program<'a> {
pub lookup_function: FastHashMap<FunctionSignature, FunctionDeclaration>,
pub lookup_type: FastHashMap<String, Handle<Type>>,
pub lookup_global_variables: FastHashMap<String, GlobalLookup>,
pub lookup_constants: FastHashMap<String, Handle<Constant>>,
pub global_variables: Vec<(String, GlobalLookup)>,
pub constants: Vec<(String, Handle<Constant>)>,
pub entry_args: Vec<(Binding, bool, Handle<GlobalVariable>)>,
pub entries: Vec<(String, ShaderStage, Handle<Function>)>,
@@ -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<Expression>,
ctx: &Context,
root: Handle<Expression>,
meta: SourceMetadata,
) -> Result<Handle<Constant>, 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<Expression>,
expressions: &'function mut Arena<Expression>,
pub locals: &'function mut Arena<LocalVariable>,
pub arguments: &'function mut Vec<FunctionArgument>,
//TODO: Find less allocation heavy representation
pub scopes: Vec<FastHashMap<String, VariableReference>>,
pub lookup_global_var_exps: FastHashMap<String, VariableReference>,
pub lookup_constant_exps: FastHashMap<String, VariableReference>,
pub typifier: Typifier,
pub samplers: FastHashMap<Handle<Expression>, Handle<Expression>>,
pub typifier: Typifier,
pub hir_exprs: Arena<HirExpr>,
emitter: Emitter,
}
impl<'function> Context<'function> {
pub fn new(
program: &mut Program,
body: &mut Block,
expressions: &'function mut Arena<Expression>,
locals: &'function mut Arena<LocalVariable>,
arguments: &'function mut Vec<FunctionArgument>,
) -> 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<Expression> {
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<VariableReference> {
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<VariableReference> {
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<VariableReference> {
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

View File

@@ -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<Expression>, 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 {

View File

@@ -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<Handle<HirExpr>> {
fn parse_primary(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
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<Vec<Handle<HirExpr>>> {
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<Handle<HirExpr>> {
fn parse_postfix(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
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<Handle<HirExpr>> {
fn parse_unary(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
// 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<Handle<HirExpr>>,
min_bp: u8,
) -> Result<Handle<HirExpr>> {
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<Handle<HirExpr>>,
) -> Result<Handle<HirExpr>> {
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<Handle<HirExpr>> {
let tgt = self.parse_unary(ctx)?;
fn parse_assignment(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
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<Handle<HirExpr>> {
let mut expr = self.parse_assignment(ctx)?;
fn parse_expression(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
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),
}
}
}

View File

@@ -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<Option<VariableReference>, 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<Expression>,
name: &str,
meta: SourceMetadata,
) -> Result<Handle<Expression>, 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<Handle<Expression>> = 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);

View File

@@ -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<usize>,
}