[llvm] [CodeGen] Correctly handle non-standard cases in RemoveLoadsIntoFakeUses (PR #111551)
Stephen Tozer via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 4 09:46:41 PST 2024
https://github.com/SLTozer updated https://github.com/llvm/llvm-project/pull/111551
>From 3fa10a6b9105c855eda21fe129dbdec35168cb71 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Tue, 8 Oct 2024 13:53:37 +0100
Subject: [PATCH 1/5] [CodeGen] Correctly handle non-standard cases in
RemoveLoadsIntoFakeUses
In the RemoveLoadsIntoFakeUses pass, we try to remove loads that are only
used by fake uses, as well as the fake use in question. There are two
existing errors with the pass however: it incorrectly examines every operand
of each FAKE_USE, when only the first is relevant (extra operands should
just be "killed" regs), and it ignores cases where the FAKE_USE register is
not an exact match for the loaded register, which is incorrect as regalloc
may choose to load a wider value than was required pre-regalloc.
This patch fixes both of these cases.
---
llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp | 60 ++++----
.../CodeGen/X86/fake-use-remove-loads.mir | 129 ++++++++++++++++++
2 files changed, 165 insertions(+), 24 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/fake-use-remove-loads.mir
diff --git a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
index ef7a58670c3ac5..0670e1b8871286 100644
--- a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
+++ b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
@@ -94,11 +94,13 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
for (MachineInstr &MI : make_early_inc_range(reverse(*MBB))) {
if (MI.isFakeUse()) {
- for (const MachineOperand &MO : MI.operands()) {
- // Track the Fake Uses that use this register so that we can delete
- // them if we delete the corresponding load.
- if (MO.isReg())
- RegFakeUses[MO.getReg()].push_back(&MI);
+ const MachineOperand &FakeUseOp = MI.getOperand(0);
+ // Track the Fake Uses that use this register so that we can delete
+ // them if we delete the corresponding load.
+ if (FakeUseOp.isReg()) {
+ assert(FakeUseOp.getReg().isPhysical() &&
+ "VReg seen in function with NoVRegs set?");
+ RegFakeUses[FakeUseOp.getReg()].push_back(&MI);
}
// Do not record FAKE_USE uses in LivePhysRegs so that we can recognize
// otherwise-unused loads.
@@ -113,27 +115,34 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
// Don't delete live physreg defs, or any reserved register defs.
if (!LivePhysRegs.available(Reg) || MRI->isReserved(Reg))
continue;
- // There should be an exact match between the loaded register and the
- // FAKE_USE use. If not, this is a load that is unused by anything? It
- // should probably be deleted, but that's outside of this pass' scope.
- if (RegFakeUses.contains(Reg)) {
- LLVM_DEBUG(dbgs() << "RemoveLoadsIntoFakeUses: DELETING: " << MI);
- // It is possible that some DBG_VALUE instructions refer to this
- // instruction. They will be deleted in the live debug variable
- // analysis.
- MI.eraseFromParent();
- AnyChanges = true;
- ++NumLoadsDeleted;
- // Each FAKE_USE now appears to be a fake use of the previous value
- // of the loaded register; delete them to avoid incorrectly
- // interpreting them as such.
- for (MachineInstr *FakeUse : RegFakeUses[Reg]) {
+ // There should typically be an exact match between the loaded register
+ // and the FAKE_USE, but sometimes regalloc will choose to load a larger
+ // value than is needed. Therefore, as long as the load isn't used by
+ // anything except at least one FAKE_USE, we will delete it. If it isn't
+ // used by any fake uses, it should still be safe to delete but we
+ // choose to ignore it so that this pass has no side effects unrelated
+ // to fake uses.
+ bool HasFakeUse = false;
+ for (MCPhysReg SubReg : TRI->subregs_inclusive(Reg)) {
+ if (!RegFakeUses.contains(SubReg))
+ continue;
+ HasFakeUse = true;
+ for (MachineInstr *FakeUse : RegFakeUses[SubReg]) {
LLVM_DEBUG(dbgs()
<< "RemoveLoadsIntoFakeUses: DELETING: " << *FakeUse);
FakeUse->eraseFromParent();
}
- NumFakeUsesDeleted += RegFakeUses[Reg].size();
- RegFakeUses[Reg].clear();
+ NumFakeUsesDeleted += RegFakeUses[SubReg].size();
+ RegFakeUses[SubReg].clear();
+ }
+ if (HasFakeUse) {
+ LLVM_DEBUG(dbgs() << "RemoveLoadsIntoFakeUses: DELETING: " << MI);
+ // Since this load only exists to restore a spilled register and we
+ // haven't, run LiveDebugValues yet, there shouldn't be any DBG_VALUEs
+ // for this load; otherwise, deleting this would be incorrect.
+ MI.eraseFromParent();
+ AnyChanges = true;
+ ++NumLoadsDeleted;
}
continue;
}
@@ -147,8 +156,11 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
Register Reg = MO.getReg();
assert(Reg.isPhysical() &&
"VReg seen in function with NoVRegs set?");
- for (MCRegUnit Unit : TRI->regunits(Reg))
- RegFakeUses.erase(Unit);
+ // We clear RegFakeUses for this register and all subregisters,
+ // because any such FAKE_USE encountered prior applies only to this
+ // instruction.
+ for (MCPhysReg SubReg : TRI->subregs_inclusive(Reg))
+ RegFakeUses.erase(SubReg);
}
}
}
diff --git a/llvm/test/CodeGen/X86/fake-use-remove-loads.mir b/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
new file mode 100644
index 00000000000000..a8edbed5b28fe5
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
@@ -0,0 +1,129 @@
+# Ensure that loads into FAKE_USEs are correctly removed by the
+# remove-loads-into-fake-uses pass.
+# RUN: llc -run-pass remove-loads-into-fake-uses -mtriple=x86_64-unknown-linux -debug-only=remove-loads-into-fake-uses 2>&1 -o - %s | FileCheck %s --implicit-check-not=DELETING
+# REQUIRES: asserts
+#
+## We ensure that the load into the FAKE_USE is removed, along with the FAKE_USE
+## itself, even when the FAKE_USE is for a subregister of the move, and that we
+## correctly handle situations where FAKE_USE has additional `killed` operands
+## added by other passes.
+
+# CHECK: DELETING: FAKE_USE renamable $eax
+# CHECK: DELETING: renamable $rax = MOV64rm $rbp
+
+## Also verify that the store to the stack slot still exists.
+
+# CHECK-LABEL: bb.5:
+# CHECK: MOV64mi32 $rbp, 1, $noreg, -48, $noreg, 0 :: (store (s64) into %stack.0)
+# CHECK-LABEL: bb.6:
+
+
+--- |
+ define void @_ZN1g1jEv(ptr %this, i1 %cmp36, ptr %ref.tmp5) {
+ entry:
+ ret void
+ }
+
+...
+---
+name: _ZN1g1jEv
+alignment: 16
+tracksRegLiveness: true
+noPhis: true
+noVRegs: true
+hasFakeUses: true
+tracksDebugUserValues: true
+liveins:
+ - { reg: '$rdi', virtual-reg: '' }
+ - { reg: '$esi', virtual-reg: '' }
+ - { reg: '$rdx', virtual-reg: '' }
+frameInfo:
+ isCalleeSavedInfoValid: true
+stack:
+ - { id: 0, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ bb.0:
+ successors: %bb.2(0x80000000)
+ liveins: $esi, $rdi, $rdx, $r15, $r14, $r13, $r12, $rbx
+
+ frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp
+ frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ frame-setup CFI_INSTRUCTION offset $rbp, -16
+ $rbp = frame-setup MOV64rr $rsp
+ frame-setup CFI_INSTRUCTION def_cfa_register $rbp
+ frame-setup PUSH64r killed $r15, implicit-def $rsp, implicit $rsp
+ frame-setup PUSH64r killed $r14, implicit-def $rsp, implicit $rsp
+ frame-setup PUSH64r killed $r13, implicit-def $rsp, implicit $rsp
+ frame-setup PUSH64r killed $r12, implicit-def $rsp, implicit $rsp
+ frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp
+ frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp
+ CFI_INSTRUCTION offset $rbx, -56
+ CFI_INSTRUCTION offset $r12, -48
+ CFI_INSTRUCTION offset $r13, -40
+ CFI_INSTRUCTION offset $r14, -32
+ CFI_INSTRUCTION offset $r15, -24
+ $rbx = MOV64rr $rdx
+ $r14d = MOV32rr $esi
+ $r15 = MOV64rr $rdi
+ renamable $r12d = XOR32rr undef $r12d, undef $r12d, implicit-def dead $eflags, implicit-def $r12
+ renamable $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $rax
+ JMP_1 %bb.2
+
+ bb.1:
+ successors: %bb.2(0x783e0f0f), %bb.6(0x07c1f0f1)
+ liveins: $rbx, $r12, $r15, $r13d, $r14d
+
+ renamable $rax = MOV64rm $rbp, 1, $noreg, -48, $noreg :: (load (s64) from %stack.0)
+ FAKE_USE renamable $eax, implicit killed $rax
+ renamable $eax = MOV32ri 1, implicit-def $rax
+ TEST32rr killed renamable $r13d, renamable $r13d, implicit-def $eflags
+ JCC_1 %bb.6, 9, implicit $eflags
+
+ bb.2:
+ successors: %bb.3(0x80000000)
+ liveins: $rax, $rbx, $r12, $r15, $r14d
+
+ MOV64mr $rbp, 1, $noreg, -48, $noreg, killed renamable $rax :: (store (s64) into %stack.0)
+ renamable $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags
+
+ bb.3:
+ successors: %bb.4(0x04000000), %bb.3(0x7c000000)
+ liveins: $eax, $rbx, $r12, $r15, $r14d
+
+ $r13d = MOV32rr killed $eax
+ $rdi = MOV64rr $r15
+ CALL64r renamable $r12, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
+ dead renamable $eax = MOV32rm renamable $rbx, 1, $noreg, 0, $noreg :: (volatile load (s32) from %ir.ref.tmp5)
+ renamable $eax = MOV32ri 1
+ TEST8ri renamable $r14b, 1, implicit-def $eflags
+ JCC_1 %bb.3, 4, implicit $eflags
+
+ bb.4:
+ successors: %bb.5(0x40000000), %bb.1(0x40000000)
+ liveins: $eflags, $rbx, $r12, $r15, $r13d, $r14d
+
+ JCC_1 %bb.1, 4, implicit $eflags
+
+ bb.5:
+ successors: %bb.1(0x80000000)
+ liveins: $rbx, $r12, $r15, $r13d, $r14d
+
+ renamable $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $rax
+ MOV64mi32 $rbp, 1, $noreg, -48, $noreg, 0 :: (store (s64) into %stack.0)
+ CALL64r killed renamable $rax, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit-def dead $eax
+ JMP_1 %bb.1
+
+ bb.6:
+ $rsp = frame-destroy ADD64ri32 $rsp, 8, implicit-def dead $eflags
+ $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp
+ $r12 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
+ $r13 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
+ $r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
+ $r15 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
+ $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp
+ frame-destroy CFI_INSTRUCTION def_cfa $rsp, 8
+ RET64
+
+...
>From 5a233d73e3b1373ad98eed98605a29dac332caad Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Tue, 8 Oct 2024 17:45:39 +0100
Subject: [PATCH 2/5] Remove assertions, handle 0-op FAKE_USES, use RegUnits
---
llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp | 49 +++++++++----------
.../CodeGen/X86/fake-use-remove-loads.mir | 2 +-
2 files changed, 25 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
index 0670e1b8871286..b56a07010188d3 100644
--- a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
+++ b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
@@ -86,22 +86,23 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
const TargetInstrInfo *TII = ST.getInstrInfo();
const TargetRegisterInfo *TRI = ST.getRegisterInfo();
- SmallDenseMap<Register, SmallVector<MachineInstr *>> RegFakeUses;
+ SmallDenseMap<MCRegUnit, SmallVector<MachineInstr *>> RegFakeUses;
LivePhysRegs.init(*TRI);
SmallVector<MachineInstr *, 16> Statepoints;
for (MachineBasicBlock *MBB : post_order(&MF)) {
+ RegFakeUses.clear();
LivePhysRegs.addLiveOuts(*MBB);
for (MachineInstr &MI : make_early_inc_range(reverse(*MBB))) {
if (MI.isFakeUse()) {
+ if (MI.getNumOperands() == 0 || !MI.getOperand(0).isReg())
+ continue;
const MachineOperand &FakeUseOp = MI.getOperand(0);
- // Track the Fake Uses that use this register so that we can delete
- // them if we delete the corresponding load.
- if (FakeUseOp.isReg()) {
- assert(FakeUseOp.getReg().isPhysical() &&
- "VReg seen in function with NoVRegs set?");
- RegFakeUses[FakeUseOp.getReg()].push_back(&MI);
- }
+ // Track the Fake Uses that use these register units so that we can
+ // delete them if we delete the corresponding load.
+ if (FakeUseOp.isReg())
+ for (MCRegUnit Unit : TRI->regunits(FakeUseOp.getReg()))
+ RegFakeUses[Unit].push_back(&MI);
// Do not record FAKE_USE uses in LivePhysRegs so that we can recognize
// otherwise-unused loads.
continue;
@@ -111,7 +112,6 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
// reload of a spilled register.
if (MI.getRestoreSize(TII)) {
Register Reg = MI.getOperand(0).getReg();
- assert(Reg.isPhysical() && "VReg seen in function with NoVRegs set?");
// Don't delete live physreg defs, or any reserved register defs.
if (!LivePhysRegs.available(Reg) || MRI->isReserved(Reg))
continue;
@@ -122,20 +122,15 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
// used by any fake uses, it should still be safe to delete but we
// choose to ignore it so that this pass has no side effects unrelated
// to fake uses.
- bool HasFakeUse = false;
- for (MCPhysReg SubReg : TRI->subregs_inclusive(Reg)) {
- if (!RegFakeUses.contains(SubReg))
+ SmallDenseSet<MachineInstr *> FakeUsesToDelete;
+ for (MCRegUnit Unit : TRI->regunits(Reg)) {
+ if (!RegFakeUses.contains(Unit))
continue;
- HasFakeUse = true;
- for (MachineInstr *FakeUse : RegFakeUses[SubReg]) {
- LLVM_DEBUG(dbgs()
- << "RemoveLoadsIntoFakeUses: DELETING: " << *FakeUse);
- FakeUse->eraseFromParent();
- }
- NumFakeUsesDeleted += RegFakeUses[SubReg].size();
- RegFakeUses[SubReg].clear();
+ for (MachineInstr *FakeUse : RegFakeUses[Unit])
+ FakeUsesToDelete.insert(FakeUse);
+ RegFakeUses.erase(Unit);
}
- if (HasFakeUse) {
+ if (!FakeUsesToDelete.empty()) {
LLVM_DEBUG(dbgs() << "RemoveLoadsIntoFakeUses: DELETING: " << MI);
// Since this load only exists to restore a spilled register and we
// haven't, run LiveDebugValues yet, there shouldn't be any DBG_VALUEs
@@ -143,6 +138,12 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
MI.eraseFromParent();
AnyChanges = true;
++NumLoadsDeleted;
+ for (MachineInstr *FakeUse : FakeUsesToDelete) {
+ LLVM_DEBUG(dbgs()
+ << "RemoveLoadsIntoFakeUses: DELETING: " << *FakeUse);
+ FakeUse->eraseFromParent();
+ }
+ NumFakeUsesDeleted += FakeUsesToDelete.size();
}
continue;
}
@@ -154,13 +155,11 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
for (const MachineOperand &MO : MI.operands()) {
if (MO.isReg() && MO.isDef()) {
Register Reg = MO.getReg();
- assert(Reg.isPhysical() &&
- "VReg seen in function with NoVRegs set?");
// We clear RegFakeUses for this register and all subregisters,
// because any such FAKE_USE encountered prior applies only to this
// instruction.
- for (MCPhysReg SubReg : TRI->subregs_inclusive(Reg))
- RegFakeUses.erase(SubReg);
+ for (MCRegUnit Unit : TRI->regunits(Reg))
+ RegFakeUses.erase(Unit);
}
}
}
diff --git a/llvm/test/CodeGen/X86/fake-use-remove-loads.mir b/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
index a8edbed5b28fe5..e001bbec637ac9 100644
--- a/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
+++ b/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
@@ -8,8 +8,8 @@
## correctly handle situations where FAKE_USE has additional `killed` operands
## added by other passes.
-# CHECK: DELETING: FAKE_USE renamable $eax
# CHECK: DELETING: renamable $rax = MOV64rm $rbp
+# CHECK: DELETING: FAKE_USE renamable $eax
## Also verify that the store to the stack slot still exists.
>From eedae0671b428d1148bee46117a157fc16fb2e41 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Mon, 14 Oct 2024 11:21:52 +0100
Subject: [PATCH 3/5] Use a SmallVector of fake uses instead of a SmallDenseMap
---
llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp | 32 +++---
.../CodeGen/X86/fake-use-remove-loads.mir | 99 +++++--------------
2 files changed, 38 insertions(+), 93 deletions(-)
diff --git a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
index b56a07010188d3..74ad2fe3858ea9 100644
--- a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
+++ b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
@@ -86,7 +86,7 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
const TargetInstrInfo *TII = ST.getInstrInfo();
const TargetRegisterInfo *TRI = ST.getRegisterInfo();
- SmallDenseMap<MCRegUnit, SmallVector<MachineInstr *>> RegFakeUses;
+ SmallVector<MachineInstr *> RegFakeUses;
LivePhysRegs.init(*TRI);
SmallVector<MachineInstr *, 16> Statepoints;
for (MachineBasicBlock *MBB : post_order(&MF)) {
@@ -101,8 +101,7 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
// Track the Fake Uses that use these register units so that we can
// delete them if we delete the corresponding load.
if (FakeUseOp.isReg())
- for (MCRegUnit Unit : TRI->regunits(FakeUseOp.getReg()))
- RegFakeUses[Unit].push_back(&MI);
+ RegFakeUses.push_back(&MI);
// Do not record FAKE_USE uses in LivePhysRegs so that we can recognize
// otherwise-unused loads.
continue;
@@ -123,12 +122,12 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
// choose to ignore it so that this pass has no side effects unrelated
// to fake uses.
SmallDenseSet<MachineInstr *> FakeUsesToDelete;
- for (MCRegUnit Unit : TRI->regunits(Reg)) {
- if (!RegFakeUses.contains(Unit))
- continue;
- for (MachineInstr *FakeUse : RegFakeUses[Unit])
+ SmallVector<MachineInstr *> RemainingFakeUses;
+ for (MachineInstr *&FakeUse : reverse(RegFakeUses)) {
+ if (TRI->regsOverlap(Reg, FakeUse->getOperand(0).getReg())) {
FakeUsesToDelete.insert(FakeUse);
- RegFakeUses.erase(Unit);
+ RegFakeUses.erase(&FakeUse);
+ }
}
if (!FakeUsesToDelete.empty()) {
LLVM_DEBUG(dbgs() << "RemoveLoadsIntoFakeUses: DELETING: " << MI);
@@ -153,14 +152,15 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
// that register.
if (!RegFakeUses.empty()) {
for (const MachineOperand &MO : MI.operands()) {
- if (MO.isReg() && MO.isDef()) {
- Register Reg = MO.getReg();
- // We clear RegFakeUses for this register and all subregisters,
- // because any such FAKE_USE encountered prior applies only to this
- // instruction.
- for (MCRegUnit Unit : TRI->regunits(Reg))
- RegFakeUses.erase(Unit);
- }
+ if (!MO.isReg())
+ continue;
+ Register Reg = MO.getReg();
+ // We clear RegFakeUses for this register and all subregisters,
+ // because any such FAKE_USE encountered prior is no longer relevant
+ // for later encountered loads.
+ for (MachineInstr *&FakeUse : reverse(RegFakeUses))
+ if (!TRI->regsOverlap(Reg, FakeUse->getOperand(0).getReg()))
+ RegFakeUses.erase(&FakeUse);
}
}
LivePhysRegs.stepBackward(MI);
diff --git a/llvm/test/CodeGen/X86/fake-use-remove-loads.mir b/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
index e001bbec637ac9..d82434d1b72cf7 100644
--- a/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
+++ b/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
@@ -13,18 +13,17 @@
## Also verify that the store to the stack slot still exists.
-# CHECK-LABEL: bb.5:
-# CHECK: MOV64mi32 $rbp, 1, $noreg, -48, $noreg, 0 :: (store (s64) into %stack.0)
-# CHECK-LABEL: bb.6:
+# CHECK-LABEL: bb.0:
+# CHECK: MOV64mr $rbp, 1, $noreg, -48, $noreg, killed renamable $rax :: (store (s64) into %stack.0)
+## Finally, verify that when the register has a use between the restore and the
+## FAKE_USE, we do not delete the load or fake use.
+
+# CHECK: renamable $r11 = MOV64rm $rbp, 1, $noreg, -40, $noreg :: (load (s64) from %stack.1)
+# CHECK: renamable $r12d = XOR32rr $r12d, $r11d, implicit-def dead $eflags
+# CHECK: FAKE_USE killed renamable $r11d
---- |
- define void @_ZN1g1jEv(ptr %this, i1 %cmp36, ptr %ref.tmp5) {
- entry:
- ret void
- }
-...
---
name: _ZN1g1jEv
alignment: 16
@@ -40,90 +39,36 @@ liveins:
frameInfo:
isCalleeSavedInfoValid: true
stack:
- - { id: 0, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8,
+ - { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+ - { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
stack-id: default, callee-saved-register: '', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
body: |
bb.0:
- successors: %bb.2(0x80000000)
- liveins: $esi, $rdi, $rdx, $r15, $r14, $r13, $r12, $rbx
-
- frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp
- frame-setup CFI_INSTRUCTION def_cfa_offset 16
- frame-setup CFI_INSTRUCTION offset $rbp, -16
- $rbp = frame-setup MOV64rr $rsp
- frame-setup CFI_INSTRUCTION def_cfa_register $rbp
- frame-setup PUSH64r killed $r15, implicit-def $rsp, implicit $rsp
- frame-setup PUSH64r killed $r14, implicit-def $rsp, implicit $rsp
- frame-setup PUSH64r killed $r13, implicit-def $rsp, implicit $rsp
- frame-setup PUSH64r killed $r12, implicit-def $rsp, implicit $rsp
- frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp
- frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp
- CFI_INSTRUCTION offset $rbx, -56
- CFI_INSTRUCTION offset $r12, -48
- CFI_INSTRUCTION offset $r13, -40
- CFI_INSTRUCTION offset $r14, -32
- CFI_INSTRUCTION offset $r15, -24
+ liveins: $esi, $rdi, $rdx, $r15, $r14, $r13, $r12, $r11, $rbx
+
$rbx = MOV64rr $rdx
$r14d = MOV32rr $esi
$r15 = MOV64rr $rdi
renamable $r12d = XOR32rr undef $r12d, undef $r12d, implicit-def dead $eflags, implicit-def $r12
renamable $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $rax
- JMP_1 %bb.2
-
- bb.1:
- successors: %bb.2(0x783e0f0f), %bb.6(0x07c1f0f1)
- liveins: $rbx, $r12, $r15, $r13d, $r14d
-
- renamable $rax = MOV64rm $rbp, 1, $noreg, -48, $noreg :: (load (s64) from %stack.0)
- FAKE_USE renamable $eax, implicit killed $rax
- renamable $eax = MOV32ri 1, implicit-def $rax
- TEST32rr killed renamable $r13d, renamable $r13d, implicit-def $eflags
- JCC_1 %bb.6, 9, implicit $eflags
-
- bb.2:
- successors: %bb.3(0x80000000)
- liveins: $rax, $rbx, $r12, $r15, $r14d
-
MOV64mr $rbp, 1, $noreg, -48, $noreg, killed renamable $rax :: (store (s64) into %stack.0)
+ MOV64mr $rbp, 1, $noreg, -40, $noreg, killed renamable $r11 :: (store (s64) into %stack.1)
renamable $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags
-
- bb.3:
- successors: %bb.4(0x04000000), %bb.3(0x7c000000)
- liveins: $eax, $rbx, $r12, $r15, $r14d
-
$r13d = MOV32rr killed $eax
$rdi = MOV64rr $r15
CALL64r renamable $r12, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
- dead renamable $eax = MOV32rm renamable $rbx, 1, $noreg, 0, $noreg :: (volatile load (s32) from %ir.ref.tmp5)
+ dead renamable $eax = MOV32rm renamable $rbx, 1, $noreg, 0, $noreg
renamable $eax = MOV32ri 1
TEST8ri renamable $r14b, 1, implicit-def $eflags
- JCC_1 %bb.3, 4, implicit $eflags
-
- bb.4:
- successors: %bb.5(0x40000000), %bb.1(0x40000000)
- liveins: $eflags, $rbx, $r12, $r15, $r13d, $r14d
-
- JCC_1 %bb.1, 4, implicit $eflags
-
- bb.5:
- successors: %bb.1(0x80000000)
- liveins: $rbx, $r12, $r15, $r13d, $r14d
-
- renamable $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $rax
- MOV64mi32 $rbp, 1, $noreg, -48, $noreg, 0 :: (store (s64) into %stack.0)
- CALL64r killed renamable $rax, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit-def dead $eax
- JMP_1 %bb.1
-
- bb.6:
- $rsp = frame-destroy ADD64ri32 $rsp, 8, implicit-def dead $eflags
- $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp
- $r12 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
- $r13 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
- $r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
- $r15 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
- $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp
- frame-destroy CFI_INSTRUCTION def_cfa $rsp, 8
+ renamable $rax = MOV64rm $rbp, 1, $noreg, -48, $noreg :: (load (s64) from %stack.0)
+ FAKE_USE renamable $eax, implicit killed $rax
+ renamable $r11 = MOV64rm $rbp, 1, $noreg, -40, $noreg :: (load (s64) from %stack.1)
+ renamable $r12d = XOR32rr $r12d, $r11d, implicit-def dead $eflags
+ FAKE_USE killed renamable $r11d
+ TEST32rr killed renamable $r13d, renamable $r13d, implicit-def $eflags
RET64
...
>From dc200af13c1a49b093e87eb0bbc32e74e43d73c6 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Wed, 16 Oct 2024 00:41:24 +0100
Subject: [PATCH 4/5] Use 'readsRegister'
---
llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
index 74ad2fe3858ea9..03bc8b33745eff 100644
--- a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
+++ b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
@@ -124,7 +124,7 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
SmallDenseSet<MachineInstr *> FakeUsesToDelete;
SmallVector<MachineInstr *> RemainingFakeUses;
for (MachineInstr *&FakeUse : reverse(RegFakeUses)) {
- if (TRI->regsOverlap(Reg, FakeUse->getOperand(0).getReg())) {
+ if (FakeUse->readsRegister(Reg, TRI)) {
FakeUsesToDelete.insert(FakeUse);
RegFakeUses.erase(&FakeUse);
}
@@ -159,7 +159,7 @@ bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
// because any such FAKE_USE encountered prior is no longer relevant
// for later encountered loads.
for (MachineInstr *&FakeUse : reverse(RegFakeUses))
- if (!TRI->regsOverlap(Reg, FakeUse->getOperand(0).getReg()))
+ if (FakeUse->readsRegister(Reg, TRI))
RegFakeUses.erase(&FakeUse);
}
}
>From dfdd8d8b2ee55fedf0e532391bb96372417d2feb Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Wed, 4 Dec 2024 17:46:23 +0000
Subject: [PATCH 5/5] Update test to check full output
---
.../CodeGen/X86/fake-use-remove-loads.mir | 67 ++++++++++++-------
1 file changed, 43 insertions(+), 24 deletions(-)
diff --git a/llvm/test/CodeGen/X86/fake-use-remove-loads.mir b/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
index d82434d1b72cf7..4283552a207401 100644
--- a/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
+++ b/llvm/test/CodeGen/X86/fake-use-remove-loads.mir
@@ -1,27 +1,17 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
# Ensure that loads into FAKE_USEs are correctly removed by the
# remove-loads-into-fake-uses pass.
-# RUN: llc -run-pass remove-loads-into-fake-uses -mtriple=x86_64-unknown-linux -debug-only=remove-loads-into-fake-uses 2>&1 -o - %s | FileCheck %s --implicit-check-not=DELETING
+# RUN: llc -run-pass remove-loads-into-fake-uses -mtriple=x86_64-unknown-linux -debug-only=remove-loads-into-fake-uses 2>&1 -o - %s | FileCheck %s
# REQUIRES: asserts
#
-## We ensure that the load into the FAKE_USE is removed, along with the FAKE_USE
-## itself, even when the FAKE_USE is for a subregister of the move, and that we
-## correctly handle situations where FAKE_USE has additional `killed` operands
-## added by other passes.
-
-# CHECK: DELETING: renamable $rax = MOV64rm $rbp
-# CHECK: DELETING: FAKE_USE renamable $eax
-
-## Also verify that the store to the stack slot still exists.
-
-# CHECK-LABEL: bb.0:
-# CHECK: MOV64mr $rbp, 1, $noreg, -48, $noreg, killed renamable $rax :: (store (s64) into %stack.0)
-
-## Finally, verify that when the register has a use between the restore and the
-## FAKE_USE, we do not delete the load or fake use.
-
-# CHECK: renamable $r11 = MOV64rm $rbp, 1, $noreg, -40, $noreg :: (load (s64) from %stack.1)
-# CHECK: renamable $r12d = XOR32rr $r12d, $r11d, implicit-def dead $eflags
-# CHECK: FAKE_USE killed renamable $r11d
+## We verify that:
+## - The load into the FAKE_USE is removed, along with the FAKE_USE itself,
+## even when the FAKE_USE is for a subregister of the move.
+## - We correctly handle situations where FAKE_USE has additional `killed`
+## operands added by other passes.
+## - The store to the stack slot still exists.
+## - When the register has a use between the restore and the FAKE_USE, we do
+## not delete the load or fake use.
---
@@ -39,16 +29,45 @@ liveins:
frameInfo:
isCalleeSavedInfoValid: true
stack:
- - { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
- stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ - { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
- - { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
- stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ - { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
body: |
bb.0:
liveins: $esi, $rdi, $rdx, $r15, $r14, $r13, $r12, $r11, $rbx
+ ; CHECK-LABEL: name: _ZN1g1jEv
+ ; CHECK: liveins: $esi, $rdi, $rdx, $r15, $r14, $r13, $r12, $r11, $rbx
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $rbx = MOV64rr $rdx
+ ; CHECK-NEXT: $r14d = MOV32rr $esi
+ ; CHECK-NEXT: $r15 = MOV64rr $rdi
+ ; CHECK-NEXT: renamable $r12d = XOR32rr undef $r12d, undef $r12d, implicit-def dead $eflags, implicit-def $r12
+ ; CHECK-NEXT: renamable $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $rax
+
+ ;; The store to the stack slot is still present.
+ ; CHECK-NEXT: MOV64mr $rbp, 1, $noreg, -48, $noreg, killed renamable $rax :: (store (s64) into %stack.0)
+
+ ; CHECK-NEXT: MOV64mr $rbp, 1, $noreg, -40, $noreg, killed renamable $r11 :: (store (s64) into %stack.1)
+ ; CHECK-NEXT: renamable $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags
+ ; CHECK-NEXT: $r13d = MOV32rr killed $eax
+ ; CHECK-NEXT: $rdi = MOV64rr $r15
+ ; CHECK-NEXT: CALL64r renamable $r12, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
+ ; CHECK-NEXT: dead renamable $eax = MOV32rm renamable $rbx, 1, $noreg, 0, $noreg
+ ; CHECK-NEXT: renamable $eax = MOV32ri 1
+ ; CHECK-NEXT: TEST8ri renamable $r14b, 1, implicit-def $eflags
+
+ ;; First FAKE_USE and its corresponding load are removed; second FAKE_USE of
+ ;; a restored value that is also used is preserved.
+ ; CHECK-NEXT: renamable $r11 = MOV64rm $rbp, 1, $noreg, -40, $noreg :: (load (s64) from %stack.1)
+ ; CHECK-NEXT: renamable $r12d = XOR32rr $r12d, $r11d, implicit-def dead $eflags
+ ; CHECK-NEXT: FAKE_USE killed renamable $r11d
+
+ ; CHECK-NEXT: TEST32rr killed renamable $r13d, renamable $r13d, implicit-def $eflags
+ ; CHECK-NEXT: RET64
$rbx = MOV64rr $rdx
$r14d = MOV32rr $esi
$r15 = MOV64rr $rdi
More information about the llvm-commits
mailing list