softfloat: Introduce sh[lr]_double primitives
Have x86_64 assembly for them, with a fallback. This avoids shuffling values through %cl in the x86 case. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
5ffb6bd9c4
commit
463e45dcb4
102
fpu/softfloat.c
102
fpu/softfloat.c
|
@ -957,15 +957,12 @@ static int frac128_normalize(FloatParts128 *a)
|
||||||
{
|
{
|
||||||
if (a->frac_hi) {
|
if (a->frac_hi) {
|
||||||
int shl = clz64(a->frac_hi);
|
int shl = clz64(a->frac_hi);
|
||||||
if (shl) {
|
a->frac_hi = shl_double(a->frac_hi, a->frac_lo, shl);
|
||||||
int shr = 64 - shl;
|
a->frac_lo <<= shl;
|
||||||
a->frac_hi = (a->frac_hi << shl) | (a->frac_lo >> shr);
|
|
||||||
a->frac_lo = (a->frac_lo << shl);
|
|
||||||
}
|
|
||||||
return shl;
|
return shl;
|
||||||
} else if (a->frac_lo) {
|
} else if (a->frac_lo) {
|
||||||
int shl = clz64(a->frac_lo);
|
int shl = clz64(a->frac_lo);
|
||||||
a->frac_hi = (a->frac_lo << shl);
|
a->frac_hi = a->frac_lo << shl;
|
||||||
a->frac_lo = 0;
|
a->frac_lo = 0;
|
||||||
return shl + 64;
|
return shl + 64;
|
||||||
}
|
}
|
||||||
|
@ -976,7 +973,7 @@ static int frac256_normalize(FloatParts256 *a)
|
||||||
{
|
{
|
||||||
uint64_t a0 = a->frac_hi, a1 = a->frac_hm;
|
uint64_t a0 = a->frac_hi, a1 = a->frac_hm;
|
||||||
uint64_t a2 = a->frac_lm, a3 = a->frac_lo;
|
uint64_t a2 = a->frac_lm, a3 = a->frac_lo;
|
||||||
int ret, shl, shr;
|
int ret, shl;
|
||||||
|
|
||||||
if (likely(a0)) {
|
if (likely(a0)) {
|
||||||
shl = clz64(a0);
|
shl = clz64(a0);
|
||||||
|
@ -1006,11 +1003,10 @@ static int frac256_normalize(FloatParts256 *a)
|
||||||
ret += shl;
|
ret += shl;
|
||||||
}
|
}
|
||||||
|
|
||||||
shr = -shl & 63;
|
a0 = shl_double(a0, a1, shl);
|
||||||
a0 = (a0 << shl) | (a1 >> shr);
|
a1 = shl_double(a1, a2, shl);
|
||||||
a1 = (a1 << shl) | (a2 >> shr);
|
a2 = shl_double(a2, a3, shl);
|
||||||
a2 = (a2 << shl) | (a3 >> shr);
|
a3 <<= shl;
|
||||||
a3 = (a3 << shl);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
a->frac_hi = a0;
|
a->frac_hi = a0;
|
||||||
|
@ -1029,7 +1025,20 @@ static void frac64_shl(FloatParts64 *a, int c)
|
||||||
|
|
||||||
static void frac128_shl(FloatParts128 *a, int c)
|
static void frac128_shl(FloatParts128 *a, int c)
|
||||||
{
|
{
|
||||||
shift128Left(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo);
|
uint64_t a0 = a->frac_hi, a1 = a->frac_lo;
|
||||||
|
|
||||||
|
if (c & 64) {
|
||||||
|
a0 = a1, a1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
c &= 63;
|
||||||
|
if (c) {
|
||||||
|
a0 = shl_double(a0, a1, c);
|
||||||
|
a1 = a1 << c;
|
||||||
|
}
|
||||||
|
|
||||||
|
a->frac_hi = a0;
|
||||||
|
a->frac_lo = a1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define frac_shl(A, C) FRAC_GENERIC_64_128(shl, A)(A, C)
|
#define frac_shl(A, C) FRAC_GENERIC_64_128(shl, A)(A, C)
|
||||||
|
@ -1041,19 +1050,68 @@ static void frac64_shr(FloatParts64 *a, int c)
|
||||||
|
|
||||||
static void frac128_shr(FloatParts128 *a, int c)
|
static void frac128_shr(FloatParts128 *a, int c)
|
||||||
{
|
{
|
||||||
shift128Right(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo);
|
uint64_t a0 = a->frac_hi, a1 = a->frac_lo;
|
||||||
|
|
||||||
|
if (c & 64) {
|
||||||
|
a1 = a0, a0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
c &= 63;
|
||||||
|
if (c) {
|
||||||
|
a1 = shr_double(a0, a1, c);
|
||||||
|
a0 = a0 >> c;
|
||||||
|
}
|
||||||
|
|
||||||
|
a->frac_hi = a0;
|
||||||
|
a->frac_lo = a1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define frac_shr(A, C) FRAC_GENERIC_64_128(shr, A)(A, C)
|
#define frac_shr(A, C) FRAC_GENERIC_64_128(shr, A)(A, C)
|
||||||
|
|
||||||
static void frac64_shrjam(FloatParts64 *a, int c)
|
static void frac64_shrjam(FloatParts64 *a, int c)
|
||||||
{
|
{
|
||||||
shift64RightJamming(a->frac, c, &a->frac);
|
uint64_t a0 = a->frac;
|
||||||
|
|
||||||
|
if (likely(c != 0)) {
|
||||||
|
if (likely(c < 64)) {
|
||||||
|
a0 = (a0 >> c) | (shr_double(a0, 0, c) != 0);
|
||||||
|
} else {
|
||||||
|
a0 = a0 != 0;
|
||||||
|
}
|
||||||
|
a->frac = a0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void frac128_shrjam(FloatParts128 *a, int c)
|
static void frac128_shrjam(FloatParts128 *a, int c)
|
||||||
{
|
{
|
||||||
shift128RightJamming(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo);
|
uint64_t a0 = a->frac_hi, a1 = a->frac_lo;
|
||||||
|
uint64_t sticky = 0;
|
||||||
|
|
||||||
|
if (unlikely(c == 0)) {
|
||||||
|
return;
|
||||||
|
} else if (likely(c < 64)) {
|
||||||
|
/* nothing */
|
||||||
|
} else if (likely(c < 128)) {
|
||||||
|
sticky = a1;
|
||||||
|
a1 = a0;
|
||||||
|
a0 = 0;
|
||||||
|
c &= 63;
|
||||||
|
if (c == 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sticky = a0 | a1;
|
||||||
|
a0 = a1 = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
sticky |= shr_double(a1, 0, c);
|
||||||
|
a1 = shr_double(a0, a1, c);
|
||||||
|
a0 = a0 >> c;
|
||||||
|
|
||||||
|
done:
|
||||||
|
a->frac_lo = a1 | (sticky != 0);
|
||||||
|
a->frac_hi = a0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void frac256_shrjam(FloatParts256 *a, int c)
|
static void frac256_shrjam(FloatParts256 *a, int c)
|
||||||
|
@ -1061,7 +1119,6 @@ static void frac256_shrjam(FloatParts256 *a, int c)
|
||||||
uint64_t a0 = a->frac_hi, a1 = a->frac_hm;
|
uint64_t a0 = a->frac_hi, a1 = a->frac_hm;
|
||||||
uint64_t a2 = a->frac_lm, a3 = a->frac_lo;
|
uint64_t a2 = a->frac_lm, a3 = a->frac_lo;
|
||||||
uint64_t sticky = 0;
|
uint64_t sticky = 0;
|
||||||
int invc;
|
|
||||||
|
|
||||||
if (unlikely(c == 0)) {
|
if (unlikely(c == 0)) {
|
||||||
return;
|
return;
|
||||||
|
@ -1086,12 +1143,11 @@ static void frac256_shrjam(FloatParts256 *a, int c)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
invc = -c & 63;
|
sticky |= shr_double(a3, 0, c);
|
||||||
sticky |= a3 << invc;
|
a3 = shr_double(a2, a3, c);
|
||||||
a3 = (a3 >> c) | (a2 << invc);
|
a2 = shr_double(a1, a2, c);
|
||||||
a2 = (a2 >> c) | (a1 << invc);
|
a1 = shr_double(a0, a1, c);
|
||||||
a1 = (a1 >> c) | (a0 << invc);
|
a0 = a0 >> c;
|
||||||
a0 = (a0 >> c);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
a->frac_lo = a3 | (sticky != 0);
|
a->frac_lo = a3 | (sticky != 0);
|
||||||
|
|
|
@ -85,6 +85,42 @@ this code that are retained.
|
||||||
#include "fpu/softfloat-types.h"
|
#include "fpu/softfloat-types.h"
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shl_double: double-word merging left shift
|
||||||
|
* @l: left or most-significant word
|
||||||
|
* @r: right or least-significant word
|
||||||
|
* @c: shift count
|
||||||
|
*
|
||||||
|
* Shift @l left by @c bits, shifting in bits from @r.
|
||||||
|
*/
|
||||||
|
static inline uint64_t shl_double(uint64_t l, uint64_t r, int c)
|
||||||
|
{
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
asm("shld %b2, %1, %0" : "+r"(l) : "r"(r), "ci"(c));
|
||||||
|
return l;
|
||||||
|
#else
|
||||||
|
return c ? (l << c) | (r >> (64 - c)) : l;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shr_double: double-word merging right shift
|
||||||
|
* @l: left or most-significant word
|
||||||
|
* @r: right or least-significant word
|
||||||
|
* @c: shift count
|
||||||
|
*
|
||||||
|
* Shift @r right by @c bits, shifting in bits from @l.
|
||||||
|
*/
|
||||||
|
static inline uint64_t shr_double(uint64_t l, uint64_t r, int c)
|
||||||
|
{
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
asm("shrd %b2, %1, %0" : "+r"(r) : "r"(l), "ci"(c));
|
||||||
|
return r;
|
||||||
|
#else
|
||||||
|
return c ? (r >> c) | (l << (64 - c)) : r;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
| Shifts `a' right by the number of bits given in `count'. If any nonzero
|
| Shifts `a' right by the number of bits given in `count'. If any nonzero
|
||||||
| bits are shifted off, they are ``jammed'' into the least significant bit of
|
| bits are shifted off, they are ``jammed'' into the least significant bit of
|
||||||
|
|
Loading…
Reference in New Issue