Skip to content

Commit 8979f16

Browse files
lhamesgithub-actions[bot]
authored andcommitted
Automerge: [orc-rt] Add bit.h -- substitute for not yet available STL <bit> APIs. (#155208)
Currently provides endian enum and byteswap.
2 parents 6b2e90f + 36627e1 commit 8979f16

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed

orc-rt/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set(ORC_RT_HEADERS
1111
orc-rt/Math.h
1212
orc-rt/RTTI.h
1313
orc-rt/WrapperFunctionResult.h
14+
orc-rt/bit.h
1415
orc-rt/move_only_function.h
1516
orc-rt/span.h
1617
)

orc-rt/include/orc-rt/bit.h

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//===-------- bit.h - Substitute for future STL bit APIs -------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Substitutes for STL <bit> APIs that aren't available to the ORC runtime yet.
10+
//
11+
// TODO: Replace all uses once the respective APIs are available.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef ORC_RT_BIT_H
16+
#define ORC_RT_BIT_H
17+
18+
#include <cstddef>
19+
#include <cstdint>
20+
#include <type_traits>
21+
#if defined(_MSC_VER) && !defined(_DEBUG)
22+
#include <stdlib.h>
23+
#endif
24+
25+
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
26+
defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
27+
#include <endian.h>
28+
#elif defined(_AIX)
29+
#include <sys/machine.h>
30+
#elif defined(__sun)
31+
/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
32+
#include <sys/types.h>
33+
#define BIG_ENDIAN 4321
34+
#define LITTLE_ENDIAN 1234
35+
#if defined(_BIG_ENDIAN)
36+
#define BYTE_ORDER BIG_ENDIAN
37+
#else
38+
#define BYTE_ORDER LITTLE_ENDIAN
39+
#endif
40+
#elif defined(__MVS__)
41+
#define BIG_ENDIAN 4321
42+
#define LITTLE_ENDIAN 1234
43+
#define BYTE_ORDER BIG_ENDIAN
44+
#else
45+
#if !defined(BYTE_ORDER) && !defined(_WIN32)
46+
#include <machine/endian.h>
47+
#endif
48+
#endif
49+
50+
namespace orc_rt {
51+
52+
enum class endian {
53+
big,
54+
little,
55+
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
56+
native = big
57+
#else
58+
native = little
59+
#endif
60+
};
61+
62+
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
63+
[[nodiscard]] constexpr T byteswap(T V) noexcept {
64+
// Implementation taken from llvm/include/ADT/bit.h.
65+
if constexpr (sizeof(T) == 1) {
66+
return V;
67+
} else if constexpr (sizeof(T) == 2) {
68+
uint16_t UV = V;
69+
#if defined(_MSC_VER) && !defined(_DEBUG)
70+
// The DLL version of the runtime lacks these functions (bug!?), but in a
71+
// release build they're replaced with BSWAP instructions anyway.
72+
return _byteswap_ushort(UV);
73+
#else
74+
uint16_t Hi = UV << 8;
75+
uint16_t Lo = UV >> 8;
76+
return Hi | Lo;
77+
#endif
78+
} else if constexpr (sizeof(T) == 4) {
79+
uint32_t UV = V;
80+
#if __has_builtin(__builtin_bswap32)
81+
return __builtin_bswap32(UV);
82+
#elif defined(_MSC_VER) && !defined(_DEBUG)
83+
return _byteswap_ulong(UV);
84+
#else
85+
uint32_t Byte0 = UV & 0x000000FF;
86+
uint32_t Byte1 = UV & 0x0000FF00;
87+
uint32_t Byte2 = UV & 0x00FF0000;
88+
uint32_t Byte3 = UV & 0xFF000000;
89+
return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
90+
#endif
91+
} else if constexpr (sizeof(T) == 8) {
92+
uint64_t UV = V;
93+
#if __has_builtin(__builtin_bswap64)
94+
return __builtin_bswap64(UV);
95+
#elif defined(_MSC_VER) && !defined(_DEBUG)
96+
return _byteswap_uint64(UV);
97+
#else
98+
uint64_t Hi = llvm::byteswap<uint32_t>(UV);
99+
uint32_t Lo = llvm::byteswap<uint32_t>(UV >> 32);
100+
return (Hi << 32) | Lo;
101+
#endif
102+
} else {
103+
static_assert(!sizeof(T *), "Don't know how to handle the given type.");
104+
return 0;
105+
}
106+
}
107+
108+
} // namespace orc_rt
109+
110+
#endif // ORC_RT_BIT_H

orc-rt/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ add_orc_rt_unittest(CoreTests
2020
MathTest.cpp
2121
RTTITest.cpp
2222
WrapperFunctionResultTest.cpp
23+
bit-test.cpp
2324
move_only_function-test.cpp
2425
span-test.cpp
2526
DISABLE_LLVM_LINK_LLVM_DYLIB

orc-rt/unittests/bit-test.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===- BitTest.cpp --------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Tests for orc-rt's bit.h APIs.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "orc-rt/bit.h"
14+
#include "gtest/gtest.h"
15+
16+
#include <cstdint>
17+
18+
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
19+
#define IS_BIG_ENDIAN
20+
#elif defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && \
21+
BYTE_ORDER == LITTLE_ENDIAN
22+
#define IS_LITTLE_ENDIAN
23+
#endif
24+
25+
using namespace orc_rt;
26+
27+
TEST(BitTest, endian) {
28+
#if defined(IS_BIG_ENDIAN)
29+
EXPECT_EQ(endian::native, endian::big);
30+
#elif defined(IS_LITTLE_ENDIAN)
31+
EXPECT_EQ(endian::native, endian::little);
32+
#else
33+
ADD_FAILURE() << "BYTE_ORDER is neither BIG_ENDIAN nor LITTLE_ENDIAN.";
34+
#endif
35+
}
36+
37+
TEST(MathTest, byte_swap_32) {
38+
unsigned char Seq[] = {0x01, 0x23, 0x45, 0x67};
39+
uint32_t X = 0;
40+
memcpy(&X, Seq, sizeof(X));
41+
auto Y = byteswap(X);
42+
43+
static_assert(sizeof(Seq) == sizeof(X),
44+
"sizeof(char[4]) != sizeof(uint32_t) ?");
45+
static_assert(std::is_same_v<decltype(X), decltype(Y)>,
46+
"byte_swap return type doesn't match input");
47+
48+
#if defined(IS_BIG_ENDIAN)
49+
EXPECT_EQ(X, uint32_t(0x01234567));
50+
EXPECT_EQ(Y, uint32_t(0x67452301));
51+
#elif defined(IS_LITTLE_ENDIAN)
52+
EXPECT_EQ(X, uint32_t(0x67452301));
53+
EXPECT_EQ(Y, uint32_t(0x01234567));
54+
#else
55+
ADD_FAILURE() << "BYTE_ORDER is neither BIG_ENDIAN nor LITTLE_ENDIAN.";
56+
#endif
57+
}
58+
59+
TEST(MathTest, byte_swap_64) {
60+
unsigned char Seq[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
61+
uint64_t X = 0;
62+
memcpy(&X, Seq, sizeof(X));
63+
auto Y = byteswap(X);
64+
65+
static_assert(sizeof(Seq) == sizeof(X),
66+
"sizeof(char[8]) != sizeof(uint64_t) ?");
67+
static_assert(std::is_same_v<decltype(X), decltype(Y)>,
68+
"byte_swap return type doesn't match input");
69+
70+
#if defined(IS_BIG_ENDIAN)
71+
EXPECT_EQ(X, uint64_t(0x0123456789ABCDEF));
72+
EXPECT_EQ(Y, uint64_t(0xEFCDAB8967452301));
73+
#elif defined(IS_LITTLE_ENDIAN)
74+
EXPECT_EQ(X, uint64_t(0xEFCDAB8967452301));
75+
EXPECT_EQ(Y, uint64_t(0x0123456789ABCDEF));
76+
#else
77+
ADD_FAILURE() << "BYTE_ORDER is neither BIG_ENDIAN nor LITTLE_ENDIAN.";
78+
#endif
79+
}

0 commit comments

Comments
 (0)