/* atof_ieee.c - turn a Flonum into an IEEE floating point number
Copyright (C) 1987 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
GAS 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define bzero(s,n) memset(s,0,n)
#define bcopy(from,to,n) memcpy((to),(from),(n))
extern FLONUM_TYPE generic_floating_point_number
; /* Flonums returned here. */
/* Precision in LittleNums. */
#define MAX_PRECISION (6)
/* Length in LittleNums of guard bits. */
static unsigned long int mask
[] = {
static int bits_left_in_littlenum
;
static int littlenums_left
;
static LITTLENUM_TYPE
* littlenum_pointer
;
next_bits (number_of_bits
)
if (number_of_bits
>= bits_left_in_littlenum
)
return_value
= mask
[bits_left_in_littlenum
] & *littlenum_pointer
;
number_of_bits
-= bits_left_in_littlenum
;
return_value
<<= number_of_bits
;
bits_left_in_littlenum
= LITTLENUM_NUMBER_OF_BITS
- number_of_bits
;
return_value
|= (*littlenum_pointer
>>bits_left_in_littlenum
) & mask
[number_of_bits
];
bits_left_in_littlenum
-= number_of_bits
;
return_value
= mask
[number_of_bits
] & (*littlenum_pointer
>>bits_left_in_littlenum
);
/* Num had better be less than LITTLENUM_NUMBER_OF_BITS */
bits_left_in_littlenum
=num
;
} else if(bits_left_in_littlenum
+num
>LITTLENUM_NUMBER_OF_BITS
) {
bits_left_in_littlenum
= num
-(LITTLENUM_NUMBER_OF_BITS
-bits_left_in_littlenum
);
bits_left_in_littlenum
+=num
;
make_invalid_floating_point_number (words
)
as_warn("cannot create floating-point number");
words
[0]= ((unsigned)-1)>>1; /* Zero the leftmost bit */
/***********************************************************************\
* Warning: this returns 16-bit LITTLENUMs. It is up to the caller *
* to figure out any alignment problems and to conspire for the *
* bytes/word to be emitted in the right order. Bigendians beware! *
\***********************************************************************/
/* Note that atof-ieee always has X and P precisions enabled. it is up
to md_atof to filter them out if the target machine does not support
char * /* Return pointer past text consumed. */
atof_ieee (str
, what_kind
, words
)
char * str
; /* Text to convert to binary. */
char what_kind
; /* 'd', 'f', 'g', 'h' */
LITTLENUM_TYPE
* words
; /* Build the binary here. */
static LITTLENUM_TYPE bits
[MAX_PRECISION
+ MAX_PRECISION
+ GUARD
];
/* Extra bits for zeroed low-order bits. */
/* The 1st MAX_PRECISION are zeroed, */
/* the last contain flonum bits. */
int precision
; /* Number of 16-bit words in the format. */
generic_floating_point_number
.low
= bits
+ MAX_PRECISION
;
generic_floating_point_number
.high
= NULL
;
generic_floating_point_number
.leader
= NULL
;
generic_floating_point_number
.exponent
= NULL
;
generic_floating_point_number
.sign
= '\0';
/* Use more LittleNums than seems */
/* necessary: the highest flonum may have */
/* 15 leading 0 bits, so could be useless. */
bzero (bits
, sizeof(LITTLENUM_TYPE
) * MAX_PRECISION
);
make_invalid_floating_point_number (words
);
generic_floating_point_number
.high
= generic_floating_point_number
.low
+ precision
- 1 + GUARD
;
if (atof_generic (& return_value
, ".", EXP_CHARS
, & generic_floating_point_number
)) {
/* as_warn("Error converting floating point number (Exponent overflow?)"); */
make_invalid_floating_point_number (words
);
gen_to_words(words
, precision
, exponent_bits
);
/* Turn generic_floating_point_number into a real float/double/extended */
gen_to_words(words
,precision
,exponent_bits
)
if (generic_floating_point_number
.low
> generic_floating_point_number
.leader
) {
if(generic_floating_point_number
.sign
=='+')
bzero (&words
[1], sizeof(LITTLENUM_TYPE
) * (precision
-1));
/* NaN: Do the right thing */
if(generic_floating_point_number
.sign
==0) {
if(precision
==F_PRECISION
) {
} else if(generic_floating_point_number
.sign
=='P') {
/* +INF: Do the right thing */
if(precision
==F_PRECISION
) {
} else if(generic_floating_point_number
.sign
=='N') {
if(precision
==F_PRECISION
) {
* The floating point formats we support have:
* Bits 14:n are excess-whatever exponent.
* Bits n-1:0 (if any) are most significant bits of fraction.
* Bits 15:0 of the next word(s) are the next most significant bits.
* So we need: number of bits of exponent, number of bits of
bits_left_in_littlenum
= LITTLENUM_NUMBER_OF_BITS
;
littlenum_pointer
= generic_floating_point_number
.leader
;
littlenums_left
= 1+generic_floating_point_number
.leader
- generic_floating_point_number
.low
;
/* Seek (and forget) 1st significant bit */
for (exponent_skippage
= 0;! next_bits(1); exponent_skippage
++)
exponent_1
= generic_floating_point_number
.exponent
+ generic_floating_point_number
.leader
+ 1 -
generic_floating_point_number
.low
;
/* Radix LITTLENUM_RADIX, point just higher than generic_floating_point_number.leader. */
exponent_2
= exponent_1
* LITTLENUM_NUMBER_OF_BITS
;
exponent_3
= exponent_2
- exponent_skippage
;
/* Forget leading zeros, forget 1st bit. */
exponent_4
= exponent_3
+ ((1 << (exponent_bits
- 1)) - 2);
/* Word 1. Sign, exponent and perhaps high bits. */
word1
= (generic_floating_point_number
.sign
== '+') ? 0 : (1<<(LITTLENUM_NUMBER_OF_BITS
-1));
/* Assume 2's complement integers. */
if(exponent_4
<1 && exponent_4
>=-62) {
prec_bits
=LITTLENUM_NUMBER_OF_BITS
*precision
-(exponent_bits
+1+num_bits
);
if(precision
==X_PRECISION
&& exponent_bits
==15)
prec_bits
-=LITTLENUM_NUMBER_OF_BITS
+1;
if(num_bits
>=LITTLENUM_NUMBER_OF_BITS
-exponent_bits
) {
/* Bigger than one littlenum */
num_bits
-=(LITTLENUM_NUMBER_OF_BITS
-1)-exponent_bits
;
if(num_bits
+exponent_bits
+1>=precision
*LITTLENUM_NUMBER_OF_BITS
) {
make_invalid_floating_point_number(words
);
if(precision
==X_PRECISION
&& exponent_bits
==15) {
num_bits
-=LITTLENUM_NUMBER_OF_BITS
-1;
while(num_bits
>=LITTLENUM_NUMBER_OF_BITS
) {
num_bits
-=LITTLENUM_NUMBER_OF_BITS
;
*lp
++=next_bits(LITTLENUM_NUMBER_OF_BITS
-(num_bits
));
if(precision
==X_PRECISION
&& exponent_bits
==15) {
if(num_bits
==LITTLENUM_NUMBER_OF_BITS
) {
*lp
++=next_bits(LITTLENUM_NUMBER_OF_BITS
-1);
} else if(num_bits
==LITTLENUM_NUMBER_OF_BITS
-1)
*lp
++=next_bits(LITTLENUM_NUMBER_OF_BITS
-1-num_bits
);
word1
|= next_bits ((LITTLENUM_NUMBER_OF_BITS
-1) - (exponent_bits
+num_bits
));
while(lp
<words
+precision
)
*lp
++=next_bits(LITTLENUM_NUMBER_OF_BITS
);
/* Round the mantissa up, but don't change the number */
if(prec_bits
>LITTLENUM_NUMBER_OF_BITS
) {
while(tmp_bits
>LITTLENUM_NUMBER_OF_BITS
) {
if(lp
[n
]!=(LITTLENUM_TYPE
)-1)
tmp_bits
-=LITTLENUM_NUMBER_OF_BITS
;
if(tmp_bits
>LITTLENUM_NUMBER_OF_BITS
|| (lp
[n
]&mask
[tmp_bits
])!=mask
[tmp_bits
]) {
for (carry
= 1; carry
&& (lp
>= words
); lp
--) {
carry
>>= LITTLENUM_NUMBER_OF_BITS
;
} else if((*lp
&mask
[prec_bits
])!=mask
[prec_bits
])
} else if (exponent_4
& ~ mask
[exponent_bits
]) {
* Exponent overflow. Lose immediately.
* We leave return_value alone: admit we read the
* number, but return a floating exception
* because we can't encode the number.
make_invalid_floating_point_number (words
);
word1
|= (exponent_4
<< ((LITTLENUM_NUMBER_OF_BITS
-1) - exponent_bits
))
| next_bits ((LITTLENUM_NUMBER_OF_BITS
-1) - exponent_bits
);
/* X_PRECISION is special: it has 16 bits of zero in the middle,
if(exponent_bits
==15 && precision
==X_PRECISION
) {
*lp
++= 1<<(LITTLENUM_NUMBER_OF_BITS
)|next_bits(LITTLENUM_NUMBER_OF_BITS
-1);
/* The rest of the words are just mantissa bits. */
while(lp
< words
+ precision
)
*lp
++ = next_bits (LITTLENUM_NUMBER_OF_BITS
);
* Since the NEXT bit is a 1, round UP the mantissa.
* The cunning design of these hidden-1 floats permits
* us to let the mantissa overflow into the exponent, and
* it 'does the right thing'. However, we lose if the
* highest-order bit of the lowest-order word flips.
/* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
Please allow at least 1 more bit in carry than is in a LITTLENUM.
We need that extra bit to hold a carry during a LITTLENUM carry
propagation. Another extra bit (kept 0) will assure us that we
don't get a sticky sign bit after shifting right, and that
permits us to propagate the carry without any masking of bits.
for (carry
= 1, lp
--; carry
&& (lp
>= words
); lp
--) {
carry
>>= LITTLENUM_NUMBER_OF_BITS
;
if ( (word1
^ *words
) & (1 << (LITTLENUM_NUMBER_OF_BITS
- 1)) ) {
/* We leave return_value alone: admit we read the
* number, but return a floating exception
* because we can't encode the number.
*words
&= ~ (1 << (LITTLENUM_NUMBER_OF_BITS
- 1));
/* make_invalid_floating_point_number (words); */
/* return return_value; */
/* This routine is a real kludge. Someone really should do it better, but
I'm too lazy, and I don't understand this stuff all too well anyway
if(atof_generic(&bufp
,".", EXP_CHARS
, &generic_floating_point_number
))
as_warn("Error converting number to floating point (Exponent overflow?)");
f
=generic_floating_point_number
;
generic_floating_point_number
= *gen
;
gen_to_words(&arr
[0],4,11);
bcopy(&arr
[0],&dv
,sizeof(double));
sprintf(sbuf
,"%x %x %x %x %.14G ",arr
[0],arr
[1],arr
[2],arr
[3],dv
);
gen_to_words(&arr
[0],2,8);
bcopy(&arr
[0],&fv
,sizeof(float));
sprintf(sbuf
+strlen(sbuf
),"%x %x %.12g\n",arr
[0],arr
[1],fv
);
generic_floating_point_number
=f
;