Skip to content

Commit 80a9112

Browse files
pratikasharigcbot
authored andcommitted
Remove redundant spills in post RA spill cleanup
Remove redundant spills in post RA spill cleanup. A redundant spill is: 1. A spill in basic block that has a spill lexically after, before a fill appears. It means the spilled value is never read back. 2. A spill in program that has no fill. Both of these can occur as a result of redundant fill elimination done earlier in post RA spill cleanup pass.
1 parent cfcbe00 commit 80a9112

3 files changed

Lines changed: 120 additions & 0 deletions

File tree

visa/GraphColor.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8407,6 +8407,7 @@ void GlobalRA::stackCallProlog() {
84078407
builder.getBESP(), InstOpt_WriteEnable, false);
84088408
}
84098409
builder.setFDSpillInst(store);
8410+
store->markDoNotDelete();
84108411
auto iter = std::find_if(entryBB->begin(), entryBB->end(),
84118412
[](G4_INST *inst) { return !inst->isLabel(); });
84128413
iter = entryBB->insertBefore(iter, store);
@@ -9678,6 +9679,7 @@ void GlobalRA::storeCEInProlog() {
96789679
InstOpt_WriteEnable, false);
96799680
}
96809681
kernel.fg.getEntryBB()->insertAfter(nextPos, store);
9682+
store->markDoNotDelete();
96819683

96829684
if (builder.kernel.getOption(vISA_GenerateDebugInfo)) {
96839685
builder.kernel.getKernelDebugInfo()->setSaveCEInst(store);

visa/SpillFillPropagation.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
718830
void 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
}

visa/SpillFillPropagation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ class SpillFillPropagation {
7272
std::unordered_map<unsigned, PendingFill> &pendingFills);
7373
void processBBForward(G4_BB *bb);
7474
void processBBBackward(G4_BB *bb);
75+
void removeRedundantSpills();
76+
void removeSpillWithoutFill();
7577
bool replaceFillWithMovsAfter(G4_BB *bb, INST_LIST_RITER &rit,
7678
INST_LIST_ITER &insertAfterIt,
7779
const PendingFill &pf,

0 commit comments

Comments
 (0)