@@ -150,13 +150,98 @@ fn get_name<'a>(names: &FxHashMap<Word, &'a str>, id: Word) -> Cow<'a, str> {
150150 )
151151}
152152
153+ impl Options {
154+ // FIXME(eddyb) using a method on this type seems a bit sketchy.
155+ fn spirt_cleanup_for_dumping ( & self , module : & mut spirt:: Module ) {
156+ if self . spirt_strip_custom_debuginfo_from_dumps {
157+ spirt_passes:: debuginfo:: convert_custom_debuginfo_to_spv ( module) ;
158+ }
159+ if !self . spirt_keep_debug_sources_in_dumps {
160+ const DOTS : & str = "⋯" ;
161+ let dots_interned_str = module. cx ( ) . intern ( DOTS ) ;
162+ let spirt:: ModuleDebugInfo :: Spv ( debuginfo) = & mut module. debug_info ;
163+ for sources in debuginfo. source_languages . values_mut ( ) {
164+ for file in sources. file_contents . values_mut ( ) {
165+ * file = DOTS . into ( ) ;
166+ }
167+ sources. file_contents . insert (
168+ dots_interned_str,
169+ "sources hidden, to show them use \
170+ `RUSTGPU_CODEGEN_ARGS=--spirt-keep-debug-sources-in-dumps`"
171+ . into ( ) ,
172+ ) ;
173+ }
174+ }
175+ }
176+ }
177+
153178pub fn link (
154179 sess : & Session ,
155180 mut inputs : Vec < Module > ,
156181 opts : & Options ,
157182 outputs : & OutputFilenames ,
158183 disambiguated_crate_name_for_dumps : & OsStr ,
159184) -> Result < LinkResult > {
185+ // HACK(eddyb) this is defined here to allow SPIR-T pretty-printing to apply
186+ // to SPIR-V being dumped, outside of e.g. `--dump-spirt-passes`.
187+ // FIXME(eddyb) this isn't used everywhere, sadly - to find those, search
188+ // elsewhere for `.assemble()` and/or `spirv_tools::binary::from_binary`.
189+ let spv_module_to_spv_words_and_spirt_module = |spv_module : & Module | {
190+ let spv_words;
191+ let spv_bytes = {
192+ let _timer = sess. timer ( "assemble-to-spv_bytes-for-spirt" ) ;
193+ spv_words = spv_module. assemble ( ) ;
194+ // FIXME(eddyb) this is wastefully cloning all the bytes, but also
195+ // `spirt::Module` should have a method that takes `Vec<u32>`.
196+ spirv_tools:: binary:: from_binary ( & spv_words) . to_vec ( )
197+ } ;
198+
199+ // FIXME(eddyb) should've really been "spirt::Module::lower_from_spv_bytes".
200+ let _timer = sess. timer ( "spirt::Module::lower_from_spv_file" ) ;
201+ let cx = std:: rc:: Rc :: new ( spirt:: Context :: new ( ) ) ;
202+ crate :: custom_insts:: register_to_spirt_context ( & cx) ;
203+ (
204+ spv_words,
205+ spirt:: Module :: lower_from_spv_bytes ( cx, spv_bytes) ,
206+ )
207+ } ;
208+
209+ let dump_spv_and_spirt = |spv_module : & Module , dump_file_path_stem : PathBuf | {
210+ let ( spv_words, spirt_module_or_err) = spv_module_to_spv_words_and_spirt_module ( spv_module) ;
211+ std:: fs:: write (
212+ dump_file_path_stem. with_extension ( "spv" ) ,
213+ spirv_tools:: binary:: from_binary ( & spv_words) ,
214+ )
215+ . unwrap ( ) ;
216+
217+ // FIXME(eddyb) reify SPIR-V -> SPIR-T errors so they're easier to debug.
218+ if let Ok ( mut module) = spirt_module_or_err {
219+ // HACK(eddyb) avoid pretty-printing massive amounts of unused SPIR-T.
220+ spirt:: passes:: link:: minimize_exports ( & mut module, |export_key| {
221+ matches ! ( export_key, spirt:: ExportKey :: SpvEntryPoint { .. } )
222+ } ) ;
223+
224+ opts. spirt_cleanup_for_dumping ( & mut module) ;
225+
226+ let pretty = spirt:: print:: Plan :: for_module ( & module) . pretty_print ( ) ;
227+
228+ // FIXME(eddyb) don't allocate whole `String`s here.
229+ std:: fs:: write (
230+ dump_file_path_stem. with_extension ( "spirt" ) ,
231+ pretty. to_string ( ) ,
232+ )
233+ . unwrap ( ) ;
234+ std:: fs:: write (
235+ dump_file_path_stem. with_extension ( "spirt.html" ) ,
236+ pretty
237+ . render_to_html ( )
238+ . with_dark_mode_support ( )
239+ . to_html_doc ( ) ,
240+ )
241+ . unwrap ( ) ;
242+ }
243+ } ;
244+
160245 let mut output = {
161246 let _timer = sess. timer ( "link_merge" ) ;
162247 // shift all the ids
@@ -193,12 +278,7 @@ pub fn link(
193278 } ;
194279
195280 if let Some ( dir) = & opts. dump_post_merge {
196- std:: fs:: write (
197- dir. join ( disambiguated_crate_name_for_dumps)
198- . with_extension ( "spv" ) ,
199- spirv_tools:: binary:: from_binary ( & output. assemble ( ) ) ,
200- )
201- . unwrap ( ) ;
281+ dump_spv_and_spirt ( & output, dir. join ( disambiguated_crate_name_for_dumps) ) ;
202282 }
203283
204284 // remove duplicates (https://github.com/KhronosGroup/SPIRV-Tools/blob/e7866de4b1dc2a7e8672867caeb0bdca49f458d3/source/opt/remove_duplicates_pass.cpp)
@@ -401,40 +481,22 @@ pub fn link(
401481 }
402482 } ;
403483
404- let spv_words;
405- let spv_bytes = {
406- let _timer = sess. timer ( "assemble-to-spv_bytes-for-spirt" ) ;
407- spv_words = output. assemble ( ) ;
408- // FIXME(eddyb) this is wastefully cloning all the bytes, but also
409- // `spirt::Module` should have a method that takes `Vec<u32>`.
410- spirv_tools:: binary:: from_binary ( & spv_words) . to_vec ( )
411- } ;
412- let cx = std:: rc:: Rc :: new ( spirt:: Context :: new ( ) ) ;
413- crate :: custom_insts:: register_to_spirt_context ( & cx) ;
414- let mut module = {
415- let _timer = sess. timer ( "spirt::Module::lower_from_spv_file" ) ;
416- match spirt:: Module :: lower_from_spv_bytes ( cx. clone ( ) , spv_bytes) {
417- Ok ( module) => module,
418- Err ( e) => {
419- let spv_path = outputs. temp_path_ext ( "spirt-lower-from-spv-input.spv" , None ) ;
420-
421- let was_saved_msg = match std:: fs:: write (
422- & spv_path,
423- spirv_tools:: binary:: from_binary ( & spv_words) ,
424- ) {
425- Ok ( ( ) ) => format ! ( "was saved to {}" , spv_path. display( ) ) ,
426- Err ( e) => format ! ( "could not be saved: {e}" ) ,
427- } ;
428-
429- return Err ( sess
430- . dcx ( )
431- . struct_err ( format ! ( "{e}" ) )
432- . with_note ( "while lowering SPIR-V module to SPIR-T (spirt::spv::lower)" )
433- . with_note ( format ! ( "input SPIR-V module {was_saved_msg}" ) )
434- . emit ( ) ) ;
435- }
436- }
437- } ;
484+ let ( spv_words, module_or_err) = spv_module_to_spv_words_and_spirt_module ( & output) ;
485+ let mut module = module_or_err. map_err ( |e| {
486+ let spv_path = outputs. temp_path_ext ( "spirt-lower-from-spv-input.spv" , None ) ;
487+
488+ let was_saved_msg =
489+ match std:: fs:: write ( & spv_path, spirv_tools:: binary:: from_binary ( & spv_words) ) {
490+ Ok ( ( ) ) => format ! ( "was saved to {}" , spv_path. display( ) ) ,
491+ Err ( e) => format ! ( "could not be saved: {e}" ) ,
492+ } ;
493+
494+ sess. dcx ( )
495+ . struct_err ( format ! ( "{e}" ) )
496+ . with_note ( "while lowering SPIR-V module to SPIR-T (spirt::spv::lower)" )
497+ . with_note ( format ! ( "input SPIR-V module {was_saved_msg}" ) )
498+ . emit ( )
499+ } ) ?;
438500 // HACK(eddyb) don't dump the unstructured state if not requested, as
439501 // after SPIR-T 0.4.0 it's extremely verbose (due to def-use hermeticity).
440502 if opts. spirt_keep_unstructured_cfg_in_dumps || !opts. structurize {
@@ -499,31 +561,12 @@ pub fn link(
499561 // NOTE(eddyb) this should be *before* `lift_to_spv` below,
500562 // so if that fails, the dump could be used to debug it.
501563 if let Some ( dump_spirt_file_path) = & dump_spirt_file_path {
502- if opts. spirt_strip_custom_debuginfo_from_dumps {
503- for ( _, module) in & mut per_pass_module_for_dumping {
504- spirt_passes:: debuginfo:: convert_custom_debuginfo_to_spv ( module) ;
505- }
506- }
507- if !opts. spirt_keep_debug_sources_in_dumps {
508- for ( _, module) in & mut per_pass_module_for_dumping {
509- let spirt:: ModuleDebugInfo :: Spv ( debuginfo) = & mut module. debug_info ;
510- for sources in debuginfo. source_languages . values_mut ( ) {
511- const DOTS : & str = "⋯" ;
512- for file in sources. file_contents . values_mut ( ) {
513- * file = DOTS . into ( ) ;
514- }
515- sources. file_contents . insert (
516- cx. intern ( DOTS ) ,
517- "sources hidden, to show them use \
518- `RUSTGPU_CODEGEN_ARGS=--spirt-keep-debug-sources-in-dumps`"
519- . into ( ) ,
520- ) ;
521- }
522- }
564+ for ( _, module) in & mut per_pass_module_for_dumping {
565+ opts. spirt_cleanup_for_dumping ( module) ;
523566 }
524567
525568 let plan = spirt:: print:: Plan :: for_versions (
526- & cx ,
569+ module . cx_ref ( ) ,
527570 per_pass_module_for_dumping
528571 . iter ( )
529572 . map ( |( pass, module) | ( format ! ( "after {pass}" ) , module) ) ,
@@ -695,13 +738,8 @@ pub fn link(
695738 file_name. push ( "." ) ;
696739 file_name. push ( file_stem) ;
697740 }
698- file_name. push ( ".spv" ) ;
699741
700- std:: fs:: write (
701- dir. join ( file_name) ,
702- spirv_tools:: binary:: from_binary ( & output. assemble ( ) ) ,
703- )
704- . unwrap ( ) ;
742+ dump_spv_and_spirt ( output, dir. join ( file_name) ) ;
705743 }
706744 // Run DCE again, even if module_output_type == ModuleOutputType::Multiple - the first DCE ran before
707745 // structurization and mem2reg (for perf reasons), and mem2reg may remove references to
0 commit comments