1 //===- RISCVInstrInfoTest.cpp - RISCVInstrInfo unit tests -----------------===//
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
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"
29 class RISCVInstrInfoTest
: public testing::TestWithParam
<const char *> {
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() {
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();
74 MachineInstr
*MI1
= BuildMI(*MF
, DL
, TII
->get(RISCV::ADDI
), RISCV::X1
)
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());
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.
90 MachineInstr
*MI3
= BuildMI(*MF
, DL
, TII
->get(RISCV::ADDIW
), RISCV::X1
)
94 EXPECT_FALSE(TII
->isAddImmediate(*MI3
, RISCV::X1
));
98 TEST_P(RISCVInstrInfoTest
, IsCopyInstrImpl
) {
99 const RISCVInstrInfo
*TII
= ST
->getInstrInfo();
104 MachineInstr
*MI1
= BuildMI(*MF
, DL
, TII
->get(RISCV::ADDI
), RISCV::X1
)
108 auto MI1Res
= TII
->isCopyInstrImpl(*MI1
);
109 EXPECT_FALSE(MI1Res
.has_value());
111 MachineInstr
*MI2
= BuildMI(*MF
, DL
, TII
->get(RISCV::ADDI
), RISCV::X1
)
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
)
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
)
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
)
143 auto MI5Res
= TII
->isCopyInstrImpl(*MI5
);
144 EXPECT_FALSE(MI5Res
.has_value());
146 MachineInstr
*MI6
= BuildMI(*MF
, DL
, TII
->get(RISCV::ADD
), RISCV::X1
)
150 auto MI6Res
= TII
->isCopyInstrImpl(*MI6
);
151 EXPECT_FALSE(MI6Res
.has_value());
153 MachineInstr
*MI7
= BuildMI(*MF
, DL
, TII
->get(RISCV::ADD
), RISCV::X1
)
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();
166 SmallVector
<const MachineOperand
*> BaseOps
;
167 LocationSize Width
= 0;
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
)
178 bool Res
= TII
->getMemOperandsWithOffsetWidth(*MI
, BaseOps
, Offset
,
179 OffsetIsScalable
, Width
, TRI
);
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);
189 MMO
= MF
->getMachineMemOperand(MachinePointerInfo(),
190 MachineMemOperand::MOStore
, 4, Align(4));
191 MI
= BuildMI(*MF
, DL
, TII
->get(RISCV::FSW
))
196 Res
= TII
->getMemOperandsWithOffsetWidth(*MI
, BaseOps
, Offset
,
197 OffsetIsScalable
, Width
, TRI
);
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);
207 MMO
= MF
->getMachineMemOperand(MachinePointerInfo(),
208 MachineMemOperand::MOStore
, 16, Align(16));
209 MI
= BuildMI(*MF
, DL
, TII
->get(RISCV::PseudoVLE32_V_M1
), RISCV::V8
)
212 Res
= TII
->getMemOperandsWithOffsetWidth(*MI
, BaseOps
, Offset
,
213 OffsetIsScalable
, Width
, TRI
);
214 ASSERT_FALSE(Res
); // Vector loads/stored are not handled for now.
217 MI
= BuildMI(*MF
, DL
, TII
->get(RISCV::ADDI
), RISCV::X4
)
220 Res
= TII
->getMemOperandsWithOffsetWidth(*MI
, BaseOps
, Offset
,
221 OffsetIsScalable
, Width
, TRI
);
224 MMO
= MF
->getMachineMemOperand(MachinePointerInfo(),
225 MachineMemOperand::MOStore
, 4, Align(4));
226 MI
= BuildMI(*MF
, DL
, TII
->get(RISCV::SW
))
231 Res
= TII
->getMemOperandsWithOffsetWidth(*MI
, BaseOps
, Offset
,
232 OffsetIsScalable
, Width
, TRI
);
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
) {
244 raw_string_ostream
OS(Output
);
246 EXPECT_EQ(Output
, Expected
);
249 TEST_P(RISCVInstrInfoTest
, DescribeLoadedValue
) {
250 const RISCVInstrInfo
*TII
= ST
->getInstrInfo();
253 MachineBasicBlock
*MBB
= MF
->CreateMachineBasicBlock();
254 MF
->getProperties().set(MachineFunctionProperties::Property::NoVRegs
);
257 auto *MI1
= BuildMI(*MBB
, MBB
->begin(), DL
, TII
->get(RISCV::ADDI
), RISCV::X1
)
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()");
270 auto *MI2
= BuildMI(*MBB
, MBB
->begin(), DL
, TII
->get(RISCV::ADDI
), RISCV::X3
)
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)");
284 auto *MI3
= BuildMI(*MBB
, MBB
->begin(), DL
, TII
->get(RISCV::ADDI
), RISCV::X2
)
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
)
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(
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);
341 INSTANTIATE_TEST_SUITE_P(RV32And64
, RISCVInstrInfoTest
,
342 testing::Values("riscv32", "riscv64"));