af868995e1
Loongson-3 CPU family include Loongson-3A R1/R2/R3/R4 and Loongson-3B R1/R2. Loongson-3A R1 is the oldest and its ISA is the smallest, while Loongson-3A R4 is the newest and its ISA is almost the superset of all others. To reduce complexity, we just define two CPU types: 1) "Loongson-3A1000" CPU which is corresponding to Loongson-3A R1. It is suitable for TCG because Loongson-3A R1 has fewest ASE. 2) "Loongson-3A4000" CPU which is corresponding to Loongson-3A R4. It is suitable for KVM because Loongson-3A R4 has the VZ ASE. Loongson-3A has CONFIG6 and CONFIG7, so add their bit-fields as well. [AM: Rearranged insn_flags, added comments, renamed lmi_helper.c, improved commit message, fixed checkpatch warnings] Signed-off-by: Huacai Chen <chenhc@lemote.com> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> Signed-off-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> Message-Id: <1591065557-9174-3-git-send-email-chenhc@lemote.com>
748 lines
14 KiB
C
748 lines
14 KiB
C
/*
|
|
* Loongson Multimedia Instruction emulation helpers for QEMU.
|
|
*
|
|
* Copyright (c) 2011 Richard Henderson <rth@twiddle.net>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "cpu.h"
|
|
#include "exec/helper-proto.h"
|
|
|
|
/*
|
|
* If the byte ordering doesn't matter, i.e. all columns are treated
|
|
* identically, then this union can be used directly. If byte ordering
|
|
* does matter, we generally ignore dumping to memory.
|
|
*/
|
|
typedef union {
|
|
uint8_t ub[8];
|
|
int8_t sb[8];
|
|
uint16_t uh[4];
|
|
int16_t sh[4];
|
|
uint32_t uw[2];
|
|
int32_t sw[2];
|
|
uint64_t d;
|
|
} LMIValue;
|
|
|
|
/* Some byte ordering issues can be mitigated by XORing in the following. */
|
|
#ifdef HOST_WORDS_BIGENDIAN
|
|
# define BYTE_ORDER_XOR(N) N
|
|
#else
|
|
# define BYTE_ORDER_XOR(N) 0
|
|
#endif
|
|
|
|
#define SATSB(x) (x < -0x80 ? -0x80 : x > 0x7f ? 0x7f : x)
|
|
#define SATUB(x) (x > 0xff ? 0xff : x)
|
|
|
|
#define SATSH(x) (x < -0x8000 ? -0x8000 : x > 0x7fff ? 0x7fff : x)
|
|
#define SATUH(x) (x > 0xffff ? 0xffff : x)
|
|
|
|
#define SATSW(x) \
|
|
(x < -0x80000000ll ? -0x80000000ll : x > 0x7fffffff ? 0x7fffffff : x)
|
|
#define SATUW(x) (x > 0xffffffffull ? 0xffffffffull : x)
|
|
|
|
uint64_t helper_paddsb(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; ++i) {
|
|
int r = vs.sb[i] + vt.sb[i];
|
|
vs.sb[i] = SATSB(r);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_paddusb(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; ++i) {
|
|
int r = vs.ub[i] + vt.ub[i];
|
|
vs.ub[i] = SATUB(r);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_paddsh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; ++i) {
|
|
int r = vs.sh[i] + vt.sh[i];
|
|
vs.sh[i] = SATSH(r);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_paddush(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; ++i) {
|
|
int r = vs.uh[i] + vt.uh[i];
|
|
vs.uh[i] = SATUH(r);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_paddb(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; ++i) {
|
|
vs.ub[i] += vt.ub[i];
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_paddh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; ++i) {
|
|
vs.uh[i] += vt.uh[i];
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_paddw(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 2; ++i) {
|
|
vs.uw[i] += vt.uw[i];
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psubsb(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; ++i) {
|
|
int r = vs.sb[i] - vt.sb[i];
|
|
vs.sb[i] = SATSB(r);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psubusb(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; ++i) {
|
|
int r = vs.ub[i] - vt.ub[i];
|
|
vs.ub[i] = SATUB(r);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psubsh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; ++i) {
|
|
int r = vs.sh[i] - vt.sh[i];
|
|
vs.sh[i] = SATSH(r);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psubush(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; ++i) {
|
|
int r = vs.uh[i] - vt.uh[i];
|
|
vs.uh[i] = SATUH(r);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psubb(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; ++i) {
|
|
vs.ub[i] -= vt.ub[i];
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psubh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; ++i) {
|
|
vs.uh[i] -= vt.uh[i];
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psubw(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned int i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 2; ++i) {
|
|
vs.uw[i] -= vt.uw[i];
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pshufh(uint64_t fs, uint64_t ft)
|
|
{
|
|
unsigned host = BYTE_ORDER_XOR(3);
|
|
LMIValue vd, vs;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vd.d = 0;
|
|
for (i = 0; i < 4; i++, ft >>= 2) {
|
|
vd.uh[i ^ host] = vs.uh[(ft & 3) ^ host];
|
|
}
|
|
return vd.d;
|
|
}
|
|
|
|
uint64_t helper_packsswh(uint64_t fs, uint64_t ft)
|
|
{
|
|
uint64_t fd = 0;
|
|
int64_t tmp;
|
|
|
|
tmp = (int32_t)(fs >> 0);
|
|
tmp = SATSH(tmp);
|
|
fd |= (tmp & 0xffff) << 0;
|
|
|
|
tmp = (int32_t)(fs >> 32);
|
|
tmp = SATSH(tmp);
|
|
fd |= (tmp & 0xffff) << 16;
|
|
|
|
tmp = (int32_t)(ft >> 0);
|
|
tmp = SATSH(tmp);
|
|
fd |= (tmp & 0xffff) << 32;
|
|
|
|
tmp = (int32_t)(ft >> 32);
|
|
tmp = SATSH(tmp);
|
|
fd |= (tmp & 0xffff) << 48;
|
|
|
|
return fd;
|
|
}
|
|
|
|
uint64_t helper_packsshb(uint64_t fs, uint64_t ft)
|
|
{
|
|
uint64_t fd = 0;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
int16_t tmp = fs >> (i * 16);
|
|
tmp = SATSB(tmp);
|
|
fd |= (uint64_t)(tmp & 0xff) << (i * 8);
|
|
}
|
|
for (i = 0; i < 4; ++i) {
|
|
int16_t tmp = ft >> (i * 16);
|
|
tmp = SATSB(tmp);
|
|
fd |= (uint64_t)(tmp & 0xff) << (i * 8 + 32);
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
uint64_t helper_packushb(uint64_t fs, uint64_t ft)
|
|
{
|
|
uint64_t fd = 0;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
int16_t tmp = fs >> (i * 16);
|
|
tmp = SATUB(tmp);
|
|
fd |= (uint64_t)(tmp & 0xff) << (i * 8);
|
|
}
|
|
for (i = 0; i < 4; ++i) {
|
|
int16_t tmp = ft >> (i * 16);
|
|
tmp = SATUB(tmp);
|
|
fd |= (uint64_t)(tmp & 0xff) << (i * 8 + 32);
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
uint64_t helper_punpcklwd(uint64_t fs, uint64_t ft)
|
|
{
|
|
return (fs & 0xffffffff) | (ft << 32);
|
|
}
|
|
|
|
uint64_t helper_punpckhwd(uint64_t fs, uint64_t ft)
|
|
{
|
|
return (fs >> 32) | (ft & ~0xffffffffull);
|
|
}
|
|
|
|
uint64_t helper_punpcklhw(uint64_t fs, uint64_t ft)
|
|
{
|
|
unsigned host = BYTE_ORDER_XOR(3);
|
|
LMIValue vd, vs, vt;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
vd.uh[0 ^ host] = vs.uh[0 ^ host];
|
|
vd.uh[1 ^ host] = vt.uh[0 ^ host];
|
|
vd.uh[2 ^ host] = vs.uh[1 ^ host];
|
|
vd.uh[3 ^ host] = vt.uh[1 ^ host];
|
|
|
|
return vd.d;
|
|
}
|
|
|
|
uint64_t helper_punpckhhw(uint64_t fs, uint64_t ft)
|
|
{
|
|
unsigned host = BYTE_ORDER_XOR(3);
|
|
LMIValue vd, vs, vt;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
vd.uh[0 ^ host] = vs.uh[2 ^ host];
|
|
vd.uh[1 ^ host] = vt.uh[2 ^ host];
|
|
vd.uh[2 ^ host] = vs.uh[3 ^ host];
|
|
vd.uh[3 ^ host] = vt.uh[3 ^ host];
|
|
|
|
return vd.d;
|
|
}
|
|
|
|
uint64_t helper_punpcklbh(uint64_t fs, uint64_t ft)
|
|
{
|
|
unsigned host = BYTE_ORDER_XOR(7);
|
|
LMIValue vd, vs, vt;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
vd.ub[0 ^ host] = vs.ub[0 ^ host];
|
|
vd.ub[1 ^ host] = vt.ub[0 ^ host];
|
|
vd.ub[2 ^ host] = vs.ub[1 ^ host];
|
|
vd.ub[3 ^ host] = vt.ub[1 ^ host];
|
|
vd.ub[4 ^ host] = vs.ub[2 ^ host];
|
|
vd.ub[5 ^ host] = vt.ub[2 ^ host];
|
|
vd.ub[6 ^ host] = vs.ub[3 ^ host];
|
|
vd.ub[7 ^ host] = vt.ub[3 ^ host];
|
|
|
|
return vd.d;
|
|
}
|
|
|
|
uint64_t helper_punpckhbh(uint64_t fs, uint64_t ft)
|
|
{
|
|
unsigned host = BYTE_ORDER_XOR(7);
|
|
LMIValue vd, vs, vt;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
vd.ub[0 ^ host] = vs.ub[4 ^ host];
|
|
vd.ub[1 ^ host] = vt.ub[4 ^ host];
|
|
vd.ub[2 ^ host] = vs.ub[5 ^ host];
|
|
vd.ub[3 ^ host] = vt.ub[5 ^ host];
|
|
vd.ub[4 ^ host] = vs.ub[6 ^ host];
|
|
vd.ub[5 ^ host] = vt.ub[6 ^ host];
|
|
vd.ub[6 ^ host] = vs.ub[7 ^ host];
|
|
vd.ub[7 ^ host] = vt.ub[7 ^ host];
|
|
|
|
return vd.d;
|
|
}
|
|
|
|
uint64_t helper_pavgh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; i++) {
|
|
vs.uh[i] = (vs.uh[i] + vt.uh[i] + 1) >> 1;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pavgb(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; i++) {
|
|
vs.ub[i] = (vs.ub[i] + vt.ub[i] + 1) >> 1;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pmaxsh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; i++) {
|
|
vs.sh[i] = (vs.sh[i] >= vt.sh[i] ? vs.sh[i] : vt.sh[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pminsh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; i++) {
|
|
vs.sh[i] = (vs.sh[i] <= vt.sh[i] ? vs.sh[i] : vt.sh[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pmaxub(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; i++) {
|
|
vs.ub[i] = (vs.ub[i] >= vt.ub[i] ? vs.ub[i] : vt.ub[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pminub(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; i++) {
|
|
vs.ub[i] = (vs.ub[i] <= vt.ub[i] ? vs.ub[i] : vt.ub[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pcmpeqw(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 2; i++) {
|
|
vs.uw[i] = -(vs.uw[i] == vt.uw[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pcmpgtw(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 2; i++) {
|
|
vs.uw[i] = -(vs.uw[i] > vt.uw[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pcmpeqh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; i++) {
|
|
vs.uh[i] = -(vs.uh[i] == vt.uh[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pcmpgth(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; i++) {
|
|
vs.uh[i] = -(vs.uh[i] > vt.uh[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pcmpeqb(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; i++) {
|
|
vs.ub[i] = -(vs.ub[i] == vt.ub[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pcmpgtb(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; i++) {
|
|
vs.ub[i] = -(vs.ub[i] > vt.ub[i]);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psllw(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs;
|
|
unsigned i;
|
|
|
|
ft &= 0x7f;
|
|
if (ft > 31) {
|
|
return 0;
|
|
}
|
|
vs.d = fs;
|
|
for (i = 0; i < 2; ++i) {
|
|
vs.uw[i] <<= ft;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psrlw(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs;
|
|
unsigned i;
|
|
|
|
ft &= 0x7f;
|
|
if (ft > 31) {
|
|
return 0;
|
|
}
|
|
vs.d = fs;
|
|
for (i = 0; i < 2; ++i) {
|
|
vs.uw[i] >>= ft;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psraw(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs;
|
|
unsigned i;
|
|
|
|
ft &= 0x7f;
|
|
if (ft > 31) {
|
|
ft = 31;
|
|
}
|
|
vs.d = fs;
|
|
for (i = 0; i < 2; ++i) {
|
|
vs.sw[i] >>= ft;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psllh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs;
|
|
unsigned i;
|
|
|
|
ft &= 0x7f;
|
|
if (ft > 15) {
|
|
return 0;
|
|
}
|
|
vs.d = fs;
|
|
for (i = 0; i < 4; ++i) {
|
|
vs.uh[i] <<= ft;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psrlh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs;
|
|
unsigned i;
|
|
|
|
ft &= 0x7f;
|
|
if (ft > 15) {
|
|
return 0;
|
|
}
|
|
vs.d = fs;
|
|
for (i = 0; i < 4; ++i) {
|
|
vs.uh[i] >>= ft;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_psrah(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs;
|
|
unsigned i;
|
|
|
|
ft &= 0x7f;
|
|
if (ft > 15) {
|
|
ft = 15;
|
|
}
|
|
vs.d = fs;
|
|
for (i = 0; i < 4; ++i) {
|
|
vs.sh[i] >>= ft;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pmullh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; ++i) {
|
|
vs.sh[i] *= vt.sh[i];
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pmulhh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; ++i) {
|
|
int32_t r = vs.sh[i] * vt.sh[i];
|
|
vs.sh[i] = r >> 16;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pmulhuh(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 4; ++i) {
|
|
uint32_t r = vs.uh[i] * vt.uh[i];
|
|
vs.uh[i] = r >> 16;
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_pmaddhw(uint64_t fs, uint64_t ft)
|
|
{
|
|
unsigned host = BYTE_ORDER_XOR(3);
|
|
LMIValue vs, vt;
|
|
uint32_t p0, p1;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
p0 = vs.sh[0 ^ host] * vt.sh[0 ^ host];
|
|
p0 += vs.sh[1 ^ host] * vt.sh[1 ^ host];
|
|
p1 = vs.sh[2 ^ host] * vt.sh[2 ^ host];
|
|
p1 += vs.sh[3 ^ host] * vt.sh[3 ^ host];
|
|
|
|
return ((uint64_t)p1 << 32) | p0;
|
|
}
|
|
|
|
uint64_t helper_pasubub(uint64_t fs, uint64_t ft)
|
|
{
|
|
LMIValue vs, vt;
|
|
unsigned i;
|
|
|
|
vs.d = fs;
|
|
vt.d = ft;
|
|
for (i = 0; i < 8; ++i) {
|
|
int r = vs.ub[i] - vt.ub[i];
|
|
vs.ub[i] = (r < 0 ? -r : r);
|
|
}
|
|
return vs.d;
|
|
}
|
|
|
|
uint64_t helper_biadd(uint64_t fs)
|
|
{
|
|
unsigned i, fd;
|
|
|
|
for (i = fd = 0; i < 8; ++i) {
|
|
fd += (fs >> (i * 8)) & 0xff;
|
|
}
|
|
return fd & 0xffff;
|
|
}
|
|
|
|
uint64_t helper_pmovmskb(uint64_t fs)
|
|
{
|
|
unsigned fd = 0;
|
|
|
|
fd |= ((fs >> 7) & 1) << 0;
|
|
fd |= ((fs >> 15) & 1) << 1;
|
|
fd |= ((fs >> 23) & 1) << 2;
|
|
fd |= ((fs >> 31) & 1) << 3;
|
|
fd |= ((fs >> 39) & 1) << 4;
|
|
fd |= ((fs >> 47) & 1) << 5;
|
|
fd |= ((fs >> 55) & 1) << 6;
|
|
fd |= ((fs >> 63) & 1) << 7;
|
|
|
|
return fd & 0xff;
|
|
}
|