]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights | |
7 | * Reserved. This file contains Original Code and/or Modifications of | |
8 | * Original Code as defined in and that are subject to the Apple Public | |
9 | * Source License Version 1.1 (the "License"). You may not use this file | |
10 | * except in compliance with the License. Please obtain a copy of the | |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the | |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* float.c floating-point constant support for the Netwide Assembler | |
25 | * | |
26 | * The Netwide Assembler is copyright (C) 1996 Simon Tatham and | |
27 | * Julian Hall. All rights reserved. The software is | |
28 | * redistributable under the licence given in the file "Licence" | |
29 | * distributed in the NASM archive. | |
30 | * | |
31 | * initial version 13/ix/96 by Simon Tatham | |
32 | */ | |
33 | ||
34 | #include <stdio.h> | |
35 | #include <stdlib.h> | |
36 | #include <string.h> | |
37 | ||
38 | #include "nasm.h" | |
39 | ||
40 | #define TRUE 1 | |
41 | #define FALSE 0 | |
42 | ||
43 | #define MANT_WORDS 6 /* 64 bits + 32 for accuracy == 96 */ | |
44 | #define MANT_DIGITS 28 /* 29 digits don't fit in 96 bits */ | |
45 | ||
46 | /* | |
47 | * guaranteed top bit of from is set | |
48 | * => we only have to worry about _one_ bit shift to the left | |
49 | */ | |
50 | ||
51 | static int multiply(unsigned short *to, unsigned short *from) { | |
52 | unsigned long temp[MANT_WORDS*2]; | |
53 | int i, j; | |
54 | ||
55 | for (i=0; i<MANT_WORDS*2; i++) | |
56 | temp[i] = 0; | |
57 | ||
58 | for (i=0; i<MANT_WORDS; i++) | |
59 | for (j=0; j<MANT_WORDS; j++) { | |
60 | unsigned long n; | |
61 | n = (unsigned long)to[i] * (unsigned long)from[j]; | |
62 | temp[i+j] += n >> 16; | |
63 | temp[i+j+1] += n & 0xFFFF; | |
64 | } | |
65 | ||
66 | for (i=MANT_WORDS*2; --i ;) { | |
67 | temp[i-1] += temp[i] >> 16; | |
68 | temp[i] &= 0xFFFF; | |
69 | } | |
70 | if (temp[0] & 0x8000) { | |
71 | for (i=0; i<MANT_WORDS; i++) | |
72 | to[i] = temp[i] & 0xFFFF; | |
73 | return 0; | |
74 | } else { | |
75 | for (i=0; i<MANT_WORDS; i++) | |
76 | to[i] = (temp[i] << 1) + !!(temp[i+1] & 0x8000); | |
77 | return -1; | |
78 | } | |
79 | } | |
80 | ||
81 | static void flconvert(char *string, unsigned short *mant, long *exponent, | |
82 | efunc error) { | |
83 | char digits[MANT_DIGITS], *p, *q, *r; | |
84 | unsigned short mult[MANT_WORDS], *m, bit; | |
85 | long tenpwr, twopwr; | |
86 | int extratwos, started, seendot; | |
87 | ||
88 | p = digits; | |
89 | tenpwr = 0; | |
90 | started = seendot = FALSE; | |
91 | while (*string && *string != 'E' && *string != 'e') { | |
92 | if (*string == '.') { | |
93 | if (!seendot) | |
94 | seendot = TRUE; | |
95 | else { | |
96 | error (ERR_NONFATAL, | |
97 | "too many periods in floating-point constant"); | |
98 | return; | |
99 | } | |
100 | } else if (*string >= '0' && *string <= '9') { | |
101 | if (*string == '0' && !started) { | |
102 | if (seendot) | |
103 | tenpwr--; | |
104 | } else { | |
105 | started = TRUE; | |
106 | if (p < digits+sizeof(digits)) | |
107 | *p++ = *string - '0'; | |
108 | if (!seendot) | |
109 | tenpwr++; | |
110 | } | |
111 | } else { | |
112 | error (ERR_NONFATAL, | |
113 | "floating-point constant: `%c' is invalid character", | |
114 | *string); | |
115 | return; | |
116 | } | |
117 | string++; | |
118 | } | |
119 | if (*string) { | |
120 | string++; /* eat the E */ | |
121 | tenpwr += atoi(string); | |
122 | } | |
123 | ||
124 | /* | |
125 | * At this point, the memory interval [digits,p) contains a | |
126 | * series of decimal digits zzzzzzz such that our number X | |
127 | * satisfies | |
128 | * | |
129 | * X = 0.zzzzzzz * 10^tenpwr | |
130 | */ | |
131 | ||
132 | bit = 0x8000; | |
133 | for (m=mant; m<mant+MANT_WORDS; m++) | |
134 | *m = 0; | |
135 | m = mant; | |
136 | q = digits; | |
137 | started = FALSE; | |
138 | twopwr = 0; | |
139 | while (m < mant+MANT_WORDS) { | |
140 | unsigned short carry = 0; | |
141 | while (p > q && !p[-1]) | |
142 | p--; | |
143 | if (p <= q) | |
144 | break; | |
145 | for (r = p; r-- > q ;) { | |
146 | int i; | |
147 | ||
148 | i = 2 * *r + carry; | |
149 | if (i >= 10) | |
150 | carry = 1, i -= 10; | |
151 | else | |
152 | carry = 0; | |
153 | *r = i; | |
154 | } | |
155 | if (carry) | |
156 | *m |= bit, started = TRUE; | |
157 | if (started) { | |
158 | if (bit == 1) | |
159 | bit = 0x8000, m++; | |
160 | else | |
161 | bit >>= 1; | |
162 | } else | |
163 | twopwr--; | |
164 | } | |
165 | twopwr += tenpwr; | |
166 | ||
167 | /* | |
168 | * At this point the `mant' array contains the first six | |
169 | * fractional places of a base-2^16 real number, which when | |
170 | * multiplied by 2^twopwr and 5^tenpwr gives X. So now we | |
171 | * really do multiply by 5^tenpwr. | |
172 | */ | |
173 | ||
174 | if (tenpwr < 0) { | |
175 | for (m=mult; m<mult+MANT_WORDS; m++) | |
176 | *m = 0xCCCC; | |
177 | extratwos = -2; | |
178 | tenpwr = -tenpwr; | |
179 | } else if (tenpwr > 0) { | |
180 | mult[0] = 0xA000; | |
181 | for (m=mult+1; m<mult+MANT_WORDS; m++) | |
182 | *m = 0; | |
183 | extratwos = 3; | |
184 | } else | |
185 | extratwos = 0; | |
186 | while (tenpwr) { | |
187 | if (tenpwr & 1) | |
188 | twopwr += extratwos + multiply (mant, mult); | |
189 | extratwos = extratwos * 2 + multiply (mult, mult); | |
190 | tenpwr >>= 1; | |
191 | } | |
192 | ||
193 | /* | |
194 | * Conversion is done. The elements of `mant' contain the first | |
195 | * fractional places of a base-2^16 real number in [0.5,1) | |
196 | * which we can multiply by 2^twopwr to get X. Or, of course, | |
197 | * it contains zero. | |
198 | */ | |
199 | *exponent = twopwr; | |
200 | } | |
201 | ||
202 | /* | |
203 | * Shift a mantissa to the right by i (i < 16) bits. | |
204 | */ | |
205 | static void shr(unsigned short *mant, int i) { | |
206 | unsigned short n = 0, m; | |
207 | int j; | |
208 | ||
209 | for (j=0; j<MANT_WORDS; j++) { | |
210 | m = (mant[j] << (16-i)) & 0xFFFF; | |
211 | mant[j] = (mant[j] >> i) | n; | |
212 | n = m; | |
213 | } | |
214 | } | |
215 | ||
216 | /* | |
217 | * Round a mantissa off after i words. | |
218 | */ | |
219 | static int round(unsigned short *mant, int i) { | |
220 | if (mant[i] & 0x8000) { | |
221 | do { | |
222 | ++mant[--i]; | |
223 | mant[i] &= 0xFFFF; | |
224 | } while (i > 0 && !mant[i]); | |
225 | return !i && !mant[i]; | |
226 | } | |
227 | return 0; | |
228 | } | |
229 | ||
230 | #define put(a,b) ( (*(a)=(b)), ((a)[1]=(b)>>8) ) | |
231 | ||
232 | static int to_double(char *str, long sign, unsigned char *result, | |
233 | efunc error) { | |
234 | unsigned short mant[MANT_WORDS]; | |
235 | long exponent; | |
236 | ||
237 | sign = (sign < 0 ? 0x8000L : 0L); | |
238 | ||
239 | flconvert (str, mant, &exponent, error); | |
240 | if (mant[0] & 0x8000) { | |
241 | /* | |
242 | * Non-zero. | |
243 | */ | |
244 | exponent--; | |
245 | if (exponent >= -1022 && exponent <= 1024) { | |
246 | /* | |
247 | * Normalised. | |
248 | */ | |
249 | exponent += 1023; | |
250 | shr(mant, 11); | |
251 | round(mant, 4); | |
252 | if (mant[0] & 0x20) /* did we scale up by one? */ | |
253 | shr(mant, 1), exponent++; | |
254 | mant[0] &= 0xF; /* remove leading one */ | |
255 | put(result+6,(exponent << 4) | mant[0] | sign); | |
256 | put(result+4,mant[1]); | |
257 | put(result+2,mant[2]); | |
258 | put(result+0,mant[3]); | |
259 | } else if (exponent < -1022 && exponent >= -1074) { | |
260 | /* | |
261 | * Denormal. | |
262 | */ | |
263 | int shift = -(exponent+1011); | |
264 | int sh = shift % 16, wds = shift / 16; | |
265 | shr(mant, sh); | |
266 | if (round(mant, 4-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) { | |
267 | shr(mant, 1); | |
268 | if (sh==0) | |
269 | mant[0] |= 0x8000; | |
270 | exponent++; | |
271 | } | |
272 | put(result+6,(wds == 0 ? mant[0] : 0) | sign); | |
273 | put(result+4,(wds <= 1 ? mant[1-wds] : 0)); | |
274 | put(result+2,(wds <= 2 ? mant[2-wds] : 0)); | |
275 | put(result+0,(wds <= 3 ? mant[3-wds] : 0)); | |
276 | } else { | |
277 | if (exponent > 0) { | |
278 | error(ERR_NONFATAL, "overflow in floating-point constant"); | |
279 | return 0; | |
280 | } else | |
281 | memset (result, 0, 8); | |
282 | } | |
283 | } else { | |
284 | /* | |
285 | * Zero. | |
286 | */ | |
287 | memset (result, 0, 8); | |
288 | } | |
289 | return 1; /* success */ | |
290 | } | |
291 | ||
292 | static int to_float(char *str, long sign, unsigned char *result, | |
293 | efunc error) { | |
294 | unsigned short mant[MANT_WORDS]; | |
295 | long exponent; | |
296 | ||
297 | sign = (sign < 0 ? 0x8000L : 0L); | |
298 | ||
299 | flconvert (str, mant, &exponent, error); | |
300 | if (mant[0] & 0x8000) { | |
301 | /* | |
302 | * Non-zero. | |
303 | */ | |
304 | exponent--; | |
305 | if (exponent >= -126 && exponent <= 128) { | |
306 | /* | |
307 | * Normalised. | |
308 | */ | |
309 | exponent += 127; | |
310 | shr(mant, 8); | |
311 | round(mant, 2); | |
312 | if (mant[0] & 0x100) /* did we scale up by one? */ | |
313 | shr(mant, 1), exponent++; | |
314 | mant[0] &= 0x7F; /* remove leading one */ | |
315 | put(result+2,(exponent << 7) | mant[0] | sign); | |
316 | put(result+0,mant[1]); | |
317 | } else if (exponent < -126 && exponent >= -149) { | |
318 | /* | |
319 | * Denormal. | |
320 | */ | |
321 | int shift = -(exponent+118); | |
322 | int sh = shift % 16, wds = shift / 16; | |
323 | shr(mant, sh); | |
324 | if (round(mant, 2-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) { | |
325 | shr(mant, 1); | |
326 | if (sh==0) | |
327 | mant[0] |= 0x8000; | |
328 | exponent++; | |
329 | } | |
330 | put(result+2,(wds == 0 ? mant[0] : 0) | sign); | |
331 | put(result+0,(wds <= 1 ? mant[1-wds] : 0)); | |
332 | } else { | |
333 | if (exponent > 0) { | |
334 | error(ERR_NONFATAL, "overflow in floating-point constant"); | |
335 | return 0; | |
336 | } else | |
337 | memset (result, 0, 4); | |
338 | } | |
339 | } else { | |
340 | memset (result, 0, 4); | |
341 | } | |
342 | return 1; | |
343 | } | |
344 | ||
345 | static int to_ldoub(char *str, long sign, unsigned char *result, | |
346 | efunc error) { | |
347 | unsigned short mant[MANT_WORDS]; | |
348 | long exponent; | |
349 | ||
350 | sign = (sign < 0 ? 0x8000L : 0L); | |
351 | ||
352 | flconvert (str, mant, &exponent, error); | |
353 | if (mant[0] & 0x8000) { | |
354 | /* | |
355 | * Non-zero. | |
356 | */ | |
357 | exponent--; | |
358 | if (exponent >= -16383 && exponent <= 16384) { | |
359 | /* | |
360 | * Normalised. | |
361 | */ | |
362 | exponent += 16383; | |
363 | if (round(mant, 4)) /* did we scale up by one? */ | |
364 | shr(mant, 1), mant[0] |= 0x8000, exponent++; | |
365 | put(result+8,exponent | sign); | |
366 | put(result+6,mant[0]); | |
367 | put(result+4,mant[1]); | |
368 | put(result+2,mant[2]); | |
369 | put(result+0,mant[3]); | |
370 | } else if (exponent < -16383 && exponent >= -16446) { | |
371 | /* | |
372 | * Denormal. | |
373 | */ | |
374 | int shift = -(exponent+16383); | |
375 | int sh = shift % 16, wds = shift / 16; | |
376 | shr(mant, sh); | |
377 | if (round(mant, 4-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) { | |
378 | shr(mant, 1); | |
379 | if (sh==0) | |
380 | mant[0] |= 0x8000; | |
381 | exponent++; | |
382 | } | |
383 | put(result+8,sign); | |
384 | put(result+6,(wds == 0 ? mant[0] : 0)); | |
385 | put(result+4,(wds <= 1 ? mant[1-wds] : 0)); | |
386 | put(result+2,(wds <= 2 ? mant[2-wds] : 0)); | |
387 | put(result+0,(wds <= 3 ? mant[3-wds] : 0)); | |
388 | } else { | |
389 | if (exponent > 0) { | |
390 | error(ERR_NONFATAL, "overflow in floating-point constant"); | |
391 | return 0; | |
392 | } else | |
393 | memset (result, 0, 10); | |
394 | } | |
395 | } else { | |
396 | /* | |
397 | * Zero. | |
398 | */ | |
399 | memset (result, 0, 10); | |
400 | } | |
401 | return 1; | |
402 | } | |
403 | ||
404 | int float_const (char *number, long sign, unsigned char *result, int bytes, | |
405 | efunc error) { | |
406 | if (bytes == 4) | |
407 | return to_float (number, sign, result, error); | |
408 | else if (bytes == 8) | |
409 | return to_double (number, sign, result, error); | |
410 | else if (bytes == 10) | |
411 | return to_ldoub (number, sign, result, error); | |
412 | else { | |
413 | error(ERR_PANIC, "strange value %d passed to float_const", bytes); | |
414 | return 0; | |
415 | } | |
416 | } |