[MLIR] Prevent invalid IR from being passed outside of RemoveDeadValues (#121079)
[llvm-project.git] / llvm / unittests / Target / RISCV / RISCVInstrInfoTest.cpp
blob820918f811a34927cc1e51e2cc9cf5c906225921
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 //===----------------------------------------------------------------------===//
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"
21 #include "gtest/gtest.h"
23 #include <memory>
25 using namespace llvm;
27 namespace {
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;
38 static void SetUpTestSuite() {
39 LLVMInitializeRISCVTargetInfo();
40 LLVMInitializeRISCVTarget();
41 LLVMInitializeRISCVTargetMC();
44 RISCVInstrInfoTest() {
45 std::string Error;
46 auto TT(Triple::normalize(GetParam()));
47 const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
48 TargetOptions Options;
50 TM.reset(static_cast<RISCVTargetMachine *>(TheTarget->createTargetMachine(
51 TT, "generic", "", Options, std::nullopt, std::nullopt,
52 CodeGenOptLevel::Default)));
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());
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);
66 MF = std::make_unique<MachineFunction>(*F, *TM, *ST, MMI->getContext(), 42);
70 TEST_P(RISCVInstrInfoTest, IsAddImmediate) {
71 const RISCVInstrInfo *TII = ST->getInstrInfo();
72 DebugLoc DL;
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());
84 MachineInstr *MI2 =
85 BuildMI(*MF, DL, TII->get(RISCV::LUI), RISCV::X1).addImm(-128).getInstr();
86 EXPECT_FALSE(TII->isAddImmediate(*MI2, RISCV::X1));
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));
98 TEST_P(RISCVInstrInfoTest, IsCopyInstrImpl) {
99 const RISCVInstrInfo *TII = ST->getInstrInfo();
100 DebugLoc DL;
102 // ADDI.
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());
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);
120 // Partial coverage of FSGNJ_* instructions.
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());
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);
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());
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());
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());
161 TEST_P(RISCVInstrInfoTest, GetMemOperandsWithOffsetWidth) {
162 const RISCVInstrInfo *TII = ST->getInstrInfo();
163 const TargetRegisterInfo *TRI = ST->getRegisterInfo();
164 DebugLoc DL;
166 SmallVector<const MachineOperand *> BaseOps;
167 LocationSize Width = 0;
168 int64_t Offset;
169 bool OffsetIsScalable;
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);
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);
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.
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);
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);
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);
249 TEST_P(RISCVInstrInfoTest, DescribeLoadedValue) {
250 const RISCVInstrInfo *TII = ST->getInstrInfo();
251 DebugLoc DL;
253 MachineBasicBlock *MBB = MF->CreateMachineBasicBlock();
254 MF->getProperties().set(MachineFunctionProperties::Property::NoVRegs);
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()");
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)");
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)");
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)");
315 MF->deleteMachineBasicBlock(MBB);
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);
339 } // namespace
341 INSTANTIATE_TEST_SUITE_P(RV32And64, RISCVInstrInfoTest,
342 testing::Values("riscv32", "riscv64"));