-
Notifications
You must be signed in to change notification settings - Fork 15.7k
[libc][mathvec] Initial commit for LIBC vector math component #173058
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
Created a mathvec/ file structure that mirrors the structure of the math/ directory, and added a dummy expf implementation.
Simplistic checks based on a wrapper duplicating a scalar input. Introduce SIMD matcher (ultimately should be moved to test utils/) - Comparison with exception is supported. - Test all rounding modes in one line. - Control lanes A potential improvement could be made later: load vector in test over range instead of duplicating input. That would reduce run time of vector testing.
Implements a fully vectorised expf routine, that is correctly rounded for Round-to-nearest. As an example for what a correctly rounded vector routine looks like using LLVM LIBC SIMD types.
|
@llvm/pr-subscribers-libc Author: None (DylanFleming-arm) ChangesCreated mathvec directories and unittest framework for vector math functions, as well as an initial implementation of vector expf, which is presently CR for round-to-nearest. Patch is 28.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/173058.diff 20 Files Affected:
diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index 4e6b4195a9c5e..2d474f08841ca 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -350,6 +350,7 @@ include(LLVMLibCRules)
set(TARGET_LLVMLIBC_ENTRYPOINTS "")
set(TARGET_LIBC_ENTRYPOINTS "")
set(TARGET_LIBM_ENTRYPOINTS "")
+set(TARGET_LIBMVEC_ENTRYPOINTS "")
set(TARGET_LLVMLIBC_REMOVED_ENTRYPOINTS "")
# Check entrypoints.txt
@@ -380,6 +381,7 @@ foreach(removed_entrypoint IN LISTS TARGET_LLVMLIBC_REMOVED_ENTRYPOINTS)
list(REMOVE_ITEM TARGET_LLVMLIBC_ENTRYPOINTS ${removed_entrypoint})
list(REMOVE_ITEM TARGET_LIBC_ENTRYPOINTS ${removed_entrypoint})
list(REMOVE_ITEM TARGET_LIBM_ENTRYPOINTS ${removed_entrypoint})
+ list(REMOVE_ITEM TARGET_LIBMVEC_ENTRYPOINTS ${removed_entrypoint})
endforeach()
set(TARGET_ENTRYPOINT_NAME_LIST "")
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 970c825bbfc96..d0db8b0acff2b 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1178,7 +1178,14 @@ if(LLVM_LIBC_FULL_BUILD)
)
endif()
+if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE)
+ set(TARGET_LIBMVEC_ENTRYPOINTS
+ libc.src.mathvec.expf
+ )
+endif()
+
set(TARGET_LLVMLIBC_ENTRYPOINTS
${TARGET_LIBC_ENTRYPOINTS}
${TARGET_LIBM_ENTRYPOINTS}
+ ${TARGET_LIBMVEC_ENTRYPOINTS}
)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 9399b284fa2da..7c5e649968223 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1396,7 +1396,14 @@ if(LLVM_LIBC_FULL_BUILD)
)
endif()
+if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE)
+ set(TARGET_LIBMVEC_ENTRYPOINTS
+ libc.src.mathvec.expf
+ )
+endif()
+
set(TARGET_LLVMLIBC_ENTRYPOINTS
${TARGET_LIBC_ENTRYPOINTS}
${TARGET_LIBM_ENTRYPOINTS}
+ ${TARGET_LIBMVEC_ENTRYPOINTS}
)
diff --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt
index ce0b07fb6cb49..19751a9cc0736 100644
--- a/libc/lib/CMakeLists.txt
+++ b/libc/lib/CMakeLists.txt
@@ -2,10 +2,10 @@ set(libc_archive_targets "")
set(libc_archive_names "")
set(libc_archive_entrypoint_lists "")
if(LLVM_LIBC_FULL_BUILD)
- list(APPEND libc_archive_names c m)
- list(APPEND libc_archive_targets libc libm)
+ list(APPEND libc_archive_names c m mvec)
+ list(APPEND libc_archive_targets libc libm libmvec)
list(APPEND libc_archive_entrypoint_lists
- TARGET_LIBC_ENTRYPOINTS TARGET_LIBM_ENTRYPOINTS)
+ TARGET_LIBC_ENTRYPOINTS TARGET_LIBM_ENTRYPOINTS TARGET_LIBMVEC_ENTRYPOINTS)
else()
list(APPEND libc_archive_names llvmlibc)
list(APPEND libc_archive_targets libc)
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index b2afe0a33acee..8f005a700a80f 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -29,6 +29,11 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
add_subdirectory(termios)
endif()
+if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE)
+ message(STATUS "Vector math enabled")
+ add_subdirectory(mathvec)
+endif()
+
if(NOT LLVM_LIBC_FULL_BUILD)
return()
endif()
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index c7f127d6934a0..1ebd7dd2621a2 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -416,3 +416,6 @@ if(NOT (LIBC_TARGET_OS_IS_DARWIN))
endif()
add_subdirectory(math)
+if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE)
+ add_subdirectory(mathvec)
+endif()
diff --git a/libc/src/__support/mathvec/CMakeLists.txt b/libc/src/__support/mathvec/CMakeLists.txt
new file mode 100644
index 0000000000000..4b6e31ad29929
--- /dev/null
+++ b/libc/src/__support/mathvec/CMakeLists.txt
@@ -0,0 +1,35 @@
+add_header_library(
+ common_constants
+ HDRS
+ common_constants.h
+ DEPENDS
+)
+
+add_header_library(
+ expf_utils
+ HDRS
+ expf_utils.h
+ DEPENDS
+ libc.src.__support.CPP.simd
+ libc.src.__support.mathvec.common_constants
+)
+
+add_header_library(
+ expf
+ HDRS
+ expf.h
+ DEPENDS
+ libc.src.__support.common
+ libc.src.__support.CPP.simd
+ libc.src.__support.FPUtil.FPBits
+ libc.src.__support.mathvec.expf_utils
+ libc.src.__support.mathvec.vector_utils
+)
+
+add_header_library(
+ vector_utils
+ HDRS
+ vector_utils.h
+ DEPENDS
+ libc.src.__support.CPP.simd
+)
diff --git a/libc/src/__support/mathvec/common_constants.h b/libc/src/__support/mathvec/common_constants.h
new file mode 100644
index 0000000000000..c235d6842e5b0
--- /dev/null
+++ b/libc/src/__support/mathvec/common_constants.h
@@ -0,0 +1,40 @@
+//===-- Common constants for mathvec functions ------------------*- 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_MATHVEC_COMMON_CONSTANTS_H
+#define LLVM_LIBC_SRC___SUPPORT_MATHVEC_COMMON_CONSTANTS_H
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace common_constants_internal {
+
+// Lookup table for mantissas of 2^(i / 64) with i = 0, ..., 63.
+static constexpr uint64_t EXP_MANTISSA[64] = {
+ 0x0000000000000, 0x02c9a3e778061, 0x059b0d3158574, 0x0874518759bc8,
+ 0x0b5586cf9890f, 0x0e3ec32d3d1a2, 0x11301d0125b51, 0x1429aaea92de0,
+ 0x172b83c7d517b, 0x1a35beb6fcb75, 0x1d4873168b9aa, 0x2063b88628cd6,
+ 0x2387a6e756238, 0x26b4565e27cdd, 0x29e9df51fdee1, 0x2d285a6e4030b,
+ 0x306fe0a31b715, 0x33c08b26416ff, 0x371a7373aa9cb, 0x3a7db34e59ff7,
+ 0x3dea64c123422, 0x4160a21f72e2a, 0x44e086061892d, 0x486a2b5c13cd0,
+ 0x4bfdad5362a27, 0x4f9b2769d2ca7, 0x5342b569d4f82, 0x56f4736b527da,
+ 0x5ab07dd485429, 0x5e76f15ad2148, 0x6247eb03a5585, 0x6623882552225,
+ 0x6a09e667f3bcd, 0x6dfb23c651a2f, 0x71f75e8ec5f74, 0x75feb564267c9,
+ 0x7a11473eb0187, 0x7e2f336cf4e62, 0x82589994cce13, 0x868d99b4492ed,
+ 0x8ace5422aa0db, 0x8f1ae99157736, 0x93737b0cdc5e5, 0x97d829fde4e50,
+ 0x9c49182a3f090, 0xa0c667b5de565, 0xa5503b23e255d, 0xa9e6b5579fdbf,
+ 0xae89f995ad3ad, 0xb33a2b84f15fb, 0xb7f76f2fb5e47, 0xbcc1e904bc1d2,
+ 0xc199bdd85529c, 0xc67f12e57d14b, 0xcb720dcef9069, 0xd072d4a07897c,
+ 0xd5818dcfba487, 0xda9e603db3285, 0xdfc97337b9b5f, 0xe502ee78b3ff6,
+ 0xea4afa2a490da, 0xefa1bee615a27, 0xf50765b6e4540, 0xfa7c1819e90d8,
+};
+
+} // namespace common_constants_internal
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATHVEC_COMMON_CONSTANTS_H
diff --git a/libc/src/__support/mathvec/expf.h b/libc/src/__support/mathvec/expf.h
new file mode 100644
index 0000000000000..6b5abb4a0c32f
--- /dev/null
+++ b/libc/src/__support/mathvec/expf.h
@@ -0,0 +1,76 @@
+//===-- Implementation header for SIMD expf ---------------------*- 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_MATHVEC_EXPF_H
+#define LLVM_LIBC_SRC___SUPPORT_MATHVEC_EXPF_H
+
+#include "src/__support/CPP/simd.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/common.h"
+#include "src/__support/mathvec/expf_utils.h"
+#include "src/__support/mathvec/vector_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace mathvec {
+
+template <size_t N>
+LIBC_INLINE cpp::simd<double, N> inline_exp(cpp::simd<double, N> x) {
+ static constexpr cpp::simd<double, N> shift = 0x1.800000000ffc0p+46;
+
+ auto z = shift + x * 0x1.71547652b82fep+0;
+ auto n = z - shift;
+
+ auto r = x;
+ r = r - n * 0x1.62e42fefa3800p-1;
+ r = r - n * 0x1.ef35793c76730p-45;
+
+ /* y = exp(r) - 1 ~= r + C0 r^2 + C1 r^3 + C2 r^4 + C3 r^5. */
+ static constexpr cpp::simd<double, N> c0 = 0x1.fffffffffdbcdp-2;
+ static constexpr cpp::simd<double, N> c1 = 0x1.555555555444cp-3;
+ static constexpr cpp::simd<double, N> c2 = 0x1.555573c6a9f7dp-5;
+ static constexpr cpp::simd<double, N> c3 = 0x1.1111266d28935p-7;
+
+ auto r2 = r * r;
+ auto p01 = c0 + r * c1;
+ auto p23 = c2 + r * c3;
+ auto p04 = p01 + r2 * p23;
+ auto y = r + p04 * r2;
+
+ auto u = reinterpret_cast<cpp::simd<uint64_t, N>>(z);
+ auto s = exp_lookup(u);
+ return s + s * y;
+}
+
+template <size_t N>
+LIBC_INLINE cpp::simd<float, N> expf(cpp::simd<float, N> x) {
+ using FPBits = typename fputil::FPBits<float>;
+ cpp::simd<float, N> ret;
+
+ auto is_inf = cpp::simd_cast<bool>(x >= 0x1.62e38p+9);
+ auto is_zero = cpp::simd_cast<bool>(x <= -0x1.628c2ap+9);
+ auto is_special = is_inf | is_zero;
+
+ auto special_res =
+ cpp::select(is_inf, cpp::simd<float, N>(FPBits::inf().get_val()),
+ cpp::simd<float>(0.0f));
+
+ auto [lo, hi] = vector_float_to_double(x);
+
+ auto lo_res = inline_exp(lo);
+ auto hi_res = inline_exp(hi);
+
+ ret = vector_double_to_float(lo_res, hi_res);
+ return cpp::select(is_special, special_res, ret);
+}
+
+} // namespace mathvec
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATHVEC_EXPF_H
diff --git a/libc/src/__support/mathvec/expf_utils.h b/libc/src/__support/mathvec/expf_utils.h
new file mode 100644
index 0000000000000..2650bcba9bca7
--- /dev/null
+++ b/libc/src/__support/mathvec/expf_utils.h
@@ -0,0 +1,29 @@
+//===-- Common utils for exp function ---------------------------*- 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_MATHVEC_EXP_UTILS_H
+#define LLVM_LIBC_SRC___SUPPORT_MATHVEC_EXP_UTILS_H
+
+#include "src/__support/CPP/simd.h"
+#include "src/__support/mathvec/common_constants.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+template <size_t N>
+LIBC_INLINE cpp::simd<double, N> exp_lookup(cpp::simd<uint64_t, N> u) {
+ auto index = u & cpp::simd<uint64_t, N>(0x3f);
+ auto mantissa = cpp::gather<cpp::simd<uint64_t, N>>(
+ true, index, common_constants_internal::EXP_MANTISSA);
+ auto exponent = (u >> 6) << 52;
+ auto result = mantissa | exponent;
+ return reinterpret_cast<cpp::simd<double, N>>(result);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATHVEC_EXP_UTILS_H
diff --git a/libc/src/__support/mathvec/vector_utils.h b/libc/src/__support/mathvec/vector_utils.h
new file mode 100644
index 0000000000000..d2138f148a0ee
--- /dev/null
+++ b/libc/src/__support/mathvec/vector_utils.h
@@ -0,0 +1,46 @@
+//===-- Common utils for SIMD functions -------------------------*- 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_MATHVEC_VECTOR_UTILS_H
+#define LLVM_LIBC_SRC___SUPPORT_MATHVEC_VECTOR_UTILS_H
+
+#include "src/__support/CPP/simd.h"
+#include <tuple>
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Casts a simd<float, N> into two simd<double, N/2>
+template <size_t N>
+LIBC_INLINE constexpr auto vector_float_to_double(cpp::simd<float, N> v) {
+ static_assert(N % 2 == 0, "vector size must be even");
+ constexpr size_t H = N / 2;
+
+ auto parts = cpp::split<H, H>(v);
+ auto lo_f = cpp::get<0>(parts);
+ auto hi_f = cpp::get<1>(parts);
+
+ auto lo_d = cpp::simd_cast<double, float, H>(lo_f);
+ auto hi_d = cpp::simd_cast<double, float, H>(hi_f);
+
+ return cpp::make_tuple(lo_d, hi_d);
+}
+
+// Casts two simd<double, N> into a simd<float, 2N>
+template <size_t N>
+LIBC_INLINE constexpr auto vector_double_to_float(cpp::simd<double, N> lo_d,
+ cpp::simd<double, N> hi_d) {
+
+ auto lo_f = cpp::simd_cast<float, double, N>(lo_d);
+ auto hi_f = cpp::simd_cast<float, double, N>(hi_d);
+
+ return cpp::concat(lo_f, hi_f);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATHVEC_VECTOR_UTILS_H
diff --git a/libc/src/mathvec/CMakeLists.txt b/libc/src/mathvec/CMakeLists.txt
new file mode 100644
index 0000000000000..dff1dd3b70b51
--- /dev/null
+++ b/libc/src/mathvec/CMakeLists.txt
@@ -0,0 +1,43 @@
+add_subdirectory(generic)
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
+ add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
+endif()
+
+function(add_vector_math_entrypoint_object name)
+ # We prefer machine specific implementation if available. Hence we check
+ # that first and return early if we are able to add an alias target for the
+ # machine specific implementation.
+ get_fq_target_name("${LIBC_TARGET_ARCHITECTURE}.${name}" fq_machine_specific_target_name)
+ if(TARGET ${fq_machine_specific_target_name})
+ add_entrypoint_object(
+ ${name}
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_ARCHITECTURE}.${name}
+ )
+ return()
+ endif()
+
+ get_fq_target_name("generic.${name}" fq_generic_target_name)
+ if(TARGET ${fq_generic_target_name})
+ add_entrypoint_object(
+ ${name}
+ ALIAS
+ DEPENDS
+ .generic.${name}
+ )
+ return()
+ endif()
+
+ # Add a dummy entrypoint object for missing implementations. They will be skipped
+ # anyway as there will be no entry for them in the target entrypoints list.
+ add_entrypoint_object(
+ ${name}
+ SRCS
+ dummy_srcs
+ HDRS
+ dummy_hdrs
+ )
+endfunction()
+
+add_vector_math_entrypoint_object(expf)
diff --git a/libc/src/mathvec/expf.h b/libc/src/mathvec/expf.h
new file mode 100644
index 0000000000000..257fb485838af
--- /dev/null
+++ b/libc/src/mathvec/expf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for SIMD expf ---------------------*- 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_MATHVEC_EXPF_H
+#define LLVM_LIBC_SRC_MATHVEC_EXPF_H
+
+#include "src/__support/CPP/simd.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+cpp::simd<float> expf(cpp::simd<float> x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATHVEC_EXPF_H
diff --git a/libc/src/mathvec/generic/CMakeLists.txt b/libc/src/mathvec/generic/CMakeLists.txt
new file mode 100644
index 0000000000000..769794d6d5eee
--- /dev/null
+++ b/libc/src/mathvec/generic/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_entrypoint_object(
+ expf
+ SRCS
+ expf.cpp
+ HDRS
+ ../expf.h
+ DEPENDS
+ libc.src.__support.CPP.simd
+ FLAGS
+ ROUND_OPT
+ FMA_OPT
+)
diff --git a/libc/src/mathvec/generic/expf.cpp b/libc/src/mathvec/generic/expf.cpp
new file mode 100644
index 0000000000000..2e113d17e8680
--- /dev/null
+++ b/libc/src/mathvec/generic/expf.cpp
@@ -0,0 +1,18 @@
+//===-- Single-precision SIMD e^x vector function -------------------------===//
+//
+// 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/mathvec/expf.h"
+#include "src/__support/mathvec/expf.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(cpp::simd<float>, expf, (cpp::simd<float> x)) {
+ return mathvec::expf(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/UnitTest/SIMDMatcher.h b/libc/test/UnitTest/SIMDMatcher.h
new file mode 100644
index 0000000000000..542d311ddbd89
--- /dev/null
+++ b/libc/test/UnitTest/SIMDMatcher.h
@@ -0,0 +1,61 @@
+//===-- SIMDMatchers.h ------------------------------------------*- 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_TEST_UNITTEST_SIMDMATCHER_H
+#define LLVM_LIBC_TEST_UNITTEST_SIMDMATCHER_H
+
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+#include "hdr/math_macros.h"
+
+#define EXPECT_SIMD_EQ(REF, RES) \
+ for (size_t i = 0; \
+ i < LIBC_NAMESPACE::cpp::internal::native_vector_size<float>; i++) { \
+ EXPECT_FP_EQ(REF[i], RES[i]); \
+ }
+
+#define EXPECT_SIMD_EQ_WITH_EXCEPTION(REF, RES, EXCEPTION) \
+ for (size_t i = 0; \
+ i < LIBC_NAMESPACE::cpp::internal::native_vector_size<float>; i++) { \
+ EXPECT_FP_EQ_WITH_EXCEPTION(REF[i], RES[i], EXCEPTION); \
+ }
+
+#define EXPECT_SIMD_EQ_ROUNDING_MODE(expected, actual, rounding_mode) \
+ do { \
+ using namespace LIBC_NAMESPACE::fputil::testing; \
+ ForceRoundingMode __r((rounding_mode)); \
+ if (__r.success) { \
+ EXPECT_SIMD_EQ((expected), (actual)) \
+ } \
+ } while (0)
+
+#define EXPECT_SIMD_EQ_ROUNDING_NEAREST(expected, actual) \
+ EXPECT_SIMD_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Nearest)
+
+#define EXPECT_SIMD_EQ_ROUNDING_UPWARD(expected, actual) \
+ EXPECT_SIMD_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Upward)
+
+#define EXPECT_SIMD_EQ_ROUNDING_DOWNWARD(expected, actual) \
+ EXPECT_SIMD_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Downward)
+
+#define EXPECT_SIMD_EQ_ROUNDING_TOWARD_ZERO(expected, actual) \
+ EXPECT_SIMD_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::TowardZero)
+
+#define EXPECT_SIMD_EQ_ALL_ROUNDING(expected, actual) \
+ do { \
+ EXPECT_SIMD_EQ_ROUNDING_NEAREST((expected), (actual)); \
+ EXPECT_SIMD_EQ_ROUNDING_UPWARD((expected), (actual)); \
+ EXPECT_SIMD_EQ_ROUNDING_DOWNWARD((expected), (actual)); \
+ EXPECT_SIMD_EQ_ROUNDING_TOWARD_ZERO((expected), (actual)); \
+ } while (0)
+
+#endif // LLVM_LIBC_TEST_UNITTEST_SIMDMATCHER_H
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 0c6ec9f07a9b7..5e61c739c066a 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -87,6 +87,10 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
add_subdirectory(termios)
endif()
+if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE)
+ add_subdirectory(mathvec)
+endif()
+
if(NOT LLVM_LIBC_FULL_BUILD)
return()
endif()
diff --git a/libc/test/src/mathvec/AddTest.h b/libc/test/src/mathvec/AddTest.h
new file mode 100644
index 0000000000000..2f7d0ec6904e3
--- /dev/null
+++ b/libc/test/src/mathvec/AddTest.h
@@ -0,0 +1,87 @@
+//===-- Utility class to test different flavors of float add ----*- 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_TEST_SRC_MATHVEC_ADDTEST_H
+#define LLVM_LIBC_TEST_SRC_MATHVEC_ADDTEST_H
+
+#include "src/__support/CPP/algorithm.h"
+#incl...
[truncated]
|
| endif() | ||
|
|
||
| if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE) | ||
| message(STATUS "Vector math enabled") |
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 should either be removed for made to be more descriptive, don't think it means much if there's no way to turn it off.
|
|
||
| // Lookup table for mantissas of 2^(i / 64) with i = 0, ..., 63. | ||
| static constexpr uint64_t EXP_MANTISSA[64] = { | ||
| 0x0000000000000, 0x02c9a3e778061, 0x059b0d3158574, 0x0874518759bc8, |
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.
@lntue don't we usually use the hexademical floating point format? Or do these really just need to be integers.
| using FPBits = typename fputil::FPBits<float>; | ||
| cpp::simd<float, N> ret; | ||
|
|
||
| auto is_inf = cpp::simd_cast<bool>(x >= 0x1.62e38p+9); |
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 thought I let these automatically convert to boolean, but I guess it's easier like this because you infer the size?
| cpp::select(is_inf, cpp::simd<float, N>(FPBits::inf().get_val()), | ||
| cpp::simd<float>(0.0f)); |
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.
Honestly probably best just to use direct ternary and broadcasting constructors. Those helpers are mostly there just to let people know it's possible I guess? https://godbolt.org/z/o35rf7GK8
|
|
||
| // Casts a simd<float, N> into two simd<double, N/2> | ||
| template <size_t N> | ||
| LIBC_INLINE constexpr auto vector_float_to_double(cpp::simd<float, N> v) { |
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'm pretty sure the compiler should correctly handle oversized vectors, would be easier to just do the regular SIMD cast I would think.
| true, index, common_constants_internal::EXP_MANTISSA); | ||
| auto exponent = (u >> 6) << 52; | ||
| auto result = mantissa | exponent; | ||
| return reinterpret_cast<cpp::simd<double, N>>(result); |
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 feels strange to do reinterpret_cast from a simd register of integer to a simd register of double.
| return reinterpret_cast<cpp::simd<double, N>>(result); | |
| return cpp::bit_cast<cpp::simd<double, N>>(result); |
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.
Yeah, bit casting here seems suspicious. I'd assume it'd either be a broadcast or a simd cast
| template <size_t N> | ||
| LIBC_INLINE cpp::simd<double, N> exp_lookup(cpp::simd<uint64_t, N> u) { | ||
| auto index = u & cpp::simd<uint64_t, N>(0x3f); | ||
| auto mantissa = cpp::gather<cpp::simd<uint64_t, N>>( |
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.
FYI, performance here will be very bad if the target doesn't support gather natively. We should probably have a feature check for this
Created mathvec directories and unittest framework for vector math functions, as well as an initial implementation of vector expf, which is presently CR for round-to-nearest.