]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - arch/x86/math-emu/reg_compare.c
Merge tag 'for-linus-20170825' of git://git.infradead.org/linux-mtd
[mirror_ubuntu-artful-kernel.git] / arch / x86 / math-emu / reg_compare.c
CommitLineData
1da177e4
LT
1/*---------------------------------------------------------------------------+
2 | reg_compare.c |
3 | |
4 | Compare two floating point registers |
5 | |
6 | Copyright (C) 1992,1993,1994,1997 |
7 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8 | E-mail billm@suburbia.net |
9 | |
10 | |
11 +---------------------------------------------------------------------------*/
12
13/*---------------------------------------------------------------------------+
14 | compare() is the core FPU_REG comparison function |
15 +---------------------------------------------------------------------------*/
16
17#include "fpu_system.h"
18#include "exception.h"
19#include "fpu_emu.h"
20#include "control_w.h"
21#include "status_w.h"
22
1da177e4
LT
23static int compare(FPU_REG const *b, int tagb)
24{
3d0d14f9
IM
25 int diff, exp0, expb;
26 u_char st0_tag;
27 FPU_REG *st0_ptr;
28 FPU_REG x, y;
29 u_char st0_sign, signb = getsign(b);
30
31 st0_ptr = &st(0);
32 st0_tag = FPU_gettag0();
33 st0_sign = getsign(st0_ptr);
34
35 if (tagb == TAG_Special)
36 tagb = FPU_Special(b);
37 if (st0_tag == TAG_Special)
38 st0_tag = FPU_Special(st0_ptr);
39
40 if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
41 || ((tagb != TAG_Valid) && (tagb != TW_Denormal))) {
42 if (st0_tag == TAG_Zero) {
43 if (tagb == TAG_Zero)
44 return COMP_A_eq_B;
45 if (tagb == TAG_Valid)
46 return ((signb ==
47 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
48 if (tagb == TW_Denormal)
49 return ((signb ==
50 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
51 | COMP_Denormal;
52 } else if (tagb == TAG_Zero) {
53 if (st0_tag == TAG_Valid)
54 return ((st0_sign ==
55 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
56 if (st0_tag == TW_Denormal)
57 return ((st0_sign ==
58 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
59 | COMP_Denormal;
60 }
61
62 if (st0_tag == TW_Infinity) {
63 if ((tagb == TAG_Valid) || (tagb == TAG_Zero))
64 return ((st0_sign ==
65 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
66 else if (tagb == TW_Denormal)
67 return ((st0_sign ==
68 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
69 | COMP_Denormal;
70 else if (tagb == TW_Infinity) {
71 /* The 80486 book says that infinities can be equal! */
72 return (st0_sign == signb) ? COMP_A_eq_B :
73 ((st0_sign ==
74 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
75 }
76 /* Fall through to the NaN code */
77 } else if (tagb == TW_Infinity) {
78 if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero))
79 return ((signb ==
80 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
81 if (st0_tag == TW_Denormal)
82 return ((signb ==
83 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
84 | COMP_Denormal;
85 /* Fall through to the NaN code */
86 }
87
88 /* The only possibility now should be that one of the arguments
89 is a NaN */
90 if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) {
91 int signalling = 0, unsupported = 0;
92 if (st0_tag == TW_NaN) {
93 signalling =
94 (st0_ptr->sigh & 0xc0000000) == 0x80000000;
95 unsupported = !((exponent(st0_ptr) == EXP_OVER)
96 && (st0_ptr->
97 sigh & 0x80000000));
98 }
99 if (tagb == TW_NaN) {
100 signalling |=
101 (b->sigh & 0xc0000000) == 0x80000000;
102 unsupported |= !((exponent(b) == EXP_OVER)
103 && (b->sigh & 0x80000000));
104 }
105 if (signalling || unsupported)
106 return COMP_No_Comp | COMP_SNaN | COMP_NaN;
107 else
108 /* Neither is a signaling NaN */
109 return COMP_No_Comp | COMP_NaN;
110 }
111
112 EXCEPTION(EX_Invalid);
1da177e4
LT
113 }
114
3d0d14f9
IM
115 if (st0_sign != signb) {
116 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
117 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
118 COMP_Denormal : 0);
1da177e4
LT
119 }
120
3d0d14f9
IM
121 if ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) {
122 FPU_to_exp16(st0_ptr, &x);
123 FPU_to_exp16(b, &y);
124 st0_ptr = &x;
125 b = &y;
126 exp0 = exponent16(st0_ptr);
127 expb = exponent16(b);
128 } else {
129 exp0 = exponent(st0_ptr);
130 expb = exponent(b);
1da177e4 131 }
1da177e4
LT
132
133#ifdef PARANOID
3d0d14f9
IM
134 if (!(st0_ptr->sigh & 0x80000000))
135 EXCEPTION(EX_Invalid);
136 if (!(b->sigh & 0x80000000))
137 EXCEPTION(EX_Invalid);
1da177e4
LT
138#endif /* PARANOID */
139
3d0d14f9
IM
140 diff = exp0 - expb;
141 if (diff == 0) {
142 diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
143 identical */
144 if (diff == 0) {
145 diff = st0_ptr->sigl > b->sigl;
146 if (diff == 0)
147 diff = -(st0_ptr->sigl < b->sigl);
148 }
1da177e4 149 }
1da177e4 150
3d0d14f9
IM
151 if (diff > 0) {
152 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
153 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
154 COMP_Denormal : 0);
155 }
156 if (diff < 0) {
157 return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
158 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
159 COMP_Denormal : 0);
160 }
1da177e4 161
3d0d14f9
IM
162 return COMP_A_eq_B
163 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
164 COMP_Denormal : 0);
165
166}
1da177e4
LT
167
168/* This function requires that st(0) is not empty */
169int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
170{
75e2f0a6 171 int f, c;
3d0d14f9
IM
172
173 c = compare(loaded_data, loaded_tag);
174
175 if (c & COMP_NaN) {
176 EXCEPTION(EX_Invalid);
177 f = SW_C3 | SW_C2 | SW_C0;
178 } else
179 switch (c & 7) {
180 case COMP_A_lt_B:
181 f = SW_C0;
182 break;
183 case COMP_A_eq_B:
184 f = SW_C3;
185 break;
186 case COMP_A_gt_B:
187 f = 0;
188 break;
189 case COMP_No_Comp:
190 f = SW_C3 | SW_C2 | SW_C0;
191 break;
3d0d14f9 192 default:
75e2f0a6 193#ifdef PARANOID
3d0d14f9 194 EXCEPTION(EX_INTERNAL | 0x121);
75e2f0a6 195#endif /* PARANOID */
3d0d14f9
IM
196 f = SW_C3 | SW_C2 | SW_C0;
197 break;
3d0d14f9
IM
198 }
199 setcc(f);
200 if (c & COMP_Denormal) {
201 return denormal_operand() < 0;
202 }
203 return 0;
1da177e4
LT
204}
205
1da177e4
LT
206static int compare_st_st(int nr)
207{
75e2f0a6 208 int f, c;
3d0d14f9
IM
209 FPU_REG *st_ptr;
210
211 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
212 setcc(SW_C3 | SW_C2 | SW_C0);
213 /* Stack fault */
214 EXCEPTION(EX_StackUnder);
215 return !(control_word & CW_Invalid);
216 }
217
218 st_ptr = &st(nr);
219 c = compare(st_ptr, FPU_gettagi(nr));
220 if (c & COMP_NaN) {
221 setcc(SW_C3 | SW_C2 | SW_C0);
222 EXCEPTION(EX_Invalid);
223 return !(control_word & CW_Invalid);
224 } else
225 switch (c & 7) {
226 case COMP_A_lt_B:
227 f = SW_C0;
228 break;
229 case COMP_A_eq_B:
230 f = SW_C3;
231 break;
232 case COMP_A_gt_B:
233 f = 0;
234 break;
235 case COMP_No_Comp:
236 f = SW_C3 | SW_C2 | SW_C0;
237 break;
3d0d14f9 238 default:
75e2f0a6 239#ifdef PARANOID
3d0d14f9 240 EXCEPTION(EX_INTERNAL | 0x122);
75e2f0a6 241#endif /* PARANOID */
3d0d14f9
IM
242 f = SW_C3 | SW_C2 | SW_C0;
243 break;
3d0d14f9
IM
244 }
245 setcc(f);
246 if (c & COMP_Denormal) {
247 return denormal_operand() < 0;
248 }
249 return 0;
1da177e4
LT
250}
251
b8e4a910
DV
252static int compare_i_st_st(int nr)
253{
254 int f, c;
255 FPU_REG *st_ptr;
256
257 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
258 FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
259 /* Stack fault */
260 EXCEPTION(EX_StackUnder);
261 return !(control_word & CW_Invalid);
262 }
263
264 partial_status &= ~SW_C0;
265 st_ptr = &st(nr);
266 c = compare(st_ptr, FPU_gettagi(nr));
267 if (c & COMP_NaN) {
268 FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
269 EXCEPTION(EX_Invalid);
270 return !(control_word & CW_Invalid);
271 }
272
273 switch (c & 7) {
274 case COMP_A_lt_B:
275 f = X86_EFLAGS_CF;
276 break;
277 case COMP_A_eq_B:
278 f = X86_EFLAGS_ZF;
279 break;
280 case COMP_A_gt_B:
281 f = 0;
282 break;
283 case COMP_No_Comp:
284 f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
285 break;
b8e4a910 286 default:
75e2f0a6 287#ifdef PARANOID
b8e4a910 288 EXCEPTION(EX_INTERNAL | 0x122);
75e2f0a6 289#endif /* PARANOID */
b8e4a910
DV
290 f = 0;
291 break;
b8e4a910
DV
292 }
293 FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
294 if (c & COMP_Denormal) {
295 return denormal_operand() < 0;
296 }
297 return 0;
298}
299
1da177e4
LT
300static int compare_u_st_st(int nr)
301{
3d0d14f9
IM
302 int f = 0, c;
303 FPU_REG *st_ptr;
304
305 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
306 setcc(SW_C3 | SW_C2 | SW_C0);
307 /* Stack fault */
308 EXCEPTION(EX_StackUnder);
309 return !(control_word & CW_Invalid);
1da177e4 310 }
3d0d14f9
IM
311
312 st_ptr = &st(nr);
313 c = compare(st_ptr, FPU_gettagi(nr));
314 if (c & COMP_NaN) {
315 setcc(SW_C3 | SW_C2 | SW_C0);
316 if (c & COMP_SNaN) { /* This is the only difference between
317 un-ordered and ordinary comparisons */
318 EXCEPTION(EX_Invalid);
319 return !(control_word & CW_Invalid);
320 }
321 return 0;
322 } else
323 switch (c & 7) {
324 case COMP_A_lt_B:
325 f = SW_C0;
326 break;
327 case COMP_A_eq_B:
328 f = SW_C3;
329 break;
330 case COMP_A_gt_B:
331 f = 0;
332 break;
333 case COMP_No_Comp:
334 f = SW_C3 | SW_C2 | SW_C0;
335 break;
1da177e4 336#ifdef PARANOID
3d0d14f9
IM
337 default:
338 EXCEPTION(EX_INTERNAL | 0x123);
339 f = SW_C3 | SW_C2 | SW_C0;
340 break;
341#endif /* PARANOID */
342 }
343 setcc(f);
344 if (c & COMP_Denormal) {
345 return denormal_operand() < 0;
346 }
347 return 0;
1da177e4
LT
348}
349
b8e4a910
DV
350static int compare_ui_st_st(int nr)
351{
352 int f = 0, c;
353 FPU_REG *st_ptr;
354
355 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
356 FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
357 /* Stack fault */
358 EXCEPTION(EX_StackUnder);
359 return !(control_word & CW_Invalid);
360 }
361
362 partial_status &= ~SW_C0;
363 st_ptr = &st(nr);
364 c = compare(st_ptr, FPU_gettagi(nr));
365 if (c & COMP_NaN) {
366 FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
367 if (c & COMP_SNaN) { /* This is the only difference between
368 un-ordered and ordinary comparisons */
369 EXCEPTION(EX_Invalid);
370 return !(control_word & CW_Invalid);
371 }
372 return 0;
373 }
374
375 switch (c & 7) {
376 case COMP_A_lt_B:
377 f = X86_EFLAGS_CF;
378 break;
379 case COMP_A_eq_B:
380 f = X86_EFLAGS_ZF;
381 break;
382 case COMP_A_gt_B:
383 f = 0;
384 break;
385 case COMP_No_Comp:
386 f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
387 break;
388#ifdef PARANOID
389 default:
390 EXCEPTION(EX_INTERNAL | 0x123);
391 f = 0;
392 break;
393#endif /* PARANOID */
394 }
395 FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
396 if (c & COMP_Denormal) {
397 return denormal_operand() < 0;
398 }
399 return 0;
400}
401
1da177e4
LT
402/*---------------------------------------------------------------------------*/
403
404void fcom_st(void)
405{
3d0d14f9
IM
406 /* fcom st(i) */
407 compare_st_st(FPU_rm);
1da177e4
LT
408}
409
1da177e4
LT
410void fcompst(void)
411{
3d0d14f9
IM
412 /* fcomp st(i) */
413 if (!compare_st_st(FPU_rm))
414 FPU_pop();
1da177e4
LT
415}
416
1da177e4
LT
417void fcompp(void)
418{
3d0d14f9
IM
419 /* fcompp */
420 if (FPU_rm != 1) {
421 FPU_illegal();
422 return;
423 }
424 if (!compare_st_st(1))
425 poppop();
1da177e4
LT
426}
427
1da177e4
LT
428void fucom_(void)
429{
3d0d14f9
IM
430 /* fucom st(i) */
431 compare_u_st_st(FPU_rm);
1da177e4
LT
432
433}
434
1da177e4
LT
435void fucomp(void)
436{
3d0d14f9
IM
437 /* fucomp st(i) */
438 if (!compare_u_st_st(FPU_rm))
439 FPU_pop();
1da177e4
LT
440}
441
1da177e4
LT
442void fucompp(void)
443{
3d0d14f9
IM
444 /* fucompp */
445 if (FPU_rm == 1) {
446 if (!compare_u_st_st(1))
447 poppop();
448 } else
449 FPU_illegal();
1da177e4 450}
b8e4a910
DV
451
452/* P6+ compare-to-EFLAGS ops */
453
454void fcomi_(void)
455{
456 /* fcomi st(i) */
457 compare_i_st_st(FPU_rm);
458}
459
460void fcomip(void)
461{
462 /* fcomip st(i) */
463 if (!compare_i_st_st(FPU_rm))
464 FPU_pop();
465}
466
467void fucomi_(void)
468{
469 /* fucomi st(i) */
470 compare_ui_st_st(FPU_rm);
471}
472
473void fucomip(void)
474{
475 /* fucomip st(i) */
476 if (!compare_ui_st_st(FPU_rm))
477 FPU_pop();
478}