~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/math-emu/reg_compare.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php