Skip to content

Commit d0267ca

Browse files
committed
[0; N] emit a single OpConstantNull rather than an OpConstantComposite with N operands
1 parent 3f7cb64 commit d0267ca

5 files changed

Lines changed: 80 additions & 0 deletions

File tree

crates/rustc_codegen_spirv/src/builder/builder_methods.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ use std::ops::{BitAnd, BitOr, BitXor, Not, RangeInclusive};
3737
use tracing::{Level, instrument, span};
3838
use tracing::{trace, warn};
3939

40+
const LARGE_ARRAY_MEMSET_WARN_THRESHOLD: usize = 1024;
41+
4042
enum ConstValue {
4143
Unsigned(u128),
4244
Signed(i128),
@@ -425,8 +427,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
425427
.def(self)
426428
}
427429
SpirvType::Array { element, count } => {
430+
if fill_byte == 0 {
431+
return self.constant_null(ty.def(self.span(), self)).def(self);
432+
}
428433
let elem_pat = self.memset_const_pattern(&self.lookup_type(element), fill_byte);
429434
let count = self.builder.lookup_const_scalar(count).unwrap() as usize;
435+
if count > LARGE_ARRAY_MEMSET_WARN_THRESHOLD {
436+
self.warn(format!(
437+
"large array of {count} elements with a non-zero fill will generate a \
438+
SPIR-V constant with {count} operands, which may be slow to compile; \
439+
consider using a storage buffer for large data instead"
440+
));
441+
}
430442
self.constant_composite(ty.def(self.span(), self), iter::repeat_n(elem_pat, count))
431443
.def(self)
432444
}
@@ -1928,6 +1940,13 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
19281940
count: u64,
19291941
dest: PlaceRef<'tcx, Self::Value>,
19301942
) {
1943+
if count > LARGE_ARRAY_MEMSET_WARN_THRESHOLD as u64 {
1944+
self.warn(format!(
1945+
"large array of {count} elements with a non-zero fill will generate {count} \
1946+
SPIR-V store instructions, which may be slow to compile; \
1947+
consider using a storage buffer for large data instead"
1948+
));
1949+
}
19311950
let zero = self.const_usize(0);
19321951
let start = dest.project_index(self, zero).val.llval;
19331952

crates/rustc_codegen_spirv/src/builder/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
101101
}
102102
}
103103

104+
#[track_caller]
105+
pub fn warn(&self, msg: impl Into<DiagMessage>) {
106+
if let Some(current_span) = self.current_span {
107+
self.tcx.dcx().span_warn(current_span, msg);
108+
} else {
109+
self.tcx.dcx().warn(msg);
110+
}
111+
}
112+
104113
#[track_caller]
105114
pub fn err(&self, msg: impl Into<DiagMessage>) {
106115
if let Some(current_span) = self.current_span {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Tests that large non-zero-initialized arrays emit a compile warning.
2+
// A `[v; N]` array with non-zero v generates N SPIR-V instructions (either
3+
// store ops or OpConstantComposite operands), which is inherently slow.
4+
5+
// build-pass
6+
7+
#![no_std]
8+
use spirv_std::glam::Vec4;
9+
use spirv_std::spirv;
10+
11+
#[spirv(vertex)]
12+
pub fn test_vs(
13+
#[spirv(push_constant)] index: &u32,
14+
#[spirv(position)] out_pos: &mut Vec4,
15+
) {
16+
let nonzeroed = [1.0f32; 2048];
17+
18+
let i = *index as usize % 2048;
19+
*out_pos = Vec4::new(nonzeroed[i], nonzeroed[i], 0.0, 1.0);
20+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
warning: large array of 2048 elements with a non-zero fill will generate 2048 SPIR-V store instructions, which may be slow to compile; consider using a storage buffer for large data instead
2+
--> $DIR/large_array_nonzero_fill.rs:16:21
3+
|
4+
LL | let nonzeroed = [1.0f32; 2048];
5+
| ^^^^^^^^^^^^^^
6+
7+
warning: 1 warning emitted
8+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Tests that zero-initialized large arrays compile without warnings.
2+
// A `[0; N]` array goes through `memset_const_pattern` with fill_byte=0,
3+
// which should emit a single OpConstantNull
4+
5+
// build-pass
6+
7+
#![no_std]
8+
use spirv_std::glam::Vec4;
9+
use spirv_std::spirv;
10+
11+
#[spirv(vertex)]
12+
pub fn test_vs(
13+
#[spirv(push_constant)] index: &u32,
14+
#[spirv(position)] out_pos: &mut Vec4,
15+
) {
16+
let zeroed = [1.0f32; 2048];
17+
18+
let i = *index as usize % 2048;
19+
*out_pos = Vec4::new(zeroed[i], zeroed[i], 0.0, 1.0);
20+
}
21+
22+
23+
24+

0 commit comments

Comments
 (0)