| //===- RegisterPressureTest.cpp -------------------------------------------===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/CodeGen/RegisterPressure.h" | |
| #include "CodeGenTestBase.h" | |
| #include "llvm/CodeGen/LiveIntervals.h" | |
| #include "llvm/CodeGen/MIRParser/MIRParser.h" | |
| #include "llvm/CodeGen/TargetSubtargetInfo.h" | |
| #include "llvm/Config/Targets.h" | |
| #include "llvm/Passes/PassBuilder.h" | |
| #include "llvm/Support/TargetSelect.h" | |
| #include "gtest/gtest.h" | |
| using namespace llvm; | |
| class RegisterPressureTest : public CodeGenTestBase { | |
| public: | |
| static void SetUpTestCase() { | |
| #if LLVM_HAS_AMDGPU_TARGET | |
| LLVMInitializeAMDGPUTargetInfo(); | |
| LLVMInitializeAMDGPUTarget(); | |
| LLVMInitializeAMDGPUTargetMC(); | |
| #else | |
| GTEST_SKIP(); | |
| #endif | |
| } | |
| void SetUp() override { setUpImpl("amdgpu9.50--", "", ""); } | |
| }; | |
| /// Replicates the scheduler's effect on \p LIS on an intra-block move of \p | |
| /// MI right before \p MoveBefore, which must be in the same block as \p MI. | |
| static void moveMIAndAdjustLiveness(MachineBasicBlock::iterator MoveBefore, | |
| MachineInstr &MI, LiveIntervals &LIS) { | |
| MachineBasicBlock &MBB = *MI.getParent(); | |
| const MachineFunction &MF = *MBB.getParent(); | |
| const MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); | |
| MBB.splice(MoveBefore, &MBB, MI.getIterator()); | |
| LIS.handleMove(MI); | |
| RegisterOperands RegOpers; | |
| RegOpers.collect(MI, TRI, MRI, true, /*IgnoreDead=*/false); | |
| RegOpers.adjustLaneLiveness(LIS, MRI, MI); | |
| } | |
| /// When a scheduler move turns a live subregister def into the dead, last def | |
| /// of its virtual register, `adjustLaneLiveness` must add a dead flag on the | |
| /// def operand. Here %0.sub1 defines a lane that is never used: before the move | |
| /// it is a partially-dead def sitting in the middle of %0's merged live | |
| /// interval (legal without a dead flag), but sinking it below the use of | |
| /// %0.sub0 makes it the interval's terminal segment, which ends on a dead slot. | |
| TEST_F(RegisterPressureTest, MarkDeadDefAfterMoveBeyondLastUse) { | |
| StringRef MIRString = R"( | |
| --- | |
| name: func | |
| tracksRegLiveness: true | |
| machineFunctionInfo: | |
| isEntryFunction: true | |
| body: | | |
| bb.0: | |
| undef %0.sub0:vreg_64 = IMPLICIT_DEF | |
| %0.sub1:vreg_64 = IMPLICIT_DEF | |
| %1:vgpr_32 = V_ADD_U32_e32 %0.sub0, %0.sub0, implicit $exec | |
| bb.1: | |
| S_NOP 0, implicit %1 | |
| S_ENDPGM 0 | |
| ... | |
| )"; | |
| ASSERT_TRUE(parseMIR(MIRString)); | |
| MachineFunction &MF = getMF("func"); | |
| LiveIntervals &LIS = MFAM.getResult<LiveIntervalsAnalysis>(MF); | |
| MachineBasicBlock &MBB0 = *MF.getBlockNumbered(0); | |
| MachineInstr &Sub1Def = *std::next(MBB0.begin()); | |
| // Sink %0.sub1's (dead) def to the end of bb.0, past the use of %0.sub0. This | |
| // replicates a scheduler move: the def becomes the last, dead def of %0. | |
| moveMIAndAdjustLiveness(MBB0.end(), Sub1Def, LIS); | |
| EXPECT_TRUE(MF.verify(&LIS, /*Indexes=*/nullptr, /*Banner=*/nullptr, | |
| /*OS=*/&errs(), /*AbortOnError=*/false)); | |
| } |