brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.5 KiB · 593991c Raw
343 lines · cpp
1//===--------- llvm/unittests/Target/AMDGPU/AMDGPUUnitTests.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 "AMDGPUUnitTests.h"10#include "AMDGPUTargetMachine.h"11#include "GCNSubtarget.h"12#include "llvm/MC/TargetRegistry.h"13#include "llvm/Support/TargetSelect.h"14#include "llvm/TargetParser/TargetParser.h"15#include "gtest/gtest.h"16 17#include "AMDGPUGenSubtargetInfo.inc"18 19using namespace llvm;20 21std::once_flag flag;22 23void InitializeAMDGPUTarget() {24  std::call_once(flag, []() {25    LLVMInitializeAMDGPUTargetInfo();26    LLVMInitializeAMDGPUTarget();27    LLVMInitializeAMDGPUTargetMC();28  });29}30 31std::unique_ptr<const GCNTargetMachine>32llvm::createAMDGPUTargetMachine(std::string TStr, StringRef CPU, StringRef FS) {33  InitializeAMDGPUTarget();34 35  Triple TT(TStr);36  std::string Error;37  const Target *T = TargetRegistry::lookupTarget(TT, Error);38  if (!T)39    return nullptr;40 41  TargetOptions Options;42  return std::unique_ptr<GCNTargetMachine>(43      static_cast<GCNTargetMachine *>(T->createTargetMachine(44          TT, CPU, FS, Options, std::nullopt, std::nullopt)));45}46 47static cl::opt<bool> PrintCpuRegLimits(48    "print-cpu-reg-limits", cl::NotHidden, cl::init(false),49    cl::desc("force printing per AMDGPU CPU register limits"));50 51static bool checkMinMax(std::stringstream &OS, unsigned Occ, unsigned MinOcc,52                        unsigned MaxOcc,53                        std::function<unsigned(unsigned)> GetOcc,54                        std::function<unsigned(unsigned)> GetMinGPRs,55                        std::function<unsigned(unsigned)> GetMaxGPRs) {56  bool MinValid = true, MaxValid = true, RangeValid = true;57  unsigned MinGPRs = GetMinGPRs(Occ);58  unsigned MaxGPRs = GetMaxGPRs(Occ);59  unsigned RealOcc;60 61  if (MinGPRs >= MaxGPRs)62    RangeValid = false;63  else {64    RealOcc = GetOcc(MinGPRs);65    for (unsigned NumRegs = MinGPRs + 1; NumRegs <= MaxGPRs; ++NumRegs) {66      if (RealOcc != GetOcc(NumRegs)) {67        RangeValid = false;68        break;69      }70    }71  }72 73  if (RangeValid && RealOcc > MinOcc && RealOcc <= MaxOcc) {74    if (MinGPRs > 0 && GetOcc(MinGPRs - 1) <= RealOcc)75      MinValid = false;76 77    if (GetOcc(MaxGPRs + 1) >= RealOcc)78      MaxValid = false;79  }80 81  std::stringstream MinStr;82  MinStr << (MinValid ? ' ' : '<') << ' ' << std::setw(3) << MinGPRs << " (O"83         << GetOcc(MinGPRs) << ") " << (RangeValid ? ' ' : 'R');84 85  OS << std::left << std::setw(15) << MinStr.str() << std::setw(3) << MaxGPRs86     << " (O" << GetOcc(MaxGPRs) << ')' << (MaxValid ? "" : " >");87 88  return MinValid && MaxValid && RangeValid;89}90 91static const std::pair<StringRef, StringRef>92  EmptyFS = {"", ""},93  W32FS = {"+wavefrontsize32", "w32"},94  W64FS = {"+wavefrontsize64", "w64"};95 96using TestFuncTy = function_ref<bool(std::stringstream &, unsigned,97                                     const GCNSubtarget &, bool)>;98 99static bool testAndRecord(std::stringstream &Table, const GCNSubtarget &ST,100                          TestFuncTy test, unsigned DynamicVGPRBlockSize) {101  bool Success = true;102  unsigned MaxOcc = ST.getMaxWavesPerEU();103  for (unsigned Occ = MaxOcc; Occ > 0; --Occ) {104    Table << std::right << std::setw(3) << Occ << "    ";105    Success = test(Table, Occ, ST, DynamicVGPRBlockSize) && Success;106    Table << '\n';107  }108  return Success;109}110 111static void testGPRLimits(const char *RegName, bool TestW32W64,112                          TestFuncTy test) {113  SmallVector<StringRef> CPUs;114  AMDGPU::fillValidArchListAMDGCN(CPUs);115 116  std::map<std::string, SmallVector<std::string>> TablePerCPUs;117  for (auto CPUName : CPUs) {118    auto CanonCPUName =119        AMDGPU::getArchNameAMDGCN(AMDGPU::parseArchAMDGCN(CPUName));120 121    auto *FS = &EmptyFS;122    while (true) {123      auto TM = createAMDGPUTargetMachine("amdgcn-amd-", CPUName, FS->first);124      if (!TM)125        break;126 127      GCNSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),128                      std::string(TM->getTargetFeatureString()), *TM);129 130      if (TestW32W64 &&131          ST.getFeatureBits().test(AMDGPU::FeatureWavefrontSize32))132        FS = &W32FS;133 134      std::stringstream Table;135      bool Success = testAndRecord(Table, ST, test, /*DynamicVGPRBlockSize=*/0);136      if (!Success || PrintCpuRegLimits)137        TablePerCPUs[Table.str()].push_back((CanonCPUName + FS->second).str());138 139      if (FS != &W32FS)140        break;141 142      FS = &W64FS;143    }144  }145  std::stringstream OS;146  for (auto &P : TablePerCPUs) {147    for (auto &CPUName : P.second)148      OS << ' ' << CPUName;149    OS << ":\nOcc    Min" << RegName << "        Max" << RegName << '\n'150       << P.first << '\n';151  }152  auto ErrStr = OS.str();153  EXPECT_TRUE(ErrStr.empty()) << ErrStr;154}155 156static void testDynamicVGPRLimits(StringRef CPUName, StringRef FS,157                                  TestFuncTy test) {158  auto TM = createAMDGPUTargetMachine("amdgcn-amd-", CPUName, FS);159  ASSERT_TRUE(TM) << "No target machine";160 161  GCNSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),162                  std::string(TM->getTargetFeatureString()), *TM);163 164  auto testWithBlockSize = [&](unsigned DynamicVGPRBlockSize) {165    std::stringstream Table;166    bool Success = testAndRecord(Table, ST, test, DynamicVGPRBlockSize);167    EXPECT_TRUE(Success && !PrintCpuRegLimits)168        << CPUName << " dynamic VGPR block size " << DynamicVGPRBlockSize169        << ":\nOcc    MinVGPR        MaxVGPR\n"170        << Table.str() << '\n';171  };172 173  testWithBlockSize(16);174  testWithBlockSize(32);175}176 177TEST(AMDGPU, TestVGPRLimitsPerOccupancy) {178  auto test = [](std::stringstream &OS, unsigned Occ, const GCNSubtarget &ST,179                 unsigned DynamicVGPRBlockSize) {180    unsigned MaxVGPRNum = ST.getAddressableNumVGPRs(DynamicVGPRBlockSize);181    return checkMinMax(182        OS, Occ, ST.getOccupancyWithNumVGPRs(MaxVGPRNum, DynamicVGPRBlockSize),183        ST.getMaxWavesPerEU(),184        [&](unsigned NumGPRs) {185          return ST.getOccupancyWithNumVGPRs(NumGPRs, DynamicVGPRBlockSize);186        },187        [&](unsigned Occ) {188          return ST.getMinNumVGPRs(Occ, DynamicVGPRBlockSize);189        },190        [&](unsigned Occ) {191          return ST.getMaxNumVGPRs(Occ, DynamicVGPRBlockSize);192        });193  };194 195  testGPRLimits("VGPR", true, test);196 197  testDynamicVGPRLimits("gfx1200", "+wavefrontsize32", test);198}199 200static void testAbsoluteLimits(StringRef CPUName, StringRef FS,201                               unsigned DynamicVGPRBlockSize,202                               unsigned ExpectedMinOcc, unsigned ExpectedMaxOcc,203                               unsigned ExpectedMaxVGPRs) {204  auto TM = createAMDGPUTargetMachine("amdgcn-amd-", CPUName, FS);205  ASSERT_TRUE(TM) << "No target machine";206 207  GCNSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),208                  std::string(TM->getTargetFeatureString()), *TM);209 210  // Test function without attributes.211  LLVMContext Context;212  Module M("", Context);213  Function *Func =214      Function::Create(FunctionType::get(Type::getVoidTy(Context), false),215                       GlobalValue::ExternalLinkage, "testFunc", &M);216  Func->setCallingConv(CallingConv::AMDGPU_CS_Chain);217  Func->addFnAttr("amdgpu-flat-work-group-size", "1,32");218 219  std::string DVGPRBlockSize = std::to_string(DynamicVGPRBlockSize);220  if (DynamicVGPRBlockSize)221    Func->addFnAttr("amdgpu-dynamic-vgpr-block-size", DVGPRBlockSize);222 223  auto Range = ST.getWavesPerEU(*Func);224  EXPECT_EQ(ExpectedMinOcc, Range.first) << CPUName << ' ' << FS;225  EXPECT_EQ(ExpectedMaxOcc, Range.second) << CPUName << ' ' << FS;226  EXPECT_EQ(ExpectedMaxVGPRs, ST.getMaxNumVGPRs(*Func)) << CPUName << ' ' << FS;227  EXPECT_EQ(ExpectedMaxVGPRs, ST.getAddressableNumVGPRs(DynamicVGPRBlockSize))228      << CPUName << ' ' << FS;229 230  // Function with requested 'amdgpu-waves-per-eu' in a valid range.231  Func->addFnAttr("amdgpu-waves-per-eu", "10,12");232  Range = ST.getWavesPerEU(*Func);233  EXPECT_EQ(10u, Range.first) << CPUName << ' ' << FS;234  EXPECT_EQ(12u, Range.second) << CPUName << ' ' << FS;235}236 237TEST(AMDGPU, TestOccupancyAbsoluteLimits) {238  // CPUName, Features, DynamicVGPRBlockSize; Expected MinOcc, MaxOcc, MaxVGPRs239  testAbsoluteLimits("gfx1200", "+wavefrontsize32", 0, 1, 16, 256);240  testAbsoluteLimits("gfx1200", "+wavefrontsize32", 16, 1, 16, 128);241  testAbsoluteLimits("gfx1200", "+wavefrontsize32", 32, 1, 16, 256);242}243 244static const char *printSubReg(const TargetRegisterInfo &TRI, unsigned SubReg) {245  return SubReg ? TRI.getSubRegIndexName(SubReg) : "<none>";246}247 248TEST(AMDGPU, TestReverseComposeSubRegIndices) {249  auto TM = createAMDGPUTargetMachine("amdgcn-amd-", "gfx900", "");250  if (!TM)251    return;252  GCNSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),253                  std::string(TM->getTargetFeatureString()), *TM);254 255  const SIRegisterInfo *TRI = ST.getRegisterInfo();256 257#define EXPECT_SUBREG_EQ(A, B, Expect)                                         \258  do {                                                                         \259    unsigned Reversed = TRI->reverseComposeSubRegIndices(A, B);                \260    EXPECT_EQ(Reversed, Expect)                                                \261        << printSubReg(*TRI, A) << ", " << printSubReg(*TRI, B) << " => "      \262        << printSubReg(*TRI, Reversed) << ", *" << printSubReg(*TRI, Expect);  \263  } while (0);264 265  EXPECT_SUBREG_EQ(AMDGPU::NoSubRegister, AMDGPU::sub0, AMDGPU::sub0);266  EXPECT_SUBREG_EQ(AMDGPU::sub0, AMDGPU::NoSubRegister, AMDGPU::sub0);267 268  EXPECT_SUBREG_EQ(AMDGPU::sub0, AMDGPU::sub0, AMDGPU::sub0);269 270  EXPECT_SUBREG_EQ(AMDGPU::sub0, AMDGPU::sub1, AMDGPU::sub1);271  EXPECT_SUBREG_EQ(AMDGPU::sub1, AMDGPU::sub0, AMDGPU::NoSubRegister);272 273  EXPECT_SUBREG_EQ(AMDGPU::sub0_sub1, AMDGPU::sub0, AMDGPU::sub0);274  EXPECT_SUBREG_EQ(AMDGPU::sub0, AMDGPU::sub0_sub1, AMDGPU::sub0_sub1);275 276  EXPECT_SUBREG_EQ(AMDGPU::sub0_sub1_sub2_sub3, AMDGPU::sub0_sub1,277                   AMDGPU::sub0_sub1);278  EXPECT_SUBREG_EQ(AMDGPU::sub0_sub1, AMDGPU::sub0_sub1_sub2_sub3,279                   AMDGPU::sub0_sub1_sub2_sub3);280 281  EXPECT_SUBREG_EQ(AMDGPU::sub0_sub1_sub2_sub3, AMDGPU::sub1_sub2,282                   AMDGPU::sub1_sub2);283  EXPECT_SUBREG_EQ(AMDGPU::sub1_sub2, AMDGPU::sub0_sub1_sub2_sub3,284                   AMDGPU::NoSubRegister);285 286  EXPECT_SUBREG_EQ(AMDGPU::sub1_sub2_sub3, AMDGPU::sub0_sub1_sub2_sub3,287                   AMDGPU::NoSubRegister);288  EXPECT_SUBREG_EQ(AMDGPU::sub0_sub1_sub2_sub3, AMDGPU::sub1_sub2_sub3,289                   AMDGPU::sub1_sub2_sub3);290 291  EXPECT_SUBREG_EQ(AMDGPU::sub0, AMDGPU::sub30, AMDGPU::NoSubRegister);292  EXPECT_SUBREG_EQ(AMDGPU::sub30, AMDGPU::sub0, AMDGPU::NoSubRegister);293 294  EXPECT_SUBREG_EQ(AMDGPU::sub0, AMDGPU::sub31, AMDGPU::NoSubRegister);295  EXPECT_SUBREG_EQ(AMDGPU::sub31, AMDGPU::sub0, AMDGPU::NoSubRegister);296 297  EXPECT_SUBREG_EQ(AMDGPU::sub0_sub1, AMDGPU::sub30, AMDGPU::NoSubRegister);298  EXPECT_SUBREG_EQ(AMDGPU::sub30, AMDGPU::sub0_sub1, AMDGPU::NoSubRegister);299 300  EXPECT_SUBREG_EQ(AMDGPU::sub0_sub1, AMDGPU::sub30_sub31,301                   AMDGPU::NoSubRegister);302  EXPECT_SUBREG_EQ(AMDGPU::sub30_sub31, AMDGPU::sub0_sub1,303                   AMDGPU::NoSubRegister);304 305  for (unsigned SubIdx0 = 1, LastSubReg = TRI->getNumSubRegIndices();306       SubIdx0 != LastSubReg; ++SubIdx0) {307    for (unsigned SubIdx1 = 1; SubIdx1 != LastSubReg; ++SubIdx1) {308      if (unsigned ForwardCompose =309              TRI->composeSubRegIndices(SubIdx0, SubIdx1)) {310        unsigned ReverseComposed =311            TRI->reverseComposeSubRegIndices(SubIdx0, ForwardCompose);312        EXPECT_EQ(ReverseComposed, SubIdx1);313      }314 315      if (unsigned ReverseCompose =316              TRI->reverseComposeSubRegIndices(SubIdx0, SubIdx1)) {317        unsigned Recompose = TRI->composeSubRegIndices(SubIdx0, ReverseCompose);318        EXPECT_EQ(Recompose, SubIdx1);319      }320    }321  }322}323 324TEST(AMDGPU, TestGetNamedOperandIdx) {325  std::unique_ptr<const GCNTargetMachine> TM =326      createAMDGPUTargetMachine("amdgcn-amd-", "gfx900", "");327  if (!TM)328    return;329  const MCInstrInfo *MCII = TM->getMCInstrInfo();330 331  for (unsigned Opcode = 0, E = MCII->getNumOpcodes(); Opcode != E; ++Opcode) {332    const MCInstrDesc &Desc = MCII->get(Opcode);333    for (unsigned Idx = 0; Idx < Desc.getNumOperands(); ++Idx) {334      AMDGPU::OpName OpName = AMDGPU::getOperandIdxName(Opcode, Idx);335      if (OpName == AMDGPU::OpName::NUM_OPERAND_NAMES)336        continue;337      int16_t RetrievedIdx = AMDGPU::getNamedOperandIdx(Opcode, OpName);338      EXPECT_EQ(Idx, static_cast<unsigned>(RetrievedIdx))339          << "Opcode " << Opcode << " (" << MCII->getName(Opcode) << ')';340    }341  }342}343