114 lines
4 KiB
C++
114 lines
4 KiB
C++
#include "AArch64InstrInfo.h"
|
|
#include "AArch64Subtarget.h"
|
|
#include "AArch64TargetMachine.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
#include "llvm/MC/TargetRegistry.h"
|
|
#include "llvm/Support/TargetSelect.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#define GET_COMPUTE_FEATURES
|
|
#include "AArch64GenInstrInfo.inc"
|
|
|
|
using namespace llvm;
|
|
namespace {
|
|
std::unique_ptr<LLVMTargetMachine> createTargetMachine(const std::string &CPU) {
|
|
auto TT(Triple::normalize("aarch64--"));
|
|
|
|
LLVMInitializeAArch64TargetInfo();
|
|
LLVMInitializeAArch64Target();
|
|
LLVMInitializeAArch64TargetMC();
|
|
|
|
std::string Error;
|
|
const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
|
|
|
|
return std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine *>(
|
|
TheTarget->createTargetMachine(TT, CPU, "", TargetOptions(), std::nullopt,
|
|
std::nullopt, CodeGenOptLevel::Default)));
|
|
}
|
|
|
|
std::unique_ptr<AArch64InstrInfo> createInstrInfo(TargetMachine *TM) {
|
|
AArch64Subtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),
|
|
std::string(TM->getTargetCPU()),
|
|
std::string(TM->getTargetFeatureString()), *TM, true);
|
|
return std::make_unique<AArch64InstrInfo>(ST);
|
|
}
|
|
|
|
/// Returns true if the instruction is enabled under a feature that the
|
|
/// CPU supports.
|
|
static bool isInstructionSupportedByCPU(unsigned Opcode,
|
|
FeatureBitset Features) {
|
|
FeatureBitset AvailableFeatures =
|
|
llvm::AArch64_MC::computeAvailableFeatures(Features);
|
|
FeatureBitset RequiredFeatures =
|
|
llvm::AArch64_MC::computeRequiredFeatures(Opcode);
|
|
FeatureBitset MissingFeatures =
|
|
(AvailableFeatures & RequiredFeatures) ^ RequiredFeatures;
|
|
return MissingFeatures.none();
|
|
}
|
|
|
|
void runSVEPseudoTestForCPU(const std::string &CPU) {
|
|
|
|
std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine(CPU);
|
|
ASSERT_TRUE(TM);
|
|
std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
|
|
ASSERT_TRUE(II);
|
|
|
|
const MCSubtargetInfo *STI = TM->getMCSubtargetInfo();
|
|
MCSchedModel SchedModel = STI->getSchedModel();
|
|
|
|
for (unsigned i = 0; i < AArch64::INSTRUCTION_LIST_END; ++i) {
|
|
// Check if instruction is in the pseudo table
|
|
// i holds the opcode of the pseudo, OrigInstr holds the opcode of the
|
|
// original instruction
|
|
int OrigInstr = AArch64::getSVEPseudoMap(i);
|
|
if (OrigInstr == -1)
|
|
continue;
|
|
|
|
// Ignore any pseudos/instructions which may not be part of the scheduler
|
|
// model for the CPU we're testing. This avoids this test from failing when
|
|
// new instructions are added that are not yet covered by the scheduler
|
|
// model.
|
|
if (!isInstructionSupportedByCPU(OrigInstr, STI->getFeatureBits()))
|
|
continue;
|
|
|
|
const MCInstrDesc &Desc = II->get(i);
|
|
unsigned SCClass = Desc.getSchedClass();
|
|
const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SCClass);
|
|
|
|
const MCInstrDesc &DescOrig = II->get(OrigInstr);
|
|
unsigned SCClassOrig = DescOrig.getSchedClass();
|
|
const MCSchedClassDesc *SCDescOrig =
|
|
SchedModel.getSchedClassDesc(SCClassOrig);
|
|
|
|
int Latency = 0;
|
|
int LatencyOrig = 0;
|
|
|
|
for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries;
|
|
DefIdx != DefEnd; ++DefIdx) {
|
|
const MCWriteLatencyEntry *WLEntry =
|
|
STI->getWriteLatencyEntry(SCDesc, DefIdx);
|
|
const MCWriteLatencyEntry *WLEntryOrig =
|
|
STI->getWriteLatencyEntry(SCDescOrig, DefIdx);
|
|
Latency = std::max(Latency, static_cast<int>(WLEntry->Cycles));
|
|
LatencyOrig = std::max(Latency, static_cast<int>(WLEntryOrig->Cycles));
|
|
}
|
|
|
|
ASSERT_EQ(Latency, LatencyOrig);
|
|
ASSERT_TRUE(SCDesc->isValid());
|
|
}
|
|
}
|
|
|
|
// TODO : Add more CPUs that support SVE/SVE2
|
|
TEST(AArch64SVESchedPseudoTesta510, IsCorrect) {
|
|
runSVEPseudoTestForCPU("cortex-a510");
|
|
}
|
|
|
|
TEST(AArch64SVESchedPseudoTestv2, IsCorrect) {
|
|
runSVEPseudoTestForCPU("neoverse-v2");
|
|
}
|
|
|
|
} // namespace
|