Skip to content

Commit ad8c6f7

Browse files
committed
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.
1 parent 1932353 commit ad8c6f7

File tree

16 files changed

+144
-6
lines changed

16 files changed

+144
-6
lines changed

crates/rustc_codegen_spirv/src/abi.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -649,9 +649,6 @@ fn trans_aggregate<'tcx>(cx: &CodegenCx<'tcx>, span: Span, ty: TyAndLayout<'tcx>
649649
element: element_type,
650650
}
651651
.def(span, cx)
652-
} else if count == 0 {
653-
// spir-v doesn't support zero-sized arrays
654-
create_zst(cx, span, ty)
655652
} else {
656653
let count_const = cx.constant_u32(span, count as u32);
657654
let element_spv = cx.lookup_type(element_type);

crates/rustc_codegen_spirv/src/builder/builder_methods.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
406406
let ptr = ptr.strip_ptrcasts();
407407
let mut leaf_ty = match self.lookup_type(ptr.ty) {
408408
SpirvType::Pointer { pointee } => pointee,
409-
other => self.fatal(format!("non-pointer type: {other:?}")),
409+
SpirvType::Adt { .. } => return None,
410+
other => self.fatal(format!("adjust_pointer for non-pointer type: {other:?}")),
410411
};
411412

412413
// FIXME(eddyb) this isn't efficient, `recover_access_chain_from_offset`
@@ -528,8 +529,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
528529
let stride = ty_kind.sizeof(self)?;
529530
ty_size = MaybeSized::Sized(stride);
530531

531-
indices.push((offset.bytes() / stride.bytes()).try_into().ok()?);
532-
offset = Size::from_bytes(offset.bytes() % stride.bytes());
532+
if stride.bytes() == 0 {
533+
indices.push(0);
534+
offset = Size::from_bytes(0);
535+
} else {
536+
indices.push((offset.bytes() / stride.bytes()).try_into().ok()?);
537+
offset = Size::from_bytes(offset.bytes() % stride.bytes());
538+
}
533539
}
534540
_ => return None,
535541
}
@@ -566,6 +572,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
566572
.iter()
567573
.map(|index| {
568574
result_pointee_type = match self.lookup_type(result_pointee_type) {
575+
SpirvType::Array { count, element }
576+
if self.builder.lookup_const_u64(count) == Some(0) =>
577+
{
578+
self.fatal(format!(
579+
"evaluation of constant value failed: cannot index into [{}; 0]",
580+
self.debug_type(element)
581+
))
582+
}
569583
SpirvType::Array { element, .. } | SpirvType::RuntimeArray { element } => {
570584
element
571585
}

crates/rustc_codegen_spirv/src/codegen_cx/constant.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,9 @@ impl<'tcx> CodegenCx<'tcx> {
549549
}
550550
self.constant_composite(ty, values.into_iter())
551551
}
552+
SpirvType::Array { count, .. } if self.builder.lookup_const_u64(count) == Some(0) => {
553+
self.undef(ty)
554+
}
552555
SpirvType::Array { element, count } => {
553556
let count = self.builder.lookup_const_u64(count).unwrap() as usize;
554557
let values = (0..count).map(|_| {

crates/rustc_codegen_spirv/src/spirv_type.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ impl SpirvType<'_> {
368368
.bytes(),
369369
)
370370
.expect("alignof: Vectors must have power-of-2 size"),
371+
Self::Array { count, .. } if cx.builder.lookup_const_u64(count) == Some(0) => {
372+
Align::from_bytes(0).unwrap()
373+
}
371374
Self::Array { element, .. }
372375
| Self::RuntimeArray { element }
373376
| Self::Matrix { element, .. } => cx.lookup_type(element).alignof(cx),

tests/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ the resulting binary with spirv-val). Because of this, there might be some stran
2121
the point isn't to make a fully functional shader every time (that would take an annoying amount of
2222
effort), but rather validate that specific parts of the compiler are doing their job correctly
2323
(either succeeding as they should, or erroring as they should).
24+
25+
For more docs on compiletests, check the [rustc docs](https://rustc-dev-guide.rust-lang.org/tests/compiletest.html).

tests/ui/lang/core/array/array_0.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![allow(unconditional_panic)]
2+
3+
// build-fail
4+
#![cfg_attr(target_arch = "spirv", no_std)]
5+
use spirv_std::spirv;
6+
7+
#[spirv(compute(threads(1, 1, 1)))]
8+
pub fn compute() {
9+
let array = [0; 0];
10+
let x = array[0];
11+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: evaluation of constant value failed: cannot index into [i32; 0]
2+
--> $DIR/array_0.rs:10:13
3+
|
4+
10 | let x = array[0];
5+
| ^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// build-fail
2+
#![allow(unconditional_panic)]
3+
4+
#![cfg_attr(target_arch = "spirv", no_std)]
5+
use spirv_std::spirv;
6+
7+
// note that &mut [usize; 0] will cause an even worse panic
8+
#[spirv(compute(threads(1, 1, 1)))]
9+
pub fn compute(m: [usize; 0]) {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: entry point parameter type not yet supported (`[usize; 0]` has size `0`)
2+
--> $DIR/array_entry_param.rs:9:19
3+
|
4+
9 | pub fn compute(m: [usize; 0]) {}
5+
| ^^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// build-pass
2+
#![cfg_attr(target_arch = "spirv", no_std)]
3+
use spirv_std::spirv;
4+
5+
#[spirv(compute(threads(1, 1, 1)))]
6+
pub fn compute() {
7+
let mut array = [(); 0];
8+
for i in 0..array.len() {
9+
array[i] = ();
10+
}
11+
let () = array[0];
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: this operation will panic at runtime
2+
--> $DIR/array_zst_0.rs:11:14
3+
|
4+
11 | let () = array[0];
5+
| ^^^^^^^^ index out of bounds: the length is 0 but the index is 0
6+
|
7+
= note: `#[deny(unconditional_panic)]` on by default
8+
9+
error: aborting due to 1 previous error
10+

tests/ui/lang/core/array/gep0.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// build-fail
2+
3+
#![cfg_attr(target_arch = "spirv", no_std)]
4+
use spirv_std::spirv;
5+
6+
fn example<const N: usize>() {
7+
let mut array = [0; N];
8+
for i in 0..N {
9+
array[i] += i;
10+
}
11+
}
12+
13+
#[spirv(compute(threads(1, 1, 1)))]
14+
pub fn compute() {
15+
example::<0>();
16+
}

tests/ui/lang/core/array/gep0.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: evaluation of constant value failed: cannot index into [u32; 0]
2+
--> $DIR/gep0.rs:9:9
3+
|
4+
9 | array[i] += i;
5+
| ^^^^^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// build-pass
2+
// compile-flags: -C llvm-args=--disassemble-entry=compute
3+
#![allow(unconditional_panic)]
4+
5+
#![cfg_attr(target_arch = "spirv", no_std)]
6+
use spirv_std::spirv;
7+
8+
#[spirv(compute(threads(1, 1, 1)))]
9+
pub fn compute() {
10+
let mut array = [0; 0];
11+
// writes to an array compile fine although they should be a panic.
12+
// (&mut array)[0] = 1; // this fails to compile, but it seems that below is
13+
// optimized out, and I'm not sure where.
14+
// GEP is not being hit, and neither is any load/store.
15+
array[0] = 1;
16+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
%1 = OpFunction %2 None %3
2+
%4 = OpLabel
3+
OpLine %5 15 4
4+
%6 = OpULessThan %7 %8 %8
5+
OpNoLine
6+
OpSelectionMerge %9 None
7+
OpBranchConditional %6 %10 %11
8+
%10 = OpLabel
9+
OpBranch %9
10+
%11 = OpLabel
11+
OpReturn
12+
%9 = OpLabel
13+
OpReturn
14+
OpFunctionEnd
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![cfg_attr(target_arch = "spirv", no_std)]
2+
use spirv_std::spirv;
3+
4+
#[spirv(compute(threads(1, 1, 1)))]
5+
pub fn compute() {
6+
let array = [0; 0];
7+
}

0 commit comments

Comments
 (0)