[llvm] [orc-rt] Add bit.h -- substitute for not yet available STL <bit> APIs. (PR #155208)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 24 22:07:21 PDT 2025


https://github.com/lhames created https://github.com/llvm/llvm-project/pull/155208

Currently provides endian enum and byteswap.

>From 09a241fb68ee9c38e991562cad1f5db4d9a668e3 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Mon, 25 Aug 2025 14:50:56 +1000
Subject: [PATCH] [orc-rt] Add bit.h -- substitute for not yet available STL
 <bit> APIs.

Currently provides endian enum and byteswap.
---
 orc-rt/include/CMakeLists.txt   |   1 +
 orc-rt/include/orc-rt/bit.h     | 110 ++++++++++++++++++++++++++++++++
 orc-rt/unittests/CMakeLists.txt |   1 +
 orc-rt/unittests/bit-test.cpp   |  79 +++++++++++++++++++++++
 4 files changed, 191 insertions(+)
 create mode 100644 orc-rt/include/orc-rt/bit.h
 create mode 100644 orc-rt/unittests/bit-test.cpp

diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index d8d98eae9fa7e..859b8fb503ca8 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -11,6 +11,7 @@ set(ORC_RT_HEADERS
     orc-rt/Math.h
     orc-rt/RTTI.h
     orc-rt/WrapperFunctionResult.h
+    orc-rt/bit.h
     orc-rt/move_only_function.h
     orc-rt/span.h
 )
diff --git a/orc-rt/include/orc-rt/bit.h b/orc-rt/include/orc-rt/bit.h
new file mode 100644
index 0000000000000..97dbee2f3442b
--- /dev/null
+++ b/orc-rt/include/orc-rt/bit.h
@@ -0,0 +1,110 @@
+//===-------- bit.h - Substitute for future STL bit APIs -------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Substitutes for STL <bit> APIs that aren't available to the ORC runtime yet.
+//
+// TODO: Replace all uses once the respective APIs are available.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_BIT_H
+#define ORC_RT_BIT_H
+
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+#if defined(_MSC_VER) && !defined(_DEBUG)
+#include <stdlib.h>
+#endif
+
+#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) ||            \
+    defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
+#include <endian.h>
+#elif defined(_AIX)
+#include <sys/machine.h>
+#elif defined(__sun)
+/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
+#include <sys/types.h>
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#if defined(_BIG_ENDIAN)
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#elif defined(__MVS__)
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#if !defined(BYTE_ORDER) && !defined(_WIN32)
+#include <machine/endian.h>
+#endif
+#endif
+
+namespace orc_rt {
+
+enum class endian {
+  big,
+  little,
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
+  native = big
+#else
+  native = little
+#endif
+};
+
+template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+[[nodiscard]] constexpr T byteswap(T V) noexcept {
+  // Implementation taken from llvm/include/ADT/bit.h.
+  if constexpr (sizeof(T) == 1) {
+    return V;
+  } else if constexpr (sizeof(T) == 2) {
+    uint16_t UV = V;
+#if defined(_MSC_VER) && !defined(_DEBUG)
+    // The DLL version of the runtime lacks these functions (bug!?), but in a
+    // release build they're replaced with BSWAP instructions anyway.
+    return _byteswap_ushort(UV);
+#else
+    uint16_t Hi = UV << 8;
+    uint16_t Lo = UV >> 8;
+    return Hi | Lo;
+#endif
+  } else if constexpr (sizeof(T) == 4) {
+    uint32_t UV = V;
+#if __has_builtin(__builtin_bswap32)
+    return __builtin_bswap32(UV);
+#elif defined(_MSC_VER) && !defined(_DEBUG)
+    return _byteswap_ulong(UV);
+#else
+    uint32_t Byte0 = UV & 0x000000FF;
+    uint32_t Byte1 = UV & 0x0000FF00;
+    uint32_t Byte2 = UV & 0x00FF0000;
+    uint32_t Byte3 = UV & 0xFF000000;
+    return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
+#endif
+  } else if constexpr (sizeof(T) == 8) {
+    uint64_t UV = V;
+#if __has_builtin(__builtin_bswap64)
+    return __builtin_bswap64(UV);
+#elif defined(_MSC_VER) && !defined(_DEBUG)
+    return _byteswap_uint64(UV);
+#else
+    uint64_t Hi = llvm::byteswap<uint32_t>(UV);
+    uint32_t Lo = llvm::byteswap<uint32_t>(UV >> 32);
+    return (Hi << 32) | Lo;
+#endif
+  } else {
+    static_assert(!sizeof(T *), "Don't know how to handle the given type.");
+    return 0;
+  }
+}
+
+} // namespace orc_rt
+
+#endif // ORC_RT_BIT_H
diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt
index 03f772d16c473..fb782f17a8231 100644
--- a/orc-rt/unittests/CMakeLists.txt
+++ b/orc-rt/unittests/CMakeLists.txt
@@ -20,6 +20,7 @@ add_orc_rt_unittest(CoreTests
   MathTest.cpp
   RTTITest.cpp
   WrapperFunctionResultTest.cpp
+  bit-test.cpp
   move_only_function-test.cpp
   span-test.cpp
   DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/orc-rt/unittests/bit-test.cpp b/orc-rt/unittests/bit-test.cpp
new file mode 100644
index 0000000000000..43662e0e641b8
--- /dev/null
+++ b/orc-rt/unittests/bit-test.cpp
@@ -0,0 +1,79 @@
+//===- BitTest.cpp --------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for orc-rt's bit.h APIs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt/bit.h"
+#include "gtest/gtest.h"
+
+#include <cstdint>
+
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
+#define IS_BIG_ENDIAN
+#elif defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) &&                         \
+    BYTE_ORDER == LITTLE_ENDIAN
+#define IS_LITTLE_ENDIAN
+#endif
+
+using namespace orc_rt;
+
+TEST(BitTest, endian) {
+#if defined(IS_BIG_ENDIAN)
+  EXPECT_EQ(endian::native, endian::big);
+#elif defined(IS_LITTLE_ENDIAN)
+  EXPECT_EQ(endian::native, endian::little);
+#else
+  ADD_FAILURE() << "BYTE_ORDER is neither BIG_ENDIAN nor LITTLE_ENDIAN.";
+#endif
+}
+
+TEST(MathTest, byte_swap_32) {
+  unsigned char Seq[] = {0x01, 0x23, 0x45, 0x67};
+  uint32_t X = 0;
+  memcpy(&X, Seq, sizeof(X));
+  auto Y = byteswap(X);
+
+  static_assert(sizeof(Seq) == sizeof(X),
+                "sizeof(char[4]) != sizeof(uint32_t) ?");
+  static_assert(std::is_same_v<decltype(X), decltype(Y)>,
+                "byte_swap return type doesn't match input");
+
+#if defined(IS_BIG_ENDIAN)
+  EXPECT_EQ(X, uint32_t(0x01234567));
+  EXPECT_EQ(Y, uint32_t(0x67452301));
+#elif defined(IS_LITTLE_ENDIAN)
+  EXPECT_EQ(X, uint32_t(0x67452301));
+  EXPECT_EQ(Y, uint32_t(0x01234567));
+#else
+  ADD_FAILURE() << "BYTE_ORDER is neither BIG_ENDIAN nor LITTLE_ENDIAN.";
+#endif
+}
+
+TEST(MathTest, byte_swap_64) {
+  unsigned char Seq[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
+  uint64_t X = 0;
+  memcpy(&X, Seq, sizeof(X));
+  auto Y = byteswap(X);
+
+  static_assert(sizeof(Seq) == sizeof(X),
+                "sizeof(char[8]) != sizeof(uint64_t) ?");
+  static_assert(std::is_same_v<decltype(X), decltype(Y)>,
+                "byte_swap return type doesn't match input");
+
+#if defined(IS_BIG_ENDIAN)
+  EXPECT_EQ(X, uint64_t(0x0123456789ABCDEF));
+  EXPECT_EQ(Y, uint64_t(0xEFCDAB8967452301));
+#elif defined(IS_LITTLE_ENDIAN)
+  EXPECT_EQ(X, uint64_t(0xEFCDAB8967452301));
+  EXPECT_EQ(Y, uint64_t(0x0123456789ABCDEF));
+#else
+  ADD_FAILURE() << "BYTE_ORDER is neither BIG_ENDIAN nor LITTLE_ENDIAN.";
+#endif
+}



More information about the llvm-commits mailing list