@@ -713,6 +713,118 @@ void SpillFillPropagation::processBBBackward(G4_BB *bb) {
713713 }
714714}
715715
716+ // Per-BB bottom-up pass that removes spills fully overwritten by a later spill
717+ // before any fill reads the same scratch rows. Tracks per-BB the set of scratch
718+ // row offsets known to be re-spilled below the current point.
719+ void SpillFillPropagation::removeRedundantSpills () {
720+ for (G4_BB *bb : kernel.fg ) {
721+ std::unordered_set<unsigned > spilledOffsets;
722+
723+ for (auto rit = bb->rbegin (); rit != bb->rend ();) {
724+ G4_INST *inst = *rit;
725+
726+ if (inst->isFillIntrinsic ()) {
727+ auto *fill = inst->asFillIntrinsic ();
728+ unsigned offset = fill->getOffset ();
729+ unsigned numRows = fill->getNumRows ();
730+ // Fill reads scratch — earlier spills to these rows are needed.
731+ for (unsigned i = 0 ; i < numRows; ++i)
732+ spilledOffsets.erase (offset + i);
733+ ++rit;
734+ continue ;
735+ }
736+
737+ if (inst->isSpillIntrinsic ()) {
738+ auto *spill = inst->asSpillIntrinsic ();
739+ if (spill->isScatterSpill ()) {
740+ // Don't propagate any tracked live spill across a scatter spill.
741+ spilledOffsets.clear ();
742+ ++rit;
743+ continue ;
744+ }
745+ unsigned offset = spill->getOffset ();
746+ unsigned numRows = spill->getNumRows ();
747+ // Non-scatter spill (WE or non-WE) is redundant if every row is
748+ // already overwritten by a later spill below.
749+ bool redundant = true ;
750+ for (unsigned i = 0 ; i < numRows; ++i) {
751+ if (!spilledOffsets.count (offset + i)) {
752+ redundant = false ;
753+ break ;
754+ }
755+ }
756+ if (redundant && !spill->isDoNotDelete ()) {
757+ INST_LIST_ITER fwd = std::next (rit).base ();
758+ auto next = bb->erase (fwd);
759+ rit = INST_LIST_RITER (next);
760+ continue ;
761+ }
762+ // Only WriteEnable spills fully overwrite scratch and can cover
763+ // earlier spills. Non-WE spills don't update the set.
764+ if (inst->isWriteEnableInst ()) {
765+ for (unsigned i = 0 ; i < numRows; ++i)
766+ spilledOffsets.insert (offset + i);
767+ }
768+ ++rit;
769+ continue ;
770+ }
771+
772+ ++rit;
773+ }
774+ }
775+ }
776+
777+ // Kernel-wide pass that removes spills whose every row offset is never read
778+ // by any fill. Such spills are dead because scratch is only observable via
779+ // fill intrinsics.
780+ void SpillFillPropagation::removeSpillWithoutFill () {
781+ std::unordered_set<unsigned > filledOffsets;
782+ for (G4_BB *bb : kernel.fg ) {
783+ for (G4_INST *inst : *bb) {
784+ if (!inst->isFillIntrinsic ())
785+ continue ;
786+ auto *fill = inst->asFillIntrinsic ();
787+ unsigned offset = fill->getOffset ();
788+ unsigned numRows = fill->getNumRows ();
789+ for (unsigned i = 0 ; i < numRows; ++i)
790+ filledOffsets.insert (offset + i);
791+ }
792+ }
793+
794+ for (G4_BB *bb : kernel.fg ) {
795+ for (auto it = bb->begin (); it != bb->end ();) {
796+ G4_INST *inst = *it;
797+ if (!inst->isSpillIntrinsic ()) {
798+ ++it;
799+ continue ;
800+ }
801+ auto *spill = inst->asSpillIntrinsic ();
802+ if (spill->isScatterSpill ()) {
803+ ++it;
804+ continue ;
805+ }
806+ if (spill->isDoNotDelete ()) {
807+ ++it;
808+ continue ;
809+ }
810+ unsigned offset = spill->getOffset ();
811+ unsigned numRows = spill->getNumRows ();
812+ bool hasFill = false ;
813+ for (unsigned i = 0 ; i < numRows; ++i) {
814+ if (filledOffsets.count (offset + i)) {
815+ hasFill = true ;
816+ break ;
817+ }
818+ }
819+ if (!hasFill) {
820+ it = bb->erase (it);
821+ continue ;
822+ }
823+ ++it;
824+ }
825+ }
826+ }
827+
716828// Entry point. Run backward pass first to catch cases where the source GRFs
717829// are clobbered before a later fill, then forward pass for remaining cases.
718830void SpillFillPropagation::run () {
@@ -731,4 +843,8 @@ void SpillFillPropagation::run() {
731843
732844 for (G4_BB *bb : kernel.fg )
733845 processBBForward (bb);
846+
847+ removeRedundantSpills ();
848+
849+ removeSpillWithoutFill ();
734850}
0 commit comments