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

View File

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

View File

@ -28,13 +28,16 @@ impl<T> RuntimeArray<T> {
/// and lead to UB.
#[spirv_std_macros::gpu_only]
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! {
"%result = OpAccessChain _ {arr} {index}",
"OpReturnValue %result",
"OpStore {result_slot} %result",
arr = in(reg) self,
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
@ -46,12 +49,15 @@ impl<T> RuntimeArray<T> {
/// and lead to UB.
#[spirv_std_macros::gpu_only]
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! {
"%result = OpAccessChain _ {arr} {index}",
"OpReturnValue %result",
"OpStore {result_slot} %result",
arr = in(reg) self,
index = in(reg) index,
options(noreturn),
result_slot = in(reg) result_slot.as_mut_ptr(),
}
result_slot.assume_init()
}
}