1
- use super :: { Result , get_name, get_names} ;
1
+ use super :: { get_name, get_names} ;
2
2
use rspirv:: dr:: { Block , Function , Module } ;
3
3
use rspirv:: spirv:: { Decoration , ExecutionModel , Op , Word } ;
4
4
use rustc_codegen_spirv_types:: Capability ;
@@ -7,23 +7,32 @@ use rustc_session::Session;
7
7
use std:: iter:: once;
8
8
use std:: mem:: take;
9
9
10
+ /// Error marker type, indicating an integer/float type SPIR-V lacks support for.
11
+ struct UnsupportedType ;
12
+
10
13
/// Returns the capability required for an integer type of the given width, if any.
11
- fn capability_for_int_width ( width : u32 ) -> Option < rspirv:: spirv:: Capability > {
12
- match width {
14
+ fn capability_for_int_width (
15
+ width : u32 ,
16
+ ) -> Result < Option < rspirv:: spirv:: Capability > , UnsupportedType > {
17
+ Ok ( match width {
13
18
8 => Some ( rspirv:: spirv:: Capability :: Int8 ) ,
14
19
16 => Some ( rspirv:: spirv:: Capability :: Int16 ) ,
20
+ 32 => None ,
15
21
64 => Some ( rspirv:: spirv:: Capability :: Int64 ) ,
16
- _ => None ,
17
- }
22
+ _ => return Err ( UnsupportedType ) ,
23
+ } )
18
24
}
19
25
20
26
/// Returns the capability required for a float type of the given width, if any.
21
- fn capability_for_float_width ( width : u32 ) -> Option < rspirv:: spirv:: Capability > {
22
- match width {
27
+ fn capability_for_float_width (
28
+ width : u32 ,
29
+ ) -> Result < Option < rspirv:: spirv:: Capability > , UnsupportedType > {
30
+ Ok ( match width {
23
31
16 => Some ( rspirv:: spirv:: Capability :: Float16 ) ,
32
+ 32 => None ,
24
33
64 => Some ( rspirv:: spirv:: Capability :: Float64 ) ,
25
- _ => None ,
26
- }
34
+ _ => return Err ( UnsupportedType ) ,
35
+ } )
27
36
}
28
37
29
38
pub fn shift_ids ( module : & mut Module , add : u32 ) {
@@ -177,7 +186,7 @@ pub fn name_variables_pass(module: &mut Module) {
177
186
}
178
187
179
188
// Some instructions are only valid in fragment shaders. Check them.
180
- pub fn check_fragment_insts ( sess : & Session , module : & Module ) -> Result < ( ) > {
189
+ pub fn check_fragment_insts ( sess : & Session , module : & Module ) -> super :: Result < ( ) > {
181
190
let mut visited = vec ! [ false ; module. functions. len( ) ] ;
182
191
let mut stack = Vec :: new ( ) ;
183
192
let mut names = None ;
@@ -219,7 +228,7 @@ pub fn check_fragment_insts(sess: &Session, module: &Module) -> Result<()> {
219
228
names : & mut Option < FxHashMap < Word , & ' m str > > ,
220
229
index : usize ,
221
230
func_id_to_idx : & FxHashMap < Word , usize > ,
222
- ) -> Result < ( ) > {
231
+ ) -> super :: Result < ( ) > {
223
232
if visited[ index] {
224
233
return Ok ( ( ) ) ;
225
234
}
@@ -288,7 +297,7 @@ pub fn check_fragment_insts(sess: &Session, module: &Module) -> Result<()> {
288
297
///
289
298
/// This function validates that if a module uses types like u8/i8 (requiring Int8),
290
299
/// u16/i16 (requiring Int16), etc., the corresponding capabilities are declared.
291
- pub fn check_type_capabilities ( sess : & Session , module : & Module ) -> Result < ( ) > {
300
+ pub fn check_type_capabilities ( sess : & Session , module : & Module ) -> super :: Result < ( ) > {
292
301
use rspirv:: spirv:: Capability ;
293
302
294
303
// Collect declared capabilities
@@ -298,44 +307,48 @@ pub fn check_type_capabilities(sess: &Session, module: &Module) -> Result<()> {
298
307
. map ( |inst| inst. operands [ 0 ] . unwrap_capability ( ) )
299
308
. collect ( ) ;
300
309
301
- let mut errors = Vec :: new ( ) ;
310
+ let mut missing_caps = vec ! [ ] ;
302
311
303
312
for inst in & module. types_global_values {
304
- match inst. class . opcode {
313
+ let ( prefix , width , maybe_required_cap ) = match inst. class . opcode {
305
314
Op :: TypeInt => {
306
315
let width = inst. operands [ 0 ] . unwrap_literal_bit32 ( ) ;
307
- let signedness = inst. operands [ 1 ] . unwrap_literal_bit32 ( ) != 0 ;
308
- let type_name = if signedness { "i" } else { "u" } ;
309
-
310
- if let Some ( required_cap) = capability_for_int_width ( width)
311
- && !declared_capabilities. contains ( & required_cap)
312
- {
313
- errors. push ( format ! (
314
- "`{type_name}{width}` type used without `OpCapability {required_cap:?}`"
315
- ) ) ;
316
- }
316
+ let signed = inst. operands [ 1 ] . unwrap_literal_bit32 ( ) != 0 ;
317
+
318
+ (
319
+ if signed { "i" } else { "u" } ,
320
+ width,
321
+ capability_for_int_width ( width) ,
322
+ )
317
323
}
318
324
Op :: TypeFloat => {
319
325
let width = inst. operands [ 0 ] . unwrap_literal_bit32 ( ) ;
320
326
321
- if let Some ( required_cap) = capability_for_float_width ( width)
322
- && !declared_capabilities. contains ( & required_cap)
323
- {
324
- errors. push ( format ! (
325
- "`f{width}` type used without `OpCapability {required_cap:?}`"
326
- ) ) ;
327
- }
327
+ ( "f" , width, capability_for_float_width ( width) )
328
328
}
329
- _ => { }
329
+ _ => continue ,
330
+ } ;
331
+
332
+ match maybe_required_cap {
333
+ Err ( UnsupportedType ) => {
334
+ sess. dcx ( )
335
+ . err ( format ! ( "`{prefix}{width}` unsupported in SPIR-V" ) ) ;
336
+ }
337
+ Ok ( Some ( required_cap) ) if !declared_capabilities. contains ( & required_cap) => {
338
+ missing_caps. push ( format ! (
339
+ "`{prefix}{width}` type used without `OpCapability {required_cap:?}`"
340
+ ) ) ;
341
+ }
342
+ Ok ( _) => { }
330
343
}
331
344
}
332
345
333
- if !errors . is_empty ( ) {
346
+ if !missing_caps . is_empty ( ) {
334
347
let mut err = sess
335
348
. dcx ( )
336
- . struct_err ( "Missing required capabilities for types" ) ;
337
- for error in errors {
338
- err = err . with_note ( error ) ;
349
+ . struct_err ( "missing required capabilities for types" ) ;
350
+ for msg in missing_caps {
351
+ err. note ( msg ) ;
339
352
}
340
353
Err ( err. emit ( ) )
341
354
} else {
@@ -359,13 +372,13 @@ pub fn remove_unused_type_capabilities(module: &mut Module) {
359
372
match inst. class . opcode {
360
373
Op :: TypeInt => {
361
374
let width = inst. operands [ 0 ] . unwrap_literal_bit32 ( ) ;
362
- if let Some ( cap) = capability_for_int_width ( width) {
375
+ if let Ok ( Some ( cap) ) = capability_for_int_width ( width) {
363
376
needed_type_capabilities. insert ( cap) ;
364
377
}
365
378
}
366
379
Op :: TypeFloat => {
367
380
let width = inst. operands [ 0 ] . unwrap_literal_bit32 ( ) ;
368
- if let Some ( cap) = capability_for_float_width ( width) {
381
+ if let Ok ( Some ( cap) ) = capability_for_float_width ( width) {
369
382
needed_type_capabilities. insert ( cap) ;
370
383
}
371
384
}
@@ -391,7 +404,7 @@ pub fn remove_unused_type_capabilities(module: &mut Module) {
391
404
392
405
/// Remove all [`Decoration::NonUniform`] if this module does *not* have [`Capability::ShaderNonUniform`].
393
406
/// This allows image asm to always declare `NonUniform` and not worry about conditional compilation.
394
- pub fn remove_non_uniform_decorations ( _sess : & Session , module : & mut Module ) -> Result < ( ) > {
407
+ pub fn remove_non_uniform_decorations ( _sess : & Session , module : & mut Module ) -> super :: Result < ( ) > {
395
408
let has_shader_non_uniform_capability = module. capabilities . iter ( ) . any ( |inst| {
396
409
inst. class . opcode == Op :: Capability
397
410
&& inst. operands [ 0 ] . unwrap_capability ( ) == Capability :: ShaderNonUniform
0 commit comments