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 { 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 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. 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 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 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 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 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 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 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 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 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 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 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 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