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