#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/fpu/fpu_simulator.h>
#include <sys/fpu/globals.h>
static void
unpackint32(
unpacked *pu,
int32_t x)
{
uint_t ux;
pu->sticky = pu->rounded = 0;
if (x == 0) {
pu->sign = 0;
pu->fpclass = fp_zero;
} else {
(*pu).sign = x < 0;
(*pu).fpclass = fp_normal;
(*pu).exponent = INTEGER_BIAS;
if (x < 0) ux = -x; else ux = x;
(*pu).significand[0] = ux>>15;
(*pu).significand[1] = (ux&0x7fff)<<17;
(*pu).significand[2] = 0;
(*pu).significand[3] = 0;
fpu_normalize(pu);
}
}
static void
subroutine(void)
{
}
static void
unpackint64(
unpacked *pu,
int64_t x)
{
union {
uint64_t ll;
uint32_t i[2];
} ux;
subroutine();
pu->sticky = pu->rounded = 0;
if (x == 0) {
pu->sign = 0;
pu->fpclass = fp_zero;
} else {
(*pu).sign = x < 0;
(*pu).fpclass = fp_normal;
(*pu).exponent = LONGLONG_BIAS;
if (x < 0) ux.ll = -x; else ux.ll = x;
(*pu).significand[0] = ux.i[0]>>15;
(*pu).significand[1] = (((ux.i[0]&0x7fff)<<17) | (ux.i[1]>>15));
(*pu).significand[2] = (ux.i[1]&0x7fff)<<17;
(*pu).significand[3] = 0;
fpu_normalize(pu);
}
}
void
unpacksingle(
fp_simd_type *pfpsd,
unpacked *pu,
single_type x)
{
uint_t U;
pu->sticky = pu->rounded = 0;
U = x.significand;
(*pu).sign = x.sign;
pu->significand[1] = 0;
pu->significand[2] = 0;
pu->significand[3] = 0;
if (x.exponent == 0) {
if (x.significand == 0) {
pu->fpclass = fp_zero;
return;
} else {
pu->fpclass = fp_normal;
pu->exponent = -SINGLE_BIAS-6;
pu->significand[0] = U;
fpu_normalize(pu);
return;
}
} else if (x.exponent == 0xff) {
if (x.significand == 0) {
pu->fpclass = fp_infinity;
return;
} else {
if ((U & 0x400000) != 0) {
pu->fpclass = fp_quiet;
} else {
pu->fpclass = fp_signaling;
fpu_set_exception(pfpsd, fp_invalid);
}
pu->significand[0] = 0x18000 | (U >> 7);
(*pu).significand[1] = ((U&0x7f)<<25);
return;
}
}
(*pu).exponent = x.exponent - SINGLE_BIAS;
(*pu).fpclass = fp_normal;
(*pu).significand[0] = 0x10000|(U>>7);
(*pu).significand[1] = ((U&0x7f)<<25);
}
void
unpackdouble(
fp_simd_type *pfpsd,
unpacked *pu,
double_type x,
uint_t y)
{
uint_t U;
pu->sticky = pu->rounded = 0;
U = x.significand;
(*pu).sign = x.sign;
pu->significand[1] = y;
pu->significand[2] = 0;
pu->significand[3] = 0;
if (x.exponent == 0) {
if ((x.significand == 0) && (y == 0)) {
pu->fpclass = fp_zero;
return;
} else {
pu->fpclass = fp_normal;
pu->exponent = -DOUBLE_BIAS-3;
pu->significand[0] = U;
fpu_normalize(pu);
return;
}
} else if (x.exponent == 0x7ff) {
if ((U|y) == 0) {
pu->fpclass = fp_infinity;
return;
} else {
if ((U & 0x80000) != 0) {
pu->fpclass = fp_quiet;
} else {
pu->fpclass = fp_signaling;
fpu_set_exception(pfpsd, fp_invalid);
}
pu->significand[0] = 0x18000 | (U >> 4);
(*pu).significand[1] = ((U&0xf)<<28)|(y>>4);
(*pu).significand[2] = ((y&0xf)<<28);
return;
}
}
(*pu).exponent = x.exponent - DOUBLE_BIAS;
(*pu).fpclass = fp_normal;
(*pu).significand[0] = 0x10000|(U>>4);
(*pu).significand[1] = ((U&0xf)<<28)|(y>>4);
(*pu).significand[2] = ((y&0xf)<<28);
}
static void
unpackextended(
fp_simd_type *pfpsd,
unpacked *pu,
extended_type x,
uint32_t y,
uint32_t z,
uint32_t w)
{
uint_t U;
pu->sticky = pu->rounded = 0;
U = x.significand;
(*pu).sign = x.sign;
(*pu).fpclass = fp_normal;
(*pu).exponent = x.exponent - EXTENDED_BIAS;
(*pu).significand[0] = (x.exponent == 0) ? U : 0x10000|U;
(*pu).significand[1] = y;
(*pu).significand[2] = z;
(*pu).significand[3] = w;
if (x.exponent < 0x7fff) {
if ((z|y|w|pu->significand[0]) == 0) {
pu->fpclass = fp_zero;
return;
} else {
if (x.exponent == 0) {
fpu_normalize(pu);
pu->exponent += 1;
}
return;
}
} else {
if ((U|z|y|w) == 0) {
pu->fpclass = fp_infinity;
return;
} else {
if ((U & 0x00008000) != 0) {
pu->fpclass = fp_quiet;
} else {
pu->fpclass = fp_signaling;
fpu_set_exception(pfpsd, fp_invalid);
}
pu->significand[0] |= 0x8000;
return;
}
}
}
void
_fp_unpack(
fp_simd_type *pfpsd,
unpacked *pu,
uint_t n,
enum fp_op_type dtype)
{
freg_type f;
union {
uint32_t y[4];
uint64_t ll[2];
freg_type f;
} fp;
switch (dtype) {
case fp_op_int32:
pfpsd->fp_current_read_freg(&f, n, pfpsd);
unpackint32(pu, f.int32_reg);
break;
case fp_op_int64:
if ((n & 0x1) == 1)
n = (n & 0x1e) | 0x20;
pfpsd->fp_current_read_dreg(&fp.ll[0], DOUBLE(n), pfpsd);
unpackint64(pu, fp.f.int64_reg);
break;
case fp_op_single:
pfpsd->fp_current_read_freg(&f, n, pfpsd);
unpacksingle(pfpsd, pu, f.single_reg);
break;
case fp_op_double:
if ((n & 0x1) == 1)
n = (n & 0x1e) | 0x20;
pfpsd->fp_current_read_dreg(&fp.ll[0], DOUBLE(n), pfpsd);
unpackdouble(pfpsd, pu, fp.f.double_reg, fp.y[1]);
break;
case fp_op_extended:
if ((n & 0x1) == 1)
n = (n & 0x1e) | 0x20;
pfpsd->fp_current_read_dreg(&fp.ll[0], QUAD_E(n), pfpsd);
pfpsd->fp_current_read_dreg(&fp.ll[1], QUAD_F(n), pfpsd);
unpackextended(pfpsd, pu, fp.f.extended_reg, fp.y[1],
fp.y[2], fp.y[3]);
break;
}
}
void
_fp_unpack_word(
fp_simd_type *pfpsd,
uint32_t *pu,
uint_t n)
{
pfpsd->fp_current_read_freg(pu, n, pfpsd);
}
void
_fp_unpack_extword(
fp_simd_type *pfpsd,
uint64_t *pu,
uint_t n)
{
if ((n & 0x1) == 1)
n = (n & 0x1e) | 0x20;
pfpsd->fp_current_read_dreg(pu, DOUBLE(n), pfpsd);
}