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