diff --git a/src/dynarmic/src/dynarmic/backend/x64/hostloc.h b/src/dynarmic/src/dynarmic/backend/x64/hostloc.h index c96a18628a..d6fb88554e 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/hostloc.h +++ b/src/dynarmic/src/dynarmic/backend/x64/hostloc.h @@ -13,9 +13,9 @@ namespace Dynarmic::Backend::X64 { -// Our static vector will contain 32 elements, stt. an uint16_t will fill up 64 bytes +// Our static vector will contain 32 elements, stt. an uint8_t will fill up 64 bytes // (an entire cache line). Thanks. -enum class HostLoc : uint16_t { +enum class HostLoc : std::uint8_t { // Ordering of the registers is intentional. See also: HostLocToX64. RAX, RCX, @@ -60,48 +60,48 @@ enum class HostLoc : uint16_t { constexpr size_t NonSpillHostLocCount = static_cast(HostLoc::FirstSpill); -inline bool HostLocIsGPR(HostLoc reg) { +constexpr bool HostLocIsGPR(HostLoc reg) { return reg >= HostLoc::RAX && reg <= HostLoc::R15; } -inline bool HostLocIsXMM(HostLoc reg) { +constexpr bool HostLocIsXMM(HostLoc reg) { return reg >= HostLoc::XMM0 && reg <= HostLoc::XMM15; } -inline bool HostLocIsRegister(HostLoc reg) { +constexpr bool HostLocIsRegister(HostLoc reg) { return HostLocIsGPR(reg) || HostLocIsXMM(reg); } -inline bool HostLocIsFlag(HostLoc reg) { +constexpr bool HostLocIsFlag(HostLoc reg) { return reg >= HostLoc::CF && reg <= HostLoc::OF; } -inline HostLoc HostLocRegIdx(int idx) { +constexpr HostLoc HostLocRegIdx(int idx) { ASSERT(idx >= 0 && idx <= 15); return HostLoc(idx); } -inline HostLoc HostLocXmmIdx(int idx) { +constexpr HostLoc HostLocXmmIdx(int idx) { ASSERT(idx >= 0 && idx <= 15); return HostLoc(size_t(HostLoc::XMM0) + idx); } -inline HostLoc HostLocSpill(size_t i) { +constexpr HostLoc HostLocSpill(size_t i) { return HostLoc(size_t(HostLoc::FirstSpill) + i); } -inline bool HostLocIsSpill(HostLoc reg) { +constexpr bool HostLocIsSpill(HostLoc reg) { return reg >= HostLoc::FirstSpill; } -inline size_t HostLocBitWidth(HostLoc loc) { +constexpr size_t HostLocBitWidth(HostLoc loc) { if (HostLocIsGPR(loc)) return 64; - if (HostLocIsXMM(loc)) + else if (HostLocIsXMM(loc)) return 128; - if (HostLocIsSpill(loc)) + else if (HostLocIsSpill(loc)) return 128; - if (HostLocIsFlag(loc)) + else if (HostLocIsFlag(loc)) return 1; UNREACHABLE(); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp index 2f615514ab..fa6006ed2a 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp @@ -357,9 +357,8 @@ void RegAlloc::HostCall(IR::Inst* result_def, static const boost::container::static_vector other_caller_save = [args_hostloc]() noexcept { boost::container::static_vector ret(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end()); ret.erase(std::find(ret.begin(), ret.end(), ABI_RETURN)); - for (auto const hostloc : args_hostloc) { + for (auto const hostloc : args_hostloc) ret.erase(std::find(ret.begin(), ret.end(), hostloc)); - } return ret; }(); @@ -368,7 +367,7 @@ void RegAlloc::HostCall(IR::Inst* result_def, DefineValueImpl(result_def, ABI_RETURN); } - for (size_t i = 0; i < args_count; i++) { + for (size_t i = 0; i < args.size(); i++) { if (args[i] && !args[i]->get().IsVoid()) { UseScratch(*args[i], args_hostloc[i]); // LLVM puts the burden of zero-extension of 8 and 16 bit values on the caller instead of the callee @@ -383,36 +382,35 @@ void RegAlloc::HostCall(IR::Inst* result_def, case IR::Type::U32: code->mov(reg.cvt32(), reg.cvt32()); break; + case IR::Type::U64: + break; //no op default: - break; // Nothing needs to be done + UNREACHABLE(); } } } - for (size_t i = 0; i < args_count; i++) { + for (size_t i = 0; i < args.size(); i++) if (!args[i]) { // TODO: Force spill ScratchGpr(args_hostloc[i]); } - } - - for (HostLoc caller_saved : other_caller_save) { + for (auto const caller_saved : other_caller_save) ScratchImpl({caller_saved}); - } } void RegAlloc::AllocStackSpace(const size_t stack_space) noexcept { - ASSERT(stack_space < static_cast(std::numeric_limits::max())); + ASSERT(stack_space < size_t(std::numeric_limits::max())); ASSERT(reserved_stack_space == 0); reserved_stack_space = stack_space; - code->sub(code->rsp, static_cast(stack_space)); + code->sub(code->rsp, u32(stack_space)); } void RegAlloc::ReleaseStackSpace(const size_t stack_space) noexcept { - ASSERT(stack_space < static_cast(std::numeric_limits::max())); + ASSERT(stack_space < size_t(std::numeric_limits::max())); ASSERT(reserved_stack_space == stack_space); reserved_stack_space = 0; - code->add(code->rsp, static_cast(stack_space)); + code->add(code->rsp, u32(stack_space)); } HostLoc RegAlloc::SelectARegister(const boost::container::static_vector& desired_locations) const noexcept { @@ -494,7 +492,6 @@ void RegAlloc::DefineValueImpl(IR::Inst* def_inst, const IR::Value& use_inst) no HostLoc RegAlloc::LoadImmediate(IR::Value imm, HostLoc host_loc) noexcept { ASSERT_MSG(imm.IsImmediate(), "imm is not an immediate"); - if (HostLocIsGPR(host_loc)) { const Xbyak::Reg64 reg = HostLocToReg64(host_loc); const u64 imm_value = imm.GetImmediateAsU64(); @@ -503,10 +500,7 @@ HostLoc RegAlloc::LoadImmediate(IR::Value imm, HostLoc host_loc) noexcept { } else { code->mov(reg, imm_value); } - return host_loc; - } - - if (HostLocIsXMM(host_loc)) { + } else if (HostLocIsXMM(host_loc)) { const Xbyak::Xmm reg = HostLocToXmm(host_loc); const u64 imm_value = imm.GetImmediateAsU64(); if (imm_value == 0) { @@ -514,23 +508,19 @@ HostLoc RegAlloc::LoadImmediate(IR::Value imm, HostLoc host_loc) noexcept { } else { MAYBE_AVX(movaps, reg, code->Const(code->xword, imm_value)); } - return host_loc; + } else { + UNREACHABLE(); } - - UNREACHABLE(); + return host_loc; } void RegAlloc::Move(HostLoc to, HostLoc from) noexcept { const size_t bit_width = LocInfo(from).GetMaxBitWidth(); - ASSERT(LocInfo(to).IsEmpty() && !LocInfo(from).IsLocked()); ASSERT(bit_width <= HostLocBitWidth(to)); ASSERT_MSG(!LocInfo(from).IsEmpty(), "Mov eliminated"); - - if (!LocInfo(from).IsEmpty()) { - EmitMove(bit_width, to, from); - LocInfo(to) = std::exchange(LocInfo(from), {}); - } + EmitMove(bit_width, to, from); + LocInfo(to) = std::exchange(LocInfo(from), {}); } void RegAlloc::CopyToScratch(size_t bit_width, HostLoc to, HostLoc from) noexcept { diff --git a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h index e673f40263..f70329f471 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h +++ b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h @@ -264,7 +264,7 @@ private: BlockOfCode* code = nullptr; size_t reserved_stack_space = 0; }; -// Ensure a cache line is used, this is primordial -static_assert(sizeof(boost::container::static_vector) == 64); +// Ensure a cache line (or less) is used, this is primordial +static_assert(sizeof(boost::container::static_vector) == 40); } // namespace Dynarmic::Backend::X64 diff --git a/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.h b/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.h index 68d0ccff24..3f4823010b 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.h +++ b/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.h @@ -16,7 +16,7 @@ namespace Dynarmic::Backend::X64 { -enum class HostLoc : uint16_t; +enum class HostLoc : std::uint8_t; using Vector = std::array; #ifdef _MSC_VER diff --git a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp index 956e7905a5..885bf3c0e7 100644 --- a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp +++ b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp @@ -91,6 +91,9 @@ static u32 GenRandomInst(u64 pc, bool is_last_inst) { "MSR_reg", "MSR_imm", "MRS", + // Does not need test + "SVC", + "BRK" }; for (const auto& [fn, bitstring] : list) { @@ -200,7 +203,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv jit_env.ticks_left = instructions.size(); CheckedRun([&]() { jit.Run(); }); - uni_env.ticks_left = instructions.size(); + uni_env.ticks_left = instructions.size() * 4; uni.Run(); SCOPE_FAIL { @@ -296,7 +299,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv return; } - REQUIRE(uni.GetPC() == jit.GetPC()); + REQUIRE(uni.GetPC() + 4 == jit.GetPC()); REQUIRE(uni.GetRegisters() == jit.GetRegisters()); REQUIRE(uni.GetVectors() == jit.GetVectors()); REQUIRE(uni.GetSP() == jit.GetSP()); @@ -306,7 +309,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv REQUIRE(FP::FPSR{uni.GetFpsr()}.QC() == FP::FPSR{jit.GetFpsr()}.QC()); } -TEST_CASE("A64: Single random instruction", "[a64]") { +TEST_CASE("A64: Single random instruction", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; @@ -333,7 +336,7 @@ TEST_CASE("A64: Single random instruction", "[a64]") { } } -TEST_CASE("A64: Floating point instructions", "[a64]") { +TEST_CASE("A64: Floating point instructions", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; @@ -458,7 +461,7 @@ TEST_CASE("A64: Floating point instructions", "[a64]") { } } -TEST_CASE("A64: Small random block", "[a64]") { +TEST_CASE("A64: Small random block", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; @@ -493,7 +496,7 @@ TEST_CASE("A64: Small random block", "[a64]") { } } -TEST_CASE("A64: Large random block", "[a64]") { +TEST_CASE("A64: Large random block", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; diff --git a/src/dynarmic/tests/A64/verify_unicorn.cpp b/src/dynarmic/tests/A64/verify_unicorn.cpp index 5ffe4f15b0..0c0ccc1609 100644 --- a/src/dynarmic/tests/A64/verify_unicorn.cpp +++ b/src/dynarmic/tests/A64/verify_unicorn.cpp @@ -13,7 +13,7 @@ using namespace Dynarmic; -TEST_CASE("Unicorn: Sanity test", "[a64]") { +TEST_CASE("Unicorn: Sanity test", "[a64][unicorn]") { A64TestEnv env; env.code_mem.emplace_back(0x8b020020); // ADD X0, X1, X2 @@ -39,7 +39,7 @@ TEST_CASE("Unicorn: Sanity test", "[a64]") { REQUIRE(unicorn.GetPC() == 4); } -TEST_CASE("Unicorn: Ensure 0xFFFF'FFFF'FFFF'FFFF is readable", "[a64]") { +TEST_CASE("Unicorn: Ensure 0xFFFF'FFFF'FFFF'FFFF is readable", "[a64][unicorn]") { A64TestEnv env; env.code_mem.emplace_back(0x385fed99); // LDRB W25, [X12, #0xfffffffffffffffe]! @@ -59,7 +59,7 @@ TEST_CASE("Unicorn: Ensure 0xFFFF'FFFF'FFFF'FFFF is readable", "[a64]") { REQUIRE(unicorn.GetPC() == 4); } -TEST_CASE("Unicorn: Ensure is able to read across page boundaries", "[a64]") { +TEST_CASE("Unicorn: Ensure is able to read across page boundaries", "[a64][unicorn]") { A64TestEnv env; env.code_mem.emplace_back(0xb85f93d9); // LDUR W25, [X30, #0xfffffffffffffff9] diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp index da7e88ea03..b6fdefe0fc 100644 --- a/src/tests/video_core/memory_tracker.cpp +++ b/src/tests/video_core/memory_tracker.cpp @@ -28,11 +28,10 @@ public: for (u64 page = page_start; page < page_end; ++page) { int& value = page_table[page]; value += delta; - if (value < 0) { - throw std::logic_error{"negative page"}; - } if (value == 0) { page_table.erase(page); + } else if (value < 0) { + throw std::logic_error{"negative page"}; } } }