From 1ad928dc2cda89e2e0ae5cf60fc3899dd29564a4 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Fri, 28 Jul 2023 09:42:24 -0400 Subject: [PATCH] IR: Add special NZCV "flag" Reserve 4 bytes of "flags" to model the 32-bit arm64 NZCV register, so we can start porting FEX's flag handling code over to using NZCV without needing the whole compiler to be aware of instructions that might clobber host flags. Signed-off-by: Alyssa Rosenzweig --- .../Interface/Core/Interpreter/MemoryOps.cpp | 22 ++++++++++++++----- .../Interface/Core/JIT/Arm64/MemoryOps.cpp | 12 ++++++++-- .../Interface/Core/JIT/x86_64/MemoryOps.cpp | 12 ++++++++-- .../FEXCore/include/FEXCore/Core/X86Enums.h | 7 ++++++ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/MemoryOps.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/MemoryOps.cpp index 096da6f6a..d4c355b97 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/MemoryOps.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/MemoryOps.cpp @@ -190,19 +190,31 @@ DEF_OP(LoadFlag) { uintptr_t ContextPtr = reinterpret_cast(Data->State->CurrentFrame); ContextPtr += offsetof(FEXCore::Core::CPUState, flags[0]); ContextPtr += Op->Flag; - uint8_t const *MemData = reinterpret_cast(ContextPtr); - GD = *MemData; + + if (Op->Flag == 24 /* NZCV */) { + uint32_t const *MemData = reinterpret_cast(ContextPtr); + GD = *MemData; + } else { + uint8_t const *MemData = reinterpret_cast(ContextPtr); + GD = *MemData; + } } DEF_OP(StoreFlag) { auto Op = IROp->C(); - uint8_t Arg = *GetSrc(Data->SSAData, Op->Value); + uint32_t Arg = *GetSrc(Data->SSAData, Op->Value); uintptr_t ContextPtr = reinterpret_cast(Data->State->CurrentFrame); ContextPtr += offsetof(FEXCore::Core::CPUState, flags[0]); ContextPtr += Op->Flag; - uint8_t *MemData = reinterpret_cast(ContextPtr); - *MemData = Arg; + + if (Op->Flag == 24 /* NZCV */) { + uint32_t *MemData = reinterpret_cast(ContextPtr); + *MemData = Arg; + } else { + uint8_t *MemData = reinterpret_cast(ContextPtr); + *MemData = Arg; + } } DEF_OP(LoadMem) { diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp index 8805637f6..33aedd381 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp @@ -1051,12 +1051,20 @@ DEF_OP(FillRegister) { DEF_OP(LoadFlag) { auto Op = IROp->C(); auto Dst = GetReg(Node); - ldrb(Dst, STATE, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag); + + if (Op->Flag == 24 /* NZCV */) + ldr(Dst.W(), STATE, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag); + else + ldrb(Dst, STATE, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag); } DEF_OP(StoreFlag) { auto Op = IROp->C(); - strb(GetReg(Op->Value.ID()), STATE, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag); + + if (Op->Flag == 24 /* NZCV */) + str(GetReg(Op->Value.ID()).W(), STATE, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag); + else + strb(GetReg(Op->Value.ID()), STATE, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag); } FEXCore::ARMEmitter::ExtendedMemOperand Arm64JITCore::GenerateMemOperand(uint8_t AccessSize, diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/MemoryOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/MemoryOps.cpp index 98a7f3807..775d4d27c 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/MemoryOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/MemoryOps.cpp @@ -601,14 +601,22 @@ DEF_OP(LoadFlag) { auto Op = IROp->C(); auto Dst = GetDst(Node); - movzx(Dst, byte [STATE + (offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag)]); + + if (Op->Flag == 24 /* NZCV */) + mov(Dst.cvt32(), dword [STATE + (offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag)]); + else + movzx(Dst, byte [STATE + (offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag)]); } DEF_OP(StoreFlag) { auto Op = IROp->C(); mov (rax, GetSrc(Op->Value.ID())); - mov(byte [STATE + (offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag)], al); + + if (Op->Flag == 24 /* NZCV */) + mov(dword [STATE + (offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag)], eax); + else + mov(byte [STATE + (offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag)], al); } Xbyak::RegExp X86JITCore::GenerateModRM(Xbyak::Reg Base, IR::OrderedNodeWrapper Offset, IR::MemOffsetType OffsetType, uint8_t OffsetScale) const { diff --git a/External/FEXCore/include/FEXCore/Core/X86Enums.h b/External/FEXCore/include/FEXCore/Core/X86Enums.h index a28c942cd..21a36f071 100644 --- a/External/FEXCore/include/FEXCore/Core/X86Enums.h +++ b/External/FEXCore/include/FEXCore/Core/X86Enums.h @@ -74,6 +74,13 @@ enum X86RegLocation : uint32_t { RFLAG_VIP_LOC = 20, RFLAG_ID_LOC = 21, + // So we can implement arm64-like flag manipulaton on the interpreter/x86 jit.. + // SF/ZF/CF/OF packed into a 32-bit word, matching arm64's NZCV structure (not semantics). + RFLAG_NZCV_LOC = 24, + RFLAG_NZCV_1_LOC = 25, + RFLAG_NZCV_2_LOC = 26, + RFLAG_NZCV_3_LOC = 27, + // So we can share flag handling logic, we put x87 flags after RFLAGS X87FLAG_BASE = 32, X87FLAG_IE_LOC = 32,