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