summaryrefslogtreecommitdiff
path: root/lib/mlibc/options/internal/generic/essential.cpp
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2024-03-07 17:28:00 -0500
committerIan Moffett <ian@osmora.org>2024-03-07 17:28:32 -0500
commitbd5969fc876a10b18613302db7087ef3c40f18e1 (patch)
tree7c2b8619afe902abf99570df2873fbdf40a4d1a1 /lib/mlibc/options/internal/generic/essential.cpp
parenta95b38b1b92b172e6cc4e8e56a88a30cc65907b0 (diff)
lib: Add mlibc
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'lib/mlibc/options/internal/generic/essential.cpp')
-rw-r--r--lib/mlibc/options/internal/generic/essential.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/lib/mlibc/options/internal/generic/essential.cpp b/lib/mlibc/options/internal/generic/essential.cpp
new file mode 100644
index 0000000..d00df1e
--- /dev/null
+++ b/lib/mlibc/options/internal/generic/essential.cpp
@@ -0,0 +1,217 @@
+#include <string.h>
+#include <stdint.h>
+
+namespace {
+ // Needed since we cannot declare a templated enum.
+ template<typename T>
+ struct word_helper {
+ using underlying [[gnu::aligned(1)]] = T;
+ enum class [[gnu::may_alias]] word_enum : underlying { };
+ };
+
+ template<typename T>
+ using word = typename word_helper<T>::word_enum;
+
+ template<typename T>
+ [[gnu::always_inline]]
+ inline word<T> alias_load(const unsigned char *&p) {
+ word<T> value = *reinterpret_cast<const word<T> *>(p);
+ p += sizeof(T);
+ return value;
+ }
+
+ template<typename T>
+ [[gnu::always_inline]]
+ inline void alias_store(unsigned char *&p, word<T> value) {
+ *reinterpret_cast<word<T> *>(p) = value;
+ p += sizeof(T);
+ }
+
+#ifdef __LP64__
+ void *forward_copy(void *__restrict dest, const void *__restrict src, size_t n) {
+ auto curDest = reinterpret_cast<unsigned char *>(dest);
+ auto curSrc = reinterpret_cast<const unsigned char *>(src);
+
+ while(n >= 8 * 8) {
+ auto w1 = alias_load<uint64_t>(curSrc);
+ auto w2 = alias_load<uint64_t>(curSrc);
+ auto w3 = alias_load<uint64_t>(curSrc);
+ auto w4 = alias_load<uint64_t>(curSrc);
+ auto w5 = alias_load<uint64_t>(curSrc);
+ auto w6 = alias_load<uint64_t>(curSrc);
+ auto w7 = alias_load<uint64_t>(curSrc);
+ auto w8 = alias_load<uint64_t>(curSrc);
+ alias_store<uint64_t>(curDest, w1);
+ alias_store<uint64_t>(curDest, w2);
+ alias_store<uint64_t>(curDest, w3);
+ alias_store<uint64_t>(curDest, w4);
+ alias_store<uint64_t>(curDest, w5);
+ alias_store<uint64_t>(curDest, w6);
+ alias_store<uint64_t>(curDest, w7);
+ alias_store<uint64_t>(curDest, w8);
+ n -= 8 * 8;
+ }
+ if(n >= 4 * 8) {
+ auto w1 = alias_load<uint64_t>(curSrc);
+ auto w2 = alias_load<uint64_t>(curSrc);
+ auto w3 = alias_load<uint64_t>(curSrc);
+ auto w4 = alias_load<uint64_t>(curSrc);
+ alias_store<uint64_t>(curDest, w1);
+ alias_store<uint64_t>(curDest, w2);
+ alias_store<uint64_t>(curDest, w3);
+ alias_store<uint64_t>(curDest, w4);
+ n -= 4 * 8;
+ }
+ if(n >= 2 * 8) {
+ auto w1 = alias_load<uint64_t>(curSrc);
+ auto w2 = alias_load<uint64_t>(curSrc);
+ alias_store<uint64_t>(curDest, w1);
+ alias_store<uint64_t>(curDest, w2);
+ n -= 2 * 8;
+ }
+ if(n >= 8) {
+ auto w = alias_load<uint64_t>(curSrc);
+ alias_store<uint64_t>(curDest, w);
+ n -= 8;
+ }
+ if(n >= 4) {
+ auto w = alias_load<uint32_t>(curSrc);
+ alias_store<uint32_t>(curDest, w);
+ n -= 4;
+ }
+ if(n >= 2) {
+ auto w = alias_load<uint16_t>(curSrc);
+ alias_store<uint16_t>(curDest, w);
+ n -= 2;
+ }
+ if(n)
+ *curDest = *curSrc;
+ return dest;
+ }
+#else // !__LP64__
+ void *forward_copy(void *dest, const void *src, size_t n) {
+ for(size_t i = 0; i < n; i++)
+ ((char *)dest)[i] = ((const char *)src)[i];
+ return dest;
+ }
+#endif // __LP64__ / !__LP64__
+}
+
+// --------------------------------------------------------------------------------------
+// memcpy() implementation.
+// --------------------------------------------------------------------------------------
+
+
+void *memcpy(void *__restrict dest, const void *__restrict src, size_t n) {
+ return forward_copy(dest, src, n);
+}
+
+
+// --------------------------------------------------------------------------------------
+// memset() implementation.
+// --------------------------------------------------------------------------------------
+
+#ifdef __LP64__
+
+void *memset(void *dest, int val, size_t n) {
+ auto curDest = reinterpret_cast<unsigned char *>(dest);
+ unsigned char byte = val;
+
+ // Get rid of misalignment.
+ while(n && (reinterpret_cast<uintptr_t>(curDest) & 7)) {
+ *curDest++ = byte;
+ --n;
+ }
+
+ auto pattern64 = static_cast<word<uint64_t>>(
+ static_cast<uint64_t>(byte)
+ | (static_cast<uint64_t>(byte) << 8)
+ | (static_cast<uint64_t>(byte) << 16)
+ | (static_cast<uint64_t>(byte) << 24)
+ | (static_cast<uint64_t>(byte) << 32)
+ | (static_cast<uint64_t>(byte) << 40)
+ | (static_cast<uint64_t>(byte) << 48)
+ | (static_cast<uint64_t>(byte) << 56));
+
+ auto pattern32 = static_cast<word<uint32_t>>(
+ static_cast<uint32_t>(byte)
+ | (static_cast<uint32_t>(byte) << 8)
+ | (static_cast<uint32_t>(byte) << 16)
+ | (static_cast<uint32_t>(byte) << 24));
+
+ auto pattern16 = static_cast<word<uint16_t>>(
+ static_cast<uint16_t>(byte)
+ | (static_cast<uint16_t>(byte) << 8));
+
+ while(n >= 8 * 8) {
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ n -= 8 * 8;
+ }
+ if(n >= 4 * 8) {
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ n -= 4 * 8;
+ }
+ if(n >= 2 * 8) {
+ alias_store<uint64_t>(curDest, pattern64);
+ alias_store<uint64_t>(curDest, pattern64);
+ n -= 2 * 8;
+ }
+ if(n >= 8) {
+ alias_store<uint64_t>(curDest, pattern64);
+ n -= 8;
+ }
+ if(n >= 4) {
+ alias_store<uint32_t>(curDest, pattern32);
+ n -= 4;
+ }
+ if(n >= 2) {
+ alias_store<uint16_t>(curDest, pattern16);
+ n -= 2;
+ }
+ if(n)
+ *curDest = byte;
+ return dest;
+}
+
+#else // !__LP64__
+
+void *memset(void *dest, int byte, size_t count) {
+ for(size_t i = 0; i < count; i++)
+ ((char *)dest)[i] = (char)byte;
+ return dest;
+}
+
+#endif // __LP64__ / !__LP64__
+
+// --------------------------------------------------------------------------------------
+// "Non-optimized" functions.
+// --------------------------------------------------------------------------------------
+
+void *memmove(void *dest, const void *src, size_t size) {
+ char *dest_bytes = (char *)dest;
+ char *src_bytes = (char *)src;
+ if(dest_bytes < src_bytes) {
+ return forward_copy(dest, src, size);
+ }else if(dest_bytes > src_bytes) {
+ for(size_t i = 0; i < size; i++)
+ dest_bytes[size - i - 1] = src_bytes[size - i - 1];
+ }
+ return dest;
+}
+
+size_t strlen(const char *s) {
+ size_t len = 0;
+ for(size_t i = 0; s[i]; i++)
+ len++;
+ return len;
+}