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

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

Version: ~ [ linux-5.15-rc5 ] ~ [ linux-5.14.11 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.72 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.152 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.210 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.250 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.286 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.288 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ 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.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 23 static int compare(FPU_REG const *b, int tagb)
 24 {
 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);
113         }
114 
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);
119         }
120 
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);
131         }
132 
133 #ifdef PARANOID
134         if (!(st0_ptr->sigh & 0x80000000))
135                 EXCEPTION(EX_Invalid);
136         if (!(b->sigh & 0x80000000))
137                 EXCEPTION(EX_Invalid);
138 #endif /* PARANOID */
139 
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                 }
149         }
150 
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         }
161 
162         return COMP_A_eq_B
163             | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
164                COMP_Denormal : 0);
165 
166 }
167 
168 /* This function requires that st(0) is not empty */
169 int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
170 {
171         int f = 0, c;
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;
192 #ifdef PARANOID
193                 default:
194                         EXCEPTION(EX_INTERNAL | 0x121);
195                         f = SW_C3 | SW_C2 | SW_C0;
196                         break;
197 #endif /* PARANOID */
198                 }
199         setcc(f);
200         if (c & COMP_Denormal) {
201                 return denormal_operand() < 0;
202         }
203         return 0;
204 }
205 
206 static int compare_st_st(int nr)
207 {
208         int f = 0, c;
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;
238 #ifdef PARANOID
239                 default:
240                         EXCEPTION(EX_INTERNAL | 0x122);
241                         f = SW_C3 | SW_C2 | SW_C0;
242                         break;
243 #endif /* PARANOID */
244                 }
245         setcc(f);
246         if (c & COMP_Denormal) {
247                 return denormal_operand() < 0;
248         }
249         return 0;
250 }
251 
252 static 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;
286 #ifdef PARANOID
287         default:
288                 EXCEPTION(EX_INTERNAL | 0x122);
289                 f = 0;
290                 break;
291 #endif /* PARANOID */
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 
300 static int compare_u_st_st(int nr)
301 {
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);
310         }
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;
336 #ifdef PARANOID
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;
348 }
349 
350 static 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 
402 /*---------------------------------------------------------------------------*/
403 
404 void fcom_st(void)
405 {
406         /* fcom st(i) */
407         compare_st_st(FPU_rm);
408 }
409 
410 void fcompst(void)
411 {
412         /* fcomp st(i) */
413         if (!compare_st_st(FPU_rm))
414                 FPU_pop();
415 }
416 
417 void fcompp(void)
418 {
419         /* fcompp */
420         if (FPU_rm != 1) {
421                 FPU_illegal();
422                 return;
423         }
424         if (!compare_st_st(1))
425                 poppop();
426 }
427 
428 void fucom_(void)
429 {
430         /* fucom st(i) */
431         compare_u_st_st(FPU_rm);
432 
433 }
434 
435 void fucomp(void)
436 {
437         /* fucomp st(i) */
438         if (!compare_u_st_st(FPU_rm))
439                 FPU_pop();
440 }
441 
442 void fucompp(void)
443 {
444         /* fucompp */
445         if (FPU_rm == 1) {
446                 if (!compare_u_st_st(1))
447                         poppop();
448         } else
449                 FPU_illegal();
450 }
451 
452 /* P6+ compare-to-EFLAGS ops */
453 
454 void fcomi_(void)
455 {
456         /* fcomi st(i) */
457         compare_i_st_st(FPU_rm);
458 }
459 
460 void fcomip(void)
461 {
462         /* fcomip st(i) */
463         if (!compare_i_st_st(FPU_rm))
464                 FPU_pop();
465 }
466 
467 void fucomi_(void)
468 {
469         /* fucomi st(i) */
470         compare_ui_st_st(FPU_rm);
471 }
472 
473 void fucomip(void)
474 {
475         /* fucomip st(i) */
476         if (!compare_ui_st_st(FPU_rm))
477                 FPU_pop();
478 }
479 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp