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