hlsl: factor storage logic into a separate module

This commit is contained in:
Dzmitry Malyshau
2021-07-26 00:24:05 -04:00
committed by Dzmitry Malyshau
parent 284cfcce47
commit e7502d0a9b
4 changed files with 433 additions and 418 deletions

View File

@@ -21,7 +21,7 @@
// int dim_1d = NagaDimensions1D(image_1d);
// ```
use super::{super::FunctionCtx, writer::BackendResult};
use super::{super::FunctionCtx, BackendResult};
use crate::arena::Handle;
use std::fmt::Write;

View File

@@ -9,12 +9,13 @@
mod conv;
mod help;
mod keywords;
mod storage;
mod writer;
use std::fmt::Error as FmtError;
use thiserror::Error;
pub use writer::Writer;
use crate::proc;
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
@@ -69,6 +70,9 @@ impl crate::ImageDimension {
}
}
/// Shorthand result used internally by the backend
type BackendResult = Result<(), Error>;
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
@@ -138,3 +142,18 @@ pub enum Error {
#[error("{0}")]
Custom(String),
}
pub struct Writer<'a, W> {
out: W,
names: crate::FastHashMap<proc::NameKey, String>,
namer: proc::Namer,
/// HLSL backend options
options: &'a Options,
/// Information about entry point arguments wrapped into structure
ep_inputs: Vec<Option<writer::EntryPointBinding>>,
/// Set of expressions that have associated temporary variables
named_expressions: crate::NamedExpressions,
wrapped_array_lengths: crate::FastHashSet<help::WrappedArrayLength>,
wrapped_image_queries: crate::FastHashSet<help::WrappedImageQuery>,
temp_access_chain: Vec<storage::SubAccess>,
}

395
src/back/hlsl/storage.rs Normal file
View File

@@ -0,0 +1,395 @@
use super::{
super::{FunctionCtx, INDENT},
BackendResult, Error,
};
use crate::{
proc::{NameKey, TypeResolution},
Handle,
};
use std::{fmt, mem};
const STORE_TEMP_NAME: &str = "_value";
pub(super) enum SubAccess {
Offset(u32),
Index {
value: Handle<crate::Expression>,
stride: u32,
},
}
pub(super) enum StoreValue {
Expression(Handle<crate::Expression>),
TempIndex {
depth: usize,
index: u32,
ty: TypeResolution,
},
TempAccess {
depth: usize,
base: Handle<crate::Type>,
member_index: u32,
},
}
impl<W: fmt::Write> super::Writer<'_, W> {
fn write_storage_address(
&mut self,
module: &crate::Module,
chain: &[SubAccess],
func_ctx: &FunctionCtx,
) -> BackendResult {
for (i, access) in chain.iter().enumerate() {
if i != 0 {
write!(self.out, "+")?;
}
match *access {
SubAccess::Offset(offset) => {
write!(self.out, "{}", offset)?;
}
SubAccess::Index { value, stride } => {
self.write_expr(module, value, func_ctx)?;
write!(self.out, "*{}", stride)?;
}
}
}
Ok(())
}
fn write_storage_load_sequence<I: Iterator<Item = (TypeResolution, u32)>>(
&mut self,
module: &crate::Module,
var_handle: Handle<crate::GlobalVariable>,
sequence: I,
func_ctx: &FunctionCtx,
) -> BackendResult {
for (i, (ty_resolution, offset)) in sequence.enumerate() {
// add the index temporarily
self.temp_access_chain.push(SubAccess::Offset(offset));
if i != 0 {
write!(self.out, ", ")?;
};
self.write_storage_load(module, var_handle, ty_resolution, func_ctx)?;
self.temp_access_chain.pop();
}
Ok(())
}
/// Helper function to write down the Load operation on a `ByteAddressBuffer`.
pub(super) fn write_storage_load(
&mut self,
module: &crate::Module,
var_handle: Handle<crate::GlobalVariable>,
result_ty: TypeResolution,
func_ctx: &FunctionCtx,
) -> BackendResult {
match *result_ty.inner_with(&module.types) {
crate::TypeInner::Scalar { kind, width: _ } => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
let cast = kind.to_hlsl_cast();
write!(self.out, "{}({}.Load(", cast, var_name)?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, "))")?;
self.temp_access_chain = chain;
}
crate::TypeInner::Vector {
size,
kind,
width: _,
} => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
let cast = kind.to_hlsl_cast();
write!(self.out, "{}({}.Load{}(", cast, var_name, size as u8)?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, "))")?;
self.temp_access_chain = chain;
}
crate::TypeInner::Matrix {
columns,
rows,
width,
} => {
write!(
self.out,
"{}{}x{}(",
crate::ScalarKind::Float.to_hlsl_str(width)?,
columns as u8,
rows as u8,
)?;
let row_stride = width as u32 * rows as u32;
let iter = (0..columns as u32).map(|i| {
let ty_inner = crate::TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
};
(TypeResolution::Value(ty_inner), i * row_stride)
});
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
write!(self.out, ")")?;
}
crate::TypeInner::Array {
base,
size: crate::ArraySize::Constant(const_handle),
..
} => {
write!(self.out, "{{")?;
let count = module.constants[const_handle].to_array_length().unwrap();
let stride = module.types[base].inner.span(&module.constants);
let iter = (0..count).map(|i| (TypeResolution::Handle(base), stride * i));
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
write!(self.out, "}}")?;
}
crate::TypeInner::Struct { ref members, .. } => {
write!(self.out, "{{")?;
let iter = members
.iter()
.map(|m| (TypeResolution::Handle(m.ty), m.offset));
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
write!(self.out, "}}")?;
}
_ => unreachable!(),
}
Ok(())
}
fn write_store_value(
&mut self,
module: &crate::Module,
value: &StoreValue,
func_ctx: &FunctionCtx,
) -> BackendResult {
match *value {
StoreValue::Expression(expr) => self.write_expr(module, expr, &func_ctx)?,
StoreValue::TempIndex {
depth,
index,
ty: _,
} => write!(self.out, "{}{}[{}]", STORE_TEMP_NAME, depth, index)?,
StoreValue::TempAccess {
depth,
base,
member_index,
} => {
let name = &self.names[&NameKey::StructMember(base, member_index)];
write!(self.out, "{}{}.{}", STORE_TEMP_NAME, depth, name)?
}
}
Ok(())
}
/// Helper function to write down the Store operation on a `ByteAddressBuffer`.
pub(super) fn write_storage_store(
&mut self,
module: &crate::Module,
var_handle: Handle<crate::GlobalVariable>,
value: StoreValue,
func_ctx: &FunctionCtx,
indent: usize,
) -> BackendResult {
let temp_resolution;
let ty_resolution = match value {
StoreValue::Expression(expr) => &func_ctx.info[expr].ty,
StoreValue::TempIndex {
depth: _,
index: _,
ref ty,
} => ty,
StoreValue::TempAccess {
depth: _,
base,
member_index,
} => {
let ty_handle = match module.types[base].inner {
crate::TypeInner::Struct { ref members, .. } => {
members[member_index as usize].ty
}
_ => unreachable!(),
};
temp_resolution = TypeResolution::Handle(ty_handle);
&temp_resolution
}
};
match *ty_resolution.inner_with(&module.types) {
crate::TypeInner::Scalar { .. } => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
write!(self.out, "{}{}.Store(", INDENT.repeat(indent), var_name)?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, ", asuint(")?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, "));")?;
self.temp_access_chain = chain;
}
crate::TypeInner::Vector { size, .. } => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
write!(
self.out,
"{}{}.Store{}(",
INDENT.repeat(indent),
var_name,
size as u8
)?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, ", asuint(")?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, "));")?;
self.temp_access_chain = chain;
}
crate::TypeInner::Matrix {
columns,
rows,
width,
} => {
// first, assign the value to a temporary
writeln!(self.out, "{}{{", INDENT.repeat(indent))?;
let depth = indent + 1;
write!(
self.out,
"{}{}{}x{} {}{} = ",
INDENT.repeat(indent + 1),
crate::ScalarKind::Float.to_hlsl_str(width)?,
columns as u8,
rows as u8,
STORE_TEMP_NAME,
depth,
)?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, ";")?;
// then iterate the stores
let row_stride = width as u32 * rows as u32;
for i in 0..columns as u32 {
self.temp_access_chain
.push(SubAccess::Offset(i * row_stride));
let ty_inner = crate::TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
};
let sv = StoreValue::TempIndex {
depth,
index: i,
ty: TypeResolution::Value(ty_inner),
};
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
self.temp_access_chain.pop();
}
// done
writeln!(self.out, "{}}}", INDENT.repeat(indent))?;
}
crate::TypeInner::Array {
base,
size: crate::ArraySize::Constant(const_handle),
..
} => {
// first, assign the value to a temporary
writeln!(self.out, "{}{{", INDENT.repeat(indent))?;
write!(self.out, "{}", INDENT.repeat(indent + 1))?;
self.write_value_type(module, &module.types[base].inner)?;
let depth = indent + 1;
write!(self.out, " {}{}", STORE_TEMP_NAME, depth)?;
self.write_array_size(module, crate::ArraySize::Constant(const_handle))?;
write!(self.out, " = ")?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, ";")?;
// then iterate the stores
let count = module.constants[const_handle].to_array_length().unwrap();
let stride = module.types[base].inner.span(&module.constants);
for i in 0..count {
self.temp_access_chain.push(SubAccess::Offset(i * stride));
let sv = StoreValue::TempIndex {
depth,
index: i,
ty: TypeResolution::Handle(base),
};
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
self.temp_access_chain.pop();
}
// done
writeln!(self.out, "{}}}", INDENT.repeat(indent))?;
}
crate::TypeInner::Struct { ref members, .. } => {
// first, assign the value to a temporary
writeln!(self.out, "{}{{", INDENT.repeat(indent))?;
let depth = indent + 1;
let struct_ty = ty_resolution.handle().unwrap();
let struct_name = &self.names[&NameKey::Type(struct_ty)];
write!(
self.out,
"{}{} {}{} = ",
INDENT.repeat(indent + 1),
struct_name,
STORE_TEMP_NAME,
depth
)?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, ";")?;
// then iterate the stores
for (i, member) in members.iter().enumerate() {
self.temp_access_chain
.push(SubAccess::Offset(member.offset));
let sv = StoreValue::TempAccess {
depth,
base: struct_ty,
member_index: i as u32,
};
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
self.temp_access_chain.pop();
}
// done
writeln!(self.out, "{}}}", INDENT.repeat(indent))?;
}
_ => unreachable!(),
}
Ok(())
}
pub(super) fn fill_access_chain(
&mut self,
module: &crate::Module,
mut cur_expr: Handle<crate::Expression>,
func_ctx: &FunctionCtx,
) -> Result<Handle<crate::GlobalVariable>, Error> {
self.temp_access_chain.clear();
loop {
let stride = func_ctx.info[cur_expr]
.ty
.inner_with(&module.types)
.span(&module.constants);
let (next_expr, sub) = match func_ctx.expressions[cur_expr] {
crate::Expression::GlobalVariable(handle) => return Ok(handle),
crate::Expression::Access { base, index } => (
base,
SubAccess::Index {
value: index,
stride,
},
),
crate::Expression::AccessIndex { base, index } => {
match *func_ctx.info[base].ty.inner_with(&module.types) {
crate::TypeInner::Struct { ref members, .. } => {
(base, SubAccess::Offset(members[index as usize].offset))
}
_ => (base, SubAccess::Offset(index * stride)),
}
}
ref other => {
return Err(Error::Unimplemented(format!(
"Pointer access of {:?}",
other
)))
}
};
self.temp_access_chain.push(sub);
cur_expr = next_expr;
}
}
}

View File

@@ -1,51 +1,20 @@
use super::{
help::{MipLevelCoordinate, WrappedArrayLength, WrappedImageQuery},
Error, Options,
storage::StoreValue,
BackendResult, Error, Options,
};
use crate::{
back,
proc::{self, NameKey},
valid, Handle, Module, ShaderStage, TypeInner,
};
use std::{fmt, mem};
use std::fmt;
const LOCATION_SEMANTIC: &str = "LOC";
const STORE_TEMP_NAME: &str = "_value";
/// Shorthand result used internally by the backend
pub(super) type BackendResult = Result<(), Error>;
#[derive(Copy, Clone, PartialEq)]
enum Io {
Input,
Output,
}
enum SubAccess {
Offset(u32),
Index {
value: Handle<crate::Expression>,
stride: u32,
},
}
enum StoreValue {
Expression(Handle<crate::Expression>),
TempIndex {
depth: usize,
index: u32,
ty: proc::TypeResolution,
},
TempAccess {
depth: usize,
base: Handle<crate::Type>,
member_index: u32,
},
}
/// Structure contains information required for generating
/// wrapped structure of all entry points arguments
struct EntryPointBinding {
pub(super) struct EntryPointBinding {
/// Generated structure name
name: String,
/// Members of generated structure
@@ -53,27 +22,18 @@ struct EntryPointBinding {
}
struct EpStructMember {
pub name: String,
pub ty: Handle<crate::Type>,
pub binding: Option<crate::Binding>,
name: String,
ty: Handle<crate::Type>,
binding: Option<crate::Binding>,
}
pub struct Writer<'a, W> {
pub(super) out: W,
names: crate::FastHashMap<NameKey, String>,
namer: proc::Namer,
/// HLSL backend options
options: &'a Options,
/// Information about entry point arguments wrapped into structure
ep_inputs: Vec<Option<EntryPointBinding>>,
/// Set of expressions that have associated temporary variables
named_expressions: crate::NamedExpressions,
pub(super) wrapped_array_lengths: crate::FastHashSet<WrappedArrayLength>,
pub(super) wrapped_image_queries: crate::FastHashSet<WrappedImageQuery>,
temp_access_chain: Vec<SubAccess>,
#[derive(Copy, Clone, PartialEq)]
enum Io {
Input,
Output,
}
impl<'a, W: fmt::Write> Writer<'a, W> {
impl<'a, W: fmt::Write> super::Writer<'a, W> {
pub fn new(out: W, options: &'a Options) -> Self {
Self {
out,
@@ -524,8 +484,11 @@ impl<'a, W: fmt::Write> Writer<'a, W> {
Ok(())
}
// copy-paste from glsl-out
fn write_array_size(&mut self, module: &Module, size: crate::ArraySize) -> BackendResult {
pub(super) fn write_array_size(
&mut self,
module: &Module,
size: crate::ArraySize,
) -> BackendResult {
write!(self.out, "[")?;
// Write the array size
@@ -1788,366 +1751,4 @@ impl<'a, W: fmt::Write> Writer<'a, W> {
}
Ok(())
}
fn write_storage_address(
&mut self,
module: &Module,
chain: &[SubAccess],
func_ctx: &back::FunctionCtx<'_>,
) -> BackendResult {
for (i, access) in chain.iter().enumerate() {
if i != 0 {
write!(self.out, "+")?;
}
match *access {
SubAccess::Offset(offset) => {
write!(self.out, "{}", offset)?;
}
SubAccess::Index { value, stride } => {
self.write_expr(module, value, func_ctx)?;
write!(self.out, "*{}", stride)?;
}
}
}
Ok(())
}
fn write_storage_load_sequence<I: Iterator<Item = (proc::TypeResolution, u32)>>(
&mut self,
module: &Module,
var_handle: Handle<crate::GlobalVariable>,
sequence: I,
func_ctx: &back::FunctionCtx<'_>,
) -> BackendResult {
for (i, (ty_resolution, offset)) in sequence.enumerate() {
// add the index temporarily
self.temp_access_chain.push(SubAccess::Offset(offset));
if i != 0 {
write!(self.out, ", ")?;
};
self.write_storage_load(module, var_handle, ty_resolution, func_ctx)?;
self.temp_access_chain.pop();
}
Ok(())
}
/// Helper function to write down the Load operation on a `ByteAddressBuffer`.
fn write_storage_load(
&mut self,
module: &Module,
var_handle: Handle<crate::GlobalVariable>,
result_ty: proc::TypeResolution,
func_ctx: &back::FunctionCtx<'_>,
) -> BackendResult {
match *result_ty.inner_with(&module.types) {
TypeInner::Scalar { kind, width: _ } => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
let cast = kind.to_hlsl_cast();
write!(self.out, "{}({}.Load(", cast, var_name)?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, "))")?;
self.temp_access_chain = chain;
}
TypeInner::Vector {
size,
kind,
width: _,
} => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
let cast = kind.to_hlsl_cast();
write!(self.out, "{}({}.Load{}(", cast, var_name, size as u8)?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, "))")?;
self.temp_access_chain = chain;
}
TypeInner::Matrix {
columns,
rows,
width,
} => {
write!(
self.out,
"{}{}x{}(",
crate::ScalarKind::Float.to_hlsl_str(width)?,
columns as u8,
rows as u8,
)?;
let row_stride = width as u32 * rows as u32;
let iter = (0..columns as u32).map(|i| {
let ty_inner = TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
};
(proc::TypeResolution::Value(ty_inner), i * row_stride)
});
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
write!(self.out, ")")?;
}
TypeInner::Array {
base,
size: crate::ArraySize::Constant(const_handle),
..
} => {
write!(self.out, "{{")?;
let count = module.constants[const_handle].to_array_length().unwrap();
let stride = module.types[base].inner.span(&module.constants);
let iter = (0..count).map(|i| (proc::TypeResolution::Handle(base), stride * i));
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
write!(self.out, "}}")?;
}
TypeInner::Struct { ref members, .. } => {
write!(self.out, "{{")?;
let iter = members
.iter()
.map(|m| (proc::TypeResolution::Handle(m.ty), m.offset));
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
write!(self.out, "}}")?;
}
_ => unreachable!(),
}
Ok(())
}
fn write_store_value(
&mut self,
module: &Module,
value: &StoreValue,
func_ctx: &back::FunctionCtx,
) -> BackendResult {
match *value {
StoreValue::Expression(expr) => self.write_expr(module, expr, &func_ctx)?,
StoreValue::TempIndex {
depth,
index,
ty: _,
} => write!(self.out, "{}{}[{}]", STORE_TEMP_NAME, depth, index)?,
StoreValue::TempAccess {
depth,
base,
member_index,
} => {
let name = &self.names[&NameKey::StructMember(base, member_index)];
write!(self.out, "{}{}.{}", STORE_TEMP_NAME, depth, name)?
}
}
Ok(())
}
/// Helper function to write down the Store operation on a `ByteAddressBuffer`.
fn write_storage_store(
&mut self,
module: &Module,
var_handle: Handle<crate::GlobalVariable>,
value: StoreValue,
func_ctx: &back::FunctionCtx<'_>,
indent: usize,
) -> BackendResult {
let temp_resolution;
let ty_resolution = match value {
StoreValue::Expression(expr) => &func_ctx.info[expr].ty,
StoreValue::TempIndex {
depth: _,
index: _,
ref ty,
} => ty,
StoreValue::TempAccess {
depth: _,
base,
member_index,
} => {
let ty_handle = match module.types[base].inner {
TypeInner::Struct { ref members, .. } => members[member_index as usize].ty,
_ => unreachable!(),
};
temp_resolution = proc::TypeResolution::Handle(ty_handle);
&temp_resolution
}
};
match *ty_resolution.inner_with(&module.types) {
TypeInner::Scalar { .. } => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
write!(
self.out,
"{}{}.Store(",
back::INDENT.repeat(indent),
var_name
)?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, ", asuint(")?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, "));")?;
self.temp_access_chain = chain;
}
TypeInner::Vector { size, .. } => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
write!(
self.out,
"{}{}.Store{}(",
back::INDENT.repeat(indent),
var_name,
size as u8
)?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, ", asuint(")?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, "));")?;
self.temp_access_chain = chain;
}
TypeInner::Matrix {
columns,
rows,
width,
} => {
// first, assign the value to a temporary
writeln!(self.out, "{}{{", back::INDENT.repeat(indent))?;
let depth = indent + 1;
write!(
self.out,
"{}{}{}x{} {}{} = ",
back::INDENT.repeat(indent + 1),
crate::ScalarKind::Float.to_hlsl_str(width)?,
columns as u8,
rows as u8,
STORE_TEMP_NAME,
depth,
)?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, ";")?;
// then iterate the stores
let row_stride = width as u32 * rows as u32;
for i in 0..columns as u32 {
self.temp_access_chain
.push(SubAccess::Offset(i * row_stride));
let ty_inner = TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
};
let sv = StoreValue::TempIndex {
depth,
index: i,
ty: proc::TypeResolution::Value(ty_inner),
};
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
self.temp_access_chain.pop();
}
// done
writeln!(self.out, "{}}}", back::INDENT.repeat(indent))?;
}
TypeInner::Array {
base,
size: crate::ArraySize::Constant(const_handle),
..
} => {
// first, assign the value to a temporary
writeln!(self.out, "{}{{", back::INDENT.repeat(indent))?;
write!(self.out, "{}", back::INDENT.repeat(indent + 1))?;
self.write_value_type(module, &module.types[base].inner)?;
let depth = indent + 1;
write!(self.out, " {}{}", STORE_TEMP_NAME, depth)?;
self.write_array_size(module, crate::ArraySize::Constant(const_handle))?;
write!(self.out, " = ")?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, ";")?;
// then iterate the stores
let count = module.constants[const_handle].to_array_length().unwrap();
let stride = module.types[base].inner.span(&module.constants);
for i in 0..count {
self.temp_access_chain.push(SubAccess::Offset(i * stride));
let sv = StoreValue::TempIndex {
depth,
index: i,
ty: proc::TypeResolution::Handle(base),
};
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
self.temp_access_chain.pop();
}
// done
writeln!(self.out, "{}}}", back::INDENT.repeat(indent))?;
}
TypeInner::Struct { ref members, .. } => {
// first, assign the value to a temporary
writeln!(self.out, "{}{{", back::INDENT.repeat(indent))?;
let depth = indent + 1;
let struct_ty = ty_resolution.handle().unwrap();
let struct_name = &self.names[&NameKey::Type(struct_ty)];
write!(
self.out,
"{}{} {}{} = ",
back::INDENT.repeat(indent + 1),
struct_name,
STORE_TEMP_NAME,
depth
)?;
self.write_store_value(module, &value, func_ctx)?;
writeln!(self.out, ";")?;
// then iterate the stores
for (i, member) in members.iter().enumerate() {
self.temp_access_chain
.push(SubAccess::Offset(member.offset));
let sv = StoreValue::TempAccess {
depth,
base: struct_ty,
member_index: i as u32,
};
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
self.temp_access_chain.pop();
}
// done
writeln!(self.out, "{}}}", back::INDENT.repeat(indent))?;
}
_ => unreachable!(),
}
Ok(())
}
fn fill_access_chain(
&mut self,
module: &Module,
mut cur_expr: Handle<crate::Expression>,
func_ctx: &back::FunctionCtx<'_>,
) -> Result<Handle<crate::GlobalVariable>, Error> {
self.temp_access_chain.clear();
loop {
let stride = func_ctx.info[cur_expr]
.ty
.inner_with(&module.types)
.span(&module.constants);
let (next_expr, sub) = match func_ctx.expressions[cur_expr] {
crate::Expression::GlobalVariable(handle) => return Ok(handle),
crate::Expression::Access { base, index } => (
base,
SubAccess::Index {
value: index,
stride,
},
),
crate::Expression::AccessIndex { base, index } => {
match *func_ctx.info[base].ty.inner_with(&module.types) {
TypeInner::Struct { ref members, .. } => {
(base, SubAccess::Offset(members[index as usize].offset))
}
_ => (base, SubAccess::Offset(index * stride)),
}
}
ref other => {
return Err(Error::Unimplemented(format!(
"Pointer access of {:?}",
other
)))
}
};
self.temp_access_chain.push(sub);
cur_expr = next_expr;
}
}
}