Last active
September 15, 2023 22:59
-
-
Save ammarfaizi2/648e4c956fd17d7bf7045d7559242c64 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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