1 /* 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)fpu_compare.c 7.4 (Berkeley) 04/20/93 17 * 18 * from: $Header: fpu_compare.c,v 1.3 92/11/26 01:39:46 torek Exp $ 19 */ 20 21 /* 22 * CMP and CMPE instructions. 23 * 24 * These rely on the fact that our internal wide format is achieved by 25 * adding zero bits to the end of narrower mantissas. 26 */ 27 28 #include <sys/types.h> 29 30 #include <machine/reg.h> 31 32 #include <sparc/fpu/fpu_arith.h> 33 #include <sparc/fpu/fpu_emu.h> 34 35 /* 36 * Perform a compare instruction (with or without unordered exception). 37 * This updates the fcc field in the fsr. 38 * 39 * If either operand is NaN, the result is unordered. For cmpe, this 40 * causes an NV exception. Everything else is ordered: 41 * |Inf| > |numbers| > |0|. 42 * We already arranged for fp_class(Inf) > fp_class(numbers) > fp_class(0), 43 * so we get this directly. Note, however, that two zeros compare equal 44 * regardless of sign, while everything else depends on sign. 45 * 46 * Incidentally, two Infs of the same sign compare equal (per the 80387 47 * manual---it would be nice if the SPARC documentation were more 48 * complete). 49 */ 50 void 51 fpu_compare(struct fpemu *fe, int cmpe) 52 { 53 register struct fpn *a, *b; 54 register int cc, r3, r2, r1, r0; 55 FPU_DECL_CARRY 56 57 a = &fe->fe_f1; 58 b = &fe->fe_f2; 59 60 if (ISNAN(a) || ISNAN(b)) { 61 /* 62 * In any case, we already got an exception for signalling 63 * NaNs; here we may replace that one with an identical 64 * exception, but so what?. 65 */ 66 if (cmpe) 67 fe->fe_cx = FSR_NV; 68 cc = FSR_CC_UO; 69 goto done; 70 } 71 72 /* 73 * Must handle both-zero early to avoid sign goofs. Otherwise, 74 * at most one is 0, and if the signs differ we are done. 75 */ 76 if (ISZERO(a) && ISZERO(b)) { 77 cc = FSR_CC_EQ; 78 goto done; 79 } 80 if (a->fp_sign) { /* a < 0 (or -0) */ 81 if (!b->fp_sign) { /* b >= 0 (or if a = -0, b > 0) */ 82 cc = FSR_CC_LT; 83 goto done; 84 } 85 } else { /* a > 0 (or +0) */ 86 if (b->fp_sign) { /* b <= -0 (or if a = +0, b < 0) */ 87 cc = FSR_CC_GT; 88 goto done; 89 } 90 } 91 92 /* 93 * Now the signs are the same (but may both be negative). All 94 * we have left are these cases: 95 * 96 * |a| < |b| [classes or values differ] 97 * |a| > |b| [classes or values differ] 98 * |a| == |b| [classes and values identical] 99 * 100 * We define `diff' here to expand these as: 101 * 102 * |a| < |b|, a,b >= 0: a < b => FSR_CC_LT 103 * |a| < |b|, a,b < 0: a > b => FSR_CC_GT 104 * |a| > |b|, a,b >= 0: a > b => FSR_CC_GT 105 * |a| > |b|, a,b < 0: a < b => FSR_CC_LT 106 */ 107 #define opposite_cc(cc) ((cc) == FSR_CC_LT ? FSR_CC_GT : FSR_CC_LT) 108 #define diff(magnitude) (a->fp_sign ? opposite_cc(magnitude) : (magnitude)) 109 if (a->fp_class < b->fp_class) { /* |a| < |b| */ 110 cc = diff(FSR_CC_LT); 111 goto done; 112 } 113 if (a->fp_class > b->fp_class) { /* |a| > |b| */ 114 cc = diff(FSR_CC_GT); 115 goto done; 116 } 117 /* now none can be 0: only Inf and numbers remain */ 118 if (ISINF(a)) { /* |Inf| = |Inf| */ 119 cc = FSR_CC_EQ; 120 goto done; 121 } 122 /* 123 * Only numbers remain. To compare two numbers in magnitude, we 124 * simply subtract their mantissas. 125 */ 126 FPU_SUBS(r3, a->fp_mant[0], b->fp_mant[0]); 127 FPU_SUBCS(r2, a->fp_mant[1], b->fp_mant[1]); 128 FPU_SUBCS(r1, a->fp_mant[2], b->fp_mant[2]); 129 FPU_SUBC(r0, a->fp_mant[3], b->fp_mant[3]); 130 if (r0 < 0) /* underflow: |a| < |b| */ 131 cc = diff(FSR_CC_LT); 132 else if ((r0 | r1 | r2 | r3) != 0) /* |a| > |b| */ 133 cc = diff(FSR_CC_GT); 134 else 135 cc = FSR_CC_EQ; /* |a| == |b| */ 136 done: 137 fe->fe_fsr = (fe->fe_fsr & ~FSR_FCC) | (cc << FSR_FCC_SHIFT); 138 } 139