xref: /llvm-project/llvm/unittests/Target/LoongArch/InstSizes.cpp (revision bb3f5e1fed7c6ba733b7f273e93f5d3930976185)
1 #include "LoongArchSubtarget.h"
2 #include "LoongArchTargetMachine.h"
3 #include "llvm/CodeGen/MIRParser/MIRParser.h"
4 #include "llvm/CodeGen/MachineModuleInfo.h"
5 #include "llvm/IR/Module.h"
6 #include "llvm/MC/TargetRegistry.h"
7 #include "llvm/Support/MemoryBuffer.h"
8 #include "llvm/Support/TargetSelect.h"
9 #include <optional>
10 
11 #include "gtest/gtest.h"
12 
13 using namespace llvm;
14 
15 namespace {
16 std::unique_ptr<TargetMachine> createTargetMachine() {
17   auto TT(Triple::normalize("loongarch64--"));
18   std::string CPU("generic-la64");
19   std::string FS("+64bit");
20 
21   LLVMInitializeLoongArchTargetInfo();
22   LLVMInitializeLoongArchTarget();
23   LLVMInitializeLoongArchTargetMC();
24 
25   std::string Error;
26   const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
27 
28   return std::unique_ptr<TargetMachine>(
29       TheTarget->createTargetMachine(TT, CPU, FS, TargetOptions(), std::nullopt,
30                                      std::nullopt, CodeGenOptLevel::Default));
31 }
32 
33 std::unique_ptr<LoongArchInstrInfo> createInstrInfo(TargetMachine *TM) {
34   LoongArchSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),
35                         std::string(TM->getTargetCPU()),
36                         std::string(TM->getTargetFeatureString()), "lp64d",
37                         *TM);
38   return std::make_unique<LoongArchInstrInfo>(ST);
39 }
40 
41 /// The \p InputIRSnippet is only needed for things that can't be expressed in
42 /// the \p InputMIRSnippet (global variables etc)
43 /// Inspired by AArch64
44 void runChecks(
45     TargetMachine *TM, LoongArchInstrInfo *II, const StringRef InputIRSnippet,
46     const StringRef InputMIRSnippet,
47     std::function<void(LoongArchInstrInfo &, MachineFunction &)> Checks) {
48   LLVMContext Context;
49 
50   auto MIRString = "--- |\n"
51                    "  declare void @sizes()\n" +
52                    InputIRSnippet.str() +
53                    "...\n"
54                    "---\n"
55                    "name: sizes\n"
56                    "jumpTable:\n"
57                    "  kind:            block-address\n"
58                    "  entries:\n"
59                    "    - id:              0\n"
60                    "      blocks:          [ '%bb.0' ]\n"
61                    "body: |\n"
62                    "  bb.0:\n" +
63                    InputMIRSnippet.str();
64 
65   std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRString);
66   std::unique_ptr<MIRParser> MParser =
67       createMIRParser(std::move(MBuffer), Context);
68   ASSERT_TRUE(MParser);
69 
70   std::unique_ptr<Module> M = MParser->parseIRModule();
71   ASSERT_TRUE(M);
72 
73   M->setTargetTriple(TM->getTargetTriple().getTriple());
74   M->setDataLayout(TM->createDataLayout());
75 
76   MachineModuleInfo MMI(TM);
77   bool Res = MParser->parseMachineFunctions(*M, MMI);
78   ASSERT_FALSE(Res);
79 
80   auto F = M->getFunction("sizes");
81   ASSERT_TRUE(F != nullptr);
82   auto &MF = MMI.getOrCreateMachineFunction(*F);
83 
84   Checks(*II, MF);
85 }
86 
87 } // anonymous namespace
88 
89 TEST(InstSizes, INLINEASM_BR) {
90   std::unique_ptr<TargetMachine> TM = createTargetMachine();
91   std::unique_ptr<LoongArchInstrInfo> II = createInstrInfo(TM.get());
92 
93   runChecks(TM.get(), II.get(), "",
94             // clang-format off
95             "  INLINEASM_BR &nop, 1 /* sideeffect attdialect */, 13 /* imm */, %jump-table.0\n",
96             // clang-format on
97             [](LoongArchInstrInfo &II, MachineFunction &MF) {
98               auto I = MF.begin()->begin();
99               EXPECT_EQ(4u, II.getInstSizeInBytes(*I));
100             });
101 }
102 
103 TEST(InstSizes, SPACE) {
104   std::unique_ptr<TargetMachine> TM = createTargetMachine();
105   std::unique_ptr<LoongArchInstrInfo> II = createInstrInfo(TM.get());
106 
107   runChecks(TM.get(), II.get(), "", "  INLINEASM &\".space 1024\", 1\n",
108             [](LoongArchInstrInfo &II, MachineFunction &MF) {
109               auto I = MF.begin()->begin();
110               EXPECT_EQ(1024u, II.getInstSizeInBytes(*I));
111             });
112 }
113 
114 TEST(InstSizes, AtomicPseudo) {
115   std::unique_ptr<TargetMachine> TM = createTargetMachine();
116   std::unique_ptr<LoongArchInstrInfo> II = createInstrInfo(TM.get());
117 
118   runChecks(
119       TM.get(), II.get(), "",
120       // clang-format off
121       "    dead early-clobber renamable $r10, dead early-clobber renamable $r11 = PseudoMaskedAtomicLoadAdd32 renamable $r7, renamable $r6, renamable $r8, 4\n"
122       "    dead early-clobber renamable $r10, dead early-clobber renamable $r11 = PseudoAtomicLoadAdd32 renamable $r7, renamable $r6, renamable $r8\n"
123       "    dead early-clobber renamable $r5, dead early-clobber renamable $r9, dead early-clobber renamable $r10 = PseudoMaskedAtomicLoadUMax32 renamable $r7, renamable $r6, renamable $r8, 4\n"
124       "    early-clobber renamable $r9, dead early-clobber renamable $r10, dead early-clobber renamable $r11 = PseudoMaskedAtomicLoadMax32 killed renamable $r6, killed renamable $r5, killed renamable $r7, killed renamable $r8, 4\n"
125       "    dead early-clobber renamable $r5, dead early-clobber renamable $r9 = PseudoCmpXchg32 renamable $r7, renamable $r4, renamable $r6, 4\n"
126       "    dead early-clobber renamable $r5, dead early-clobber renamable $r9 = PseudoMaskedCmpXchg32 killed renamable $r7, killed renamable $r4, killed renamable $r6, killed renamable $r8, 4\n",
127       // clang-format on
128       [](LoongArchInstrInfo &II, MachineFunction &MF) {
129         auto I = MF.begin()->begin();
130         EXPECT_EQ(36u, II.getInstSizeInBytes(*I));
131         ++I;
132         EXPECT_EQ(24u, II.getInstSizeInBytes(*I));
133         ++I;
134         EXPECT_EQ(48u, II.getInstSizeInBytes(*I));
135         ++I;
136         EXPECT_EQ(56u, II.getInstSizeInBytes(*I));
137         ++I;
138         EXPECT_EQ(36u, II.getInstSizeInBytes(*I));
139         ++I;
140         EXPECT_EQ(44u, II.getInstSizeInBytes(*I));
141       });
142 }
143 
144 TEST(InstSizes, StatePoint) {
145   std::unique_ptr<TargetMachine> TM = createTargetMachine();
146   std::unique_ptr<LoongArchInstrInfo> II = createInstrInfo(TM.get());
147 
148   runChecks(
149       TM.get(), II.get(), "  declare zeroext i1 @return_i1()\n",
150       // clang-format off
151       "  STATEPOINT 0, 0, 0, target-flags(loongarch-call-plt) @return_i1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, implicit-def $r3, implicit-def $r4\n",
152       // clang-format on
153       [](LoongArchInstrInfo &II, MachineFunction &MF) {
154         auto I = MF.begin()->begin();
155         EXPECT_EQ(4u, II.getInstSizeInBytes(*I));
156       });
157 }
158