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