1276789Sdim//===-- lib/comparesf2.c - Single-precision comparisons -----------*- C -*-===//
2276789Sdim//
3276789Sdim//                     The LLVM Compiler Infrastructure
4276789Sdim//
5276789Sdim// This file is dual licensed under the MIT and the University of Illinois Open
6276789Sdim// Source Licenses. See LICENSE.TXT for details.
7276789Sdim//
8276789Sdim//===----------------------------------------------------------------------===//
9276789Sdim//
10276789Sdim// This file implements the following soft-fp_t comparison routines:
11276789Sdim//
12276789Sdim//   __eqsf2   __gesf2   __unordsf2
13276789Sdim//   __lesf2   __gtsf2
14276789Sdim//   __ltsf2
15276789Sdim//   __nesf2
16276789Sdim//
17276789Sdim// The semantics of the routines grouped in each column are identical, so there
18276789Sdim// is a single implementation for each, and wrappers to provide the other names.
19276789Sdim//
20276789Sdim// The main routines behave as follows:
21276789Sdim//
22276789Sdim//   __lesf2(a,b) returns -1 if a < b
23276789Sdim//                         0 if a == b
24276789Sdim//                         1 if a > b
25276789Sdim//                         1 if either a or b is NaN
26276789Sdim//
27276789Sdim//   __gesf2(a,b) returns -1 if a < b
28276789Sdim//                         0 if a == b
29276789Sdim//                         1 if a > b
30276789Sdim//                        -1 if either a or b is NaN
31276789Sdim//
32276789Sdim//   __unordsf2(a,b) returns 0 if both a and b are numbers
33276789Sdim//                           1 if either a or b is NaN
34276789Sdim//
35276789Sdim// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of
36276789Sdim// NaN values.
37276789Sdim//
38276789Sdim//===----------------------------------------------------------------------===//
39276789Sdim
40276789Sdim#define SINGLE_PRECISION
41276789Sdim#include "fp_lib.h"
42276789Sdim
43276789Sdimenum LE_RESULT {
44276789Sdim    LE_LESS      = -1,
45276789Sdim    LE_EQUAL     =  0,
46276789Sdim    LE_GREATER   =  1,
47276789Sdim    LE_UNORDERED =  1
48276789Sdim};
49276789Sdim
50276789SdimCOMPILER_RT_ABI enum LE_RESULT
51276789Sdim__lesf2(fp_t a, fp_t b) {
52276789Sdim
53276789Sdim    const srep_t aInt = toRep(a);
54276789Sdim    const srep_t bInt = toRep(b);
55276789Sdim    const rep_t aAbs = aInt & absMask;
56276789Sdim    const rep_t bAbs = bInt & absMask;
57276789Sdim
58276789Sdim    // If either a or b is NaN, they are unordered.
59276789Sdim    if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
60276789Sdim
61276789Sdim    // If a and b are both zeros, they are equal.
62276789Sdim    if ((aAbs | bAbs) == 0) return LE_EQUAL;
63276789Sdim
64276789Sdim    // If at least one of a and b is positive, we get the same result comparing
65276789Sdim    // a and b as signed integers as we would with a fp_ting-point compare.
66276789Sdim    if ((aInt & bInt) >= 0) {
67276789Sdim        if (aInt < bInt) return LE_LESS;
68276789Sdim        else if (aInt == bInt) return LE_EQUAL;
69276789Sdim        else return LE_GREATER;
70276789Sdim    }
71276789Sdim
72276789Sdim    // Otherwise, both are negative, so we need to flip the sense of the
73276789Sdim    // comparison to get the correct result.  (This assumes a twos- or ones-
74276789Sdim    // complement integer representation; if integers are represented in a
75276789Sdim    // sign-magnitude representation, then this flip is incorrect).
76276789Sdim    else {
77276789Sdim        if (aInt > bInt) return LE_LESS;
78276789Sdim        else if (aInt == bInt) return LE_EQUAL;
79276789Sdim        else return LE_GREATER;
80276789Sdim    }
81276789Sdim}
82276789Sdim
83296417Sdim#if defined(__ELF__)
84296417Sdim// Alias for libgcc compatibility
85296417SdimFNALIAS(__cmpsf2, __lesf2);
86296417Sdim#endif
87296417Sdim
88276789Sdimenum GE_RESULT {
89276789Sdim    GE_LESS      = -1,
90276789Sdim    GE_EQUAL     =  0,
91276789Sdim    GE_GREATER   =  1,
92276789Sdim    GE_UNORDERED = -1   // Note: different from LE_UNORDERED
93276789Sdim};
94276789Sdim
95276789SdimCOMPILER_RT_ABI enum GE_RESULT
96276789Sdim__gesf2(fp_t a, fp_t b) {
97276789Sdim
98276789Sdim    const srep_t aInt = toRep(a);
99276789Sdim    const srep_t bInt = toRep(b);
100276789Sdim    const rep_t aAbs = aInt & absMask;
101276789Sdim    const rep_t bAbs = bInt & absMask;
102276789Sdim
103276789Sdim    if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
104276789Sdim    if ((aAbs | bAbs) == 0) return GE_EQUAL;
105276789Sdim    if ((aInt & bInt) >= 0) {
106276789Sdim        if (aInt < bInt) return GE_LESS;
107276789Sdim        else if (aInt == bInt) return GE_EQUAL;
108276789Sdim        else return GE_GREATER;
109276789Sdim    } else {
110276789Sdim        if (aInt > bInt) return GE_LESS;
111276789Sdim        else if (aInt == bInt) return GE_EQUAL;
112276789Sdim        else return GE_GREATER;
113276789Sdim    }
114276789Sdim}
115276789Sdim
116276789SdimARM_EABI_FNALIAS(fcmpun, unordsf2)
117276789Sdim
118276789SdimCOMPILER_RT_ABI int
119276789Sdim__unordsf2(fp_t a, fp_t b) {
120276789Sdim    const rep_t aAbs = toRep(a) & absMask;
121276789Sdim    const rep_t bAbs = toRep(b) & absMask;
122276789Sdim    return aAbs > infRep || bAbs > infRep;
123276789Sdim}
124276789Sdim
125276789Sdim// The following are alternative names for the preceding routines.
126276789Sdim
127276789SdimCOMPILER_RT_ABI enum LE_RESULT
128276789Sdim__eqsf2(fp_t a, fp_t b) {
129276789Sdim    return __lesf2(a, b);
130276789Sdim}
131276789Sdim
132276789SdimCOMPILER_RT_ABI enum LE_RESULT
133276789Sdim__ltsf2(fp_t a, fp_t b) {
134276789Sdim    return __lesf2(a, b);
135276789Sdim}
136276789Sdim
137276789SdimCOMPILER_RT_ABI enum LE_RESULT
138276789Sdim__nesf2(fp_t a, fp_t b) {
139276789Sdim    return __lesf2(a, b);
140276789Sdim}
141276789Sdim
142276789SdimCOMPILER_RT_ABI enum GE_RESULT
143276789Sdim__gtsf2(fp_t a, fp_t b) {
144276789Sdim    return __gesf2(a, b);
145276789Sdim}
146