Skip to content

Commit

Permalink
Fix zero-sized Array GEPs
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
JulianKnodt committed Dec 8, 2024
1 parent 1932353 commit 4f9b334
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 7 deletions.
7 changes: 5 additions & 2 deletions crates/rustc_codegen_spirv/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 9 additions & 5 deletions crates/rustc_codegen_spirv/src/builder/builder_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions crates/rustc_codegen_spirv/src/spirv_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/lang/core/array/array_0.rs
Original file line number Diff line number Diff line change
@@ -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];
}
10 changes: 10 additions & 0 deletions tests/ui/lang/core/array/array_0.stderr
Original file line number Diff line number Diff line change
@@ -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

11 changes: 11 additions & 0 deletions tests/ui/lang/core/array/array_zst_0.rs
Original file line number Diff line number Diff line change
@@ -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] = ();
}
}
14 changes: 14 additions & 0 deletions tests/ui/lang/core/array/gep0.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![cfg_attr(target_arch = "spirv", no_std)]
use spirv_std::spirv;

fn example<const LENGTH: usize>() {
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>();
}
10 changes: 10 additions & 0 deletions tests/ui/lang/core/array/oob_0_array.rs
Original file line number Diff line number Diff line change
@@ -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;
}
10 changes: 10 additions & 0 deletions tests/ui/lang/core/array/oob_0_array.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 4f9b334

Please sign in to comment.