blob: e027f256825b6ad8a139be70c3382f846e133d20 [file] [log] [blame]
#include "LoongArchSubtarget.h"
#include "LoongArchTargetMachine.h"
#include "llvm/CodeGen/MIRParser/MIRParser.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetSelect.h"
#include <optional>
#include "gtest/gtest.h"
using namespace llvm;
namespace {
std::unique_ptr<LLVMTargetMachine> createTargetMachine() {
auto TT(Triple::normalize("loongarch64--"));
std::string CPU("generic-la64");
std::string FS("+64bit");
LLVMInitializeLoongArchTargetInfo();
LLVMInitializeLoongArchTarget();
LLVMInitializeLoongArchTargetMC();
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
return std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine *>(
TheTarget->createTargetMachine(TT, CPU, FS, TargetOptions(), std::nullopt,
std::nullopt, CodeGenOptLevel::Default)));
}
std::unique_ptr<LoongArchInstrInfo> createInstrInfo(TargetMachine *TM) {
LoongArchSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),
std::string(TM->getTargetCPU()),
std::string(TM->getTargetFeatureString()), "lp64d",
*TM);
return std::make_unique<LoongArchInstrInfo>(ST);
}
/// The \p InputIRSnippet is only needed for things that can't be expressed in
/// the \p InputMIRSnippet (global variables etc)
/// Inspired by AArch64
void runChecks(
LLVMTargetMachine *TM, LoongArchInstrInfo *II,
const StringRef InputIRSnippet, const StringRef InputMIRSnippet,
std::function<void(LoongArchInstrInfo &, MachineFunction &)> Checks) {
LLVMContext Context;
auto MIRString = "--- |\n"
" declare void @sizes()\n" +
InputIRSnippet.str() +
"...\n"
"---\n"
"name: sizes\n"
"jumpTable:\n"
" kind: block-address\n"
" entries:\n"
" - id: 0\n"
" blocks: [ '%bb.0' ]\n"
"body: |\n"
" bb.0:\n" +
InputMIRSnippet.str();
std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRString);
std::unique_ptr<MIRParser> MParser =
createMIRParser(std::move(MBuffer), Context);
ASSERT_TRUE(MParser);
std::unique_ptr<Module> M = MParser->parseIRModule();
ASSERT_TRUE(M);
M->setTargetTriple(TM->getTargetTriple().getTriple());
M->setDataLayout(TM->createDataLayout());
MachineModuleInfo MMI(TM);
bool Res = MParser->parseMachineFunctions(*M, MMI);
ASSERT_FALSE(Res);
auto F = M->getFunction("sizes");
ASSERT_TRUE(F != nullptr);
auto &MF = MMI.getOrCreateMachineFunction(*F);
Checks(*II, MF);
}
} // anonymous namespace
TEST(InstSizes, INLINEASM_BR) {
std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
std::unique_ptr<LoongArchInstrInfo> II = createInstrInfo(TM.get());
runChecks(TM.get(), II.get(), "",
// clang-format off
" INLINEASM_BR &nop, 1 /* sideeffect attdialect */, 13 /* imm */, %jump-table.0\n",
// clang-format on
[](LoongArchInstrInfo &II, MachineFunction &MF) {
auto I = MF.begin()->begin();
EXPECT_EQ(4u, II.getInstSizeInBytes(*I));
});
}
TEST(InstSizes, SPACE) {
std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
std::unique_ptr<LoongArchInstrInfo> II = createInstrInfo(TM.get());
runChecks(TM.get(), II.get(), "", " INLINEASM &\".space 1024\", 1\n",
[](LoongArchInstrInfo &II, MachineFunction &MF) {
auto I = MF.begin()->begin();
EXPECT_EQ(1024u, II.getInstSizeInBytes(*I));
});
}
TEST(InstSizes, AtomicPseudo) {
std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
std::unique_ptr<LoongArchInstrInfo> II = createInstrInfo(TM.get());
runChecks(
TM.get(), II.get(), "",
// clang-format off
" dead early-clobber renamable $r10, dead early-clobber renamable $r11 = PseudoMaskedAtomicLoadAdd32 renamable $r7, renamable $r6, renamable $r8, 4\n"
" dead early-clobber renamable $r10, dead early-clobber renamable $r11 = PseudoAtomicLoadAdd32 renamable $r7, renamable $r6, renamable $r8\n"
" dead early-clobber renamable $r5, dead early-clobber renamable $r9, dead early-clobber renamable $r10 = PseudoMaskedAtomicLoadUMax32 renamable $r7, renamable $r6, renamable $r8, 4\n"
" 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"
" dead early-clobber renamable $r5, dead early-clobber renamable $r9 = PseudoCmpXchg32 renamable $r7, renamable $r4, renamable $r6\n"
" 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",
// clang-format on
[](LoongArchInstrInfo &II, MachineFunction &MF) {
auto I = MF.begin()->begin();
EXPECT_EQ(36u, II.getInstSizeInBytes(*I));
++I;
EXPECT_EQ(24u, II.getInstSizeInBytes(*I));
++I;
EXPECT_EQ(48u, II.getInstSizeInBytes(*I));
++I;
EXPECT_EQ(56u, II.getInstSizeInBytes(*I));
++I;
EXPECT_EQ(36u, II.getInstSizeInBytes(*I));
++I;
EXPECT_EQ(44u, II.getInstSizeInBytes(*I));
});
}