From 4f9b334519e4e9ce80e352dde369e541f8170be6 Mon Sep 17 00:00:00 2001 From: julianknodt Date: Sat, 7 Dec 2024 00:16:20 -0800 Subject: [PATCH] Fix zero-sized Array GEPs Previously GEP on zero-sized arrays, would fail. This change fixes arrays to instead emit runtime arrays. I do not know if this will lead to any runtime cost, but it fixes all the compile errors. --- crates/rustc_codegen_spirv/src/abi.rs | 7 +++++-- .../src/builder/builder_methods.rs | 14 +++++++++----- crates/rustc_codegen_spirv/src/spirv_type.rs | 3 +++ tests/ui/lang/core/array/array_0.rs | 9 +++++++++ tests/ui/lang/core/array/array_0.stderr | 10 ++++++++++ tests/ui/lang/core/array/array_zst_0.rs | 11 +++++++++++ tests/ui/lang/core/array/gep0.rs | 14 ++++++++++++++ tests/ui/lang/core/array/oob_0_array.rs | 10 ++++++++++ tests/ui/lang/core/array/oob_0_array.stderr | 10 ++++++++++ 9 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 tests/ui/lang/core/array/array_0.rs create mode 100644 tests/ui/lang/core/array/array_0.stderr create mode 100644 tests/ui/lang/core/array/array_zst_0.rs create mode 100644 tests/ui/lang/core/array/gep0.rs create mode 100644 tests/ui/lang/core/array/oob_0_array.rs create mode 100644 tests/ui/lang/core/array/oob_0_array.stderr diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index 44188bfc5c..656e4fe0a4 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -650,8 +650,11 @@ fn trans_aggregate<'tcx>(cx: &CodegenCx<'tcx>, span: Span, ty: TyAndLayout<'tcx> } .def(span, cx) } else if count == 0 { - // spir-v doesn't support zero-sized arrays - create_zst(cx, span, ty) + // create a run-time array instead of ZST ADT + SpirvType::RuntimeArray { + element: element_type, + } + .def(span, cx) } else { let count_const = cx.constant_u32(span, count as u32); let element_spv = cx.lookup_type(element_type); diff --git a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index c97a8a2ecb..0f3c6b112f 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -528,8 +528,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let stride = ty_kind.sizeof(self)?; ty_size = MaybeSized::Sized(stride); - indices.push((offset.bytes() / stride.bytes()).try_into().ok()?); - offset = Size::from_bytes(offset.bytes() % stride.bytes()); + if stride.bytes() == 0 { + indices.push(0); + offset = Size::from_bytes(0); + } else { + indices.push((offset.bytes() / stride.bytes()).try_into().ok()?); + offset = Size::from_bytes(offset.bytes() % stride.bytes()); + } } _ => return None, } @@ -566,9 +571,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .iter() .map(|index| { result_pointee_type = match self.lookup_type(result_pointee_type) { - SpirvType::Array { element, .. } | SpirvType::RuntimeArray { element } => { - element - } + SpirvType::Array { element, .. } + | SpirvType::RuntimeArray { element } => element, _ => self.fatal(format!( "GEP not implemented for type {}", self.debug_type(result_pointee_type) diff --git a/crates/rustc_codegen_spirv/src/spirv_type.rs b/crates/rustc_codegen_spirv/src/spirv_type.rs index f4ebd399bb..31f425a307 100644 --- a/crates/rustc_codegen_spirv/src/spirv_type.rs +++ b/crates/rustc_codegen_spirv/src/spirv_type.rs @@ -368,6 +368,9 @@ impl SpirvType<'_> { .bytes(), ) .expect("alignof: Vectors must have power-of-2 size"), + Self::Array { count, .. } if cx.builder.lookup_const_u64(count) == Some(0) => { + Align::from_bytes(0).unwrap() + } Self::Array { element, .. } | Self::RuntimeArray { element } | Self::Matrix { element, .. } => cx.lookup_type(element).alignof(cx), diff --git a/tests/ui/lang/core/array/array_0.rs b/tests/ui/lang/core/array/array_0.rs new file mode 100644 index 0000000000..eda74a17c6 --- /dev/null +++ b/tests/ui/lang/core/array/array_0.rs @@ -0,0 +1,9 @@ +// build-fail +#![cfg_attr(target_arch = "spirv", no_std)] +use spirv_std::spirv; + +#[spirv(compute(threads(1, 1, 1)))] +pub fn compute() { + let array = [0; 0]; + let x = array[0]; +} diff --git a/tests/ui/lang/core/array/array_0.stderr b/tests/ui/lang/core/array/array_0.stderr new file mode 100644 index 0000000000..db0acae848 --- /dev/null +++ b/tests/ui/lang/core/array/array_0.stderr @@ -0,0 +1,10 @@ +error: this operation will panic at runtime + --> $DIR/array_0.rs:8:13 + | +8 | let x = array[0]; + | ^^^^^^^^ index out of bounds: the length is 0 but the index is 0 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/lang/core/array/array_zst_0.rs b/tests/ui/lang/core/array/array_zst_0.rs new file mode 100644 index 0000000000..7c144f98f5 --- /dev/null +++ b/tests/ui/lang/core/array/array_zst_0.rs @@ -0,0 +1,11 @@ +// build-pass +#![cfg_attr(target_arch = "spirv", no_std)] +use spirv_std::spirv; + +#[spirv(compute(threads(1, 1, 1)))] +pub fn compute() { + let mut array = [(); 0]; + for i in 0..array.len() { + array[i] = (); + } +} diff --git a/tests/ui/lang/core/array/gep0.rs b/tests/ui/lang/core/array/gep0.rs new file mode 100644 index 0000000000..d093c8d36c --- /dev/null +++ b/tests/ui/lang/core/array/gep0.rs @@ -0,0 +1,14 @@ +#![cfg_attr(target_arch = "spirv", no_std)] +use spirv_std::spirv; + +fn example() { + let mut array = [0; LENGTH]; + for i in 0..array.len() { + array[i] += i; + } +} + +#[spirv(compute(threads(1, 1, 1)))] +pub fn compute() { + example::<0>(); +} diff --git a/tests/ui/lang/core/array/oob_0_array.rs b/tests/ui/lang/core/array/oob_0_array.rs new file mode 100644 index 0000000000..d980dcead7 --- /dev/null +++ b/tests/ui/lang/core/array/oob_0_array.rs @@ -0,0 +1,10 @@ +// build-fail + +#![cfg_attr(target_arch = "spirv", no_std)] +use spirv_std::spirv; + +#[spirv(compute(threads(1, 1, 1)))] +pub fn compute() { + let mut array = [0; 0]; + array[0] = 1; +} diff --git a/tests/ui/lang/core/array/oob_0_array.stderr b/tests/ui/lang/core/array/oob_0_array.stderr new file mode 100644 index 0000000000..4f85c8483f --- /dev/null +++ b/tests/ui/lang/core/array/oob_0_array.stderr @@ -0,0 +1,10 @@ +error: this operation will panic at runtime + --> $DIR/oob_0_array.rs:9:5 + | +9 | array[0] = 1; + | ^^^^^^^^ index out of bounds: the length is 0 but the index is 0 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to 1 previous error +