From d9d5f45e2d5fe3b94133c48c46f03311ee4f3d20 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sun, 30 Jul 2023 11:05:05 -0700 Subject: [PATCH] Restore missing cosmopolitan documentation on website --- Makefile | 2 +- libc/integral/c.inc | 13 +- libc/intrin/bzero.c | 4 +- libc/intrin/memchr.c | 4 +- libc/intrin/memcmp.c | 4 +- libc/intrin/memmove.c | 4 +- libc/intrin/memrchr.c | 4 +- libc/intrin/memset.c | 7 +- libc/intrin/stpcpy.c | 2 +- libc/intrin/strchr.c | 4 +- libc/intrin/strchrnul.c | 4 +- libc/intrin/strcpy.c | 2 +- libc/intrin/strlen.c | 2 +- libc/intrin/weaken.h | 4 + libc/stdckdint.h | 652 +++++++++++++++++++++++- libc/str/bcmp.c | 6 +- libc/str/djbsort.c | 2 +- libc/str/isutf8.c | 2 +- libc/str/memmem.c | 2 +- libc/str/memrchr16.c | 4 +- libc/str/rawmemchr.c | 4 +- libc/str/strcasestr.c | 2 +- libc/str/strlen16.c | 2 +- libc/str/strstr.c | 2 +- libc/str/timingsafe_bcmp.c | 7 +- libc/str/wcslen.c | 2 +- libc/str/wcwidth.c | 2 +- libc/str/wmemrchr.c | 4 +- third_party/chibicc/README.cosmo | 1 - third_party/chibicc/chibicc.h | 2 - third_party/chibicc/chibicc.mk | 6 +- third_party/chibicc/codegen.c | 27 - third_party/chibicc/help.txt | 4 - third_party/chibicc/parse.c | 47 -- third_party/chibicc/printast.c | 1 - third_party/chibicc/test/builtin_test.c | 102 ---- 36 files changed, 715 insertions(+), 228 deletions(-) diff --git a/Makefile b/Makefile index 47519f3b5..86424d681 100644 --- a/Makefile +++ b/Makefile @@ -414,7 +414,7 @@ o/cosmopolitan.html: \ $(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS)))) o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \ -fno-common -include libc/integral/normalize.inc -o $@ \ - @$(TMPDIR)/$(subst /,_,$@) + -DCOSMO @$(TMPDIR)/$(subst /,_,$@) $(SRCS): \ libc/integral/normalize.inc \ diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 68cb18191..167c057f6 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -44,6 +44,10 @@ #endif #endif +#ifdef __chibicc__ +#define __extension__ +#endif + #if __STDC_VERSION__ + 0 < 201112 #if defined(__GNUC__) && !defined(__STRICT_ANSI__) #define _Alignas(x) __attribute__((__aligned__(x))) @@ -828,13 +832,18 @@ void abort(void) wontreturn; #define __static_yoink_source(PATH) #endif -#define __strong_reference(sym, aliassym) \ - extern __typeof(sym) aliassym __attribute__((__alias__(#sym))) #define __weak_reference(sym, alias) \ __asm__(".weak\t" #alias "\n\t" \ ".equ\t" #alias ", " #sym "\n\t" \ ".type\t" #alias ",@notype") +#ifndef __chibicc__ +#define __strong_reference(sym, alias) \ + extern __typeof(sym) alias __attribute__((__alias__(#sym))) +#else +#define __strong_reference(sym, alias) __weak_reference(sym, alias) +#endif + #define __funline \ extern __inline \ __attribute__((__gnu_inline__, __always_inline__, __artificial__)) diff --git a/libc/intrin/bzero.c b/libc/intrin/bzero.c index 3daf166f4..836813a6e 100644 --- a/libc/intrin/bzero.c +++ b/libc/intrin/bzero.c @@ -43,7 +43,7 @@ static void bzero128(char *p, size_t n) { } } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) _Microarchitecture("avx") static void bzero_avx(char *p, size_t n) { xmm_t v = {0}; if (IsAsan()) __asan_verify(p, n); @@ -154,7 +154,7 @@ void bzero(void *p, size_t n) { b[--n] = x; } while (n); } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) } else if (IsTiny()) { asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "a"(0)); return; diff --git a/libc/intrin/memchr.c b/libc/intrin/memchr.c index 16c0897fa..690680de3 100644 --- a/libc/intrin/memchr.c +++ b/libc/intrin/memchr.c @@ -35,7 +35,7 @@ static inline const unsigned char *memchr_pure(const unsigned char *s, return 0; } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) dontasan static inline const unsigned char *memchr_sse(const unsigned char *s, unsigned char c, size_t n) { @@ -71,7 +71,7 @@ dontasan static inline const unsigned char *memchr_sse(const unsigned char *s, * @asyncsignalsafe */ void *memchr(const void *s, int c, size_t n) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) const void *r; if (IsAsan()) __asan_verify(s, n); r = memchr_sse(s, c, n); diff --git a/libc/intrin/memcmp.c b/libc/intrin/memcmp.c index 7ef00b4d1..8ae2b395c 100644 --- a/libc/intrin/memcmp.c +++ b/libc/intrin/memcmp.c @@ -26,7 +26,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1))); -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) static dontinline antiquity int memcmp_sse(const unsigned char *p, const unsigned char *q, size_t n) { @@ -143,7 +143,7 @@ int memcmp(const void *a, const void *b, size_t n) { const unsigned char *p, *q; if ((p = a) == (q = b) || !n) return 0; if ((c = *p - *q)) return c; -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) if (!IsTiny()) { if (n <= 16) { if (n >= 8) { diff --git a/libc/intrin/memmove.c b/libc/intrin/memmove.c index a3a0c1018..98c3ae77c 100644 --- a/libc/intrin/memmove.c +++ b/libc/intrin/memmove.c @@ -95,7 +95,7 @@ void *memmove(void *dst, const void *src, size_t n) { d = dst; s = src; -#ifdef __x86__ +#if defined(__x86_64__) && !defined(__chibicc__) if (IsTiny()) { uint16_t w1, w2; uint32_t l1, l2; @@ -214,7 +214,7 @@ void *memmove(void *dst, const void *src, size_t n) { default: if (d == s) return d; -#ifdef __x86__ +#if defined(__x86_64__) && !defined(__chibicc__) if (n < kHalfCache3 || !kHalfCache3) { if (d > s) { if (IsAsan() || n < 900 || !X86_HAVE(ERMS)) { diff --git a/libc/intrin/memrchr.c b/libc/intrin/memrchr.c index 8e7f95714..79f07ebdc 100644 --- a/libc/intrin/memrchr.c +++ b/libc/intrin/memrchr.c @@ -35,7 +35,7 @@ static inline const unsigned char *memrchr_pure(const unsigned char *s, return 0; } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) dontasan static inline const unsigned char *memrchr_sse(const unsigned char *s, unsigned char c, size_t n) { @@ -69,7 +69,7 @@ dontasan static inline const unsigned char *memrchr_sse(const unsigned char *s, * @asyncsignalsafe */ void *memrchr(const void *s, int c, size_t n) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) const void *r; if (IsAsan()) __asan_verify(s, n); r = memrchr_sse(s, c, n); diff --git a/libc/intrin/memset.c b/libc/intrin/memset.c index f34aec2da..f4ad25edc 100644 --- a/libc/intrin/memset.c +++ b/libc/intrin/memset.c @@ -24,9 +24,9 @@ #include "libc/str/str.h" #ifndef __aarch64__ +#ifndef __chibicc__ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1))); typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16))); - static void *memset_sse(char *p, char c, size_t n) { xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c}; if (IsAsan()) __asan_verify(p, n); @@ -44,8 +44,9 @@ static void *memset_sse(char *p, char c, size_t n) { } return p; } +#endif -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) _Microarchitecture("avx") static void *memset_avx(char *p, char c, size_t n) { char *t; xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c}; @@ -158,7 +159,7 @@ void *memset(void *p, int c, size_t n) { } while (n); } return b; -#ifdef __x86__ +#if defined(__x86_64__) && !defined(__chibicc__) } else if (IsTiny()) { asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "a"(c)); return p; diff --git a/libc/intrin/stpcpy.c b/libc/intrin/stpcpy.c index 8d1fa3999..ba7b97a63 100644 --- a/libc/intrin/stpcpy.c +++ b/libc/intrin/stpcpy.c @@ -38,7 +38,7 @@ dontasan char *stpcpy(char *d, const char *s) { if (IsAsan()) { __asan_verify(d, strlen(s) + 1); } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) for (; (uintptr_t)(s + i) & 15; ++i) { if (!(d[i] = s[i])) { return d + i; diff --git a/libc/intrin/strchr.c b/libc/intrin/strchr.c index 60cc9cdd5..aa5fe133b 100644 --- a/libc/intrin/strchr.c +++ b/libc/intrin/strchr.c @@ -30,7 +30,7 @@ static inline const char *strchr_pure(const char *s, int c) { } } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); dontasan static inline const char *strchr_sse(const char *s, unsigned char c) { unsigned k; @@ -95,7 +95,7 @@ static dontasan inline const char *strchr_x64(const char *p, uint64_t c) { * @vforksafe */ char *strchr(const char *s, int c) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) const char *r; if (X86_HAVE(SSE)) { if (IsAsan()) __asan_verify(s, 1); diff --git a/libc/intrin/strchrnul.c b/libc/intrin/strchrnul.c index 7861219f6..aaca503cb 100644 --- a/libc/intrin/strchrnul.c +++ b/libc/intrin/strchrnul.c @@ -30,7 +30,7 @@ static inline const char *strchrnul_pure(const char *s, int c) { } } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); dontasan static inline const char *strchrnul_sse(const char *s, unsigned char c) { @@ -94,7 +94,7 @@ dontasan static const char *strchrnul_x64(const char *p, uint64_t c) { * NUL terminator if c is not found */ char *strchrnul(const char *s, int c) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) const char *r; if (X86_HAVE(SSE)) { if (IsAsan()) __asan_verify(s, 1); diff --git a/libc/intrin/strcpy.c b/libc/intrin/strcpy.c index 48a4a22f4..8683c3c72 100644 --- a/libc/intrin/strcpy.c +++ b/libc/intrin/strcpy.c @@ -39,7 +39,7 @@ dontasan char *strcpy(char *d, const char *s) { if (IsAsan()) { __asan_verify(d, strlen(s) + 1); } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) for (; (uintptr_t)(s + i) & 15; ++i) { if (!(d[i] = s[i])) { return d; diff --git a/libc/intrin/strlen.c b/libc/intrin/strlen.c index 0bdaa3f14..1b0f77433 100644 --- a/libc/intrin/strlen.c +++ b/libc/intrin/strlen.c @@ -30,7 +30,7 @@ */ dontasan size_t strlen(const char *s) { if (IsAsan()) __asan_verify_str(s); -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); xmm_t z = {0}; unsigned m, k = (uintptr_t)s & 15; diff --git a/libc/intrin/weaken.h b/libc/intrin/weaken.h index 765dd8fb6..44aea3e28 100644 --- a/libc/intrin/weaken.h +++ b/libc/intrin/weaken.h @@ -2,11 +2,15 @@ #define COSMOPOLITAN_LIBC_BITS_WEAKEN_H_ #if !(__ASSEMBLER__ + __LINKER__ + 0) +#ifndef __chibicc__ #define _weaken(symbol) \ __extension__({ \ extern __typeof__(symbol) symbol __attribute__((__weak__)); \ &symbol; \ }) +#else +#define _weaken(symbol) (&(symbol)) +#endif #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_BITS_WEAKEN_H_ */ diff --git a/libc/stdckdint.h b/libc/stdckdint.h index eacc77187..c40f9348c 100644 --- a/libc/stdckdint.h +++ b/libc/stdckdint.h @@ -1,10 +1,656 @@ -#ifndef COSMOPOLITAN_LIBC_STDCKDINT_H_ -#define COSMOPOLITAN_LIBC_STDCKDINT_H_ +/* + * Copyright 2023 Justine Alexandra Roberts Tunney + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @fileoverview C23 Checked Arithmetic + * + * This header defines three type generic functions: + * + * - `bool ckd_add(res, a, b)` + * - `bool ckd_sub(res, a, b)` + * - `bool ckd_mul(res, a, b)` + * + * Which allow integer arithmetic errors to be detected. There are many + * kinds of integer errors, e.g. overflow, truncation, etc. These funcs + * catch them all. Here's an example of how it works: + * + * uint32_t c; + * int32_t a = 0x7fffffff; + * int32_t b = 2; + * assert(!ckd_add(&c, a, b)); + * assert(c == 0x80000001u); + * + * Experienced C / C++ users should find this example counter-intuitive + * because the expression `0x7fffffff + 2` not only overflows it's also + * undefined behavior. However here we see it's specified, and does not + * result in an error. That's because C23 checked arithmetic is not the + * arithmetic you're used to. The new standard changes the mathematics. + * + * C23 checked arithmetic is defined as performing the arithmetic using + * infinite precision and then checking if the resulting value will fit + * in the output type. Our example above did not result in an error due + * to `0x80000001` being a legal value for `uint32_t`. + * + * This implementation will use the GNU compiler builtins, when they're + * available, only if you don't use build flags like `-std=c11` because + * they define `__STRICT_ANSI__` and GCC extensions aren't really ANSI. + * Instead, you'll get a pretty good pure C11 and C++11 implementation. + * + * @see https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf + * @version 0.1 (2023-07-22) + */ + +#ifndef JTCKDINT_H_ +#define JTCKDINT_H_ +/* clang-format off */ + +#ifdef __has_include +#define __ckd_has_include(x) __has_include(x) +#else +#define __ckd_has_include(x) 0 +#endif #define __STDC_VERSION_STDCKDINT_H__ 202311L +#if ((defined(__llvm__) || \ + (defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 406)) && \ + !defined(__STRICT_ANSI__)) +#define __ckd_have_int128 +#define __ckd_intmax __int128 +#elif ((defined(__cplusplus) && __cplusplus >= 201103L) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define __ckd_intmax long long +#else +#define __ckd_intmax long +#endif + +typedef signed __ckd_intmax __ckd_intmax_t; +typedef unsigned __ckd_intmax __ckd_uintmax_t; + +#ifdef __has_builtin +#define __ckd_has_builtin(x) __has_builtin(x) +#else +#define __ckd_has_builtin(x) 0 +#endif + +#if (!defined(__STRICT_ANSI__) && \ + ((defined(__GNUC__) && __GNUC__ >= 5 && \ + !defined(__chibicc__) && !defined(__ICC)) || \ + (__ckd_has_builtin(__builtin_add_overflow) && \ + __ckd_has_builtin(__builtin_sub_overflow) && \ + __ckd_has_builtin(__builtin_mul_overflow)))) #define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res)) #define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res)) #define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res)) -#endif /* COSMOPOLITAN_LIBC_STDCKDINT_H_ */ +#elif defined(__cplusplus) && __cplusplus >= 201103L +#include "third_party/libcxx/type_traits" +#include "third_party/libcxx/limits" + +template +inline bool ckd_add(__T *__res, __U __a, __V __b) { + static_assert(std::is_integral<__T>::value && + std::is_integral<__U>::value && + std::is_integral<__V>::value, + "non-integral types not allowed"); + static_assert(!std::is_same<__T, bool>::value && + !std::is_same<__U, bool>::value && + !std::is_same<__V, bool>::value, + "checked booleans not supported"); + static_assert(!std::is_same<__T, char>::value && + !std::is_same<__U, char>::value && + !std::is_same<__V, char>::value, + "unqualified char type is ambiguous"); + __ckd_uintmax_t __x = __a; + __ckd_uintmax_t __y = __b; + __ckd_uintmax_t __z = __x + __y; + *__res = __z; + if (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) { + if (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) { + return static_cast<__ckd_intmax_t>(__z) != static_cast<__T>(__z); + } else if (!std::is_same<__T, __ckd_uintmax_t>::value) { + return (__z != static_cast<__T>(__z) || + ((std::is_signed<__U>::value || + std::is_signed<__V>::value) && + static_cast<__ckd_intmax_t>(__z) < 0)); + } + } + bool __truncated = false; + if (sizeof(__T) < sizeof(__ckd_intmax_t)) { + __truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z)); + } + switch (std::is_signed<__T>::value << 2 | // + std::is_signed<__U>::value << 1 | // + std::is_signed<__V>::value) { + case 0: // u = u + u + return __truncated | (__z < __x); + case 1: // u = u + s + __y ^= std::numeric_limits<__ckd_intmax_t>::min(); + return __truncated | + (static_cast<__ckd_intmax_t>((__z ^ __x) & + (__z ^ __y)) < 0); + case 2: // u = s + u + __x ^= std::numeric_limits<__ckd_intmax_t>::min(); + return __truncated | + (static_cast<__ckd_intmax_t>((__z ^ __x) & + (__z ^ __y)) < 0); + case 3: // u = s + s + return __truncated | + (static_cast<__ckd_intmax_t>(((__z | __x) & __y) | + ((__z & __x) & ~__y)) < 0); + case 4: // s = u + u + return __truncated | (__z < __x) | (static_cast<__ckd_intmax_t>(__z) < 0); + case 5: // s = u + s + __y ^= std::numeric_limits<__ckd_intmax_t>::min(); + return __truncated | (__x + __y < __y); + case 6: // s = s + u + __x ^= std::numeric_limits<__ckd_intmax_t>::min(); + return __truncated | (__x + __y < __x); + case 7: // s = s + s + return __truncated | + (static_cast<__ckd_intmax_t>((__z ^ __x) & + (__z ^ __y)) < 0); + default: + for (;;) (void)0; + } +} + +template +inline bool ckd_sub(__T *__res, __U __a, __V __b) { + static_assert(std::is_integral<__T>::value && + std::is_integral<__U>::value && + std::is_integral<__V>::value, + "non-integral types not allowed"); + static_assert(!std::is_same<__T, bool>::value && + !std::is_same<__U, bool>::value && + !std::is_same<__V, bool>::value, + "checked booleans not supported"); + static_assert(!std::is_same<__T, char>::value && + !std::is_same<__U, char>::value && + !std::is_same<__V, char>::value, + "unqualified char type is ambiguous"); + __ckd_uintmax_t __x = __a; + __ckd_uintmax_t __y = __b; + __ckd_uintmax_t __z = __x - __y; + *__res = __z; + if (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) { + if (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) { + return static_cast<__ckd_intmax_t>(__z) != static_cast<__T>(__z); + } else if (!std::is_same<__T, __ckd_uintmax_t>::value) { + return (__z != static_cast<__T>(__z) || + ((std::is_signed<__U>::value || + std::is_signed<__V>::value) && + static_cast<__ckd_intmax_t>(__z) < 0)); + } + } + bool __truncated = false; + if (sizeof(__T) < sizeof(__ckd_intmax_t)) { + __truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z)); + } + switch (std::is_signed<__T>::value << 2 | // + std::is_signed<__U>::value << 1 | // + std::is_signed<__V>::value) { + case 0: // u = u - u + return __truncated | (__x < __y); + case 1: // u = u - s + __y ^= std::numeric_limits<__ckd_intmax_t>::min(); + return __truncated | + (static_cast<__ckd_intmax_t>((__x ^ __y) & + (__z ^ __x)) < 0); + case 2: // u = s - u + return __truncated | (__y > __x) | (static_cast<__ckd_intmax_t>(__x) < 0); + case 3: // u = s - s + return __truncated | + (static_cast<__ckd_intmax_t>(((__z & __x) & __y) | + ((__z | __x) & ~__y)) < 0); + case 4: // s = u - u + return __truncated | + ((__x < __y) ^ (static_cast<__ckd_intmax_t>(__z) < 0)); + case 5: // s = u - s + __y ^= std::numeric_limits<__ckd_intmax_t>::min(); + return __truncated | (__x >= __y); + case 6: // s = s - u + __x ^= std::numeric_limits<__ckd_intmax_t>::min(); + return __truncated | (__x < __y); + case 7: // s = s - s + return __truncated | + (static_cast<__ckd_intmax_t>((__x ^ __y) & + (__z ^ __x)) < 0); + default: + for (;;) (void)0; + } +} + +template +inline bool ckd_mul(__T *__res, __U __a, __V __b) { + static_assert(std::is_integral<__T>::value && + std::is_integral<__U>::value && + std::is_integral<__V>::value, + "non-integral types not allowed"); + static_assert(!std::is_same<__T, bool>::value && + !std::is_same<__U, bool>::value && + !std::is_same<__V, bool>::value, + "checked booleans not supported"); + static_assert(!std::is_same<__T, char>::value && + !std::is_same<__U, char>::value && + !std::is_same<__V, char>::value, + "unqualified char type is ambiguous"); + __ckd_uintmax_t __x = __a; + __ckd_uintmax_t __y = __b; + if ((sizeof(__U) * 8 - std::is_signed<__U>::value) + + (sizeof(__V) * 8 - std::is_signed<__V>::value) <= + (sizeof(__T) * 8 - std::is_signed<__T>::value)) { + if (sizeof(__ckd_uintmax_t) > sizeof(__T) || std::is_signed<__T>::value) { + __ckd_intmax_t __z = __x * __y; + return __z != (*__res = __z); + } else if (!std::is_same<__T, __ckd_uintmax_t>::value) { + __ckd_uintmax_t __z = __x * __y; + *__res = __z; + return (__z != static_cast<__T>(__z) || + ((std::is_signed<__U>::value || + std::is_signed<__V>::value) && + static_cast<__ckd_intmax_t>(__z) < 0)); + } + } + switch (std::is_signed<__T>::value << 2 | // + std::is_signed<__U>::value << 1 | // + std::is_signed<__V>::value) { + case 0: { // u = u * u + __ckd_uintmax_t __z = __x * __y; + int __o = __x && __z / __x != __y; + *__res = __z; + return __o | (sizeof(__T) < sizeof(__z) && + __z != static_cast<__ckd_uintmax_t>(*__res)); + } + case 1: { // u = u * s + __ckd_uintmax_t __z = __x * __y; + int __o = __x && __z / __x != __y; + *__res = __z; + return (__o | ((static_cast<__ckd_intmax_t>(__y) < 0) & !!__x) | + (sizeof(__T) < sizeof(__z) && + __z != static_cast<__ckd_uintmax_t>(*__res))); + } + case 2: { // u = s * u + __ckd_uintmax_t __z = __x * __y; + int __o = __x && __z / __x != __y; + *__res = __z; + return (__o | ((static_cast<__ckd_intmax_t>(__x) < 0) & !!__y) | + (sizeof(__T) < sizeof(__z) && + __z != static_cast<__ckd_uintmax_t>(*__res))); + } + case 3: { // u = s * s + int __o = false; + if (static_cast<__ckd_intmax_t>(__x & __y) < 0) { + __x = -__x; + __y = -__y; + } else if (static_cast<__ckd_intmax_t>(__x ^ __y) < 0) { + __o = __x && __y; + } + __ckd_uintmax_t __z = __x * __y; + __o |= __x && __z / __x != __y; + *__res = __z; + return __o | (sizeof(__T) < sizeof(__z) && + __z != static_cast<__ckd_uintmax_t>(*__res)); + } + case 4: { // s = u * u + __ckd_uintmax_t __z = __x * __y; + int __o = __x && __z / __x != __y; + *__res = __z; + return (__o | (static_cast<__ckd_intmax_t>(__z) < 0) | + (sizeof(__T) < sizeof(__z) && + __z != static_cast<__ckd_uintmax_t>(*__res))); + } + case 5: { // s = u * s + __ckd_uintmax_t __t = -__y; + __t = static_cast<__ckd_intmax_t>(__t) < 0 ? __y : __t; + __ckd_uintmax_t __p = __t * __x; + int __o = __t && __p / __t != __x; + int __n = static_cast<__ckd_intmax_t>(__y) < 0; + __ckd_uintmax_t __z = __n ? -__p : __p; + *__res = __z; + __ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max(); + return (__o | (__p > __m + __n) | + (sizeof(__T) < sizeof(__z) && + __z != static_cast<__ckd_uintmax_t>(*__res))); + } + case 6: { // s = s * u + __ckd_uintmax_t __t = -__x; + __t = static_cast<__ckd_intmax_t>(__t) < 0 ? __x : __t; + __ckd_uintmax_t __p = __t * __y; + int __o = __t && __p / __t != __y; + int __n = static_cast<__ckd_intmax_t>(__x) < 0; + __ckd_uintmax_t __z = __n ? -__p : __p; + *__res = __z; + __ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max(); + return (__o | (__p > __m + __n) | + (sizeof(__T) < sizeof(__z) && + __z != static_cast<__ckd_uintmax_t>(*__res))); + } + case 7: { // s = s * s + __ckd_uintmax_t __z = __x * __y; + *__res = __z; + return ((((static_cast<__ckd_intmax_t>(__y) < 0) && + (static_cast<__ckd_intmax_t>(__x) == + std::numeric_limits<__ckd_intmax_t>::min())) || + (__y && ((static_cast<__ckd_intmax_t>(__z) / + static_cast<__ckd_intmax_t>(__y)) != + static_cast<__ckd_intmax_t>(__x)))) | + (sizeof(__T) < sizeof(__z) && + __z != static_cast<__ckd_uintmax_t>(*__res))); + } + default: + for (;;) (void)0; + } +} + +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + +#define ckd_add(res, a, b) __ckd_expr(add, (res), (a), (b)) +#define ckd_sub(res, a, b) __ckd_expr(sub, (res), (a), (b)) +#define ckd_mul(res, a, b) __ckd_expr(mul, (res), (a), (b)) + +#if defined(__GNUC__) || defined(__llvm__) +#define __ckd_inline \ + extern __inline __attribute__((__gnu_inline__, \ + __always_inline__, \ + __artificial__)) +#else +#define __ckd_inline static inline +#endif + +#ifdef __ckd_have_int128 +#define __ckd_generic_int128(x, y) , signed __int128: x, unsigned __int128: y +#else +#define __ckd_generic_int128(x, y) +#endif + +#define __ckd_sign(T) \ + ((T)1 << (sizeof(T) * 8 - 1)) + +#define __ckd_is_signed(x) \ + _Generic(x, \ + signed char: 1, \ + unsigned char: 0, \ + signed short: 1, \ + unsigned short: 0, \ + signed int: 1, \ + unsigned int: 0, \ + signed long: 1, \ + unsigned long: 0, \ + signed long long: 1, \ + unsigned long long: 0 \ + __ckd_generic_int128(1, 0)) + +#define __ckd_expr(op, res, a, b) \ + (_Generic(*res, \ + signed char: __ckd_##op##_schar, \ + unsigned char: __ckd_##op##_uchar, \ + signed short: __ckd_##op##_sshort, \ + unsigned short: __ckd_##op##_ushort, \ + signed int: __ckd_##op##_sint, \ + unsigned int: __ckd_##op##_uint, \ + signed long: __ckd_##op##_slong, \ + unsigned long: __ckd_##op##_ulong, \ + signed long long: __ckd_##op##_slonger, \ + unsigned long long: __ckd_##op##_ulonger \ + __ckd_generic_int128( \ + __ckd_##op##_sint128, \ + __ckd_##op##_uint128))( \ + res, a, b, \ + __ckd_is_signed(a), \ + __ckd_is_signed(b))) + +#define __ckd_declare_add(S, T) \ + __ckd_inline char S(void *__res, \ + __ckd_uintmax_t __x, \ + __ckd_uintmax_t __y, \ + char __a_signed, \ + char __b_signed) { \ + __ckd_uintmax_t __z = __x + __y; \ + *(T *)__res = __z; \ + char __truncated = 0; \ + if (sizeof(T) < sizeof(__ckd_intmax_t)) { \ + __truncated = __z != (__ckd_uintmax_t)(T)__z; \ + } \ + switch (__ckd_is_signed((T)0) << 2 | \ + __a_signed << 1 | __b_signed) { \ + case 0: /* u = u + u */ \ + return __truncated | (__z < __x); \ + case 1: /* u = u + s */ \ + __y ^= __ckd_sign(__ckd_uintmax_t); \ + return __truncated | \ + ((__ckd_intmax_t)((__z ^ __x) & \ + (__z ^ __y)) < 0); \ + case 2: /* u = s + u */ \ + __x ^= __ckd_sign(__ckd_uintmax_t); \ + return __truncated | \ + ((__ckd_intmax_t)((__z ^ __x) & \ + (__z ^ __y)) < 0); \ + case 3: /* u = s + s */ \ + return __truncated | \ + ((__ckd_intmax_t)(((__z | __x) & __y) | \ + ((__z & __x) & ~__y)) < 0); \ + case 4: /* s = u + u */ \ + return __truncated | (__z < __x) | ((__ckd_intmax_t)__z < 0); \ + case 5: /* s = u + s */ \ + __y ^= __ckd_sign(__ckd_uintmax_t); \ + return __truncated | (__x + __y < __y); \ + case 6: /* s = s + u */ \ + __x ^= __ckd_sign(__ckd_uintmax_t); \ + return __truncated | (__x + __y < __x); \ + case 7: /* s = s + s */ \ + return __truncated | \ + ((__ckd_intmax_t)((__z ^ __x) & \ + (__z ^ __y)) < 0); \ + default: \ + for (;;) (void)0; \ + } \ + } + +__ckd_declare_add(__ckd_add_schar, signed char) +__ckd_declare_add(__ckd_add_uchar, unsigned char) +__ckd_declare_add(__ckd_add_sshort, signed short) +__ckd_declare_add(__ckd_add_ushort, unsigned short) +__ckd_declare_add(__ckd_add_sint, signed int) +__ckd_declare_add(__ckd_add_uint, unsigned int) +__ckd_declare_add(__ckd_add_slong, signed long) +__ckd_declare_add(__ckd_add_ulong, unsigned long) +__ckd_declare_add(__ckd_add_slonger, signed long long) +__ckd_declare_add(__ckd_add_ulonger, unsigned long long) +#ifdef __ckd_have_int128 +__ckd_declare_add(__ckd_add_sint128, signed __int128) +__ckd_declare_add(__ckd_add_uint128, unsigned __int128) +#endif + +#define __ckd_declare_sub(S, T) \ + __ckd_inline char S(void *__res, \ + __ckd_uintmax_t __x, \ + __ckd_uintmax_t __y, \ + char __a_signed, \ + char __b_signed) { \ + __ckd_uintmax_t __z = __x - __y; \ + *(T *)__res = __z; \ + char __truncated = 0; \ + if (sizeof(T) < sizeof(__ckd_intmax_t)) { \ + __truncated = __z != (__ckd_uintmax_t)(T)__z; \ + } \ + switch (__ckd_is_signed((T)0) << 2 | \ + __a_signed << 1 | __b_signed) { \ + case 0: /* u = u - u */ \ + return __truncated | (__x < __y); \ + case 1: /* u = u - s */ \ + __y ^= __ckd_sign(__ckd_uintmax_t); \ + return __truncated | \ + ((__ckd_intmax_t)((__x ^ __y) & \ + (__z ^ __x)) < 0); \ + case 2: /* u = s - u */ \ + return __truncated | (__y > __x) | ((__ckd_intmax_t)__x < 0); \ + case 3: /* u = s - s */ \ + return __truncated | \ + ((__ckd_intmax_t)(((__z & __x) & __y) | \ + ((__z | __x) & ~__y)) < 0); \ + case 4: /* s = u - u */ \ + return __truncated | ((__x < __y) ^ ((__ckd_intmax_t)__z < 0)); \ + case 5: /* s = u - s */ \ + __y ^= __ckd_sign(__ckd_uintmax_t); \ + return __truncated | (__x >= __y); \ + case 6: /* s = s - u */ \ + __x ^= __ckd_sign(__ckd_uintmax_t); \ + return __truncated | (__x < __y); \ + case 7: /* s = s - s */ \ + return __truncated | \ + ((__ckd_intmax_t)((__x ^ __y) & \ + (__z ^ __x)) < 0); \ + default: \ + for (;;) (void)0; \ + } \ + } + +__ckd_declare_sub(__ckd_sub_schar, signed char) +__ckd_declare_sub(__ckd_sub_uchar, unsigned char) +__ckd_declare_sub(__ckd_sub_sshort, signed short) +__ckd_declare_sub(__ckd_sub_ushort, unsigned short) +__ckd_declare_sub(__ckd_sub_sint, signed int) +__ckd_declare_sub(__ckd_sub_uint, unsigned int) +__ckd_declare_sub(__ckd_sub_slong, signed long) +__ckd_declare_sub(__ckd_sub_ulong, unsigned long) +__ckd_declare_sub(__ckd_sub_slonger, signed long long) +__ckd_declare_sub(__ckd_sub_ulonger, unsigned long long) +#ifdef __ckd_have_int128 +__ckd_declare_sub(__ckd_sub_sint128, signed __int128) +__ckd_declare_sub(__ckd_sub_uint128, unsigned __int128) +#endif + +#define __ckd_declare_mul(S, T) \ + __ckd_inline char S(void *__res, \ + __ckd_uintmax_t __x, \ + __ckd_uintmax_t __y, \ + char __a_signed, \ + char __b_signed) { \ + switch (__ckd_is_signed((T)0) << 2 | \ + __a_signed << 1 | __b_signed) { \ + case 0: { /* u = u * u */ \ + __ckd_uintmax_t __z = __x * __y; \ + int __o = __x && __z / __x != __y; \ + *(T *)__res = __z; \ + return __o | (sizeof(T) < sizeof(__z) && \ + __z != (__ckd_uintmax_t)*(T *)__res); \ + } \ + case 1: { /* u = u * s */ \ + __ckd_uintmax_t __z = __x * __y; \ + int __o = __x && __z / __x != __y; \ + *(T *)__res = __z; \ + return (__o | (((__ckd_intmax_t)__y < 0) & !!__x) | \ + (sizeof(T) < sizeof(__z) && \ + __z != (__ckd_uintmax_t)*(T *)__res)); \ + } \ + case 2: { /* u = s * u */ \ + __ckd_uintmax_t __z = __x * __y; \ + int __o = __x && __z / __x != __y; \ + *(T *)__res = __z; \ + return (__o | (((__ckd_intmax_t)__x < 0) & !!__y) | \ + (sizeof(T) < sizeof(__z) && \ + __z != (__ckd_uintmax_t)*(T *)__res)); \ + } \ + case 3: { /* u = s * s */ \ + int __o = 0; \ + if ((__ckd_intmax_t)(__x & __y) < 0) { \ + __x = -__x; \ + __y = -__y; \ + } else if ((__ckd_intmax_t)(__x ^ __y) < 0) { \ + __o = __x && __y; \ + } \ + __ckd_uintmax_t __z = __x * __y; \ + __o |= __x && __z / __x != __y; \ + *(T *)__res = __z; \ + return __o | (sizeof(T) < sizeof(__z) && \ + __z != (__ckd_uintmax_t)*(T *)__res); \ + } \ + case 4: { /* s = u * u */ \ + __ckd_uintmax_t __z = __x * __y; \ + int __o = __x && __z / __x != __y; \ + *(T *)__res = __z; \ + return (__o | ((__ckd_intmax_t)(__z) < 0) | \ + (sizeof(T) < sizeof(__z) && \ + __z != (__ckd_uintmax_t)*(T *)__res)); \ + } \ + case 5: { /* s = u * s */ \ + __ckd_uintmax_t __t = -__y; \ + __t = (__ckd_intmax_t)(__t) < 0 ? __y : __t; \ + __ckd_uintmax_t __p = __t * __x; \ + int __o = __t && __p / __t != __x; \ + int __n = (__ckd_intmax_t)__y < 0; \ + __ckd_uintmax_t __z = __n ? -__p : __p; \ + *(T *)__res = __z; \ + __ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \ + return (__o | (__p > __m + __n) | \ + (sizeof(T) < sizeof(__z) && \ + __z != (__ckd_uintmax_t)*(T *)__res)); \ + } \ + case 6: { /* s = s * u */ \ + __ckd_uintmax_t __t = -__x; \ + __t = (__ckd_intmax_t)(__t) < 0 ? __x : __t; \ + __ckd_uintmax_t __p = __t * __y; \ + int __o = __t && __p / __t != __y; \ + int __n = (__ckd_intmax_t)__x < 0; \ + __ckd_uintmax_t __z = __n ? -__p : __p; \ + *(T *)__res = __z; \ + __ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \ + return (__o | (__p > __m + __n) | \ + (sizeof(T) < sizeof(__z) && \ + __z != (__ckd_uintmax_t)*(T *)__res)); \ + } \ + case 7: { /* s = s * s */ \ + __ckd_uintmax_t __z = __x * __y; \ + *(T *)__res = __z; \ + return (((((__ckd_intmax_t)__y < 0) && \ + (__x == __ckd_sign(__ckd_uintmax_t))) || \ + (__y && (((__ckd_intmax_t)__z / \ + (__ckd_intmax_t)__y) != \ + (__ckd_intmax_t)__x))) | \ + (sizeof(T) < sizeof(__z) && \ + __z != (__ckd_uintmax_t)*(T *)__res)); \ + } \ + default: \ + for (;;) (void)0; \ + } \ + } + +__ckd_declare_mul(__ckd_mul_schar, signed char) +__ckd_declare_mul(__ckd_mul_uchar, unsigned char) +__ckd_declare_mul(__ckd_mul_sshort, signed short) +__ckd_declare_mul(__ckd_mul_ushort, unsigned short) +__ckd_declare_mul(__ckd_mul_sint, signed int) +__ckd_declare_mul(__ckd_mul_uint, unsigned int) +__ckd_declare_mul(__ckd_mul_slong, signed long) +__ckd_declare_mul(__ckd_mul_ulong, unsigned long) +__ckd_declare_mul(__ckd_mul_slonger, signed long long) +__ckd_declare_mul(__ckd_mul_ulonger, unsigned long long) +#ifdef __ckd_have_int128 +__ckd_declare_mul(__ckd_mul_sint128, signed __int128) +__ckd_declare_mul(__ckd_mul_uint128, unsigned __int128) +#endif + +#else +#pragma message "checked integer arithmetic unsupported in this environment" + +#define ckd_add(res, x, y) (*(res) = (x) + (y), 0) +#define ckd_sub(res, x, y) (*(res) = (x) - (y), 0) +#define ckd_mul(res, x, y) (*(res) = (x) * (y), 0) + +#endif /* GNU */ +#endif /* JTCKDINT_H_ */ diff --git a/libc/str/bcmp.c b/libc/str/bcmp.c index 0f29a1eb9..3bfabb7f2 100644 --- a/libc/str/bcmp.c +++ b/libc/str/bcmp.c @@ -23,6 +23,7 @@ typedef uint64_t xmm_t __attribute__((__vector_size__(16), __aligned__(1))); +#if !defined(__chibicc__) static int bcmp_sse(const char *p, const char *q, size_t n) { xmm_t a; while (n > 32) { @@ -36,8 +37,9 @@ static int bcmp_sse(const char *p, const char *q, size_t n) { *(const xmm_t *)(p + n - 16) ^ *(const xmm_t *)(q + n - 16); return !!(a[0] | a[1]); } +#endif -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) _Microarchitecture("avx") static int bcmp_avx(const char *p, const char *q, size_t n) { xmm_t a, b, c, d; @@ -123,12 +125,14 @@ int bcmp(const void *a, const void *b, size_t n) { __builtin_memcpy(&j, q + n - 4, 4); return !!(i ^ j); } +#ifndef __chibicc__ #ifdef __x86_64__ } else if (LIKELY(X86_HAVE(AVX))) { return bcmp_avx(p, q, n); #endif } else { return bcmp_sse(p, q, n); +#endif } } while (n--) { diff --git a/libc/str/djbsort.c b/libc/str/djbsort.c index b4b58e811..b4452af54 100644 --- a/libc/str/djbsort.c +++ b/libc/str/djbsort.c @@ -34,7 +34,7 @@ void djbsort(int32_t *a, size_t n) { __asan_verify(a, m); } if (n > 1) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) if (X86_HAVE(AVX2)) { djbsort_avx2(a, n); } else { diff --git a/libc/str/isutf8.c b/libc/str/isutf8.c index 28b84e58a..446a07093 100644 --- a/libc/str/isutf8.c +++ b/libc/str/isutf8.c @@ -60,7 +60,7 @@ dontasan bool _isutf8(const void *data, size_t size) { p = data; e = p + size; while (p < e) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) if (!((intptr_t)p & 15)) { for (;;) { if ((m = __builtin_ia32_pmovmskb128(*(xmm_t *)p >= (xmm_t){0}) ^ diff --git a/libc/str/memmem.c b/libc/str/memmem.c index c597ef79c..aa2d63703 100644 --- a/libc/str/memmem.c +++ b/libc/str/memmem.c @@ -34,7 +34,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); */ dontasan void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) char c; xmm_t n, *v; unsigned i, k, m; diff --git a/libc/str/memrchr16.c b/libc/str/memrchr16.c index 4d52aff18..654190f99 100644 --- a/libc/str/memrchr16.c +++ b/libc/str/memrchr16.c @@ -34,7 +34,7 @@ static inline const char16_t *memrchr16_pure(const char16_t *s, char16_t c, return 0; } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) dontasan static inline const char16_t *memrchr16_sse(const char16_t *s, char16_t c, size_t n) { size_t i; @@ -67,7 +67,7 @@ dontasan static inline const char16_t *memrchr16_sse(const char16_t *s, * @asyncsignalsafe */ void *memrchr16(const void *s, int c, size_t n) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) const void *r; if (!IsTiny() && X86_HAVE(SSE)) { if (IsAsan()) __asan_verify(s, n * 2); diff --git a/libc/str/rawmemchr.c b/libc/str/rawmemchr.c index 271c355b8..3d4f806d8 100644 --- a/libc/str/rawmemchr.c +++ b/libc/str/rawmemchr.c @@ -31,7 +31,7 @@ static inline const unsigned char *rawmemchr_pure(const unsigned char *s, } } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); dontasan static inline const char *rawmemchr_sse(const char *s, unsigned char c) { @@ -68,7 +68,7 @@ static inline dontasan uint64_t UncheckedAlignedRead64(unsigned char *p) { * @return is pointer to first instance of c */ void *rawmemchr(const void *s, int c) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) const void *r; if (X86_HAVE(SSE)) { if (IsAsan()) __asan_verify(s, 1); diff --git a/libc/str/strcasestr.c b/libc/str/strcasestr.c index 15b0666b2..bac10770b 100644 --- a/libc/str/strcasestr.c +++ b/libc/str/strcasestr.c @@ -36,7 +36,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); * @see strstr() */ dontasan char *strcasestr(const char *haystack, const char *needle) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) char c; xmm_t *p; size_t i; diff --git a/libc/str/strlen16.c b/libc/str/strlen16.c index 2fb5ab89e..8acc5ad5d 100644 --- a/libc/str/strlen16.c +++ b/libc/str/strlen16.c @@ -30,7 +30,7 @@ typedef char16_t xmm_t __attribute__((__vector_size__(16), __aligned__(16))); * @asyncsignalsafe */ dontasan size_t strlen16(const char16_t *s) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) size_t n; xmm_t z = {0}; unsigned m, k = (uintptr_t)s & 15; diff --git a/libc/str/strstr.c b/libc/str/strstr.c index 19cb585a0..e15b2a7e5 100644 --- a/libc/str/strstr.c +++ b/libc/str/strstr.c @@ -36,7 +36,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); * @see memmem() */ dontasan char *strstr(const char *haystack, const char *needle) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) xmm_t *p; size_t i; unsigned k, m; diff --git a/libc/str/timingsafe_bcmp.c b/libc/str/timingsafe_bcmp.c index 82e54b5ea..38b88d9bc 100644 --- a/libc/str/timingsafe_bcmp.c +++ b/libc/str/timingsafe_bcmp.c @@ -22,8 +22,8 @@ #include "libc/nexgen32e/x86feature.h" #include "libc/str/str.h" +#ifndef __chibicc__ typedef uint64_t xmm_t __attribute__((__vector_size__(16), __aligned__(1))); - dontasan static unsigned timingsafe_bcmp_sse(const char *p, const char *q, size_t n) { uint64_t w; @@ -39,8 +39,9 @@ dontasan static unsigned timingsafe_bcmp_sse(const char *p, const char *q, w = a[0] | a[1]; return w | w >> 32; } +#endif -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) dontasan static _Microarchitecture("avx") int timingsafe_bcmp_avx(const char *p, const char *q, size_t n) { @@ -141,12 +142,14 @@ int timingsafe_bcmp(const void *a, const void *b, size_t n) { __asan_verify(a, n); __asan_verify(b, n); } +#ifndef __chibicc__ #ifdef __x86_64__ if (X86_HAVE(AVX)) { return timingsafe_bcmp_avx(p, q, n); } #endif return timingsafe_bcmp_sse(p, q, n); +#endif } } else if (n >= 4) { __builtin_memcpy(&u0, p, 4); diff --git a/libc/str/wcslen.c b/libc/str/wcslen.c index ecea304cf..57aa11e40 100644 --- a/libc/str/wcslen.c +++ b/libc/str/wcslen.c @@ -30,7 +30,7 @@ typedef wchar_t xmm_t __attribute__((__vector_size__(16), __aligned__(16))); * @asyncsignalsafe */ dontasan size_t wcslen(const wchar_t *s) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) size_t n; xmm_t z = {0}; unsigned m, k = (uintptr_t)s & 15; diff --git a/libc/str/wcwidth.c b/libc/str/wcwidth.c index 1de16ac99..ed182f991 100644 --- a/libc/str/wcwidth.c +++ b/libc/str/wcwidth.c @@ -30,7 +30,7 @@ extern const uint32_t kCombiningCharsBits; * Returns cell width of monospace character. */ int wcwidth(wchar_t c) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) if (LIKELY(32 <= c && c < 127)) { return 1; } else if (!c) { diff --git a/libc/str/wmemrchr.c b/libc/str/wmemrchr.c index ab9805c6e..d8f2567ac 100644 --- a/libc/str/wmemrchr.c +++ b/libc/str/wmemrchr.c @@ -35,7 +35,7 @@ static inline const wchar_t *wmemrchr_pure(const wchar_t *s, wchar_t c, return 0; } -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) dontasan static inline const wchar_t *wmemrchr_sse(const wchar_t *s, wchar_t c, size_t n) { size_t i; @@ -68,7 +68,7 @@ dontasan static inline const wchar_t *wmemrchr_sse(const wchar_t *s, wchar_t c, * @asyncsignalsafe */ void *wmemrchr(const wchar_t *s, wchar_t c, size_t n) { -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__chibicc__) size_t bytes; const void *r; if (IsAsan()) { diff --git a/third_party/chibicc/README.cosmo b/third_party/chibicc/README.cosmo index 7c8d7c738..c6eadd9d3 100644 --- a/third_party/chibicc/README.cosmo +++ b/third_party/chibicc/README.cosmo @@ -12,7 +12,6 @@ local enhancements - support __int128 - support _Static_assert - support __vector_size__ -- support __builtin_add_overflow, etc. - support GCC C11 __atomic_* primitives - support __builtin_memcpy, strlen, strpbrk, etc. - support __builtin_constant_p, __builtin_likely, etc. diff --git a/third_party/chibicc/chibicc.h b/third_party/chibicc/chibicc.h index 56b9362e5..300cd74e4 100644 --- a/third_party/chibicc/chibicc.h +++ b/third_party/chibicc/chibicc.h @@ -410,8 +410,6 @@ struct Node { Node *atomic_expr; // Variable Obj *var; - // Arithmetic - Node *overflow; // Numeric literal int64_t val; long double fval; diff --git a/third_party/chibicc/chibicc.mk b/third_party/chibicc/chibicc.mk index 524a71fbd..9e4c02091 100644 --- a/third_party/chibicc/chibicc.mk +++ b/third_party/chibicc/chibicc.mk @@ -19,6 +19,10 @@ CHIBICC_FLAGS = \ -DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) \ -DMODE='"$(MODE)"' +o/$(MODE)/%.chibicc.o: private .UNSANDBOXED = true +o/$(MODE)/%.chibicc.o: %.c $(CHIBICC) + @$(COMPILE) $(CHIBICC) $(OBJECTIFY.c.flags) -c $< $(OUTPUT_OPTION) + PKGS += THIRD_PARTY_CHIBICC THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A THIRD_PARTY_CHIBICC = $(THIRD_PARTY_CHIBICC_A_DEPS) $(THIRD_PARTY_CHIBICC_A) @@ -101,7 +105,7 @@ o/$(MODE)/third_party/chibicc/as.com.dbg: \ @$(APELINK) o/$(MODE)/third_party/chibicc/chibicc.o: private \ - CPPFLAGS += $(THIRD_PARTY_CHIBICC_DEFINES ) + CPPFLAGS += $(THIRD_PARTY_CHIBICC_DEFINES) THIRD_PARTY_CHIBICC_LIBS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x))) THIRD_PARTY_CHIBICC_SRCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_SRCS)) diff --git a/third_party/chibicc/codegen.c b/third_party/chibicc/codegen.c index 3f40de693..6004345d5 100644 --- a/third_party/chibicc/codegen.c +++ b/third_party/chibicc/codegen.c @@ -1152,19 +1152,6 @@ static int GetSseIntSuffix(Type *ty) { } } -static bool IsOverflowArithmetic(Node *node) { - return (node->kind == ND_ADD || node->kind == ND_SUB || - node->kind == ND_MUL || node->kind == ND_NEG) && - node->overflow; -} - -static void HandleOverflow(const char *ax) { - pop("%rdi"); - println("\tmov\t%s,(%%rdi)", ax); - emitlin("\tseto\t%al"); - emitlin("\tmovzbl\t%al,%eax"); -} - static void HandleAtomicArithmetic(Node *node, const char *op) { gen_expr(node->lhs); push(); @@ -1238,10 +1225,6 @@ void gen_expr(Node *node) { } } case ND_NEG: - if (IsOverflowArithmetic(node)) { - gen_expr(node->overflow); - push(); - } gen_expr(node->lhs); switch (node->ty->kind) { case TY_FLOAT: @@ -1277,9 +1260,6 @@ void gen_expr(Node *node) { ax = "%eax"; } println("\tneg\t%s", ax); - if (IsOverflowArithmetic(node)) { - HandleOverflow(ax); - } return; case ND_VAR: gen_addr(node); @@ -1771,10 +1751,6 @@ void gen_expr(Node *node) { error_tok(node->tok, "invalid expression"); } } - if (IsOverflowArithmetic(node)) { - gen_expr(node->overflow); - push(); - } if (node->lhs->ty->vector_size == 16) { gen_expr(node->rhs); pushx(); @@ -2210,9 +2186,6 @@ void gen_expr(Node *node) { default: error_tok(node->tok, "invalid expression"); } - if (IsOverflowArithmetic(node)) { - HandleOverflow(ax); - } } void gen_stmt(Node *node) { diff --git a/third_party/chibicc/help.txt b/third_party/chibicc/help.txt index 54c585310..e7baa62f3 100644 --- a/third_party/chibicc/help.txt +++ b/third_party/chibicc/help.txt @@ -198,10 +198,6 @@ BUILTIN FUNCTIONS _Bool __builtin_types_compatible_p(typename, typename) T __builtin_atomic_exchange(T *addr, T neu) T * __builtin_assume_aligned(T *addr) - _Bool __builtin_add_overflow(T, T, T *) - _Bool __builtin_sub_overflow(T, T, T *) - _Bool __builtin_mul_overflow(T, T, T *) - _Bool __builtin_neg_overflow(T, T, T *) void * __builtin_alloca(unsigned long) void __builtin_trap() int __builtin_clz(int) diff --git a/third_party/chibicc/parse.c b/third_party/chibicc/parse.c index 32edc279b..1117ade40 100644 --- a/third_party/chibicc/parse.c +++ b/third_party/chibicc/parse.c @@ -2631,27 +2631,6 @@ static Node *new_mul(Node *lhs, Node *rhs, Token *tok) { return new_binary(ND_MUL, lhs, rhs, tok); } -static Node *builtin_overflow(Token **rest, Token *tok, - Node *new_op(Node *, Node *, Token *)) { - Token *start = tok; - tok = skip(tok->next, '('); - Node *lhs = assign(&tok, tok); - tok = skip(tok, ','); - Node *rhs = assign(&tok, tok); - tok = skip(tok, ','); - Node *dst = assign(&tok, tok); - *rest = skip(tok, ')'); - Node *node = new_op(lhs, rhs, start); - add_type(node); - add_type(dst); - if (!is_compatible(pointer_to(node->ty), dst->ty)) { - error_tok(start, "output pointer type incompatible"); - } - node->overflow = dst; - node->ty = copy_type(ty_bool); - return node; -} - // add = mul ("+" mul | "-" mul)* static Node *add(Token **rest, Token *tok) { Node *node = mul(&tok, tok); @@ -3378,32 +3357,6 @@ static Node *primary(Token **rest, Token *tok) { *rest = skip(tok, ')'); return node; } - if (kw == KW___BUILTIN_ADD_OVERFLOW) { - return builtin_overflow(rest, tok, new_add); - } - if (kw == KW___BUILTIN_SUB_OVERFLOW) { - return builtin_overflow(rest, tok, new_sub); - } - if (kw == KW___BUILTIN_MUL_OVERFLOW) { - return builtin_overflow(rest, tok, new_mul); - } - if (kw == KW___BUILTIN_NEG_OVERFLOW) { - Token *start = tok; - tok = skip(tok->next, '('); - Node *lhs = assign(&tok, tok); - tok = skip(tok, ','); - Node *dst = assign(&tok, tok); - *rest = skip(tok, ')'); - Node *node = new_unary(ND_NEG, lhs, start); - add_type(node); - add_type(dst); - if (!is_compatible(pointer_to(node->ty), dst->ty)) { - error_tok(start, "output pointer type incompatible"); - } - node->overflow = dst; - node->ty = copy_type(ty_bool); - return node; - } if (kw == KW___BUILTIN_FPCLASSIFY) { Node *node = new_node(ND_FPCLASSIFY, tok); node->fpc = calloc(1, sizeof(FpClassify)); diff --git a/third_party/chibicc/printast.c b/third_party/chibicc/printast.c index 38b42591b..d7decabf3 100644 --- a/third_party/chibicc/printast.c +++ b/third_party/chibicc/printast.c @@ -189,7 +189,6 @@ static void PrintNode(FILE *f, int l, const char *s, Node *n) { PrintInt(f, l + 2, "end: ", n->end); PrintMember(f, l + 2, "member: ", n->member); PrintObj(f, l + 2, "var: ", n->var); - PrintNode(f, l + 2, "overflow: ", n->overflow); PrintInt(f, l + 2, "val: ", n->val); if (n->fval) PrintLine(f, l + 2, "fval: %Lf", n->fval); PrintLine(f, l, "}"); diff --git a/third_party/chibicc/test/builtin_test.c b/third_party/chibicc/test/builtin_test.c index 429cbd70b..eed30e51b 100644 --- a/third_party/chibicc/test/builtin_test.c +++ b/third_party/chibicc/test/builtin_test.c @@ -192,104 +192,6 @@ void test_memcpy(void) { } } -void test_add_overflow(void) { - { - int z; - ASSERT(0, ckd_add(&z, 2, 3)); - ASSERT(5, z); - } - { - int x, y, z; - x = 2; - y = 3; - ASSERT(0, ckd_add(&z, x, y)); - ASSERT(5, z); - } - { - int x, y, z; - x = 0x7fffffff; - y = 1; - ASSERT(1, ckd_add(&z, x, y)); - ASSERT(-2147483648, z); - } - { - long x, y, z; - x = 0x7fffffff; - y = 1; - ASSERT(0, ckd_add(&z, x, y)); - ASSERT(2147483648, z); - } -} - -void test_sub_overflow(void) { - { - int x, y, z; - x = 2; - y = 3; - ASSERT(0, ckd_sub(&z, x, y)); - ASSERT(-1, z); - } - { - int x, y, z; - x = -2147483648; - y = 1; - ASSERT(1, ckd_sub(&z, x, y)); - ASSERT(2147483647, z); - } - { - long x, y, z; - x = -2147483648; - y = 1; - ASSERT(0, ckd_sub(&z, x, y)); - ASSERT(-2147483649, z); - } -} - -void test_mul_overflow(void) { - { - int x, y, z; - x = 2; - y = 3; - ASSERT(0, ckd_mul(&z, x, y)); - ASSERT(6, z); - } - { - int x, y, z; - x = 2147483647; - y = 2; - ASSERT(1, ckd_mul(&z, x, y)); - ASSERT(-2, z); - } - { - long x, y, z; - x = 2147483647; - y = 2; - ASSERT(0, ckd_mul(&z, x, y)); - ASSERT(4294967294, z); - } -} - -void test_neg_overflow(void) { - { - int x, z; - x = 2; - ASSERT(0, __builtin_neg_overflow(x, &z)); - ASSERT(-2, z); - } - { - int x, z; - x = -2147483648; - ASSERT(1, __builtin_neg_overflow(x, &z)); - ASSERT(-2147483648, z); - } - { - long x, z; - x = -2147483648; - ASSERT(0, __builtin_neg_overflow(x, &z)); - ASSERT(2147483648, z); - } -} - void test_inf(void) { ASSERT(0, __builtin_isinf(0)); ASSERT(0, __builtin_isinf(1)); @@ -433,10 +335,6 @@ int main() { test_memcpy(); test_offsetof(); test_ignored(); - test_add_overflow(); - test_sub_overflow(); - test_mul_overflow(); - test_neg_overflow(); test_strlen(); test_strchr(); test_strpbrk();