2018-01-25 17:51:45 +00:00
|
|
|
/* This file is part of the dynarmic project.
|
|
|
|
* Copyright (c) 2018 MerryMage
|
2020-04-23 15:25:11 +01:00
|
|
|
* SPDX-License-Identifier: 0BSD
|
2018-01-25 17:51:45 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
#include <climits>
|
|
|
|
|
2018-08-14 19:13:47 +01:00
|
|
|
#include "backend/x64/block_of_code.h"
|
|
|
|
#include "backend/x64/emit_x64.h"
|
2018-07-29 08:48:28 +01:00
|
|
|
#include "common/crypto/crc32.h"
|
2018-01-25 17:51:45 +00:00
|
|
|
#include "frontend/ir/microinstruction.h"
|
|
|
|
|
2020-04-08 11:46:36 +01:00
|
|
|
namespace Dynarmic::Backend::X64 {
|
2018-01-25 17:51:45 +00:00
|
|
|
|
|
|
|
using namespace Xbyak::util;
|
2018-07-29 08:48:28 +01:00
|
|
|
namespace CRC32 = Common::Crypto::CRC32;
|
2018-01-25 17:51:45 +00:00
|
|
|
|
|
|
|
static void EmitCRC32Castagnoli(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, const int data_size) {
|
|
|
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
|
|
|
|
|
|
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tSSE42)) {
|
|
|
|
const Xbyak::Reg32 crc = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
|
|
|
const Xbyak::Reg value = ctx.reg_alloc.UseGpr(args[1]).changeBit(data_size);
|
|
|
|
code.crc32(crc, value);
|
|
|
|
ctx.reg_alloc.DefineValue(inst, crc);
|
2020-06-03 11:16:53 +01:00
|
|
|
return;
|
2018-01-25 17:51:45 +00:00
|
|
|
}
|
2020-06-03 11:16:53 +01:00
|
|
|
|
|
|
|
ctx.reg_alloc.HostCall(inst, args[0], args[1], {});
|
|
|
|
code.mov(code.ABI_PARAM3, data_size / CHAR_BIT);
|
|
|
|
code.CallFunction(&CRC32::ComputeCRC32Castagnoli);
|
2018-01-25 17:51:45 +00:00
|
|
|
}
|
|
|
|
|
2018-01-28 06:41:58 +00:00
|
|
|
static void EmitCRC32ISO(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, const int data_size) {
|
|
|
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
|
|
|
|
2020-06-06 17:07:03 +01:00
|
|
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tPCLMULQDQ) && data_size < 32) {
|
2020-06-03 11:16:53 +01:00
|
|
|
const Xbyak::Reg32 crc = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
2020-06-06 17:07:03 +01:00
|
|
|
const Xbyak::Reg64 value = ctx.reg_alloc.UseScratchGpr(args[1]);
|
2020-06-03 11:16:53 +01:00
|
|
|
const Xbyak::Xmm xmm_value = ctx.reg_alloc.ScratchXmm();
|
|
|
|
const Xbyak::Xmm xmm_const = ctx.reg_alloc.ScratchXmm();
|
2020-06-06 17:07:03 +01:00
|
|
|
const Xbyak::Xmm xmm_tmp = ctx.reg_alloc.ScratchXmm();
|
2020-06-03 11:16:53 +01:00
|
|
|
|
2020-06-06 20:46:09 +01:00
|
|
|
code.movdqa(xmm_const, code.MConst(xword, 0xb4e5b025'f7011641, 0x00000001'DB710641));
|
2020-06-03 11:16:53 +01:00
|
|
|
|
2020-06-06 17:07:03 +01:00
|
|
|
code.movzx(value.cvt32(), value.changeBit(data_size));
|
|
|
|
code.xor_(value.cvt32(), crc);
|
|
|
|
code.movd(xmm_tmp, value.cvt32());
|
|
|
|
code.pslldq(xmm_tmp, (64 - data_size) / 8);
|
|
|
|
|
|
|
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX)) {
|
|
|
|
code.vpclmulqdq(xmm_value, xmm_tmp, xmm_const, 0x00);
|
|
|
|
code.pclmulqdq(xmm_value, xmm_const, 0x10);
|
|
|
|
code.pxor(xmm_value, xmm_tmp);
|
|
|
|
} else {
|
|
|
|
code.movdqa(xmm_value, xmm_tmp);
|
|
|
|
code.pclmulqdq(xmm_value, xmm_const, 0x00);
|
|
|
|
code.pclmulqdq(xmm_value, xmm_const, 0x10);
|
|
|
|
code.pxor(xmm_value, xmm_tmp);
|
2020-06-03 11:16:53 +01:00
|
|
|
}
|
|
|
|
|
2020-06-06 17:07:03 +01:00
|
|
|
code.pextrd(crc, xmm_value, 2);
|
|
|
|
|
|
|
|
ctx.reg_alloc.DefineValue(inst, crc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tPCLMULQDQ) && data_size == 32) {
|
|
|
|
const Xbyak::Reg32 crc = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
|
|
|
const Xbyak::Reg32 value = ctx.reg_alloc.UseGpr(args[1]).cvt32();
|
|
|
|
const Xbyak::Xmm xmm_value = ctx.reg_alloc.ScratchXmm();
|
|
|
|
const Xbyak::Xmm xmm_const = ctx.reg_alloc.ScratchXmm();
|
|
|
|
|
2020-06-06 20:46:09 +01:00
|
|
|
code.movdqa(xmm_const, code.MConst(xword, 0xb4e5b025'f7011641, 0x00000001'DB710641));
|
2020-06-06 17:07:03 +01:00
|
|
|
|
|
|
|
code.xor_(crc, value);
|
|
|
|
code.shl(crc.cvt64(), 32);
|
|
|
|
code.movq(xmm_value, crc.cvt64());
|
|
|
|
|
2020-06-03 11:16:53 +01:00
|
|
|
code.pclmulqdq(xmm_value, xmm_const, 0x00);
|
|
|
|
code.pclmulqdq(xmm_value, xmm_const, 0x10);
|
|
|
|
|
2020-06-03 18:55:58 +01:00
|
|
|
code.pextrd(crc, xmm_value, 2);
|
2020-06-03 11:16:53 +01:00
|
|
|
|
|
|
|
ctx.reg_alloc.DefineValue(inst, crc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tPCLMULQDQ) && data_size == 64) {
|
|
|
|
const Xbyak::Reg32 crc = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
2020-06-06 17:07:03 +01:00
|
|
|
const Xbyak::Reg64 value = ctx.reg_alloc.UseGpr(args[1]);
|
2020-06-03 11:16:53 +01:00
|
|
|
const Xbyak::Xmm xmm_value = ctx.reg_alloc.ScratchXmm();
|
|
|
|
const Xbyak::Xmm xmm_const = ctx.reg_alloc.ScratchXmm();
|
|
|
|
|
2020-06-06 17:07:03 +01:00
|
|
|
code.movdqa(xmm_const, code.MConst(xword, 0xb4e5b025'f7011641, 0x00000001'DB710641));
|
2020-06-03 11:16:53 +01:00
|
|
|
|
2020-06-04 19:06:25 +01:00
|
|
|
code.mov(crc, crc);
|
2020-06-06 17:07:03 +01:00
|
|
|
code.xor_(crc.cvt64(), value);
|
|
|
|
code.movq(xmm_value, crc.cvt64());
|
2020-06-03 11:16:53 +01:00
|
|
|
|
2020-06-06 17:07:03 +01:00
|
|
|
code.pclmulqdq(xmm_value, xmm_const, 0x00);
|
2020-06-03 11:16:53 +01:00
|
|
|
code.pclmulqdq(xmm_value, xmm_const, 0x10);
|
|
|
|
|
2020-06-03 18:55:58 +01:00
|
|
|
code.pextrd(crc, xmm_value, 2);
|
2020-06-03 11:16:53 +01:00
|
|
|
|
|
|
|
ctx.reg_alloc.DefineValue(inst, crc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-29 17:31:50 +00:00
|
|
|
ctx.reg_alloc.HostCall(inst, args[0], args[1], {});
|
|
|
|
code.mov(code.ABI_PARAM3, data_size / CHAR_BIT);
|
2018-07-29 08:48:28 +01:00
|
|
|
code.CallFunction(&CRC32::ComputeCRC32ISO);
|
2018-01-28 06:41:58 +00:00
|
|
|
}
|
|
|
|
|
2018-01-25 17:51:45 +00:00
|
|
|
void EmitX64::EmitCRC32Castagnoli8(EmitContext& ctx, IR::Inst* inst) {
|
2018-02-03 14:28:57 +00:00
|
|
|
EmitCRC32Castagnoli(code, ctx, inst, 8);
|
2018-01-25 17:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitX64::EmitCRC32Castagnoli16(EmitContext& ctx, IR::Inst* inst) {
|
2018-02-03 14:28:57 +00:00
|
|
|
EmitCRC32Castagnoli(code, ctx, inst, 16);
|
2018-01-25 17:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitX64::EmitCRC32Castagnoli32(EmitContext& ctx, IR::Inst* inst) {
|
2018-02-03 14:28:57 +00:00
|
|
|
EmitCRC32Castagnoli(code, ctx, inst, 32);
|
2018-01-25 17:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitX64::EmitCRC32Castagnoli64(EmitContext& ctx, IR::Inst* inst) {
|
2018-02-03 14:28:57 +00:00
|
|
|
EmitCRC32Castagnoli(code, ctx, inst, 64);
|
2018-01-25 17:51:45 +00:00
|
|
|
}
|
|
|
|
|
2018-01-28 06:41:58 +00:00
|
|
|
void EmitX64::EmitCRC32ISO8(EmitContext& ctx, IR::Inst* inst) {
|
2018-02-03 14:28:57 +00:00
|
|
|
EmitCRC32ISO(code, ctx, inst, 8);
|
2018-01-28 06:41:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitX64::EmitCRC32ISO16(EmitContext& ctx, IR::Inst* inst) {
|
2018-02-03 14:28:57 +00:00
|
|
|
EmitCRC32ISO(code, ctx, inst, 16);
|
2018-01-28 06:41:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitX64::EmitCRC32ISO32(EmitContext& ctx, IR::Inst* inst) {
|
2018-02-03 14:28:57 +00:00
|
|
|
EmitCRC32ISO(code, ctx, inst, 32);
|
2018-01-28 06:41:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitX64::EmitCRC32ISO64(EmitContext& ctx, IR::Inst* inst) {
|
2018-02-03 14:28:57 +00:00
|
|
|
EmitCRC32ISO(code, ctx, inst, 64);
|
2018-01-28 06:41:58 +00:00
|
|
|
}
|
|
|
|
|
2020-04-08 11:46:36 +01:00
|
|
|
} // namespace Dynarmic::Backend::X64
|