xref: /llvm-project/llvm/unittests/Target/AArch64/AArch64SVESchedPseudoTest.cpp (revision bb3f5e1fed7c6ba733b7f273e93f5d3930976185)
1 #include "AArch64InstrInfo.h"
2 #include "AArch64Subtarget.h"
3 #include "AArch64TargetMachine.h"
4 #include "llvm/MC/MCSubtargetInfo.h"
5 #include "llvm/MC/TargetRegistry.h"
6 #include "llvm/Support/TargetSelect.h"
7 #include "llvm/Support/raw_ostream.h"
8 #include "llvm/Target/TargetMachine.h"
9 #include "llvm/Target/TargetOptions.h"
10 
11 #include "gtest/gtest.h"
12 
13 #define GET_COMPUTE_FEATURES
14 #include "AArch64GenInstrInfo.inc"
15 
16 using namespace llvm;
17 namespace {
18 std::unique_ptr<TargetMachine> createTargetMachine(const std::string &CPU) {
19   auto TT(Triple::normalize("aarch64--"));
20 
21   LLVMInitializeAArch64TargetInfo();
22   LLVMInitializeAArch64Target();
23   LLVMInitializeAArch64TargetMC();
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, "", TargetOptions(), std::nullopt,
30                                      std::nullopt, CodeGenOptLevel::Default));
31 }
32 
33 std::unique_ptr<AArch64InstrInfo> createInstrInfo(TargetMachine *TM) {
34   AArch64Subtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),
35                       std::string(TM->getTargetCPU()),
36                       std::string(TM->getTargetFeatureString()), *TM, true);
37   return std::make_unique<AArch64InstrInfo>(ST);
38 }
39 
40 /// Returns true if the instruction is enabled under a feature that the
41 /// CPU supports.
42 static bool isInstructionSupportedByCPU(unsigned Opcode,
43                                         FeatureBitset Features) {
44   FeatureBitset AvailableFeatures =
45       llvm::AArch64_MC::computeAvailableFeatures(Features);
46   FeatureBitset RequiredFeatures =
47       llvm::AArch64_MC::computeRequiredFeatures(Opcode);
48   FeatureBitset MissingFeatures =
49       (AvailableFeatures & RequiredFeatures) ^ RequiredFeatures;
50   return MissingFeatures.none();
51 }
52 
53 void runSVEPseudoTestForCPU(const std::string &CPU) {
54 
55   std::unique_ptr<TargetMachine> TM = createTargetMachine(CPU);
56   ASSERT_TRUE(TM);
57   std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
58   ASSERT_TRUE(II);
59 
60   const MCSubtargetInfo *STI = TM->getMCSubtargetInfo();
61   MCSchedModel SchedModel = STI->getSchedModel();
62 
63   for (unsigned i = 0; i < AArch64::INSTRUCTION_LIST_END; ++i) {
64     // Check if instruction is in the pseudo table
65     // i holds the opcode of the pseudo, OrigInstr holds the opcode of the
66     // original instruction
67     int OrigInstr = AArch64::getSVEPseudoMap(i);
68     if (OrigInstr == -1)
69       continue;
70 
71     // Ignore any pseudos/instructions which may not be part of the scheduler
72     // model for the CPU we're testing. This avoids this test from failing when
73     // new instructions are added that are not yet covered by the scheduler
74     // model.
75     if (!isInstructionSupportedByCPU(OrigInstr, STI->getFeatureBits()))
76       continue;
77 
78     const MCInstrDesc &Desc = II->get(i);
79     unsigned SCClass = Desc.getSchedClass();
80     const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SCClass);
81 
82     const MCInstrDesc &DescOrig = II->get(OrigInstr);
83     unsigned SCClassOrig = DescOrig.getSchedClass();
84     const MCSchedClassDesc *SCDescOrig =
85         SchedModel.getSchedClassDesc(SCClassOrig);
86 
87     int Latency = 0;
88     int LatencyOrig = 0;
89 
90     for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries;
91          DefIdx != DefEnd; ++DefIdx) {
92       const MCWriteLatencyEntry *WLEntry =
93           STI->getWriteLatencyEntry(SCDesc, DefIdx);
94       const MCWriteLatencyEntry *WLEntryOrig =
95           STI->getWriteLatencyEntry(SCDescOrig, DefIdx);
96       Latency = std::max(Latency, static_cast<int>(WLEntry->Cycles));
97       LatencyOrig = std::max(Latency, static_cast<int>(WLEntryOrig->Cycles));
98     }
99 
100     ASSERT_EQ(Latency, LatencyOrig);
101     ASSERT_TRUE(SCDesc->isValid());
102   }
103 }
104 
105 // TODO : Add more CPUs that support SVE/SVE2
106 TEST(AArch64SVESchedPseudoTesta510, IsCorrect) {
107   runSVEPseudoTestForCPU("cortex-a510");
108 }
109 
110 TEST(AArch64SVESchedPseudoTestn1, IsCorrect) {
111   runSVEPseudoTestForCPU("neoverse-n2");
112 }
113 
114 TEST(AArch64SVESchedPseudoTestn3, IsCorrect) {
115   runSVEPseudoTestForCPU("neoverse-n3");
116 }
117 
118 TEST(AArch64SVESchedPseudoTestv1, IsCorrect) {
119   runSVEPseudoTestForCPU("neoverse-v1");
120 }
121 
122 TEST(AArch64SVESchedPseudoTestv2, IsCorrect) {
123   runSVEPseudoTestForCPU("neoverse-v2");
124 }
125 
126 } // namespace
127