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