Terminator processor, used in WGSL and GLSL frontends

This commit is contained in:
Dzmitry Malyshau 2020-12-04 15:03:53 -05:00 committed by Dzmitry Malyshau
parent f18443a79d
commit 5fe9429a63
4 changed files with 55 additions and 10 deletions

View File

@ -5,10 +5,15 @@ pomelo! {
//%verbose;
%include {
use super::super::{error::ErrorKind, token::*, ast::*};
use crate::{proc::Typifier, Arena, BinaryOperator, Binding, Block, Constant,
ConstantInner, EntryPoint, Expression, FallThrough, FastHashMap, Function, GlobalVariable, Handle, Interpolation,
LocalVariable, MemberOrigin, SampleLevel, ScalarKind, Statement, StorageAccess,
StorageClass, StructMember, Type, TypeInner, UnaryOperator};
use crate::{
proc::{ensure_block_returns, Typifier},
Arena, BinaryOperator, Binding, Block, Constant,
ConstantInner, EntryPoint, Expression, FallThrough,
FastHashMap, Function, GlobalVariable, Handle, Interpolation,
LocalVariable, MemberOrigin, SampleLevel, ScalarKind,
Statement, StorageAccess,
StorageClass, StructMember, Type, TypeInner, UnaryOperator,
};
}
%token #[derive(Debug)] #[cfg_attr(test, derive(PartialEq))] pub enum Token {};
%parser pub struct Parser<'a> {};
@ -1117,11 +1122,7 @@ pomelo! {
extra.context.clear_scopes();
extra.context.lookup_global_var_exps.clear();
extra.context.typifier = Typifier::new();
// make sure function ends with return
match cs.last() {
Some(Statement::Return {..}) => {}
_ => {cs.push(Statement::Return { value:None });}
}
ensure_block_returns(&mut cs);
f.body = cs;
f.fill_global_use(&extra.module.global_variables);
f

View File

@ -7,7 +7,7 @@ mod lexer;
use crate::{
arena::{Arena, Handle},
proc::{ResolveContext, ResolveError, Typifier},
proc::{ensure_block_returns, ResolveContext, ResolveError, Typifier},
FastHashMap,
};
@ -1594,6 +1594,8 @@ impl Parser {
arguments: &fun.arguments,
},
)?;
// fixup the IR
ensure_block_returns(&mut fun.body);
// done
fun.fill_global_use(&module.global_variables);
self.scopes.pop();

View File

@ -4,6 +4,7 @@
mod call_graph;
mod interface;
mod namer;
mod terminator;
mod typifier;
mod validator;
@ -11,6 +12,7 @@ mod validator;
pub use call_graph::{CallGraph, CallGraphBuilder};
pub use interface::{Interface, Visitor};
pub use namer::{EntryPointIndex, NameKey, Namer};
pub use terminator::ensure_block_returns;
pub use typifier::{check_constant_type, ResolveContext, ResolveError, Typifier};
pub use validator::{ValidationError, Validator};

40
src/proc/terminator.rs Normal file
View File

@ -0,0 +1,40 @@
/// Ensure that the given block has return statements
/// at the end of its control flow.
///
/// Note: we don't want to blindly append a return statement
/// to the end, because it may be either redundant or invalid,
/// e.g. when the user already has returns in if/else branches.
pub fn ensure_block_returns(block: &mut crate::Block) {
match block.last_mut() {
Some(&mut crate::Statement::Block(ref mut b)) => {
ensure_block_returns(b);
}
Some(&mut crate::Statement::If {
condition: _,
ref mut accept,
ref mut reject,
}) => {
ensure_block_returns(accept);
ensure_block_returns(reject);
}
Some(&mut crate::Statement::Switch {
selector: _,
ref mut cases,
ref mut default,
}) => {
for case in cases.values_mut() {
if let (ref mut b, None) = *case {
ensure_block_returns(b);
}
}
ensure_block_returns(default);
}
Some(&mut crate::Statement::Break)
| Some(&mut crate::Statement::Continue)
| Some(&mut crate::Statement::Return { .. })
| Some(&mut crate::Statement::Kill) => (),
Some(&mut crate::Statement::Loop { .. })
| Some(&mut crate::Statement::Store { .. })
| None => block.push(crate::Statement::Return { value: None }),
}
}