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