[msl-out] Correctly construct out-of-bounds values for all types.

This commit is contained in:
Jim Blandy
2021-12-14 18:01:42 -08:00
committed by Dzmitry Malyshau
parent 8a2fbd360d
commit 3867ef4f6c
5 changed files with 58 additions and 12 deletions

View File

@@ -210,4 +210,6 @@ pub const RESERVED: &[&str] = &[
"M_2_SQRTPI",
"M_SQRT2",
"M_SQRT1_2",
// Naga utilities
"DefaultConstructible",
];

View File

@@ -822,7 +822,7 @@ impl<W: Write> Writer<W> {
{
write!(self.out, " ? ")?;
self.put_access_chain(expr_handle, policy, context)?;
write!(self.out, " : 0")?;
write!(self.out, " : DefaultConstructible()")?;
if !is_scoped {
write!(self.out, ")")?;
@@ -1529,7 +1529,7 @@ impl<W: Write> Writer<W> {
{
write!(self.out, " ? ")?;
self.put_unchecked_load(pointer, policy, context)?;
write!(self.out, " : 0")?;
write!(self.out, " : DefaultConstructible()")?;
if !is_scoped {
write!(self.out, ")")?;
@@ -2154,6 +2154,13 @@ impl<W: Write> Writer<W> {
writeln!(self.out, "#include <simd/simd.h>")?;
writeln!(self.out)?;
if options
.bounds_check_policies
.contains(index::BoundsCheckPolicy::ReadZeroSkipWrite)
{
self.put_default_constructible()?;
}
{
let mut indices = vec![];
for (handle, var) in module.global_variables.iter() {
@@ -2181,6 +2188,28 @@ impl<W: Write> Writer<W> {
self.write_functions(module, info, options, pipeline_options)
}
/// Write the definition for the `DefaultConstructible` class.
///
/// The [`ReadZeroSkipWrite`] bounds check policy requires us to be able to
/// produce 'zero' values for any type, including structs, arrays, and so
/// on. We could do this by emitting default constructor applications, but
/// that would entail printing the name of the type, which is more trouble
/// than you'd think. Instead, we just construct this magic C++14 class that
/// can be converted to any type that can be default constructed, using
/// template parameter inference to detect which type is needed, so we don't
/// have to figure out the name.
///
/// [`ReadZeroSkipWrite`]: index::BoundsCheckPolicy::ReadZeroSkipWrite
fn put_default_constructible(&mut self) -> BackendResult {
writeln!(self.out, "struct DefaultConstructible {{")?;
writeln!(self.out, " template<typename T>")?;
writeln!(self.out, " operator T() && {{")?;
writeln!(self.out, " return T {{}};")?;
writeln!(self.out, " }}")?;
writeln!(self.out, "}};")?;
Ok(())
}
fn write_type_defs(&mut self, module: &crate::Module) -> BackendResult {
for (handle, ty) in module.types.iter() {
if !ty.needs_alias() {