llvm.org GIT mirror llvm / c8b18df
[Support][Endian] Add support for specifying the alignment and native unaligned types. * Add support for specifying the alignment to use. * Add the concept of native endianness. Used for unaligned native types. The native alignment and read/write simplification is based on a patch by Richard Smith. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171406 91177308-0d34-0410-b5e6-96231b3b80d8 Michael J. Spencer 7 years ago
4 changed file(s) with 90 addition(s) and 122 deletion(s). Raw diff Collapse all Expand all
150150 #define LLVM_UNLIKELY(EXPR) (EXPR)
151151 #endif
152152
153
154153 // C++ doesn't support 'extern template' of template specializations. GCC does,
155154 // but requires __extension__ before it. In the header, use this:
156155 // EXTERN_TEMPLATE_INSTANTIATION(class foo);
186185 #define LLVM_ATTRIBUTE_ALWAYS_INLINE
187186 #endif
188187
189
190188 #ifdef __GNUC__
191189 #define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn))
192190 #elif defined(_MSC_VER)
224222 #if defined(__clang__) || (__GNUC__ > 4) \
225223 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
226224 # define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
225 #elif defined(_MSC_VER)
226 # define LLVM_BUILTIN_UNREACHABLE __assume(false)
227 #else
228 # define LLVM_BUILTIN_UNREACHABLE 0
227229 #endif
228230
229231 /// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression
235237 # define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0
236238 #endif
237239
238 #endif
240 /// \macro LLVM_ASSUME_ALIGNED
241 /// \brief Returns a pointer with an assumed alignment.
242 #if defined(__GNUC__) && !defined(__clang__)
243 // FIXME: Enable on clang when it supports it.
244 # define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
245 #else
246 # define LLVM_ASSUME_ALIGNED(p, a) \
247 (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
248 #endif
249
250 #endif
1313 #ifndef LLVM_SUPPORT_ENDIAN_H
1414 #define LLVM_SUPPORT_ENDIAN_H
1515
16 #include "llvm/Support/AlignOf.h"
1617 #include "llvm/Support/Host.h"
1718 #include "llvm/Support/SwapByteOrder.h"
1819 #include "llvm/Support/type_traits.h"
1920
2021 namespace llvm {
2122 namespace support {
23 enum endianness {big, little, native};
2224
23 enum endianness {big, little};
24 enum alignment {unaligned, aligned};
25 // These are named values for common alignments.
26 enum {aligned = 0, unaligned = 1};
2527
2628 namespace detail {
27
28 template
29 struct alignment_access_helper;
30
31 template
32 struct alignment_access_helper
33 {
34 value_type val;
35 };
36
37 // Provides unaligned loads and stores.
38 #pragma pack(push)
39 #pragma pack(1)
40 template
41 struct alignment_access_helper
42 {
43 value_type val;
44 };
45 #pragma pack(pop)
46
29 /// \brief ::value is either alignment, or alignof(T) if alignment is 0.
30 template
31 struct PickAlignment {
32 enum {value = alignment == 0 ? AlignOf::Alignment : alignment};
33 };
4734 } // end namespace detail
4835
4936 namespace endian {
50 template
51 inline value_type read_le(const void *memory) {
52 value_type t =
53 reinterpret_cast
54 *>(memory)->val;
55 if (sys::isBigEndianHost())
56 return sys::SwapByteOrder(t);
57 return t;
58 }
59
60 template
61 inline void write_le(void *memory, value_type value) {
62 if (sys::isBigEndianHost())
63 value = sys::SwapByteOrder(value);
64 reinterpret_cast *>
65 (memory)->val = value;
66 }
67
68 template
69 inline value_type read_be(const void *memory) {
70 value_type t =
71 reinterpret_cast
72 *>(memory)->val;
73 if (sys::isLittleEndianHost())
74 return sys::SwapByteOrder(t);
75 return t;
76 }
77
78 template
79 inline void write_be(void *memory, value_type value) {
80 if (sys::isLittleEndianHost())
81 value = sys::SwapByteOrder(value);
82 reinterpret_cast *>
83 (memory)->val = value;
84 }
37 template
38 inline value_type byte_swap(value_type value) {
39 if (endian != native && sys::isBigEndianHost() != (endian == big))
40 return sys::SwapByteOrder(value);
41 return value;
8542 }
86
87 namespace detail {
8843
8944 template
9045 endianness endian,
91 alignment align>
92 class packed_endian_specific_integral;
46 std::size_t alignment>
47 inline value_type read(const void *memory) {
48 value_type ret;
9349
94 template
95 class packed_endian_specific_integral {
96 public:
50 memcpy(&ret,
51 LLVM_ASSUME_ALIGNED(memory,
52 (detail::PickAlignment::value)),
53 sizeof(value_type));
54 return byte_swap(ret);
55 }
56
57 template
58 endianness endian,
59 std::size_t alignment>
60 inline void write(void *memory, value_type value) {
61 value = byte_swap(value);
62 memcpy(LLVM_ASSUME_ALIGNED(memory,
63 (detail::PickAlignment::value)),
64 &value,
65 sizeof(value_type));
66 }
67 } // end namespace endian
68
69 namespace detail {
70 template
71 endianness endian,
72 std::size_t alignment>
73 struct packed_endian_specific_integral {
9774 operator value_type() const {
98 return endian::read_le(Value);
75 return endian::read(
76 (const void*)Value.buffer);
9977 }
78
10079 void operator=(value_type newValue) {
101 endian::write_le((void *)&Value, newValue);
80 endian::write(
81 (void*)Value.buffer, newValue);
10282 }
83
10384 private:
104 uint8_t Value[sizeof(value_type)];
85 AlignedCharArray::value,
86 sizeof(value_type)> Value;
10587 };
106
107 template
108 class packed_endian_specific_integral {
109 public:
110 operator value_type() const {
111 return endian::read_be(Value);
112 }
113 void operator=(value_type newValue) {
114 endian::write_be((void *)&Value, newValue);
115 }
116 private:
117 uint8_t Value[sizeof(value_type)];
118 };
119
120 template
121 class packed_endian_specific_integral {
122 public:
123 operator value_type() const {
124 return endian::read_le(&Value);
125 }
126 void operator=(value_type newValue) {
127 endian::write_le((void *)&Value, newValue);
128 }
129 private:
130 value_type Value;
131 };
132
133 template
134 class packed_endian_specific_integral {
135 public:
136 operator value_type() const {
137 return endian::read_be(&Value);
138 }
139 void operator=(value_type newValue) {
140 endian::write_be((void *)&Value, newValue);
141 }
142 private:
143 value_type Value;
144 };
145
14688 } // end namespace detail
14789
14890 typedef detail::packed_endian_specific_integral
217159 typedef detail::packed_endian_specific_integral
218160 aligned_big64_t;
219161
162 typedef detail::packed_endian_specific_integral
163 unaligned_uint16_t;
164 typedef detail::packed_endian_specific_integral
165 unaligned_uint32_t;
166 typedef detail::packed_endian_specific_integral
167 unaligned_uint64_t;
168
169 typedef detail::packed_endian_specific_integral
170 unaligned_int16_t;
171 typedef detail::packed_endian_specific_integral
172 unaligned_int32_t;
173 typedef detail::packed_endian_specific_integral
174 unaligned_int64_t;
220175 } // end namespace llvm
221176 } // end namespace support
222177
2020
2121 TEST(Endian, Read) {
2222 // These are 5 bytes so we can be sure at least one of the reads is unaligned.
23 unsigned char big[] = {0x00, 0x01, 0x02, 0x03, 0x04};
24 unsigned char little[] = {0x00, 0x04, 0x03, 0x02, 0x01};
23 unsigned char bigval[] = {0x00, 0x01, 0x02, 0x03, 0x04};
24 unsigned char littleval[] = {0x00, 0x04, 0x03, 0x02, 0x01};
2525 int32_t BigAsHost = 0x00010203;
26 EXPECT_EQ(BigAsHost, (endian::read_be(big)));
26 EXPECT_EQ(BigAsHost, (endian::read(bigval)));
2727 int32_t LittleAsHost = 0x02030400;
28 EXPECT_EQ(LittleAsHost, (endian::read_le(little)));
28 EXPECT_EQ(LittleAsHost,(endian::read(littleval)));
2929
30 EXPECT_EQ((endian::read_be(big + 1)),
31 (endian::read_le(little + 1)));
30 EXPECT_EQ((endian::read(bigval + 1)),
31 (endian::read(littleval + 1)));
3232 }
3333
3434 TEST(Endian, Write) {
3535 unsigned char data[5];
36 endian::write_be, unaligned>(data, -1362446643);
36 endian::write, unaligned>(data, -1362446643);
3737 EXPECT_EQ(data[0], 0xAE);
3838 EXPECT_EQ(data[1], 0xCA);
3939 EXPECT_EQ(data[2], 0xB6);
4040 EXPECT_EQ(data[3], 0xCD);
41 endian::write_be, unaligned>(data + 1, -1362446643);
41 endian::write, unaligned>(data + 1, -1362446643);
4242 EXPECT_EQ(data[1], 0xAE);
4343 EXPECT_EQ(data[2], 0xCA);
4444 EXPECT_EQ(data[3], 0xB6);
4545 EXPECT_EQ(data[4], 0xCD);
4646
47 endian::write_le, unaligned>(data, -1362446643);
47 endian::write, unaligned>(data, -1362446643);
4848 EXPECT_EQ(data[0], 0xCD);
4949 EXPECT_EQ(data[1], 0xB6);
5050 EXPECT_EQ(data[2], 0xCA);
5151 EXPECT_EQ(data[3], 0xAE);
52 endian::write_le, unaligned>(data + 1, -1362446643);
52 endian::write, unaligned>(data + 1, -1362446643);
5353 EXPECT_EQ(data[1], 0xCD);
5454 EXPECT_EQ(data[2], 0xB6);
5555 EXPECT_EQ(data[3], 0xCA);
6868 EXPECT_EQ(*big_val, *little_val);
6969 }
7070
71 }
71 } // end anon namespace
789789 raw_ostream &operator <<( raw_ostream &OS
790790 , const binary_le_impl &BLE) {
791791 char Buffer[sizeof(BLE.Value)];
792 support::endian::write_le(Buffer, BLE.Value);
792 support::endian::write(
793 Buffer, BLE.Value);
793794 OS.write(Buffer, sizeof(BLE.Value));
794795 return OS;
795796 }