1331722Seadler/* 291174Stmm * Copyright (c) 1992, 1993 391174Stmm * The Regents of the University of California. All rights reserved. 491174Stmm * 591174Stmm * This software was developed by the Computer Systems Engineering group 691174Stmm * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 791174Stmm * contributed to Berkeley. 891174Stmm * 991174Stmm * All advertising materials mentioning features or use of this software 1091174Stmm * must display the following acknowledgement: 1191174Stmm * This product includes software developed by the University of 1291174Stmm * California, Lawrence Berkeley Laboratory. 1391174Stmm * 1491174Stmm * Redistribution and use in source and binary forms, with or without 1591174Stmm * modification, are permitted provided that the following conditions 1691174Stmm * are met: 1791174Stmm * 1. Redistributions of source code must retain the above copyright 1891174Stmm * notice, this list of conditions and the following disclaimer. 1991174Stmm * 2. Redistributions in binary form must reproduce the above copyright 2091174Stmm * notice, this list of conditions and the following disclaimer in the 2191174Stmm * documentation and/or other materials provided with the distribution. 2291174Stmm * 4. Neither the name of the University nor the names of its contributors 2391174Stmm * may be used to endorse or promote products derived from this software 2491174Stmm * without specific prior written permission. 2591174Stmm * 2691174Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2791174Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2891174Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2991174Stmm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3091174Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3191174Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3291174Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3391174Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3491174Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3591174Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3691174Stmm * SUCH DAMAGE. 3791174Stmm * 3891174Stmm * @(#)fpu_compare.c 8.1 (Berkeley) 6/11/93 3992986Sobrien * $NetBSD: fpu_compare.c,v 1.3 2001/08/26 05:46:31 eeh Exp $ 4091174Stmm */ 4191174Stmm 4292986Sobrien#include <sys/cdefs.h> 4392986Sobrien__FBSDID("$FreeBSD$"); 4492986Sobrien 4591174Stmm/* 4691174Stmm * CMP and CMPE instructions. 4791174Stmm * 4891174Stmm * These rely on the fact that our internal wide format is achieved by 4991174Stmm * adding zero bits to the end of narrower mantissas. 5091174Stmm */ 5191174Stmm 5291174Stmm#include <sys/types.h> 5391174Stmm 5491174Stmm#include <machine/frame.h> 5591174Stmm#include <machine/fp.h> 5691174Stmm#include <machine/fsr.h> 5791174Stmm 5891174Stmm#include "fpu_arith.h" 5991174Stmm#include "fpu_emu.h" 6091174Stmm#include "fpu_extern.h" 6191174Stmm 6292055Stmmstatic u_long fcc_nmask[] = { 6392055Stmm ~FSR_FCC0_MASK, 6492055Stmm ~FSR_FCC1_MASK, 6592055Stmm ~FSR_FCC2_MASK, 6692055Stmm ~FSR_FCC3_MASK 6792055Stmm}; 6892055Stmm 6992055Stmm/* XXX: we don't use the FSR_FCCx macros here; it's much easier this way. */ 7092055Stmmstatic int fcc_shift[] = { 7192055Stmm FSR_FCC0_SHIFT, 7292055Stmm FSR_FCC1_SHIFT, 7392055Stmm FSR_FCC2_SHIFT, 7492055Stmm FSR_FCC3_SHIFT 7592055Stmm}; 7692055Stmm 7791174Stmm/* 7891174Stmm * Perform a compare instruction (with or without unordered exception). 7991174Stmm * This updates the fcc field in the fsr. 8091174Stmm * 8191174Stmm * If either operand is NaN, the result is unordered. For cmpe, this 8291174Stmm * causes an NV exception. Everything else is ordered: 8391174Stmm * |Inf| > |numbers| > |0|. 8491174Stmm * We already arranged for fp_class(Inf) > fp_class(numbers) > fp_class(0), 8591174Stmm * so we get this directly. Note, however, that two zeros compare equal 8691174Stmm * regardless of sign, while everything else depends on sign. 8791174Stmm * 8891174Stmm * Incidentally, two Infs of the same sign compare equal (per the 80387 8991174Stmm * manual---it would be nice if the SPARC documentation were more 9091174Stmm * complete). 9191174Stmm */ 9291174Stmmvoid 9392055Stmm__fpu_compare(struct fpemu *fe, int cmpe, int fcc) 9491174Stmm{ 9592889Sobrien struct fpn *a, *b; 9692889Sobrien int cc; 9791174Stmm FPU_DECL_CARRY 9891174Stmm 9991174Stmm a = &fe->fe_f1; 10091174Stmm b = &fe->fe_f2; 10191174Stmm 10291174Stmm if (ISNAN(a) || ISNAN(b)) { 10391174Stmm /* 10491174Stmm * In any case, we already got an exception for signalling 10591174Stmm * NaNs; here we may replace that one with an identical 10691174Stmm * exception, but so what?. 10791174Stmm */ 10891174Stmm if (cmpe) 10991174Stmm fe->fe_cx = FSR_NV; 11091174Stmm cc = FSR_CC_UO; 11191174Stmm goto done; 11291174Stmm } 11391174Stmm 11491174Stmm /* 11591174Stmm * Must handle both-zero early to avoid sign goofs. Otherwise, 11691174Stmm * at most one is 0, and if the signs differ we are done. 11791174Stmm */ 11891174Stmm if (ISZERO(a) && ISZERO(b)) { 11991174Stmm cc = FSR_CC_EQ; 12091174Stmm goto done; 12191174Stmm } 12291174Stmm if (a->fp_sign) { /* a < 0 (or -0) */ 12391174Stmm if (!b->fp_sign) { /* b >= 0 (or if a = -0, b > 0) */ 12491174Stmm cc = FSR_CC_LT; 12591174Stmm goto done; 12691174Stmm } 12791174Stmm } else { /* a > 0 (or +0) */ 12891174Stmm if (b->fp_sign) { /* b <= -0 (or if a = +0, b < 0) */ 12991174Stmm cc = FSR_CC_GT; 13091174Stmm goto done; 13191174Stmm } 13291174Stmm } 13391174Stmm 13491174Stmm /* 13591174Stmm * Now the signs are the same (but may both be negative). All 13691174Stmm * we have left are these cases: 13791174Stmm * 13891174Stmm * |a| < |b| [classes or values differ] 13991174Stmm * |a| > |b| [classes or values differ] 14091174Stmm * |a| == |b| [classes and values identical] 14191174Stmm * 14291174Stmm * We define `diff' here to expand these as: 14391174Stmm * 14491174Stmm * |a| < |b|, a,b >= 0: a < b => FSR_CC_LT 14591174Stmm * |a| < |b|, a,b < 0: a > b => FSR_CC_GT 14691174Stmm * |a| > |b|, a,b >= 0: a > b => FSR_CC_GT 14791174Stmm * |a| > |b|, a,b < 0: a < b => FSR_CC_LT 14891174Stmm */ 14991174Stmm#define opposite_cc(cc) ((cc) == FSR_CC_LT ? FSR_CC_GT : FSR_CC_LT) 15091174Stmm#define diff(magnitude) (a->fp_sign ? opposite_cc(magnitude) : (magnitude)) 15191174Stmm if (a->fp_class < b->fp_class) { /* |a| < |b| */ 15291174Stmm cc = diff(FSR_CC_LT); 15391174Stmm goto done; 15491174Stmm } 15591174Stmm if (a->fp_class > b->fp_class) { /* |a| > |b| */ 15691174Stmm cc = diff(FSR_CC_GT); 15791174Stmm goto done; 15891174Stmm } 15991174Stmm /* now none can be 0: only Inf and numbers remain */ 16091174Stmm if (ISINF(a)) { /* |Inf| = |Inf| */ 16191174Stmm cc = FSR_CC_EQ; 16291174Stmm goto done; 16391174Stmm } 16491174Stmm /* 16591174Stmm * Only numbers remain. To compare two numbers in magnitude, we 16691174Stmm * simply subtract them. 16791174Stmm */ 16891174Stmm a = __fpu_sub(fe); 16991174Stmm if (a->fp_class == FPC_ZERO) 17091174Stmm cc = FSR_CC_EQ; 17191174Stmm else 17291174Stmm cc = diff(FSR_CC_GT); 17391174Stmm 17491174Stmmdone: 17592055Stmm fe->fe_fsr = (fe->fe_fsr & fcc_nmask[fcc]) | 17692055Stmm ((u_long)cc << fcc_shift[fcc]); 17791174Stmm} 178