161 lines · cpp
1//===--------- llvm/unittests/Target/AMDGPU/LiveRegUnits.cpp --------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "AMDGPUTargetMachine.h"10#include "AMDGPUUnitTests.h"11#include "GCNSubtarget.h"12#include "llvm/CodeGen/MIRParser/MIRParser.h"13#include "llvm/CodeGen/MachineModuleInfo.h"14#include "llvm/MC/TargetRegistry.h"15#include "llvm/Support/SourceMgr.h"16#include "llvm/Support/TargetSelect.h"17#include "llvm/TargetParser/TargetParser.h"18#include "gtest/gtest.h"19 20#include "AMDGPUGenSubtargetInfo.inc"21 22using namespace llvm;23 24// FIXME: Consolidate parseMIR and other common helpers (this one is copied from25// unittests/MIR/MachineMetadata.cpp).26std::unique_ptr<Module> parseMIR(LLVMContext &Context, const TargetMachine &TM,27 StringRef MIRCode, const char *FnName,28 MachineModuleInfo &MMI) {29 SMDiagnostic Diagnostic;30 std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);31 auto MIR = createMIRParser(std::move(MBuffer), Context);32 if (!MIR)33 return nullptr;34 35 std::unique_ptr<Module> Mod = MIR->parseIRModule();36 if (!Mod)37 return nullptr;38 39 Mod->setDataLayout(TM.createDataLayout());40 41 if (MIR->parseMachineFunctions(*Mod, MMI)) {42 return nullptr;43 }44 45 return Mod;46}47 48TEST(AMDGPULiveRegUnits, TestVGPRBlockLoadStore) {49 auto TM = createAMDGPUTargetMachine("amdgcn-amd-", "gfx1200", "");50 ASSERT_TRUE(TM) << "No target machine";51 52 GCNSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),53 std::string(TM->getTargetFeatureString()), *TM);54 55 // Add a very simple MIR snippet that saves and restores a block of VGPRs. The56 // body of the function, represented by a S_NOP, clobbers one CSR (v42) and57 // one caller-saved register (v49), and reads one CSR (v61) and one58 // callee-saved register (v53).59 StringRef MIRString = R"MIR(60name: vgpr-block-insts61stack:62- { id: 0, name: '', type: spill-slot, offset: 0, size: 16, alignment: 4,63 stack-id: default, callee-saved-register: '$vgpr40_vgpr41_vgpr42_vgpr43_vgpr44_vgpr45_vgpr46_vgpr47_vgpr48_vgpr49_vgpr50_vgpr51_vgpr52_vgpr53_vgpr54_vgpr55_vgpr56_vgpr57_vgpr58_vgpr59_vgpr60_vgpr61_vgpr62_vgpr63_vgpr64_vgpr65_vgpr66_vgpr67_vgpr68_vgpr69_vgpr70_vgpr71',64 callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',65 debug-info-location: '' }66body: |67 bb.0:68 liveins: $sgpr30_sgpr31, $vgpr42_vgpr43_vgpr44_vgpr45_vgpr46_vgpr47_vgpr48_vgpr49_vgpr50_vgpr51_vgpr52_vgpr53_vgpr54_vgpr55_vgpr56_vgpr57_vgpr58_vgpr59_vgpr60_vgpr61_vgpr62_vgpr63_vgpr64_vgpr65_vgpr66_vgpr67_vgpr68_vgpr69_vgpr70_vgpr71_vgpr72_vgpr7369 70 $m0 = S_MOV_B32 171 SCRATCH_STORE_BLOCK_SADDR $vgpr42_vgpr43_vgpr44_vgpr45_vgpr46_vgpr47_vgpr48_vgpr49_vgpr50_vgpr51_vgpr52_vgpr53_vgpr54_vgpr55_vgpr56_vgpr57_vgpr58_vgpr59_vgpr60_vgpr61_vgpr62_vgpr63_vgpr64_vgpr65_vgpr66_vgpr67_vgpr68_vgpr69_vgpr70_vgpr71_vgpr72_vgpr73, $sgpr32, 0, 0, implicit $exec, implicit $flat_scr, implicit $m0 :: (store (s1024) into %stack.0, align 4, addrspace 5)72 S_NOP 0, implicit-def $vgpr42, implicit-def $vgpr49, implicit $vgpr53, implicit $vgpr6173 $m0 = S_MOV_B32 174 $vgpr42_vgpr43_vgpr44_vgpr45_vgpr46_vgpr47_vgpr48_vgpr49_vgpr50_vgpr51_vgpr52_vgpr53_vgpr54_vgpr55_vgpr56_vgpr57_vgpr58_vgpr59_vgpr60_vgpr61_vgpr62_vgpr63_vgpr64_vgpr65_vgpr66_vgpr67_vgpr68_vgpr69_vgpr70_vgpr71_vgpr72_vgpr73 = SCRATCH_LOAD_BLOCK_SADDR $sgpr32, 0, 0, implicit $exec, implicit $flat_scr, implicit $m0, implicit $vgpr43, implicit $vgpr44, implicit $vgpr45, implicit $vgpr46, implicit $vgpr47, implicit $vgpr56, implicit $vgpr57, implicit $vgpr58, implicit $vgpr59, implicit $vgpr60, implicit $vgpr61, implicit $vgpr62, implicit $vgpr63, implicit $vgpr72, implicit $vgpr73 :: (load (s1024) from %stack.0, align 4, addrspace 5)75 S_SETPC_B64_return $sgpr30_sgpr3176...77)MIR";78 79 LLVMContext Context;80 MachineModuleInfo MMI(TM.get());81 auto M = parseMIR(Context, *TM, MIRString, "vgpr-block-insts", MMI);82 83 auto *MF = MMI.getMachineFunction(*M->getFunction("vgpr-block-insts"));84 auto *MBB = MF->getBlockNumbered(0);85 86 auto MIt = --MBB->instr_end();87 88 LiveRegUnits LiveUnits;89 LiveUnits.init(*ST.getRegisterInfo());90 91 LiveUnits.addLiveOuts(*MBB);92 LiveUnits.stepBackward(*MIt);93 94 // Right after the restore, we expect all the CSRs to be unavailable.95 // Check v40-v88 (callee and caller saved regs interleaved in blocks of 8).96 for (unsigned I = 0; I < 8; ++I) {97 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR40 + I)) << "I = " << I;98 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR48 + I)) << "I = " << I;99 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR56 + I)) << "I = " << I;100 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR64 + I)) << "I = " << I;101 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR72 + I)) << "I = " << I;102 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR80 + I)) << "I = " << I;103 }104 105 --MIt;106 LiveUnits.stepBackward(*MIt);107 108 // Right before the restore, we expect the CSRs that are actually transferred109 // (in this case v42) to be available. Everything else should be the same as110 // before.111 for (unsigned I = 0; I < 8; ++I) {112 if (I == 2)113 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR40 + I)) << "I = " << I;114 else115 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR40 + I)) << "I = " << I;116 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR48 + I)) << "I = " << I;117 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR56 + I)) << "I = " << I;118 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR64 + I)) << "I = " << I;119 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR72 + I)) << "I = " << I;120 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR80 + I)) << "I = " << I;121 }122 123 --MIt; // Set m0 has no effect on VGPRs.124 LiveUnits.stepBackward(*MIt);125 --MIt; // S_NOP.126 LiveUnits.stepBackward(*MIt);127 128 // The S_NOP uses one of the caller-saved registers (v53), so that won't be129 // available anymore.130 for (unsigned I = 0; I < 8; ++I) {131 if (I == 2)132 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR40 + I)) << "I = " << I;133 else134 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR40 + I)) << "I = " << I;135 if (I == 5)136 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR48 + I)) << "I = " << I;137 else138 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR48 + I)) << "I = " << I;139 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR56 + I)) << "I = " << I;140 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR64 + I)) << "I = " << I;141 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR72 + I)) << "I = " << I;142 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR80 + I)) << "I = " << I;143 }144 145 --MIt;146 LiveUnits.stepBackward(*MIt);147 148 // Right before the save, all the VGPRs in the block that we're saving will be149 // unavailable, regardless of whether they're callee or caller saved. This is150 // unfortunate and should probably be fixed somehow.151 // VGPRs outside the block will only be unavailable if they're callee saved.152 for (unsigned I = 0; I < 8; ++I) {153 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR40 + I)) << "I = " << I;154 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR48 + I)) << "I = " << I;155 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR56 + I)) << "I = " << I;156 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR64 + I)) << "I = " << I;157 EXPECT_FALSE(LiveUnits.available(AMDGPU::VGPR72 + I)) << "I = " << I;158 EXPECT_TRUE(LiveUnits.available(AMDGPU::VGPR80 + I)) << "I = " << I;159 }160}161