this repo has no description
1/*
2 * modfl.s
3 *
4 * by Ian Ollmann
5 *
6 * Copyright 2007 Apple Inc. All rights reserved.
7 *
8 */
9
10/*
11#include <machine/asm.h>
12#define LOCAL_STACK_SIZE 12
13#include "abi.h"
14
15#if defined( __LP64__ )
16 #define DEST_P %rdi
17 #define LOAD_DEST_P
18#else
19 #define DEST_P %eax
20 #define LOAD_DEST_P mov SECOND_ARG_OFFSET(STACKP), DEST_P
21#endif
22
23// I tried branch free code here. Alas there were so many special cases, that 2/3 of the code was patchup after the fidll instruction.
24// I've moved some special cases { 0, +-inf, NaN} out, which simplifies things quite a bit on any path you care to follow.
25
26ENTRY( modfl )
27 SUBP $LOCAL_STACK_SIZE, STACKP
28
29 LOAD_DEST_P
30 fldt FIRST_ARG_OFFSET(STACKP) // {x}
31 fld %st(0) // { x, x }
32 fabs // { |x|, x }
33 fld %st(0) // { |x|, |x|, x }
34 frndint // { |i|, |x|, x }
35 fucomi %st(1), %st(0) // { |i|, |x|, x }
36 jz 1f
37
38 //at this point we know we are a denormal or normal non-integer
39 //the next step is to truncate the value. We've already rounded it
40 //to an int. We just need to make sure that the right rounding direction
41 //applied
42 fld1 // { 1, |i|, |x|, x }
43 fldz // { 0, 1, |i|, |x|, x }
44 fcmovnbe %st(1), %st(0) // { 0 or 1, 1, |i|, |x|, x }
45 fstp %st(1) // { 0 or 1, |i|, |x|, x }
46 fsubrp %st(1), %st(0) // { |i|, |x|, x }
47
48 //fix the sign
49 fld %st(0) // { |i|, |i|, |x|, x }
50 fchs // { -|i|, |i|, |x|, x }
51 fxch %st(2) // { |x|, |i|, -|i|, x }
52 fucomip %st(3), %st(0) // { |i|, -|i|, x }
53 fcmovne %st(1), %st(0) // { i result, -|i|, x }
54 fstp %st(1) // { i result, x }
55
56 //get the fractional part and store the iresult
57 fsubr %st(0), %st(1) // { i result, f result }
58 fstpt (DEST_P) // { -|i|, f result }
59 ADDP $LOCAL_STACK_SIZE, STACKP
60 ret
61
621: //special case entry for NaN, inf and integers, including zero
63 fstp %st(0) // { |x|, x }
64 fstp %st(0) // { x }
65
66 //handle integers, Inf and zero
67 fldz // { 0, x }
68 fadd %st(0), %st(1) // { 0, x } silence NaN
69 fucomi %st(1), %st(0) // { 0, x }
70 fchs // { -0, x }
71 fldz // { 0, -0, x }
72 fcmovnbe %st(1), %st(0) // { +-0, -0, x }
73 fcmove %st(2), %st(0) // { f, -0, x }
74 fxch %st(2) // { x, -0, f }
75 fstpt (DEST_P) // { -0, f }
76 fstp %st(0) // { f }
77 ADDP $LOCAL_STACK_SIZE, STACKP
78 ret
79 */
80
81#include <machine/asm.h>
82#include "abi.h"
83
84#if defined( __i386__ )
85 #define RESULT_P %edx
86#else
87 #define RESULT_P %rdi
88#endif
89
90ENTRY( modfl )
91 xorl %eax, %eax
92 movw 8+FRAME_SIZE(STACKP), %ax //load sign + exponent of input
93 movl %eax, %ecx //set aside sign + exponent
94 andl $0x7fff, %eax // remove sign
95 addl $(16384-62), %eax
96 cmpw $(16383+16384-62), %ax
97 jl 1f
98
99 //common case of 1.0 <= x < 2**64
100 movq FRAME_SIZE( STACKP), %xmm0
101 subl $(16383+16384-62), %eax
102 movl $63, %edx
103 subl %eax, %edx
104 movd %edx, %xmm1
105#if defined( __i386__ )
106 movl 16+FRAME_SIZE( STACKP ), RESULT_P
107#endif
108 pcmpeqb %xmm2, %xmm2
109 psllq %xmm1, %xmm2
110 pand %xmm2, %xmm0
111 movq %xmm0, (RESULT_P)
112 movw %cx, 8(RESULT_P)
113 fldt FRAME_SIZE(STACKP) // { x, 0 }
114 fldt (RESULT_P) // { truncl(x), x }
115 fucomi %st(1), %st(0) // { truncl(x), x }
116 je 4f //if x is an integer goto 4
117
118 fsubr %st(0), %st(1) // { truncl(x), fract }
119 fstpt (RESULT_P) // { fract }
120 ret
121
1221:
123#if defined( __i386__ )
124 movl 16+FRAME_SIZE( STACKP ), RESULT_P
125#endif
126 jae 2f //Inf, NaN, big numbers go to 2
127
128 // |x| < 1.0
129 pxor %xmm0, %xmm0
130 movq %xmm0, (RESULT_P)
131 andl $0x8000, %ecx
132 movw %cx, 8(RESULT_P)
133 fldt FRAME_SIZE( STACKP )
134 ret
135
1362:
137 // |x| >= 2**63 or NAN
138 fldz // { 0 }
139 fldt FRAME_SIZE( STACKP ) // { x, 0 }
140 fucomi %st(1), %st(0)
141 jp 3f // do NaNs elsewhere
142 fstpt ( RESULT_P) // { 0 }
143 fchs // { -0 }
144 fldz // { 0, -0 }
145 fcmovb %st(1), %st(0) // { fract, -0 }
146 fstp %st(1)
147 ret
148
1493: //NaN // { x, 0 }
150 fld %st(0) // { x, x, 0 }
151 fstpt (RESULT_P) // { x, 0 }
152 fstp %st(1) // { x }s
153 ret
154
1554: //integer // { truncl(x), x }
156 fstpt (RESULT_P) // { x }
157 fldz // { 0, x }
158 fucomi %st(1), %st(0)
159 fchs // { -0, x }
160 fldz // { 0, -0, x }
161 fcmovnb %st(1), %st(0) // { fract, -0, x }
162 fstp %st(2) // { -0, fract }
163 fstp %st(0) // { fract }
164 ret