1 /*	$Id: softfloat.c,v 1.1 2012/01/01 16:20:55 ragge Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Anders Magnusson. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #ifdef SOFTFLOAT
30 
31 #include "pass1.h"
32 
33 
34 /*
35  * Floating point emulation to be used when cross-compiling.
36  * Currently only supports F- and D-float, used in DEC machines.
37  * Should be trivial to add other emulations.
38  *
39  * XXX - assumes that:
40  *	- long long is (at least) 64 bits
41  *	- int is at least 32 bits.
42  *	- short is 16 bits.
43  */
44 
45 #ifdef FDFLOAT
46 
47 /*
48  * Useful macros to manipulate the float.
49  */
50 #define DSIGN(w)	(((w).fd1 >> 15) & 1)
51 #define DSIGNSET(w,s)	((w).fd1 = (s << 15) | ((w).fd1 & 077777))
52 #define DEXP(w)		(((w).fd1 >> 7) & 0377)
53 #define DEXPSET(w,e)	((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177))
54 #define DMANTH(w)	((w).fd1 & 0177)
55 #define DMANTHSET(w,m)	((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600))
56 
57 typedef unsigned int lword;
58 typedef unsigned long long dword;
59 
60 #define MAXMANT 0x100000000000000LL
61 
62 /*
63  * Returns a zero dfloat.
64  */
65 static SF
nulldf(void)66 nulldf(void)
67 {
68 	SF rv;
69 
70 	rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0;
71 	return rv;
72 }
73 
74 /*
75  * Convert a (u)longlong to dfloat.
76  * XXX - fails on too large (> 55 bits) numbers.
77  */
78 SF
soft_cast(CONSZ ll,TWORD t)79 soft_cast(CONSZ ll, TWORD t)
80 {
81 	int i;
82 	SF rv;
83 
84 	rv = nulldf();
85 	if (ll == 0)
86 		return rv;  /* fp is zero */
87 	if (ll < 0)
88 		DSIGNSET(rv,1), ll = -ll;
89 	for (i = 0; ll > 0; i++, ll <<= 1)
90 		;
91 	DEXPSET(rv, 192-i);
92 	DMANTHSET(rv, ll >> 56);
93 	rv.fd2 = ll >> 40;
94 	rv.fd3 = ll >> 24;
95 	rv.fd4 = ll >> 8;
96 	return rv;
97 }
98 
99 /*
100  * multiply two dfloat. Use chop, not round.
101  */
102 SF
soft_mul(SF p1,SF p2)103 soft_mul(SF p1, SF p2)
104 {
105 	SF rv;
106 	lword a1[2], a2[2], res[4];
107 	dword sum;
108 
109 	res[0] = res[1] = res[2] = res[3] = 0;
110 
111 	/* move mantissa into lwords */
112 	a1[0] = p1.fd4 | (p1.fd3 << 16);
113 	a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000;
114 
115 	a2[0] = p2.fd4 | (p2.fd3 << 16);
116 	a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000;
117 
118 #define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \
119 	res[r] = sum; sum >>= 32;
120 
121 	sum = 0;
122 	MULONE(0, 0, 0);
123 	MULONE(1, 0, 1);
124 	res[2] = sum;
125 	sum = 0;
126 	MULONE(0, 1, 1);
127 	MULONE(1, 1, 2);
128 	res[3] = sum;
129 
130 	rv.fd1 = 0;
131 	DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2));
132 	DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128);
133 	if (res[3] & 0x8000) {
134 		res[3] = (res[3] << 8) | (res[2] >> 24);
135 		res[2] = (res[2] << 8) | (res[1] >> 24);
136 	} else {
137 		DEXPSET(rv, DEXP(rv) - 1);
138 		res[3] = (res[3] << 9) | (res[2] >> 23);
139 		res[2] = (res[2] << 9) | (res[1] >> 23);
140 	}
141 	DMANTHSET(rv, res[3] >> 16);
142 	rv.fd2 = res[3];
143 	rv.fd3 = res[2] >> 16;
144 	rv.fd4 = res[2];
145 	return rv;
146 }
147 
148 SF
soft_div(SF t,SF n)149 soft_div(SF t, SF n)
150 {
151 	SF rv;
152 	dword T, N, K;
153 	int c;
154 
155 #define SHL(x,b) ((dword)(x) << b)
156 	T = SHL(1,55) | SHL(DMANTH(t), 48) |
157 	    SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4;
158 	N = SHL(1,55) | SHL(DMANTH(n), 48) |
159 	    SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4;
160 
161 	c = T > N;
162 	for (K = 0; (K & 0x80000000000000ULL) == 0; ) {
163 		if (T >= N) {
164 			T -= N;
165 			K |= 1;
166 		}
167 		T <<= 1;
168 		K <<= 1;
169 	}
170 	rv.fd1 = 0;
171 	DSIGNSET(rv, DSIGN(t) ^ DSIGN(n));
172 	DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c);
173 	DMANTHSET(rv, K >> 48);
174 	rv.fd2 = K >> 32;
175 	rv.fd3 = K >> 16;
176 	rv.fd4 = K;
177 	return rv;
178 }
179 
180 /*
181  * Negate a float number. Easy.
182  */
183 SF
soft_neg(SF sf)184 soft_neg(SF sf)
185 {
186 	int sign = DSIGN(sf) == 0;
187 	DSIGNSET(sf, sign);
188 	return sf;
189 }
190 
191 /*
192  * Return true if fp number is zero.
193  */
194 int
soft_isz(SF sf)195 soft_isz(SF sf)
196 {
197 	return (DEXP(sf) == 0);
198 }
199 
200 int
soft_cmp_eq(SF x1,SF x2)201 soft_cmp_eq(SF x1, SF x2)
202 {
203 	cerror("soft_cmp_eq");
204 	return 0;
205 }
206 
207 int
soft_cmp_ne(SF x1,SF x2)208 soft_cmp_ne(SF x1, SF x2)
209 {
210 	cerror("soft_cmp_ne");
211 	return 0;
212 }
213 
214 int
soft_cmp_le(SF x1,SF x2)215 soft_cmp_le(SF x1, SF x2)
216 {
217 	cerror("soft_cmp_le");
218 	return 0;
219 }
220 
221 int
soft_cmp_lt(SF x1,SF x2)222 soft_cmp_lt(SF x1, SF x2)
223 {
224 	cerror("soft_cmp_lt");
225 	return 0;
226 }
227 
228 int
soft_cmp_ge(SF x1,SF x2)229 soft_cmp_ge(SF x1, SF x2)
230 {
231 	cerror("soft_cmp_ge");
232 	return 0;
233 }
234 
235 int
soft_cmp_gt(SF x1,SF x2)236 soft_cmp_gt(SF x1, SF x2)
237 {
238 	cerror("soft_cmp_gt");
239 	return 0;
240 }
241 
242 /*
243  * Convert a fp number to a CONSZ.
244  */
245 CONSZ
soft_val(SF sf)246 soft_val(SF sf)
247 {
248 	CONSZ mant;
249 	int exp = DEXP(sf) - 128;
250 
251 	mant = SHL(1,55) | SHL(DMANTH(sf), 48) |
252             SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4;
253 
254 	while (exp < 0)
255 		mant >>= 1, exp++;
256 	while (exp > 0)
257 		mant <<= 1, exp--;
258 	return mant;
259 }
260 
261 SF
soft_plus(SF x1,SF x2)262 soft_plus(SF x1, SF x2)
263 {
264 	cerror("soft_plus");
265 	return x1;
266 }
267 
268 SF
soft_minus(SF x1,SF x2)269 soft_minus(SF x1, SF x2)
270 {
271 	cerror("soft_minus");
272 	return x1;
273 }
274 
275 /*
276  * Convert a hex constant to floating point number.
277  */
278 NODE *
fhexcon(char * s)279 fhexcon(char *s)
280 {
281 	cerror("fhexcon");
282 	return NULL;
283 }
284 
285 /*
286  * Convert a floating-point constant to D-float and store it in a NODE.
287  */
288 NODE *
floatcon(char * s)289 floatcon(char *s)
290 {
291 	NODE *p;
292 	dword mant;
293 	SF fl, flexp, exp5;
294 	int exp, negexp, bexp;
295 
296 	exp = 0;
297 	mant = 0;
298 #define ADDTO(sum, val) sum = sum * 10 + val - '0'
299 	for (; *s >= '0' && *s <= '9'; s++) {
300 		if (mant<MAXMANT)
301 			ADDTO(mant, *s);
302 		else
303 			exp++;
304 	}
305 	if (*s == '.') {
306 		for (s++; *s >= '0' && *s <= '9'; s++) {
307 			if (mant<MAXMANT) {
308 				ADDTO(mant, *s);
309 				exp--;
310 			}
311 		}
312 	}
313 
314 	if ((*s == 'E') || (*s == 'e')) {
315 		int eexp = 0, sign = 0;
316 		s++;
317 		if (*s == '+')
318 			s++;
319 		else if (*s=='-')
320 			sign = 1, s++;
321 
322 		for (; *s >= '0' && *s <= '9'; s++)
323 			ADDTO(eexp, *s);
324 		if (sign)
325 			eexp = -eexp;
326 		exp = exp + eexp;
327 	}
328 
329 	negexp = 1;
330 	if (exp<0) {
331 		negexp = -1;
332 		exp = -exp;
333 	}
334 
335 
336 	flexp = soft_cast(1, INT);
337 	exp5 = soft_cast(5, INT);
338 	bexp = exp;
339 	fl = soft_cast(mant, INT);
340 
341 	for (; exp; exp >>= 1) {
342 		if (exp&01)
343 			flexp = soft_mul(flexp, exp5);
344 		exp5 = soft_mul(exp5, exp5);
345 	}
346 	if (negexp<0)
347 		fl = soft_div(fl, flexp);
348 	else
349 		fl = soft_mul(fl, flexp);
350 
351 	DEXPSET(fl, DEXP(fl) + negexp*bexp);
352 	p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */
353 	p->n_dcon = fl;
354 	return p;
355 }
356 #else
357 #error missing softfloat definition
358 #endif
359 #endif
360