1132718Skan/* ieee754-df.S double-precision floating point support for ARM
2132718Skan
3169689Skan   Copyright (C) 2003, 2004, 2005  Free Software Foundation, Inc.
4132718Skan   Contributed by Nicolas Pitre (nico@cam.org)
5132718Skan
6132718Skan   This file is free software; you can redistribute it and/or modify it
7132718Skan   under the terms of the GNU General Public License as published by the
8132718Skan   Free Software Foundation; either version 2, or (at your option) any
9132718Skan   later version.
10132718Skan
11132718Skan   In addition to the permissions in the GNU General Public License, the
12132718Skan   Free Software Foundation gives you unlimited permission to link the
13132718Skan   compiled version of this file into combinations with other programs,
14132718Skan   and to distribute those combinations without any restriction coming
15132718Skan   from the use of this file.  (The General Public License restrictions
16132718Skan   do apply in other respects; for example, they cover modification of
17132718Skan   the file, and distribution when not linked into a combine
18132718Skan   executable.)
19132718Skan
20132718Skan   This file is distributed in the hope that it will be useful, but
21132718Skan   WITHOUT ANY WARRANTY; without even the implied warranty of
22132718Skan   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23132718Skan   General Public License for more details.
24132718Skan
25132718Skan   You should have received a copy of the GNU General Public License
26132718Skan   along with this program; see the file COPYING.  If not, write to
27169689Skan   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
28169689Skan   Boston, MA 02110-1301, USA.  */
29132718Skan
30132718Skan/*
31132718Skan * Notes:
32132718Skan *
33132718Skan * The goal of this code is to be as fast as possible.  This is
34132718Skan * not meant to be easy to understand for the casual reader.
35132718Skan * For slightly simpler code please see the single precision version
36132718Skan * of this file.
37132718Skan *
38132718Skan * Only the default rounding mode is intended for best performances.
39132718Skan * Exceptions aren't supported yet, but that can be added quite easily
40132718Skan * if necessary without impacting performances.
41132718Skan */
42132718Skan
43132718Skan
44132718Skan@ For FPA, float words are always big-endian.
45132718Skan@ For VFP, floats words follow the memory system mode.
46132718Skan#if defined(__VFP_FP__) && !defined(__ARMEB__)
47132718Skan#define xl r0
48132718Skan#define xh r1
49132718Skan#define yl r2
50132718Skan#define yh r3
51132718Skan#else
52132718Skan#define xh r0
53132718Skan#define xl r1
54132718Skan#define yh r2
55132718Skan#define yl r3
56132718Skan#endif
57132718Skan
58132718Skan
59132718Skan#ifdef L_negdf2
60132718Skan
61132718SkanARM_FUNC_START negdf2
62169689SkanARM_FUNC_ALIAS aeabi_dneg negdf2
63169689Skan
64132718Skan	@ flip sign bit
65132718Skan	eor	xh, xh, #0x80000000
66132718Skan	RET
67132718Skan
68169689Skan	FUNC_END aeabi_dneg
69132718Skan	FUNC_END negdf2
70132718Skan
71132718Skan#endif
72132718Skan
73132718Skan#ifdef L_addsubdf3
74132718Skan
75169689SkanARM_FUNC_START aeabi_drsub
76169689Skan
77169689Skan	eor	xh, xh, #0x80000000	@ flip sign bit of first arg
78169689Skan	b	1f
79169689Skan
80132718SkanARM_FUNC_START subdf3
81169689SkanARM_FUNC_ALIAS aeabi_dsub subdf3
82169689Skan
83169689Skan	eor	yh, yh, #0x80000000	@ flip sign bit of second arg
84169689Skan#if defined(__INTERWORKING_STUBS__)
85132718Skan	b	1f			@ Skip Thumb-code prologue
86132718Skan#endif
87132718Skan
88132718SkanARM_FUNC_START adddf3
89169689SkanARM_FUNC_ALIAS aeabi_dadd adddf3
90132718Skan
91169689Skan1:	stmfd	sp!, {r4, r5, lr}
92132718Skan
93169689Skan	@ Look for zeroes, equal values, INF, or NAN.
94169689Skan	mov	r4, xh, lsl #1
95169689Skan	mov	r5, yh, lsl #1
96169689Skan	teq	r4, r5
97169689Skan	teqeq	xl, yl
98169689Skan	orrnes	ip, r4, xl
99169689Skan	orrnes	ip, r5, yl
100169689Skan	mvnnes	ip, r4, asr #21
101169689Skan	mvnnes	ip, r5, asr #21
102169689Skan	beq	LSYM(Lad_s)
103132718Skan
104132718Skan	@ Compute exponent difference.  Make largest exponent in r4,
105132718Skan	@ corresponding arg in xh-xl, and positive exponent difference in r5.
106169689Skan	mov	r4, r4, lsr #21
107169689Skan	rsbs	r5, r4, r5, lsr #21
108132718Skan	rsblt	r5, r5, #0
109132718Skan	ble	1f
110132718Skan	add	r4, r4, r5
111132718Skan	eor	yl, xl, yl
112132718Skan	eor	yh, xh, yh
113132718Skan	eor	xl, yl, xl
114132718Skan	eor	xh, yh, xh
115132718Skan	eor	yl, xl, yl
116132718Skan	eor	yh, xh, yh
117132718Skan1:
118132718Skan	@ If exponent difference is too large, return largest argument
119132718Skan	@ already in xh-xl.  We need up to 54 bit to handle proper rounding
120132718Skan	@ of 0x1p54 - 1.1.
121169689Skan	cmp	r5, #54
122132718Skan	RETLDM	"r4, r5" hi
123132718Skan
124132718Skan	@ Convert mantissa to signed integer.
125132718Skan	tst	xh, #0x80000000
126169689Skan	mov	xh, xh, lsl #12
127169689Skan	mov	ip, #0x00100000
128169689Skan	orr	xh, ip, xh, lsr #12
129132718Skan	beq	1f
130132718Skan	rsbs	xl, xl, #0
131132718Skan	rsc	xh, xh, #0
132132718Skan1:
133132718Skan	tst	yh, #0x80000000
134169689Skan	mov	yh, yh, lsl #12
135169689Skan	orr	yh, ip, yh, lsr #12
136132718Skan	beq	1f
137132718Skan	rsbs	yl, yl, #0
138132718Skan	rsc	yh, yh, #0
139132718Skan1:
140132718Skan	@ If exponent == difference, one or both args were denormalized.
141132718Skan	@ Since this is not common case, rescale them off line.
142132718Skan	teq	r4, r5
143132718Skan	beq	LSYM(Lad_d)
144132718SkanLSYM(Lad_x):
145132718Skan
146169689Skan	@ Compensate for the exponent overlapping the mantissa MSB added later
147169689Skan	sub	r4, r4, #1
148169689Skan
149169689Skan	@ Shift yh-yl right per r5, add to xh-xl, keep leftover bits into ip.
150169689Skan	rsbs	lr, r5, #32
151169689Skan	blt	1f
152132718Skan	mov	ip, yl, lsl lr
153169689Skan	adds	xl, xl, yl, lsr r5
154169689Skan	adc	xh, xh, #0
155169689Skan	adds	xl, xl, yh, lsl lr
156169689Skan	adcs	xh, xh, yh, asr r5
157169689Skan	b	2f
158169689Skan1:	sub	r5, r5, #32
159132718Skan	add	lr, lr, #32
160132718Skan	cmp	yl, #1
161169689Skan	mov	ip, yh, lsl lr
162169689Skan	orrcs	ip, ip, #2		@ 2 not 1, to allow lsr #1 later
163169689Skan	adds	xl, xl, yh, asr r5
164169689Skan	adcs	xh, xh, yh, asr #31
165169689Skan2:
166132718Skan	@ We now have a result in xh-xl-ip.
167169689Skan	@ Keep absolute value in xh-xl-ip, sign in r5 (the n bit was set above)
168169689Skan	and	r5, xh, #0x80000000
169132718Skan	bpl	LSYM(Lad_p)
170132718Skan	rsbs	ip, ip, #0
171132718Skan	rscs	xl, xl, #0
172132718Skan	rsc	xh, xh, #0
173132718Skan
174132718Skan	@ Determine how to normalize the result.
175132718SkanLSYM(Lad_p):
176132718Skan	cmp	xh, #0x00100000
177169689Skan	bcc	LSYM(Lad_a)
178132718Skan	cmp	xh, #0x00200000
179169689Skan	bcc	LSYM(Lad_e)
180132718Skan
181132718Skan	@ Result needs to be shifted right.
182132718Skan	movs	xh, xh, lsr #1
183132718Skan	movs	xl, xl, rrx
184169689Skan	mov	ip, ip, rrx
185169689Skan	add	r4, r4, #1
186132718Skan
187169689Skan	@ Make sure we did not bust our exponent.
188169689Skan	mov	r2, r4, lsl #21
189169689Skan	cmn	r2, #(2 << 21)
190169689Skan	bcs	LSYM(Lad_o)
191169689Skan
192132718Skan	@ Our result is now properly aligned into xh-xl, remaining bits in ip.
193132718Skan	@ Round with MSB of ip. If halfway between two numbers, round towards
194132718Skan	@ LSB of xl = 0.
195132718Skan	@ Pack final result together.
196132718SkanLSYM(Lad_e):
197169689Skan	cmp	ip, #0x80000000
198169689Skan	moveqs	ip, xl, lsr #1
199169689Skan	adcs	xl, xl, #0
200169689Skan	adc	xh, xh, r4, lsl #20
201132718Skan	orr	xh, xh, r5
202132718Skan	RETLDM	"r4, r5"
203132718Skan
204169689Skan	@ Result must be shifted left and exponent adjusted.
205169689SkanLSYM(Lad_a):
206169689Skan	movs	ip, ip, lsl #1
207169689Skan	adcs	xl, xl, xl
208169689Skan	adc	xh, xh, xh
209169689Skan	tst	xh, #0x00100000
210169689Skan	sub	r4, r4, #1
211169689Skan	bne	LSYM(Lad_e)
212169689Skan
213169689Skan	@ No rounding necessary since ip will always be 0 at this point.
214132718SkanLSYM(Lad_l):
215169689Skan
216132718Skan#if __ARM_ARCH__ < 5
217132718Skan
218132718Skan	teq	xh, #0
219169689Skan	movne	r3, #20
220169689Skan	moveq	r3, #52
221132718Skan	moveq	xh, xl
222132718Skan	moveq	xl, #0
223132718Skan	mov	r2, xh
224169689Skan	cmp	r2, #(1 << 16)
225169689Skan	movhs	r2, r2, lsr #16
226169689Skan	subhs	r3, r3, #16
227169689Skan	cmp	r2, #(1 << 8)
228169689Skan	movhs	r2, r2, lsr #8
229169689Skan	subhs	r3, r3, #8
230169689Skan	cmp	r2, #(1 << 4)
231169689Skan	movhs	r2, r2, lsr #4
232169689Skan	subhs	r3, r3, #4
233169689Skan	cmp	r2, #(1 << 2)
234169689Skan	subhs	r3, r3, #2
235169689Skan	sublo	r3, r3, r2, lsr #1
236169689Skan	sub	r3, r3, r2, lsr #3
237132718Skan
238132718Skan#else
239132718Skan
240132718Skan	teq	xh, #0
241132718Skan	moveq	xh, xl
242132718Skan	moveq	xl, #0
243132718Skan	clz	r3, xh
244132718Skan	addeq	r3, r3, #32
245132718Skan	sub	r3, r3, #11
246132718Skan
247132718Skan#endif
248132718Skan
249132718Skan	@ determine how to shift the value.
250132718Skan	subs	r2, r3, #32
251132718Skan	bge	2f
252132718Skan	adds	r2, r2, #12
253132718Skan	ble	1f
254132718Skan
255132718Skan	@ shift value left 21 to 31 bits, or actually right 11 to 1 bits
256132718Skan	@ since a register switch happened above.
257132718Skan	add	ip, r2, #20
258132718Skan	rsb	r2, r2, #12
259132718Skan	mov	xl, xh, lsl ip
260132718Skan	mov	xh, xh, lsr r2
261132718Skan	b	3f
262132718Skan
263132718Skan	@ actually shift value left 1 to 20 bits, which might also represent
264132718Skan	@ 32 to 52 bits if counting the register switch that happened earlier.
265132718Skan1:	add	r2, r2, #20
266132718Skan2:	rsble	ip, r2, #32
267132718Skan	mov	xh, xh, lsl r2
268132718Skan	orrle	xh, xh, xl, lsr ip
269132718Skan	movle	xl, xl, lsl r2
270132718Skan
271132718Skan	@ adjust exponent accordingly.
272169689Skan3:	subs	r4, r4, r3
273169689Skan	addge	xh, xh, r4, lsl #20
274169689Skan	orrge	xh, xh, r5
275169689Skan	RETLDM	"r4, r5" ge
276132718Skan
277132718Skan	@ Exponent too small, denormalize result.
278132718Skan	@ Find out proper shift value.
279169689Skan	mvn	r4, r4
280169689Skan	subs	r4, r4, #31
281132718Skan	bge	2f
282132718Skan	adds	r4, r4, #12
283132718Skan	bgt	1f
284132718Skan
285132718Skan	@ shift result right of 1 to 20 bits, sign is in r5.
286132718Skan	add	r4, r4, #20
287132718Skan	rsb	r2, r4, #32
288132718Skan	mov	xl, xl, lsr r4
289132718Skan	orr	xl, xl, xh, lsl r2
290132718Skan	orr	xh, r5, xh, lsr r4
291132718Skan	RETLDM	"r4, r5"
292132718Skan
293132718Skan	@ shift result right of 21 to 31 bits, or left 11 to 1 bits after
294132718Skan	@ a register switch from xh to xl.
295132718Skan1:	rsb	r4, r4, #12
296132718Skan	rsb	r2, r4, #32
297132718Skan	mov	xl, xl, lsr r2
298132718Skan	orr	xl, xl, xh, lsl r4
299132718Skan	mov	xh, r5
300132718Skan	RETLDM	"r4, r5"
301132718Skan
302132718Skan	@ Shift value right of 32 to 64 bits, or 0 to 32 bits after a switch
303132718Skan	@ from xh to xl.
304132718Skan2:	mov	xl, xh, lsr r4
305132718Skan	mov	xh, r5
306132718Skan	RETLDM	"r4, r5"
307132718Skan
308132718Skan	@ Adjust exponents for denormalized arguments.
309169689Skan	@ Note that r4 must not remain equal to 0.
310132718SkanLSYM(Lad_d):
311132718Skan	teq	r4, #0
312169689Skan	eor	yh, yh, #0x00100000
313132718Skan	eoreq	xh, xh, #0x00100000
314169689Skan	addeq	r4, r4, #1
315169689Skan	subne	r5, r5, #1
316132718Skan	b	LSYM(Lad_x)
317132718Skan
318169689Skan
319169689SkanLSYM(Lad_s):
320169689Skan	mvns	ip, r4, asr #21
321169689Skan	mvnnes	ip, r5, asr #21
322169689Skan	beq	LSYM(Lad_i)
323169689Skan
324169689Skan	teq	r4, r5
325169689Skan	teqeq	xl, yl
326169689Skan	beq	1f
327169689Skan
328169689Skan	@ Result is x + 0.0 = x or 0.0 + y = y.
329169689Skan	orrs	ip, r4, xl
330169689Skan	moveq	xh, yh
331169689Skan	moveq	xl, yl
332169689Skan	RETLDM	"r4, r5"
333169689Skan
334169689Skan1:	teq	xh, yh
335169689Skan
336169689Skan	@ Result is x - x = 0.
337132718Skan	movne	xh, #0
338169689Skan	movne	xl, #0
339169689Skan	RETLDM	"r4, r5" ne
340132718Skan
341169689Skan	@ Result is x + x = 2x.
342169689Skan	movs	ip, r4, lsr #21
343169689Skan	bne	2f
344169689Skan	movs	xl, xl, lsl #1
345169689Skan	adcs	xh, xh, xh
346169689Skan	orrcs	xh, xh, #0x80000000
347169689Skan	RETLDM	"r4, r5"
348169689Skan2:	adds	r4, r4, #(2 << 21)
349169689Skan	addcc	xh, xh, #(1 << 20)
350169689Skan	RETLDM	"r4, r5" cc
351169689Skan	and	r5, xh, #0x80000000
352169689Skan
353132718Skan	@ Overflow: return INF.
354132718SkanLSYM(Lad_o):
355132718Skan	orr	xh, r5, #0x7f000000
356132718Skan	orr	xh, xh, #0x00f00000
357132718Skan	mov	xl, #0
358132718Skan	RETLDM	"r4, r5"
359132718Skan
360132718Skan	@ At least one of x or y is INF/NAN.
361132718Skan	@   if xh-xl != INF/NAN: return yh-yl (which is INF/NAN)
362132718Skan	@   if yh-yl != INF/NAN: return xh-xl (which is INF/NAN)
363132718Skan	@   if either is NAN: return NAN
364132718Skan	@   if opposite sign: return NAN
365169689Skan	@   otherwise return xh-xl (which is INF or -INF)
366132718SkanLSYM(Lad_i):
367169689Skan	mvns	ip, r4, asr #21
368132718Skan	movne	xh, yh
369132718Skan	movne	xl, yl
370169689Skan	mvneqs	ip, r5, asr #21
371169689Skan	movne	yh, xh
372169689Skan	movne	yl, xl
373132718Skan	orrs	r4, xl, xh, lsl #12
374169689Skan	orreqs	r5, yl, yh, lsl #12
375132718Skan	teqeq	xh, yh
376169689Skan	orrne	xh, xh, #0x00080000	@ quiet NAN
377132718Skan	RETLDM	"r4, r5"
378132718Skan
379169689Skan	FUNC_END aeabi_dsub
380132718Skan	FUNC_END subdf3
381169689Skan	FUNC_END aeabi_dadd
382132718Skan	FUNC_END adddf3
383132718Skan
384132718SkanARM_FUNC_START floatunsidf
385169689SkanARM_FUNC_ALIAS aeabi_ui2d floatunsidf
386169689Skan
387132718Skan	teq	r0, #0
388132718Skan	moveq	r1, #0
389132718Skan	RETc(eq)
390132718Skan	stmfd	sp!, {r4, r5, lr}
391169689Skan	mov	r4, #0x400		@ initial exponent
392169689Skan	add	r4, r4, #(52-1 - 1)
393132718Skan	mov	r5, #0			@ sign bit is 0
394169689Skan	.ifnc	xl, r0
395132718Skan	mov	xl, r0
396169689Skan	.endif
397132718Skan	mov	xh, #0
398132718Skan	b	LSYM(Lad_l)
399132718Skan
400169689Skan	FUNC_END aeabi_ui2d
401132718Skan	FUNC_END floatunsidf
402132718Skan
403132718SkanARM_FUNC_START floatsidf
404169689SkanARM_FUNC_ALIAS aeabi_i2d floatsidf
405169689Skan
406132718Skan	teq	r0, #0
407132718Skan	moveq	r1, #0
408132718Skan	RETc(eq)
409132718Skan	stmfd	sp!, {r4, r5, lr}
410169689Skan	mov	r4, #0x400		@ initial exponent
411169689Skan	add	r4, r4, #(52-1 - 1)
412132718Skan	ands	r5, r0, #0x80000000	@ sign bit in r5
413132718Skan	rsbmi	r0, r0, #0		@ absolute value
414169689Skan	.ifnc	xl, r0
415132718Skan	mov	xl, r0
416169689Skan	.endif
417132718Skan	mov	xh, #0
418132718Skan	b	LSYM(Lad_l)
419132718Skan
420169689Skan	FUNC_END aeabi_i2d
421132718Skan	FUNC_END floatsidf
422132718Skan
423132718SkanARM_FUNC_START extendsfdf2
424169689SkanARM_FUNC_ALIAS aeabi_f2d extendsfdf2
425169689Skan
426169689Skan	movs	r2, r0, lsl #1		@ toss sign bit
427132718Skan	mov	xh, r2, asr #3		@ stretch exponent
428132718Skan	mov	xh, xh, rrx		@ retrieve sign bit
429132718Skan	mov	xl, r2, lsl #28		@ retrieve remaining bits
430169689Skan	andnes	r3, r2, #0xff000000	@ isolate exponent
431169689Skan	teqne	r3, #0xff000000		@ if not 0, check if INF or NAN
432132718Skan	eorne	xh, xh, #0x38000000	@ fixup exponent otherwise.
433169689Skan	RETc(ne)			@ and return it.
434132718Skan
435169689Skan	teq	r2, #0			@ if actually 0
436169689Skan	teqne	r3, #0xff000000		@ or INF or NAN
437169689Skan	RETc(eq)			@ we are done already.
438132718Skan
439169689Skan	@ value was denormalized.  We can normalize it now.
440132718Skan	stmfd	sp!, {r4, r5, lr}
441169689Skan	mov	r4, #0x380		@ setup corresponding exponent
442132718Skan	and	r5, xh, #0x80000000	@ move sign bit in r5
443132718Skan	bic	xh, xh, #0x80000000
444132718Skan	b	LSYM(Lad_l)
445132718Skan
446169689Skan	FUNC_END aeabi_f2d
447132718Skan	FUNC_END extendsfdf2
448132718Skan
449169689SkanARM_FUNC_START floatundidf
450169689SkanARM_FUNC_ALIAS aeabi_ul2d floatundidf
451169689Skan
452169689Skan	orrs	r2, r0, r1
453169689Skan#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
454169689Skan	mvfeqd	f0, #0.0
455169689Skan#endif
456169689Skan	RETc(eq)
457169689Skan
458169689Skan#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
459169689Skan	@ For hard FPA code we want to return via the tail below so that
460169689Skan	@ we can return the result in f0 as well as in r0/r1 for backwards
461169689Skan	@ compatibility.
462169689Skan	adr	ip, LSYM(f0_ret)
463169689Skan	stmfd	sp!, {r4, r5, ip, lr}
464169689Skan#else
465169689Skan	stmfd	sp!, {r4, r5, lr}
466169689Skan#endif
467169689Skan
468169689Skan	mov	r5, #0
469169689Skan	b	2f
470169689Skan
471169689SkanARM_FUNC_START floatdidf
472169689SkanARM_FUNC_ALIAS aeabi_l2d floatdidf
473169689Skan
474169689Skan	orrs	r2, r0, r1
475169689Skan#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
476169689Skan	mvfeqd	f0, #0.0
477169689Skan#endif
478169689Skan	RETc(eq)
479169689Skan
480169689Skan#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
481169689Skan	@ For hard FPA code we want to return via the tail below so that
482169689Skan	@ we can return the result in f0 as well as in r0/r1 for backwards
483169689Skan	@ compatibility.
484169689Skan	adr	ip, LSYM(f0_ret)
485169689Skan	stmfd	sp!, {r4, r5, ip, lr}
486169689Skan#else
487169689Skan	stmfd	sp!, {r4, r5, lr}
488169689Skan#endif
489169689Skan
490169689Skan	ands	r5, ah, #0x80000000	@ sign bit in r5
491169689Skan	bpl	2f
492169689Skan	rsbs	al, al, #0
493169689Skan	rsc	ah, ah, #0
494169689Skan2:
495169689Skan	mov	r4, #0x400		@ initial exponent
496169689Skan	add	r4, r4, #(52-1 - 1)
497169689Skan
498169689Skan	@ FPA little-endian: must swap the word order.
499169689Skan	.ifnc	xh, ah
500169689Skan	mov	ip, al
501169689Skan	mov	xh, ah
502169689Skan	mov	xl, ip
503169689Skan	.endif
504169689Skan
505169689Skan	movs	ip, xh, lsr #22
506169689Skan	beq	LSYM(Lad_p)
507169689Skan
508169689Skan	@ The value is too big.  Scale it down a bit...
509169689Skan	mov	r2, #3
510169689Skan	movs	ip, ip, lsr #3
511169689Skan	addne	r2, r2, #3
512169689Skan	movs	ip, ip, lsr #3
513169689Skan	addne	r2, r2, #3
514169689Skan	add	r2, r2, ip, lsr #3
515169689Skan
516169689Skan	rsb	r3, r2, #32
517169689Skan	mov	ip, xl, lsl r3
518169689Skan	mov	xl, xl, lsr r2
519169689Skan	orr	xl, xl, xh, lsl r3
520169689Skan	mov	xh, xh, lsr r2
521169689Skan	add	r4, r4, r2
522169689Skan	b	LSYM(Lad_p)
523169689Skan
524169689Skan#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
525169689Skan
526169689Skan	@ Legacy code expects the result to be returned in f0.  Copy it
527169689Skan	@ there as well.
528169689SkanLSYM(f0_ret):
529169689Skan	stmfd	sp!, {r0, r1}
530169689Skan	ldfd	f0, [sp], #8
531169689Skan	RETLDM
532169689Skan
533169689Skan#endif
534169689Skan
535169689Skan	FUNC_END floatdidf
536169689Skan	FUNC_END aeabi_l2d
537169689Skan	FUNC_END floatundidf
538169689Skan	FUNC_END aeabi_ul2d
539169689Skan
540132718Skan#endif /* L_addsubdf3 */
541132718Skan
542132718Skan#ifdef L_muldivdf3
543132718Skan
544132718SkanARM_FUNC_START muldf3
545169689SkanARM_FUNC_ALIAS aeabi_dmul muldf3
546132718Skan	stmfd	sp!, {r4, r5, r6, lr}
547132718Skan
548169689Skan	@ Mask out exponents, trap any zero/denormal/INF/NAN.
549169689Skan	mov	ip, #0xff
550169689Skan	orr	ip, ip, #0x700
551169689Skan	ands	r4, ip, xh, lsr #20
552169689Skan	andnes	r5, ip, yh, lsr #20
553169689Skan	teqne	r4, ip
554132718Skan	teqne	r5, ip
555169689Skan	bleq	LSYM(Lml_s)
556132718Skan
557169689Skan	@ Add exponents together
558169689Skan	add	r4, r4, r5
559132718Skan
560169689Skan	@ Determine final sign.
561169689Skan	eor	r6, xh, yh
562132718Skan
563132718Skan	@ Convert mantissa to unsigned integer.
564169689Skan	@ If power of two, branch to a separate path.
565169689Skan	bic	xh, xh, ip, lsl #21
566169689Skan	bic	yh, yh, ip, lsl #21
567169689Skan	orrs	r5, xl, xh, lsl #12
568169689Skan	orrnes	r5, yl, yh, lsl #12
569132718Skan	orr	xh, xh, #0x00100000
570132718Skan	orr	yh, yh, #0x00100000
571169689Skan	beq	LSYM(Lml_1)
572132718Skan
573132718Skan#if __ARM_ARCH__ < 4
574132718Skan
575169689Skan	@ Put sign bit in r6, which will be restored in yl later.
576169689Skan	and   r6, r6, #0x80000000
577169689Skan
578132718Skan	@ Well, no way to make it shorter without the umull instruction.
579169689Skan	stmfd	sp!, {r6, r7, r8, r9, sl, fp}
580132718Skan	mov	r7, xl, lsr #16
581132718Skan	mov	r8, yl, lsr #16
582132718Skan	mov	r9, xh, lsr #16
583132718Skan	mov	sl, yh, lsr #16
584132718Skan	bic	xl, xl, r7, lsl #16
585132718Skan	bic	yl, yl, r8, lsl #16
586132718Skan	bic	xh, xh, r9, lsl #16
587132718Skan	bic	yh, yh, sl, lsl #16
588132718Skan	mul	ip, xl, yl
589132718Skan	mul	fp, xl, r8
590132718Skan	mov	lr, #0
591132718Skan	adds	ip, ip, fp, lsl #16
592132718Skan	adc	lr, lr, fp, lsr #16
593132718Skan	mul	fp, r7, yl
594132718Skan	adds	ip, ip, fp, lsl #16
595132718Skan	adc	lr, lr, fp, lsr #16
596132718Skan	mul	fp, xl, sl
597132718Skan	mov	r5, #0
598132718Skan	adds	lr, lr, fp, lsl #16
599132718Skan	adc	r5, r5, fp, lsr #16
600132718Skan	mul	fp, r7, yh
601132718Skan	adds	lr, lr, fp, lsl #16
602132718Skan	adc	r5, r5, fp, lsr #16
603132718Skan	mul	fp, xh, r8
604132718Skan	adds	lr, lr, fp, lsl #16
605132718Skan	adc	r5, r5, fp, lsr #16
606132718Skan	mul	fp, r9, yl
607132718Skan	adds	lr, lr, fp, lsl #16
608132718Skan	adc	r5, r5, fp, lsr #16
609132718Skan	mul	fp, xh, sl
610132718Skan	mul	r6, r9, sl
611132718Skan	adds	r5, r5, fp, lsl #16
612132718Skan	adc	r6, r6, fp, lsr #16
613132718Skan	mul	fp, r9, yh
614132718Skan	adds	r5, r5, fp, lsl #16
615132718Skan	adc	r6, r6, fp, lsr #16
616132718Skan	mul	fp, xl, yh
617132718Skan	adds	lr, lr, fp
618132718Skan	mul	fp, r7, sl
619132718Skan	adcs	r5, r5, fp
620132718Skan	mul	fp, xh, yl
621132718Skan	adc	r6, r6, #0
622132718Skan	adds	lr, lr, fp
623132718Skan	mul	fp, r9, r8
624132718Skan	adcs	r5, r5, fp
625132718Skan	mul	fp, r7, r8
626132718Skan	adc	r6, r6, #0
627132718Skan	adds	lr, lr, fp
628132718Skan	mul	fp, xh, yh
629132718Skan	adcs	r5, r5, fp
630132718Skan	adc	r6, r6, #0
631169689Skan	ldmfd	sp!, {yl, r7, r8, r9, sl, fp}
632132718Skan
633132718Skan#else
634132718Skan
635169689Skan	@ Here is the actual multiplication.
636132718Skan	umull	ip, lr, xl, yl
637132718Skan	mov	r5, #0
638169689Skan	umlal	lr, r5, xh, yl
639169689Skan	and	yl, r6, #0x80000000
640132718Skan	umlal	lr, r5, xl, yh
641132718Skan	mov	r6, #0
642132718Skan	umlal	r5, r6, xh, yh
643132718Skan
644132718Skan#endif
645132718Skan
646132718Skan	@ The LSBs in ip are only significant for the final rounding.
647169689Skan	@ Fold them into lr.
648132718Skan	teq	ip, #0
649132718Skan	orrne	lr, lr, #1
650132718Skan
651169689Skan	@ Adjust result upon the MSB position.
652169689Skan	sub	r4, r4, #0xff
653169689Skan	cmp	r6, #(1 << (20-11))
654169689Skan	sbc	r4, r4, #0x300
655169689Skan	bcs	1f
656169689Skan	movs	lr, lr, lsl #1
657169689Skan	adcs	r5, r5, r5
658169689Skan	adc	r6, r6, r6
659132718Skan1:
660169689Skan	@ Shift to final position, add sign to result.
661169689Skan	orr	xh, yl, r6, lsl #11
662169689Skan	orr	xh, xh, r5, lsr #21
663169689Skan	mov	xl, r5, lsl #11
664169689Skan	orr	xl, xl, lr, lsr #21
665169689Skan	mov	lr, lr, lsl #11
666132718Skan
667169689Skan	@ Check exponent range for under/overflow.
668169689Skan	subs	ip, r4, #(254 - 1)
669169689Skan	cmphi	ip, #0x700
670169689Skan	bhi	LSYM(Lml_u)
671132718Skan
672169689Skan	@ Round the result, merge final exponent.
673169689Skan	cmp	lr, #0x80000000
674169689Skan	moveqs	lr, xl, lsr #1
675169689Skan	adcs	xl, xl, #0
676169689Skan	adc	xh, xh, r4, lsl #20
677132718Skan	RETLDM	"r4, r5, r6"
678132718Skan
679169689Skan	@ Multiplication by 0x1p*: let''s shortcut a lot of code.
680169689SkanLSYM(Lml_1):
681169689Skan	and	r6, r6, #0x80000000
682169689Skan	orr	xh, r6, xh
683169689Skan	orr	xl, xl, yl
684132718Skan	eor	xh, xh, yh
685169689Skan	subs	r4, r4, ip, lsr #1
686169689Skan	rsbgts	r5, r4, ip
687169689Skan	orrgt	xh, xh, r4, lsl #20
688169689Skan	RETLDM	"r4, r5, r6" gt
689132718Skan
690169689Skan	@ Under/overflow: fix things up for the code below.
691169689Skan	orr	xh, xh, #0x00100000
692169689Skan	mov	lr, #0
693169689Skan	subs	r4, r4, #1
694169689Skan
695169689SkanLSYM(Lml_u):
696169689Skan	@ Overflow?
697169689Skan	bgt	LSYM(Lml_o)
698169689Skan
699132718Skan	@ Check if denormalized result is possible, otherwise return signed 0.
700169689Skan	cmn	r4, #(53 + 1)
701132718Skan	movle	xl, #0
702132718Skan	bicle	xh, xh, #0x7fffffff
703132718Skan	RETLDM	"r4, r5, r6" le
704132718Skan
705132718Skan	@ Find out proper shift value.
706169689Skan	rsb	r4, r4, #0
707169689Skan	subs	r4, r4, #32
708132718Skan	bge	2f
709132718Skan	adds	r4, r4, #12
710132718Skan	bgt	1f
711132718Skan
712132718Skan	@ shift result right of 1 to 20 bits, preserve sign bit, round, etc.
713132718Skan	add	r4, r4, #20
714132718Skan	rsb	r5, r4, #32
715132718Skan	mov	r3, xl, lsl r5
716132718Skan	mov	xl, xl, lsr r4
717132718Skan	orr	xl, xl, xh, lsl r5
718169689Skan	and	r2, xh, #0x80000000
719169689Skan	bic	xh, xh, #0x80000000
720132718Skan	adds	xl, xl, r3, lsr #31
721169689Skan	adc	xh, r2, xh, lsr r4
722169689Skan	orrs	lr, lr, r3, lsl #1
723169689Skan	biceq	xl, xl, r3, lsr #31
724132718Skan	RETLDM	"r4, r5, r6"
725132718Skan
726132718Skan	@ shift result right of 21 to 31 bits, or left 11 to 1 bits after
727132718Skan	@ a register switch from xh to xl. Then round.
728132718Skan1:	rsb	r4, r4, #12
729132718Skan	rsb	r5, r4, #32
730132718Skan	mov	r3, xl, lsl r4
731132718Skan	mov	xl, xl, lsr r5
732132718Skan	orr	xl, xl, xh, lsl r4
733132718Skan	bic	xh, xh, #0x7fffffff
734132718Skan	adds	xl, xl, r3, lsr #31
735132718Skan	adc	xh, xh, #0
736169689Skan	orrs	lr, lr, r3, lsl #1
737169689Skan	biceq	xl, xl, r3, lsr #31
738132718Skan	RETLDM	"r4, r5, r6"
739132718Skan
740132718Skan	@ Shift value right of 32 to 64 bits, or 0 to 32 bits after a switch
741132718Skan	@ from xh to xl.  Leftover bits are in r3-r6-lr for rounding.
742132718Skan2:	rsb	r5, r4, #32
743169689Skan	orr	lr, lr, xl, lsl r5
744132718Skan	mov	r3, xl, lsr r4
745132718Skan	orr	r3, r3, xh, lsl r5
746132718Skan	mov	xl, xh, lsr r4
747132718Skan	bic	xh, xh, #0x7fffffff
748132718Skan	bic	xl, xl, xh, lsr r4
749132718Skan	add	xl, xl, r3, lsr #31
750169689Skan	orrs	lr, lr, r3, lsl #1
751169689Skan	biceq	xl, xl, r3, lsr #31
752132718Skan	RETLDM	"r4, r5, r6"
753132718Skan
754132718Skan	@ One or both arguments are denormalized.
755132718Skan	@ Scale them leftwards and preserve sign bit.
756132718SkanLSYM(Lml_d):
757132718Skan	teq	r4, #0
758132718Skan	bne	2f
759132718Skan	and	r6, xh, #0x80000000
760132718Skan1:	movs	xl, xl, lsl #1
761169689Skan	adc	xh, xh, xh
762132718Skan	tst	xh, #0x00100000
763169689Skan	subeq	r4, r4, #1
764132718Skan	beq	1b
765132718Skan	orr	xh, xh, r6
766132718Skan	teq	r5, #0
767169689Skan	movne	pc, lr
768132718Skan2:	and	r6, yh, #0x80000000
769132718Skan3:	movs	yl, yl, lsl #1
770169689Skan	adc	yh, yh, yh
771132718Skan	tst	yh, #0x00100000
772169689Skan	subeq	r5, r5, #1
773132718Skan	beq	3b
774132718Skan	orr	yh, yh, r6
775169689Skan	mov	pc, lr
776132718Skan
777132718SkanLSYM(Lml_s):
778169689Skan	@ Isolate the INF and NAN cases away
779169689Skan	teq	r4, ip
780169689Skan	and	r5, ip, yh, lsr #20
781169689Skan	teqne	r5, ip
782169689Skan	beq	1f
783169689Skan
784169689Skan	@ Here, one or more arguments are either denormalized or zero.
785132718Skan	orrs	r6, xl, xh, lsl #1
786132718Skan	orrnes	r6, yl, yh, lsl #1
787169689Skan	bne	LSYM(Lml_d)
788169689Skan
789169689Skan	@ Result is 0, but determine sign anyway.
790169689SkanLSYM(Lml_z):
791169689Skan	eor	xh, xh, yh
792169689Skan	bic	xh, xh, #0x7fffffff
793169689Skan	mov	xl, #0
794169689Skan	RETLDM	"r4, r5, r6"
795169689Skan
796169689Skan1:	@ One or both args are INF or NAN.
797169689Skan	orrs	r6, xl, xh, lsl #1
798169689Skan	moveq	xl, yl
799169689Skan	moveq	xh, yh
800169689Skan	orrnes	r6, yl, yh, lsl #1
801132718Skan	beq	LSYM(Lml_n)		@ 0 * INF or INF * 0 -> NAN
802132718Skan	teq	r4, ip
803132718Skan	bne	1f
804132718Skan	orrs	r6, xl, xh, lsl #12
805132718Skan	bne	LSYM(Lml_n)		@ NAN * <anything> -> NAN
806132718Skan1:	teq	r5, ip
807132718Skan	bne	LSYM(Lml_i)
808132718Skan	orrs	r6, yl, yh, lsl #12
809169689Skan	movne	xl, yl
810169689Skan	movne	xh, yh
811132718Skan	bne	LSYM(Lml_n)		@ <anything> * NAN -> NAN
812132718Skan
813132718Skan	@ Result is INF, but we need to determine its sign.
814132718SkanLSYM(Lml_i):
815132718Skan	eor	xh, xh, yh
816132718Skan
817132718Skan	@ Overflow: return INF (sign already in xh).
818132718SkanLSYM(Lml_o):
819132718Skan	and	xh, xh, #0x80000000
820132718Skan	orr	xh, xh, #0x7f000000
821132718Skan	orr	xh, xh, #0x00f00000
822132718Skan	mov	xl, #0
823132718Skan	RETLDM	"r4, r5, r6"
824132718Skan
825169689Skan	@ Return a quiet NAN.
826132718SkanLSYM(Lml_n):
827169689Skan	orr	xh, xh, #0x7f000000
828132718Skan	orr	xh, xh, #0x00f80000
829132718Skan	RETLDM	"r4, r5, r6"
830132718Skan
831169689Skan	FUNC_END aeabi_dmul
832132718Skan	FUNC_END muldf3
833132718Skan
834132718SkanARM_FUNC_START divdf3
835169689SkanARM_FUNC_ALIAS aeabi_ddiv divdf3
836169689Skan
837132718Skan	stmfd	sp!, {r4, r5, r6, lr}
838132718Skan
839169689Skan	@ Mask out exponents, trap any zero/denormal/INF/NAN.
840169689Skan	mov	ip, #0xff
841169689Skan	orr	ip, ip, #0x700
842169689Skan	ands	r4, ip, xh, lsr #20
843169689Skan	andnes	r5, ip, yh, lsr #20
844169689Skan	teqne	r4, ip
845132718Skan	teqne	r5, ip
846169689Skan	bleq	LSYM(Ldv_s)
847132718Skan
848169689Skan	@ Substract divisor exponent from dividend''s.
849169689Skan	sub	r4, r4, r5
850132718Skan
851132718Skan	@ Preserve final sign into lr.
852132718Skan	eor	lr, xh, yh
853132718Skan
854132718Skan	@ Convert mantissa to unsigned integer.
855132718Skan	@ Dividend -> r5-r6, divisor -> yh-yl.
856169689Skan	orrs	r5, yl, yh, lsl #12
857169689Skan	mov	xh, xh, lsl #12
858169689Skan	beq	LSYM(Ldv_1)
859169689Skan	mov	yh, yh, lsl #12
860132718Skan	mov	r5, #0x10000000
861132718Skan	orr	yh, r5, yh, lsr #4
862132718Skan	orr	yh, yh, yl, lsr #24
863169689Skan	mov	yl, yl, lsl #8
864132718Skan	orr	r5, r5, xh, lsr #4
865132718Skan	orr	r5, r5, xl, lsr #24
866132718Skan	mov	r6, xl, lsl #8
867132718Skan
868132718Skan	@ Initialize xh with final sign bit.
869132718Skan	and	xh, lr, #0x80000000
870132718Skan
871132718Skan	@ Ensure result will land to known bit position.
872169689Skan	@ Apply exponent bias accordingly.
873132718Skan	cmp	r5, yh
874132718Skan	cmpeq	r6, yl
875169689Skan	adc	r4, r4, #(255 - 2)
876169689Skan	add	r4, r4, #0x300
877132718Skan	bcs	1f
878132718Skan	movs	yh, yh, lsr #1
879132718Skan	mov	yl, yl, rrx
880132718Skan1:
881132718Skan	@ Perform first substraction to align result to a nibble.
882132718Skan	subs	r6, r6, yl
883132718Skan	sbc	r5, r5, yh
884132718Skan	movs	yh, yh, lsr #1
885132718Skan	mov	yl, yl, rrx
886132718Skan	mov	xl, #0x00100000
887132718Skan	mov	ip, #0x00080000
888132718Skan
889132718Skan	@ The actual division loop.
890132718Skan1:	subs	lr, r6, yl
891132718Skan	sbcs	lr, r5, yh
892132718Skan	subcs	r6, r6, yl
893132718Skan	movcs	r5, lr
894132718Skan	orrcs	xl, xl, ip
895132718Skan	movs	yh, yh, lsr #1
896132718Skan	mov	yl, yl, rrx
897132718Skan	subs	lr, r6, yl
898132718Skan	sbcs	lr, r5, yh
899132718Skan	subcs	r6, r6, yl
900132718Skan	movcs	r5, lr
901132718Skan	orrcs	xl, xl, ip, lsr #1
902132718Skan	movs	yh, yh, lsr #1
903132718Skan	mov	yl, yl, rrx
904132718Skan	subs	lr, r6, yl
905132718Skan	sbcs	lr, r5, yh
906132718Skan	subcs	r6, r6, yl
907132718Skan	movcs	r5, lr
908132718Skan	orrcs	xl, xl, ip, lsr #2
909132718Skan	movs	yh, yh, lsr #1
910132718Skan	mov	yl, yl, rrx
911132718Skan	subs	lr, r6, yl
912132718Skan	sbcs	lr, r5, yh
913132718Skan	subcs	r6, r6, yl
914132718Skan	movcs	r5, lr
915132718Skan	orrcs	xl, xl, ip, lsr #3
916132718Skan
917132718Skan	orrs	lr, r5, r6
918132718Skan	beq	2f
919132718Skan	mov	r5, r5, lsl #4
920132718Skan	orr	r5, r5, r6, lsr #28
921132718Skan	mov	r6, r6, lsl #4
922132718Skan	mov	yh, yh, lsl #3
923132718Skan	orr	yh, yh, yl, lsr #29
924132718Skan	mov	yl, yl, lsl #3
925132718Skan	movs	ip, ip, lsr #4
926132718Skan	bne	1b
927132718Skan
928132718Skan	@ We are done with a word of the result.
929132718Skan	@ Loop again for the low word if this pass was for the high word.
930132718Skan	tst	xh, #0x00100000
931132718Skan	bne	3f
932132718Skan	orr	xh, xh, xl
933132718Skan	mov	xl, #0
934132718Skan	mov	ip, #0x80000000
935132718Skan	b	1b
936132718Skan2:
937132718Skan	@ Be sure result starts in the high word.
938132718Skan	tst	xh, #0x00100000
939132718Skan	orreq	xh, xh, xl
940132718Skan	moveq	xl, #0
941132718Skan3:
942169689Skan	@ Check exponent range for under/overflow.
943169689Skan	subs	ip, r4, #(254 - 1)
944169689Skan	cmphi	ip, #0x700
945169689Skan	bhi	LSYM(Lml_u)
946132718Skan
947169689Skan	@ Round the result, merge final exponent.
948132718Skan	subs	ip, r5, yh
949132718Skan	subeqs	ip, r6, yl
950169689Skan	moveqs	ip, xl, lsr #1
951132718Skan	adcs	xl, xl, #0
952169689Skan	adc	xh, xh, r4, lsl #20
953132718Skan	RETLDM	"r4, r5, r6"
954132718Skan
955132718Skan	@ Division by 0x1p*: shortcut a lot of code.
956132718SkanLSYM(Ldv_1):
957132718Skan	and	lr, lr, #0x80000000
958132718Skan	orr	xh, lr, xh, lsr #12
959169689Skan	adds	r4, r4, ip, lsr #1
960169689Skan	rsbgts	r5, r4, ip
961169689Skan	orrgt	xh, xh, r4, lsl #20
962132718Skan	RETLDM	"r4, r5, r6" gt
963132718Skan
964132718Skan	orr	xh, xh, #0x00100000
965132718Skan	mov	lr, #0
966169689Skan	subs	r4, r4, #1
967169689Skan	b	LSYM(Lml_u)
968132718Skan
969169689Skan	@ Result mightt need to be denormalized: put remainder bits
970169689Skan	@ in lr for rounding considerations.
971132718SkanLSYM(Ldv_u):
972132718Skan	orr	lr, r5, r6
973169689Skan	b	LSYM(Lml_u)
974132718Skan
975132718Skan	@ One or both arguments is either INF, NAN or zero.
976132718SkanLSYM(Ldv_s):
977169689Skan	and	r5, ip, yh, lsr #20
978132718Skan	teq	r4, ip
979132718Skan	teqeq	r5, ip
980132718Skan	beq	LSYM(Lml_n)		@ INF/NAN / INF/NAN -> NAN
981132718Skan	teq	r4, ip
982132718Skan	bne	1f
983132718Skan	orrs	r4, xl, xh, lsl #12
984132718Skan	bne	LSYM(Lml_n)		@ NAN / <anything> -> NAN
985169689Skan	teq	r5, ip
986169689Skan	bne	LSYM(Lml_i)		@ INF / <anything> -> INF
987169689Skan	mov	xl, yl
988169689Skan	mov	xh, yh
989169689Skan	b	LSYM(Lml_n)		@ INF / (INF or NAN) -> NAN
990132718Skan1:	teq	r5, ip
991132718Skan	bne	2f
992132718Skan	orrs	r5, yl, yh, lsl #12
993169689Skan	beq	LSYM(Lml_z)		@ <anything> / INF -> 0
994169689Skan	mov	xl, yl
995169689Skan	mov	xh, yh
996169689Skan	b	LSYM(Lml_n)		@ <anything> / NAN -> NAN
997169689Skan2:	@ If both are nonzero, we need to normalize and resume above.
998169689Skan	orrs	r6, xl, xh, lsl #1
999169689Skan	orrnes	r6, yl, yh, lsl #1
1000169689Skan	bne	LSYM(Lml_d)
1001169689Skan	@ One or both arguments are 0.
1002132718Skan	orrs	r4, xl, xh, lsl #1
1003132718Skan	bne	LSYM(Lml_i)		@ <non_zero> / 0 -> INF
1004132718Skan	orrs	r5, yl, yh, lsl #1
1005132718Skan	bne	LSYM(Lml_z)		@ 0 / <non_zero> -> 0
1006132718Skan	b	LSYM(Lml_n)		@ 0 / 0 -> NAN
1007132718Skan
1008169689Skan	FUNC_END aeabi_ddiv
1009132718Skan	FUNC_END divdf3
1010132718Skan
1011132718Skan#endif /* L_muldivdf3 */
1012132718Skan
1013132718Skan#ifdef L_cmpdf2
1014132718Skan
1015169689Skan@ Note: only r0 (return value) and ip are clobbered here.
1016169689Skan
1017132718SkanARM_FUNC_START gtdf2
1018132718SkanARM_FUNC_ALIAS gedf2 gtdf2
1019132718Skan	mov	ip, #-1
1020132718Skan	b	1f
1021132718Skan
1022132718SkanARM_FUNC_START ltdf2
1023132718SkanARM_FUNC_ALIAS ledf2 ltdf2
1024132718Skan	mov	ip, #1
1025132718Skan	b	1f
1026132718Skan
1027132718SkanARM_FUNC_START cmpdf2
1028132718SkanARM_FUNC_ALIAS nedf2 cmpdf2
1029132718SkanARM_FUNC_ALIAS eqdf2 cmpdf2
1030132718Skan	mov	ip, #1			@ how should we specify unordered here?
1031132718Skan
1032169689Skan1:	str	ip, [sp, #-4]
1033132718Skan
1034132718Skan	@ Trap any INF/NAN first.
1035169689Skan	mov	ip, xh, lsl #1
1036169689Skan	mvns	ip, ip, asr #21
1037169689Skan	mov	ip, yh, lsl #1
1038169689Skan	mvnnes	ip, ip, asr #21
1039132718Skan	beq	3f
1040132718Skan
1041132718Skan	@ Test for equality.
1042132718Skan	@ Note that 0.0 is equal to -0.0.
1043132718Skan2:	orrs	ip, xl, xh, lsl #1	@ if x == 0.0 or -0.0
1044132718Skan	orreqs	ip, yl, yh, lsl #1	@ and y == 0.0 or -0.0
1045132718Skan	teqne	xh, yh			@ or xh == yh
1046132718Skan	teqeq	xl, yl			@ and xl == yl
1047132718Skan	moveq	r0, #0			@ then equal.
1048169689Skan	RETc(eq)
1049132718Skan
1050169689Skan	@ Clear C flag
1051169689Skan	cmn	r0, #0
1052169689Skan
1053169689Skan	@ Compare sign,
1054132718Skan	teq	xh, yh
1055132718Skan
1056169689Skan	@ Compare values if same sign
1057169689Skan	cmppl	xh, yh
1058169689Skan	cmpeq	xl, yl
1059132718Skan
1060169689Skan	@ Result:
1061132718Skan	movcs	r0, yh, asr #31
1062132718Skan	mvncc	r0, yh, asr #31
1063132718Skan	orr	r0, r0, #1
1064169689Skan	RET
1065132718Skan
1066132718Skan	@ Look for a NAN.
1067169689Skan3:	mov	ip, xh, lsl #1
1068169689Skan	mvns	ip, ip, asr #21
1069132718Skan	bne	4f
1070169689Skan	orrs	ip, xl, xh, lsl #12
1071132718Skan	bne	5f			@ x is NAN
1072169689Skan4:	mov	ip, yh, lsl #1
1073169689Skan	mvns	ip, ip, asr #21
1074132718Skan	bne	2b
1075169689Skan	orrs	ip, yl, yh, lsl #12
1076132718Skan	beq	2b			@ y is not NAN
1077169689Skan5:	ldr	r0, [sp, #-4]		@ unordered return code
1078169689Skan	RET
1079132718Skan
1080132718Skan	FUNC_END gedf2
1081132718Skan	FUNC_END gtdf2
1082132718Skan	FUNC_END ledf2
1083132718Skan	FUNC_END ltdf2
1084132718Skan	FUNC_END nedf2
1085132718Skan	FUNC_END eqdf2
1086132718Skan	FUNC_END cmpdf2
1087132718Skan
1088169689SkanARM_FUNC_START aeabi_cdrcmple
1089169689Skan
1090169689Skan	mov	ip, r0
1091169689Skan	mov	r0, r2
1092169689Skan	mov	r2, ip
1093169689Skan	mov	ip, r1
1094169689Skan	mov	r1, r3
1095169689Skan	mov	r3, ip
1096169689Skan	b	6f
1097169689Skan
1098169689SkanARM_FUNC_START aeabi_cdcmpeq
1099169689SkanARM_FUNC_ALIAS aeabi_cdcmple aeabi_cdcmpeq
1100169689Skan
1101169689Skan	@ The status-returning routines are required to preserve all
1102169689Skan	@ registers except ip, lr, and cpsr.
1103169689Skan6:	stmfd	sp!, {r0, lr}
1104169689Skan	ARM_CALL cmpdf2
1105169689Skan	@ Set the Z flag correctly, and the C flag unconditionally.
1106169689Skan	cmp	 r0, #0
1107169689Skan	@ Clear the C flag if the return value was -1, indicating
1108169689Skan	@ that the first operand was smaller than the second.
1109169689Skan	cmnmi	 r0, #0
1110169689Skan	RETLDM   "r0"
1111169689Skan
1112169689Skan	FUNC_END aeabi_cdcmple
1113169689Skan	FUNC_END aeabi_cdcmpeq
1114169689Skan	FUNC_END aeabi_cdrcmple
1115169689Skan
1116169689SkanARM_FUNC_START	aeabi_dcmpeq
1117169689Skan
1118169689Skan	str	lr, [sp, #-8]!
1119169689Skan	ARM_CALL aeabi_cdcmple
1120169689Skan	moveq	r0, #1	@ Equal to.
1121169689Skan	movne	r0, #0	@ Less than, greater than, or unordered.
1122169689Skan	RETLDM
1123169689Skan
1124169689Skan	FUNC_END aeabi_dcmpeq
1125169689Skan
1126169689SkanARM_FUNC_START	aeabi_dcmplt
1127169689Skan
1128169689Skan	str	lr, [sp, #-8]!
1129169689Skan	ARM_CALL aeabi_cdcmple
1130169689Skan	movcc	r0, #1	@ Less than.
1131169689Skan	movcs	r0, #0	@ Equal to, greater than, or unordered.
1132169689Skan	RETLDM
1133169689Skan
1134169689Skan	FUNC_END aeabi_dcmplt
1135169689Skan
1136169689SkanARM_FUNC_START	aeabi_dcmple
1137169689Skan
1138169689Skan	str	lr, [sp, #-8]!
1139169689Skan	ARM_CALL aeabi_cdcmple
1140169689Skan	movls	r0, #1  @ Less than or equal to.
1141169689Skan	movhi	r0, #0	@ Greater than or unordered.
1142169689Skan	RETLDM
1143169689Skan
1144169689Skan	FUNC_END aeabi_dcmple
1145169689Skan
1146169689SkanARM_FUNC_START	aeabi_dcmpge
1147169689Skan
1148169689Skan	str	lr, [sp, #-8]!
1149169689Skan	ARM_CALL aeabi_cdrcmple
1150169689Skan	movls	r0, #1	@ Operand 2 is less than or equal to operand 1.
1151169689Skan	movhi	r0, #0	@ Operand 2 greater than operand 1, or unordered.
1152169689Skan	RETLDM
1153169689Skan
1154169689Skan	FUNC_END aeabi_dcmpge
1155169689Skan
1156169689SkanARM_FUNC_START	aeabi_dcmpgt
1157169689Skan
1158169689Skan	str	lr, [sp, #-8]!
1159169689Skan	ARM_CALL aeabi_cdrcmple
1160169689Skan	movcc	r0, #1	@ Operand 2 is less than operand 1.
1161169689Skan	movcs	r0, #0  @ Operand 2 is greater than or equal to operand 1,
1162169689Skan			@ or they are unordered.
1163169689Skan	RETLDM
1164169689Skan
1165169689Skan	FUNC_END aeabi_dcmpgt
1166169689Skan
1167132718Skan#endif /* L_cmpdf2 */
1168132718Skan
1169132718Skan#ifdef L_unorddf2
1170132718Skan
1171132718SkanARM_FUNC_START unorddf2
1172169689SkanARM_FUNC_ALIAS aeabi_dcmpun unorddf2
1173169689Skan
1174169689Skan	mov	ip, xh, lsl #1
1175169689Skan	mvns	ip, ip, asr #21
1176132718Skan	bne	1f
1177169689Skan	orrs	ip, xl, xh, lsl #12
1178132718Skan	bne	3f			@ x is NAN
1179169689Skan1:	mov	ip, yh, lsl #1
1180169689Skan	mvns	ip, ip, asr #21
1181132718Skan	bne	2f
1182169689Skan	orrs	ip, yl, yh, lsl #12
1183132718Skan	bne	3f			@ y is NAN
1184132718Skan2:	mov	r0, #0			@ arguments are ordered.
1185169689Skan	RET
1186132718Skan
1187132718Skan3:	mov	r0, #1			@ arguments are unordered.
1188169689Skan	RET
1189132718Skan
1190169689Skan	FUNC_END aeabi_dcmpun
1191132718Skan	FUNC_END unorddf2
1192132718Skan
1193132718Skan#endif /* L_unorddf2 */
1194132718Skan
1195132718Skan#ifdef L_fixdfsi
1196132718Skan
1197132718SkanARM_FUNC_START fixdfsi
1198169689SkanARM_FUNC_ALIAS aeabi_d2iz fixdfsi
1199132718Skan
1200132718Skan	@ check exponent range.
1201169689Skan	mov	r2, xh, lsl #1
1202169689Skan	adds	r2, r2, #(1 << 21)
1203169689Skan	bcs	2f			@ value is INF or NAN
1204169689Skan	bpl	1f			@ value is too small
1205169689Skan	mov	r3, #(0xfffffc00 + 31)
1206169689Skan	subs	r2, r3, r2, asr #21
1207169689Skan	bls	3f			@ value is too large
1208132718Skan
1209169689Skan	@ scale value
1210169689Skan	mov	r3, xh, lsl #11
1211169689Skan	orr	r3, r3, #0x80000000
1212169689Skan	orr	r3, r3, xl, lsr #21
1213169689Skan	tst	xh, #0x80000000		@ the sign bit
1214169689Skan	mov	r0, r3, lsr r2
1215132718Skan	rsbne	r0, r0, #0
1216132718Skan	RET
1217132718Skan
1218132718Skan1:	mov	r0, #0
1219132718Skan	RET
1220132718Skan
1221132718Skan2:	orrs	xl, xl, xh, lsl #12
1222169689Skan	bne	4f			@ x is NAN.
1223169689Skan3:	ands	r0, xh, #0x80000000	@ the sign bit
1224132718Skan	moveq	r0, #0x7fffffff		@ maximum signed positive si
1225132718Skan	RET
1226132718Skan
1227132718Skan4:	mov	r0, #0			@ How should we convert NAN?
1228132718Skan	RET
1229132718Skan
1230169689Skan	FUNC_END aeabi_d2iz
1231132718Skan	FUNC_END fixdfsi
1232132718Skan
1233132718Skan#endif /* L_fixdfsi */
1234132718Skan
1235132718Skan#ifdef L_fixunsdfsi
1236132718Skan
1237132718SkanARM_FUNC_START fixunsdfsi
1238169689SkanARM_FUNC_ALIAS aeabi_d2uiz fixunsdfsi
1239132718Skan
1240132718Skan	@ check exponent range.
1241169689Skan	movs	r2, xh, lsl #1
1242169689Skan	bcs	1f			@ value is negative
1243169689Skan	adds	r2, r2, #(1 << 21)
1244169689Skan	bcs	2f			@ value is INF or NAN
1245169689Skan	bpl	1f			@ value is too small
1246169689Skan	mov	r3, #(0xfffffc00 + 31)
1247169689Skan	subs	r2, r3, r2, asr #21
1248169689Skan	bmi	3f			@ value is too large
1249132718Skan
1250169689Skan	@ scale value
1251169689Skan	mov	r3, xh, lsl #11
1252169689Skan	orr	r3, r3, #0x80000000
1253169689Skan	orr	r3, r3, xl, lsr #21
1254169689Skan	mov	r0, r3, lsr r2
1255132718Skan	RET
1256132718Skan
1257132718Skan1:	mov	r0, #0
1258132718Skan	RET
1259132718Skan
1260132718Skan2:	orrs	xl, xl, xh, lsl #12
1261132718Skan	bne	4f			@ value is NAN.
1262132718Skan3:	mov	r0, #0xffffffff		@ maximum unsigned si
1263132718Skan	RET
1264132718Skan
1265132718Skan4:	mov	r0, #0			@ How should we convert NAN?
1266132718Skan	RET
1267132718Skan
1268169689Skan	FUNC_END aeabi_d2uiz
1269132718Skan	FUNC_END fixunsdfsi
1270132718Skan
1271132718Skan#endif /* L_fixunsdfsi */
1272132718Skan
1273132718Skan#ifdef L_truncdfsf2
1274132718Skan
1275132718SkanARM_FUNC_START truncdfsf2
1276169689SkanARM_FUNC_ALIAS aeabi_d2f truncdfsf2
1277169689Skan
1278132718Skan	@ check exponent range.
1279169689Skan	mov	r2, xh, lsl #1
1280169689Skan	subs	r3, r2, #((1023 - 127) << 21)
1281169689Skan	subcss	ip, r3, #(1 << 21)
1282169689Skan	rsbcss	ip, ip, #(254 << 21)
1283169689Skan	bls	2f			@ value is out of range
1284132718Skan
1285169689Skan1:	@ shift and round mantissa
1286169689Skan	and	ip, xh, #0x80000000
1287169689Skan	mov	r2, xl, lsl #3
1288169689Skan	orr	xl, ip, xl, lsr #29
1289169689Skan	cmp	r2, #0x80000000
1290169689Skan	adc	r0, xl, r3, lsl #2
1291169689Skan	biceq	r0, r0, #1
1292169689Skan	RET
1293132718Skan
1294169689Skan2:	@ either overflow or underflow
1295169689Skan	tst	xh, #0x40000000
1296169689Skan	bne	3f			@ overflow
1297132718Skan
1298169689Skan	@ check if denormalized value is possible
1299169689Skan	adds	r2, r3, #(23 << 21)
1300169689Skan	andlt	r0, xh, #0x80000000	@ too small, return signed 0.
1301169689Skan	RETc(lt)
1302132718Skan
1303169689Skan	@ denormalize value so we can resume with the code above afterwards.
1304169689Skan	orr	xh, xh, #0x00100000
1305169689Skan	mov	r2, r2, lsr #21
1306169689Skan	rsb	r2, r2, #24
1307169689Skan	rsb	ip, r2, #32
1308169689Skan	movs	r3, xl, lsl ip
1309169689Skan	mov	xl, xl, lsr r2
1310169689Skan	orrne	xl, xl, #1		@ fold r3 for rounding considerations.
1311169689Skan	mov	r3, xh, lsl #11
1312169689Skan	mov	r3, r3, lsr #11
1313169689Skan	orr	xl, xl, r3, lsl ip
1314169689Skan	mov	r3, r3, lsr r2
1315169689Skan	mov	r3, r3, lsl #1
1316169689Skan	b	1b
1317132718Skan
1318169689Skan3:	@ chech for NAN
1319169689Skan	mvns	r3, r2, asr #21
1320169689Skan	bne	5f			@ simple overflow
1321169689Skan	orrs	r3, xl, xh, lsl #12
1322132718Skan	movne	r0, #0x7f000000
1323132718Skan	orrne	r0, r0, #0x00c00000
1324132718Skan	RETc(ne)			@ return NAN
1325132718Skan
1326169689Skan5:	@ return INF with sign
1327132718Skan	and	r0, xh, #0x80000000
1328132718Skan	orr	r0, r0, #0x7f000000
1329132718Skan	orr	r0, r0, #0x00800000
1330132718Skan	RET
1331132718Skan
1332169689Skan	FUNC_END aeabi_d2f
1333132718Skan	FUNC_END truncdfsf2
1334132718Skan
1335132718Skan#endif /* L_truncdfsf2 */
1336