blob: afa84d2e45ddd29d57e0f639c6e1de9787c2a8dd [file] [log] [blame]
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001/* float.c floating-point constant support for the Netwide Assembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
7 *
8 * initial version 13/ix/96 by Simon Tatham
9 */
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000014#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000015
16#include "nasm.h"
17
18#define TRUE 1
19#define FALSE 0
20
H. Peter Anvine2c80182005-01-15 22:15:51 +000021#define MANT_WORDS 6 /* 64 bits + 32 for accuracy == 96 */
22#define MANT_DIGITS 28 /* 29 digits don't fit in 96 bits */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000023
24/*
25 * guaranteed top bit of from is set
26 * => we only have to worry about _one_ bit shift to the left
27 */
28
Keith Kaniosb7a89542007-04-12 02:40:54 +000029static int ieee_multiply(uint16_t *to, uint16_t *from)
H. Peter Anvineba20a72002-04-30 20:53:55 +000030{
Keith Kaniosb7a89542007-04-12 02:40:54 +000031 uint32_t temp[MANT_WORDS * 2];
H. Peter Anvine2c80182005-01-15 22:15:51 +000032 int i, j;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000033
H. Peter Anvine2c80182005-01-15 22:15:51 +000034 for (i = 0; i < MANT_WORDS * 2; i++)
35 temp[i] = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000036
H. Peter Anvine2c80182005-01-15 22:15:51 +000037 for (i = 0; i < MANT_WORDS; i++)
38 for (j = 0; j < MANT_WORDS; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +000039 uint32_t n;
40 n = (uint32_t)to[i] * (uint32_t)from[j];
H. Peter Anvine2c80182005-01-15 22:15:51 +000041 temp[i + j] += n >> 16;
42 temp[i + j + 1] += n & 0xFFFF;
43 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000044
H. Peter Anvine2c80182005-01-15 22:15:51 +000045 for (i = MANT_WORDS * 2; --i;) {
46 temp[i - 1] += temp[i] >> 16;
47 temp[i] &= 0xFFFF;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000048 }
49 if (temp[0] & 0x8000) {
H. Peter Anvine2c80182005-01-15 22:15:51 +000050 for (i = 0; i < MANT_WORDS; i++)
51 to[i] = temp[i] & 0xFFFF;
52 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000053 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +000054 for (i = 0; i < MANT_WORDS; i++)
55 to[i] = (temp[i] << 1) + !!(temp[i + 1] & 0x8000);
56 return -1;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000057 }
58}
59
Keith Kaniosa6dfa782007-04-13 16:47:53 +000060static void ieee_flconvert(char *string, uint16_t *mant,
Keith Kaniosb7a89542007-04-12 02:40:54 +000061 int32_t *exponent, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +000062{
Keith Kaniosa6dfa782007-04-13 16:47:53 +000063 char digits[MANT_DIGITS];
64 char *p, *q, *r;
Keith Kaniosb7a89542007-04-12 02:40:54 +000065 uint16_t mult[MANT_WORDS], bit;
66 uint16_t *m;
67 int32_t tenpwr, twopwr;
H. Peter Anvine2c80182005-01-15 22:15:51 +000068 int extratwos, started, seendot;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000069
70 p = digits;
71 tenpwr = 0;
72 started = seendot = FALSE;
73 while (*string && *string != 'E' && *string != 'e') {
H. Peter Anvine2c80182005-01-15 22:15:51 +000074 if (*string == '.') {
75 if (!seendot)
76 seendot = TRUE;
77 else {
78 error(ERR_NONFATAL,
79 "too many periods in floating-point constant");
80 return;
81 }
82 } else if (*string >= '0' && *string <= '9') {
83 if (*string == '0' && !started) {
84 if (seendot)
85 tenpwr--;
86 } else {
87 started = TRUE;
88 if (p < digits + sizeof(digits))
89 *p++ = *string - '0';
90 if (!seendot)
91 tenpwr++;
92 }
93 } else {
94 error(ERR_NONFATAL,
95 "floating-point constant: `%c' is invalid character",
96 *string);
97 return;
98 }
99 string++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000100 }
101 if (*string) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000102 string++; /* eat the E */
103 tenpwr += atoi(string);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000104 }
105
106 /*
107 * At this point, the memory interval [digits,p) contains a
108 * series of decimal digits zzzzzzz such that our number X
109 * satisfies
110 *
111 * X = 0.zzzzzzz * 10^tenpwr
112 */
113
114 bit = 0x8000;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000115 for (m = mant; m < mant + MANT_WORDS; m++)
116 *m = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000117 m = mant;
118 q = digits;
119 started = FALSE;
120 twopwr = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000121 while (m < mant + MANT_WORDS) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000122 uint16_t carry = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000123 while (p > q && !p[-1])
124 p--;
125 if (p <= q)
126 break;
127 for (r = p; r-- > q;) {
128 int i;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000129
H. Peter Anvine2c80182005-01-15 22:15:51 +0000130 i = 2 * *r + carry;
131 if (i >= 10)
132 carry = 1, i -= 10;
133 else
134 carry = 0;
135 *r = i;
136 }
137 if (carry)
138 *m |= bit, started = TRUE;
139 if (started) {
140 if (bit == 1)
141 bit = 0x8000, m++;
142 else
143 bit >>= 1;
144 } else
145 twopwr--;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000146 }
147 twopwr += tenpwr;
148
149 /*
150 * At this point the `mant' array contains the first six
151 * fractional places of a base-2^16 real number, which when
152 * multiplied by 2^twopwr and 5^tenpwr gives X. So now we
153 * really do multiply by 5^tenpwr.
154 */
155
156 if (tenpwr < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000157 for (m = mult; m < mult + MANT_WORDS; m++)
158 *m = 0xCCCC;
159 extratwos = -2;
160 tenpwr = -tenpwr;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000161 } else if (tenpwr > 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000162 mult[0] = 0xA000;
163 for (m = mult + 1; m < mult + MANT_WORDS; m++)
164 *m = 0;
165 extratwos = 3;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000166 } else
H. Peter Anvine2c80182005-01-15 22:15:51 +0000167 extratwos = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000168 while (tenpwr) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000169 if (tenpwr & 1)
170 twopwr += extratwos + ieee_multiply(mant, mult);
171 extratwos = extratwos * 2 + ieee_multiply(mult, mult);
172 tenpwr >>= 1;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000173 }
174
175 /*
176 * Conversion is done. The elements of `mant' contain the first
177 * fractional places of a base-2^16 real number in [0.5,1)
178 * which we can multiply by 2^twopwr to get X. Or, of course,
179 * it contains zero.
180 */
181 *exponent = twopwr;
182}
183
184/*
185 * Shift a mantissa to the right by i (i < 16) bits.
186 */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000187static void ieee_shr(uint16_t *mant, int i)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000188{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000189 uint16_t n = 0, m;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000190 int j;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000191
H. Peter Anvine2c80182005-01-15 22:15:51 +0000192 for (j = 0; j < MANT_WORDS; j++) {
193 m = (mant[j] << (16 - i)) & 0xFFFF;
194 mant[j] = (mant[j] >> i) | n;
195 n = m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000196 }
197}
198
199/*
200 * Round a mantissa off after i words.
201 */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000202static int ieee_round(uint16_t *mant, int i)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000203{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000204 if (mant[i] & 0x8000) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000205 do {
206 ++mant[--i];
207 mant[i] &= 0xFFFF;
208 } while (i > 0 && !mant[i]);
209 return !i && !mant[i];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000210 }
211 return 0;
212}
213
214#define put(a,b) ( (*(a)=(b)), ((a)[1]=(b)>>8) )
215
H. Peter Anvin141d7cf2007-09-18 16:39:03 -0700216/* 64-bit format with 52-bit mantissa and 11-bit exponent */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000217static int to_double(char *str, int32_t sign, uint8_t *result,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000218 efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000219{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000220 uint16_t mant[MANT_WORDS];
221 int32_t exponent;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000222
223 sign = (sign < 0 ? 0x8000L : 0L);
224
H. Peter Anvine2c80182005-01-15 22:15:51 +0000225 ieee_flconvert(str, mant, &exponent, error);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000226 if (mant[0] & 0x8000) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000227 /*
228 * Non-zero.
229 */
230 exponent--;
231 if (exponent >= -1022 && exponent <= 1024) {
232 /*
233 * Normalised.
234 */
235 exponent += 1023;
236 ieee_shr(mant, 11);
237 ieee_round(mant, 4);
238 if (mant[0] & 0x20) /* did we scale up by one? */
239 ieee_shr(mant, 1), exponent++;
240 mant[0] &= 0xF; /* remove leading one */
241 put(result + 6, (exponent << 4) | mant[0] | sign);
242 put(result + 4, mant[1]);
243 put(result + 2, mant[2]);
244 put(result + 0, mant[3]);
245 } else if (exponent < -1022 && exponent >= -1074) {
246 /*
247 * Denormal.
248 */
249 int shift = -(exponent + 1011);
250 int sh = shift % 16, wds = shift / 16;
251 ieee_shr(mant, sh);
252 if (ieee_round(mant, 4 - wds)
253 || (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) {
254 ieee_shr(mant, 1);
255 if (sh == 0)
256 mant[0] |= 0x8000;
257 exponent++;
258 }
259 put(result + 6, (wds == 0 ? mant[0] : 0) | sign);
260 put(result + 4, (wds <= 1 ? mant[1 - wds] : 0));
261 put(result + 2, (wds <= 2 ? mant[2 - wds] : 0));
262 put(result + 0, (wds <= 3 ? mant[3 - wds] : 0));
263 } else {
264 if (exponent > 0) {
265 error(ERR_NONFATAL, "overflow in floating-point constant");
266 return 0;
267 } else
268 memset(result, 0, 8);
269 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000270 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000271 /*
272 * Zero.
273 */
274 memset(result, 0, 8);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000275 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000276 return 1; /* success */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000277}
278
H. Peter Anvin141d7cf2007-09-18 16:39:03 -0700279/* 32-bit format with 23-bit mantissa and 8-bit exponent */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000280static int to_float(char *str, int32_t sign, uint8_t *result,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000281 efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000282{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000283 uint16_t mant[MANT_WORDS];
284 int32_t exponent;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000285
286 sign = (sign < 0 ? 0x8000L : 0L);
287
H. Peter Anvine2c80182005-01-15 22:15:51 +0000288 ieee_flconvert(str, mant, &exponent, error);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000289 if (mant[0] & 0x8000) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000290 /*
291 * Non-zero.
292 */
293 exponent--;
294 if (exponent >= -126 && exponent <= 128) {
295 /*
296 * Normalised.
297 */
298 exponent += 127;
299 ieee_shr(mant, 8);
300 ieee_round(mant, 2);
301 if (mant[0] & 0x100) /* did we scale up by one? */
302 ieee_shr(mant, 1), exponent++;
303 mant[0] &= 0x7F; /* remove leading one */
304 put(result + 2, (exponent << 7) | mant[0] | sign);
305 put(result + 0, mant[1]);
306 } else if (exponent < -126 && exponent >= -149) {
307 /*
308 * Denormal.
309 */
310 int shift = -(exponent + 118);
311 int sh = shift % 16, wds = shift / 16;
312 ieee_shr(mant, sh);
313 if (ieee_round(mant, 2 - wds)
314 || (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) {
315 ieee_shr(mant, 1);
316 if (sh == 0)
317 mant[0] |= 0x8000;
318 exponent++;
319 }
320 put(result + 2, (wds == 0 ? mant[0] : 0) | sign);
321 put(result + 0, (wds <= 1 ? mant[1 - wds] : 0));
322 } else {
323 if (exponent > 0) {
324 error(ERR_NONFATAL, "overflow in floating-point constant");
325 return 0;
326 } else
327 memset(result, 0, 4);
328 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000329 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 memset(result, 0, 4);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000331 }
332 return 1;
333}
334
H. Peter Anvin141d7cf2007-09-18 16:39:03 -0700335/* 16-bit format with 10-bit mantissa and 5-bit exponent.
336 Defined in IEEE 754r. Used in SSE5. See the AMD SSE5 manual, AMD
337 document number 43479. */
338static int to_float16(char *str, int32_t sign, uint8_t *result,
339 efunc error)
340{
341 uint16_t mant[MANT_WORDS];
342 int32_t exponent;
343
344 sign = (sign < 0 ? 0x8000L : 0L);
345
346 ieee_flconvert(str, mant, &exponent, error);
347 if (mant[0] & 0x8000) {
348 /*
349 * Non-zero.
350 */
351 exponent--;
352 if (exponent >= -14 && exponent <= 16) {
353 /*
354 * Normalised.
355 */
356 exponent += 15;
357 ieee_shr(mant, 5);
358 ieee_round(mant, 1);
359 if (mant[0] & 0x800) /* did we scale up by one? */
360 ieee_shr(mant, 1), exponent++;
361 mant[0] &= 0x3FF; /* remove leading one */
362 put(result + 0, (exponent << 7) | mant[0] | sign);
363 } else if (exponent < -14 && exponent >= -24) {
364 /*
365 * Denormal.
366 */
367 int shift = -(exponent + 8);
368 int sh = shift % 16, wds = shift / 16;
369 ieee_shr(mant, sh);
370 if (ieee_round(mant, 1 - wds)
371 || (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) {
372 ieee_shr(mant, 1);
373 if (sh == 0)
374 mant[0] |= 0x8000;
375 exponent++;
376 }
377 put(result + 0, (wds == 0 ? mant[0] : 0) | sign);
378 } else {
379 if (exponent > 0) {
380 error(ERR_NONFATAL, "overflow in floating-point constant");
381 return 0;
382 } else
383 memset(result, 0, 2);
384 }
385 } else {
386 memset(result, 0, 2);
387 }
388 return 1;
389}
390
391/* 80-bit format with 64-bit mantissa *including an explicit integer 1*
392 and 15-bit exponent. */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000393static int to_ldoub(char *str, int32_t sign, uint8_t *result,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000394 efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000395{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000396 uint16_t mant[MANT_WORDS];
397 int32_t exponent;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000398
399 sign = (sign < 0 ? 0x8000L : 0L);
400
H. Peter Anvine2c80182005-01-15 22:15:51 +0000401 ieee_flconvert(str, mant, &exponent, error);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000402 if (mant[0] & 0x8000) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000403 /*
404 * Non-zero.
405 */
406 exponent--;
407 if (exponent >= -16383 && exponent <= 16384) {
408 /*
409 * Normalised.
410 */
411 exponent += 16383;
412 if (ieee_round(mant, 4)) /* did we scale up by one? */
413 ieee_shr(mant, 1), mant[0] |= 0x8000, exponent++;
414 put(result + 8, exponent | sign);
415 put(result + 6, mant[0]);
416 put(result + 4, mant[1]);
417 put(result + 2, mant[2]);
418 put(result + 0, mant[3]);
419 } else if (exponent < -16383 && exponent >= -16446) {
420 /*
421 * Denormal.
422 */
423 int shift = -(exponent + 16383);
424 int sh = shift % 16, wds = shift / 16;
425 ieee_shr(mant, sh);
426 if (ieee_round(mant, 4 - wds)
427 || (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) {
428 ieee_shr(mant, 1);
429 if (sh == 0)
430 mant[0] |= 0x8000;
431 exponent++;
432 }
433 put(result + 8, sign);
434 put(result + 6, (wds == 0 ? mant[0] : 0));
435 put(result + 4, (wds <= 1 ? mant[1 - wds] : 0));
436 put(result + 2, (wds <= 2 ? mant[2 - wds] : 0));
437 put(result + 0, (wds <= 3 ? mant[3 - wds] : 0));
438 } else {
439 if (exponent > 0) {
440 error(ERR_NONFATAL, "overflow in floating-point constant");
441 return 0;
442 } else
443 memset(result, 0, 10);
444 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000445 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000446 /*
447 * Zero.
448 */
449 memset(result, 0, 10);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000450 }
451 return 1;
452}
453
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000454int float_const(char *number, int32_t sign, uint8_t *result, int bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000455 efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000456{
H. Peter Anvin141d7cf2007-09-18 16:39:03 -0700457 switch (bytes) {
458 case 2:
459 return to_float16(number, sign, result, error);
460 case 4:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000461 return to_float(number, sign, result, error);
H. Peter Anvin141d7cf2007-09-18 16:39:03 -0700462 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000463 return to_double(number, sign, result, error);
H. Peter Anvin141d7cf2007-09-18 16:39:03 -0700464 case 10:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000465 return to_ldoub(number, sign, result, error);
H. Peter Anvin141d7cf2007-09-18 16:39:03 -0700466 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000467 error(ERR_PANIC, "strange value %d passed to float_const", bytes);
468 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000469 }
470}