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