xref: /llvm-project/llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp (revision fac87b889c50f493ba332950f613fa15a45be9a9)
1 //===-- SnippetFileTest.cpp -------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "SnippetFile.h"
10 
11 #include "LlvmState.h"
12 #include "TestBase.h"
13 #include "X86InstrInfo.h"
14 #include "llvm/MC/TargetRegistry.h"
15 #include "llvm/Support/Error.h"
16 #include "llvm/Support/FileSystem.h"
17 #include "llvm/Support/Path.h"
18 #include "llvm/Support/TargetSelect.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/Testing/Support/SupportHelpers.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 
24 namespace llvm {
25 namespace exegesis {
26 
27 void InitializeX86ExegesisTarget();
28 
29 namespace {
30 
31 using testing::ElementsAre;
32 using testing::Eq;
33 using testing::Property;
34 using testing::SizeIs;
35 using testing::UnorderedElementsAre;
36 
37 using llvm::unittest::TempDir;
38 
39 class X86SnippetFileTest : public X86TestBase {
40 protected:
41   Expected<std::vector<BenchmarkCode>> TestCommon(StringRef Contents) {
42     TempDir TestDirectory("SnippetFileTestDir", /*Unique*/ true);
43     SmallString<64> Filename(TestDirectory.path());
44     sys::path::append(Filename, "snippet.s");
45     errs() << Filename << "-------\n";
46     {
47       std::error_code EC;
48       raw_fd_ostream FOS(Filename, EC);
49       FOS << Contents;
50       EXPECT_FALSE(EC);
51     }
52     return readSnippets(State, Filename);
53   }
54 };
55 
56 // FIXME: Refactor these to ../Common/Matchers.h
57 static auto HasOpcode = [](unsigned Opcode) {
58   return Property(&MCInst::getOpcode, Eq(Opcode));
59 };
60 
61 MATCHER_P2(RegisterInitialValueIs, Reg, Val, "") {
62   if (arg.Register == Reg &&
63       arg.Value.getLimitedValue() == static_cast<uint64_t>(Val))
64     return true;
65   *result_listener << "expected: {" << Reg << ", " << Val << "} ";
66   *result_listener << "actual: {" << arg.Register << ", "
67                    << arg.Value.getLimitedValue() << "}";
68   return false;
69 }
70 
71 MATCHER_P3(MemoryDefinitionIs, Name, Value, Size, "") {
72   if (arg.second.Value.getLimitedValue() == static_cast<uint64_t>(Value) &&
73       arg.second.SizeBytes == static_cast<size_t>(Size) && arg.first == Name)
74     return true;
75   *result_listener << "expected: {" << Name << ", " << Value << ", " << Size
76                    << "} ";
77   *result_listener << "actual: {" << arg.first << ", "
78                    << arg.second.Value.getLimitedValue() << ", "
79                    << arg.second.SizeBytes << "}";
80   return false;
81 }
82 
83 MATCHER_P2(MemoryMappingIs, Address, Name, "") {
84   if (arg.Address == static_cast<uintptr_t>(Address) &&
85       arg.MemoryValueName == Name)
86     return true;
87   *result_listener << "expected: {" << Address << ", " << Name << "} ";
88   *result_listener << "actual: {" << arg.Address << ", " << arg.MemoryValueName
89                    << "}";
90   return false;
91 }
92 
93 TEST_F(X86SnippetFileTest, Works) {
94   auto Snippets = TestCommon(R"(
95     # LLVM-EXEGESIS-DEFREG RAX 0f
96     # LLVM-EXEGESIS-DEFREG SIL 0
97     # LLVM-EXEGESIS-LIVEIN RDI
98     # LLVM-EXEGESIS-LIVEIN DL
99     incq %rax
100   )");
101   EXPECT_FALSE((bool)Snippets.takeError());
102   ASSERT_THAT(*Snippets, SizeIs(1));
103   const auto &Snippet = (*Snippets)[0];
104   ASSERT_THAT(Snippet.Key.Instructions, ElementsAre(HasOpcode(X86::INC64r)));
105   ASSERT_THAT(Snippet.Key.RegisterInitialValues,
106               ElementsAre(RegisterInitialValueIs(X86::RAX, 15),
107                           RegisterInitialValueIs(X86::SIL, 0)));
108   ASSERT_THAT(Snippet.LiveIns, ElementsAre(X86::RDI, X86::DL));
109 }
110 
111 TEST_F(X86SnippetFileTest, BadDefregParam) {
112   auto Error = TestCommon(R"(
113     # LLVM-EXEGESIS-DEFREG DOESNOEXIST 0
114     incq %rax
115   )")
116                    .takeError();
117   EXPECT_TRUE((bool)Error);
118   consumeError(std::move(Error));
119 }
120 
121 TEST_F(X86SnippetFileTest, NoDefregValue) {
122   auto Error = TestCommon(R"(
123     # LLVM-EXEGESIS-DEFREG RAX
124     incq %rax
125   )")
126                    .takeError();
127   EXPECT_TRUE((bool)Error);
128   consumeError(std::move(Error));
129 }
130 
131 TEST_F(X86SnippetFileTest, MissingParam) {
132   auto Error = TestCommon(R"(
133     # LLVM-EXEGESIS-LIVEIN
134     incq %rax
135   )")
136                    .takeError();
137   EXPECT_TRUE((bool)Error);
138   consumeError(std::move(Error));
139 }
140 
141 TEST_F(X86SnippetFileTest, NoAsmStreamer) {
142   auto Snippets = TestCommon(R"(
143     .cv_fpo_proc foo 4
144   )");
145   EXPECT_FALSE((bool)Snippets.takeError());
146 }
147 
148 TEST_F(X86SnippetFileTest, MemoryDefinitionTestSingleDef) {
149   auto Snippets = TestCommon(R"(
150     # LLVM-EXEGESIS-MEM-DEF test1 4096 ff
151     # LLVM-EXEGESIS-MEM-MAP test1 65536
152     # LLVM-EXEGESIS-MEM-MAP test1 131072
153     movq $8192, %r10
154     movq (%r10), %r11
155   )");
156   EXPECT_FALSE((bool)Snippets.takeError());
157   ASSERT_THAT(*Snippets, SizeIs(1));
158   const auto &Snippet = (*Snippets)[0];
159   ASSERT_THAT(Snippet.Key.MemoryValues,
160               UnorderedElementsAre(MemoryDefinitionIs("test1", 255, 4096)));
161   ASSERT_THAT(Snippet.Key.MemoryMappings,
162               ElementsAre(MemoryMappingIs(65536, "test1"),
163                           MemoryMappingIs(131072, "test1")));
164 }
165 
166 TEST_F(X86SnippetFileTest, MemoryDefinitionsTestTwoDef) {
167   auto Snippets = TestCommon(R"(
168     # LLVM-EXEGESIS-MEM-DEF test1 4096 ff
169     # LLVM-EXEGESIS-MEM-DEF test2 4096 100
170     # LLVM-EXEGESIS-MEM-MAP test1 65536
171     # LLVM-EXEGESIS-MEM-MAP test2 131072
172     movq $8192, %r10
173     movq (%r10), %r11
174   )");
175   EXPECT_FALSE((bool)Snippets.takeError());
176   ASSERT_THAT(*Snippets, SizeIs(1));
177   const auto &Snippet = (*Snippets)[0];
178   ASSERT_THAT(Snippet.Key.MemoryValues,
179               UnorderedElementsAre(MemoryDefinitionIs("test1", 255, 4096),
180                                    MemoryDefinitionIs("test2", 256, 4096)));
181   ASSERT_THAT(Snippet.Key.MemoryMappings,
182               ElementsAre(MemoryMappingIs(65536, "test1"),
183                           MemoryMappingIs(131072, "test2")));
184 }
185 
186 TEST_F(X86SnippetFileTest, MemoryDefinitionMissingParameter) {
187   auto Error = TestCommon(R"(
188     # LLVM-EXEGESIS-MEM-DEF test1 4096
189   )")
190                    .takeError();
191   EXPECT_TRUE((bool)Error);
192   consumeError(std::move(Error));
193 }
194 
195 TEST_F(X86SnippetFileTest, MemoryMappingMissingParameters) {
196   auto Error = TestCommon(R"(
197     # LLVM-EXEGESIS-MEM-MAP test1
198   )")
199                    .takeError();
200   EXPECT_TRUE((bool)Error);
201   consumeError(std::move(Error));
202 }
203 
204 TEST_F(X86SnippetFileTest, MemoryMappingNoDefinition) {
205   auto Error = TestCommon(R"(
206     # LLVM-EXEGESIS-MEM-MAP test1 65536
207   )")
208                    .takeError();
209   EXPECT_TRUE((bool)Error);
210   consumeError(std::move(Error));
211 }
212 
213 TEST_F(X86SnippetFileTest, SnippetAddress) {
214   auto Snippets = TestCommon(R"(
215     # LLVM-EXEGESIS-SNIPPET-ADDRESS 10000
216   )");
217   ASSERT_TRUE(static_cast<bool>(Snippets));
218   EXPECT_THAT(*Snippets, SizeIs(1));
219   const auto &Snippet = (*Snippets)[0];
220   EXPECT_EQ(Snippet.Key.SnippetAddress, static_cast<uintptr_t>(0x10000));
221 }
222 
223 TEST_F(X86SnippetFileTest, LoopRegister) {
224   auto Snippets = TestCommon(R"(
225     # LLVM-EXEGESIS-LOOP-REGISTER R11
226   )");
227   ASSERT_TRUE(static_cast<bool>(Snippets));
228   EXPECT_THAT(*Snippets, SizeIs(1));
229   const auto &Snippet = (*Snippets)[0];
230   EXPECT_EQ(Snippet.Key.LoopRegister, X86::R11);
231 }
232 
233 TEST_F(X86SnippetFileTest, LoopRegisterInvalidRegister) {
234   auto Error = TestCommon(R"(
235     # LLVM-EXEGESIS-LOOP-REGISTER INVALID
236   )")
237                    .takeError();
238   EXPECT_TRUE(static_cast<bool>(Error));
239   consumeError(std::move(Error));
240 }
241 
242 } // namespace
243 } // namespace exegesis
244 } // namespace llvm
245