1 #include "AArch64Subtarget.h"
2 #include "AArch64TargetMachine.h"
3 #include "llvm/CodeGen/MIRParser/MIRParser.h"
4 #include "llvm/CodeGen/MachineModuleInfo.h"
5 #include "llvm/MC/TargetRegistry.h"
6 #include "llvm/Support/MemoryBuffer.h"
7 #include "llvm/Support/TargetSelect.h"
8 
9 #include "gtest/gtest.h"
10 
11 using namespace llvm;
12 
13 namespace {
createTargetMachine()14 std::unique_ptr<LLVMTargetMachine> createTargetMachine() {
15   auto TT(Triple::normalize("aarch64--"));
16   std::string CPU("generic");
17   std::string FS("+pauth,+mops,+mte");
18 
19   LLVMInitializeAArch64TargetInfo();
20   LLVMInitializeAArch64Target();
21   LLVMInitializeAArch64TargetMC();
22 
23   std::string Error;
24   const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
25 
26   return std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine*>(
27       TheTarget->createTargetMachine(TT, CPU, FS, TargetOptions(), None, None,
28                                      CodeGenOpt::Default)));
29 }
30 
createInstrInfo(TargetMachine * TM)31 std::unique_ptr<AArch64InstrInfo> createInstrInfo(TargetMachine *TM) {
32   AArch64Subtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),
33                       std::string(TM->getTargetCPU()),
34                       std::string(TM->getTargetFeatureString()), *TM,
35                       /* isLittle */ false);
36   return std::make_unique<AArch64InstrInfo>(ST);
37 }
38 
39 /// The \p InputIRSnippet is only needed for things that can't be expressed in
40 /// the \p InputMIRSnippet (global variables etc)
41 /// TODO: Some of this might be useful for other architectures as well - extract
42 ///       the platform-independent parts somewhere they can be reused.
runChecks(LLVMTargetMachine * TM,AArch64InstrInfo * II,const StringRef InputIRSnippet,const StringRef InputMIRSnippet,std::function<void (AArch64InstrInfo &,MachineFunction &)> Checks)43 void runChecks(
44     LLVMTargetMachine *TM, AArch64InstrInfo *II, const StringRef InputIRSnippet,
45     const StringRef InputMIRSnippet,
46     std::function<void(AArch64InstrInfo &, MachineFunction &)> Checks) {
47   LLVMContext Context;
48 
49   auto MIRString =
50     "--- |\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 
TEST(InstSizes,Authenticated)89 TEST(InstSizes, Authenticated) {
90   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
91   ASSERT_TRUE(TM);
92   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
93 
94   auto isAuthInst = [](AArch64InstrInfo &II, MachineFunction &MF) {
95     auto I = MF.begin()->begin();
96     EXPECT_EQ(4u, II.getInstSizeInBytes(*I));
97     EXPECT_TRUE(I->getDesc().isAuthenticated());
98   };
99 
100   runChecks(TM.get(), II.get(), "",
101             "    \n"
102             "    BLRAA $x10, $x9\n",
103             isAuthInst);
104 
105   runChecks(TM.get(), II.get(), "",
106             "    \n"
107             "    RETAB implicit $lr, implicit $sp, implicit killed $x0\n",
108             isAuthInst);
109 
110   runChecks(TM.get(), II.get(), "",
111             "    \n"
112             "    frame-destroy AUTIASP implicit-def $lr, implicit killed $lr, implicit $sp\n",
113             isAuthInst);
114 
115   runChecks(TM.get(), II.get(), "",
116             "    \n"
117             "    frame-destroy AUTIBSP implicit-def $lr, implicit killed $lr, implicit $sp\n",
118             isAuthInst);
119 }
120 
TEST(InstSizes,STACKMAP)121 TEST(InstSizes, STACKMAP) {
122   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
123   ASSERT_TRUE(TM);
124   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
125 
126   runChecks(TM.get(), II.get(), "", "    STACKMAP 0, 16\n"
127                                     "    STACKMAP 1, 32\n",
128             [](AArch64InstrInfo &II, MachineFunction &MF) {
129               auto I = MF.begin()->begin();
130               EXPECT_EQ(16u, II.getInstSizeInBytes(*I));
131               ++I;
132               EXPECT_EQ(32u, II.getInstSizeInBytes(*I));
133             });
134 }
135 
TEST(InstSizes,PATCHPOINT)136 TEST(InstSizes, PATCHPOINT) {
137   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
138   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
139 
140   runChecks(TM.get(), II.get(), "",
141             "    PATCHPOINT 0, 16, 0, 0, 0, csr_aarch64_aapcs\n"
142             "    PATCHPOINT 1, 32, 0, 0, 0, csr_aarch64_aapcs\n",
143             [](AArch64InstrInfo &II, MachineFunction &MF) {
144               auto I = MF.begin()->begin();
145               EXPECT_EQ(16u, II.getInstSizeInBytes(*I));
146               ++I;
147               EXPECT_EQ(32u, II.getInstSizeInBytes(*I));
148             });
149 }
150 
TEST(InstSizes,STATEPOINT)151 TEST(InstSizes, STATEPOINT) {
152   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
153   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
154 
155   runChecks(TM.get(), II.get(), "",
156             "    STATEPOINT 0, 0, 0, @sizes, 2, 0, 2, 0, 2, 0, 2, 1, 1, 8,"
157             " $sp, 24, 2, 0, 2, 1, 0, 0\n",
158             [](AArch64InstrInfo &II, MachineFunction &MF) {
159               auto I = MF.begin()->begin();
160               EXPECT_EQ(4u, II.getInstSizeInBytes(*I));
161             });
162 }
163 
TEST(InstSizes,SPACE)164 TEST(InstSizes, SPACE) {
165   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
166   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
167 
168   runChecks(TM.get(), II.get(), "",
169             "    $xzr = SPACE 1024, undef $xzr\n"
170             "    dead $xzr = SPACE 4096, $xzr\n",
171             [](AArch64InstrInfo &II, MachineFunction &MF) {
172               auto I = MF.begin()->begin();
173               EXPECT_EQ(1024u, II.getInstSizeInBytes(*I));
174               ++I;
175               EXPECT_EQ(4096u, II.getInstSizeInBytes(*I));
176             });
177 }
178 
TEST(InstSizes,TLSDESC_CALLSEQ)179 TEST(InstSizes, TLSDESC_CALLSEQ) {
180   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
181   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
182 
183   runChecks(
184       TM.get(), II.get(),
185       "  @ThreadLocalGlobal = external thread_local global i32, align 8\n",
186       "    TLSDESC_CALLSEQ target-flags(aarch64-tls) @ThreadLocalGlobal\n",
187       [](AArch64InstrInfo &II, MachineFunction &MF) {
188         auto I = MF.begin()->begin();
189         EXPECT_EQ(16u, II.getInstSizeInBytes(*I));
190       });
191 }
192 
TEST(InstSizes,StoreSwiftAsyncContext)193 TEST(InstSizes, StoreSwiftAsyncContext) {
194   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
195   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
196 
197   runChecks(
198       TM.get(), II.get(), "",
199       "    StoreSwiftAsyncContext $x0, $x1, 12, implicit-def $x16, "
200       "implicit-def $x17\n",
201       [](AArch64InstrInfo &II, MachineFunction &MF) {
202         auto I = MF.begin()->begin();
203         EXPECT_EQ(20u, II.getInstSizeInBytes(*I));
204       });
205 }
206 
TEST(InstSizes,SpeculationBarrierISBDSBEndBB)207 TEST(InstSizes, SpeculationBarrierISBDSBEndBB) {
208   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
209   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
210 
211   runChecks(
212       TM.get(), II.get(), "",
213       "    SpeculationBarrierISBDSBEndBB\n"
214       "    BR $x8\n",
215       [](AArch64InstrInfo &II, MachineFunction &MF) {
216         auto I = MF.begin()->begin();
217         EXPECT_EQ(8u, II.getInstSizeInBytes(*I));
218       });
219 }
220 
TEST(InstSizes,SpeculationBarrierSBEndBB)221 TEST(InstSizes, SpeculationBarrierSBEndBB) {
222   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
223   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
224 
225   runChecks(
226       TM.get(), II.get(), "",
227       "    SpeculationBarrierSBEndBB\n"
228       "    BR $x8\n",
229       [](AArch64InstrInfo &II, MachineFunction &MF) {
230         auto I = MF.begin()->begin();
231         EXPECT_EQ(4u, II.getInstSizeInBytes(*I));
232       });
233 }
234 
TEST(InstSizes,JumpTable)235 TEST(InstSizes, JumpTable) {
236   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
237   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
238 
239   runChecks(TM.get(), II.get(), "",
240             "    $x10, $x11 = JumpTableDest32 $x9, $x8, %jump-table.0\n"
241             "    $x10, $x11 = JumpTableDest16 $x9, $x8, %jump-table.0\n"
242             "    $x10, $x11 = JumpTableDest8 $x9, $x8, %jump-table.0\n",
243             [](AArch64InstrInfo &II, MachineFunction &MF) {
244               auto I = MF.begin()->begin();
245               EXPECT_EQ(12u, II.getInstSizeInBytes(*I));
246               ++I;
247               EXPECT_EQ(12u, II.getInstSizeInBytes(*I));
248               ++I;
249               EXPECT_EQ(12u, II.getInstSizeInBytes(*I));
250             });
251 }
252 
TEST(InstSizes,MOPSMemoryPseudos)253 TEST(InstSizes, MOPSMemoryPseudos) {
254   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
255   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
256 
257   runChecks(TM.get(), II.get(), "",
258             "  $x0, $x1, $x2 = MOPSMemoryMovePseudo $x0, $x1, $x2, "
259             "implicit-def $nzcv\n"
260             "  $x0, $x1 = MOPSMemorySetPseudo $x0, $x1, $x2, "
261             "implicit-def $nzcv\n"
262             "  $x0, $x1, $x8 = MOPSMemoryCopyPseudo $x0, $x1, $x8, "
263             "implicit-def $nzcv\n"
264             "  $x0, $x1 = MOPSMemorySetTaggingPseudo $x0, $x1, $x2, "
265             "implicit-def $nzcv\n",
266             [](AArch64InstrInfo &II, MachineFunction &MF) {
267               auto I = MF.begin()->begin();
268               EXPECT_EQ(12u, II.getInstSizeInBytes(*I));
269               ++I;
270               EXPECT_EQ(12u, II.getInstSizeInBytes(*I));
271               ++I;
272               EXPECT_EQ(12u, II.getInstSizeInBytes(*I));
273               ++I;
274               EXPECT_EQ(12u, II.getInstSizeInBytes(*I));
275             });
276 }
277