1222656Sed// This file is dual licensed under the MIT and the University of Illinois Open
2222656Sed// Source Licenses. See LICENSE.TXT for details.
3214152Sed
4214152Sed#include "../assembly.h"
5214152Sed
6214152Sed// float __floatundisf(du_int a);
7214152Sed
8214152Sed// Note that there is a hardware instruction, fildll, that does most of what
9214152Sed// this function needs to do.  However, because of our ia32 ABI, it will take
10214152Sed// a write-small read-large stall, so the software implementation here is
11214152Sed// actually several cycles faster.
12214152Sed
13214152Sed// This is a branch-free implementation.  A branchy implementation might be
14214152Sed// faster for the common case if you know something a priori about the input
15214152Sed// distribution.
16214152Sed
17214152Sed/* branch-free x87 implementation - one cycle slower than without x87.
18214152Sed
19214152Sed#ifdef __i386__
20214152Sed
21214152Sed.const
22214152Sed.align 3
23214152Sed
24214152Sed		.quad	0x43f0000000000000
25214152Sedtwop64:	.quad	0x0000000000000000
26214152Sed
27214152Sed#define			TWOp64			twop64-0b(%ecx,%eax,8)
28214152Sed
29214152Sed.text
30214152Sed.align 4
31214152SedDEFINE_COMPILERRT_FUNCTION(__floatundisf)
32214152Sed	movl		8(%esp),		%eax
33214152Sed	movd		8(%esp),		%xmm1
34214152Sed	movd		4(%esp),		%xmm0
35214152Sed	punpckldq	%xmm1,			%xmm0
36214152Sed	calll		0f
37214152Sed0:	popl		%ecx
38214152Sed	sarl		$31,			%eax
39214152Sed	movq		%xmm0,			4(%esp)
40214152Sed	fildll		4(%esp)
41214152Sed	faddl		TWOp64
42214152Sed	fstps		4(%esp)
43214152Sed	flds		4(%esp)
44214152Sed	ret
45214152Sed
46214152Sed#endif // __i386__
47214152Sed
48214152Sed*/
49214152Sed
50214152Sed/* branch-free, x87-free implementation - faster at the expense of code size */
51214152Sed
52214152Sed#ifdef __i386__
53214152Sed
54214152Sed#ifndef __ELF__
55214152Sed.const
56214152Sed.align 3
57214152Sed#else
58214152Sed.align 8
59214152Sed#endif
60214152Sedtwop52: .quad 0x4330000000000000
61214152Sed		.quad 0x0000000000000fff
62214152Sedsticky: .quad 0x0000000000000000
63214152Sed		.long 0x00000012
64214152Sedtwelve:	.long 0x00000000
65214152Sed
66214152Sed#define			TWOp52			twop52-0b(%ecx)
67214152Sed#define			STICKY			sticky-0b(%ecx,%eax,8)
68214152Sed
69214152Sed.text
70214152Sed.align 4
71214152SedDEFINE_COMPILERRT_FUNCTION(__floatundisf)
72214152Sed	movl		8(%esp),		%eax
73214152Sed	movd		8(%esp),		%xmm1
74214152Sed	movd		4(%esp),		%xmm0
75214152Sed	punpckldq	%xmm1,			%xmm0
76214152Sed
77214152Sed	calll		0f
78214152Sed0:	popl		%ecx
79214152Sed	shrl		%eax					// high 31 bits of input as sint32
80214152Sed	addl		$0x7ff80000,	%eax
81214152Sed	sarl		$31,			%eax	// (big input) ? -1 : 0
82214152Sed	movsd		STICKY,			%xmm1	// (big input) ? 0xfff : 0
83214152Sed	movl		$12,			%edx
84214152Sed	andl		%eax,			%edx	// (big input) ? 12 : 0
85214152Sed	movd		%edx,			%xmm3
86214152Sed	andpd		%xmm0,			%xmm1	// (big input) ? input & 0xfff : 0
87214152Sed	movsd		TWOp52,			%xmm2	// 0x1.0p52
88214152Sed	psrlq		%xmm3,			%xmm0	// (big input) ? input >> 12 : input
89214152Sed	orpd		%xmm2,			%xmm1	// 0x1.0p52 + ((big input) ? input & 0xfff : input)
90214152Sed	orpd		%xmm1,			%xmm0	// 0x1.0p52 + ((big input) ? (input >> 12 | input & 0xfff) : input)
91214152Sed	subsd		%xmm2,			%xmm0	// (double)((big input) ? (input >> 12 | input & 0xfff) : input)
92214152Sed	cvtsd2ss	%xmm0,			%xmm0	// (float)((big input) ? (input >> 12 | input & 0xfff) : input)
93214152Sed	pslld		$23,			%xmm3
94214152Sed	paddd		%xmm3,			%xmm0	// (float)input
95214152Sed	movd		%xmm0,			4(%esp)
96214152Sed	flds		4(%esp)
97214152Sed	ret
98214152Sed
99214152Sed#endif // __i386__
100