-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[libc][math] Add Generic Comparison Operations for floating point types #144983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-libc Author: Krishna Pandey (krishna2803) ChangesThe PR implements the following generic comparison operation functions for floating point types along with unittests:
cc @lntue @overmighty Patch is 23.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144983.diff 4 Files Affected:
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index bfe0170f09fd9..ce068df8d4c03 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -209,6 +209,17 @@ add_header_library(
libc.src.__support.macros.properties.types
)
+add_header_library(
+ comparison_operations
+ HDRS
+ ComparisonOperations.h
+ DEPENDS
+ .fp_bits
+ .fenv_impl
+ libc.src.__support.CPP.type_traits
+ libc.src.__support.config
+)
+
add_header_library(
hypot
HDRS
diff --git a/libc/src/__support/FPUtil/ComparisonOperations.h b/libc/src/__support/FPUtil/ComparisonOperations.h
new file mode 100644
index 0000000000000..cf71a14df0465
--- /dev/null
+++ b/libc/src/__support/FPUtil/ComparisonOperations.h
@@ -0,0 +1,122 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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
+
+namespace LIBC_NAMESPACE_DECL {
+namespace fputil {
+
+// IEEE Standard 754-2019. Section 5.11
+// Rules for comparison within the same floating point type
+// 1. +0 = −0
+// 2. (i) +inf = +inf
+// (ii) -inf = -inf
+// (iii) -inf != +inf
+// 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) {
+ 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 comparisons 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 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) {
+ 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 comparison 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 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();
+
+ // 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_COMPARISONOPERATIONS_H
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 1e64e9ba425a5..1dcd666ec3d25 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(
+ comparison_operations_test
+ SUITE
+ libc-fputil-tests
+ SRCS
+ comparison_operations_test.cpp
+ DEPENDS
+ libc.src.__support.FPUtil.fp_bits
+ # libc.src.__support.FPUtil.comparison_operations
+)
+
diff --git a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
new file mode 100644
index 0000000000000..94c234446ad8e
--- /dev/null
+++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
@@ -0,0 +1,254 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/FPUtil/ComparisonOperations.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(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 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(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>; \
+ 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(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 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(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 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(l...
[truncated]
|
@@ -0,0 +1,331 @@ | |||
//===-- Unittests for Comparison Operations for FPBits class -------------===// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: formatting.
//===-- Unittests for Comparison Operations for FPBits class -------------===// | |
//===-- Unittests for Comparison Operations for FPBits class --------------===// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had an extra review comment I thought I had sent but seemingly didn't.
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 | ||
if (x_bits.is_nan() || y_bits.is_nan()) | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 | |
if (x_bits.is_nan() || y_bits.is_nan()) | |
return false; | |
if (x_bits.is_nan() || y_bits.is_nan()) { | |
fputil::raise_except_if_required(FE_INVALID); | |
return false; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated, as of 4a69dc51
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); | ||
auto test_qnan = [&](T x, T y) { | ||
EXPECT_FALSE(equals(x, y)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); | |
auto test_qnan = [&](T x, T y) { | |
EXPECT_FALSE(equals(x, y)); | |
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// NOTE: equals and not equals operations should raise FE_INVALID for | |
// quiet NaN operands | |
// NOTE: equals and not equals operations should not raise FE_INVALID for | |
// quiet NaN operands |
But I think what we should do instead is add comments at definition for fputil::equals
, fputil::not_equals
, etc, saying which IEEE 754 comparison predicate they implement. E.g., for fputil::equals
:
// Implements the compareQuietEqual predicate as per IEEE Std 754-2019.
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> equals(T x,
T 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just all Signaling comparison operations, no exceptions. fputil::equals
and fputil::not_equals
implement Quiet predicates (compareQuietEqual
, compareQuietNotEqual
), but IEEE 754 also defines equivalent Signaling predicates (compareSignalingEqual
, compareSignalingNotEqual
).
} | ||
void test_greater_than() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: spacing/formatting.
} | |
void test_greater_than() { | |
} | |
void test_greater_than() { |
|
||
// 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) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is no longer needed since the refactoring to use FEnvSafeTest
.
// 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) |
Emit a context error and delete the instruction. This allows removing the AMDGPU hack where some atomic libcalls are falsely added. NVPTX also later copied the same hack, so remove it there too. For now just emit the generic error, which is not good. It's missing any useful context information (despite taking the instruction). It's also confusing in the failed atomicrmw case, since it's reporting failure at the intermediate failed cmpxchg instead of the original atomicrmw.
…6829) Before this patch, we emitted a bunch of irrelevant (to this test) warnings: ``` ../clang/test/SemaCXX/discrim-union.cpp:49:24: warning: 'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior [-Wconstexpr-not-const] 49 | constexpr const T &get(select<0>) { return val; } | ^ | const ../clang/test/SemaCXX/discrim-union.cpp:50:104: warning: 'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior [-Wconstexpr-not-const] 50 | template<unsigned N> constexpr const decltype(static_cast<const rest_t&>(rest).get(select<N-1>{})) get(select<N>) { | ^ | const ../clang/test/SemaCXX/discrim-union.cpp:82:22: warning: 'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior [-Wconstexpr-not-const] 82 | constexpr unsigned index() noexcept { return elem; } | ^ | const ../clang/test/SemaCXX/discrim-union.cpp:88:33: warning: 'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior [-Wconstexpr-not-const] 88 | constexpr const_get_result<N> get() { | ^ | const ../clang/test/SemaCXX/discrim-union.cpp:96:22: warning: 'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior [-Wconstexpr-not-const] 96 | constexpr const U &get() { | ^ | const 5 warnings generated. ```
…ns (llvm#147570) We were previously limited to abs(sub(zext(),zext()) patterns, but add handling for a number of other abdu patterns until a topological sorted dag allows us to rely on a ABDU node having already been created. Now that we don't just match zext() sources, I've generalised the createPSADBW helper to explicitly zext/truncate to the expected vXi8 source type - it still assumes the sources are correct for a PSADBW node. Fixes llvm#143456
.. produced by ADT/BitmaskEnum.h. These aren't implicitly convertible to an integer, so I needed to tweak a couple of bitwise operations and add an explicit constructor for HexNumber and FlagEntry. Motivation: I'd like to use this in the SFrame data structures (llvm#147264)
A disjoint OR can be transformed to an EOR. We already lower EOR+NOT to EON, but not DisjointOR+NOT.
This generalizes the support added in llvm#99287 renaming the option to RUNTIMES_USE_LIBC and integrating the module into libc++abi and libunwind as well.
Instead, return the new Pointer. This was weird before because some callers had to get the value from the stack again to perform further operations.
…ple.c for AIX specific targets (llvm#147584) This is a followup on the [[PowerPC][clang] Fix triple constructor ambiguity causing "unknown" target triple on AIX](llvm#147488 (comment)) to address the [post-commit review comment](llvm#147488 (comment)). --------- Co-authored-by: Tony Varghese <[email protected]>
…ns (llvm#147245) When collapsing linalg dimensions we check if its memref operands are guaranteed to be collapsible. However, we currently assume that the matching indexing map is the identity map. This commit modifies this behavior and checks if the memref is collapsible on the transformed dimensions.
…ckFPH intrinsic tests
…146082) Previously we had a table of entries for every Libcall for the comparison to use against an integer 0 if it was a soft float compare function. This was only relevant to a handful of opcodes, so it was wasteful. Now that we can distinguish the abstract libcall for the compare with the concrete implementation, we can just directly hardcode the comparison against the libcall impl without this configuration system.
llvm#146083) This fully consolidates all the calling convention configuration into RuntimeLibcallInfo. I'm assuming that __aeabi functions have a universal calling convention, and on other ABIs just don't use them. This will enable splitting of RuntimeLibcallInfo into the ABI and lowering component.
… present (llvm#147089) If the subtarget's latency is dependent on vl, then we shouldn't try to fold away vsetvli toggles if it means increasing vl.
The code is correct as it aligns with the SPIR-V Specification, but the comment was incorrect.
…same throughout the function (llvm#147506) This change only applies to functions the can be reasonably expected to use SVE registers. Modifying vector length in the middle of a function might cause incorrect stack deallocation if there are callee-saved SVE registers or incorrect access to SVE stack slots. Addresses (non-issue) llvm#143670
This commit removes the test file test-member-invalidation.cpp which was recently introduced in 39bc052 by splitting off a test case from new.cpp. In that commit I preserved that test in a slightly modified setting to demonstrate that it wasn't broken by the change; but in this separate commit I'm removing it because I don't think that it "deserves a place" among our tests. The primary issue is that this test examines the values of data members of a deleted object -- which is irrelevant, because code that relies on the value of these members should be reported as a use-after-free bug. (In fact, cplusplus.NewDelete reports it as a use-after-free bug, and the checker family `MallocChecker` sinks the execution path even if that particular frontend is not enabled.) Moreover, a comment claimed that this tests "Invalidate Region even in case of default destructor" while in fact it tested a situaton where the destructor is a plain declared-but-not-defined method. The invalidation of `this` is done by the conservative evaluation, and we don't need this overcomplicated test to validate that very basic behavior.
Also fill in some other passes.
This patch removes the buildkite_info object from generate_test_report_lib as we no longer support buildkite so it is dead code now. Eventually we should set up equivalent functionality on the Github side for downloading the logs from a convenient link, but for now clean up the code. Reviewers: cmtice, DavidSpickett, lnihlen Reviewed By: DavidSpickett Pull Request: llvm#147784
This is another Buildkite relic that we can get rid of now to simplify things a bit. Reviewers: cmtice, DavidSpickett, lnihlen Reviewed By: DavidSpickett Pull Request: llvm#147791
This patch makes it so that generate_test_report_github.py generates a test report even when we don't get any test results. This otherwise created a pretty confusing user experience on the Github side if the build failed before any tests ran or in cases like running check-libc where none of the tests are run through lit. Reviewers: lnihlen, cmtice Pull Request: llvm#147871
…47951) I'm surprised at how bad the test coverage is here. There is some overlap with existing tests, but they aren't comprehensive and do not cover all the ABIs, or all the different types. Fixes llvm#147935
…std::nullopt_t) {}. (llvm#147816) Our local Flang build on PowerPC was broken as ``` llvm/flang/../mlir/include/mlir/IR/ValueRange.h:401:20: error: 'ArrayRef' is deprecated: Use {} or ArrayRef<T>() instead [-Werror,-Wdeprecated-declarations] 401 | : ValueRange(ArrayRef<Value>(std::forward<Arg>(arg))) {} | ^ llvm/flang/lib/Optimizer/CodeGen/CodeGen.cpp:2243:53: note: in instantiation of function template specialization 'mlir::ValueRange::ValueRange<const std::nullopt_t &, void>' requested here 2243 | /*cstInteriorIndices=*/std::nullopt, fieldIndices, | ^ llvm/include/llvm/ADT/ArrayRef.h:70:18: note: 'ArrayRef' has been explicitly marked deprecated here 70 | /*implicit*/ LLVM_DEPRECATED("Use {} or ArrayRef<T>() instead", "{}") | ^ llvm/include/llvm/Support/Compiler.h:244:50: note: expanded from macro 'LLVM_DEPRECATED' 244 | #define LLVM_DEPRECATED(MSG, FIX) __attribute__((deprecated(MSG, FIX))) | ^ 1 error generated. ``` This patch is to fix it.
…47943) In the future, we want `ol_symbol_handle_t` to represent both kernels and global variables The first step in this process is a rename and promotion to a "typed handle".
…vectorizing operands (llvm#147583)" This reverts commit ac4a38e. This breaks the RVV builders (MicroBenchmarks/ImageProcessing/Blur/blur.test and MultiSource/Benchmarks/tramp3d-v4/tramp3d-v4.test from llvm-test-suite) and reportedly SPEC Accel2023 <llvm#147583 (comment)>.
…ions (llvm#147927) This is a fix for llvm#136102. It missed scoping for `DeclareFuncOps`. In scenarios with multiple function declarations, the `valueMapper` wasn't updated and later uses of values in other functions still used the assigned names in prior functions. This is visible in the reproducer here iree-org/iree#21303: Although the counter for variable enumeration was reset, as it is visible for the local vars, the function arguments were mapped to old names. Due to this mapping, the counter was never increased, and the local variables conflicted with the arguments. This fix adds proper scoping for declarations and a test-case to cover the scenario with multiple `DeclareFuncOps`.
A experimental_vp_reverse isn't exactly functionally the same as vector_reverse, so previously it wasn't getting picked up by the generic VP costing code that reuses the non-VP equivalents. But for costing purposes it's good enough so we can reuse it. The type-based cost for vector_reverse is still incorrect and should be fixed in another patch.
This PR adds overrides in `SPIRVTTIImpl` for `collectFlatAddressOperands` and `rewriteIntrinsicWithAddressSpace` to enable `InferAddressSpacesPass` to rewrite the `llvm.spv.generic.cast.to.ptr.explicit` intrinsic (corresponding to `OpGenericCastToPtrExplicit`) when the address space of the argument can be inferred. When the destination address space of the cast matches the inferred address space of the argument, the call is replaced with that argument. When they do not match, the cast is replaced with a constant null pointer.
The `-mframe-pointer` flag is not explicitly set in the original `flang` invocation and so the value passed to `flang -fc1` can vary depending on the host machine, so don't verify it in the output. `-mframe-pointer` forwarding is already verified by `flang/test/Driver/frame-pointer-forwarding.f90`.
Summary: Recent changes altered the name without updating this, add it in and also tell the builtins build that C++ compilers work because it seems to require that now.
When the RegisterCoalescer adds an implicit-def when coalescing a SUBREG_TO_REG (llvm#123632), this causes issues when removing other COPY nodes by commuting the instruction because it doesn't take the implicit-def into consideration. This PR fixes that.
We should not include both linux/prctl.h and sys/prctl.h. This works with glibc because the latter includes the former, but breaks with musl because the latter redeclares the contents of the former, resulting in: ``` /usr/local/aarch64-linux-musl/include/sys/prctl.h:88:8: error: redefinition of 'struct prctl_mm_map' 88 | struct prctl_mm_map { | ^~~~~~~~~~~~ In file included from /checkout/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp:13: /usr/local/aarch64-linux-musl/include/linux/prctl.h:134:8: note: previous definition of 'struct prctl_mm_map' 134 | struct prctl_mm_map { | ^~~~~~~~~~~~ ``` Fixes llvm#139443.
Signed-off-by: Krishna Pandey <[email protected]>
The PR implements the following generic comparison operation functions for floating point types along with unittests:
fputil::equals
fputil::less_than
fputil::less_than_or_equals
fputil::greater_than
fputil::greater_than_or_equals
cc @lntue @overmighty