mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[msl-out] Correctly construct out-of-bounds values for all types.
This commit is contained in:
committed by
Dzmitry Malyshau
parent
8a2fbd360d
commit
3867ef4f6c
@@ -210,4 +210,6 @@ pub const RESERVED: &[&str] = &[
|
||||
"M_2_SQRTPI",
|
||||
"M_SQRT2",
|
||||
"M_SQRT1_2",
|
||||
// Naga utilities
|
||||
"DefaultConstructible",
|
||||
];
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -148,6 +148,11 @@ impl BoundsCheckPolicies {
|
||||
_ => self.index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if any of `self`'s policies are `policy`.
|
||||
pub fn contains(&self, policy: BoundsCheckPolicy) -> bool {
|
||||
self.index == policy || self.buffer == policy || self.image == policy
|
||||
}
|
||||
}
|
||||
|
||||
/// An index that may be statically known, or may need to be computed at runtime.
|
||||
@@ -204,9 +209,7 @@ pub fn find_checked_indexes(
|
||||
let mut guarded_indices = BitSet::new();
|
||||
|
||||
// Don't bother scanning if we never need `ReadZeroSkipWrite`.
|
||||
if policies.index == BoundsCheckPolicy::ReadZeroSkipWrite
|
||||
|| policies.buffer == BoundsCheckPolicy::ReadZeroSkipWrite
|
||||
{
|
||||
if policies.contains(BoundsCheckPolicy::ReadZeroSkipWrite) {
|
||||
for (_handle, expr) in function.expressions.iter() {
|
||||
// There's no need to handle `AccessIndex` expressions, as their
|
||||
// indices never need to be cached.
|
||||
|
||||
Reference in New Issue
Block a user