[libc-commits] [libc] 7e075ad - [libc] Add endianness support
Guillaume Chatelet via libc-commits
libc-commits at lists.llvm.org
Fri Apr 16 14:35:17 PDT 2021
Author: Guillaume Chatelet
Date: 2021-04-16T21:35:08Z
New Revision: 7e075ad0b261236dd0a01f0b5e01f3221b0700d7
URL: https://github.com/llvm/llvm-project/commit/7e075ad0b261236dd0a01f0b5e01f3221b0700d7
DIFF: https://github.com/llvm/llvm-project/commit/7e075ad0b261236dd0a01f0b5e01f3221b0700d7.diff
LOG: [libc] Add endianness support
Add endianness detection support. This will be useful to implement `memcmp`.
Differential Revision: https://reviews.llvm.org/D100571
Added:
libc/src/__support/endian.h
libc/test/src/__support/CMakeLists.txt
libc/test/src/__support/endian_test.cpp
Modified:
libc/src/__support/CMakeLists.txt
libc/test/src/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index b20e8bc9a811f..4206d742b9bc8 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -2,6 +2,7 @@ add_header_library(
common
HDRS
common.h
+ endian.h
sanitizer.h
)
diff --git a/libc/src/__support/endian.h b/libc/src/__support/endian.h
new file mode 100644
index 0000000000000..e1d52ca468d34
--- /dev/null
+++ b/libc/src/__support/endian.h
@@ -0,0 +1,142 @@
+//===-- Endianness support ------------------------------------------------===//
+//
+// 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_ENDIAN_H
+#define LLVM_LIBC_SRC_SUPPORT_ENDIAN_H
+
+#include <stdint.h>
+
+namespace __llvm_libc {
+
+// We rely on compiler preprocessor defines to allow for cross compilation.
+#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \
+ !defined(__ORDER_BIG_ENDIAN__)
+#error "Missing preprocessor definitions for endianness detection."
+#endif
+
+namespace internal {
+
+// Converts uint8_t, uint16_t, uint32_t, uint64_t to its big or little endian
+// counterpart.
+// We use explicit template specialization:
+// - to prevent accidental integer promotion.
+// - to prevent fallback in (unlikely) case of middle-endianness.
+
+template <unsigned ORDER> struct Endian {
+ static constexpr const bool isLittle = ORDER == __ORDER_LITTLE_ENDIAN__;
+ static constexpr const bool isBig = ORDER == __ORDER_BIG_ENDIAN__;
+ template <typename T> static T ToBigEndian(T value);
+ template <typename T> static T ToLittleEndian(T value);
+};
+
+// Little Endian specializations
+template <>
+template <>
+inline uint8_t
+Endian<__ORDER_LITTLE_ENDIAN__>::ToBigEndian<uint8_t>(uint8_t v) {
+ return v;
+}
+template <>
+template <>
+inline uint8_t
+Endian<__ORDER_LITTLE_ENDIAN__>::ToLittleEndian<uint8_t>(uint8_t v) {
+ return v;
+}
+template <>
+template <>
+inline uint16_t
+Endian<__ORDER_LITTLE_ENDIAN__>::ToBigEndian<uint16_t>(uint16_t v) {
+ return __builtin_bswap16(v);
+}
+template <>
+template <>
+inline uint16_t
+Endian<__ORDER_LITTLE_ENDIAN__>::ToLittleEndian<uint16_t>(uint16_t v) {
+ return v;
+}
+template <>
+template <>
+inline uint32_t
+Endian<__ORDER_LITTLE_ENDIAN__>::ToBigEndian<uint32_t>(uint32_t v) {
+ return __builtin_bswap32(v);
+}
+template <>
+template <>
+inline uint32_t
+Endian<__ORDER_LITTLE_ENDIAN__>::ToLittleEndian<uint32_t>(uint32_t v) {
+ return v;
+}
+template <>
+template <>
+inline uint64_t
+Endian<__ORDER_LITTLE_ENDIAN__>::ToBigEndian<uint64_t>(uint64_t v) {
+ return __builtin_bswap64(v);
+}
+template <>
+template <>
+inline uint64_t
+Endian<__ORDER_LITTLE_ENDIAN__>::ToLittleEndian<uint64_t>(uint64_t v) {
+ return v;
+}
+
+// Big Endian specializations
+template <>
+template <>
+inline uint8_t Endian<__ORDER_BIG_ENDIAN__>::ToBigEndian<uint8_t>(uint8_t v) {
+ return v;
+}
+template <>
+template <>
+inline uint8_t
+Endian<__ORDER_BIG_ENDIAN__>::ToLittleEndian<uint8_t>(uint8_t v) {
+ return v;
+}
+template <>
+template <>
+inline uint16_t
+Endian<__ORDER_BIG_ENDIAN__>::ToBigEndian<uint16_t>(uint16_t v) {
+ return v;
+}
+template <>
+template <>
+inline uint16_t
+Endian<__ORDER_BIG_ENDIAN__>::ToLittleEndian<uint16_t>(uint16_t v) {
+ return __builtin_bswap16(v);
+}
+template <>
+template <>
+inline uint32_t
+Endian<__ORDER_BIG_ENDIAN__>::ToBigEndian<uint32_t>(uint32_t v) {
+ return v;
+}
+template <>
+template <>
+inline uint32_t
+Endian<__ORDER_BIG_ENDIAN__>::ToLittleEndian<uint32_t>(uint32_t v) {
+ return __builtin_bswap32(v);
+}
+template <>
+template <>
+inline uint64_t
+Endian<__ORDER_BIG_ENDIAN__>::ToBigEndian<uint64_t>(uint64_t v) {
+ return v;
+}
+template <>
+template <>
+inline uint64_t
+Endian<__ORDER_BIG_ENDIAN__>::ToLittleEndian<uint64_t>(uint64_t v) {
+ return __builtin_bswap64(v);
+}
+
+} // namespace internal
+
+using Endian = internal::Endian<__BYTE_ORDER__>;
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SUPPORT_ENDIAN_H
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 1d7c47070cb9c..d4689d9a24dc6 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(__support)
add_subdirectory(ctype)
add_subdirectory(errno)
add_subdirectory(fenv)
diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt
new file mode 100644
index 0000000000000..813e4137fb4ca
--- /dev/null
+++ b/libc/test/src/__support/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_libc_testsuite(libc_support_unittests)
+
+add_libc_unittest(
+ endian_test
+ SUITE
+ libc_support_unittests
+ SRCS
+ endian_test.cpp
+ DEPENDS
+ libc.src.__support.common
+)
diff --git a/libc/test/src/__support/endian_test.cpp b/libc/test/src/__support/endian_test.cpp
new file mode 100644
index 0000000000000..89e2be2bf9707
--- /dev/null
+++ b/libc/test/src/__support/endian_test.cpp
@@ -0,0 +1,55 @@
+//===-- Unittests for endian ----------------------------------------------===//
+//
+// 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/endian.h"
+#include "utils/UnitTest/Test.h"
+
+namespace __llvm_libc {
+
+struct LlvmLibcEndian : testing::Test {
+ template <typename T> void check(const T original, const T swapped) {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ EXPECT_EQ(Endian::ToLittleEndian(original), original);
+ EXPECT_EQ(Endian::ToBigEndian(original), swapped);
+#endif
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ EXPECT_EQ(Endian::ToBigEndian(original), original);
+ EXPECT_EQ(Endian::ToLittleEndian(original), swapped);
+#endif
+ }
+};
+
+TEST_F(LlvmLibcEndian, Field) {
+ EXPECT_EQ(Endian::isLittle, __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
+ EXPECT_EQ(Endian::isBig, __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
+}
+
+TEST_F(LlvmLibcEndian, uint8_t) {
+ const auto original = uint8_t(0x12);
+ check(original, original);
+}
+
+TEST_F(LlvmLibcEndian, uint16_t) {
+ const auto original = uint16_t(0x1234);
+ const auto swapped = __builtin_bswap16(original);
+ check(original, swapped);
+}
+
+TEST_F(LlvmLibcEndian, uint32_t) {
+ const auto original = uint32_t(0x12345678);
+ const auto swapped = __builtin_bswap32(original);
+ check(original, swapped);
+}
+
+TEST_F(LlvmLibcEndian, uint64_t) {
+ const auto original = uint64_t(0x123456789ABCDEF0);
+ const auto swapped = __builtin_bswap64(original);
+ check(original, swapped);
+}
+
+} // namespace __llvm_libc
More information about the libc-commits
mailing list