mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 02:38:07 +08:00
[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.
This commit is contained in:
44
orc-rt/include/orc-rt/Endian.h
Normal file
44
orc-rt/include/orc-rt/Endian.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//===----- Endian.h - Endianness helpers for the ORC runtime ----*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Endianness helper functions for the ORC runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ORC_RT_ENDIAN_H
|
||||
#define ORC_RT_ENDIAN_H
|
||||
|
||||
#include "bit.h"
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
namespace orc_rt {
|
||||
|
||||
/// Read a value with the given endianness from memory.
|
||||
template <typename T>
|
||||
[[nodiscard]] inline std::enable_if_t<std::is_integral_v<T>, T>
|
||||
endian_read(const void *Src, orc_rt::endian E) noexcept {
|
||||
T Val;
|
||||
memcpy(&Val, Src, sizeof(T));
|
||||
if (E != orc_rt::endian::native)
|
||||
Val = orc_rt::byteswap(Val);
|
||||
return Val;
|
||||
}
|
||||
|
||||
/// Write a value with the given endianness to memory.
|
||||
template <typename T>
|
||||
inline std::enable_if_t<std::is_integral_v<T>>
|
||||
endian_write(void *Dst, T Val, orc_rt::endian E) noexcept {
|
||||
if (E != orc_rt::endian::native)
|
||||
Val = orc_rt::byteswap(Val);
|
||||
memcpy(Dst, &Val, sizeof(T));
|
||||
}
|
||||
|
||||
} // namespace orc_rt
|
||||
|
||||
#endif // ORC_RT_ENDIAN_H
|
||||
@@ -15,6 +15,7 @@ add_orc_rt_unittest(CoreTests
|
||||
AllocActionTest.cpp
|
||||
BitmaskEnumTest.cpp
|
||||
CallableTraitsHelperTest.cpp
|
||||
EndianTest.cpp
|
||||
ErrorTest.cpp
|
||||
ExecutorAddressTest.cpp
|
||||
IntervalMapTest.cpp
|
||||
|
||||
100
orc-rt/unittests/EndianTest.cpp
Normal file
100
orc-rt/unittests/EndianTest.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
//===- EndianTest.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 Endian.h APIs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "orc-rt/Endian.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
using namespace orc_rt;
|
||||
|
||||
template <typename T> static void endianRead(T Value, endian E) {
|
||||
char Buffer[sizeof(T)];
|
||||
memcpy(Buffer, &Value, sizeof(T));
|
||||
|
||||
if (E != endian::native)
|
||||
std::reverse(Buffer, Buffer + sizeof(T));
|
||||
|
||||
T NewVal = endian_read<T>(Buffer, E);
|
||||
EXPECT_EQ(NewVal, Value);
|
||||
}
|
||||
|
||||
template <typename T> static void endianWrite(T Value, endian E) {
|
||||
char Buffer[sizeof(T)];
|
||||
|
||||
endian_write(Buffer, Value, E);
|
||||
|
||||
if (E != endian::native)
|
||||
std::reverse(Buffer, Buffer + sizeof(T));
|
||||
|
||||
T NewVal;
|
||||
memcpy(&NewVal, Buffer, sizeof(T));
|
||||
|
||||
EXPECT_EQ(NewVal, Value);
|
||||
}
|
||||
|
||||
template <typename T> static void endianReadAndWrite(T Value, endian E) {
|
||||
endianRead(Value, E);
|
||||
endianWrite(Value, E);
|
||||
}
|
||||
|
||||
template <typename T> static void bothEndiansReadAndWrite(T Value) {
|
||||
endianReadAndWrite(Value, endian::little);
|
||||
endianReadAndWrite(Value, endian::big);
|
||||
}
|
||||
|
||||
// Rotate the given bit pattern through all valid rotations for T, testing that
|
||||
// the given operation works for the given pattern.
|
||||
template <typename Op, typename T>
|
||||
void forAllRotatedValues(Op O, T InitialValue) {
|
||||
T V = InitialValue;
|
||||
for (size_t I = 0; I != CHAR_BIT * sizeof(T); ++I) {
|
||||
O(V);
|
||||
V = llvm::rotl(V, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Op, typename T>
|
||||
void forAllShiftedValues(Op O, T InitialValue) {
|
||||
T V = InitialValue;
|
||||
constexpr T TopValueBit = 1 << (std::numeric_limits<T>::digits - 1);
|
||||
for (size_t I = 0; I != CHAR_BIT * sizeof(T); ++I) {
|
||||
O(V);
|
||||
if (V & TopValueBit)
|
||||
break;
|
||||
V << 1;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EndianTest, ReadWrite) {
|
||||
bothEndiansReadAndWrite<uint8_t>(0);
|
||||
bothEndiansReadAndWrite<uint8_t>(0xff);
|
||||
forAllRotatedValues(bothEndiansReadAndWrite<uint8_t>, uint8_t(1));
|
||||
forAllRotatedValues(bothEndiansReadAndWrite<uint8_t>, uint8_t(0x5A));
|
||||
|
||||
bothEndiansReadAndWrite<uint16_t>(0);
|
||||
bothEndiansReadAndWrite<uint16_t>(0xffff);
|
||||
forAllRotatedValues(bothEndiansReadAndWrite<uint16_t>, uint16_t(1));
|
||||
forAllRotatedValues(bothEndiansReadAndWrite<uint16_t>, uint16_t(0x5A5A));
|
||||
|
||||
bothEndiansReadAndWrite<uint32_t>(0);
|
||||
bothEndiansReadAndWrite<uint32_t>(0xffffffff);
|
||||
forAllRotatedValues(bothEndiansReadAndWrite<uint32_t>, uint32_t(1));
|
||||
forAllRotatedValues(bothEndiansReadAndWrite<uint32_t>, uint32_t(0x5A5A5A5A));
|
||||
|
||||
bothEndiansReadAndWrite<uint64_t>(0);
|
||||
bothEndiansReadAndWrite<uint64_t>(0xffffffffffffffff);
|
||||
forAllRotatedValues(bothEndiansReadAndWrite<uint64_t>, uint64_t(1));
|
||||
forAllRotatedValues(bothEndiansReadAndWrite<uint64_t>,
|
||||
uint64_t(0x5A5A5A5A5A5A5A5A));
|
||||
}
|
||||
Reference in New Issue
Block a user