[llvm] [NextUseAnalysis] Add updateInstrIds() method. (PR #209954)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 15 21:01:31 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
Author: Konstantina Mitropoulou (kmitropoulou)
<details>
<summary>Changes</summary>
During spilling, we emit spill/restore instructions. Hence, the ID of the instructions change. For example, let's assume that we calculate the distance from a restore to its use. The restore will get a new ID, but the use will not get a new ID because it is already in the map.
The updateInstrIds() update the instruction IDs of the basic block where the new instruction is added.
It should be called every time we emit a spill or restore instruction.
This method is similar to insertMachineInstrInMaps() from slot indexes.
---
Full diff: https://github.com/llvm/llvm-project/pull/209954.diff
4 Files Affected:
- (modified) llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp (+9)
- (modified) llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.h (+2)
- (added) llvm/unittests/Target/AMDGPU/AMDGPUNextUseAnalysisTest.cpp (+239)
- (modified) llvm/unittests/Target/AMDGPU/CMakeLists.txt (+1)
``````````diff
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
index cad1513f280fb..0f3abadc9446d 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
@@ -2106,6 +2106,11 @@ class llvm::AMDGPUNextUseAnalysisImpl {
return getShortestDistance(LiveReg, LaneBitmask::getAll(), FromMI, Uses,
nullptr, nullptr, nullptr);
}
+
+ void updateInstrIds(const MachineInstr *MI) const {
+ auto &MutableInstrToId = const_cast<InstrToIdMap &>(InstrToId);
+ calcInstrIds(MI->getParent(), MutableInstrToId);
+ }
};
AMDGPUNextUseAnalysisImpl::AMDGPUNextUseAnalysisImpl(
@@ -2265,6 +2270,10 @@ void AMDGPUNextUseAnalysis::getReachableUses(
return Impl->getReachableUses(LiveReg, LaneMask, MI, Uses);
}
+void AMDGPUNextUseAnalysis::updateInstrIds(const MachineInstr *MI) const {
+ return Impl->updateInstrIds(MI);
+}
+
//==============================================================================
// AMDGPUNextUseAnalysisLegacyPass
//==============================================================================
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.h b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.h
index 1c6e5b1d8cbce..da0b15f23d668 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.h
@@ -310,6 +310,8 @@ class AMDGPUNextUseAnalysis {
UseDistancePair *FurthestSubreg = nullptr,
DenseMap<const MachineOperand *, UseDistancePair>
*RelevantUses = nullptr) const;
+
+ void updateInstrIds(const MachineInstr *MI) const;
};
//==============================================================================
diff --git a/llvm/unittests/Target/AMDGPU/AMDGPUNextUseAnalysisTest.cpp b/llvm/unittests/Target/AMDGPU/AMDGPUNextUseAnalysisTest.cpp
new file mode 100644
index 0000000000000..e268647e0a1fc
--- /dev/null
+++ b/llvm/unittests/Target/AMDGPU/AMDGPUNextUseAnalysisTest.cpp
@@ -0,0 +1,239 @@
+//===- AMDGPUNextUseAnalysisTest.cpp ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Unit tests for AMDGPUNextUseAnalysis.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPUNextUseAnalysis.h"
+#include "AMDGPUUnitTests.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+class AMDGPUNextUseAnalysisTest : public AMDGPUCodeGenTestBase {
+public:
+ void SetUp() override { setUpImpl("amdgcn-amd-amdhsa", "gfx1310", ""); }
+};
+
+// Test that distance calculation works correctly when multiple instructions
+// are inserted at different points in the basic block.
+TEST_F(AMDGPUNextUseAnalysisTest, DistanceAfterInstructionInsertion) {
+ StringRef MIR = R"(
+name: DistanceAfterInstructionInsertion
+tracksRegLiveness: true
+machineFunctionInfo:
+ isEntryFunction: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+ %0:vgpr_32 = COPY $vgpr0
+ %1:vgpr_32 = V_MOV_B32_e32 1, implicit $exec
+ %2:vgpr_32 = V_MOV_B32_e32 2, implicit $exec
+ %3:vgpr_32 = V_ADD_U32_e32 %0, %1, implicit $exec
+ %4:vgpr_32 = V_ADD_U32_e32 %3, %2, implicit $exec
+ S_NOP 0, implicit %4
+ S_ENDPGM 0
+...
+)";
+ EXPECT_TRUE(parseMIR(MIR));
+ MachineFunction &MF = getMF("DistanceAfterInstructionInsertion");
+ AMDGPUNextUseAnalysis &NUA = MFAM.getResult<AMDGPUNextUseAnalysisPass>(MF);
+
+ MachineBasicBlock &MBB = *MF.begin();
+ const auto &TII = *MF.getSubtarget().getInstrInfo();
+
+ auto It = MBB.begin();
+ std::advance(It, 3);
+ MachineInstr &Add1 = *It++;
+ MachineInstr &Add2 = *It++;
+ MachineInstr &Nop1 = *It;
+
+ Register Add1DefReg = Add1.getOperand(0).getReg();
+
+ // Add a new multiplication before the first ADD.
+ Register NewReg1 =
+ MF.getRegInfo().createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+ MachineInstr *NewMul1 = BuildMI(MBB, Add1.getIterator(), DebugLoc(),
+ TII.get(AMDGPU::V_MUL_U32_U24_e64), NewReg1)
+ .addImm(0)
+ .addImm(1)
+ .addImm(2)
+ .getInstr();
+
+ NUA.updateInstrIds(NewMul1);
+
+ // Add the destination register of the first multiplication as an input
+ // operand of the fist ADD.
+ Add1.getOperand(1).setReg(NewReg1);
+
+ // Add a second multiplication before the first ADD
+ Register NewReg2 =
+ MF.getRegInfo().createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+ MachineInstr *NewMul2 = BuildMI(MBB, Add1.getIterator(), DebugLoc(),
+ TII.get(AMDGPU::V_MUL_U32_U24_e64), NewReg2)
+ .addImm(0)
+ .addImm(3)
+ .addImm(4)
+ .getInstr();
+
+ NUA.updateInstrIds(NewMul2);
+
+ // Add the destination register of the second multiplication as an input
+ // operand of the second ADD.
+ Add2.getOperand(1).setReg(NewReg2);
+
+ Register Add2DefReg = Add2.getOperand(0).getReg();
+
+ // Add a third multiplication before the second ADD
+ Register NewReg3 =
+ MF.getRegInfo().createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+ MachineInstr *NewMul3 = BuildMI(MBB, Add2.getIterator(), DebugLoc(),
+ TII.get(AMDGPU::V_MUL_U32_U24_e64), NewReg3)
+ .addImm(0)
+ .addImm(5)
+ .addImm(6)
+ .getInstr();
+
+ NUA.updateInstrIds(NewMul3);
+
+ MachineInstr *Nop2 =
+ BuildMI(MBB, MBB.back().getIterator(), DebugLoc(), TII.get(AMDGPU::S_NOP))
+ .addImm(0)
+ .addReg(Add1DefReg, RegState::Implicit)
+ .addReg(Add2DefReg, RegState::Implicit)
+ .getInstr();
+ NUA.updateInstrIds(Nop2);
+
+ // Add the destination register of the third multiplication as an input
+ // operand of the first NOP.
+ for (MachineOperand &MO : Nop1.operands()) {
+ if (MO.isReg() && MO.isUse())
+ MO.setReg(NewReg3);
+ }
+
+ // Instruction order after the insertion of the new instructions.
+ // %0:vgpr_32 = COPY $vgpr0
+ // %1:vgpr_32 = V_MOV_B32_e32 1, implicit $exec
+ // %2:vgpr_32 = V_MOV_B32_e32 2, implicit $exec
+ // %5:vgpr_32 = V_MUL_U32_U24_e64 0, 1, 2, implicit $exec
+ // %6:vgpr_32 = V_MUL_U32_U24_e64 0, 3, 4, implicit $exec
+ // %3:vgpr_32 = V_ADD_U32_e32 %5:vgpr_32, %1:vgpr_32, implicit $exec
+ // %7:vgpr_32 = V_MUL_U32_U24_e64 0, 5, 6, implicit $exec
+ // %4:vgpr_32 = V_ADD_U32_e32 %6:vgpr_32, %2:vgpr_32, implicit $exec
+ // S_NOP 0, implicit %7:vgpr_32
+ // S_NOP 0, implicit %3:vgpr_32, implicit %4:vgpr_32
+ // S_ENDPGM 0
+
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ SmallVector<const MachineOperand *> Add1Uses;
+ for (MachineInstr &UseMI : MRI.use_nodbg_instructions(Add1DefReg))
+ for (const MachineOperand &MO : UseMI.uses())
+ if (MO.isReg() && MO.getReg() == Add1DefReg)
+ Add1Uses.push_back(&MO);
+
+ SmallVector<const MachineOperand *> Add2Uses;
+ for (MachineInstr &UseMI : MRI.use_nodbg_instructions(Add2DefReg))
+ for (const MachineOperand &MO : UseMI.uses())
+ if (MO.isReg() && MO.getReg() == Add2DefReg)
+ Add2Uses.push_back(&MO);
+
+ SmallVector<const MachineOperand *> Mul1Uses;
+ for (MachineInstr &UseMI : MRI.use_nodbg_instructions(NewReg1))
+ for (const MachineOperand &MO : UseMI.uses())
+ if (MO.isReg() && MO.getReg() == NewReg1)
+ Mul1Uses.push_back(&MO);
+
+ SmallVector<const MachineOperand *> Mul2Uses;
+ for (MachineInstr &UseMI : MRI.use_nodbg_instructions(NewReg2))
+ for (const MachineOperand &MO : UseMI.uses())
+ if (MO.isReg() && MO.getReg() == NewReg2)
+ Mul2Uses.push_back(&MO);
+
+ SmallVector<const MachineOperand *> Mul3Uses;
+ for (MachineInstr &UseMI : MRI.use_nodbg_instructions(NewReg3))
+ for (const MachineOperand &MO : UseMI.uses())
+ if (MO.isReg() && MO.getReg() == NewReg3)
+ Mul3Uses.push_back(&MO);
+
+ NextUseDistance DistNewMul1 =
+ NUA.getShortestDistance(NewReg1, *NewMul1, Mul1Uses);
+ EXPECT_EQ(DistNewMul1.getRawValue(), 2);
+
+ NextUseDistance DistNewMul2 =
+ NUA.getShortestDistance(NewReg2, *NewMul2, Mul2Uses);
+ EXPECT_EQ(DistNewMul2.getRawValue(), 3);
+
+ NextUseDistance DistAdd1 =
+ NUA.getShortestDistance(Add1DefReg, Add1, Add1Uses);
+ EXPECT_EQ(DistAdd1.getRawValue(), 4);
+
+ NextUseDistance DistNewMul3 =
+ NUA.getShortestDistance(NewReg3, *NewMul3, Mul3Uses);
+ EXPECT_EQ(DistNewMul3.getRawValue(), 2);
+
+ NextUseDistance DistAdd2 =
+ NUA.getShortestDistance(Add2DefReg, Add2, Add2Uses);
+ EXPECT_EQ(DistAdd2.getRawValue(), 2);
+
+ // Add a fourth multiplication after the second ADD.
+ Register NewReg4 =
+ MF.getRegInfo().createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+ MachineInstr *NewMul4 = BuildMI(MBB, Nop1.getIterator(), DebugLoc(),
+ TII.get(AMDGPU::V_MUL_U32_U24_e64), NewReg4)
+ .addImm(0)
+ .addImm(7)
+ .addImm(8)
+ .getInstr();
+
+ NUA.updateInstrIds(NewMul4);
+
+ MachineInstr *Nop3 =
+ BuildMI(MBB, MBB.back().getIterator(), DebugLoc(), TII.get(AMDGPU::S_NOP))
+ .addImm(0)
+ .addReg(NewReg4, RegState::Implicit)
+ .getInstr();
+ NUA.updateInstrIds(Nop3);
+
+ // Instructions after emitting more instructions.
+ // %0:vgpr_32 = COPY $vgpr0
+ // %1:vgpr_32 = V_MOV_B32_e32 1, implicit $exec
+ // %2:vgpr_32 = V_MOV_B32_e32 2, implicit $exec
+ // %5:vgpr_32 = V_MUL_U32_U24_e64 0, 1, 2, implicit $exec
+ // %6:vgpr_32 = V_MUL_U32_U24_e64 0, 3, 4, implicit $exec
+ // %3:vgpr_32 = V_ADD_U32_e32 %5:vgpr_32, %1:vgpr_32, implicit $exec
+ // %7:vgpr_32 = V_MUL_U32_U24_e64 0, 5, 6, implicit $exec
+ // %4:vgpr_32 = V_ADD_U32_e32 %6:vgpr_32, %2:vgpr_32, implicit $exec
+ // %8:vgpr_32 = V_MUL_U32_U24_e64 0, 7, 8, implicit $exec
+ // S_NOP 0, implicit %7:vgpr_32
+ // S_NOP 0, implicit %3:vgpr_32, implicit %4:vgpr_32
+ // S_NOP 0, implicit %8:vgpr_32
+ // S_ENDPGM 0
+
+ SmallVector<const MachineOperand *> Mul4Uses;
+ for (MachineInstr &UseMI : MRI.use_nodbg_instructions(NewReg4))
+ for (const MachineOperand &MO : UseMI.uses())
+ if (MO.isReg() && MO.getReg() == NewReg4)
+ Mul4Uses.push_back(&MO);
+
+ NextUseDistance DistAdd1b =
+ NUA.getShortestDistance(Add1DefReg, Add1, Add1Uses);
+ EXPECT_EQ(DistAdd1b.getRawValue(), 5);
+
+ NextUseDistance DistAdd2b =
+ NUA.getShortestDistance(Add2DefReg, Add2, Add2Uses);
+ EXPECT_EQ(DistAdd2b.getRawValue(), 3);
+
+ NextUseDistance DistNewMul4 =
+ NUA.getShortestDistance(NewReg4, *NewMul4, Mul4Uses);
+ EXPECT_EQ(DistNewMul4.getRawValue(), 3);
+}
diff --git a/llvm/unittests/Target/AMDGPU/CMakeLists.txt b/llvm/unittests/Target/AMDGPU/CMakeLists.txt
index 77335a57520bc..af35c7ccb1131 100644
--- a/llvm/unittests/Target/AMDGPU/CMakeLists.txt
+++ b/llvm/unittests/Target/AMDGPU/CMakeLists.txt
@@ -24,6 +24,7 @@ set(LLVM_LINK_COMPONENTS
add_llvm_target_unittest(AMDGPUTests
AMDGPUMCExprTest.cpp
+ AMDGPUNextUseAnalysisTest.cpp
AMDGPUUnitTests.cpp
CSETest.cpp
DwarfRegMappings.cpp
``````````
</details>
https://github.com/llvm/llvm-project/pull/209954
More information about the llvm-commits
mailing list