@@ -150,13 +150,98 @@ fn get_name<'a>(names: &FxHashMap<Word, &'a str>, id: Word) -> Cow<'a, str> {
150
150
)
151
151
}
152
152
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
+
153
178
pub fn link (
154
179
sess : & Session ,
155
180
mut inputs : Vec < Module > ,
156
181
opts : & Options ,
157
182
outputs : & OutputFilenames ,
158
183
disambiguated_crate_name_for_dumps : & OsStr ,
159
184
) -> 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
+
160
245
let mut output = {
161
246
let _timer = sess. timer ( "link_merge" ) ;
162
247
// shift all the ids
@@ -193,12 +278,7 @@ pub fn link(
193
278
} ;
194
279
195
280
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) ) ;
202
282
}
203
283
204
284
// remove duplicates (https://github.com/KhronosGroup/SPIRV-Tools/blob/e7866de4b1dc2a7e8672867caeb0bdca49f458d3/source/opt/remove_duplicates_pass.cpp)
@@ -401,40 +481,22 @@ pub fn link(
401
481
}
402
482
} ;
403
483
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
+ } ) ?;
438
500
// HACK(eddyb) don't dump the unstructured state if not requested, as
439
501
// after SPIR-T 0.4.0 it's extremely verbose (due to def-use hermeticity).
440
502
if opts. spirt_keep_unstructured_cfg_in_dumps || !opts. structurize {
@@ -499,31 +561,12 @@ pub fn link(
499
561
// NOTE(eddyb) this should be *before* `lift_to_spv` below,
500
562
// so if that fails, the dump could be used to debug it.
501
563
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) ;
523
566
}
524
567
525
568
let plan = spirt:: print:: Plan :: for_versions (
526
- & cx ,
569
+ module . cx_ref ( ) ,
527
570
per_pass_module_for_dumping
528
571
. iter ( )
529
572
. map ( |( pass, module) | ( format ! ( "after {pass}" ) , module) ) ,
@@ -695,13 +738,8 @@ pub fn link(
695
738
file_name. push ( "." ) ;
696
739
file_name. push ( file_stem) ;
697
740
}
698
- file_name. push ( ".spv" ) ;
699
741
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) ) ;
705
743
}
706
744
// Run DCE again, even if module_output_type == ModuleOutputType::Multiple - the first DCE ran before
707
745
// structurization and mem2reg (for perf reasons), and mem2reg may remove references to
0 commit comments