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