diff --git a/src/dynarmic/backend/arm64/reg_alloc.cpp b/src/dynarmic/backend/arm64/reg_alloc.cpp index 41446bb2..c92e6d7f 100644 --- a/src/dynarmic/backend/arm64/reg_alloc.cpp +++ b/src/dynarmic/backend/arm64/reg_alloc.cpp @@ -11,6 +11,8 @@ #include #include +#include "dynarmic/backend/arm64/abi.h" + namespace Dynarmic::Backend::Arm64 { using namespace oaknut::util; @@ -232,7 +234,7 @@ int RegAlloc::RealizeWriteImpl(const IR::Inst* value) { fprs[new_location_index].SetupLocation(value); return new_location_index; } else if constexpr (kind == HostLoc::Kind::Flags) { - ASSERT(flags.values.empty()); + SpillFlags(); flags.SetupLocation(value); return 0; } else { @@ -287,6 +289,31 @@ void RegAlloc::SpillFpr(int index) { spills[new_location_index] = std::exchange(fprs[index], {}); } +void RegAlloc::ReadWriteFlags(Argument& read, IR::Inst* write) { + const auto current_location = ValueLocation(read.value.GetInst()); + ASSERT(current_location); + + if (current_location->kind == HostLoc::Kind::Flags) { + if (!flags.IsOneRemainingUse()) { + SpillFlags(); + } + } else if (current_location->kind == HostLoc::Kind::Gpr) { + if (!flags.values.empty()) { + SpillFlags(); + } + code.MSR(static_cast(0b11'011'0100'0010'000), oaknut::XReg{current_location->index}); + } else if (current_location->kind == HostLoc::Kind::Spill) { + if (!flags.values.empty()) { + SpillFlags(); + } + code.LDR(Wscratch0, SP, spill_offset + current_location->index * spill_slot_size); + code.MSR(static_cast(0b11'011'0100'0010'000), Xscratch0); + } else { + ASSERT_FALSE("Invalid current location for flags"); + } + flags.SetupLocation(write); +} + void RegAlloc::SpillFlags() { ASSERT(!flags.locked && !flags.realized); if (flags.values.empty()) { diff --git a/src/dynarmic/backend/arm64/reg_alloc.h b/src/dynarmic/backend/arm64/reg_alloc.h index 12360022..4140f0fd 100644 --- a/src/dynarmic/backend/arm64/reg_alloc.h +++ b/src/dynarmic/backend/arm64/reg_alloc.h @@ -219,6 +219,7 @@ public: void DefineAsExisting(IR::Inst* inst, Argument& arg); + void ReadWriteFlags(Argument& read, IR::Inst* write); void SpillFlags(); void SpillAll();