| 238 | static fextl::vector<std::pair<std::string_view, std::string_view>> EnvironmentVariables {}; |
| 239 | |
| 240 | static bool TestInstructions(FEXCore::Context::Context* CTX, FEXCore::Core::InternalThreadState* Thread, const char* UpdatedInstructionCountsPath) { |
| 241 | LogMan::Msg::IFmt("Compiling code"); |
| 242 | |
| 243 | // Tell FEXCore to compile all the instructions upfront. |
| 244 | const TestInfo* CurrentTest = TestsStart; |
| 245 | fextl::vector<CodeSize::CodeSizeValidation::InstructionData> TestData {}; |
| 246 | TestData.resize(TestHeaderData->NumTests); |
| 247 | for (size_t i = 0; i < TestHeaderData->NumTests; ++i) { |
| 248 | uint64_t CodeRIP = (uint64_t)&CurrentTest->Code[0]; |
| 249 | LogMan::Msg::IFmt("Compiling instruction '{}'", CurrentTest->TestInst); |
| 250 | |
| 251 | TestData[i] = |
| 252 | CodeSize::Validation->CompileAndGetStats(CTX, Thread, reinterpret_cast<void*>(CodeRIP), CurrentTest->CodeSize, CurrentTest->x86InstCount); |
| 253 | |
| 254 | // Go to the next test. |
| 255 | CurrentTest = reinterpret_cast<const TestInfo*>(&CurrentTest->Code[CurrentTest->CodeSize]); |
| 256 | } |
| 257 | |
| 258 | bool TestsPassed {true}; |
| 259 | |
| 260 | // Get all the data for the instructions compiled. |
| 261 | CurrentTest = TestsStart; |
| 262 | for (size_t i = 0; i < TestHeaderData->NumTests; ++i) { |
| 263 | // Get the instruction stats. |
| 264 | const auto INSTStats = &TestData[i]; |
| 265 | |
| 266 | LogMan::Msg::IFmt("Testing instruction '{}': {} host instructions", CurrentTest->TestInst, INSTStats->first.HostCodeInstructions); |
| 267 | |
| 268 | // Show the code if the count of instructions changed to something we didn't expect. |
| 269 | bool ShouldShowCode = INSTStats->first.HostCodeInstructions != CurrentTest->ExpectedInstructionCount; |
| 270 | |
| 271 | if (ShouldShowCode) { |
| 272 | for (const auto& Line : INSTStats->second) { |
| 273 | LogMan::Msg::EFmt("\t{}", Line); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | if (INSTStats->first.HostCodeInstructions != CurrentTest->ExpectedInstructionCount) { |
| 278 | LogMan::Msg::EFmt("Fail: '{}': {} host instructions", CurrentTest->TestInst, INSTStats->first.HostCodeInstructions); |
| 279 | LogMan::Msg::EFmt("Fail: Test took {} instructions but we expected {} instructions!", INSTStats->first.HostCodeInstructions, |
| 280 | CurrentTest->ExpectedInstructionCount); |
| 281 | |
| 282 | // Fail the test if the instruction count has changed at all. |
| 283 | TestsPassed = false; |
| 284 | } |
| 285 | |
| 286 | // Go to the next test. |
| 287 | CurrentTest = reinterpret_cast<const TestInfo*>(&CurrentTest->Code[CurrentTest->CodeSize]); |
| 288 | } |
| 289 | |
| 290 | if (UpdatedInstructionCountsPath) { |
| 291 | // Unlink the file. |
| 292 | unlink(UpdatedInstructionCountsPath); |
| 293 | |
| 294 | FEXCore::File::File FD(UpdatedInstructionCountsPath, |
| 295 | FEXCore::File::FileModes::WRITE | FEXCore::File::FileModes::CREATE | FEXCore::File::FileModes::TRUNCATE); |
| 296 | |
| 297 | if (!FD.IsValid()) { |