blob: e08a4c09931a3d081fc2dcf26c7ef7e506022296 [file] [edit]
//===- 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));
}