From f0a4bf1f6a63ee5b070cbbb5decf759abcb79c6f Mon Sep 17 00:00:00 2001 From: merry Date: Sun, 20 Mar 2022 00:15:39 +0000 Subject: [PATCH] IR: Implement SHA256Hash --- src/dynarmic/CMakeLists.txt | 1 + src/dynarmic/backend/x64/emit_x64_sha.cpp | 51 +++++++++++++++ .../frontend/A64/translate/impl/simd_sha.cpp | 65 +------------------ src/dynarmic/ir/ir_emitter.cpp | 4 ++ src/dynarmic/ir/ir_emitter.h | 2 + src/dynarmic/ir/opcodes.inc | 3 + 6 files changed, 63 insertions(+), 63 deletions(-) create mode 100644 src/dynarmic/backend/x64/emit_x64_sha.cpp diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index 126b9dba..53a16f83 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -286,6 +286,7 @@ if (ARCHITECTURE STREQUAL "x86_64") backend/x64/emit_x64_packed.cpp backend/x64/emit_x64_saturation.cpp backend/x64/emit_x64_sm4.cpp + backend/x64/emit_x64_sha.cpp backend/x64/emit_x64_vector.cpp backend/x64/emit_x64_vector_floating_point.cpp backend/x64/emit_x64_vector_saturation.cpp diff --git a/src/dynarmic/backend/x64/emit_x64_sha.cpp b/src/dynarmic/backend/x64/emit_x64_sha.cpp new file mode 100644 index 00000000..2f1b5dd0 --- /dev/null +++ b/src/dynarmic/backend/x64/emit_x64_sha.cpp @@ -0,0 +1,51 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2022 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include "dynarmic/backend/x64/block_of_code.h" +#include "dynarmic/backend/x64/emit_x64.h" + +namespace Dynarmic::Backend::X64 { + +using namespace Xbyak::util; + +void EmitX64::EmitSHA256Hash(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + const bool part1 = args[3].GetImmediateU1(); + + ASSERT(code.HasHostFeature(HostFeature::SHA)); + + // 3 2 1 0 + // x = d c b a + // y = h g f e + // w = wk3 wk2 wk1 wk0 + + const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(args[0]); + const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(args[1]); + const Xbyak::Xmm w = ctx.reg_alloc.UseXmm(args[2]); + + // x64 expects: + // 3 2 1 0 + // src1 = c d g h + // src2 = a b e f + // xmm0 = - - wk1 wk0 + + code.movaps(xmm0, y); + code.shufps(xmm0, x, 0b10111011); // src1 + code.shufps(y, x, 0b00010001); // src2 + code.movaps(x, xmm0); + + code.movaps(xmm0, w); + code.sha256rnds2(x, y); + + code.punpckhqdq(xmm0, xmm0); + code.sha256rnds2(y, x); + + code.shufps(y, x, part1 ? 0b10111011 : 0b00010001); + + ctx.reg_alloc.DefineValue(inst, y); +} + +} // namespace Dynarmic::Backend::X64 diff --git a/src/dynarmic/frontend/A64/translate/impl/simd_sha.cpp b/src/dynarmic/frontend/A64/translate/impl/simd_sha.cpp index 8f0b68cf..69e0dc24 100644 --- a/src/dynarmic/frontend/A64/translate/impl/simd_sha.cpp +++ b/src/dynarmic/frontend/A64/translate/impl/simd_sha.cpp @@ -46,67 +46,6 @@ IR::U128 SHA1HashUpdate(IREmitter& ir, Vec Vm, Vec Vn, Vec Vd, SHA1HashUpdateFun return x; } - -IR::U32 SHAhashSIGMA0(IREmitter& ir, IR::U32 x) { - const IR::U32 tmp1 = ir.RotateRight(x, ir.Imm8(2)); - const IR::U32 tmp2 = ir.RotateRight(x, ir.Imm8(13)); - const IR::U32 tmp3 = ir.RotateRight(x, ir.Imm8(22)); - - return ir.Eor(tmp1, ir.Eor(tmp2, tmp3)); -} - -IR::U32 SHAhashSIGMA1(IREmitter& ir, IR::U32 x) { - const IR::U32 tmp1 = ir.RotateRight(x, ir.Imm8(6)); - const IR::U32 tmp2 = ir.RotateRight(x, ir.Imm8(11)); - const IR::U32 tmp3 = ir.RotateRight(x, ir.Imm8(25)); - - return ir.Eor(tmp1, ir.Eor(tmp2, tmp3)); -} - -enum class SHA256HashPart { - Part1, - Part2 -}; - -IR::U128 SHA256hash(IREmitter& ir, IR::U128 x, IR::U128 y, IR::U128 w, SHA256HashPart part) { - for (size_t i = 0; i < 4; i++) { - const IR::U32 low_x = ir.VectorGetElement(32, x, 0); - const IR::U32 after_low_x = ir.VectorGetElement(32, x, 1); - const IR::U32 before_high_x = ir.VectorGetElement(32, x, 2); - const IR::U32 high_x = ir.VectorGetElement(32, x, 3); - - const IR::U32 low_y = ir.VectorGetElement(32, y, 0); - const IR::U32 after_low_y = ir.VectorGetElement(32, y, 1); - const IR::U32 before_high_y = ir.VectorGetElement(32, y, 2); - const IR::U32 high_y = ir.VectorGetElement(32, y, 3); - - const IR::U32 choice = SHAchoose(ir, low_y, after_low_y, before_high_y); - const IR::U32 majority = SHAmajority(ir, low_x, after_low_x, before_high_x); - - const IR::U32 t = [&] { - const IR::U32 w_element = ir.VectorGetElement(32, w, i); - const IR::U32 sig = SHAhashSIGMA1(ir, low_y); - - return ir.Add(high_y, ir.Add(sig, ir.Add(choice, w_element))); - }(); - - const IR::U32 new_low_x = ir.Add(t, ir.Add(SHAhashSIGMA0(ir, low_x), majority)); - const IR::U32 new_low_y = ir.Add(t, high_x); - - // Shuffle all words left by 1 element: [3, 2, 1, 0] -> [2, 1, 0, 3] - const IR::U128 shuffled_x = ir.VectorShuffleWords(x, 0b10010011); - const IR::U128 shuffled_y = ir.VectorShuffleWords(y, 0b10010011); - - x = ir.VectorSetElement(32, shuffled_x, 0, new_low_x); - y = ir.VectorSetElement(32, shuffled_y, 0, new_low_y); - } - - if (part == SHA256HashPart::Part1) { - return x; - } - - return y; -} } // Anonymous namespace bool TranslatorVisitor::SHA1C(Vec Vm, Vec Vn, Vec Vd) { @@ -247,13 +186,13 @@ bool TranslatorVisitor::SHA256SU1(Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::SHA256H(Vec Vm, Vec Vn, Vec Vd) { - const IR::U128 result = SHA256hash(ir, ir.GetQ(Vd), ir.GetQ(Vn), ir.GetQ(Vm), SHA256HashPart::Part1); + const IR::U128 result = ir.SHA256Hash(ir.GetQ(Vd), ir.GetQ(Vn), ir.GetQ(Vm), true); ir.SetQ(Vd, result); return true; } bool TranslatorVisitor::SHA256H2(Vec Vm, Vec Vn, Vec Vd) { - const IR::U128 result = SHA256hash(ir, ir.GetQ(Vn), ir.GetQ(Vd), ir.GetQ(Vm), SHA256HashPart::Part2); + const IR::U128 result = ir.SHA256Hash(ir.GetQ(Vn), ir.GetQ(Vd), ir.GetQ(Vm), false); ir.SetQ(Vd, result); return true; } diff --git a/src/dynarmic/ir/ir_emitter.cpp b/src/dynarmic/ir/ir_emitter.cpp index 7156c247..dbe49bf7 100644 --- a/src/dynarmic/ir/ir_emitter.cpp +++ b/src/dynarmic/ir/ir_emitter.cpp @@ -903,6 +903,10 @@ U8 IREmitter::SM4AccessSubstitutionBox(const U8& a) { return Inst(Opcode::SM4AccessSubstitutionBox, a); } +U128 IREmitter::SHA256Hash(const U128& x, const U128& y, const U128& w, bool part1) { + return Inst(Opcode::SHA256Hash, x, y, w, Imm1(part1)); +} + UAny IREmitter::VectorGetElement(size_t esize, const U128& a, size_t index) { ASSERT_MSG(esize * index < 128, "Invalid index"); switch (esize) { diff --git a/src/dynarmic/ir/ir_emitter.h b/src/dynarmic/ir/ir_emitter.h index 7336af58..db82ba38 100644 --- a/src/dynarmic/ir/ir_emitter.h +++ b/src/dynarmic/ir/ir_emitter.h @@ -236,6 +236,8 @@ public: U8 SM4AccessSubstitutionBox(const U8& a); + U128 SHA256Hash(const U128& x, const U128& y, const U128& w, bool part1); + UAny VectorGetElement(size_t esize, const U128& a, size_t index); U128 VectorSetElement(size_t esize, const U128& a, size_t index, const UAny& elem); U128 VectorAbs(size_t esize, const U128& a); diff --git a/src/dynarmic/ir/opcodes.inc b/src/dynarmic/ir/opcodes.inc index 0c27dbe6..f72f22ac 100644 --- a/src/dynarmic/ir/opcodes.inc +++ b/src/dynarmic/ir/opcodes.inc @@ -272,6 +272,9 @@ OPCODE(AESMixColumns, U128, U128 // SM4 instructions OPCODE(SM4AccessSubstitutionBox, U8, U8 ) +// SHA instructions +OPCODE(SHA256Hash, U128, U128, U128, U128, U1 ) + // Vector instructions OPCODE(VectorGetElement8, U8, U128, U8 ) OPCODE(VectorGetElement16, U16, U128, U8 )