From 58d0b23a0fa1894bde5258870ebd3504cf2d09ea 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 | 3 --- .../src/builder/builder_methods.rs | 20 ++++++++++++++++--- .../src/codegen_cx/constant.rs | 4 ++++ crates/rustc_codegen_spirv/src/spirv_type.rs | 3 +++ tests/ui/lang/core/array/array_0.rs | 11 ++++++++++ tests/ui/lang/core/array/array_0.stderr | 8 ++++++++ tests/ui/lang/core/array/array_zst_0.rs | 11 ++++++++++ tests/ui/lang/core/array/gep0.rs | 16 +++++++++++++++ tests/ui/lang/core/array/gep0.stderr | 8 ++++++++ tests/ui/lang/core/array/oob_0_array.rs | 10 ++++++++++ tests/ui/lang/core/array/oob_0_array.stderr | 10 ++++++++++ 11 files changed, 98 insertions(+), 6 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/gep0.stderr 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..2638eb90a2 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -649,9 +649,6 @@ fn trans_aggregate<'tcx>(cx: &CodegenCx<'tcx>, span: Span, ty: TyAndLayout<'tcx> element: element_type, } .def(span, cx) - } else if count == 0 { - // spir-v doesn't support zero-sized arrays - create_zst(cx, span, ty) } 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..ebd6ded1db 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -406,7 +406,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ptr = ptr.strip_ptrcasts(); let mut leaf_ty = match self.lookup_type(ptr.ty) { SpirvType::Pointer { pointee } => pointee, - other => self.fatal(format!("non-pointer type: {other:?}")), + SpirvType::Adt { .. } => return None, + other => self.fatal(format!("adjust_pointer for non-pointer type: {other:?}")), }; // FIXME(eddyb) this isn't efficient, `recover_access_chain_from_offset` @@ -528,8 +529,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,6 +572,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .iter() .map(|index| { result_pointee_type = match self.lookup_type(result_pointee_type) { + SpirvType::Array { count, element } + if self.builder.lookup_const_u64(count) == Some(0) => + { + self.fatal(format!( + "Cannot index into [{}; 0], will panic at runtime.", + self.debug_type(element) + )) + } SpirvType::Array { element, .. } | SpirvType::RuntimeArray { element } => { element } diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs index 04b8d72f91..2524cdd40d 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs @@ -549,6 +549,10 @@ impl<'tcx> CodegenCx<'tcx> { } self.constant_composite(ty, values.into_iter()) } + SpirvType::Array { count, .. } if self.builder.lookup_const_u64(count) == Some(0) => + { + self.undef(ty) + } SpirvType::Array { element, count } => { let count = self.builder.lookup_const_u64(count).unwrap() as usize; let values = (0..count).map(|_| { 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..dad076b490 --- /dev/null +++ b/tests/ui/lang/core/array/array_0.rs @@ -0,0 +1,11 @@ +#![allow(unconditional_panic)] + +// 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..228401a104 --- /dev/null +++ b/tests/ui/lang/core/array/array_0.stderr @@ -0,0 +1,8 @@ +error: Cannot index into [i32; 0], will panic at runtime. + --> $DIR/array_0.rs:10:13 + | +10 | let x = array[0]; + | ^^^^^^^^ + +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..8c87b0e738 --- /dev/null +++ b/tests/ui/lang/core/array/gep0.rs @@ -0,0 +1,16 @@ +// build-fail + +#![cfg_attr(target_arch = "spirv", no_std)] +use spirv_std::spirv; + +fn example() { + let mut array = [0; N]; + for i in 0..N { + array[i] += i; + } +} + +#[spirv(compute(threads(1, 1, 1)))] +pub fn compute() { + example::<0>(); +} diff --git a/tests/ui/lang/core/array/gep0.stderr b/tests/ui/lang/core/array/gep0.stderr new file mode 100644 index 0000000000..a2fbbc2011 --- /dev/null +++ b/tests/ui/lang/core/array/gep0.stderr @@ -0,0 +1,8 @@ +error: Cannot index into [u32; 0], will panic at runtime. + --> $DIR/gep0.rs:9:9 + | +9 | array[i] += i; + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + 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 +