1- use super :: { Result , get_name, get_names} ;
1+ use super :: { get_name, get_names} ;
22use rspirv:: dr:: { Block , Function , Module } ;
33use rspirv:: spirv:: { Decoration , ExecutionModel , Op , Word } ;
44use rustc_codegen_spirv_types:: Capability ;
@@ -7,23 +7,32 @@ use rustc_session::Session;
77use std:: iter:: once;
88use std:: mem:: take;
99
10+ /// Error marker type, indicating an integer/float type SPIR-V lacks support for.
11+ struct UnsupportedType ;
12+
1013/// 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 {
1318 8 => Some ( rspirv:: spirv:: Capability :: Int8 ) ,
1419 16 => Some ( rspirv:: spirv:: Capability :: Int16 ) ,
20+ 32 => None ,
1521 64 => Some ( rspirv:: spirv:: Capability :: Int64 ) ,
16- _ => None ,
17- }
22+ _ => return Err ( UnsupportedType ) ,
23+ } )
1824}
1925
2026/// 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 {
2331 16 => Some ( rspirv:: spirv:: Capability :: Float16 ) ,
32+ 32 => None ,
2433 64 => Some ( rspirv:: spirv:: Capability :: Float64 ) ,
25- _ => None ,
26- }
34+ _ => return Err ( UnsupportedType ) ,
35+ } )
2736}
2837
2938pub fn shift_ids ( module : & mut Module , add : u32 ) {
@@ -177,7 +186,7 @@ pub fn name_variables_pass(module: &mut Module) {
177186}
178187
179188// 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 < ( ) > {
181190 let mut visited = vec ! [ false ; module. functions. len( ) ] ;
182191 let mut stack = Vec :: new ( ) ;
183192 let mut names = None ;
@@ -219,7 +228,7 @@ pub fn check_fragment_insts(sess: &Session, module: &Module) -> Result<()> {
219228 names : & mut Option < FxHashMap < Word , & ' m str > > ,
220229 index : usize ,
221230 func_id_to_idx : & FxHashMap < Word , usize > ,
222- ) -> Result < ( ) > {
231+ ) -> super :: Result < ( ) > {
223232 if visited[ index] {
224233 return Ok ( ( ) ) ;
225234 }
@@ -288,7 +297,7 @@ pub fn check_fragment_insts(sess: &Session, module: &Module) -> Result<()> {
288297///
289298/// This function validates that if a module uses types like u8/i8 (requiring Int8),
290299/// 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 < ( ) > {
292301 use rspirv:: spirv:: Capability ;
293302
294303 // Collect declared capabilities
@@ -298,44 +307,48 @@ pub fn check_type_capabilities(sess: &Session, module: &Module) -> Result<()> {
298307 . map ( |inst| inst. operands [ 0 ] . unwrap_capability ( ) )
299308 . collect ( ) ;
300309
301- let mut errors = Vec :: new ( ) ;
310+ let mut missing_caps = vec ! [ ] ;
302311
303312 for inst in & module. types_global_values {
304- match inst. class . opcode {
313+ let ( prefix , width , maybe_required_cap ) = match inst. class . opcode {
305314 Op :: TypeInt => {
306315 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+ )
317323 }
318324 Op :: TypeFloat => {
319325 let width = inst. operands [ 0 ] . unwrap_literal_bit32 ( ) ;
320326
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) )
328328 }
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 ( _) => { }
330343 }
331344 }
332345
333- if !errors . is_empty ( ) {
346+ if !missing_caps . is_empty ( ) {
334347 let mut err = sess
335348 . 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 ) ;
339352 }
340353 Err ( err. emit ( ) )
341354 } else {
@@ -359,13 +372,13 @@ pub fn remove_unused_type_capabilities(module: &mut Module) {
359372 match inst. class . opcode {
360373 Op :: TypeInt => {
361374 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) {
363376 needed_type_capabilities. insert ( cap) ;
364377 }
365378 }
366379 Op :: TypeFloat => {
367380 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) {
369382 needed_type_capabilities. insert ( cap) ;
370383 }
371384 }
@@ -391,7 +404,7 @@ pub fn remove_unused_type_capabilities(module: &mut Module) {
391404
392405/// Remove all [`Decoration::NonUniform`] if this module does *not* have [`Capability::ShaderNonUniform`].
393406/// 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 < ( ) > {
395408 let has_shader_non_uniform_capability = module. capabilities . iter ( ) . any ( |inst| {
396409 inst. class . opcode == Op :: Capability
397410 && inst. operands [ 0 ] . unwrap_capability ( ) == Capability :: ShaderNonUniform
0 commit comments