Skip to content

Commit c8adbd7

Browse files
authored
[orc-rt] Add endian_read/write operations. (#166892)
The endian_read and endian_write operations read and write unsigned integers stored in a given endianness.
1 parent 3aa7a24 commit c8adbd7

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

orc-rt/include/orc-rt/Endian.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===----- Endian.h - Endianness helpers for the ORC runtime ----*- 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+
// Endianness helper functions for the ORC runtime.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef ORC_RT_ENDIAN_H
14+
#define ORC_RT_ENDIAN_H
15+
16+
#include "bit.h"
17+
#include <cstring>
18+
#include <type_traits>
19+
20+
namespace orc_rt {
21+
22+
/// Read a value with the given endianness from memory.
23+
template <typename T>
24+
[[nodiscard]] inline std::enable_if_t<std::is_integral_v<T>, T>
25+
endian_read(const void *Src, orc_rt::endian E) noexcept {
26+
T Val;
27+
memcpy(&Val, Src, sizeof(T));
28+
if (E != orc_rt::endian::native)
29+
Val = orc_rt::byteswap(Val);
30+
return Val;
31+
}
32+
33+
/// Write a value with the given endianness to memory.
34+
template <typename T>
35+
inline std::enable_if_t<std::is_integral_v<T>>
36+
endian_write(void *Dst, T Val, orc_rt::endian E) noexcept {
37+
if (E != orc_rt::endian::native)
38+
Val = orc_rt::byteswap(Val);
39+
memcpy(Dst, &Val, sizeof(T));
40+
}
41+
42+
} // namespace orc_rt
43+
44+
#endif // ORC_RT_ENDIAN_H

orc-rt/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_orc_rt_unittest(CoreTests
1515
AllocActionTest.cpp
1616
BitmaskEnumTest.cpp
1717
CallableTraitsHelperTest.cpp
18+
EndianTest.cpp
1819
ErrorTest.cpp
1920
ExecutorAddressTest.cpp
2021
IntervalMapTest.cpp

orc-rt/unittests/EndianTest.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//===- EndianTest.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 Endian.h APIs.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "orc-rt/Endian.h"
14+
#include "gtest/gtest.h"
15+
16+
#include <algorithm>
17+
#include <limits>
18+
19+
using namespace orc_rt;
20+
21+
template <typename T> static void endianRead(T Value, endian E) {
22+
char Buffer[sizeof(T)];
23+
memcpy(Buffer, &Value, sizeof(T));
24+
25+
if (E != endian::native)
26+
std::reverse(Buffer, Buffer + sizeof(T));
27+
28+
T NewVal = endian_read<T>(Buffer, E);
29+
EXPECT_EQ(NewVal, Value);
30+
}
31+
32+
template <typename T> static void endianWrite(T Value, endian E) {
33+
char Buffer[sizeof(T)];
34+
35+
endian_write(Buffer, Value, E);
36+
37+
if (E != endian::native)
38+
std::reverse(Buffer, Buffer + sizeof(T));
39+
40+
T NewVal;
41+
memcpy(&NewVal, Buffer, sizeof(T));
42+
43+
EXPECT_EQ(NewVal, Value);
44+
}
45+
46+
template <typename T> static void endianReadAndWrite(T Value, endian E) {
47+
endianRead(Value, E);
48+
endianWrite(Value, E);
49+
}
50+
51+
template <typename T> static void bothEndiansReadAndWrite(T Value) {
52+
endianReadAndWrite(Value, endian::little);
53+
endianReadAndWrite(Value, endian::big);
54+
}
55+
56+
// Rotate the given bit pattern through all valid rotations for T, testing that
57+
// the given operation works for the given pattern.
58+
template <typename Op, typename T>
59+
void forAllRotatedValues(Op O, T InitialValue) {
60+
T V = InitialValue;
61+
for (size_t I = 0; I != CHAR_BIT * sizeof(T); ++I) {
62+
O(V);
63+
V = llvm::rotl(V, 1);
64+
}
65+
}
66+
67+
template <typename Op, typename T>
68+
void forAllShiftedValues(Op O, T InitialValue) {
69+
T V = InitialValue;
70+
constexpr T TopValueBit = 1 << (std::numeric_limits<T>::digits - 1);
71+
for (size_t I = 0; I != CHAR_BIT * sizeof(T); ++I) {
72+
O(V);
73+
if (V & TopValueBit)
74+
break;
75+
V << 1;
76+
}
77+
}
78+
79+
TEST(EndianTest, ReadWrite) {
80+
bothEndiansReadAndWrite<uint8_t>(0);
81+
bothEndiansReadAndWrite<uint8_t>(0xff);
82+
forAllRotatedValues(bothEndiansReadAndWrite<uint8_t>, uint8_t(1));
83+
forAllRotatedValues(bothEndiansReadAndWrite<uint8_t>, uint8_t(0x5A));
84+
85+
bothEndiansReadAndWrite<uint16_t>(0);
86+
bothEndiansReadAndWrite<uint16_t>(0xffff);
87+
forAllRotatedValues(bothEndiansReadAndWrite<uint16_t>, uint16_t(1));
88+
forAllRotatedValues(bothEndiansReadAndWrite<uint16_t>, uint16_t(0x5A5A));
89+
90+
bothEndiansReadAndWrite<uint32_t>(0);
91+
bothEndiansReadAndWrite<uint32_t>(0xffffffff);
92+
forAllRotatedValues(bothEndiansReadAndWrite<uint32_t>, uint32_t(1));
93+
forAllRotatedValues(bothEndiansReadAndWrite<uint32_t>, uint32_t(0x5A5A5A5A));
94+
95+
bothEndiansReadAndWrite<uint64_t>(0);
96+
bothEndiansReadAndWrite<uint64_t>(0xffffffffffffffff);
97+
forAllRotatedValues(bothEndiansReadAndWrite<uint64_t>, uint64_t(1));
98+
forAllRotatedValues(bothEndiansReadAndWrite<uint64_t>,
99+
uint64_t(0x5A5A5A5A5A5A5A5A));
100+
}

0 commit comments

Comments
 (0)