Skip to content

Instantly share code, notes, and snippets.

@ammarfaizi2
Last active September 15, 2023 22:59
Show Gist options
  • Save ammarfaizi2/648e4c956fd17d7bf7045d7559242c64 to your computer and use it in GitHub Desktop.
Save ammarfaizi2/648e4c956fd17d7bf7045d7559242c64 to your computer and use it in GitHub Desktop.
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <endian.h>
#ifdef __x86_64__
#define NOLIBC_ARCH_HAS_U128
#endif
#define NOLIBC_ARCH_UNALIGNED_ACCESS_IS_OK
#ifdef NOLIBC_ARCH_UNALIGNED_ACCESS_IS_OK
#ifdef NOLIBC_ARCH_HAS_U128
typedef __uint128_t __al_u128 __attribute__((aligned(1), may_alias));
#endif
typedef uint64_t __al_u64 __attribute__((aligned(1), may_alias));
typedef uint32_t __al_u32 __attribute__((aligned(1), may_alias));
typedef uint16_t __al_u16 __attribute__((aligned(1), may_alias));
static inline int __memcmp_sub(const void *a, const void *b, size_t len)
{
int ret = 0;
if (len == 2) {
if (htobe16(*(__al_u16 *)a) < htobe16(*(__al_u16 *)b))
ret = -1;
else
ret = 1;
} else if (len == 4) {
if (htobe32(*(__al_u32 *)a) < htobe32(*(__al_u32 *)b))
ret = -1;
else
ret = 1;
} else if (len == 8) {
if (htobe64(*(__al_u64 *)a) < htobe64(*(__al_u64 *)b))
ret = -1;
else
ret = 1;
} else if (len == 16) {
/*
* htobe128 doesn't exist, do htobe64 at the first diff instead.
*/
const __al_u64 *aa = a, *bb = b;
if (aa[0] == bb[0]) {
aa = &aa[1];
bb = &bb[1];
}
if (htobe64(*(__al_u64 *)aa) < htobe64(*(__al_u64 *)bb))
ret = -1;
else
ret = 1;
} else {
/* Must be unreachable. */
}
return ret;
}
#define __memcmp_t(T, AP, BP, LENP) ({ \
const void **_ap = (AP); \
const void **_bp = (BP); \
size_t *_lenp = (LENP); \
\
size_t _i, _len = *_lenp / sizeof(T); \
const T (*_a)[_len] = *_ap; \
const T (*_b)[_len] = *_bp; \
int __ret = 0; \
\
*_ap = _a + _len; \
*_bp = _b + _len; \
*_lenp = *_lenp % sizeof(T); \
\
for (_i = 0; _i < _len; _i++) { \
if ((*_a)[_i] != (*_b)[_i]) { \
__ret = __memcmp_sub(&(*_a)[_i], &(*_b)[_i], sizeof(T)); \
break; \
} \
} \
\
__ret; \
})
#endif /* #ifdef NOLIBC_ARCH_UNALIGNED_ACCESS_IS_OK */
__attribute__((__unused__))
static int my_memcmp(const void *a, const void *b, size_t len)
{
const unsigned char *aa, *bb;
int ret = 0;
size_t i;
#ifdef NOLIBC_ARCH_UNALIGNED_ACCESS_IS_OK
#ifdef NOLIBC_ARCH_HAS_U128
if (len >= sizeof(__al_u128)) {
ret = __memcmp_t(__al_u128, &a, &b, &len);
if (ret || !len)
return ret;
}
#endif
/*
* Don't do __al_u64 on a 32-bit machine, it results
* in worse code.
*/
if (sizeof(long) == 8 && len >= sizeof(__al_u64)) {
ret = __memcmp_t(__al_u64, &a, &b, &len);
if (ret || !len)
return ret;
}
if (len >= sizeof(__al_u32)) {
ret = __memcmp_t(__al_u32, &a, &b, &len);
if (ret || !len)
return ret;
}
if (len >= sizeof(__al_u16)) {
ret = __memcmp_t(__al_u16, &a, &b, &len);
if (ret || !len)
return ret;
}
#endif /* #ifdef NOLIBC_ARCH_UNALIGNED_ACCESS_IS_OK */
aa = a;
bb = b;
for (i = 0; i < len; i++) {
ret = aa[i] - bb[i];
if (ret)
return ret;
}
return ret;
}
#define ARG2 "12345678abcdefghA"
#define ARG3 16
#if 1
bool test_builtin_memcmp(void *data)
{
return !!memcmp(data, ARG2, ARG3);
}
#endif
bool test_my_memcmp(void *data)
{
return !!my_memcmp(data, ARG2, ARG3);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment