mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-04-12 18:40:23 +08:00
Support 16-bit IEEE floating point; used in SSE5
SSE5 supports standard IEEE 16-bit floating point, so we should support that too.
This commit is contained in:
parent
510a2508e6
commit
141d7cf68d
71
float.c
71
float.c
@ -213,6 +213,7 @@ static int ieee_round(uint16_t *mant, int i)
|
||||
|
||||
#define put(a,b) ( (*(a)=(b)), ((a)[1]=(b)>>8) )
|
||||
|
||||
/* 64-bit format with 52-bit mantissa and 11-bit exponent */
|
||||
static int to_double(char *str, int32_t sign, uint8_t *result,
|
||||
efunc error)
|
||||
{
|
||||
@ -275,6 +276,7 @@ static int to_double(char *str, int32_t sign, uint8_t *result,
|
||||
return 1; /* success */
|
||||
}
|
||||
|
||||
/* 32-bit format with 23-bit mantissa and 8-bit exponent */
|
||||
static int to_float(char *str, int32_t sign, uint8_t *result,
|
||||
efunc error)
|
||||
{
|
||||
@ -330,6 +332,64 @@ static int to_float(char *str, int32_t sign, uint8_t *result,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 16-bit format with 10-bit mantissa and 5-bit exponent.
|
||||
Defined in IEEE 754r. Used in SSE5. See the AMD SSE5 manual, AMD
|
||||
document number 43479. */
|
||||
static int to_float16(char *str, int32_t sign, uint8_t *result,
|
||||
efunc error)
|
||||
{
|
||||
uint16_t mant[MANT_WORDS];
|
||||
int32_t exponent;
|
||||
|
||||
sign = (sign < 0 ? 0x8000L : 0L);
|
||||
|
||||
ieee_flconvert(str, mant, &exponent, error);
|
||||
if (mant[0] & 0x8000) {
|
||||
/*
|
||||
* Non-zero.
|
||||
*/
|
||||
exponent--;
|
||||
if (exponent >= -14 && exponent <= 16) {
|
||||
/*
|
||||
* Normalised.
|
||||
*/
|
||||
exponent += 15;
|
||||
ieee_shr(mant, 5);
|
||||
ieee_round(mant, 1);
|
||||
if (mant[0] & 0x800) /* did we scale up by one? */
|
||||
ieee_shr(mant, 1), exponent++;
|
||||
mant[0] &= 0x3FF; /* remove leading one */
|
||||
put(result + 0, (exponent << 7) | mant[0] | sign);
|
||||
} else if (exponent < -14 && exponent >= -24) {
|
||||
/*
|
||||
* Denormal.
|
||||
*/
|
||||
int shift = -(exponent + 8);
|
||||
int sh = shift % 16, wds = shift / 16;
|
||||
ieee_shr(mant, sh);
|
||||
if (ieee_round(mant, 1 - wds)
|
||||
|| (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) {
|
||||
ieee_shr(mant, 1);
|
||||
if (sh == 0)
|
||||
mant[0] |= 0x8000;
|
||||
exponent++;
|
||||
}
|
||||
put(result + 0, (wds == 0 ? mant[0] : 0) | sign);
|
||||
} else {
|
||||
if (exponent > 0) {
|
||||
error(ERR_NONFATAL, "overflow in floating-point constant");
|
||||
return 0;
|
||||
} else
|
||||
memset(result, 0, 2);
|
||||
}
|
||||
} else {
|
||||
memset(result, 0, 2);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 80-bit format with 64-bit mantissa *including an explicit integer 1*
|
||||
and 15-bit exponent. */
|
||||
static int to_ldoub(char *str, int32_t sign, uint8_t *result,
|
||||
efunc error)
|
||||
{
|
||||
@ -394,13 +454,16 @@ static int to_ldoub(char *str, int32_t sign, uint8_t *result,
|
||||
int float_const(char *number, int32_t sign, uint8_t *result, int bytes,
|
||||
efunc error)
|
||||
{
|
||||
if (bytes == 4)
|
||||
switch (bytes) {
|
||||
case 2:
|
||||
return to_float16(number, sign, result, error);
|
||||
case 4:
|
||||
return to_float(number, sign, result, error);
|
||||
else if (bytes == 8)
|
||||
case 8:
|
||||
return to_double(number, sign, result, error);
|
||||
else if (bytes == 10)
|
||||
case 10:
|
||||
return to_ldoub(number, sign, result, error);
|
||||
else {
|
||||
default:
|
||||
error(ERR_PANIC, "strange value %d passed to float_const", bytes);
|
||||
return 0;
|
||||
}
|
||||
|
24
parser.c
24
parser.c
@ -230,30 +230,36 @@ insn *parse_line(int pass, char *buffer, insn * result,
|
||||
if (i == TOKEN_FLOAT) {
|
||||
eop->type = EOT_DB_STRING;
|
||||
result->eops_float = TRUE;
|
||||
if (result->opcode == I_DD)
|
||||
switch (result->opcode) {
|
||||
case I_DW:
|
||||
eop->stringlen = 2;
|
||||
break;
|
||||
case I_DD:
|
||||
eop->stringlen = 4;
|
||||
else if (result->opcode == I_DQ)
|
||||
break;
|
||||
case I_DQ:
|
||||
eop->stringlen = 8;
|
||||
else if (result->opcode == I_DT)
|
||||
break;
|
||||
case I_DT:
|
||||
eop->stringlen = 10;
|
||||
else if (result->opcode == I_DO)
|
||||
eop->stringlen = 16;
|
||||
else {
|
||||
break;
|
||||
default:
|
||||
error(ERR_NONFATAL, "floating-point constant"
|
||||
" encountered in `D%c' instruction",
|
||||
result->opcode == I_DW ? 'W' : 'B');
|
||||
" encountered in `d%c' instruction"
|
||||
? (result->opcode == I_DO) ? 'o' : 'b');
|
||||
/*
|
||||
* fix suggested by Pedro Gimeno... original line
|
||||
* was:
|
||||
* eop->type = EOT_NOTHING;
|
||||
*/
|
||||
eop->stringlen = 0;
|
||||
break;
|
||||
}
|
||||
eop = nasm_realloc(eop, sizeof(extop) + eop->stringlen);
|
||||
tail = &eop->next;
|
||||
*fixptr = eop;
|
||||
eop->stringval = (char *)eop + sizeof(extop);
|
||||
if (eop->stringlen < 4 ||
|
||||
if (!eop->stringlen ||
|
||||
!float_const(tokval.t_charptr, sign,
|
||||
(uint8_t *)eop->stringval,
|
||||
eop->stringlen, error))
|
||||
|
Loading…
x
Reference in New Issue
Block a user