openMSX
aligned.hh
Go to the documentation of this file.
1 #ifndef ALIGNED_HH
2 #define ALIGNED_HH
3 
4 #include "inline.hh"
5 #include <cstdint>
6 #include <cassert>
7 #include <cstring>
8 
9 // Only need to (more strictly) align when SSE is actually enabled.
10 #ifdef __SSE2__
11 constexpr auto SSE_ALIGNMENT = 16;
12 #else
13 constexpr auto SSE_ALIGNMENT = 0; // alignas(0) has no effect
14 #endif
15 
16 
17 // Unaligned loads and stores.
18 template<typename T> [[nodiscard]] static ALWAYS_INLINE T unalignedLoad(const void* p)
19 {
20  T t;
21  memcpy(&t, p, sizeof(t));
22  return t;
23 }
24 template<typename T> static ALWAYS_INLINE void unalignedStore(void* p, T t)
25 {
26  memcpy(p, &t, sizeof(t));
27 }
28 
29 [[nodiscard]] static ALWAYS_INLINE uint16_t unalignedLoad16(const void* p) {
30  return unalignedLoad<uint16_t>(p);
31 }
32 [[nodiscard]] static ALWAYS_INLINE uint32_t unalignedLoad32(const void* p) {
33  return unalignedLoad<uint32_t>(p);
34 }
35 [[nodiscard]] static ALWAYS_INLINE uint64_t unalignedLoad64(const void* p) {
36  return unalignedLoad<uint64_t>(p);
37 }
38 static ALWAYS_INLINE void unalignedStore16(void* p, uint16_t v) {
39  unalignedStore(p, v);
40 }
41 static ALWAYS_INLINE void unalignedStore32(void* p, uint32_t v) {
42  unalignedStore(p, v);
43 }
44 static ALWAYS_INLINE void unalignedStore64(void* p, uint64_t v) {
45  unalignedStore(p, v);
46 }
47 
48 
49 // assume_aligned, assume_SSE_aligned
50 //
51 // Let the compiler know a pointer is more strictly aligned than guaranteed by
52 // the C++ language rules. Sometimes this allows the compiler to generate more
53 // efficient code (typically when auto-vectorization is performed).
54 //
55 // Example:
56 // int* p = ...
57 // assume_SSE_aligned(p); // compiler can now assume 16-byte alignment for p
58 
59 // clang offers __has_builtin, fallback for other compilers
60 #ifndef __has_builtin
61 # define __has_builtin(x) 0
62 #endif
63 
64 // gcc-version check macro
65 #if defined(__GNUC__) && defined(__GNUC_MINOR__)
66 # define GNUC_PREREQ(maj, min) \
67  (((maj) * 100 + (min)) <= (__GNUC__ * 100 + __GNUC_MINOR__))
68 #else
69 # define GNUC_PREREQ(maj, min) 0
70 #endif
71 
72 template<size_t A, typename T>
73 static ALWAYS_INLINE void assume_aligned(T* __restrict & ptr)
74 {
75 #ifdef DEBUG // only check in debug build
76  assert((reinterpret_cast<uintptr_t>(ptr) % A) == 0);
77 #endif
78 
79 #if __has_builtin(__builtin_assume_aligned) || GNUC_PREREQ(4, 7)
80  ptr = static_cast<T* __restrict>(__builtin_assume_aligned(ptr, A));
81 #else
82  (void)ptr; // nothing
83 #endif
84 }
85 
86 template<typename T> static ALWAYS_INLINE void assume_SSE_aligned(
87 #ifdef __SSE2__
88  T* __restrict & ptr) { assume_aligned<16>(ptr); }
89 #else
90  T* __restrict & /*ptr*/) { /* nothing */ }
91 #endif
92 
93 #endif // ALIGNED_HH
SSE_ALIGNMENT
constexpr auto SSE_ALIGNMENT
Definition: aligned.hh:13
ALWAYS_INLINE
#define ALWAYS_INLINE
Definition: inline.hh:16
inline.hh
t
TclObject t
Definition: TclObject_test.cc:264
openmsx::A
@ A
Definition: CPUCore.cc:204