brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.9 KiB · 2744dbc Raw
386 lines · cpp
1//===- RISCVInstrInfoTest.cpp - RISCVInstrInfo unit tests -----------------===//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 "RISCVInstrInfo.h"10#include "RISCVSubtarget.h"11#include "RISCVTargetMachine.h"12#include "llvm/CodeGen/MachineModuleInfo.h"13#include "llvm/IR/DebugInfoMetadata.h"14#include "llvm/IR/Module.h"15#include "llvm/MC/TargetRegistry.h"16#include "llvm/Support/TargetSelect.h"17#include "llvm/Target/TargetLoweringObjectFile.h"18#include "llvm/Target/TargetMachine.h"19#include "llvm/Target/TargetOptions.h"20 21#include "gtest/gtest.h"22 23#include <memory>24 25using namespace llvm;26 27namespace {28 29class RISCVInstrInfoTest : public testing::TestWithParam<const char *> {30protected:31  std::unique_ptr<RISCVTargetMachine> TM;32  std::unique_ptr<LLVMContext> Ctx;33  std::unique_ptr<RISCVSubtarget> ST;34  std::unique_ptr<MachineModuleInfo> MMI;35  std::unique_ptr<MachineFunction> MF;36  std::unique_ptr<Module> M;37 38  static void SetUpTestSuite() {39    LLVMInitializeRISCVTargetInfo();40    LLVMInitializeRISCVTarget();41    LLVMInitializeRISCVTargetMC();42  }43 44  RISCVInstrInfoTest() {45    std::string Error;46    Triple TT(GetParam());47    const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);48    TargetOptions Options;49 50    TM.reset(static_cast<RISCVTargetMachine *>(TheTarget->createTargetMachine(51        TT, "generic", "", Options, std::nullopt, std::nullopt,52        CodeGenOptLevel::Default)));53 54    Ctx = std::make_unique<LLVMContext>();55    M = std::make_unique<Module>("Module", *Ctx);56    M->setDataLayout(TM->createDataLayout());57    auto *FType = FunctionType::get(Type::getVoidTy(*Ctx), false);58    auto *F = Function::Create(FType, GlobalValue::ExternalLinkage, "Test", *M);59    MMI = std::make_unique<MachineModuleInfo>(TM.get());60 61    ST = std::make_unique<RISCVSubtarget>(62        TM->getTargetTriple(), TM->getTargetCPU(), TM->getTargetCPU(),63        TM->getTargetFeatureString(),64        TM->getTargetTriple().isArch64Bit() ? "lp64" : "ilp32", 0, 0, *TM);65 66    MF = std::make_unique<MachineFunction>(*F, *TM, *ST, MMI->getContext(), 42);67  }68};69 70TEST_P(RISCVInstrInfoTest, IsAddImmediate) {71  const RISCVInstrInfo *TII = ST->getInstrInfo();72  DebugLoc DL;73 74  MachineInstr *MI1 = BuildMI(*MF, DL, TII->get(RISCV::ADDI), RISCV::X1)75                          .addReg(RISCV::X2)76                          .addImm(-128)77                          .getInstr();78  auto MI1Res = TII->isAddImmediate(*MI1, RISCV::X1);79  ASSERT_TRUE(MI1Res.has_value());80  EXPECT_EQ(MI1Res->Reg, RISCV::X2);81  EXPECT_EQ(MI1Res->Imm, -128);82  EXPECT_FALSE(TII->isAddImmediate(*MI1, RISCV::X2).has_value());83 84  MachineInstr *MI2 =85      BuildMI(*MF, DL, TII->get(RISCV::LUI), RISCV::X1).addImm(-128).getInstr();86  EXPECT_FALSE(TII->isAddImmediate(*MI2, RISCV::X1));87 88  // Check ADDIW isn't treated as isAddImmediate.89  if (ST->is64Bit()) {90    MachineInstr *MI3 = BuildMI(*MF, DL, TII->get(RISCV::ADDIW), RISCV::X1)91                            .addReg(RISCV::X2)92                            .addImm(-128)93                            .getInstr();94    EXPECT_FALSE(TII->isAddImmediate(*MI3, RISCV::X1));95  }96}97 98TEST_P(RISCVInstrInfoTest, IsCopyInstrImpl) {99  const RISCVInstrInfo *TII = ST->getInstrInfo();100  DebugLoc DL;101 102  // ADDI.103 104  MachineInstr *MI1 = BuildMI(*MF, DL, TII->get(RISCV::ADDI), RISCV::X1)105                          .addReg(RISCV::X2)106                          .addImm(-128)107                          .getInstr();108  auto MI1Res = TII->isCopyInstrImpl(*MI1);109  EXPECT_FALSE(MI1Res.has_value());110 111  MachineInstr *MI2 = BuildMI(*MF, DL, TII->get(RISCV::ADDI), RISCV::X1)112                          .addReg(RISCV::X2)113                          .addImm(0)114                          .getInstr();115  auto MI2Res = TII->isCopyInstrImpl(*MI2);116  ASSERT_TRUE(MI2Res.has_value());117  EXPECT_EQ(MI2Res->Destination->getReg(), RISCV::X1);118  EXPECT_EQ(MI2Res->Source->getReg(), RISCV::X2);119 120  // Partial coverage of FSGNJ_* instructions.121 122  MachineInstr *MI3 = BuildMI(*MF, DL, TII->get(RISCV::FSGNJ_D), RISCV::F1_D)123                          .addReg(RISCV::F2_D)124                          .addReg(RISCV::F1_D)125                          .getInstr();126  auto MI3Res = TII->isCopyInstrImpl(*MI3);127  EXPECT_FALSE(MI3Res.has_value());128 129  MachineInstr *MI4 = BuildMI(*MF, DL, TII->get(RISCV::FSGNJ_D), RISCV::F1_D)130                          .addReg(RISCV::F2_D)131                          .addReg(RISCV::F2_D)132                          .getInstr();133  auto MI4Res = TII->isCopyInstrImpl(*MI4);134  ASSERT_TRUE(MI4Res.has_value());135  EXPECT_EQ(MI4Res->Destination->getReg(), RISCV::F1_D);136  EXPECT_EQ(MI4Res->Source->getReg(), RISCV::F2_D);137 138  // ADD/OR/XOR.139  for (unsigned Opc : {RISCV::ADD, RISCV::OR, RISCV::XOR}) {140    MachineInstr *MI5 = BuildMI(*MF, DL, TII->get(Opc), RISCV::X1)141                            .addReg(RISCV::X2)142                            .addReg(RISCV::X3)143                            .getInstr();144    auto MI5Res = TII->isCopyInstrImpl(*MI5);145    EXPECT_FALSE(MI5Res.has_value());146 147    MachineInstr *MI6 = BuildMI(*MF, DL, TII->get(Opc), RISCV::X1)148                            .addReg(RISCV::X0)149                            .addReg(RISCV::X2)150                            .getInstr();151    auto MI6Res = TII->isCopyInstrImpl(*MI6);152    ASSERT_TRUE(MI6Res.has_value());153    EXPECT_EQ(MI6Res->Destination->getReg(), RISCV::X1);154    EXPECT_EQ(MI6Res->Source->getReg(), RISCV::X2);155 156    MachineInstr *MI7 = BuildMI(*MF, DL, TII->get(Opc), RISCV::X1)157                            .addReg(RISCV::X2)158                            .addReg(RISCV::X0)159                            .getInstr();160    auto MI7Res = TII->isCopyInstrImpl(*MI7);161    ASSERT_TRUE(MI7Res.has_value());162    EXPECT_EQ(MI7Res->Destination->getReg(), RISCV::X1);163    EXPECT_EQ(MI7Res->Source->getReg(), RISCV::X2);164  }165 166  // SUB.167  MachineInstr *MI8 = BuildMI(*MF, DL, TII->get(RISCV::SUB), RISCV::X1)168                          .addReg(RISCV::X0)169                          .addReg(RISCV::X2)170                          .getInstr();171  auto MI8Res = TII->isCopyInstrImpl(*MI8);172  EXPECT_FALSE(MI8Res.has_value());173 174  MachineInstr *MI9 = BuildMI(*MF, DL, TII->get(RISCV::SUB), RISCV::X1)175                          .addReg(RISCV::X2)176                          .addReg(RISCV::X0)177                          .getInstr();178  auto MI9Res = TII->isCopyInstrImpl(*MI9);179  ASSERT_TRUE(MI9Res.has_value());180  EXPECT_EQ(MI9Res->Destination->getReg(), RISCV::X1);181  EXPECT_EQ(MI9Res->Source->getReg(), RISCV::X2);182 183  // SH1ADD(_UW), SH2ADD(_UW), SH3ADD(_UW).184  for (unsigned Opc : {RISCV::SH1ADD, RISCV::SH1ADD_UW, RISCV::SH2ADD,185                       RISCV::SH2ADD_UW, RISCV::SH3ADD, RISCV::SH3ADD_UW}) {186    MachineInstr *MI10 = BuildMI(*MF, DL, TII->get(Opc), RISCV::X1)187                             .addReg(RISCV::X2)188                             .addReg(RISCV::X3)189                             .getInstr();190    auto MI10Res = TII->isCopyInstrImpl(*MI10);191    EXPECT_FALSE(MI10Res.has_value());192 193    MachineInstr *MI11 = BuildMI(*MF, DL, TII->get(Opc), RISCV::X1)194                             .addReg(RISCV::X0)195                             .addReg(RISCV::X2)196                             .getInstr();197    auto MI11Res = TII->isCopyInstrImpl(*MI11);198    ASSERT_TRUE(MI11Res.has_value());199    EXPECT_EQ(MI11Res->Destination->getReg(), RISCV::X1);200    EXPECT_EQ(MI11Res->Source->getReg(), RISCV::X2);201  }202}203 204TEST_P(RISCVInstrInfoTest, GetMemOperandsWithOffsetWidth) {205  const RISCVInstrInfo *TII = ST->getInstrInfo();206  const TargetRegisterInfo *TRI = ST->getRegisterInfo();207  DebugLoc DL;208 209  SmallVector<const MachineOperand *> BaseOps;210  LocationSize Width = LocationSize::precise(0);211  int64_t Offset;212  bool OffsetIsScalable;213 214  auto MMO = MF->getMachineMemOperand(MachinePointerInfo(),215                                      MachineMemOperand::MOLoad, 1, Align(1));216  MachineInstr *MI = BuildMI(*MF, DL, TII->get(RISCV::LB), RISCV::X1)217                         .addReg(RISCV::X2)218                         .addImm(-128)219                         .addMemOperand(MMO)220                         .getInstr();221  bool Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset,222                                                OffsetIsScalable, Width, TRI);223  ASSERT_TRUE(Res);224  ASSERT_EQ(BaseOps.size(), 1u);225  ASSERT_TRUE(BaseOps.front()->isReg());226  EXPECT_EQ(BaseOps.front()->getReg(), RISCV::X2);227  EXPECT_EQ(Offset, -128);228  EXPECT_FALSE(OffsetIsScalable);229  EXPECT_EQ(Width, 1u);230 231  BaseOps.clear();232  MMO = MF->getMachineMemOperand(MachinePointerInfo(),233                                 MachineMemOperand::MOStore, 4, Align(4));234  MI = BuildMI(*MF, DL, TII->get(RISCV::FSW))235           .addReg(RISCV::F3_F)236           .addReg(RISCV::X3)237           .addImm(36)238           .addMemOperand(MMO);239  Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset,240                                           OffsetIsScalable, Width, TRI);241  ASSERT_TRUE(Res);242  ASSERT_EQ(BaseOps.size(), 1u);243  ASSERT_TRUE(BaseOps.front()->isReg());244  EXPECT_EQ(BaseOps.front()->getReg(), RISCV::X3);245  EXPECT_EQ(Offset, 36);246  EXPECT_FALSE(OffsetIsScalable);247  EXPECT_EQ(Width, 4u);248 249  BaseOps.clear();250  MMO = MF->getMachineMemOperand(MachinePointerInfo(),251                                 MachineMemOperand::MOStore, 16, Align(16));252  MI = BuildMI(*MF, DL, TII->get(RISCV::PseudoVLE32_V_M1), RISCV::V8)253           .addReg(RISCV::X3)254           .addMemOperand(MMO);255  Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset,256                                           OffsetIsScalable, Width, TRI);257  ASSERT_FALSE(Res); // Vector loads/stored are not handled for now.258 259  BaseOps.clear();260  MI = BuildMI(*MF, DL, TII->get(RISCV::ADDI), RISCV::X4)261           .addReg(RISCV::X5)262           .addImm(16);263  Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset,264                                           OffsetIsScalable, Width, TRI);265 266  BaseOps.clear();267  MMO = MF->getMachineMemOperand(MachinePointerInfo(),268                                 MachineMemOperand::MOStore, 4, Align(4));269  MI = BuildMI(*MF, DL, TII->get(RISCV::SW))270           .addReg(RISCV::X3)271           .addFrameIndex(2)272           .addImm(4)273           .addMemOperand(MMO);274  Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset,275                                           OffsetIsScalable, Width, TRI);276  ASSERT_TRUE(Res);277  ASSERT_EQ(BaseOps.size(), 1u);278  ASSERT_TRUE(BaseOps.front()->isFI());279  EXPECT_EQ(BaseOps.front()->getIndex(), 2);280  EXPECT_EQ(Offset, 4);281  EXPECT_FALSE(OffsetIsScalable);282  EXPECT_EQ(Width, 4u);283}284 285static void expectDIEPrintResult(const DIExpression *Expr, StringRef Expected) {286  std::string Output;287  raw_string_ostream OS(Output);288  Expr->print(OS);289  EXPECT_EQ(Output, Expected);290}291 292TEST_P(RISCVInstrInfoTest, DescribeLoadedValue) {293  const RISCVInstrInfo *TII = ST->getInstrInfo();294  DebugLoc DL;295 296  MachineBasicBlock *MBB = MF->CreateMachineBasicBlock();297  MF->getProperties().setNoVRegs();298 299  // Register move.300  auto *MI1 = BuildMI(*MBB, MBB->begin(), DL, TII->get(RISCV::ADDI), RISCV::X1)301                  .addReg(RISCV::X2)302                  .addImm(0)303                  .getInstr();304  EXPECT_FALSE(TII->describeLoadedValue(*MI1, RISCV::X2).has_value());305  std::optional<ParamLoadedValue> MI1Res =306      TII->describeLoadedValue(*MI1, RISCV::X1);307  ASSERT_TRUE(MI1Res.has_value());308  ASSERT_TRUE(MI1Res->first.isReg());309  EXPECT_EQ(MI1Res->first.getReg(), RISCV::X2);310  expectDIEPrintResult(MI1Res->second, "!DIExpression()");311 312  // Load immediate.313  auto *MI2 = BuildMI(*MBB, MBB->begin(), DL, TII->get(RISCV::ADDI), RISCV::X3)314                  .addReg(RISCV::X0)315                  .addImm(111)316                  .getInstr();317  std::optional<ParamLoadedValue> MI2Res =318      TII->describeLoadedValue(*MI2, RISCV::X3);319  ASSERT_TRUE(MI2Res.has_value());320  ASSERT_TRUE(MI2Res->first.isReg());321  EXPECT_EQ(MI2Res->first.getReg(), RISCV::X0);322  // TODO: Could be a DW_OP_constu if this is recognised as a immediate load323  // rather than just an addi.324  expectDIEPrintResult(MI2Res->second, "!DIExpression(DW_OP_plus_uconst, 111)");325 326  // Add immediate.327  auto *MI3 = BuildMI(*MBB, MBB->begin(), DL, TII->get(RISCV::ADDI), RISCV::X2)328                  .addReg(RISCV::X3)329                  .addImm(222)330                  .getInstr();331  std::optional<ParamLoadedValue> MI3Res =332      TII->describeLoadedValue(*MI3, RISCV::X2);333  ASSERT_TRUE(MI3Res.has_value());334  ASSERT_TRUE(MI3Res->first.isReg());335  EXPECT_EQ(MI3Res->first.getReg(), RISCV::X3);336  expectDIEPrintResult(MI3Res->second, "!DIExpression(DW_OP_plus_uconst, 222)");337 338  // Load value from memory.339  // It would be better (more reflective of real-world describeLoadedValue340  // usage) to test using MachinePointerInfo::getFixedStack, but341  // unfortunately it would be overly fiddly to make this work.342  auto MMO = MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF),343                                      MachineMemOperand::MOLoad, 1, Align(1));344  auto *MI4 = BuildMI(*MBB, MBB->begin(), DL, TII->get(RISCV::LB), RISCV::X1)345                  .addReg(RISCV::X2)346                  .addImm(-128)347                  .addMemOperand(MMO)348                  .getInstr();349  std::optional<ParamLoadedValue> MI4Res =350      TII->describeLoadedValue(*MI4, RISCV::X1);351  ASSERT_TRUE(MI4Res.has_value());352  ASSERT_TRUE(MI4Res->first.isReg());353  EXPECT_EQ(MI4Res->first.getReg(), RISCV::X2);354  expectDIEPrintResult(355      MI4Res->second,356      "!DIExpression(DW_OP_constu, 128, DW_OP_minus, DW_OP_deref_size, 1)");357 358  MF->deleteMachineBasicBlock(MBB);359}360 361TEST_P(RISCVInstrInfoTest, GetDestEEW) {362  const RISCVInstrInfo *TII = ST->getInstrInfo();363  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VADD_VV), 3), 3u);364  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VWADD_VV), 3), 4u);365  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VLE32_V), 5), 5u);366  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VLSE32_V), 5), 5u);367  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VREDSUM_VS), 4), 4u);368  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VWREDSUM_VS), 4), 5u);369  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VFWREDOSUM_VS), 5), 6u);370  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VFCVT_RTZ_XU_F_V), 4), 4u);371  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VFWCVT_RTZ_XU_F_V), 4), 5u);372  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VSLL_VI), 4), 4u);373  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VWSLL_VI), 4), 5u);374  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VMSEQ_VV), 4), 0u);375  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VMAND_MM), 0), 0u);376  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VIOTA_M), 3), 3u);377  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::SF_VQMACCU_2x8x2), 3), 5u);378  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::SF_VFWMACC_4x4x4), 4), 5u);379  EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::TH_VMAQA_VV), 5), 5u);380}381 382} // namespace383 384INSTANTIATE_TEST_SUITE_P(RV32And64, RISCVInstrInfoTest,385                         testing::Values("riscv32", "riscv64"));386