diff --git a/FEXCore/Source/Interface/Core/JIT/VectorOps.cpp b/FEXCore/Source/Interface/Core/JIT/VectorOps.cpp index 07e3df97d..c491e3445 100644 --- a/FEXCore/Source/Interface/Core/JIT/VectorOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/VectorOps.cpp @@ -4655,6 +4655,31 @@ DEF_OP(VBlendImm) { } } +DEF_OP(VXar) { + LOGMAN_THROW_A_FMT(HostSupportsSVE128 || HostSupportsSVE256, "Host must support SVE to use {}", __func__); + + auto Op = IROp->C(); + const auto SubRegSize = ConvertSubRegSize8(IROp); + const auto ElementSizeBits = IR::OpSizeAsBits(IROp->ElementSize); + + const auto Dst = GetVReg(Node); + const auto LHS = GetVReg(Op->LHS); + const auto RHS = GetVReg(Op->RHS); + const auto Rotate = Op->Rotate; + LOGMAN_THROW_A_FMT(Rotate >= 1 && Rotate <= ElementSizeBits, "Rotate immediate must be within [1, {}]", ElementSizeBits); + + if (Dst == LHS) { + xar(SubRegSize, Dst.Z(), RHS.Z(), Rotate); + } else if (Dst == RHS) { + movprfx(VTMP1.Z(), LHS.Z()); + xar(SubRegSize, VTMP1.Z(), RHS.Z(), Rotate); + mov(Dst.Z(), VTMP1.Z()); + } else { + movprfx(Dst.Z(), LHS.Z()); + xar(SubRegSize, Dst.Z(), RHS.Z(), Rotate); + } +} + DEF_OP(VFCopySign) { auto Op = IROp->C(); const auto OpSize = IROp->Size; diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Crypto.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Crypto.cpp index 57e7ea64b..780534702 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Crypto.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Crypto.cpp @@ -26,15 +26,23 @@ void OpDispatchBuilder::SHA1NEXTEOp(OpcodeArgs) { Ref Dest = LoadSourceFPR(Op, Op->Dest, Op->Flags); Ref Src = LoadSourceFPR(Op, Op->Src[0], Op->Flags); - // ARMv8 SHA1 extension provides a `SHA1H` instruction which does a fixed rotate by 30. - // This only operates on element 0 rather than element 3. We don't have the luxury of rewriting the x86 SHA algorithm to take advantage of this. - // Move the element to zero, rotate, and then move back (Using duplicates). - // Saves one instruction versus that path that doesn't support SHA extension. - auto Duplicated = _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Dest, 3); - auto Sha1HRotated = _VSha1H(Duplicated); - auto RotatedNode = _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Sha1HRotated, 0); - auto Tmp = _VAdd(OpSize::i128Bit, OpSize::i32Bit, Src, RotatedNode); - auto Result = _VInsElement(OpSize::i128Bit, OpSize::i32Bit, 3, 3, Src, Tmp); + Ref Result {}; + if (CTX->HostFeatures.SupportsSVE128) { + auto ZeroVec = LoadZeroVector(OpSize::i128Bit); + auto Tmp = _VInsElement(OpSize::i128Bit, OpSize::i32Bit, 3, 3, ZeroVec, Dest); + auto Xar = _VXar(OpSize::i128Bit, OpSize::i32Bit, ZeroVec, Tmp, 2); + Result = _VAdd(OpSize::i128Bit, OpSize::i32Bit, Src, Xar); + } else { + // ARMv8 SHA1 extension provides a `SHA1H` instruction which does a fixed rotate by 30. + // This only operates on element 0 rather than element 3. We don't have the luxury of rewriting the x86 SHA algorithm to take advantage of this. + // Move the element to zero, rotate, and then move back (Using duplicates). + // Saves one instruction versus that path that doesn't support SHA extension. + auto Duplicated = _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Dest, 3); + auto Sha1HRotated = _VSha1H(Duplicated); + auto RotatedNode = _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Sha1HRotated, 0); + auto Tmp = _VAdd(OpSize::i128Bit, OpSize::i32Bit, Src, RotatedNode); + Result = _VInsElement(OpSize::i128Bit, OpSize::i32Bit, 3, 3, Src, Tmp); + } StoreResult_WithAVXInsert(VectorOpType::SSE, RegClass::FPR, Op, Result); } diff --git a/FEXCore/Source/Interface/IR/IR.json b/FEXCore/Source/Interface/IR/IR.json index 14b6df9d5..20a955a0c 100644 --- a/FEXCore/Source/Interface/IR/IR.json +++ b/FEXCore/Source/Interface/IR/IR.json @@ -2184,6 +2184,18 @@ ] }, + "FPR = VXar OpSize:#RegisterSize, OpSize:#ElementSize, FPR:$LHS, FPR:$RHS, u8:$Rotate": { + "Desc": [ + "Performs an XOR of corresponding elements and then rotates them right by", + "an amount between [1, ElementSize]" + ], + "DestSize": "RegisterSize", + "ElementSize": "ElementSize", + "EmitValidation": [ + "RegisterSize == IR::OpSize::i256Bit || RegisterSize == IR::OpSize::i128Bit" + ] + }, + "FPR = VUQAdd OpSize:#RegisterSize, OpSize:#ElementSize, FPR:$Vector1, FPR:$Vector2": { "DestSize": "RegisterSize", "ElementSize": "ElementSize" diff --git a/unittests/InstructionCountCI/Crypto/H0F38_SVE128.json b/unittests/InstructionCountCI/Crypto/H0F38_SVE128.json new file mode 100644 index 000000000..200ca8b75 --- /dev/null +++ b/unittests/InstructionCountCI/Crypto/H0F38_SVE128.json @@ -0,0 +1,28 @@ +{ + "Features": { + "Bitness": 64, + "EnabledHostFeatures": [ + "CRYPTO", + "SVE128" + ], + "DisabledHostFeatures": [ + "SVE256", + "AFP" + ] + }, + "Instructions": { + "sha1nexte xmm0, xmm1": { + "ExpectedInstructionCount": 5, + "Comment": [ + "0x66 0x0f 0x38 0xc8" + ], + "ExpectedArm64ASM": [ + "movi v2.2d, #0x0", + "mov v3.16b, v2.16b", + "mov v3.s[3], v16.s[3]", + "xar z2.s, z2.s, z3.s, #2", + "add v16.4s, v17.4s, v2.4s" + ] + } + } +}