From 90ddee5f8df9ab7ee9a8839fca83ffb0cd3cea64 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 14 Sep 2023 15:52:55 -0700 Subject: [PATCH] IR: Implements support for arm64 bfxil This is useful for extracting a width from a register and inserting in to the lower bits of a destination. --- .../Interface/Core/Interpreter/ALUOps.cpp | 12 ++++++++ .../Core/Interpreter/InterpreterOps.cpp | 1 + .../Core/Interpreter/InterpreterOps.h | 1 + .../Interface/Core/JIT/Arm64/ALUOps.cpp | 23 +++++++++++++++ .../Source/Interface/Core/JIT/Arm64/JIT.cpp | 1 + .../Interface/Core/JIT/Arm64/JITClass.h | 1 + .../Interface/Core/JIT/x86_64/ALUOps.cpp | 29 +++++++++++++++++++ .../Interface/Core/JIT/x86_64/JITClass.h | 1 + FEXCore/Source/Interface/IR/IR.json | 11 +++++++ 9 files changed, 80 insertions(+) diff --git a/FEXCore/Source/Interface/Core/Interpreter/ALUOps.cpp b/FEXCore/Source/Interface/Core/Interpreter/ALUOps.cpp index 753896705..7092a32e4 100644 --- a/FEXCore/Source/Interface/Core/Interpreter/ALUOps.cpp +++ b/FEXCore/Source/Interface/Core/Interpreter/ALUOps.cpp @@ -856,6 +856,18 @@ DEF_OP(Bfi) { GD = Res; } +DEF_OP(Bfxil) { + auto Op = IROp->C(); + uint64_t SourceMask = (1ULL << Op->Width) - 1; + if (Op->Width == 64) { + SourceMask = ~0ULL; + } + const uint64_t Src1 = *GetSrc(Data->SSAData, Op->Dest); + const uint64_t Src2 = *GetSrc(Data->SSAData, Op->Src); + const uint64_t Res = (Src1 & ~SourceMask) | ((Src2 >> Op->lsb) & SourceMask); + GD = Res; +} + DEF_OP(Bfe) { auto Op = IROp->C(); diff --git a/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp b/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp index c803ee306..8fb5e1924 100644 --- a/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp +++ b/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp @@ -84,6 +84,7 @@ constexpr OpHandlerArray InterpreterOpHandlers = [] { REGISTER_OP(COUNTLEADINGZEROES, CountLeadingZeroes); REGISTER_OP(REV, Rev); REGISTER_OP(BFI, Bfi); + REGISTER_OP(BFXIL, Bfxil); REGISTER_OP(BFE, Bfe); REGISTER_OP(SBFE, Sbfe); REGISTER_OP(SELECT, Select); diff --git a/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h b/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h index 571339fa9..5d80541cd 100644 --- a/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h +++ b/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h @@ -121,6 +121,7 @@ namespace FEXCore::CPU { DEF_OP(CountLeadingZeroes); DEF_OP(Rev); DEF_OP(Bfi); + DEF_OP(Bfxil); DEF_OP(Bfe); DEF_OP(Sbfe); DEF_OP(Select); diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp index 1469ad803..380a98474 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp @@ -1177,6 +1177,29 @@ DEF_OP(Bfi) { } } +DEF_OP(Bfxil) { + auto Op = IROp->C(); + const uint8_t OpSize = IROp->Size; + + const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; + + const auto Dst = GetReg(Node); + const auto SrcDst = GetReg(Op->Dest.ID()); + const auto Src = GetReg(Op->Src.ID()); + + if (Dst == SrcDst) { + // If Dst and SrcDst match then this turns in to a single instruction. + bfxil(EmitSize, Dst, Src, Op->lsb, Op->Width); + } + else { + // Destination didn't match the dst source register. + // TODO: Inefficient until FEX can have RA constraints here. + mov(EmitSize, TMP1, SrcDst); + bfxil(EmitSize, TMP1, Src, Op->lsb, Op->Width); + mov(EmitSize, Dst, TMP1.R()); + } +} + DEF_OP(Bfe) { auto Op = IROp->C(); LOGMAN_THROW_AA_FMT(IROp->Size <= 8, "OpSize is too large for BFE: {}", IROp->Size); diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index 2ec159fce..39418e836 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -894,6 +894,7 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, REGISTER_OP(COUNTLEADINGZEROES, CountLeadingZeroes); REGISTER_OP(REV, Rev); REGISTER_OP(BFI, Bfi); + REGISTER_OP(BFXIL, Bfxil); REGISTER_OP(BFE, Bfe); REGISTER_OP(SBFE, Sbfe); REGISTER_OP(SELECT, Select); diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h b/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h index 1446ac453..d980df372 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h @@ -272,6 +272,7 @@ private: DEF_OP(CountLeadingZeroes); DEF_OP(Rev); DEF_OP(Bfi); + DEF_OP(Bfxil); DEF_OP(Bfe); DEF_OP(Sbfe); DEF_OP(Select); diff --git a/FEXCore/Source/Interface/Core/JIT/x86_64/ALUOps.cpp b/FEXCore/Source/Interface/Core/JIT/x86_64/ALUOps.cpp index e135ce780..919d604f3 100644 --- a/FEXCore/Source/Interface/Core/JIT/x86_64/ALUOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/x86_64/ALUOps.cpp @@ -1056,6 +1056,34 @@ DEF_OP(Bfi) { } } +DEF_OP(Bfxil) { + auto Op = IROp->C(); + const uint8_t OpSize = IROp->Size; + + auto Dst = GetDst(Node); + + uint64_t SourceMask = (1ULL << Op->Width) - 1; + if (Op->Width == 64) { + SourceMask = ~0ULL; + } + const uint64_t DestMask = ~SourceMask; + + mov(TMP1, GetSrc(Op->Src.ID())); + shr(TMP1, Op->lsb); + mov(Dst, GetSrc(Op->Dest.ID())); + + mov(TMP2, DestMask); + and_(Dst, TMP2); + mov(TMP2, SourceMask); + and_(TMP1, TMP2); + or_(Dst, TMP1); + + if (OpSize != 8) { + mov(rcx, uint64_t((1ULL << (OpSize * 8)) - 1)); + and_(Dst, rcx); + } +} + DEF_OP(Bfe) { auto Op = IROp->C(); LOGMAN_THROW_AA_FMT(IROp->Size <= 8, "OpSize is too large for BFE: {}", IROp->Size); @@ -1375,6 +1403,7 @@ void X86JITCore::RegisterALUHandlers() { REGISTER_OP(COUNTLEADINGZEROES, CountLeadingZeroes); REGISTER_OP(REV, Rev); REGISTER_OP(BFI, Bfi); + REGISTER_OP(BFXIL, Bfxil); REGISTER_OP(BFE, Bfe); REGISTER_OP(SBFE, Sbfe); REGISTER_OP(SELECT, Select); diff --git a/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h b/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h index 9c7bd8d03..b19bb97cf 100644 --- a/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h +++ b/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h @@ -280,6 +280,7 @@ private: DEF_OP(CountLeadingZeroes); DEF_OP(Rev); DEF_OP(Bfi); + DEF_OP(Bfxil); DEF_OP(Bfe); DEF_OP(Sbfe); DEF_OP(Select); diff --git a/FEXCore/Source/Interface/IR/IR.json b/FEXCore/Source/Interface/IR/IR.json index 71a991989..3d3e41cf0 100644 --- a/FEXCore/Source/Interface/IR/IR.json +++ b/FEXCore/Source/Interface/IR/IR.json @@ -1073,6 +1073,17 @@ "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" ] }, + "GPR = Bfxil OpSize:#Size, u8:$Width, u8:$lsb, GPR:$Dest, GPR:$Src": { + "Desc": ["Copies a bitfield from one GPR to another", + "Inserting in to the low bits of the destination", + "The source bitfield is from Src[(Width + lsb):lsb]", + "The bitfield is copied in to Dest[Width:0]" + ], + "DestSize": "Size", + "EmitValidation": [ + "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" + ] + }, "GPR = Bfe OpSize:#Size, u8:$Width, u8:$lsb, GPR:$Src": { "Desc": ["Extracts a bitfield from one GPR with zext", "The source bitfield is from Src[Width:0]",