[RegisterCoalescer] Mark implicit-defs of super-registers as dead in remat (#159110)

Currently, something like:

```
$eax = MOV32ri -11, implicit-def $rax
%al = COPY $eax
```

Can be rematerialized as:
```
dead $eax = MOV32ri -11, implicit-def $rax
```

Which marks the full $rax as used, not just $al.

With this change, this is rematerialized as:

```
dead $eax = MOV32ri -11, implicit-def dead $rax, implicit-def $al
```

To indicate that only $al is used. 

Note: This issue is latent right now, but is exposed when #134408 is
applied, as it results in the register pressure being incorrectly
calculated (unless this patch is applied too).

I think this change is in line with past fixes in this area, notably:

059cead5ed

69cd121dd9
This commit is contained in:
Benjamin Maxwell 2025-09-26 10:08:10 +01:00 committed by GitHub
parent 656707086e
commit d357e965af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 13 deletions

View File

@ -1475,10 +1475,7 @@ bool RegisterCoalescer::reMaterializeDef(const CoalescerPair &CP,
//
// The implicit-def of the super register may have been reduced to
// subregisters depending on the uses.
bool NewMIDefinesFullReg = false;
SmallVector<MCRegister, 4> NewMIImplDefs;
SmallVector<std::pair<unsigned, Register>, 4> NewMIImplDefs;
for (unsigned i = NewMI.getDesc().getNumOperands(),
e = NewMI.getNumOperands();
i != e; ++i) {
@ -1486,9 +1483,6 @@ bool RegisterCoalescer::reMaterializeDef(const CoalescerPair &CP,
if (MO.isReg() && MO.isDef()) {
assert(MO.isImplicit());
if (MO.getReg().isPhysical()) {
if (MO.getReg() == DstReg)
NewMIDefinesFullReg = true;
assert(MO.isImplicit() && MO.getReg().isPhysical() &&
(MO.isDead() ||
(DefSubIdx &&
@ -1496,7 +1490,7 @@ bool RegisterCoalescer::reMaterializeDef(const CoalescerPair &CP,
MCRegister((unsigned)NewMI.getOperand(0).getReg())) ||
TRI->isSubRegisterEq(NewMI.getOperand(0).getReg(),
MO.getReg())))));
NewMIImplDefs.push_back(MO.getReg().asMCReg());
NewMIImplDefs.push_back({i, MO.getReg()});
} else {
assert(MO.getReg() == NewMI.getOperand(0).getReg());
@ -1641,12 +1635,30 @@ bool RegisterCoalescer::reMaterializeDef(const CoalescerPair &CP,
// been asked for. If so it must implicitly define the whole thing.
assert(DstReg.isPhysical() &&
"Only expect virtual or physical registers in remat");
// When we're rematerializing into a not-quite-right register we already add
// the real definition as an implicit-def, but we should also be marking the
// "official" register as dead, since nothing else is going to use it as a
// result of this remat. Not doing this can affect pressure tracking.
NewMI.getOperand(0).setIsDead(true);
if (!NewMIDefinesFullReg) {
bool HasDefMatchingCopy = false;
for (auto [OpIndex, Reg] : NewMIImplDefs) {
if (Reg != DstReg)
continue;
// Also, if CopyDstReg is a sub-register of DstReg (and it is defined), we
// must mark DstReg as dead since it is not going to used as a result of
// this remat.
if (DstReg != CopyDstReg)
NewMI.getOperand(OpIndex).setIsDead(true);
else
HasDefMatchingCopy = true;
}
// If NewMI does not already have an implicit-def CopyDstReg add one now.
if (!HasDefMatchingCopy)
NewMI.addOperand(MachineOperand::CreateReg(
CopyDstReg, true /*IsDef*/, true /*IsImp*/, false /*IsKill*/));
}
// Record small dead def live-ranges for all the subregisters
// of the destination register.
@ -1677,8 +1689,8 @@ bool RegisterCoalescer::reMaterializeDef(const CoalescerPair &CP,
NewMI.addOperand(MO);
SlotIndex NewMIIdx = LIS->getInstructionIndex(NewMI);
for (MCRegister Reg : NewMIImplDefs) {
for (MCRegUnit Unit : TRI->regunits(Reg))
for (Register Reg : make_second_range(NewMIImplDefs)) {
for (MCRegUnit Unit : TRI->regunits(Reg.asMCReg()))
if (LiveRange *LR = LIS->getCachedRegUnit(Unit))
LR->createDeadDef(NewMIIdx.getRegSlot(), LIS->getVNInfoAllocator());
}

View File

@ -165,5 +165,25 @@ body: |
bb.3:
$rax = COPY %t3
RET 0, $rax
...
---
name: rematerialize_superregister_into_subregister_def_with_impdef_physreg
body: |
bb.0.entry:
; CHECK-LABEL: name: rematerialize_superregister_into_subregister_def_with_impdef_physreg
; CHECK: dead $esi = MOV32r0 implicit-def dead $eflags, implicit-def $rsi
; CHECK-NEXT: dead $edx = MOV32r0 implicit-def dead $eflags, implicit-def $rdx
; CHECK-NEXT: FAKE_USE implicit killed $rsi, implicit killed $rdx
; CHECK-NEXT: dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def dead $rax, implicit-def $al
; CHECK-NEXT: FAKE_USE implicit killed $al
; CHECK-NEXT: $eax = MOV32r0 implicit-def dead $eflags
; CHECK-NEXT: RET 0, $eax
undef %1.sub_32bit:gr64_with_sub_8bit = MOV32r0 implicit-def dead $eflags, implicit-def %1
$rsi = COPY %1
$rdx = COPY %1
FAKE_USE implicit killed $rsi, implicit killed $rdx
%4:gr8 = COPY killed %1.sub_8bit
$al = COPY killed %4
FAKE_USE implicit killed $al
$eax = MOV32r0 implicit-def dead $eflags
RET 0, killed $eax