155112Storek /* 255112Storek * Copyright (c) 1992 The Regents of the University of California. 355112Storek * All rights reserved. 455112Storek * 555112Storek * This software was developed by the Computer Systems Engineering group 655112Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 755112Storek * contributed to Berkeley. 855112Storek * 9*55500Sbostic * All advertising materials mentioning features or use of this software 10*55500Sbostic * must display the following acknowledgement: 11*55500Sbostic * This product includes software developed by the University of 12*55500Sbostic * California, Lawrence Berkeley Laboratories. 13*55500Sbostic * 1455112Storek * %sccs.include.redist.c% 1555112Storek * 16*55500Sbostic * @(#)fpu_compare.c 7.2 (Berkeley) 07/21/92 1755112Storek * 1855112Storek * from: $Header: fpu_compare.c,v 1.2 92/06/17 05:41:29 torek Exp $ 1955112Storek */ 2055112Storek 2155112Storek /* 2255112Storek * CMP and CMPE instructions. 2355112Storek * 2455112Storek * These rely on the fact that our internal wide format is achieved by 2555112Storek * adding zero bits to the end of narrower mantissas. 2655112Storek */ 2755112Storek 2855112Storek #include "sys/types.h" 2955112Storek 3055112Storek #include "machine/reg.h" 3155112Storek 3255112Storek #include "fpu_arith.h" 3355112Storek #include "fpu_emu.h" 3455112Storek 3555112Storek /* 3655112Storek * Perform a compare instruction (with or without unordered exception). 3755112Storek * This updates the fcc field in the fsr. 3855112Storek * 3955112Storek * If either operand is NaN, the result is unordered. For cmpe, this 4055112Storek * causes an NV exception. Everything else is ordered: 4155112Storek * |Inf| > |numbers| > |0|. 4255112Storek * We already arranged for fp_class(Inf) > fp_class(numbers) > fp_class(0), 4355112Storek * so we get this directly. Note, however, that two zeros compare equal 4455112Storek * regardless of sign, while everything else depends on sign. 4555112Storek * 4655112Storek * Incidentally, two Infs of the same sign compare equal (per the 80387 4755112Storek * manual---it would be nice if the SPARC documentation were more 4855112Storek * complete). 4955112Storek */ 5055112Storek void 5155112Storek fpu_compare(struct fpemu *fe, int cmpe) 5255112Storek { 5355112Storek register struct fpn *a, *b; 5455112Storek register int cc, r3, r2, r1, r0; 5555112Storek FPU_DECL_CARRY 5655112Storek 5755112Storek a = &fe->fe_f1; 5855112Storek b = &fe->fe_f2; 5955112Storek 6055112Storek if (ISNAN(a) || ISNAN(b)) { 6155112Storek /* 6255112Storek * In any case, we already got an exception for signalling 6355112Storek * NaNs; here we may replace that one with an identical 6455112Storek * exception, but so what?. 6555112Storek */ 6655112Storek if (cmpe) 6755112Storek fe->fe_cx = FSR_NV; 6855112Storek cc = FSR_CC_UO; 6955112Storek goto done; 7055112Storek } 7155112Storek 7255112Storek /* 7355112Storek * Must handle both-zero early to avoid sign goofs. Otherwise, 7455112Storek * at most one is 0, and if the signs differ we are done. 7555112Storek */ 7655112Storek if (ISZERO(a) && ISZERO(b)) { 7755112Storek cc = FSR_CC_EQ; 7855112Storek goto done; 7955112Storek } 8055112Storek if (a->fp_sign) { /* a < 0 (or -0) */ 8155112Storek if (!b->fp_sign) { /* b >= 0 (or if a = -0, b > 0) */ 8255112Storek cc = FSR_CC_LT; 8355112Storek goto done; 8455112Storek } 8555112Storek } else { /* a > 0 (or +0) */ 8655112Storek if (b->fp_sign) { /* b <= -0 (or if a = +0, b < 0) */ 8755112Storek cc = FSR_CC_GT; 8855112Storek goto done; 8955112Storek } 9055112Storek } 9155112Storek 9255112Storek /* 9355112Storek * Now the signs are the same (but may both be negative). All 9455112Storek * we have left are these cases: 9555112Storek * 9655112Storek * |a| < |b| [classes or values differ] 9755112Storek * |a| > |b| [classes or values differ] 9855112Storek * |a| == |b| [classes and values identical] 9955112Storek * 10055112Storek * We define `diff' here to expand these as: 10155112Storek * 10255112Storek * |a| < |b|, a,b >= 0: a < b => FSR_CC_LT 10355112Storek * |a| < |b|, a,b < 0: a > b => FSR_CC_GT 10455112Storek * |a| > |b|, a,b >= 0: a > b => FSR_CC_GT 10555112Storek * |a| > |b|, a,b < 0: a < b => FSR_CC_LT 10655112Storek */ 10755112Storek #define opposite_cc(cc) ((cc) == FSR_CC_LT ? FSR_CC_GT : FSR_CC_LT) 10855112Storek #define diff(magnitude) (a->fp_sign ? opposite_cc(magnitude) : (magnitude)) 10955112Storek if (a->fp_class < b->fp_class) { /* |a| < |b| */ 11055112Storek cc = diff(FSR_CC_LT); 11155112Storek goto done; 11255112Storek } 11355112Storek if (a->fp_class > b->fp_class) { /* |a| > |b| */ 11455112Storek cc = diff(FSR_CC_GT); 11555112Storek goto done; 11655112Storek } 11755112Storek /* now none can be 0: only Inf and numbers remain */ 11855112Storek if (ISINF(a)) { /* |Inf| = |Inf| */ 11955112Storek cc = FSR_CC_EQ; 12055112Storek goto done; 12155112Storek } 12255112Storek /* 12355112Storek * Only numbers remain. To compare two numbers in magnitude, we 12455112Storek * simply subtract their mantissas. 12555112Storek */ 12655112Storek FPU_SUBS(r3, a->fp_mant[0], b->fp_mant[0]); 12755112Storek FPU_SUBCS(r2, a->fp_mant[1], b->fp_mant[1]); 12855112Storek FPU_SUBCS(r1, a->fp_mant[2], b->fp_mant[2]); 12955112Storek FPU_SUBC(r0, a->fp_mant[3], b->fp_mant[3]); 13055112Storek if (r0 < 0) /* underflow: |a| < |b| */ 13155112Storek cc = diff(FSR_CC_LT); 13255112Storek else if ((r0 | r1 | r2 | r3) != 0) /* |a| > |b| */ 13355112Storek cc = diff(FSR_CC_GT); 13455112Storek else 13555112Storek cc = FSR_CC_EQ; /* |a| == |b| */ 13655112Storek done: 13755112Storek fe->fe_fsr = (fe->fe_fsr & ~FSR_FCC) | (cc << FSR_FCC_SHIFT); 13855112Storek } 139