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