openMSX
MemoryOps.cc
Go to the documentation of this file.
1#include "MemoryOps.hh"
2
3#include "systemfuncs.hh"
4
5#include "endian.hh"
6#include "ranges.hh"
7#include "stl.hh"
8
9#include <bit>
10#include <cassert>
11#include <cstdlib>
12#include <new> // for std::bad_alloc
13
15
16void fill_2(std::span<uint32_t> out, uint32_t val0, uint32_t val1)
17{
18 if (out.empty()) [[unlikely]] return;
19
20 // Align at 64-bit boundary.
21 if (std::bit_cast<uintptr_t>(out.data()) & alignof(uint32_t)) [[unlikely]] {
22 out.front() = val1; // start at odd pixel
23 out = out.subspan(1);
24 }
25
26 // Main loop: (aligned) 64-bit fill.
27 std::span<uint64_t> out64{std::bit_cast<uint64_t*>(out.data()), out.size() / 2};
28 uint64_t val64 = Endian::BIG ? (uint64_t(val0) << 32) | val1
29 : val0 | (uint64_t(val1) << 32);
30 ranges::fill(out64, val64);
31
32 // Single remaining pixel.
33 if (out.size() & 1) [[unlikely]] {
34 out.back() = val0;
35 }
36}
37
38
42// Helper class to keep track of aligned/unaligned pointer pairs
44{
45public:
46 AllocMap(const AllocMap&) = delete;
47 AllocMap(AllocMap&&) = delete;
48 AllocMap& operator=(const AllocMap&) = delete;
50
51 static AllocMap& instance() {
52 static AllocMap oneInstance;
53 return oneInstance;
54 }
55
56 void insert(void* aligned, void* unaligned) {
57 if (!aligned) return;
58 assert(!contains(allocMap, aligned, &Entry::aligned));
59 allocMap.emplace_back(Entry{aligned, unaligned});
60 }
61
62 void* remove(void* aligned) {
63 if (!aligned) return nullptr;
64 // LIFO order is more likely than FIFO -> search backwards
65 auto it = rfind_unguarded(allocMap, aligned, &Entry::aligned);
66 // return the associated unaligned value
67 void* unaligned = it->unaligned;
68 move_pop_back(allocMap, it);
69 return unaligned;
70 }
71
72private:
73 AllocMap() = default;
74 ~AllocMap() {
75 assert(allocMap.empty());
76 }
77
78 // typically contains 5-10 items, so (unsorted) vector is fine
79 struct Entry {
80 void* aligned;
81 void* unaligned;
82 };
83 std::vector<Entry> allocMap;
84};
85
86void* mallocAligned(size_t alignment, size_t size)
87{
88 assert("must be a power of 2" && std::has_single_bit(alignment));
89 assert(alignment >= sizeof(void*));
90#if HAVE_POSIX_MEMALIGN
91 void* aligned = nullptr;
92 if (posix_memalign(&aligned, alignment, size)) {
93 throw std::bad_alloc();
94 }
95 #if defined DEBUG
96 AllocMap::instance().insert(aligned, aligned);
97 #endif
98 return aligned;
99#elif defined _MSC_VER
100 void* result = _aligned_malloc(size, alignment);
101 if (!result && size) throw std::bad_alloc();
102 return result;
103#else
104 auto t = alignment - 1;
105 void* unaligned = malloc(size + t);
106 if (!unaligned) {
107 throw std::bad_alloc();
108 }
109 auto aligned = std::bit_cast<void*>(
110 (std::bit_cast<uintptr_t>(unaligned) + t) & ~t);
111 AllocMap::instance().insert(aligned, unaligned);
112 return aligned;
113#endif
114}
115
116void freeAligned(void* aligned)
117{
118#if HAVE_POSIX_MEMALIGN
119 #if defined DEBUG
120 AllocMap::instance().remove(aligned);
121 #endif
122 free(aligned);
123#elif defined _MSC_VER
124 return _aligned_free(aligned);
125#else
126 void* unaligned = AllocMap::instance().remove(aligned);
127 free(unaligned);
128#endif
129}
130
131} // namespace openmsx::MemoryOps
TclObject t
Aligned memory (de)allocation.
Definition MemoryOps.cc:44
AllocMap(const AllocMap &)=delete
static AllocMap & instance()
Definition MemoryOps.cc:51
void insert(void *, void *unaligned)
Definition MemoryOps.cc:56
AllocMap & operator=(AllocMap &&)=delete
AllocMap & operator=(const AllocMap &)=delete
AllocMap(AllocMap &&)=delete
constexpr bool BIG
Definition endian.hh:16
void fill_2(std::span< uint32_t > out, uint32_t val0, uint32_t val1)
Definition MemoryOps.cc:16
void * mallocAligned(size_t alignment, size_t size)
Definition MemoryOps.cc:86
void freeAligned(void *)
Definition MemoryOps.cc:116
constexpr void fill(ForwardRange &&range, const T &value)
Definition ranges.hh:315
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
Definition stl.hh:137
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
Definition stl.hh:112
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition stl.hh:35