605605< a href =#605 id =605 data-nosnippet > 605</ a > function.blocks[block].instructions.insert(< span class ="number "> 0</ span > , phi);
606606< a href =#606 id =606 data-nosnippet > 606</ a > }
607607< a href =#607 id =607 data-nosnippet > 607</ a > < span class ="kw "> super</ span > ::apply_rewrite_rules(< span class ="kw-2 "> &</ span > rewrite_rules, < span class ="kw-2 "> &mut </ span > function.blocks);
608- < a href =#608 id =608 data-nosnippet > 608</ a > }</ code > </ pre > </ div > </ section > </ main > </ body > </ html >
608+ < a href =#608 id =608 data-nosnippet > 608</ a > }
609+ < a href =#609 id =609 data-nosnippet > 609</ a >
610+ < a href =#610 id =610 data-nosnippet > 610</ a > < span class ="doccomment "> /// Fold `OpLoad` from Private/Function storage class variables that have constant initializers.
611+ < a href =#611 id =611 data-nosnippet > 611</ a > ///
612+ < a href =#612 id =612 data-nosnippet > 612</ a > /// This optimization handles patterns like:
613+ < a href =#613 id =613 data-nosnippet > 613</ a > /// ```text
614+ < a href =#614 id =614 data-nosnippet > 614</ a > /// %ptr = OpVariable %_ptr_Private_T Private %initializer
615+ < a href =#615 id =615 data-nosnippet > 615</ a > /// %val = OpLoad %T %ptr
616+ < a href =#616 id =616 data-nosnippet > 616</ a > /// ```
617+ < a href =#617 id =617 data-nosnippet > 617</ a > /// After this optimization, uses of `%val` are replaced with `%initializer`.
618+ < a href =#618 id =618 data-nosnippet > 618</ a > ///
619+ < a href =#619 id =619 data-nosnippet > 619</ a > /// This is particularly important for pointer-to-pointer constants (e.g., `&&123`)
620+ < a href =#620 id =620 data-nosnippet > 620</ a > /// where the outer pointer variable has a known initializer (the inner pointer).
621+ < a href =#621 id =621 data-nosnippet > 621</ a > /// Without this optimization, such patterns generate invalid SPIR-V in Logical
622+ < a href =#622 id =622 data-nosnippet > 622</ a > /// addressing mode (pointer-to-pointer with Private storage class is not allowed).
623+ < a href =#623 id =623 data-nosnippet > 623</ a > </ span > < span class ="kw "> pub fn </ span > fold_load_from_constant_variable(module: < span class ="kw-2 "> &mut </ span > Module) {
624+ < a href =#624 id =624 data-nosnippet > 624</ a > < span class ="kw "> use </ span > rspirv::spirv::StorageClass;
625+ < a href =#625 id =625 data-nosnippet > 625</ a >
626+ < a href =#626 id =626 data-nosnippet > 626</ a > < span class ="comment "> // Build a map of variable ID -> initializer ID for Private/Function variables
627+ < a href =#627 id =627 data-nosnippet > 627</ a > // that have constant initializers.
628+ < a href =#628 id =628 data-nosnippet > 628</ a > </ span > < span class ="kw "> let </ span > var_initializers: FxHashMap<Word, Word> = module
629+ < a href =#629 id =629 data-nosnippet > 629</ a > .types_global_values
630+ < a href =#630 id =630 data-nosnippet > 630</ a > .iter()
631+ < a href =#631 id =631 data-nosnippet > 631</ a > .filter_map(|inst| {
632+ < a href =#632 id =632 data-nosnippet > 632</ a > < span class ="kw "> if </ span > inst.class.opcode != Op::Variable {
633+ < a href =#633 id =633 data-nosnippet > 633</ a > < span class ="kw "> return </ span > < span class ="prelude-val "> None</ span > ;
634+ < a href =#634 id =634 data-nosnippet > 634</ a > }
635+ < a href =#635 id =635 data-nosnippet > 635</ a > < span class ="comment "> // Check storage class - only Private and Function can be folded
636+ < a href =#636 id =636 data-nosnippet > 636</ a > </ span > < span class ="kw "> let </ span > storage_class = inst.operands.first()< span class ="question-mark "> ?</ span > .unwrap_storage_class();
637+ < a href =#637 id =637 data-nosnippet > 637</ a > < span class ="kw "> if </ span > !< span class ="macro "> matches!</ span > (
638+ < a href =#638 id =638 data-nosnippet > 638</ a > storage_class,
639+ < a href =#639 id =639 data-nosnippet > 639</ a > StorageClass::Private | StorageClass::Function
640+ < a href =#640 id =640 data-nosnippet > 640</ a > ) {
641+ < a href =#641 id =641 data-nosnippet > 641</ a > < span class ="kw "> return </ span > < span class ="prelude-val "> None</ span > ;
642+ < a href =#642 id =642 data-nosnippet > 642</ a > }
643+ < a href =#643 id =643 data-nosnippet > 643</ a > < span class ="comment "> // Check for initializer (second operand after storage class)
644+ < a href =#644 id =644 data-nosnippet > 644</ a > </ span > < span class ="kw "> let </ span > initializer = inst.operands.get(< span class ="number "> 1</ span > )< span class ="question-mark "> ?</ span > .id_ref_any()< span class ="question-mark "> ?</ span > ;
645+ < a href =#645 id =645 data-nosnippet > 645</ a > < span class ="prelude-val "> Some</ span > ((inst.result_id< span class ="question-mark "> ?</ span > , initializer))
646+ < a href =#646 id =646 data-nosnippet > 646</ a > })
647+ < a href =#647 id =647 data-nosnippet > 647</ a > .collect();
648+ < a href =#648 id =648 data-nosnippet > 648</ a >
649+ < a href =#649 id =649 data-nosnippet > 649</ a > < span class ="kw "> if </ span > var_initializers.is_empty() {
650+ < a href =#650 id =650 data-nosnippet > 650</ a > < span class ="kw "> return</ span > ;
651+ < a href =#651 id =651 data-nosnippet > 651</ a > }
652+ < a href =#652 id =652 data-nosnippet > 652</ a >
653+ < a href =#653 id =653 data-nosnippet > 653</ a > < span class ="comment "> // Rewrite OpLoad instructions that load from variables with known initializers
654+ < a href =#654 id =654 data-nosnippet > 654</ a > </ span > < span class ="kw "> let </ span > < span class ="kw-2 "> mut </ span > rewrite_rules: FxHashMap<Word, Word> = FxHashMap::default();
655+ < a href =#655 id =655 data-nosnippet > 655</ a >
656+ < a href =#656 id =656 data-nosnippet > 656</ a > < span class ="kw "> for </ span > func < span class ="kw "> in </ span > < span class ="kw-2 "> &mut </ span > module.functions {
657+ < a href =#657 id =657 data-nosnippet > 657</ a > < span class ="kw "> for </ span > block < span class ="kw "> in </ span > < span class ="kw-2 "> &mut </ span > func.blocks {
658+ < a href =#658 id =658 data-nosnippet > 658</ a > < span class ="kw "> for </ span > inst < span class ="kw "> in </ span > < span class ="kw-2 "> &mut </ span > block.instructions {
659+ < a href =#659 id =659 data-nosnippet > 659</ a > < span class ="kw "> if </ span > inst.class.opcode != Op::Load {
660+ < a href =#660 id =660 data-nosnippet > 660</ a > < span class ="kw "> continue</ span > ;
661+ < a href =#661 id =661 data-nosnippet > 661</ a > }
662+ < a href =#662 id =662 data-nosnippet > 662</ a > < span class ="comment "> // OpLoad has pointer as first operand
663+ < a href =#663 id =663 data-nosnippet > 663</ a > </ span > < span class ="kw "> let </ span > ptr_id = inst.operands[< span class ="number "> 0</ span > ].unwrap_id_ref();
664+ < a href =#664 id =664 data-nosnippet > 664</ a > < span class ="kw "> if let </ span > < span class ="prelude-val "> Some</ span > (< span class ="kw-2 "> &</ span > initializer) = var_initializers.get(< span class ="kw-2 "> &</ span > ptr_id) {
665+ < a href =#665 id =665 data-nosnippet > 665</ a > < span class ="comment "> // This load can be replaced with the initializer value
666+ < a href =#666 id =666 data-nosnippet > 666</ a > </ span > < span class ="kw "> if let </ span > < span class ="prelude-val "> Some</ span > (result_id) = inst.result_id {
667+ < a href =#667 id =667 data-nosnippet > 667</ a > rewrite_rules.insert(result_id, initializer);
668+ < a href =#668 id =668 data-nosnippet > 668</ a > < span class ="comment "> // Turn this instruction into a Nop
669+ < a href =#669 id =669 data-nosnippet > 669</ a > </ span > < span class ="kw-2 "> *</ span > inst = Instruction::new(Op::Nop, < span class ="prelude-val "> None</ span > , < span class ="prelude-val "> None</ span > , Vec::new());
670+ < a href =#670 id =670 data-nosnippet > 670</ a > }
671+ < a href =#671 id =671 data-nosnippet > 671</ a > }
672+ < a href =#672 id =672 data-nosnippet > 672</ a > }
673+ < a href =#673 id =673 data-nosnippet > 673</ a > }
674+ < a href =#674 id =674 data-nosnippet > 674</ a > }
675+ < a href =#675 id =675 data-nosnippet > 675</ a >
676+ < a href =#676 id =676 data-nosnippet > 676</ a > < span class ="kw "> if </ span > !rewrite_rules.is_empty() {
677+ < a href =#677 id =677 data-nosnippet > 677</ a > < span class ="comment "> // Apply rewrite rules to all functions
678+ < a href =#678 id =678 data-nosnippet > 678</ a > </ span > < span class ="kw "> for </ span > func < span class ="kw "> in </ span > < span class ="kw-2 "> &mut </ span > module.functions {
679+ < a href =#679 id =679 data-nosnippet > 679</ a > < span class ="kw "> super</ span > ::apply_rewrite_rules(< span class ="kw-2 "> &</ span > rewrite_rules, < span class ="kw-2 "> &mut </ span > func.blocks);
680+ < a href =#680 id =680 data-nosnippet > 680</ a > }
681+ < a href =#681 id =681 data-nosnippet > 681</ a > }
682+ < a href =#682 id =682 data-nosnippet > 682</ a > }</ code > </ pre > </ div > </ section > </ main > </ body > </ html >
0 commit comments