Skip to content

Commit

Permalink
[glsl-in] const eval as soon as possible
Browse files Browse the repository at this point in the history
  • Loading branch information
teoxoy committed Jun 9, 2023
1 parent 667cedf commit 09d2431
Show file tree
Hide file tree
Showing 26 changed files with 575 additions and 612 deletions.
2 changes: 1 addition & 1 deletion src/front/glsl/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1789,7 +1789,7 @@ impl MacroCall {
true => {
let offset_arg = args[num_args];
num_args += 1;
match ctx.eval_constant(offset_arg, meta) {
match ctx.lift_up_const_expression(offset_arg) {
Ok(v) => Some(v),
Err(e) => {
frontend.errors.push(e);
Expand Down
82 changes: 58 additions & 24 deletions src/front/glsl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,17 @@ pub struct Context<'a> {
pub symbol_table: crate::front::SymbolTable<String, VariableReference>,
pub samplers: FastHashMap<Handle<Expression>, Handle<Expression>>,

pub const_typifier: Typifier,
pub typifier: Typifier,
emitter: Emitter,
stmt_ctx: Option<StmtContext>,
pub body: Block,
pub module: &'a mut crate::Module,
pub is_const: bool,
}

impl<'a> Context<'a> {
pub fn new(frontend: &Frontend, module: &'a mut crate::Module) -> Result<Self> {
pub fn new(frontend: &Frontend, module: &'a mut crate::Module, is_const: bool) -> Result<Self> {
let mut this = Context {
expressions: Arena::new(),
locals: Arena::new(),
Expand All @@ -91,18 +93,21 @@ impl<'a> Context<'a> {
symbol_table: crate::front::SymbolTable::default(),
samplers: FastHashMap::default(),

const_typifier: Typifier::new(),
typifier: Typifier::new(),
emitter: Emitter::default(),
stmt_ctx: Some(StmtContext::new()),
body: Block::new(),
module,
is_const: false,
};

this.emit_start();

for &(ref name, lookup) in frontend.global_variables.iter() {
this.add_global(name, lookup)?
}
this.is_const = is_const;

Ok(this)
}
Expand Down Expand Up @@ -237,15 +242,43 @@ impl<'a> Context<'a> {
}

pub fn add_expression(&mut self, expr: Expression, meta: Span) -> Result<Handle<Expression>> {
let needs_pre_emit = expr.needs_pre_emit();
if needs_pre_emit {
self.emit_end();
}
let handle = self.expressions.append(expr, meta);
if needs_pre_emit {
self.emit_start();
let mut append = |arena: &mut Arena<Expression>, expr: Expression, span| {
let is_running = self.emitter.is_running();
let needs_pre_emit = expr.needs_pre_emit();
if is_running && needs_pre_emit {
self.body.extend(self.emitter.finish(arena));
}
let h = arena.append(expr, span);
if is_running && needs_pre_emit {
self.emitter.start(arena);
}
h
};

let (expressions, const_expressions) = if self.is_const {
(&mut self.module.const_expressions, None)
} else {
(&mut self.expressions, Some(&self.module.const_expressions))
};

let mut eval = crate::proc::ConstantEvaluator {
types: &mut self.module.types,
constants: &self.module.constants,
expressions,
const_expressions,
append: (!self.is_const).then_some(&mut append),
};

let res = eval.try_eval_and_append(&expr, meta).map_err(|e| Error {
kind: e.into(),
meta,
});

match res {
Ok(expr) => Ok(expr),
Err(e) if self.is_const => Err(e),
Err(_) => Ok(append(&mut self.expressions, expr, meta)),
}
Ok(handle)
}

/// Add variable to current scope
Expand Down Expand Up @@ -509,13 +542,16 @@ impl<'a> Context<'a> {

let handle = match *kind {
HirExprKind::Access { base, index } => {
let (index, index_meta) =
self.lower_expect_inner(stmt, frontend, index, ExprPos::Rhs)?;
let (index, _) = self.lower_expect_inner(stmt, frontend, index, ExprPos::Rhs)?;
let maybe_constant_index = match pos {
// Don't try to generate `AccessIndex` if in a LHS position, since it
// wouldn't produce a pointer.
ExprPos::Lhs => None,
_ => self.eval_constant(index, index_meta).ok(),
_ => self
.module
.to_ctx()
.eval_expr_to_u32_from(index, &self.expressions)
.ok(),
};

let base = self
Expand All @@ -528,15 +564,7 @@ impl<'a> Context<'a> {
.0;

let pointer = maybe_constant_index
.and_then(|const_expr| {
Some(self.add_expression(
Expression::AccessIndex {
base,
index: self.module.to_ctx().eval_expr_to_u32(const_expr).ok()?,
},
meta,
))
})
.map(|index| self.add_expression(Expression::AccessIndex { base, index }, meta))
.unwrap_or_else(|| {
self.add_expression(Expression::Access { base, index }, meta)
})?;
Expand Down Expand Up @@ -578,8 +606,8 @@ impl<'a> Context<'a> {
self.typifier_grow(left, left_meta)?;
self.typifier_grow(right, right_meta)?;

let left_inner = self.typifier.get(left, &self.module.types);
let right_inner = self.typifier.get(right, &self.module.types);
let left_inner = self.get_type(left);
let right_inner = self.get_type(right);

match (left_inner, right_inner) {
(
Expand Down Expand Up @@ -1006,7 +1034,13 @@ impl<'a> Context<'a> {
_ if var.load => {
self.add_expression(Expression::Load { pointer: var.expr }, meta)?
}
ExprPos::Rhs => var.expr,
ExprPos::Rhs => {
if let Some((constant, _)) = self.is_const.then_some(var.constant).flatten() {
self.add_expression(Expression::Constant(constant), meta)?
} else {
var.expr
}
}
},
HirExprKind::Call(ref call) if pos != ExprPos::Lhs => {
let maybe_expr = frontend.function_or_constructor_call(
Expand Down
10 changes: 4 additions & 6 deletions src/front/glsl/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,10 +531,8 @@ impl Frontend {
}

// Check if the passed arguments require any special variations
let mut variations = builtin_required_variations(
args.iter()
.map(|&(expr, _)| ctx.typifier.get(expr, &ctx.module.types)),
);
let mut variations =
builtin_required_variations(args.iter().map(|&(expr, _)| ctx.get_type(expr)));

// Initiate the declaration if it wasn't previously initialized and inject builtins
let declaration = self.lookup_function.entry(name.clone()).or_insert_with(|| {
Expand Down Expand Up @@ -592,7 +590,7 @@ impl Frontend {
ctx.typifier_grow(call_argument.0, call_argument.1)?;

let overload_param_ty = &ctx.module.types[*overload_parameter].inner;
let call_arg_ty = ctx.typifier.get(call_argument.0, &ctx.module.types);
let call_arg_ty = ctx.get_type(call_argument.0);

log::trace!(
"Testing parameter {}\n\tOverload = {:?}\n\tCall = {:?}",
Expand Down Expand Up @@ -937,7 +935,7 @@ impl Frontend {
ctx.typifier_grow(call_argument.0, call_argument.1)?;

let overload_param_ty = &ctx.module.types[parameter_ty].inner;
let call_arg_ty = ctx.typifier.get(call_argument.0, &ctx.module.types);
let call_arg_ty = ctx.get_type(call_argument.0);
let needs_conversion = call_arg_ty != overload_param_ty;

let arg_scalar_comps = scalar_components(call_arg_ty);
Expand Down
6 changes: 3 additions & 3 deletions src/front/glsl/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl<'source> ParsingContext<'source> {
let mut module = Module::default();

// Body and expression arena for global initialization
let mut ctx = Context::new(frontend, &mut module)?;
let mut ctx = Context::new(frontend, &mut module, false)?;

while self.peek(frontend).is_some() {
self.parse_external_declaration(frontend, &mut ctx)?;
Expand Down Expand Up @@ -220,13 +220,13 @@ impl<'source> ParsingContext<'source> {
frontend: &mut Frontend,
module: &mut Module,
) -> Result<(Handle<Expression>, Span)> {
let mut ctx = Context::new(frontend, module)?;
let mut ctx = Context::new(frontend, module, true)?;

let mut stmt_ctx = ctx.stmt_ctx();
let expr = self.parse_conditional(frontend, &mut ctx, &mut stmt_ctx, None)?;
let (root, meta) = ctx.lower_expect(stmt_ctx, frontend, expr, ExprPos::Rhs)?;

Ok((ctx.eval_constant(root, meta)?, meta))
Ok((root, meta))
}
}

Expand Down
32 changes: 16 additions & 16 deletions src/front/glsl/parser/declarations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,15 @@ impl<'source> ParsingContext<'source> {
// returns Ok(None) rather than an error if there is not one
self.parse_array_specifier(frontend, ctx.ctx, &mut meta, &mut ty)?;

let is_global_const =
ctx.qualifiers.storage.0 == StorageQualifier::Const && ctx.external;

let init = self
.bump_if(frontend, TokenValue::Assign)
.map::<Result<_>, _>(|_| {
let prev_const = ctx.ctx.is_const;
ctx.ctx.is_const = is_global_const;

let (mut expr, init_meta) = self.parse_initializer(frontend, ty, ctx.ctx)?;

let scalar_components = scalar_components(&ctx.ctx.module.types[ty].inner);
Expand All @@ -232,32 +238,26 @@ impl<'source> ParsingContext<'source> {
.implicit_conversion(&mut expr, init_meta, kind, width)?;
}

ctx.ctx.is_const = prev_const;

meta.subsume(init_meta);

Ok((expr, init_meta))
Ok(expr)
})
.transpose()?;

let is_const = ctx.qualifiers.storage.0 == StorageQualifier::Const;
let maybe_const_expr = if ctx.external {
if let Some((root, meta)) = init {
match ctx.ctx.eval_constant(root, meta) {
Ok(res) => Some(res),
// If the declaration is external (global scope) and is constant qualified
// then the initializer must be a constant expression
Err(err) if is_const => return Err(err),
_ => None,
}
} else {
None
}
let maybe_const_expr = if is_global_const {
init
} else if ctx.external {
init.and_then(|expr| ctx.ctx.lift_up_const_expression(expr).ok())
} else {
None
// init.filter(|expr| ctx.ctx.expressions.is_const(*expr))
};

let pointer = ctx.add_var(frontend, ty, name, maybe_const_expr, meta)?;

if let Some((value, _)) = init.filter(|_| maybe_const_expr.is_none()) {
if let Some(value) = init.filter(|_| maybe_const_expr.is_none()) {
ctx.ctx.emit_restart();
ctx.ctx.body.push(Statement::Store { pointer, value }, meta);
}
Expand Down Expand Up @@ -317,7 +317,7 @@ impl<'source> ParsingContext<'source> {

let result = ty.map(|ty| FunctionResult { ty, binding: None });

let mut context = Context::new(frontend, ctx.module)?;
let mut context = Context::new(frontend, ctx.module, false)?;

self.parse_function_args(frontend, &mut context)?;

Expand Down
Loading

0 comments on commit 09d2431

Please sign in to comment.