[libc-commits] [libc] [libc][math] Add Generic Comparison Operations for floating point types (PR #144983)
Krishna Pandey via libc-commits
libc-commits at lists.llvm.org
Fri Jul 4 11:58:50 PDT 2025
https://github.com/krishna2803 updated https://github.com/llvm/llvm-project/pull/144983
>From 8b4ef346e4386cad6d4a0a295ddfb4e8dd3c9c2c Mon Sep 17 00:00:00 2001
From: krishna2803 <kpandey81930 at gmail.com>
Date: Fri, 20 Jun 2025 06:57:34 +0530
Subject: [PATCH 01/15] feat: add ComparisionOperations for FPBits
Signed-off-by: krishna2803 <kpandey81930 at gmail.com>
---
libc/src/__support/FPUtil/CMakeLists.txt | 10 ++
.../__support/FPUtil/ComparisionOperations.h | 121 ++++++++++++++++++
2 files changed, 131 insertions(+)
create mode 100644 libc/src/__support/FPUtil/ComparisionOperations.h
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index bfe0170f09fd9..16989cdecf6fb 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -209,6 +209,16 @@ add_header_library(
libc.src.__support.macros.properties.types
)
+add_header_library(
+ comparision_operations
+ HDRS
+ ComparisionOperations.h
+ DEPENDS
+ .fp_bits
+ .fenv_impl
+ libc.src.__support.config
+)
+
add_header_library(
hypot
HDRS
diff --git a/libc/src/__support/FPUtil/ComparisionOperations.h b/libc/src/__support/FPUtil/ComparisionOperations.h
new file mode 100644
index 0000000000000..fed3927eeecff
--- /dev/null
+++ b/libc/src/__support/FPUtil/ComparisionOperations.h
@@ -0,0 +1,121 @@
+//===-- Comparision operations on floating point numbers --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
+#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
+
+#include "FEnvImpl.h" // raise_except_if_required
+#include "FPBits.h" // FPBits<T>
+#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+namespace fputil {
+
+// IEEE Standard 754-2019. Section 5.11
+// Rules for comparision within the same floating point type
+// 1. +0 = −0
+// 2. (i) +inf = +inf
+// (ii) -inf = -inf
+// (iii) -inf != +inf
+// 3. Any comparision with NaN return false except (NaN != NaN => true)
+template <typename T>
+LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> equals(T x,
+ T y) {
+ using FPBits = FPBits<T>;
+ FPBits x_bits(x);
+ FPBits y_bits(y);
+
+ if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
+ fputil::raise_except_if_required(FE_INVALID);
+
+ // NaN == x returns false for every x
+ if (x_bits.is_nan() || y_bits.is_nan())
+ return false;
+
+ // +/- 0 == +/- 0
+ if (x_bits.is_zero() && y_bits.is_zero())
+ return true;
+
+ // should also work for comparisions of different signs
+ return x_bits.uintval() == y_bits.uintval();
+}
+
+// !(x == y) => x != y
+template <typename T>
+LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
+not_equals(T x, T y) {
+ return !equals(x, y);
+}
+
+// Rules:
+// 1. -inf < x (x != -inf)
+// 2. x < +inf (x != +inf)
+// 3. Any comparision with NaN return false
+template <typename T>
+LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x,
+ T y) {
+ using FPBits = FPBits<T>;
+ FPBits x_bits(x);
+ FPBits y_bits(y);
+
+ if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
+ fputil::raise_except_if_required(FE_INVALID);
+
+ // Any comparision with NaN returns false
+ if (x_bits.is_nan() || y_bits.is_nan())
+ return false;
+
+ if (x_bits.is_zero() && y_bits.is_zero())
+ return false;
+
+ if (x_bits.is_neg() && y_bits.is_pos())
+ return true;
+
+ if (x_bits.is_pos() && y_bits.is_neg())
+ return false;
+
+ // since we store the float in the format: s | e | m
+ // the comparisions should work if we directly compare the uintval's
+
+ // TODO: verify if we should use FPBits.get_exponent and FPBits.get_mantissa
+ // instead of directly comparing uintval's
+
+ // both negative
+ if (x_bits.is_neg())
+ return x_bits.uintval() > y_bits.uintval();
+
+ // both positive
+ return x_bits.uintval() < y_bits.uintval();
+}
+
+// x < y => y > x
+template <typename T>
+LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
+greater_than(T x, T y) {
+ return less_than(y, x);
+}
+
+// following is expression is correct, accounting for NaN case(s) as well
+// x <= y => (x < y) || (x == y)
+template <typename T>
+LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
+less_than_or_equals(T x, T y) {
+ return less_than(x, y) || equals(x, y);
+}
+
+// x >= y => (x > y) || (x == y) => (y < x) || (x == y)
+template <typename T>
+LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
+greater_than_or_equals(T x, T y) {
+ return less_than(y, x) || equals(x, y);
+}
+
+} // namespace fputil
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
>From f0997ab545a6845b9bf38e03e3bde4aac9612c7e Mon Sep 17 00:00:00 2001
From: krishna2803 <kpandey81930 at gmail.com>
Date: Fri, 20 Jun 2025 06:58:00 +0530
Subject: [PATCH 02/15] style: clang-format
Signed-off-by: krishna2803 <kpandey81930 at gmail.com>
---
libc/src/__support/FPUtil/ComparisionOperations.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libc/src/__support/FPUtil/ComparisionOperations.h b/libc/src/__support/FPUtil/ComparisionOperations.h
index fed3927eeecff..b8551998ba2be 100644
--- a/libc/src/__support/FPUtil/ComparisionOperations.h
+++ b/libc/src/__support/FPUtil/ComparisionOperations.h
@@ -9,8 +9,8 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
-#include "FEnvImpl.h" // raise_except_if_required
-#include "FPBits.h" // FPBits<T>
+#include "FEnvImpl.h" // raise_except_if_required
+#include "FPBits.h" // FPBits<T>
#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL
namespace LIBC_NAMESPACE_DECL {
>From 2a4dc5fc98c0e56c3e888bf2e216ee1fec1fb5d9 Mon Sep 17 00:00:00 2001
From: krishna2803 <kpandey81930 at gmail.com>
Date: Fri, 20 Jun 2025 10:07:07 +0530
Subject: [PATCH 03/15] chore: reorganize includes
Signed-off-by: krishna2803 <kpandey81930 at gmail.com>
---
libc/src/__support/FPUtil/CMakeLists.txt | 1 +
libc/src/__support/FPUtil/ComparisionOperations.h | 7 ++++---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 16989cdecf6fb..6b2ca3bb77fd9 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -216,6 +216,7 @@ add_header_library(
DEPENDS
.fp_bits
.fenv_impl
+ libc.src.__support.CPP.type_traits
libc.src.__support.config
)
diff --git a/libc/src/__support/FPUtil/ComparisionOperations.h b/libc/src/__support/FPUtil/ComparisionOperations.h
index b8551998ba2be..a4cdd4214b4db 100644
--- a/libc/src/__support/FPUtil/ComparisionOperations.h
+++ b/libc/src/__support/FPUtil/ComparisionOperations.h
@@ -9,9 +9,10 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
-#include "FEnvImpl.h" // raise_except_if_required
-#include "FPBits.h" // FPBits<T>
-#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL
+#include "FEnvImpl.h" // raise_except_if_required
+#include "FPBits.h" // FPBits<T>
+#include "src/__support/CPP/type_traits.h" // enable_if, is_floating_point
+#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL
namespace LIBC_NAMESPACE_DECL {
namespace fputil {
>From e44e43e11f1fc754f43bb0cad5c8f33585be41e2 Mon Sep 17 00:00:00 2001
From: krishna2803 <kpandey81930 at gmail.com>
Date: Fri, 20 Jun 2025 10:07:34 +0530
Subject: [PATCH 04/15] feat: add basic unittests for Comparision Operations
Signed-off-by: krishna2803 <kpandey81930 at gmail.com>
---
libc/test/src/__support/FPUtil/CMakeLists.txt | 12 +
.../FPUtil/comparision_operations_test.cpp | 254 ++++++++++++++++++
2 files changed, 266 insertions(+)
create mode 100644 libc/test/src/__support/FPUtil/comparision_operations_test.cpp
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 1e64e9ba425a5..851506ccec6e2 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -38,3 +38,15 @@ add_fp_unittest(
DEPENDS
libc.src.__support.FPUtil.rounding_mode
)
+
+add_fp_unittest(
+ comparision_operations_test
+ SUITE
+ libc-fputil-tests
+ SRCS
+ comparision_operations_test.cpp
+ DEPENDS
+ libc.src.__support.FPUtil.fp_bits
+ # libc.src.__support.FPUtil.comparision_operations
+)
+
diff --git a/libc/test/src/__support/FPUtil/comparision_operations_test.cpp b/libc/test/src/__support/FPUtil/comparision_operations_test.cpp
new file mode 100644
index 0000000000000..a2ac13723bae5
--- /dev/null
+++ b/libc/test/src/__support/FPUtil/comparision_operations_test.cpp
@@ -0,0 +1,254 @@
+//===-- Unittests for Comparision Operations for FPBits class -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/FPUtil/ComparisionOperations.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/properties/types.h"
+#include "src/__support/sign.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LIBC_NAMESPACE::fputil::equals;
+using LIBC_NAMESPACE::fputil::greater_than;
+using LIBC_NAMESPACE::fputil::greater_than_or_equals;
+using LIBC_NAMESPACE::fputil::less_than;
+using LIBC_NAMESPACE::fputil::less_than_or_equals;
+using LIBC_NAMESPACE::fputil::not_equals;
+
+// FIXME: currently i have used NAN here
+// need to find a better way to get a NAN floating point type
+// - need to see if FPRep could be used?
+
+#define TEST_EQUALS(Name, Type) \
+ TEST(LlvmLibcDyadic##Name##Test, Equals) { \
+ using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
+ Type pos_zero = Bits::zero().get_val(); \
+ Type neg_zero = -pos_zero; \
+ Type pos_inf = Bits::inf().get_val(); \
+ Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
+ Type nan = NAN; \
+ Type pos_normal = Type(3.14); \
+ Type neg_normal = Type(-2.71); \
+ Type pos_large = Type(1000000.0); \
+ Type neg_large = Type(-1000000.0); \
+ \
+ EXPECT_TRUE(equals(pos_zero, pos_zero)); \
+ EXPECT_TRUE(equals(neg_zero, neg_zero)); \
+ EXPECT_TRUE(equals(pos_inf, pos_inf)); \
+ EXPECT_TRUE(equals(neg_inf, neg_inf)); \
+ EXPECT_TRUE(equals(pos_normal, pos_normal)); \
+ EXPECT_TRUE(equals(neg_normal, neg_normal)); \
+ \
+ EXPECT_TRUE(equals(pos_zero, neg_zero)); \
+ EXPECT_TRUE(equals(neg_zero, pos_zero)); \
+ \
+ EXPECT_FALSE(equals(pos_normal, neg_normal)); \
+ EXPECT_FALSE(equals(pos_normal, pos_large)); \
+ EXPECT_FALSE(equals(pos_inf, neg_inf)); \
+ EXPECT_FALSE(equals(pos_inf, pos_normal)); \
+ EXPECT_FALSE(equals(neg_inf, neg_normal)); \
+ EXPECT_FALSE(equals(pos_large, neg_large)); \
+ \
+ EXPECT_FALSE(equals(nan, nan)); \
+ EXPECT_FALSE(equals(nan, pos_normal)); \
+ EXPECT_FALSE(equals(nan, pos_zero)); \
+ EXPECT_FALSE(equals(nan, pos_inf)); \
+ EXPECT_FALSE(equals(pos_normal, nan)); \
+ }
+
+#define TEST_NOT_EQUALS(Name, Type) \
+ TEST(LlvmLibcDyadic##Name##Test, NotEquals) { \
+ using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
+ Type pos_zero = Bits::zero().get_val(); \
+ Type neg_zero = Bits::zero(Sign::NEG).get_val(); \
+ Type pos_inf = Bits::inf().get_val(); \
+ Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
+ Type nan = NAN; \
+ Type pos_normal = Type(3.14); \
+ Type neg_normal = Type(-2.71); \
+ Type pos_large = Type(1000000.0); \
+ Type neg_large = Type(-1000000.0); \
+ \
+ EXPECT_FALSE(not_equals(pos_zero, pos_zero)); \
+ EXPECT_FALSE(not_equals(pos_zero, neg_zero)); \
+ EXPECT_FALSE(not_equals(pos_inf, pos_inf)); \
+ EXPECT_FALSE(not_equals(neg_inf, neg_inf)); \
+ EXPECT_FALSE(not_equals(pos_normal, pos_normal)); \
+ \
+ EXPECT_TRUE(not_equals(pos_normal, neg_normal)); \
+ EXPECT_TRUE(not_equals(pos_inf, neg_inf)); \
+ EXPECT_TRUE(not_equals(pos_normal, pos_zero)); \
+ EXPECT_TRUE(not_equals(pos_large, neg_large)); \
+ EXPECT_TRUE(not_equals(pos_inf, pos_normal)); \
+ \
+ EXPECT_TRUE(not_equals(nan, nan)); \
+ EXPECT_TRUE(not_equals(nan, pos_normal)); \
+ EXPECT_TRUE(not_equals(nan, pos_zero)); \
+ EXPECT_TRUE(not_equals(nan, pos_inf)); \
+ EXPECT_TRUE(not_equals(pos_normal, nan)); \
+ }
+
+#define TEST_LESS_THAN(Name, Type) \
+ TEST(LlvmLibcDyadic##Name##Test, LessThan) { \
+ using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
+ Type pos_zero = Bits::zero().get_val(); \
+ Type neg_zero = -pos_zero; \
+ Type pos_inf = Bits::inf().get_val(); \
+ Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
+ Type nan = NAN; \
+ Type pos_small = Type(0.1); \
+ Type neg_small = Type(-0.1); \
+ Type pos_large = Type(1000000.0); \
+ Type neg_large = Type(-1000000.0); \
+ \
+ EXPECT_TRUE(less_than(neg_small, pos_small)); \
+ EXPECT_TRUE(less_than(pos_small, pos_large)); \
+ EXPECT_TRUE(less_than(neg_large, neg_small)); \
+ EXPECT_FALSE(less_than(pos_large, pos_small)); \
+ EXPECT_FALSE(less_than(pos_small, neg_small)); \
+ \
+ EXPECT_FALSE(less_than(pos_zero, neg_zero)); \
+ EXPECT_FALSE(less_than(neg_zero, pos_zero)); \
+ EXPECT_FALSE(less_than(pos_zero, pos_zero)); \
+ \
+ EXPECT_TRUE(less_than(neg_small, pos_zero)); \
+ EXPECT_TRUE(less_than(neg_zero, pos_small)); \
+ EXPECT_FALSE(less_than(pos_small, pos_zero)); \
+ \
+ EXPECT_TRUE(less_than(neg_inf, pos_inf)); \
+ EXPECT_TRUE(less_than(neg_inf, neg_small)); \
+ EXPECT_TRUE(less_than(pos_small, pos_inf)); \
+ EXPECT_FALSE(less_than(pos_inf, pos_small)); \
+ \
+ EXPECT_FALSE(less_than(pos_small, pos_small)); \
+ EXPECT_FALSE(less_than(neg_inf, neg_inf)); \
+ \
+ EXPECT_FALSE(less_than(nan, pos_small)); \
+ EXPECT_FALSE(less_than(pos_small, nan)); \
+ EXPECT_FALSE(less_than(nan, nan)); \
+ }
+
+#define TEST_GREATER_THAN(Name, Type) \
+ TEST(LlvmLibcDyadic##Name##Test, GreaterThan) { \
+ using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
+ Type pos_zero = Bits::zero().get_val(); \
+ Type neg_zero = -pos_zero; \
+ Type pos_inf = Bits::inf().get_val(); \
+ Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
+ Type nan = NAN; \
+ Type pos_small = Type(0.1); \
+ Type neg_small = Type(-0.1); \
+ Type pos_large = Type(1000000.0); \
+ Type neg_large = Type(-1000000.0); \
+ \
+ EXPECT_TRUE(greater_than(pos_small, neg_small)); \
+ EXPECT_TRUE(greater_than(pos_large, pos_small)); \
+ EXPECT_TRUE(greater_than(neg_small, neg_large)); \
+ EXPECT_FALSE(greater_than(pos_small, pos_large)); \
+ EXPECT_FALSE(greater_than(neg_small, pos_small)); \
+ \
+ EXPECT_FALSE(greater_than(pos_zero, neg_zero)); \
+ EXPECT_FALSE(greater_than(neg_zero, pos_zero)); \
+ \
+ EXPECT_TRUE(greater_than(pos_inf, neg_inf)); \
+ EXPECT_TRUE(greater_than(pos_inf, pos_small)); \
+ EXPECT_TRUE(greater_than(pos_small, neg_inf)); \
+ EXPECT_FALSE(greater_than(neg_inf, pos_inf)); \
+ \
+ EXPECT_FALSE(greater_than(pos_small, pos_small)); \
+ EXPECT_FALSE(greater_than(pos_inf, pos_inf)); \
+ \
+ EXPECT_FALSE(greater_than(nan, pos_small)); \
+ EXPECT_FALSE(greater_than(pos_small, nan)); \
+ EXPECT_FALSE(greater_than(nan, nan)); \
+ }
+
+#define TEST_LESS_THAN_OR_EQUALS(Name, Type) \
+ TEST(LlvmLibcDyadic##Name##Test, LessThanOrEquals) { \
+ using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
+ Type pos_zero = Bits::zero().get_val(); \
+ Type neg_zero = -pos_zero; \
+ Type pos_inf = Bits::inf().get_val(); \
+ Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
+ Type nan = NAN; \
+ Type pos_small = Type(0.1); \
+ Type neg_small = Type(-0.1); \
+ Type pos_large = Type(1000000.0); \
+ Type neg_large = Type(-1000000.0); \
+ \
+ EXPECT_TRUE(less_than_or_equals(neg_small, pos_small)); \
+ EXPECT_TRUE(less_than_or_equals(pos_small, pos_large)); \
+ EXPECT_TRUE(less_than_or_equals(neg_inf, pos_small)); \
+ \
+ EXPECT_TRUE(less_than_or_equals(pos_small, pos_small)); \
+ EXPECT_TRUE(less_than_or_equals(pos_zero, neg_zero)); \
+ EXPECT_TRUE(less_than_or_equals(pos_inf, pos_inf)); \
+ \
+ EXPECT_FALSE(less_than_or_equals(pos_small, neg_small)); \
+ EXPECT_FALSE(less_than_or_equals(pos_large, pos_small)); \
+ EXPECT_FALSE(less_than_or_equals(pos_inf, pos_small)); \
+ \
+ EXPECT_TRUE(less_than_or_equals(neg_large, pos_small)); \
+ EXPECT_FALSE(less_than_or_equals(pos_large, neg_small)); \
+ \
+ EXPECT_FALSE(less_than_or_equals(nan, pos_small)); \
+ EXPECT_FALSE(less_than_or_equals(pos_small, nan)); \
+ EXPECT_FALSE(less_than_or_equals(nan, nan)); \
+ }
+
+#define TEST_GREATER_THAN_OR_EQUALS(Name, Type) \
+ TEST(LlvmLibcDyadic##Name##Test, GreaterThanOrEquals) { \
+ using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
+ Type pos_zero = Bits::zero().get_val(); \
+ Type neg_zero = -pos_zero; \
+ Type pos_inf = Bits::inf().get_val(); \
+ Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
+ Type nan = NAN; \
+ Type pos_small = Type(0.1); \
+ Type neg_small = Type(-0.1); \
+ Type pos_large = Type(1000000.0); \
+ Type neg_large = Type(-1000000.0); \
+ \
+ EXPECT_TRUE(greater_than_or_equals(pos_small, neg_small)); \
+ EXPECT_TRUE(greater_than_or_equals(pos_large, pos_small)); \
+ EXPECT_TRUE(greater_than_or_equals(pos_inf, pos_small)); \
+ \
+ EXPECT_TRUE(greater_than_or_equals(pos_small, pos_small)); \
+ EXPECT_TRUE(greater_than_or_equals(pos_zero, neg_zero)); \
+ EXPECT_TRUE(greater_than_or_equals(neg_inf, neg_inf)); \
+ \
+ EXPECT_FALSE(greater_than_or_equals(neg_small, pos_small)); \
+ EXPECT_FALSE(greater_than_or_equals(pos_small, pos_large)); \
+ EXPECT_FALSE(greater_than_or_equals(neg_inf, pos_small)); \
+ \
+ EXPECT_TRUE(greater_than_or_equals(pos_large, neg_small)); \
+ EXPECT_FALSE(greater_than_or_equals(neg_large, pos_small)); \
+ \
+ EXPECT_FALSE(greater_than_or_equals(nan, pos_small)); \
+ EXPECT_FALSE(greater_than_or_equals(pos_small, nan)); \
+ EXPECT_FALSE(greater_than_or_equals(nan, nan)); \
+ }
+
+#define TEST_COMPARISON_OPS(Name, Type) \
+ TEST_EQUALS(Name, Type) \
+ TEST_NOT_EQUALS(Name, Type) \
+ TEST_LESS_THAN(Name, Type) \
+ TEST_GREATER_THAN(Name, Type) \
+ TEST_LESS_THAN_OR_EQUALS(Name, Type) \
+ TEST_GREATER_THAN_OR_EQUALS(Name, Type)
+
+TEST_COMPARISON_OPS(Float, float)
+TEST_COMPARISON_OPS(Double, double)
+// FIXME: error: expected '(' for function-style cast or type construction
+// TEST_COMPARISON_OPS(LongDouble, (long double))
+#ifdef LIBC_TYPES_HAS_FLOAT16
+TEST_COMPARISON_OPS(Float16, float16)
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+// TODO: add other types if this is correct?
>From 8c30aa2672a9f897f701611ef134e5f2b581f774 Mon Sep 17 00:00:00 2001
From: krishna2803 <kpandey81930 at gmail.com>
Date: Fri, 20 Jun 2025 10:17:19 +0530
Subject: [PATCH 05/15] fix: spelling
Signed-off-by: krishna2803 <kpandey81930 at gmail.com>
---
libc/src/__support/FPUtil/CMakeLists.txt | 4 ++--
...ionOperations.h => ComparisonOperations.h} | 20 +++++++++----------
libc/test/src/__support/FPUtil/CMakeLists.txt | 6 +++---
...est.cpp => comparison_operations_test.cpp} | 4 ++--
4 files changed, 17 insertions(+), 17 deletions(-)
rename libc/src/__support/FPUtil/{ComparisionOperations.h => ComparisonOperations.h} (83%)
rename libc/test/src/__support/FPUtil/{comparision_operations_test.cpp => comparison_operations_test.cpp} (99%)
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 6b2ca3bb77fd9..ce068df8d4c03 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -210,9 +210,9 @@ add_header_library(
)
add_header_library(
- comparision_operations
+ comparison_operations
HDRS
- ComparisionOperations.h
+ ComparisonOperations.h
DEPENDS
.fp_bits
.fenv_impl
diff --git a/libc/src/__support/FPUtil/ComparisionOperations.h b/libc/src/__support/FPUtil/ComparisonOperations.h
similarity index 83%
rename from libc/src/__support/FPUtil/ComparisionOperations.h
rename to libc/src/__support/FPUtil/ComparisonOperations.h
index a4cdd4214b4db..cf71a14df0465 100644
--- a/libc/src/__support/FPUtil/ComparisionOperations.h
+++ b/libc/src/__support/FPUtil/ComparisonOperations.h
@@ -1,4 +1,4 @@
-//===-- Comparision operations on floating point numbers --------*- C++ -*-===//
+//===-- Comparison operations on floating point numbers --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
-#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
+#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H
+#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H
#include "FEnvImpl.h" // raise_except_if_required
#include "FPBits.h" // FPBits<T>
@@ -18,12 +18,12 @@ namespace LIBC_NAMESPACE_DECL {
namespace fputil {
// IEEE Standard 754-2019. Section 5.11
-// Rules for comparision within the same floating point type
+// Rules for comparison within the same floating point type
// 1. +0 = −0
// 2. (i) +inf = +inf
// (ii) -inf = -inf
// (iii) -inf != +inf
-// 3. Any comparision with NaN return false except (NaN != NaN => true)
+// 3. Any comparison with NaN return false except (NaN != NaN => true)
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> equals(T x,
T y) {
@@ -42,7 +42,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> equals(T x,
if (x_bits.is_zero() && y_bits.is_zero())
return true;
- // should also work for comparisions of different signs
+ // should also work for comparisons of different signs
return x_bits.uintval() == y_bits.uintval();
}
@@ -56,7 +56,7 @@ not_equals(T x, T y) {
// Rules:
// 1. -inf < x (x != -inf)
// 2. x < +inf (x != +inf)
-// 3. Any comparision with NaN return false
+// 3. Any comparison with NaN return false
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x,
T y) {
@@ -67,7 +67,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x,
if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
fputil::raise_except_if_required(FE_INVALID);
- // Any comparision with NaN returns false
+ // Any comparison with NaN returns false
if (x_bits.is_nan() || y_bits.is_nan())
return false;
@@ -81,7 +81,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x,
return false;
// since we store the float in the format: s | e | m
- // the comparisions should work if we directly compare the uintval's
+ // the comparisons should work if we directly compare the uintval's
// TODO: verify if we should use FPBits.get_exponent and FPBits.get_mantissa
// instead of directly comparing uintval's
@@ -119,4 +119,4 @@ greater_than_or_equals(T x, T y) {
} // namespace fputil
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISIONOPERATIONS_H
+#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 851506ccec6e2..1dcd666ec3d25 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -40,13 +40,13 @@ add_fp_unittest(
)
add_fp_unittest(
- comparision_operations_test
+ comparison_operations_test
SUITE
libc-fputil-tests
SRCS
- comparision_operations_test.cpp
+ comparison_operations_test.cpp
DEPENDS
libc.src.__support.FPUtil.fp_bits
- # libc.src.__support.FPUtil.comparision_operations
+ # libc.src.__support.FPUtil.comparison_operations
)
diff --git a/libc/test/src/__support/FPUtil/comparision_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
similarity index 99%
rename from libc/test/src/__support/FPUtil/comparision_operations_test.cpp
rename to libc/test/src/__support/FPUtil/comparison_operations_test.cpp
index a2ac13723bae5..10ea0a8004dcc 100644
--- a/libc/test/src/__support/FPUtil/comparision_operations_test.cpp
+++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
@@ -1,4 +1,4 @@
-//===-- Unittests for Comparision Operations for FPBits class -------------===//
+//===-- Unittests for Comparison Operations for FPBits class -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "src/__support/FPUtil/ComparisionOperations.h"
+#include "src/__support/FPUtil/ComparisonOperations.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/macros/properties/types.h"
#include "src/__support/sign.h"
>From d1e54eddd86f9fe39873e5711026475453eb5150 Mon Sep 17 00:00:00 2001
From: krishna2803 <kpandey81930 at gmail.com>
Date: Fri, 20 Jun 2025 10:23:07 +0530
Subject: [PATCH 06/15] chore: change `Dyadic` -> `ComparisonOperations` under
tests
Signed-off-by: krishna2803 <kpandey81930 at gmail.com>
---
.../__support/FPUtil/comparison_operations_test.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
index 10ea0a8004dcc..94c234446ad8e 100644
--- a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
+++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
@@ -26,7 +26,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
// - need to see if FPRep could be used?
#define TEST_EQUALS(Name, Type) \
- TEST(LlvmLibcDyadic##Name##Test, Equals) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, Equals) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
@@ -63,7 +63,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_NOT_EQUALS(Name, Type) \
- TEST(LlvmLibcDyadic##Name##Test, NotEquals) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, NotEquals) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = Bits::zero(Sign::NEG).get_val(); \
@@ -95,7 +95,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_LESS_THAN(Name, Type) \
- TEST(LlvmLibcDyadic##Name##Test, LessThan) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, LessThan) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
@@ -135,7 +135,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_GREATER_THAN(Name, Type) \
- TEST(LlvmLibcDyadic##Name##Test, GreaterThan) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, GreaterThan) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
@@ -170,7 +170,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_LESS_THAN_OR_EQUALS(Name, Type) \
- TEST(LlvmLibcDyadic##Name##Test, LessThanOrEquals) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, LessThanOrEquals) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
@@ -203,7 +203,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_GREATER_THAN_OR_EQUALS(Name, Type) \
- TEST(LlvmLibcDyadic##Name##Test, GreaterThanOrEquals) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, GreaterThanOrEquals) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
>From 80fd69d80957931525af2b291093f3c16c6d43b0 Mon Sep 17 00:00:00 2001
From: krishna2803 <kpandey81930 at gmail.com>
Date: Fri, 20 Jun 2025 10:25:24 +0530
Subject: [PATCH 07/15] style: clang-format
Signed-off-by: krishna2803 <kpandey81930 at gmail.com>
---
.../__support/FPUtil/comparison_operations_test.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
index 94c234446ad8e..47494ecf70fe4 100644
--- a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
+++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
@@ -26,7 +26,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
// - need to see if FPRep could be used?
#define TEST_EQUALS(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, Equals) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, Equals) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
@@ -63,7 +63,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_NOT_EQUALS(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, NotEquals) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, NotEquals) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = Bits::zero(Sign::NEG).get_val(); \
@@ -95,7 +95,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_LESS_THAN(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, LessThan) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, LessThan) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
@@ -135,7 +135,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_GREATER_THAN(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, GreaterThan) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, GreaterThan) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
@@ -170,7 +170,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_LESS_THAN_OR_EQUALS(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, LessThanOrEquals) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, LessThanOrEquals) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
@@ -203,7 +203,7 @@ using LIBC_NAMESPACE::fputil::not_equals;
}
#define TEST_GREATER_THAN_OR_EQUALS(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, GreaterThanOrEquals) { \
+ TEST(LlvmLibc##Name##ComparisionOperationsTest, GreaterThanOrEquals) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
Type pos_zero = Bits::zero().get_val(); \
Type neg_zero = -pos_zero; \
>From 528f08adee6cc4b7ee4737529d56e63cd7367056 Mon Sep 17 00:00:00 2001
From: Krishna Pandey <kpandey81930 at gmail.com>
Date: Tue, 1 Jul 2025 02:04:09 +0530
Subject: [PATCH 08/15] style: nits
Signed-off-by: Krishna Pandey <kpandey81930 at gmail.com>
---
libc/src/__support/FPUtil/CMakeLists.txt | 4 ++--
libc/test/src/__support/FPUtil/CMakeLists.txt | 4 +++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index ce068df8d4c03..70f5cea370fa9 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -214,10 +214,10 @@ add_header_library(
HDRS
ComparisonOperations.h
DEPENDS
- .fp_bits
.fenv_impl
- libc.src.__support.CPP.type_traits
+ .fp_bits
libc.src.__support.config
+ libc.src.__support.CPP.type_traits
)
add_header_library(
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 1dcd666ec3d25..5b63de0a6e9e4 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -47,6 +47,8 @@ add_fp_unittest(
comparison_operations_test.cpp
DEPENDS
libc.src.__support.FPUtil.fp_bits
+ # FIXME: adding the following doesn't generate the build files for comp-ops
# libc.src.__support.FPUtil.comparison_operations
+ libc.src.__support.macros.properties.types
+ libc.src.__support.sign
)
-
>From 8049d5cc9c3e7ecb704148609ab71f83caf0296e Mon Sep 17 00:00:00 2001
From: Krishna Pandey <kpandey81930 at gmail.com>
Date: Wed, 2 Jul 2025 20:54:56 +0530
Subject: [PATCH 09/15] fix: typo in CMakeLists.txt
Signed-off-by: Krishna Pandey <kpandey81930 at gmail.com>
---
libc/src/__support/FPUtil/CMakeLists.txt | 2 +-
libc/test/src/__support/FPUtil/CMakeLists.txt | 3 +--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 70f5cea370fa9..33539178ae950 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -216,7 +216,7 @@ add_header_library(
DEPENDS
.fenv_impl
.fp_bits
- libc.src.__support.config
+ libc.src.__support.macros.config
libc.src.__support.CPP.type_traits
)
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 5b63de0a6e9e4..9e3ebcc36c936 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -47,8 +47,7 @@ add_fp_unittest(
comparison_operations_test.cpp
DEPENDS
libc.src.__support.FPUtil.fp_bits
- # FIXME: adding the following doesn't generate the build files for comp-ops
- # libc.src.__support.FPUtil.comparison_operations
+ libc.src.__support.FPUtil.comparison_operations
libc.src.__support.macros.properties.types
libc.src.__support.sign
)
>From 2917e08c1d44129ad104dc8e21c23fa158099ac5 Mon Sep 17 00:00:00 2001
From: Krishna Pandey <kpandey81930 at gmail.com>
Date: Wed, 2 Jul 2025 20:55:28 +0530
Subject: [PATCH 10/15] chore: remove fputil::not_equals
Signed-off-by: Krishna Pandey <kpandey81930 at gmail.com>
---
.../__support/FPUtil/ComparisonOperations.h | 5 +--
.../FPUtil/comparison_operations_test.cpp | 34 -------------------
2 files changed, 3 insertions(+), 36 deletions(-)
diff --git a/libc/src/__support/FPUtil/ComparisonOperations.h b/libc/src/__support/FPUtil/ComparisonOperations.h
index cf71a14df0465..ad8514fd02d40 100644
--- a/libc/src/__support/FPUtil/ComparisonOperations.h
+++ b/libc/src/__support/FPUtil/ComparisonOperations.h
@@ -1,4 +1,4 @@
-//===-- Comparison operations on floating point numbers --------*- C++ -*-===//
+//===-- Comparison operations on floating point numbers ---------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -64,7 +64,8 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x,
FPBits x_bits(x);
FPBits y_bits(y);
- if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
+ if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan() ||
+ x_bits.is_quiet_nan() || y_bits.is_quiet_nan())
fputil::raise_except_if_required(FE_INVALID);
// Any comparison with NaN returns false
diff --git a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
index 47494ecf70fe4..e55a9194d956b 100644
--- a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
+++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
@@ -12,7 +12,6 @@
#include "src/__support/sign.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
-#include "utils/MPFRWrapper/MPFRUtils.h"
using LIBC_NAMESPACE::fputil::equals;
using LIBC_NAMESPACE::fputil::greater_than;
@@ -62,38 +61,6 @@ using LIBC_NAMESPACE::fputil::not_equals;
EXPECT_FALSE(equals(pos_normal, nan)); \
}
-#define TEST_NOT_EQUALS(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, NotEquals) { \
- using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
- Type pos_zero = Bits::zero().get_val(); \
- Type neg_zero = Bits::zero(Sign::NEG).get_val(); \
- Type pos_inf = Bits::inf().get_val(); \
- Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type nan = NAN; \
- Type pos_normal = Type(3.14); \
- Type neg_normal = Type(-2.71); \
- Type pos_large = Type(1000000.0); \
- Type neg_large = Type(-1000000.0); \
- \
- EXPECT_FALSE(not_equals(pos_zero, pos_zero)); \
- EXPECT_FALSE(not_equals(pos_zero, neg_zero)); \
- EXPECT_FALSE(not_equals(pos_inf, pos_inf)); \
- EXPECT_FALSE(not_equals(neg_inf, neg_inf)); \
- EXPECT_FALSE(not_equals(pos_normal, pos_normal)); \
- \
- EXPECT_TRUE(not_equals(pos_normal, neg_normal)); \
- EXPECT_TRUE(not_equals(pos_inf, neg_inf)); \
- EXPECT_TRUE(not_equals(pos_normal, pos_zero)); \
- EXPECT_TRUE(not_equals(pos_large, neg_large)); \
- EXPECT_TRUE(not_equals(pos_inf, pos_normal)); \
- \
- EXPECT_TRUE(not_equals(nan, nan)); \
- EXPECT_TRUE(not_equals(nan, pos_normal)); \
- EXPECT_TRUE(not_equals(nan, pos_zero)); \
- EXPECT_TRUE(not_equals(nan, pos_inf)); \
- EXPECT_TRUE(not_equals(pos_normal, nan)); \
- }
-
#define TEST_LESS_THAN(Name, Type) \
TEST(LlvmLibc##Name##ComparisionOperationsTest, LessThan) { \
using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
@@ -237,7 +204,6 @@ using LIBC_NAMESPACE::fputil::not_equals;
#define TEST_COMPARISON_OPS(Name, Type) \
TEST_EQUALS(Name, Type) \
- TEST_NOT_EQUALS(Name, Type) \
TEST_LESS_THAN(Name, Type) \
TEST_GREATER_THAN(Name, Type) \
TEST_LESS_THAN_OR_EQUALS(Name, Type) \
>From 873c5ed21dca755d3a17ec7750cb0d6503822f2e Mon Sep 17 00:00:00 2001
From: Krishna Pandey <kpandey81930 at gmail.com>
Date: Fri, 4 Jul 2025 18:15:26 +0530
Subject: [PATCH 11/15] chore: remove fputil::not_equals function and TODOs
Signed-off-by: Krishna Pandey <kpandey81930 at gmail.com>
---
libc/src/__support/FPUtil/ComparisonOperations.h | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/libc/src/__support/FPUtil/ComparisonOperations.h b/libc/src/__support/FPUtil/ComparisonOperations.h
index ad8514fd02d40..28e46630c737c 100644
--- a/libc/src/__support/FPUtil/ComparisonOperations.h
+++ b/libc/src/__support/FPUtil/ComparisonOperations.h
@@ -46,13 +46,6 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> equals(T x,
return x_bits.uintval() == y_bits.uintval();
}
-// !(x == y) => x != y
-template <typename T>
-LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
-not_equals(T x, T y) {
- return !equals(x, y);
-}
-
// Rules:
// 1. -inf < x (x != -inf)
// 2. x < +inf (x != +inf)
@@ -84,9 +77,6 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x,
// since we store the float in the format: s | e | m
// the comparisons should work if we directly compare the uintval's
- // TODO: verify if we should use FPBits.get_exponent and FPBits.get_mantissa
- // instead of directly comparing uintval's
-
// both negative
if (x_bits.is_neg())
return x_bits.uintval() > y_bits.uintval();
>From c0676b97fdcb26eca5134245482ccb3bd8b89d29 Mon Sep 17 00:00:00 2001
From: Krishna Pandey <kpandey81930 at gmail.com>
Date: Fri, 4 Jul 2025 19:47:55 +0530
Subject: [PATCH 12/15] chore: add tests for quiet and signaling nans.
Signed-off-by: Krishna Pandey <kpandey81930 at gmail.com>
---
.../FPUtil/comparison_operations_test.cpp | 173 ++++++++++++++----
1 file changed, 142 insertions(+), 31 deletions(-)
diff --git a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
index e55a9194d956b..388d8b7a18e04 100644
--- a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
+++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
@@ -18,11 +18,6 @@ using LIBC_NAMESPACE::fputil::greater_than;
using LIBC_NAMESPACE::fputil::greater_than_or_equals;
using LIBC_NAMESPACE::fputil::less_than;
using LIBC_NAMESPACE::fputil::less_than_or_equals;
-using LIBC_NAMESPACE::fputil::not_equals;
-
-// FIXME: currently i have used NAN here
-// need to find a better way to get a NAN floating point type
-// - need to see if FPRep could be used?
#define TEST_EQUALS(Name, Type) \
TEST(LlvmLibc##Name##ComparisionOperationsTest, Equals) { \
@@ -31,7 +26,8 @@ using LIBC_NAMESPACE::fputil::not_equals;
Type neg_zero = -pos_zero; \
Type pos_inf = Bits::inf().get_val(); \
Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type nan = NAN; \
+ Type qnan = Bits::quiet_nan().get_val(); \
+ Type snan = Bits::signaling_nan().get_val(); \
Type pos_normal = Type(3.14); \
Type neg_normal = Type(-2.71); \
Type pos_large = Type(1000000.0); \
@@ -54,11 +50,39 @@ using LIBC_NAMESPACE::fputil::not_equals;
EXPECT_FALSE(equals(neg_inf, neg_normal)); \
EXPECT_FALSE(equals(pos_large, neg_large)); \
\
- EXPECT_FALSE(equals(nan, nan)); \
- EXPECT_FALSE(equals(nan, pos_normal)); \
- EXPECT_FALSE(equals(nan, pos_zero)); \
- EXPECT_FALSE(equals(nan, pos_inf)); \
- EXPECT_FALSE(equals(pos_normal, nan)); \
+ EXPECT_FALSE(equals(qnan, qnan)); \
+ EXPECT_FALSE(equals(qnan, pos_normal)); \
+ EXPECT_FALSE(equals(qnan, pos_zero)); \
+ EXPECT_FALSE(equals(qnan, pos_inf)); \
+ EXPECT_FALSE(equals(pos_normal, qnan)); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(equals(snan, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(equals(snan, qnan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(equals(qnan, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(equals(snan, pos_normal)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(equals(pos_normal, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(equals(snan, pos_inf)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(equals(snan, pos_zero)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
}
#define TEST_LESS_THAN(Name, Type) \
@@ -68,7 +92,8 @@ using LIBC_NAMESPACE::fputil::not_equals;
Type neg_zero = -pos_zero; \
Type pos_inf = Bits::inf().get_val(); \
Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type nan = NAN; \
+ Type qnan = Bits::quiet_nan().get_val(); \
+ Type snan = Bits::signaling_nan().get_val(); \
Type pos_small = Type(0.1); \
Type neg_small = Type(-0.1); \
Type pos_large = Type(1000000.0); \
@@ -96,9 +121,29 @@ using LIBC_NAMESPACE::fputil::not_equals;
EXPECT_FALSE(less_than(pos_small, pos_small)); \
EXPECT_FALSE(less_than(neg_inf, neg_inf)); \
\
- EXPECT_FALSE(less_than(nan, pos_small)); \
- EXPECT_FALSE(less_than(pos_small, nan)); \
- EXPECT_FALSE(less_than(nan, nan)); \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than(qnan, pos_small)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than(pos_small, qnan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than(qnan, qnan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than(snan, pos_small)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than(pos_small, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than(snan, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
}
#define TEST_GREATER_THAN(Name, Type) \
@@ -108,7 +153,8 @@ using LIBC_NAMESPACE::fputil::not_equals;
Type neg_zero = -pos_zero; \
Type pos_inf = Bits::inf().get_val(); \
Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type nan = NAN; \
+ Type qnan = Bits::quiet_nan().get_val(); \
+ Type snan = Bits::signaling_nan().get_val(); \
Type pos_small = Type(0.1); \
Type neg_small = Type(-0.1); \
Type pos_large = Type(1000000.0); \
@@ -131,9 +177,29 @@ using LIBC_NAMESPACE::fputil::not_equals;
EXPECT_FALSE(greater_than(pos_small, pos_small)); \
EXPECT_FALSE(greater_than(pos_inf, pos_inf)); \
\
- EXPECT_FALSE(greater_than(nan, pos_small)); \
- EXPECT_FALSE(greater_than(pos_small, nan)); \
- EXPECT_FALSE(greater_than(nan, nan)); \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than(qnan, pos_small)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than(pos_small, qnan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than(qnan, qnan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than(snan, pos_small)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than(pos_small, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than(snan, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
}
#define TEST_LESS_THAN_OR_EQUALS(Name, Type) \
@@ -143,7 +209,8 @@ using LIBC_NAMESPACE::fputil::not_equals;
Type neg_zero = -pos_zero; \
Type pos_inf = Bits::inf().get_val(); \
Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type nan = NAN; \
+ Type qnan = Bits::quiet_nan().get_val(); \
+ Type snan = Bits::signaling_nan().get_val(); \
Type pos_small = Type(0.1); \
Type neg_small = Type(-0.1); \
Type pos_large = Type(1000000.0); \
@@ -164,9 +231,29 @@ using LIBC_NAMESPACE::fputil::not_equals;
EXPECT_TRUE(less_than_or_equals(neg_large, pos_small)); \
EXPECT_FALSE(less_than_or_equals(pos_large, neg_small)); \
\
- EXPECT_FALSE(less_than_or_equals(nan, pos_small)); \
- EXPECT_FALSE(less_than_or_equals(pos_small, nan)); \
- EXPECT_FALSE(less_than_or_equals(nan, nan)); \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than_or_equals(qnan, pos_small)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than_or_equals(pos_small, qnan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than_or_equals(qnan, qnan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than_or_equals(snan, pos_small)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than_or_equals(pos_small, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(less_than_or_equals(snan, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
}
#define TEST_GREATER_THAN_OR_EQUALS(Name, Type) \
@@ -176,7 +263,8 @@ using LIBC_NAMESPACE::fputil::not_equals;
Type neg_zero = -pos_zero; \
Type pos_inf = Bits::inf().get_val(); \
Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type nan = NAN; \
+ Type qnan = Bits::quiet_nan().get_val(); \
+ Type snan = Bits::signaling_nan().get_val(); \
Type pos_small = Type(0.1); \
Type neg_small = Type(-0.1); \
Type pos_large = Type(1000000.0); \
@@ -197,9 +285,29 @@ using LIBC_NAMESPACE::fputil::not_equals;
EXPECT_TRUE(greater_than_or_equals(pos_large, neg_small)); \
EXPECT_FALSE(greater_than_or_equals(neg_large, pos_small)); \
\
- EXPECT_FALSE(greater_than_or_equals(nan, pos_small)); \
- EXPECT_FALSE(greater_than_or_equals(pos_small, nan)); \
- EXPECT_FALSE(greater_than_or_equals(nan, nan)); \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than_or_equals(qnan, pos_small)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than_or_equals(pos_small, qnan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than_or_equals(qnan, qnan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than_or_equals(snan, pos_small)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than_or_equals(pos_small, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
+ \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
+ EXPECT_FALSE(greater_than_or_equals(snan, snan)); \
+ EXPECT_FP_EXCEPTION(FE_INVALID); \
}
#define TEST_COMPARISON_OPS(Name, Type) \
@@ -211,10 +319,13 @@ using LIBC_NAMESPACE::fputil::not_equals;
TEST_COMPARISON_OPS(Float, float)
TEST_COMPARISON_OPS(Double, double)
-// FIXME: error: expected '(' for function-style cast or type construction
-// TEST_COMPARISON_OPS(LongDouble, (long double))
+
+// We have to use type alias here, since FPBits<(long double)> is not allowed
+// if we do TEST_COMPARISON_OPS(LongDouble, (long double));
+// and Type(x) for Type = long double evaulates to long double(x)which is not
+// allowed if we do TEST_COMPARISON_OPS(LongDouble, long double);
+using long_double = long double;
+TEST_COMPARISON_OPS(LongDouble, long_double)
#ifdef LIBC_TYPES_HAS_FLOAT16
TEST_COMPARISON_OPS(Float16, float16)
#endif // LIBC_TYPES_HAS_FLOAT16
-
-// TODO: add other types if this is correct?
>From 48f6cbb0baccc0ce75f5026d57139a9936e08ff6 Mon Sep 17 00:00:00 2001
From: Krishna Pandey <kpandey81930 at gmail.com>
Date: Fri, 4 Jul 2025 23:16:19 +0530
Subject: [PATCH 13/15] chore: address nits
Signed-off-by: Krishna Pandey <kpandey81930 at gmail.com>
---
libc/src/__support/FPUtil/CMakeLists.txt | 2 +-
libc/src/__support/FPUtil/ComparisonOperations.h | 8 ++++----
libc/test/src/__support/FPUtil/CMakeLists.txt | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 33539178ae950..ec15d76d463a0 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -216,8 +216,8 @@ add_header_library(
DEPENDS
.fenv_impl
.fp_bits
- libc.src.__support.macros.config
libc.src.__support.CPP.type_traits
+ libc.src.__support.macros.config
)
add_header_library(
diff --git a/libc/src/__support/FPUtil/ComparisonOperations.h b/libc/src/__support/FPUtil/ComparisonOperations.h
index 28e46630c737c..216673bbb6be0 100644
--- a/libc/src/__support/FPUtil/ComparisonOperations.h
+++ b/libc/src/__support/FPUtil/ComparisonOperations.h
@@ -9,10 +9,10 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H
-#include "FEnvImpl.h" // raise_except_if_required
-#include "FPBits.h" // FPBits<T>
-#include "src/__support/CPP/type_traits.h" // enable_if, is_floating_point
-#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL
+#include "FEnvImpl.h"
+#include "FPBits.h"
+#include "src/__support/CPP/type_traits.h"
+#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
namespace fputil {
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 9e3ebcc36c936..90b9791f583c9 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -46,8 +46,8 @@ add_fp_unittest(
SRCS
comparison_operations_test.cpp
DEPENDS
- libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.comparison_operations
+ libc.src.__support.FPUtil.fp_bits
libc.src.__support.macros.properties.types
libc.src.__support.sign
)
>From 9d8056179c1adc92905d82bcf1c1be1baaf4ba0a Mon Sep 17 00:00:00 2001
From: Krishna Pandey <kpandey81930 at gmail.com>
Date: Fri, 4 Jul 2025 23:17:02 +0530
Subject: [PATCH 14/15] refactor: move tests inside FEnvSafeTest class
Signed-off-by: Krishna Pandey <kpandey81930 at gmail.com>
---
.../FPUtil/comparison_operations_test.cpp | 591 +++++++++---------
1 file changed, 301 insertions(+), 290 deletions(-)
diff --git a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
index 388d8b7a18e04..e14c5e2bfcea4 100644
--- a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
+++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
@@ -1,4 +1,4 @@
-//===-- Unittests for Comparison Operations for FPBits class -------------===//
+//===-- Unittests for Comparison Operations for FPBits class --------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -10,6 +10,7 @@
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/macros/properties/types.h"
#include "src/__support/sign.h"
+#include "test/UnitTest/FEnvSafeTest.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
@@ -19,313 +20,323 @@ using LIBC_NAMESPACE::fputil::greater_than_or_equals;
using LIBC_NAMESPACE::fputil::less_than;
using LIBC_NAMESPACE::fputil::less_than_or_equals;
-#define TEST_EQUALS(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, Equals) { \
- using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
- Type pos_zero = Bits::zero().get_val(); \
- Type neg_zero = -pos_zero; \
- Type pos_inf = Bits::inf().get_val(); \
- Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type qnan = Bits::quiet_nan().get_val(); \
- Type snan = Bits::signaling_nan().get_val(); \
- Type pos_normal = Type(3.14); \
- Type neg_normal = Type(-2.71); \
- Type pos_large = Type(1000000.0); \
- Type neg_large = Type(-1000000.0); \
- \
- EXPECT_TRUE(equals(pos_zero, pos_zero)); \
- EXPECT_TRUE(equals(neg_zero, neg_zero)); \
- EXPECT_TRUE(equals(pos_inf, pos_inf)); \
- EXPECT_TRUE(equals(neg_inf, neg_inf)); \
- EXPECT_TRUE(equals(pos_normal, pos_normal)); \
- EXPECT_TRUE(equals(neg_normal, neg_normal)); \
- \
- EXPECT_TRUE(equals(pos_zero, neg_zero)); \
- EXPECT_TRUE(equals(neg_zero, pos_zero)); \
- \
- EXPECT_FALSE(equals(pos_normal, neg_normal)); \
- EXPECT_FALSE(equals(pos_normal, pos_large)); \
- EXPECT_FALSE(equals(pos_inf, neg_inf)); \
- EXPECT_FALSE(equals(pos_inf, pos_normal)); \
- EXPECT_FALSE(equals(neg_inf, neg_normal)); \
- EXPECT_FALSE(equals(pos_large, neg_large)); \
- \
- EXPECT_FALSE(equals(qnan, qnan)); \
- EXPECT_FALSE(equals(qnan, pos_normal)); \
- EXPECT_FALSE(equals(qnan, pos_zero)); \
- EXPECT_FALSE(equals(qnan, pos_inf)); \
- EXPECT_FALSE(equals(pos_normal, qnan)); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(equals(snan, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(equals(snan, qnan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(equals(qnan, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(equals(snan, pos_normal)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(equals(pos_normal, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(equals(snan, pos_inf)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(equals(snan, pos_zero)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
+template <typename T>
+class ComparisonOperationsTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
+ DECLARE_SPECIAL_CONSTANTS(T)
+
+ static constexpr T normal1 = T(3.14);
+ static constexpr T normal2 = T(2.71);
+ static constexpr T small = T(0.1);
+ static constexpr T neg_small = T(-0.1);
+ static constexpr T large = T(10000.0);
+ static constexpr T neg_large = T(-10000.0);
+
+public:
+ void test_equals() {
+ EXPECT_TRUE(equals(neg_zero, neg_zero));
+ EXPECT_TRUE(equals(zero, neg_zero));
+ EXPECT_TRUE(equals(neg_zero, zero));
+
+ EXPECT_TRUE(equals(inf, inf));
+ EXPECT_TRUE(equals(neg_inf, neg_inf));
+ EXPECT_FALSE(equals(inf, neg_inf));
+ EXPECT_FALSE(equals(neg_inf, inf));
+
+ EXPECT_TRUE(equals(normal1, normal1));
+ EXPECT_TRUE(equals(normal2, normal2));
+ EXPECT_FALSE(equals(normal1, normal2));
+ EXPECT_FALSE(equals(normal1, -normal1));
+
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ auto test_qnan = [&](T x, T y) {
+ EXPECT_FALSE(equals(x, y));
+ // NOTE: equals and not equals operations should raise FE_INVALID for
+ // quiet NaN operands
+ EXPECT_FP_EXCEPTION(0);
+ };
+
+ test_qnan(aNaN, aNaN);
+ test_qnan(aNaN, neg_aNaN);
+ test_qnan(aNaN, zero);
+ test_qnan(aNaN, inf);
+ test_qnan(aNaN, normal1);
+
+ test_qnan(neg_aNaN, neg_aNaN);
+ test_qnan(neg_aNaN, aNaN);
+ test_qnan(neg_aNaN, zero);
+ test_qnan(neg_aNaN, inf);
+ test_qnan(neg_aNaN, normal1);
+
+ auto test_snan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ EXPECT_FALSE(equals(x, y));
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+ };
+
+ test_snan(sNaN, sNaN);
+ test_snan(sNaN, neg_sNaN);
+ test_snan(sNaN, aNaN);
+ test_snan(sNaN, neg_aNaN);
+ test_snan(sNaN, zero);
+ test_snan(sNaN, neg_zero);
+ test_snan(sNaN, inf);
+ test_snan(sNaN, neg_inf);
+ test_snan(sNaN, normal1);
+
+ test_snan(neg_sNaN, neg_sNaN);
+ test_snan(neg_sNaN, sNaN);
+ test_snan(neg_sNaN, aNaN);
+ test_snan(neg_sNaN, neg_aNaN);
+ test_snan(neg_sNaN, zero);
+ test_snan(neg_sNaN, neg_zero);
+ test_snan(neg_sNaN, inf);
+ test_snan(neg_sNaN, neg_inf);
+ test_snan(neg_sNaN, normal1);
}
-#define TEST_LESS_THAN(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, LessThan) { \
- using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
- Type pos_zero = Bits::zero().get_val(); \
- Type neg_zero = -pos_zero; \
- Type pos_inf = Bits::inf().get_val(); \
- Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type qnan = Bits::quiet_nan().get_val(); \
- Type snan = Bits::signaling_nan().get_val(); \
- Type pos_small = Type(0.1); \
- Type neg_small = Type(-0.1); \
- Type pos_large = Type(1000000.0); \
- Type neg_large = Type(-1000000.0); \
- \
- EXPECT_TRUE(less_than(neg_small, pos_small)); \
- EXPECT_TRUE(less_than(pos_small, pos_large)); \
- EXPECT_TRUE(less_than(neg_large, neg_small)); \
- EXPECT_FALSE(less_than(pos_large, pos_small)); \
- EXPECT_FALSE(less_than(pos_small, neg_small)); \
- \
- EXPECT_FALSE(less_than(pos_zero, neg_zero)); \
- EXPECT_FALSE(less_than(neg_zero, pos_zero)); \
- EXPECT_FALSE(less_than(pos_zero, pos_zero)); \
- \
- EXPECT_TRUE(less_than(neg_small, pos_zero)); \
- EXPECT_TRUE(less_than(neg_zero, pos_small)); \
- EXPECT_FALSE(less_than(pos_small, pos_zero)); \
- \
- EXPECT_TRUE(less_than(neg_inf, pos_inf)); \
- EXPECT_TRUE(less_than(neg_inf, neg_small)); \
- EXPECT_TRUE(less_than(pos_small, pos_inf)); \
- EXPECT_FALSE(less_than(pos_inf, pos_small)); \
- \
- EXPECT_FALSE(less_than(pos_small, pos_small)); \
- EXPECT_FALSE(less_than(neg_inf, neg_inf)); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than(qnan, pos_small)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than(pos_small, qnan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than(qnan, qnan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than(snan, pos_small)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than(pos_small, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than(snan, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
+ void test_less_than() {
+ EXPECT_TRUE(less_than(neg_small, small));
+ EXPECT_TRUE(less_than(small, large));
+
+ EXPECT_TRUE(less_than(neg_large, neg_small));
+ EXPECT_FALSE(less_than(large, small));
+ EXPECT_FALSE(less_than(small, neg_small));
+
+ EXPECT_FALSE(less_than(zero, neg_zero));
+ EXPECT_FALSE(less_than(neg_zero, zero));
+ EXPECT_FALSE(less_than(zero, zero));
+
+ EXPECT_TRUE(less_than(neg_small, zero));
+ EXPECT_TRUE(less_than(neg_zero, small));
+ EXPECT_FALSE(less_than(small, zero));
+
+ EXPECT_TRUE(less_than(neg_inf, inf));
+ EXPECT_TRUE(less_than(neg_inf, neg_small));
+ EXPECT_TRUE(less_than(small, inf));
+ EXPECT_FALSE(less_than(inf, small));
+
+ EXPECT_FALSE(less_than(small, small));
+ EXPECT_FALSE(less_than(neg_inf, neg_inf));
+
+ auto test_qnan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ EXPECT_FALSE(less_than(x, y));
+ // NOTE: All signaling comparison operations other than equals and not
+ // equals should raise FE_INVALID when comparing with NaN
+ // see Note after table 5.1 in IEEE Std 754-2019
+ // [...] The Signaling predicates in Table 5.1 signal the invalid
+ // operation exception on quiet NaN operands to warn of potential
+ // incorrect behavior of programs written assuming trichotomy.
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+ };
+
+ test_qnan(aNaN, small);
+ test_qnan(small, aNaN);
+ test_qnan(aNaN, aNaN);
+ test_qnan(neg_aNaN, neg_small);
+ test_qnan(neg_small, neg_aNaN);
+ test_qnan(neg_aNaN, neg_aNaN);
+
+ auto test_snan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ EXPECT_FALSE(less_than(x, y));
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+ };
+
+ test_snan(sNaN, small);
+ test_snan(sNaN, neg_small);
+ test_snan(sNaN, zero);
+ test_snan(sNaN, inf);
+ test_snan(sNaN, aNaN);
+ test_snan(sNaN, sNaN);
+
+ test_snan(neg_sNaN, small);
+ test_snan(neg_sNaN, neg_small);
+ test_snan(neg_sNaN, zero);
+ test_snan(neg_sNaN, inf);
+ test_snan(neg_sNaN, aNaN);
+ test_snan(neg_sNaN, neg_sNaN);
}
+ void test_greater_than() {
+ EXPECT_TRUE(greater_than(large, neg_small));
+ EXPECT_TRUE(greater_than(neg_small, neg_large));
+
+ EXPECT_FALSE(greater_than(large, large));
+ EXPECT_FALSE(greater_than(neg_small, large));
+
+ EXPECT_FALSE(greater_than(zero, neg_zero));
+ EXPECT_FALSE(greater_than(neg_zero, zero));
+
+ EXPECT_TRUE(greater_than(inf, neg_inf));
+ EXPECT_TRUE(greater_than(inf, large));
+ EXPECT_TRUE(greater_than(large, neg_inf));
+ EXPECT_FALSE(greater_than(neg_inf, inf));
-#define TEST_GREATER_THAN(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, GreaterThan) { \
- using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
- Type pos_zero = Bits::zero().get_val(); \
- Type neg_zero = -pos_zero; \
- Type pos_inf = Bits::inf().get_val(); \
- Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type qnan = Bits::quiet_nan().get_val(); \
- Type snan = Bits::signaling_nan().get_val(); \
- Type pos_small = Type(0.1); \
- Type neg_small = Type(-0.1); \
- Type pos_large = Type(1000000.0); \
- Type neg_large = Type(-1000000.0); \
- \
- EXPECT_TRUE(greater_than(pos_small, neg_small)); \
- EXPECT_TRUE(greater_than(pos_large, pos_small)); \
- EXPECT_TRUE(greater_than(neg_small, neg_large)); \
- EXPECT_FALSE(greater_than(pos_small, pos_large)); \
- EXPECT_FALSE(greater_than(neg_small, pos_small)); \
- \
- EXPECT_FALSE(greater_than(pos_zero, neg_zero)); \
- EXPECT_FALSE(greater_than(neg_zero, pos_zero)); \
- \
- EXPECT_TRUE(greater_than(pos_inf, neg_inf)); \
- EXPECT_TRUE(greater_than(pos_inf, pos_small)); \
- EXPECT_TRUE(greater_than(pos_small, neg_inf)); \
- EXPECT_FALSE(greater_than(neg_inf, pos_inf)); \
- \
- EXPECT_FALSE(greater_than(pos_small, pos_small)); \
- EXPECT_FALSE(greater_than(pos_inf, pos_inf)); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than(qnan, pos_small)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than(pos_small, qnan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than(qnan, qnan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than(snan, pos_small)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than(pos_small, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than(snan, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
+ EXPECT_FALSE(greater_than(large, large));
+ EXPECT_FALSE(greater_than(inf, inf));
+
+ auto test_qnan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ EXPECT_FALSE(greater_than(x, y));
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+ };
+
+ test_qnan(aNaN, large);
+ test_qnan(large, aNaN);
+ test_qnan(aNaN, aNaN);
+ test_qnan(neg_aNaN, neg_small);
+ test_qnan(neg_small, neg_aNaN);
+ test_qnan(neg_aNaN, neg_aNaN);
+
+ auto test_snan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ EXPECT_FALSE(greater_than(x, y));
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+ };
+
+ test_snan(sNaN, large);
+ test_snan(sNaN, neg_small);
+ test_snan(sNaN, zero);
+ test_snan(sNaN, inf);
+ test_snan(sNaN, aNaN);
+ test_snan(sNaN, sNaN);
+
+ test_snan(neg_sNaN, large);
+ test_snan(neg_sNaN, neg_small);
+ test_snan(neg_sNaN, zero);
+ test_snan(neg_sNaN, inf);
+ test_snan(neg_sNaN, aNaN);
+ test_snan(neg_sNaN, neg_sNaN);
}
-#define TEST_LESS_THAN_OR_EQUALS(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, LessThanOrEquals) { \
- using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
- Type pos_zero = Bits::zero().get_val(); \
- Type neg_zero = -pos_zero; \
- Type pos_inf = Bits::inf().get_val(); \
- Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type qnan = Bits::quiet_nan().get_val(); \
- Type snan = Bits::signaling_nan().get_val(); \
- Type pos_small = Type(0.1); \
- Type neg_small = Type(-0.1); \
- Type pos_large = Type(1000000.0); \
- Type neg_large = Type(-1000000.0); \
- \
- EXPECT_TRUE(less_than_or_equals(neg_small, pos_small)); \
- EXPECT_TRUE(less_than_or_equals(pos_small, pos_large)); \
- EXPECT_TRUE(less_than_or_equals(neg_inf, pos_small)); \
- \
- EXPECT_TRUE(less_than_or_equals(pos_small, pos_small)); \
- EXPECT_TRUE(less_than_or_equals(pos_zero, neg_zero)); \
- EXPECT_TRUE(less_than_or_equals(pos_inf, pos_inf)); \
- \
- EXPECT_FALSE(less_than_or_equals(pos_small, neg_small)); \
- EXPECT_FALSE(less_than_or_equals(pos_large, pos_small)); \
- EXPECT_FALSE(less_than_or_equals(pos_inf, pos_small)); \
- \
- EXPECT_TRUE(less_than_or_equals(neg_large, pos_small)); \
- EXPECT_FALSE(less_than_or_equals(pos_large, neg_small)); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than_or_equals(qnan, pos_small)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than_or_equals(pos_small, qnan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than_or_equals(qnan, qnan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than_or_equals(snan, pos_small)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than_or_equals(pos_small, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(less_than_or_equals(snan, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
+ void test_less_than_or_equals() {
+ EXPECT_TRUE(less_than_or_equals(neg_small, small));
+ EXPECT_TRUE(less_than_or_equals(small, large));
+ EXPECT_TRUE(less_than_or_equals(neg_inf, small));
+
+ EXPECT_TRUE(less_than_or_equals(small, small));
+ EXPECT_TRUE(less_than_or_equals(zero, neg_zero));
+ EXPECT_TRUE(less_than_or_equals(inf, inf));
+
+ EXPECT_FALSE(less_than_or_equals(small, neg_small));
+ EXPECT_FALSE(less_than_or_equals(large, small));
+ EXPECT_FALSE(less_than_or_equals(inf, small));
+
+ EXPECT_TRUE(less_than_or_equals(neg_large, small));
+ EXPECT_FALSE(less_than_or_equals(large, neg_small));
+
+ auto test_qnan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ EXPECT_FALSE(less_than_or_equals(x, y));
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+ };
+
+ test_qnan(aNaN, small);
+ test_qnan(small, aNaN);
+ test_qnan(aNaN, aNaN);
+ test_qnan(neg_aNaN, neg_small);
+ test_qnan(neg_small, neg_aNaN);
+ test_qnan(neg_aNaN, neg_aNaN);
+
+ auto test_snan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ EXPECT_FALSE(less_than_or_equals(x, y));
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+ };
+
+ test_snan(sNaN, small);
+ test_snan(sNaN, neg_small);
+ test_snan(sNaN, zero);
+ test_snan(sNaN, inf);
+ test_snan(sNaN, aNaN);
+ test_snan(sNaN, sNaN);
+
+ test_snan(neg_sNaN, small);
+ test_snan(neg_sNaN, neg_small);
+ test_snan(neg_sNaN, zero);
+ test_snan(neg_sNaN, inf);
+ test_snan(neg_sNaN, aNaN);
+ test_snan(neg_sNaN, neg_sNaN);
}
-#define TEST_GREATER_THAN_OR_EQUALS(Name, Type) \
- TEST(LlvmLibc##Name##ComparisionOperationsTest, GreaterThanOrEquals) { \
- using Bits = LIBC_NAMESPACE::fputil::FPBits<Type>; \
- Type pos_zero = Bits::zero().get_val(); \
- Type neg_zero = -pos_zero; \
- Type pos_inf = Bits::inf().get_val(); \
- Type neg_inf = Bits::inf(Sign::NEG).get_val(); \
- Type qnan = Bits::quiet_nan().get_val(); \
- Type snan = Bits::signaling_nan().get_val(); \
- Type pos_small = Type(0.1); \
- Type neg_small = Type(-0.1); \
- Type pos_large = Type(1000000.0); \
- Type neg_large = Type(-1000000.0); \
- \
- EXPECT_TRUE(greater_than_or_equals(pos_small, neg_small)); \
- EXPECT_TRUE(greater_than_or_equals(pos_large, pos_small)); \
- EXPECT_TRUE(greater_than_or_equals(pos_inf, pos_small)); \
- \
- EXPECT_TRUE(greater_than_or_equals(pos_small, pos_small)); \
- EXPECT_TRUE(greater_than_or_equals(pos_zero, neg_zero)); \
- EXPECT_TRUE(greater_than_or_equals(neg_inf, neg_inf)); \
- \
- EXPECT_FALSE(greater_than_or_equals(neg_small, pos_small)); \
- EXPECT_FALSE(greater_than_or_equals(pos_small, pos_large)); \
- EXPECT_FALSE(greater_than_or_equals(neg_inf, pos_small)); \
- \
- EXPECT_TRUE(greater_than_or_equals(pos_large, neg_small)); \
- EXPECT_FALSE(greater_than_or_equals(neg_large, pos_small)); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than_or_equals(qnan, pos_small)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than_or_equals(pos_small, qnan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than_or_equals(qnan, qnan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than_or_equals(snan, pos_small)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than_or_equals(pos_small, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
- \
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
- EXPECT_FALSE(greater_than_or_equals(snan, snan)); \
- EXPECT_FP_EXCEPTION(FE_INVALID); \
+ void test_greater_than_or_equals() {
+ EXPECT_TRUE(greater_than_or_equals(small, neg_small));
+ EXPECT_TRUE(greater_than_or_equals(large, small));
+ EXPECT_TRUE(greater_than_or_equals(inf, small));
+
+ EXPECT_TRUE(greater_than_or_equals(small, small));
+ EXPECT_TRUE(greater_than_or_equals(zero, neg_zero));
+ EXPECT_TRUE(greater_than_or_equals(neg_inf, neg_inf));
+
+ EXPECT_FALSE(greater_than_or_equals(neg_small, small));
+ EXPECT_FALSE(greater_than_or_equals(small, large));
+ EXPECT_FALSE(greater_than_or_equals(neg_inf, small));
+
+ EXPECT_TRUE(greater_than_or_equals(large, neg_small));
+ EXPECT_FALSE(greater_than_or_equals(neg_large, small));
+
+ auto test_qnan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ EXPECT_FALSE(greater_than_or_equals(x, y));
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+ };
+
+ test_qnan(aNaN, small);
+ test_qnan(small, aNaN);
+ test_qnan(aNaN, aNaN);
+ test_qnan(neg_aNaN, neg_small);
+ test_qnan(neg_small, neg_aNaN);
+ test_qnan(neg_aNaN, neg_aNaN);
+
+ auto test_snan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ EXPECT_FALSE(greater_than_or_equals(x, y));
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+ };
+
+ test_snan(sNaN, small);
+ test_snan(sNaN, neg_small);
+ test_snan(sNaN, zero);
+ test_snan(sNaN, inf);
+ test_snan(sNaN, aNaN);
+ test_snan(sNaN, sNaN);
+
+ test_snan(neg_sNaN, small);
+ test_snan(neg_sNaN, neg_small);
+ test_snan(neg_sNaN, zero);
+ test_snan(neg_sNaN, inf);
+ test_snan(neg_sNaN, aNaN);
+ test_snan(neg_sNaN, neg_sNaN);
}
+};
#define TEST_COMPARISON_OPS(Name, Type) \
- TEST_EQUALS(Name, Type) \
- TEST_LESS_THAN(Name, Type) \
- TEST_GREATER_THAN(Name, Type) \
- TEST_LESS_THAN_OR_EQUALS(Name, Type) \
- TEST_GREATER_THAN_OR_EQUALS(Name, Type)
+ using LlvmLibc##Name##ComparisonOperationsTest = \
+ ComparisonOperationsTest<Type>; \
+ TEST_F(LlvmLibc##Name##ComparisonOperationsTest, Equals) { test_equals(); } \
+ TEST_F(LlvmLibc##Name##ComparisonOperationsTest, LessThan) { \
+ test_less_than(); \
+ } \
+ TEST_F(LlvmLibc##Name##ComparisonOperationsTest, GreaterThan) { \
+ test_greater_than(); \
+ } \
+ TEST_F(LlvmLibc##Name##ComparisonOperationsTest, LessThanOrEquals) { \
+ test_less_than_or_equals(); \
+ } \
+ TEST_F(LlvmLibc##Name##ComparisonOperationsTest, GreaterThanOrEquals) { \
+ test_greater_than_or_equals(); \
+ }
TEST_COMPARISON_OPS(Float, float)
TEST_COMPARISON_OPS(Double, double)
-// We have to use type alias here, since FPBits<(long double)> is not allowed
-// if we do TEST_COMPARISON_OPS(LongDouble, (long double));
-// and Type(x) for Type = long double evaulates to long double(x)which is not
+// We have to use type alias here, since FPBits<(long double)> is not
+// allowed if we do TEST_COMPARISON_OPS(LongDouble, (long double)); and
+// Type(x) for Type = long double evaluates to long double(x)which is not
// allowed if we do TEST_COMPARISON_OPS(LongDouble, long double);
using long_double = long double;
TEST_COMPARISON_OPS(LongDouble, long_double)
+
#ifdef LIBC_TYPES_HAS_FLOAT16
TEST_COMPARISON_OPS(Float16, float16)
#endif // LIBC_TYPES_HAS_FLOAT16
>From 4a69dc512d328e66b094b10ad0a0aad95766230c Mon Sep 17 00:00:00 2001
From: Krishna Pandey <kpandey81930 at gmail.com>
Date: Sat, 5 Jul 2025 00:28:19 +0530
Subject: [PATCH 15/15] chore: further nits
Signed-off-by: Krishna Pandey <kpandey81930 at gmail.com>
---
.../src/__support/FPUtil/ComparisonOperations.h | 13 ++++++++++---
.../FPUtil/comparison_operations_test.cpp | 17 +++--------------
2 files changed, 13 insertions(+), 17 deletions(-)
diff --git a/libc/src/__support/FPUtil/ComparisonOperations.h b/libc/src/__support/FPUtil/ComparisonOperations.h
index 216673bbb6be0..05c9a056ecf09 100644
--- a/libc/src/__support/FPUtil/ComparisonOperations.h
+++ b/libc/src/__support/FPUtil/ComparisonOperations.h
@@ -17,7 +17,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace fputil {
-// IEEE Standard 754-2019. Section 5.11
+// All predicates are hereby implemented as per IEEE Std 754-2019
+// Implements compareQuietEqual predicate
// Rules for comparison within the same floating point type
// 1. +0 = −0
// 2. (i) +inf = +inf
@@ -46,7 +47,8 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> equals(T x,
return x_bits.uintval() == y_bits.uintval();
}
-// Rules:
+// Implements compareSignalingLess predicate
+// Section 5.11 Rules:
// 1. -inf < x (x != -inf)
// 2. x < +inf (x != +inf)
// 3. Any comparison with NaN return false
@@ -62,8 +64,10 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x,
fputil::raise_except_if_required(FE_INVALID);
// Any comparison with NaN returns false
- if (x_bits.is_nan() || y_bits.is_nan())
+ if (x_bits.is_nan() || y_bits.is_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
return false;
+ }
if (x_bits.is_zero() && y_bits.is_zero())
return false;
@@ -85,6 +89,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x,
return x_bits.uintval() < y_bits.uintval();
}
+// Implements compareSignalingGreater predicate
// x < y => y > x
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
@@ -92,6 +97,7 @@ greater_than(T x, T y) {
return less_than(y, x);
}
+// Implements compareSignalingLessEqual predicate
// following is expression is correct, accounting for NaN case(s) as well
// x <= y => (x < y) || (x == y)
template <typename T>
@@ -100,6 +106,7 @@ less_than_or_equals(T x, T y) {
return less_than(x, y) || equals(x, y);
}
+// Implements compareSignalingGreaterEqual predicate
// x >= y => (x > y) || (x == y) => (y < x) || (x == y)
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
diff --git a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
index e14c5e2bfcea4..91835de7be536 100644
--- a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
+++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
@@ -47,8 +47,8 @@ class ComparisonOperationsTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
EXPECT_FALSE(equals(normal1, normal2));
EXPECT_FALSE(equals(normal1, -normal1));
- LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
auto test_qnan = [&](T x, T y) {
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FALSE(equals(x, y));
// NOTE: equals and not equals operations should raise FE_INVALID for
// quiet NaN operands
@@ -121,12 +121,6 @@ class ComparisonOperationsTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
auto test_qnan = [&](T x, T y) {
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FALSE(less_than(x, y));
- // NOTE: All signaling comparison operations other than equals and not
- // equals should raise FE_INVALID when comparing with NaN
- // see Note after table 5.1 in IEEE Std 754-2019
- // [...] The Signaling predicates in Table 5.1 signal the invalid
- // operation exception on quiet NaN operands to warn of potential
- // incorrect behavior of programs written assuming trichotomy.
EXPECT_FP_EXCEPTION(FE_INVALID);
};
@@ -157,6 +151,7 @@ class ComparisonOperationsTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
test_snan(neg_sNaN, aNaN);
test_snan(neg_sNaN, neg_sNaN);
}
+
void test_greater_than() {
EXPECT_TRUE(greater_than(large, neg_small));
EXPECT_TRUE(greater_than(neg_small, neg_large));
@@ -329,13 +324,7 @@ class ComparisonOperationsTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
TEST_COMPARISON_OPS(Float, float)
TEST_COMPARISON_OPS(Double, double)
-
-// We have to use type alias here, since FPBits<(long double)> is not
-// allowed if we do TEST_COMPARISON_OPS(LongDouble, (long double)); and
-// Type(x) for Type = long double evaluates to long double(x)which is not
-// allowed if we do TEST_COMPARISON_OPS(LongDouble, long double);
-using long_double = long double;
-TEST_COMPARISON_OPS(LongDouble, long_double)
+TEST_COMPARISON_OPS(LongDouble, long double)
#ifdef LIBC_TYPES_HAS_FLOAT16
TEST_COMPARISON_OPS(Float16, float16)
More information about the libc-commits
mailing list