1 /* Helper macros for x86 libm functions.
2    Copyright (C) 2015-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #ifndef _I386_MATH_ASM_H
20 #define _I386_MATH_ASM_H 1
21 
22 /* Remove excess range and precision by storing a value on the stack
23    and loading it back.  */
24 #define FLT_NARROW_EVAL				\
25 	subl	$4, %esp;			\
26 	cfi_adjust_cfa_offset (4);		\
27 	fstps	(%esp);				\
28 	flds	(%esp);				\
29 	addl	$4, %esp;			\
30 	cfi_adjust_cfa_offset (-4);
31 #define DBL_NARROW_EVAL				\
32 	subl	$8, %esp;			\
33 	cfi_adjust_cfa_offset (8);		\
34 	fstpl	(%esp);				\
35 	fldl	(%esp);				\
36 	addl	$8, %esp;			\
37 	cfi_adjust_cfa_offset (-8);
38 
39 /* Define constants for the minimum value of a floating-point
40    type.  */
41 #define DEFINE_FLT_MIN				\
42 	.section .rodata.cst4,"aM",@progbits,4;	\
43 	.p2align 2;				\
44 	.type flt_min,@object;			\
45 flt_min:					\
46 	.byte 0, 0, 0x80, 0;			\
47 	.size flt_min, .-flt_min;
48 #define DEFINE_DBL_MIN				\
49 	.section .rodata.cst8,"aM",@progbits,8;	\
50 	.p2align 3;				\
51 	.type dbl_min,@object;			\
52 dbl_min:					\
53 	.byte 0, 0, 0, 0, 0, 0, 0x10, 0;	\
54 	.size dbl_min, .-dbl_min;
55 #define DEFINE_LDBL_MIN					\
56 	.section .rodata.cst16,"aM",@progbits,16;	\
57 	.p2align 4;					\
58 	.type ldbl_min,@object;				\
59 ldbl_min:						\
60 	.byte 0, 0, 0, 0, 0, 0, 0, 0x80, 0x1, 0;	\
61 	.byte 0, 0, 0, 0, 0, 0;				\
62 	.size ldbl_min, .-ldbl_min;
63 
64 /* Remove excess range and precision by storing a value on the stack
65    and loading it back.  The value is given to be nonnegative or NaN;
66    if it is subnormal, also force an underflow exception.  The
67    relevant constant for the minimum of the type must have been
68    defined, the MO macro must have been defined for access to memory
69    operands, and, if PIC, the PIC register must have been loaded.  */
70 #define FLT_NARROW_EVAL_UFLOW_NONNEG_NAN	\
71 	subl	$4, %esp;			\
72 	cfi_adjust_cfa_offset (4);		\
73 	flds	MO(flt_min);			\
74 	fld	%st(1);				\
75 	fucompp;				\
76 	fnstsw;					\
77 	sahf;					\
78 	jnc 6424f;				\
79 	fld	%st(0);				\
80 	fmul	%st(0);				\
81 	fstps	(%esp);				\
82 6424:	fstps	(%esp);				\
83 	flds	(%esp);				\
84 	addl	$4, %esp;			\
85 	cfi_adjust_cfa_offset (-4);
86 #define DBL_NARROW_EVAL_UFLOW_NONNEG_NAN	\
87 	subl	$8, %esp;			\
88 	cfi_adjust_cfa_offset (8);		\
89 	fldl	MO(dbl_min);			\
90 	fld	%st(1);				\
91 	fucompp;				\
92 	fnstsw;					\
93 	sahf;					\
94 	jnc 6453f;				\
95 	fld	%st(0);				\
96 	fmul	%st(0);				\
97 	fstpl	(%esp);				\
98 6453:	fstpl	(%esp);				\
99 	fldl	(%esp);				\
100 	addl	$8, %esp;			\
101 	cfi_adjust_cfa_offset (-8);
102 
103 /* Likewise, but the argument is not a NaN (so fcom instructions,
104    which support memory operands, can be used).  */
105 #define FLT_NARROW_EVAL_UFLOW_NONNEG		\
106 	subl	$4, %esp;			\
107 	cfi_adjust_cfa_offset (4);		\
108 	fcoms	MO(flt_min);			\
109 	fnstsw;					\
110 	sahf;					\
111 	jnc 6424f;				\
112 	fld	%st(0);				\
113 	fmul	%st(0);				\
114 	fstps	(%esp);				\
115 6424:	fstps	(%esp);				\
116 	flds	(%esp);				\
117 	addl	$4, %esp;			\
118 	cfi_adjust_cfa_offset (-4);
119 #define DBL_NARROW_EVAL_UFLOW_NONNEG		\
120 	subl	$8, %esp;			\
121 	cfi_adjust_cfa_offset (8);		\
122 	fcoml	MO(dbl_min);			\
123 	fnstsw;					\
124 	sahf;					\
125 	jnc 6453f;				\
126 	fld	%st(0);				\
127 	fmul	%st(0);				\
128 	fstpl	(%esp);				\
129 6453:	fstpl	(%esp);				\
130 	fldl	(%esp);				\
131 	addl	$8, %esp;			\
132 	cfi_adjust_cfa_offset (-8);
133 
134 /* Likewise, but the non-NaN argument may be negative.  */
135 #define FLT_NARROW_EVAL_UFLOW_NONNAN		\
136 	subl	$4, %esp;			\
137 	cfi_adjust_cfa_offset (4);		\
138 	fld	%st(0);				\
139 	fabs;					\
140 	fcomps	MO(flt_min);			\
141 	fnstsw;					\
142 	sahf;					\
143 	jnc 6424f;				\
144 	fld	%st(0);				\
145 	fmul	%st(0);				\
146 	fstps	(%esp);				\
147 6424:	fstps	(%esp);				\
148 	flds	(%esp);				\
149 	addl	$4, %esp;			\
150 	cfi_adjust_cfa_offset (-4);
151 #define DBL_NARROW_EVAL_UFLOW_NONNAN		\
152 	subl	$8, %esp;			\
153 	cfi_adjust_cfa_offset (8);		\
154 	fld	%st(0);				\
155 	fabs;					\
156 	fcompl	MO(dbl_min);			\
157 	fnstsw;					\
158 	sahf;					\
159 	jnc 6453f;				\
160 	fld	%st(0);				\
161 	fmul	%st(0);				\
162 	fstpl	(%esp);				\
163 6453:	fstpl	(%esp);				\
164 	fldl	(%esp);				\
165 	addl	$8, %esp;			\
166 	cfi_adjust_cfa_offset (-8);
167 
168 /* Force an underflow exception if the given value is subnormal.  The
169    relevant constant for the minimum of the type must have been
170    defined, the MO macro must have been defined for access to memory
171    operands, and, if PIC, the PIC register must have been loaded.  */
172 #define FLT_CHECK_FORCE_UFLOW			\
173 	flds	MO(flt_min);			\
174 	fld	%st(1);				\
175 	fabs;					\
176 	fucompp;				\
177 	fnstsw;					\
178 	sahf;					\
179 	jnc 6424f;				\
180 	subl	$4, %esp;			\
181 	cfi_adjust_cfa_offset (4);		\
182 	fld	%st(0);				\
183 	fmul	%st(0);				\
184 	fstps	(%esp);				\
185 	addl	$4, %esp;			\
186 	cfi_adjust_cfa_offset (-4);		\
187 6424:
188 #define DBL_CHECK_FORCE_UFLOW			\
189 	fldl	MO(dbl_min);			\
190 	fld	%st(1);				\
191 	fabs;					\
192 	fucompp;				\
193 	fnstsw;					\
194 	sahf;					\
195 	jnc 6453f;				\
196 	subl	$8, %esp;			\
197 	cfi_adjust_cfa_offset (8);		\
198 	fld	%st(0);				\
199 	fmul	%st(0);				\
200 	fstpl	(%esp);				\
201 	addl	$8, %esp;			\
202 	cfi_adjust_cfa_offset (-8);		\
203 6453:
204 
205 /* Likewise, but also remove excess range and precision if the value
206    is subnormal.  */
207 #define FLT_CHECK_FORCE_UFLOW_NARROW		\
208 	flds	MO(flt_min);			\
209 	fld	%st(1);				\
210 	fabs;					\
211 	fucompp;				\
212 	fnstsw;					\
213 	sahf;					\
214 	jnc 6424f;				\
215 	subl	$4, %esp;			\
216 	cfi_adjust_cfa_offset (4);		\
217 	fld	%st(0);				\
218 	fmul	%st(0);				\
219 	fstps	(%esp);				\
220 	fstps	(%esp);				\
221 	flds	(%esp);				\
222 	addl	$4, %esp;			\
223 	cfi_adjust_cfa_offset (-4);		\
224 6424:
225 #define DBL_CHECK_FORCE_UFLOW_NARROW		\
226 	fldl	MO(dbl_min);			\
227 	fld	%st(1);				\
228 	fabs;					\
229 	fucompp;				\
230 	fnstsw;					\
231 	sahf;					\
232 	jnc 6453f;				\
233 	subl	$8, %esp;			\
234 	cfi_adjust_cfa_offset (8);		\
235 	fld	%st(0);				\
236 	fmul	%st(0);				\
237 	fstpl	(%esp);				\
238 	fstpl	(%esp);				\
239 	fldl	(%esp);				\
240 	addl	$8, %esp;			\
241 	cfi_adjust_cfa_offset (-8);		\
242 6453:
243 
244 /* Likewise, but the argument is nonnegative or NaN.  */
245 #define LDBL_CHECK_FORCE_UFLOW_NONNEG_NAN	\
246 	fldt	MO(ldbl_min);			\
247 	fld	%st(1);				\
248 	fucompp;				\
249 	fnstsw;					\
250 	sahf;					\
251 	jnc 6464f;				\
252 	fld	%st(0);				\
253 	fmul	%st(0);				\
254 	fstp	%st(0);				\
255 6464:
256 
257 /* Likewise, but the argument is not a NaN.  */
258 #define FLT_CHECK_FORCE_UFLOW_NONNAN		\
259 	fld %st(0);				\
260 	fabs;					\
261 	fcomps	MO(flt_min);			\
262 	fnstsw;					\
263 	sahf;					\
264 	jnc 6424f;				\
265 	subl	$4, %esp;			\
266 	cfi_adjust_cfa_offset (4);		\
267 	fld	%st(0);				\
268 	fmul	%st(0);				\
269 	fstps	(%esp);				\
270 	addl	$4, %esp;			\
271 	cfi_adjust_cfa_offset (-4);		\
272 6424:
273 #define DBL_CHECK_FORCE_UFLOW_NONNAN		\
274 	fld %st(0);				\
275 	fabs;					\
276 	fcompl	MO(dbl_min);			\
277 	fnstsw;					\
278 	sahf;					\
279 	jnc 6453f;				\
280 	subl	$8, %esp;			\
281 	cfi_adjust_cfa_offset (8);		\
282 	fld	%st(0);				\
283 	fmul	%st(0);				\
284 	fstpl	(%esp);				\
285 	addl	$8, %esp;			\
286 	cfi_adjust_cfa_offset (-8);		\
287 6453:
288 #define LDBL_CHECK_FORCE_UFLOW_NONNAN		\
289 	fldt	MO(ldbl_min);			\
290 	fld	%st(1);				\
291 	fabs;					\
292 	fcompp;					\
293 	fnstsw;					\
294 	sahf;					\
295 	jnc 6464f;				\
296 	fld	%st(0);				\
297 	fmul	%st(0);				\
298 	fstp	%st(0);				\
299 6464:
300 
301 /* Likewise, but the argument is nonnegative and not a NaN.  */
302 #define FLT_CHECK_FORCE_UFLOW_NONNEG		\
303 	fcoms	MO(flt_min);			\
304 	fnstsw;					\
305 	sahf;					\
306 	jnc 6424f;				\
307 	subl	$4, %esp;			\
308 	cfi_adjust_cfa_offset (4);		\
309 	fld	%st(0);				\
310 	fmul	%st(0);				\
311 	fstps	(%esp);				\
312 	addl	$4, %esp;			\
313 	cfi_adjust_cfa_offset (-4);		\
314 6424:
315 #define DBL_CHECK_FORCE_UFLOW_NONNEG		\
316 	fcoml	MO(dbl_min);			\
317 	fnstsw;					\
318 	sahf;					\
319 	jnc 6453f;				\
320 	subl	$8, %esp;			\
321 	cfi_adjust_cfa_offset (8);		\
322 	fld	%st(0);				\
323 	fmul	%st(0);				\
324 	fstpl	(%esp);				\
325 	addl	$8, %esp;			\
326 	cfi_adjust_cfa_offset (-8);		\
327 6453:
328 #define LDBL_CHECK_FORCE_UFLOW_NONNEG		\
329 	fldt	MO(ldbl_min);			\
330 	fld	%st(1);				\
331 	fcompp;					\
332 	fnstsw;					\
333 	sahf;					\
334 	jnc 6464f;				\
335 	fld	%st(0);				\
336 	fmul	%st(0);				\
337 	fstp	%st(0);				\
338 6464:
339 
340 #endif /* i386-math-asm.h.  */
341