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__
11constexpr size_t SSE_ALIGNMENT = 16;
12#else
13constexpr 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.
28template<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}
34static ALWAYS_INLINE void unalignedStore(void* p, auto 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}
48ALWAYS_INLINE void unalignedStore16(void* p, uint16_t v) {
49 unalignedStore(p, v);
50}
51ALWAYS_INLINE void unalignedStore32(void* p, uint32_t v) {
52 unalignedStore(p, v);
53}
54ALWAYS_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
82template<size_t A, typename T>
83static 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
96template<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
TclObject t
ALWAYS_INLINE uint64_t unalignedLoad64(const void *p)
Definition: aligned.hh:45
ALWAYS_INLINE void unalignedStore64(void *p, uint64_t v)
Definition: aligned.hh:54
ALWAYS_INLINE uint16_t unalignedLoad16(const void *p)
Definition: aligned.hh:39
constexpr size_t SSE_ALIGNMENT
Definition: aligned.hh:13
ALWAYS_INLINE void unalignedStore16(void *p, uint16_t v)
Definition: aligned.hh:48
ALWAYS_INLINE void unalignedStore32(void *p, uint32_t v)
Definition: aligned.hh:51
ALWAYS_INLINE uint32_t unalignedLoad32(const void *p)
Definition: aligned.hh:42
#define ALWAYS_INLINE
Definition: inline.hh:16