spirv-std: OpStore into MaybeUninit slots, instead of (UB) OpReturnValue.

This commit is contained in:
Eduard-Mihai Burtescu 2023-03-17 21:18:47 +02:00 committed by Eduard-Mihai Burtescu
parent beecb48e39
commit ee3e42037d
3 changed files with 52 additions and 34 deletions

View File

@ -250,15 +250,18 @@ pub trait IndexUnchecked<T> {
impl<T> IndexUnchecked<T> for [T] { impl<T> IndexUnchecked<T> for [T] {
#[cfg(target_arch = "spirv")] #[cfg(target_arch = "spirv")]
unsafe fn index_unchecked(&self, index: usize) -> &T { unsafe fn index_unchecked(&self, index: usize) -> &T {
asm!( // FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
let mut result_slot = core::mem::MaybeUninit::uninit();
asm! {
"%slice_ptr = OpLoad _ {slice_ptr_ptr}", "%slice_ptr = OpLoad _ {slice_ptr_ptr}",
"%data_ptr = OpCompositeExtract _ %slice_ptr 0", "%data_ptr = OpCompositeExtract _ %slice_ptr 0",
"%val_ptr = OpAccessChain _ %data_ptr {index}", "%result = OpAccessChain _ %data_ptr {index}",
"OpReturnValue %val_ptr", "OpStore {result_slot} %result",
slice_ptr_ptr = in(reg) &self, slice_ptr_ptr = in(reg) &self,
index = in(reg) index, index = in(reg) index,
options(noreturn) result_slot = in(reg) result_slot.as_mut_ptr(),
) }
result_slot.assume_init()
} }
#[cfg(not(target_arch = "spirv"))] #[cfg(not(target_arch = "spirv"))]
@ -268,15 +271,18 @@ impl<T> IndexUnchecked<T> for [T] {
#[cfg(target_arch = "spirv")] #[cfg(target_arch = "spirv")]
unsafe fn index_unchecked_mut(&mut self, index: usize) -> &mut T { unsafe fn index_unchecked_mut(&mut self, index: usize) -> &mut T {
asm!( // FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
let mut result_slot = core::mem::MaybeUninit::uninit();
asm! {
"%slice_ptr = OpLoad _ {slice_ptr_ptr}", "%slice_ptr = OpLoad _ {slice_ptr_ptr}",
"%data_ptr = OpCompositeExtract _ %slice_ptr 0", "%data_ptr = OpCompositeExtract _ %slice_ptr 0",
"%val_ptr = OpAccessChain _ %data_ptr {index}", "%result = OpAccessChain _ %data_ptr {index}",
"OpReturnValue %val_ptr", "OpStore {result_slot} %result",
slice_ptr_ptr = in(reg) &self, slice_ptr_ptr = in(reg) &self,
index = in(reg) index, index = in(reg) index,
options(noreturn) result_slot = in(reg) result_slot.as_mut_ptr(),
) }
result_slot.assume_init()
} }
#[cfg(not(target_arch = "spirv"))] #[cfg(not(target_arch = "spirv"))]
@ -288,13 +294,16 @@ impl<T> IndexUnchecked<T> for [T] {
impl<T, const N: usize> IndexUnchecked<T> for [T; N] { impl<T, const N: usize> IndexUnchecked<T> for [T; N] {
#[cfg(target_arch = "spirv")] #[cfg(target_arch = "spirv")]
unsafe fn index_unchecked(&self, index: usize) -> &T { unsafe fn index_unchecked(&self, index: usize) -> &T {
asm!( // FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
"%val_ptr = OpAccessChain _ {array_ptr} {index}", let mut result_slot = core::mem::MaybeUninit::uninit();
"OpReturnValue %val_ptr", asm! {
"%result = OpAccessChain _ {array_ptr} {index}",
"OpStore {result_slot} %result",
array_ptr = in(reg) self, array_ptr = in(reg) self,
index = in(reg) index, index = in(reg) index,
options(noreturn) result_slot = in(reg) result_slot.as_mut_ptr(),
) }
result_slot.assume_init()
} }
#[cfg(not(target_arch = "spirv"))] #[cfg(not(target_arch = "spirv"))]
@ -304,13 +313,16 @@ impl<T, const N: usize> IndexUnchecked<T> for [T; N] {
#[cfg(target_arch = "spirv")] #[cfg(target_arch = "spirv")]
unsafe fn index_unchecked_mut(&mut self, index: usize) -> &mut T { unsafe fn index_unchecked_mut(&mut self, index: usize) -> &mut T {
asm!( // FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
"%val_ptr = OpAccessChain _ {array_ptr} {index}", let mut result_slot = core::mem::MaybeUninit::uninit();
"OpReturnValue %val_ptr", asm! {
"%result = OpAccessChain _ {array_ptr} {index}",
"OpStore {result_slot} %result",
array_ptr = in(reg) self, array_ptr = in(reg) self,
index = in(reg) index, index = in(reg) index,
options(noreturn) result_slot = in(reg) result_slot.as_mut_ptr(),
) }
result_slot.assume_init()
} }
#[cfg(not(target_arch = "spirv"))] #[cfg(not(target_arch = "spirv"))]

View File

@ -23,16 +23,16 @@ impl AccelerationStructure {
#[doc(alias = "OpConvertUToAccelerationStructureKHR")] #[doc(alias = "OpConvertUToAccelerationStructureKHR")]
#[inline] #[inline]
pub unsafe fn from_u64(id: u64) -> AccelerationStructure { pub unsafe fn from_u64(id: u64) -> AccelerationStructure {
// Since we can't represent an uninitalized opaque type in Rust at the // FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
// moment, we need to create and return the acceleration structure entirely let mut result_slot = core::mem::MaybeUninit::uninit();
// in assembly.
asm! { asm! {
"%ret = OpTypeAccelerationStructureKHR", "%ret = OpTypeAccelerationStructureKHR",
"%result = OpConvertUToAccelerationStructureKHR %ret {id}", "%result = OpConvertUToAccelerationStructureKHR %ret {id}",
"OpReturnValue %result", "OpStore {result_slot} %result",
id = in(reg) id, id = in(reg) id,
options(noreturn) result_slot = in(reg) result_slot.as_mut_ptr(),
} }
result_slot.assume_init()
} }
/// Converts a vector of two 32 bit integers into an [`AccelerationStructure`]. /// Converts a vector of two 32 bit integers into an [`AccelerationStructure`].
@ -42,17 +42,17 @@ impl AccelerationStructure {
#[doc(alias = "OpConvertUToAccelerationStructureKHR")] #[doc(alias = "OpConvertUToAccelerationStructureKHR")]
#[inline] #[inline]
pub unsafe fn from_vec(id: impl Vector<u32, 2>) -> AccelerationStructure { pub unsafe fn from_vec(id: impl Vector<u32, 2>) -> AccelerationStructure {
// Since we can't represent an uninitalized opaque type in Rust at the // FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
// moment, we need to create and return the acceleration structure entirely let mut result_slot = core::mem::MaybeUninit::uninit();
// in assembly.
asm! { asm! {
"%ret = OpTypeAccelerationStructureKHR", "%ret = OpTypeAccelerationStructureKHR",
"%id = OpLoad _ {id}", "%id = OpLoad _ {id}",
"%result = OpConvertUToAccelerationStructureKHR %ret %id", "%result = OpConvertUToAccelerationStructureKHR %ret %id",
"OpReturnValue %result", "OpStore {result_slot} %result",
id = in(reg) &id, id = in(reg) &id,
options(noreturn), result_slot = in(reg) result_slot.as_mut_ptr(),
} }
result_slot.assume_init()
} }
#[spirv_std_macros::gpu_only] #[spirv_std_macros::gpu_only]

View File

@ -28,13 +28,16 @@ impl<T> RuntimeArray<T> {
/// and lead to UB. /// and lead to UB.
#[spirv_std_macros::gpu_only] #[spirv_std_macros::gpu_only]
pub unsafe fn index(&self, index: usize) -> &T { pub unsafe fn index(&self, index: usize) -> &T {
// FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
let mut result_slot = core::mem::MaybeUninit::uninit();
asm! { asm! {
"%result = OpAccessChain _ {arr} {index}", "%result = OpAccessChain _ {arr} {index}",
"OpReturnValue %result", "OpStore {result_slot} %result",
arr = in(reg) self, arr = in(reg) self,
index = in(reg) index, index = in(reg) index,
options(noreturn), result_slot = in(reg) result_slot.as_mut_ptr(),
} }
result_slot.assume_init()
} }
/// Index the array, returning a mutable reference to an element. Unfortunately, because the /// Index the array, returning a mutable reference to an element. Unfortunately, because the
@ -46,12 +49,15 @@ impl<T> RuntimeArray<T> {
/// and lead to UB. /// and lead to UB.
#[spirv_std_macros::gpu_only] #[spirv_std_macros::gpu_only]
pub unsafe fn index_mut(&mut self, index: usize) -> &mut T { pub unsafe fn index_mut(&mut self, index: usize) -> &mut T {
// FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
let mut result_slot = core::mem::MaybeUninit::uninit();
asm! { asm! {
"%result = OpAccessChain _ {arr} {index}", "%result = OpAccessChain _ {arr} {index}",
"OpReturnValue %result", "OpStore {result_slot} %result",
arr = in(reg) self, arr = in(reg) self,
index = in(reg) index, index = in(reg) index,
options(noreturn), result_slot = in(reg) result_slot.as_mut_ptr(),
} }
result_slot.assume_init()
} }
} }