floatundisf.S revision 214152
1109998Smarkm// This file is distributed under the University of Illinois Open Source
2109998Smarkm// License. See LICENSE.TXT for details.
3109998Smarkm
4109998Smarkm#include "../assembly.h"
5109998Smarkm
6109998Smarkm// float __floatundisf(du_int a);
7109998Smarkm
8109998Smarkm// Note that there is a hardware instruction, fildll, that does most of what
9109998Smarkm// this function needs to do.  However, because of our ia32 ABI, it will take
10109998Smarkm// a write-small read-large stall, so the software implementation here is
11109998Smarkm// actually several cycles faster.
12109998Smarkm
13109998Smarkm// This is a branch-free implementation.  A branchy implementation might be
14109998Smarkm// faster for the common case if you know something a priori about the input
15109998Smarkm// distribution.
16109998Smarkm
17109998Smarkm/* branch-free x87 implementation - one cycle slower than without x87.
18109998Smarkm
19109998Smarkm#ifdef __i386__
20109998Smarkm
21109998Smarkm.const
22109998Smarkm.align 3
23109998Smarkm
24109998Smarkm		.quad	0x43f0000000000000
25109998Smarkmtwop64:	.quad	0x0000000000000000
26109998Smarkm
27109998Smarkm#define			TWOp64			twop64-0b(%ecx,%eax,8)
28109998Smarkm
29109998Smarkm.text
30109998Smarkm.align 4
31109998SmarkmDEFINE_COMPILERRT_FUNCTION(__floatundisf)
32109998Smarkm	movl		8(%esp),		%eax
33109998Smarkm	movd		8(%esp),		%xmm1
34109998Smarkm	movd		4(%esp),		%xmm0
35109998Smarkm	punpckldq	%xmm1,			%xmm0
36109998Smarkm	calll		0f
37109998Smarkm0:	popl		%ecx
38109998Smarkm	sarl		$31,			%eax
39109998Smarkm	movq		%xmm0,			4(%esp)
40109998Smarkm	fildll		4(%esp)
41109998Smarkm	faddl		TWOp64
42109998Smarkm	fstps		4(%esp)
43109998Smarkm	flds		4(%esp)
44109998Smarkm	ret
45109998Smarkm
46109998Smarkm#endif // __i386__
47109998Smarkm
48109998Smarkm*/
49109998Smarkm
50109998Smarkm/* branch-free, x87-free implementation - faster at the expense of code size */
51109998Smarkm
52109998Smarkm#ifdef __i386__
53109998Smarkm
54109998Smarkm#ifndef __ELF__
55160814Ssimon.const
56109998Smarkm.align 3
57111147Snectar#else
58109998Smarkm.align 8
59111147Snectar#endif
60111147Snectartwop52: .quad 0x4330000000000000
61109998Smarkm		.quad 0x0000000000000fff
62109998Smarkmsticky: .quad 0x0000000000000000
63109998Smarkm		.long 0x00000012
64109998Smarkmtwelve:	.long 0x00000000
65109998Smarkm
66109998Smarkm#define			TWOp52			twop52-0b(%ecx)
67109998Smarkm#define			STICKY			sticky-0b(%ecx,%eax,8)
68109998Smarkm
69109998Smarkm.text
70109998Smarkm.align 4
71109998SmarkmDEFINE_COMPILERRT_FUNCTION(__floatundisf)
72109998Smarkm	movl		8(%esp),		%eax
73109998Smarkm	movd		8(%esp),		%xmm1
74109998Smarkm	movd		4(%esp),		%xmm0
75109998Smarkm	punpckldq	%xmm1,			%xmm0
76109998Smarkm
77109998Smarkm	calll		0f
78109998Smarkm0:	popl		%ecx
79109998Smarkm	shrl		%eax					// high 31 bits of input as sint32
80109998Smarkm	addl		$0x7ff80000,	%eax
81109998Smarkm	sarl		$31,			%eax	// (big input) ? -1 : 0
82109998Smarkm	movsd		STICKY,			%xmm1	// (big input) ? 0xfff : 0
83109998Smarkm	movl		$12,			%edx
84109998Smarkm	andl		%eax,			%edx	// (big input) ? 12 : 0
85109998Smarkm	movd		%edx,			%xmm3
86109998Smarkm	andpd		%xmm0,			%xmm1	// (big input) ? input & 0xfff : 0
87109998Smarkm	movsd		TWOp52,			%xmm2	// 0x1.0p52
88109998Smarkm	psrlq		%xmm3,			%xmm0	// (big input) ? input >> 12 : input
89109998Smarkm	orpd		%xmm2,			%xmm1	// 0x1.0p52 + ((big input) ? input & 0xfff : input)
90109998Smarkm	orpd		%xmm1,			%xmm0	// 0x1.0p52 + ((big input) ? (input >> 12 | input & 0xfff) : input)
91109998Smarkm	subsd		%xmm2,			%xmm0	// (double)((big input) ? (input >> 12 | input & 0xfff) : input)
92109998Smarkm	cvtsd2ss	%xmm0,			%xmm0	// (float)((big input) ? (input >> 12 | input & 0xfff) : input)
93109998Smarkm	pslld		$23,			%xmm3
94109998Smarkm	paddd		%xmm3,			%xmm0	// (float)input
95109998Smarkm	movd		%xmm0,			4(%esp)
96109998Smarkm	flds		4(%esp)
97109998Smarkm	ret
98109998Smarkm
99109998Smarkm#endif // __i386__
100109998Smarkm