Move the global usage into the IR function

This commit is contained in:
Dzmitry Malyshau
2020-03-20 12:54:51 -04:00
committed by Dzmitry Malyshau
parent 55fab04353
commit 3ea6ca428f
6 changed files with 45 additions and 84 deletions

View File

@@ -22,8 +22,7 @@ use std::{
use crate::{
arena::Handle,
proc::GlobalUse,
FastHashMap, FastHashSet
FastHashMap,
};
/// Expect all the global variables to have a pointer type,
@@ -226,7 +225,7 @@ impl AsName for Option<String> {
struct TypedGlobalVariable<'a> {
module: &'a crate::Module,
handle: crate::Handle<crate::GlobalVariable>,
usage: GlobalUse,
usage: crate::GlobalUse,
}
impl Display for TypedGlobalVariable<'_> {
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), FmtError> {
@@ -236,7 +235,7 @@ impl Display for TypedGlobalVariable<'_> {
spirv::StorageClass::Uniform |
spirv::StorageClass::UniformConstant |
spirv::StorageClass::StorageBuffer => {
let space = if self.usage.contains(GlobalUse::STORE) {
let space = if self.usage.contains(crate::GlobalUse::STORE) {
"device "
} else {
"constant "
@@ -773,9 +772,8 @@ impl<W: Write> Writer<W> {
let fun_name = fun.name.or_index(fun_handle);
// find the entry point(s) and inputs/outputs
let mut exec_model = None;
let global_use = GlobalUse::scan(fun, &module.global_variables);
let mut last_used_global = None;
for ((handle, var), &usage) in module.global_variables.iter().zip(global_use.iter()) {
for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) {
match var.class {
spirv::StorageClass::Input => {
if let Some(crate::Binding::Location(_)) = var.binding {
@@ -789,12 +787,8 @@ impl<W: Write> Writer<W> {
last_used_global = Some(handle);
}
}
let mut var_inputs = FastHashSet::default();
let mut var_outputs = FastHashSet::default();
for ep in module.entry_points.iter() {
if ep.function == fun_handle{
var_inputs.extend(ep.inputs.iter().cloned());
var_outputs.extend(ep.outputs.iter().cloned());
if ep.function == fun_handle {
if exec_model.is_some() {
if exec_model != Some(ep.exec_model) {
return Err(Error::MixedExecutionModels(fun_handle));
@@ -819,8 +813,10 @@ impl<W: Write> Writer<W> {
if em != spirv::ExecutionModel::GLCompute {
writeln!(self.out, "struct {} {{", location_input_name)?;
for &handle in var_inputs.iter() {
let var = &module.global_variables[handle];
for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) {
if var.class != spirv::StorageClass::Input || !usage.contains(crate::GlobalUse::LOAD) {
continue
}
// if it's a struct, lift all the built-in contents up to the root
let mut ty_handle = var.ty;
if GLOBAL_POINTERS {
@@ -839,7 +835,7 @@ impl<W: Write> Writer<W> {
}
} else {
if let Some(ref binding@crate::Binding::Location(_)) = var.binding {
let tyvar = TypedGlobalVariable { module, handle, usage: GlobalUse::empty() };
let tyvar = TypedGlobalVariable { module, handle, usage: crate::GlobalUse::empty() };
let resolved = options.resolve_binding(binding, in_mode)?;
writeln!(self.out, "\t{} [[{}]];", tyvar, resolved)?;
}
@@ -847,8 +843,10 @@ impl<W: Write> Writer<W> {
}
writeln!(self.out, "}};")?;
writeln!(self.out, "struct {} {{", output_name)?;
for &handle in var_outputs.iter() {
let var = &module.global_variables[handle];
for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) {
if var.class != spirv::StorageClass::Output || !usage.contains(crate::GlobalUse::STORE) {
continue
}
// if it's a struct, lift all the built-in contents up to the root
let mut ty_handle = var.ty;
if GLOBAL_POINTERS {
@@ -867,7 +865,7 @@ impl<W: Write> Writer<W> {
writeln!(self.out, "\t{} {} [[{}]];", ty_name, name, resolved)?;
}
} else {
let tyvar = TypedGlobalVariable { module, handle, usage: GlobalUse::empty() };
let tyvar = TypedGlobalVariable { module, handle, usage: crate::GlobalUse::empty() };
write!(self.out, "\t{}", tyvar)?;
if let Some(ref binding) = var.binding {
let resolved = options.resolve_binding(binding, out_mode)?;
@@ -885,7 +883,7 @@ impl<W: Write> Writer<W> {
writeln!(self.out, "{} void {}(", em_str, fun_name)?;
}
for ((handle, var), &usage) in module.global_variables.iter().zip(global_use.iter()) {
for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) {
if usage.is_empty() || var.class == spirv::StorageClass::Output {
continue
}

View File

@@ -732,22 +732,11 @@ impl<I: Iterator<Item = u32>> Parser<I> {
module.entry_points.reserve(entry_points.len());
for raw in entry_points {
let mut ep = crate::EntryPoint {
module.entry_points.push(crate::EntryPoint {
exec_model: raw.exec_model,
name: raw.name,
function: *self.lookup_function.lookup(raw.function_id)?,
inputs: FastHashSet::default(),
outputs: FastHashSet::default(),
};
for var_id in raw.variable_ids {
let handle = self.lookup_variable.lookup(var_id)?.handle;
match module.global_variables[handle].class {
spirv::StorageClass::Input => ep.inputs.insert(handle),
spirv::StorageClass::Output => ep.outputs.insert(handle),
other => return Err(Error::InvalidVariableClass(other)),
};
}
module.entry_points.push(ep);
});
}
Ok(module)
@@ -1405,6 +1394,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
} else {
Some(self.lookup_type.lookup(result_type)?.handle)
},
global_usage: Vec::new(),
local_variables: Arena::new(),
expressions: self.make_expression_storage(),
body: Vec::new(),
@@ -1447,6 +1437,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
}
}
// done
fun.global_usage = crate::GlobalUse::scan(&fun.expressions, &fun.body, &module.global_variables);
let handle = module.functions.append(fun);
self.lookup_function.insert(fun_id, handle);
self.lookup_expression.clear();

View File

@@ -1,7 +1,7 @@
use crate::{
arena::{Arena, Handle},
proc::{GlobalUse, Typifier, ResolveError},
FastHashMap, FastHashSet,
proc::{Typifier, ResolveError},
FastHashMap,
};
@@ -1205,12 +1205,15 @@ impl Parser {
global_vars: &module.global_variables,
})?;
// done
let global_usage = crate::GlobalUse::scan(&expressions, &body, &module.global_variables);
self.scopes.pop();
let fun = crate::Function {
name: Some(fun_name.to_owned()),
control: spirv::FunctionControl::empty(),
parameter_types,
return_type,
global_usage,
local_variables,
expressions,
body,
@@ -1341,43 +1344,13 @@ impl Parser {
lexer.expect(Token::Operation('='))?;
let fun_ident = lexer.next_ident()?;
lexer.expect(Token::Separator(';'))?;
let (fun_handle, function) = module.functions
let (fun_handle, _) = module.functions
.iter()
.find(|(_, fun)| fun.name.as_ref().map(|s| s.as_str()) == Some(fun_ident))
.ok_or(Error::UnknownFunction(fun_ident))?;
let uses = GlobalUse::scan(function, &module.global_variables);
let mut inputs = FastHashSet::default();
let mut outputs = FastHashSet::default();
for ((handle, var), &usage) in module.global_variables.iter().zip(uses.iter()) {
match var.class {
_ if usage.is_empty() => {}
spirv::StorageClass::Input if usage.contains(GlobalUse::LOAD) => {
inputs.insert(handle);
}
spirv::StorageClass::Output if usage.contains(GlobalUse::STORE) => {
outputs.insert(handle);
}
spirv::StorageClass::Input |
spirv::StorageClass::Output => {
let name = lookup_global_expression
.iter()
.find(|&(_, h)| match *h {
crate::Expression::GlobalVariable(h) => h == handle,
_ => false,
})
.map(|(name, _)| name)
.unwrap();
return Err(Error::MutabilityViolation(name));
}
_ => {}
}
}
module.entry_points.push(crate::EntryPoint {
exec_model,
name: export_name.unwrap_or(fun_ident).to_owned(),
inputs,
outputs,
function: fun_handle,
});
}

View File

@@ -117,6 +117,13 @@ pub enum Binding {
Descriptor { set: spirv::Word, binding: spirv::Word },
}
bitflags::bitflags! {
pub struct GlobalUse: u8 {
const LOAD = 0x1;
const STORE = 0x2;
}
}
#[derive(Clone, Debug)]
pub struct GlobalVariable {
pub name: Option<String>,
@@ -271,6 +278,7 @@ pub struct Function {
pub control: spirv::FunctionControl,
pub parameter_types: Vec<Handle<Type>>,
pub return_type: Option<Handle<Type>>,
pub global_usage: Vec<GlobalUse>,
pub local_variables: Arena<LocalVariable>,
pub expressions: Arena<Expression>,
pub body: Block,
@@ -280,8 +288,6 @@ pub struct Function {
pub struct EntryPoint {
pub exec_model: spirv::ExecutionModel,
pub name: String,
pub inputs: FastHashSet<Handle<GlobalVariable>>,
pub outputs: FastHashSet<Handle<GlobalVariable>>,
pub function: Handle<Function>,
}

View File

@@ -2,16 +2,9 @@ use crate::{
arena::{Arena, Handle},
};
bitflags::bitflags! {
pub struct GlobalUse: u8 {
const LOAD = 0x1;
const STORE = 0x2;
}
}
struct Interface<'a> {
expressions: &'a Arena<crate::Expression>,
uses: Vec<GlobalUse>,
uses: Vec<crate::GlobalUse>,
}
impl<'a> Interface<'a> {
@@ -33,7 +26,7 @@ impl<'a> Interface<'a> {
}
E::FunctionParameter(_) => {},
E::GlobalVariable(handle) => {
self.uses[handle.index()] |= GlobalUse::LOAD;
self.uses[handle.index()] |= crate::GlobalUse::LOAD;
}
E::LocalVariable(_) => {}
E::Load { pointer } => {
@@ -117,7 +110,7 @@ impl<'a> Interface<'a> {
left = base;
}
crate::Expression::GlobalVariable(handle) => {
self.uses[handle.index()] |= GlobalUse::STORE;
self.uses[handle.index()] |= crate::GlobalUse::STORE;
break;
}
_ => break,
@@ -130,16 +123,17 @@ impl<'a> Interface<'a> {
}
}
impl GlobalUse {
impl crate::GlobalUse {
pub fn scan(
fun: &crate::Function,
expressions: &Arena<crate::Expression>,
body: &[crate::Statement],
globals: &Arena<crate::GlobalVariable>,
) -> Box<[Self]> {
) -> Vec<Self> {
let mut io = Interface {
expressions: &fun.expressions,
uses: vec![GlobalUse::empty(); globals.len()],
expressions,
uses: vec![crate::GlobalUse::empty(); globals.len()],
};
io.collect(&fun.body);
io.uses.into_boxed_slice()
io.collect(body);
io.uses
}
}

View File

@@ -1,5 +1,4 @@
mod interface;
mod typifier;
pub use interface::GlobalUse;
pub use typifier::{ResolveError, Typifier};