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-exception 6 // 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 25 using namespace llvm; 26 27 namespace { 28 29 class RISCVInstrInfoTest : public testing::TestWithParam<const char *> { 30 protected: 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 auto TT(Triple::normalize(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 70 TEST_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 98 TEST_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. TODO: Should return true for add reg, x0 and add x0, reg. 139 MachineInstr *MI5 = BuildMI(*MF, DL, TII->get(RISCV::ADD), RISCV::X1) 140 .addReg(RISCV::X2) 141 .addReg(RISCV::X3) 142 .getInstr(); 143 auto MI5Res = TII->isCopyInstrImpl(*MI5); 144 EXPECT_FALSE(MI5Res.has_value()); 145 146 MachineInstr *MI6 = BuildMI(*MF, DL, TII->get(RISCV::ADD), RISCV::X1) 147 .addReg(RISCV::X0) 148 .addReg(RISCV::X2) 149 .getInstr(); 150 auto MI6Res = TII->isCopyInstrImpl(*MI6); 151 EXPECT_FALSE(MI6Res.has_value()); 152 153 MachineInstr *MI7 = BuildMI(*MF, DL, TII->get(RISCV::ADD), RISCV::X1) 154 .addReg(RISCV::X2) 155 .addReg(RISCV::X0) 156 .getInstr(); 157 auto MI7Res = TII->isCopyInstrImpl(*MI7); 158 EXPECT_FALSE(MI7Res.has_value()); 159 } 160 161 TEST_P(RISCVInstrInfoTest, GetMemOperandsWithOffsetWidth) { 162 const RISCVInstrInfo *TII = ST->getInstrInfo(); 163 const TargetRegisterInfo *TRI = ST->getRegisterInfo(); 164 DebugLoc DL; 165 166 SmallVector<const MachineOperand *> BaseOps; 167 LocationSize Width = 0; 168 int64_t Offset; 169 bool OffsetIsScalable; 170 171 auto MMO = MF->getMachineMemOperand(MachinePointerInfo(), 172 MachineMemOperand::MOLoad, 1, Align(1)); 173 MachineInstr *MI = BuildMI(*MF, DL, TII->get(RISCV::LB), RISCV::X1) 174 .addReg(RISCV::X2) 175 .addImm(-128) 176 .addMemOperand(MMO) 177 .getInstr(); 178 bool Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset, 179 OffsetIsScalable, Width, TRI); 180 ASSERT_TRUE(Res); 181 ASSERT_EQ(BaseOps.size(), 1u); 182 ASSERT_TRUE(BaseOps.front()->isReg()); 183 EXPECT_EQ(BaseOps.front()->getReg(), RISCV::X2); 184 EXPECT_EQ(Offset, -128); 185 EXPECT_FALSE(OffsetIsScalable); 186 EXPECT_EQ(Width, 1u); 187 188 BaseOps.clear(); 189 MMO = MF->getMachineMemOperand(MachinePointerInfo(), 190 MachineMemOperand::MOStore, 4, Align(4)); 191 MI = BuildMI(*MF, DL, TII->get(RISCV::FSW)) 192 .addReg(RISCV::F3_F) 193 .addReg(RISCV::X3) 194 .addImm(36) 195 .addMemOperand(MMO); 196 Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset, 197 OffsetIsScalable, Width, TRI); 198 ASSERT_TRUE(Res); 199 ASSERT_EQ(BaseOps.size(), 1u); 200 ASSERT_TRUE(BaseOps.front()->isReg()); 201 EXPECT_EQ(BaseOps.front()->getReg(), RISCV::X3); 202 EXPECT_EQ(Offset, 36); 203 EXPECT_FALSE(OffsetIsScalable); 204 EXPECT_EQ(Width, 4u); 205 206 BaseOps.clear(); 207 MMO = MF->getMachineMemOperand(MachinePointerInfo(), 208 MachineMemOperand::MOStore, 16, Align(16)); 209 MI = BuildMI(*MF, DL, TII->get(RISCV::PseudoVLE32_V_M1), RISCV::V8) 210 .addReg(RISCV::X3) 211 .addMemOperand(MMO); 212 Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset, 213 OffsetIsScalable, Width, TRI); 214 ASSERT_FALSE(Res); // Vector loads/stored are not handled for now. 215 216 BaseOps.clear(); 217 MI = BuildMI(*MF, DL, TII->get(RISCV::ADDI), RISCV::X4) 218 .addReg(RISCV::X5) 219 .addImm(16); 220 Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset, 221 OffsetIsScalable, Width, TRI); 222 223 BaseOps.clear(); 224 MMO = MF->getMachineMemOperand(MachinePointerInfo(), 225 MachineMemOperand::MOStore, 4, Align(4)); 226 MI = BuildMI(*MF, DL, TII->get(RISCV::SW)) 227 .addReg(RISCV::X3) 228 .addFrameIndex(2) 229 .addImm(4) 230 .addMemOperand(MMO); 231 Res = TII->getMemOperandsWithOffsetWidth(*MI, BaseOps, Offset, 232 OffsetIsScalable, Width, TRI); 233 ASSERT_TRUE(Res); 234 ASSERT_EQ(BaseOps.size(), 1u); 235 ASSERT_TRUE(BaseOps.front()->isFI()); 236 EXPECT_EQ(BaseOps.front()->getIndex(), 2); 237 EXPECT_EQ(Offset, 4); 238 EXPECT_FALSE(OffsetIsScalable); 239 EXPECT_EQ(Width, 4u); 240 } 241 242 static void expectDIEPrintResult(const DIExpression *Expr, StringRef Expected) { 243 std::string Output; 244 raw_string_ostream OS(Output); 245 Expr->print(OS); 246 EXPECT_EQ(Output, Expected); 247 } 248 249 TEST_P(RISCVInstrInfoTest, DescribeLoadedValue) { 250 const RISCVInstrInfo *TII = ST->getInstrInfo(); 251 DebugLoc DL; 252 253 MachineBasicBlock *MBB = MF->CreateMachineBasicBlock(); 254 MF->getProperties().set(MachineFunctionProperties::Property::NoVRegs); 255 256 // Register move. 257 auto *MI1 = BuildMI(*MBB, MBB->begin(), DL, TII->get(RISCV::ADDI), RISCV::X1) 258 .addReg(RISCV::X2) 259 .addImm(0) 260 .getInstr(); 261 EXPECT_FALSE(TII->describeLoadedValue(*MI1, RISCV::X2).has_value()); 262 std::optional<ParamLoadedValue> MI1Res = 263 TII->describeLoadedValue(*MI1, RISCV::X1); 264 ASSERT_TRUE(MI1Res.has_value()); 265 ASSERT_TRUE(MI1Res->first.isReg()); 266 EXPECT_EQ(MI1Res->first.getReg(), RISCV::X2); 267 expectDIEPrintResult(MI1Res->second, "!DIExpression()"); 268 269 // Load immediate. 270 auto *MI2 = BuildMI(*MBB, MBB->begin(), DL, TII->get(RISCV::ADDI), RISCV::X3) 271 .addReg(RISCV::X0) 272 .addImm(111) 273 .getInstr(); 274 std::optional<ParamLoadedValue> MI2Res = 275 TII->describeLoadedValue(*MI2, RISCV::X3); 276 ASSERT_TRUE(MI2Res.has_value()); 277 ASSERT_TRUE(MI2Res->first.isReg()); 278 EXPECT_EQ(MI2Res->first.getReg(), RISCV::X0); 279 // TODO: Could be a DW_OP_constu if this is recognised as a immediate load 280 // rather than just an addi. 281 expectDIEPrintResult(MI2Res->second, "!DIExpression(DW_OP_plus_uconst, 111)"); 282 283 // Add immediate. 284 auto *MI3 = BuildMI(*MBB, MBB->begin(), DL, TII->get(RISCV::ADDI), RISCV::X2) 285 .addReg(RISCV::X3) 286 .addImm(222) 287 .getInstr(); 288 std::optional<ParamLoadedValue> MI3Res = 289 TII->describeLoadedValue(*MI3, RISCV::X2); 290 ASSERT_TRUE(MI3Res.has_value()); 291 ASSERT_TRUE(MI3Res->first.isReg()); 292 EXPECT_EQ(MI3Res->first.getReg(), RISCV::X3); 293 expectDIEPrintResult(MI3Res->second, "!DIExpression(DW_OP_plus_uconst, 222)"); 294 295 // Load value from memory. 296 // It would be better (more reflective of real-world describeLoadedValue 297 // usage) to test using MachinePointerInfo::getFixedStack, but 298 // unfortunately it would be overly fiddly to make this work. 299 auto MMO = MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF), 300 MachineMemOperand::MOLoad, 1, Align(1)); 301 auto *MI4 = BuildMI(*MBB, MBB->begin(), DL, TII->get(RISCV::LB), RISCV::X1) 302 .addReg(RISCV::X2) 303 .addImm(-128) 304 .addMemOperand(MMO) 305 .getInstr(); 306 std::optional<ParamLoadedValue> MI4Res = 307 TII->describeLoadedValue(*MI4, RISCV::X1); 308 ASSERT_TRUE(MI4Res.has_value()); 309 ASSERT_TRUE(MI4Res->first.isReg()); 310 EXPECT_EQ(MI4Res->first.getReg(), RISCV::X2); 311 expectDIEPrintResult( 312 MI4Res->second, 313 "!DIExpression(DW_OP_constu, 128, DW_OP_minus, DW_OP_deref_size, 1)"); 314 315 MF->deleteMachineBasicBlock(MBB); 316 } 317 318 TEST_P(RISCVInstrInfoTest, GetDestEEW) { 319 const RISCVInstrInfo *TII = ST->getInstrInfo(); 320 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VADD_VV), 3), 3u); 321 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VWADD_VV), 3), 4u); 322 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VLE32_V), 5), 5u); 323 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VLSE32_V), 5), 5u); 324 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VREDSUM_VS), 4), 4u); 325 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VWREDSUM_VS), 4), 5u); 326 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VFWREDOSUM_VS), 5), 6u); 327 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VFCVT_RTZ_XU_F_V), 4), 4u); 328 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VFWCVT_RTZ_XU_F_V), 4), 5u); 329 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VSLL_VI), 4), 4u); 330 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VWSLL_VI), 4), 5u); 331 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VMSEQ_VV), 4), 0u); 332 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VMAND_MM), 0), 0u); 333 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VIOTA_M), 3), 3u); 334 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VQMACCU_2x8x2), 3), 5u); 335 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::VFWMACC_4x4x4), 4), 5u); 336 EXPECT_EQ(RISCV::getDestLog2EEW(TII->get(RISCV::THVdotVMAQA_VV), 5), 5u); 337 } 338 339 } // namespace 340 341 INSTANTIATE_TEST_SUITE_P(RV32And64, RISCVInstrInfoTest, 342 testing::Values("riscv32", "riscv64")); 343