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