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/TargetSelect.h"
7 
8 #include "gtest/gtest.h"
9 
10 using namespace llvm;
11 
12 namespace {
13 std::unique_ptr<LLVMTargetMachine> createTargetMachine() {
14   auto TT(Triple::normalize("aarch64--"));
15   std::string CPU("generic");
16   std::string FS("");
17 
18   LLVMInitializeAArch64TargetInfo();
19   LLVMInitializeAArch64Target();
20   LLVMInitializeAArch64TargetMC();
21 
22   std::string Error;
23   const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
24 
25   return std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine*>(
26       TheTarget->createTargetMachine(TT, CPU, FS, TargetOptions(), None, None,
27                                      CodeGenOpt::Default)));
28 }
29 
30 std::unique_ptr<AArch64InstrInfo> createInstrInfo(TargetMachine *TM) {
31   AArch64Subtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),
32                       std::string(TM->getTargetCPU()),
33                       std::string(TM->getTargetFeatureString()), *TM,
34                       /* isLittle */ false);
35   return std::make_unique<AArch64InstrInfo>(ST);
36 }
37 
38 /// The \p InputIRSnippet is only needed for things that can't be expressed in
39 /// the \p InputMIRSnippet (global variables etc)
40 /// TODO: Some of this might be useful for other architectures as well - extract
41 ///       the platform-independent parts somewhere they can be reused.
42 void runChecks(
43     LLVMTargetMachine *TM, AArch64InstrInfo *II, const StringRef InputIRSnippet,
44     const StringRef InputMIRSnippet,
45     std::function<void(AArch64InstrInfo &, MachineFunction &)> Checks) {
46   LLVMContext Context;
47 
48   auto MIRString =
49     "--- |\n"
50     "  declare void @sizes()\n"
51     + InputIRSnippet.str() +
52     "...\n"
53     "---\n"
54     "name: sizes\n"
55     "body: |\n"
56     "  bb.0:\n"
57     + InputMIRSnippet.str();
58 
59   std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRString);
60   std::unique_ptr<MIRParser> MParser =
61       createMIRParser(std::move(MBuffer), Context);
62   ASSERT_TRUE(MParser);
63 
64   std::unique_ptr<Module> M = MParser->parseIRModule();
65   ASSERT_TRUE(M);
66 
67   M->setTargetTriple(TM->getTargetTriple().getTriple());
68   M->setDataLayout(TM->createDataLayout());
69 
70   MachineModuleInfo MMI(TM);
71   bool Res = MParser->parseMachineFunctions(*M, MMI);
72   ASSERT_FALSE(Res);
73 
74   auto F = M->getFunction("sizes");
75   ASSERT_TRUE(F != nullptr);
76   auto &MF = MMI.getOrCreateMachineFunction(*F);
77 
78   Checks(*II, MF);
79 }
80 
81 } // anonymous namespace
82 
83 TEST(InstSizes, Authenticated) {
84   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
85   ASSERT_TRUE(TM);
86   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
87 
88   auto isAuthInst = [](AArch64InstrInfo &II, MachineFunction &MF) {
89     auto I = MF.begin()->begin();
90     EXPECT_EQ(4u, II.getInstSizeInBytes(*I));
91     EXPECT_TRUE(I->getDesc().isAuthenticated());
92   };
93 
94   runChecks(TM.get(), II.get(), "",
95             "    \n"
96             "    BLRAA $x10, $x9\n",
97             isAuthInst);
98 
99   runChecks(TM.get(), II.get(), "",
100             "    \n"
101             "    RETAB implicit $lr, implicit $sp, implicit killed $x0\n",
102             isAuthInst);
103 
104   runChecks(TM.get(), II.get(), "",
105             "    \n"
106             "    frame-destroy AUTIASP implicit-def $lr, implicit killed $lr, implicit $sp\n",
107             isAuthInst);
108 
109   runChecks(TM.get(), II.get(), "",
110             "    \n"
111             "    frame-destroy AUTIBSP implicit-def $lr, implicit killed $lr, implicit $sp\n",
112             isAuthInst);
113 }
114 
115 TEST(InstSizes, STACKMAP) {
116   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
117   ASSERT_TRUE(TM);
118   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
119 
120   runChecks(TM.get(), II.get(), "", "    STACKMAP 0, 16\n"
121                                     "    STACKMAP 1, 32\n",
122             [](AArch64InstrInfo &II, MachineFunction &MF) {
123               auto I = MF.begin()->begin();
124               EXPECT_EQ(16u, II.getInstSizeInBytes(*I));
125               ++I;
126               EXPECT_EQ(32u, II.getInstSizeInBytes(*I));
127             });
128 }
129 
130 TEST(InstSizes, PATCHPOINT) {
131   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
132   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
133 
134   runChecks(TM.get(), II.get(), "",
135             "    PATCHPOINT 0, 16, 0, 0, 0, csr_aarch64_aapcs\n"
136             "    PATCHPOINT 1, 32, 0, 0, 0, csr_aarch64_aapcs\n",
137             [](AArch64InstrInfo &II, MachineFunction &MF) {
138               auto I = MF.begin()->begin();
139               EXPECT_EQ(16u, II.getInstSizeInBytes(*I));
140               ++I;
141               EXPECT_EQ(32u, II.getInstSizeInBytes(*I));
142             });
143 }
144 
145 TEST(InstSizes, TLSDESC_CALLSEQ) {
146   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
147   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
148 
149   runChecks(
150       TM.get(), II.get(),
151       "  @ThreadLocalGlobal = external thread_local global i32, align 8\n",
152       "    TLSDESC_CALLSEQ target-flags(aarch64-tls) @ThreadLocalGlobal\n",
153       [](AArch64InstrInfo &II, MachineFunction &MF) {
154         auto I = MF.begin()->begin();
155         EXPECT_EQ(16u, II.getInstSizeInBytes(*I));
156       });
157 }
158