mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-22 10:41:08 +00:00
target/arm: Generalize inl_qrdmlah_* helper functions
Unify add/sub helpers and add a parameter for rounding. This will allow saturating non-rounding to reuse this code. Backports d21798856b227a20a0a41640236af445f4f4aeb0
This commit is contained in:
parent
1bedcfbda3
commit
80325ac866
|
@ -38,19 +38,24 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Signed saturating rounding doubling multiply-accumulate high half, 16-bit */
|
/* Signed saturating rounding doubling multiply-accumulate high half, 16-bit */
|
||||||
static int16_t inl_qrdmlah_s16(int16_t src1, int16_t src2,
|
static int16_t do_sqrdmlah_h(int16_t src1, int16_t src2, int16_t src3,
|
||||||
int16_t src3, uint32_t *sat)
|
bool neg, bool round, uint32_t *sat)
|
||||||
{
|
{
|
||||||
/* Simplify:
|
/*
|
||||||
|
* Simplify:
|
||||||
* = ((a3 << 16) + ((e1 * e2) << 1) + (1 << 15)) >> 16
|
* = ((a3 << 16) + ((e1 * e2) << 1) + (1 << 15)) >> 16
|
||||||
* = ((a3 << 15) + (e1 * e2) + (1 << 14)) >> 15
|
* = ((a3 << 15) + (e1 * e2) + (1 << 14)) >> 15
|
||||||
*/
|
*/
|
||||||
int32_t ret = (int32_t)src1 * src2;
|
int32_t ret = (int32_t)src1 * src2;
|
||||||
ret = ((int32_t)src3 << 15) + ret + (1 << 14);
|
if (neg) {
|
||||||
|
ret = -ret;
|
||||||
|
}
|
||||||
|
ret += ((int32_t)src3 << 15) + (round << 14);
|
||||||
ret >>= 15;
|
ret >>= 15;
|
||||||
|
|
||||||
if (ret != (int16_t)ret) {
|
if (ret != (int16_t)ret) {
|
||||||
*sat = 1;
|
*sat = 1;
|
||||||
ret = (ret < 0 ? -0x8000 : 0x7fff);
|
ret = (ret < 0 ? INT16_MIN : INT16_MAX);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -59,8 +64,9 @@ uint32_t HELPER(neon_qrdmlah_s16)(CPUARMState *env, uint32_t src1,
|
||||||
uint32_t src2, uint32_t src3)
|
uint32_t src2, uint32_t src3)
|
||||||
{
|
{
|
||||||
uint32_t *sat = &env->vfp.qc[0];
|
uint32_t *sat = &env->vfp.qc[0];
|
||||||
uint16_t e1 = inl_qrdmlah_s16(src1, src2, src3, sat);
|
uint16_t e1 = do_sqrdmlah_h(src1, src2, src3, false, true, sat);
|
||||||
uint16_t e2 = inl_qrdmlah_s16(src1 >> 16, src2 >> 16, src3 >> 16, sat);
|
uint16_t e2 = do_sqrdmlah_h(src1 >> 16, src2 >> 16, src3 >> 16,
|
||||||
|
false, true, sat);
|
||||||
return deposit32(e1, 16, 16, e2);
|
return deposit32(e1, 16, 16, e2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,35 +80,18 @@ void HELPER(gvec_qrdmlah_s16)(void *vd, void *vn, void *vm,
|
||||||
uintptr_t i;
|
uintptr_t i;
|
||||||
|
|
||||||
for (i = 0; i < opr_sz / 2; ++i) {
|
for (i = 0; i < opr_sz / 2; ++i) {
|
||||||
d[i] = inl_qrdmlah_s16(n[i], m[i], d[i], vq);
|
d[i] = do_sqrdmlah_h(n[i], m[i], d[i], false, true, vq);
|
||||||
}
|
}
|
||||||
clear_tail(d, opr_sz, simd_maxsz(desc));
|
clear_tail(d, opr_sz, simd_maxsz(desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Signed saturating rounding doubling multiply-subtract high half, 16-bit */
|
|
||||||
static int16_t inl_qrdmlsh_s16(int16_t src1, int16_t src2,
|
|
||||||
int16_t src3, uint32_t *sat)
|
|
||||||
{
|
|
||||||
/* Similarly, using subtraction:
|
|
||||||
* = ((a3 << 16) - ((e1 * e2) << 1) + (1 << 15)) >> 16
|
|
||||||
* = ((a3 << 15) - (e1 * e2) + (1 << 14)) >> 15
|
|
||||||
*/
|
|
||||||
int32_t ret = (int32_t)src1 * src2;
|
|
||||||
ret = ((int32_t)src3 << 15) - ret + (1 << 14);
|
|
||||||
ret >>= 15;
|
|
||||||
if (ret != (int16_t)ret) {
|
|
||||||
*sat = 1;
|
|
||||||
ret = (ret < 0 ? -0x8000 : 0x7fff);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t HELPER(neon_qrdmlsh_s16)(CPUARMState *env, uint32_t src1,
|
uint32_t HELPER(neon_qrdmlsh_s16)(CPUARMState *env, uint32_t src1,
|
||||||
uint32_t src2, uint32_t src3)
|
uint32_t src2, uint32_t src3)
|
||||||
{
|
{
|
||||||
uint32_t *sat = &env->vfp.qc[0];
|
uint32_t *sat = &env->vfp.qc[0];
|
||||||
uint16_t e1 = inl_qrdmlsh_s16(src1, src2, src3, sat);
|
uint16_t e1 = do_sqrdmlah_h(src1, src2, src3, true, true, sat);
|
||||||
uint16_t e2 = inl_qrdmlsh_s16(src1 >> 16, src2 >> 16, src3 >> 16, sat);
|
uint16_t e2 = do_sqrdmlah_h(src1 >> 16, src2 >> 16, src3 >> 16,
|
||||||
|
true, true, sat);
|
||||||
return deposit32(e1, 16, 16, e2);
|
return deposit32(e1, 16, 16, e2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,19 +105,23 @@ void HELPER(gvec_qrdmlsh_s16)(void *vd, void *vn, void *vm,
|
||||||
uintptr_t i;
|
uintptr_t i;
|
||||||
|
|
||||||
for (i = 0; i < opr_sz / 2; ++i) {
|
for (i = 0; i < opr_sz / 2; ++i) {
|
||||||
d[i] = inl_qrdmlsh_s16(n[i], m[i], d[i], vq);
|
d[i] = do_sqrdmlah_h(n[i], m[i], d[i], true, true, vq);
|
||||||
}
|
}
|
||||||
clear_tail(d, opr_sz, simd_maxsz(desc));
|
clear_tail(d, opr_sz, simd_maxsz(desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Signed saturating rounding doubling multiply-accumulate high half, 32-bit */
|
/* Signed saturating rounding doubling multiply-accumulate high half, 32-bit */
|
||||||
static int32_t inl_qrdmlah_s32(int32_t src1, int32_t src2,
|
static int32_t do_sqrdmlah_s(int32_t src1, int32_t src2, int32_t src3,
|
||||||
int32_t src3, uint32_t *sat)
|
bool neg, bool round, uint32_t *sat)
|
||||||
{
|
{
|
||||||
/* Simplify similarly to int_qrdmlah_s16 above. */
|
/* Simplify similarly to int_qrdmlah_s16 above. */
|
||||||
int64_t ret = (int64_t)src1 * src2;
|
int64_t ret = (int64_t)src1 * src2;
|
||||||
ret = ((int64_t)src3 << 31) + ret + (1 << 30);
|
if (neg) {
|
||||||
|
ret = -ret;
|
||||||
|
}
|
||||||
|
ret += ((int64_t)src3 << 31) + (round << 30);
|
||||||
ret >>= 31;
|
ret >>= 31;
|
||||||
|
|
||||||
if (ret != (int32_t)ret) {
|
if (ret != (int32_t)ret) {
|
||||||
*sat = 1;
|
*sat = 1;
|
||||||
ret = (ret < 0 ? INT32_MIN : INT32_MAX);
|
ret = (ret < 0 ? INT32_MIN : INT32_MAX);
|
||||||
|
@ -140,7 +133,7 @@ uint32_t HELPER(neon_qrdmlah_s32)(CPUARMState *env, int32_t src1,
|
||||||
int32_t src2, int32_t src3)
|
int32_t src2, int32_t src3)
|
||||||
{
|
{
|
||||||
uint32_t *sat = &env->vfp.qc[0];
|
uint32_t *sat = &env->vfp.qc[0];
|
||||||
return inl_qrdmlah_s32(src1, src2, src3, sat);
|
return do_sqrdmlah_s(src1, src2, src3, false, true, sat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(gvec_qrdmlah_s32)(void *vd, void *vn, void *vm,
|
void HELPER(gvec_qrdmlah_s32)(void *vd, void *vn, void *vm,
|
||||||
|
@ -153,31 +146,16 @@ void HELPER(gvec_qrdmlah_s32)(void *vd, void *vn, void *vm,
|
||||||
uintptr_t i;
|
uintptr_t i;
|
||||||
|
|
||||||
for (i = 0; i < opr_sz / 4; ++i) {
|
for (i = 0; i < opr_sz / 4; ++i) {
|
||||||
d[i] = inl_qrdmlah_s32(n[i], m[i], d[i], vq);
|
d[i] = do_sqrdmlah_s(n[i], m[i], d[i], false, true, vq);
|
||||||
}
|
}
|
||||||
clear_tail(d, opr_sz, simd_maxsz(desc));
|
clear_tail(d, opr_sz, simd_maxsz(desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Signed saturating rounding doubling multiply-subtract high half, 32-bit */
|
|
||||||
static int32_t inl_qrdmlsh_s32(int32_t src1, int32_t src2,
|
|
||||||
int32_t src3, uint32_t *sat)
|
|
||||||
{
|
|
||||||
/* Simplify similarly to int_qrdmlsh_s16 above. */
|
|
||||||
int64_t ret = (int64_t)src1 * src2;
|
|
||||||
ret = ((int64_t)src3 << 31) - ret + (1 << 30);
|
|
||||||
ret >>= 31;
|
|
||||||
if (ret != (int32_t)ret) {
|
|
||||||
*sat = 1;
|
|
||||||
ret = (ret < 0 ? INT32_MIN : INT32_MAX);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t HELPER(neon_qrdmlsh_s32)(CPUARMState *env, int32_t src1,
|
uint32_t HELPER(neon_qrdmlsh_s32)(CPUARMState *env, int32_t src1,
|
||||||
int32_t src2, int32_t src3)
|
int32_t src2, int32_t src3)
|
||||||
{
|
{
|
||||||
uint32_t *sat = &env->vfp.qc[0];
|
uint32_t *sat = &env->vfp.qc[0];
|
||||||
return inl_qrdmlsh_s32(src1, src2, src3, sat);
|
return do_sqrdmlah_s(src1, src2, src3, true, true, sat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(gvec_qrdmlsh_s32)(void *vd, void *vn, void *vm,
|
void HELPER(gvec_qrdmlsh_s32)(void *vd, void *vn, void *vm,
|
||||||
|
@ -190,7 +168,7 @@ void HELPER(gvec_qrdmlsh_s32)(void *vd, void *vn, void *vm,
|
||||||
uintptr_t i;
|
uintptr_t i;
|
||||||
|
|
||||||
for (i = 0; i < opr_sz / 4; ++i) {
|
for (i = 0; i < opr_sz / 4; ++i) {
|
||||||
d[i] = inl_qrdmlsh_s32(n[i], m[i], d[i], vq);
|
d[i] = do_sqrdmlah_s(n[i], m[i], d[i], true, true, vq);
|
||||||
}
|
}
|
||||||
clear_tail(d, opr_sz, simd_maxsz(desc));
|
clear_tail(d, opr_sz, simd_maxsz(desc));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue