mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Restore missing cosmopolitan documentation on website
This commit is contained in:
parent
58352df0a4
commit
d9d5f45e2d
36 changed files with 715 additions and 228 deletions
2
Makefile
2
Makefile
|
@ -414,7 +414,7 @@ o/cosmopolitan.html: \
|
||||||
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))
|
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))
|
||||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
|
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
|
||||||
-fno-common -include libc/integral/normalize.inc -o $@ \
|
-fno-common -include libc/integral/normalize.inc -o $@ \
|
||||||
@$(TMPDIR)/$(subst /,_,$@)
|
-DCOSMO @$(TMPDIR)/$(subst /,_,$@)
|
||||||
|
|
||||||
$(SRCS): \
|
$(SRCS): \
|
||||||
libc/integral/normalize.inc \
|
libc/integral/normalize.inc \
|
||||||
|
|
|
@ -44,6 +44,10 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __chibicc__
|
||||||
|
#define __extension__
|
||||||
|
#endif
|
||||||
|
|
||||||
#if __STDC_VERSION__ + 0 < 201112
|
#if __STDC_VERSION__ + 0 < 201112
|
||||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||||
#define _Alignas(x) __attribute__((__aligned__(x)))
|
#define _Alignas(x) __attribute__((__aligned__(x)))
|
||||||
|
@ -828,13 +832,18 @@ void abort(void) wontreturn;
|
||||||
#define __static_yoink_source(PATH)
|
#define __static_yoink_source(PATH)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define __strong_reference(sym, aliassym) \
|
|
||||||
extern __typeof(sym) aliassym __attribute__((__alias__(#sym)))
|
|
||||||
#define __weak_reference(sym, alias) \
|
#define __weak_reference(sym, alias) \
|
||||||
__asm__(".weak\t" #alias "\n\t" \
|
__asm__(".weak\t" #alias "\n\t" \
|
||||||
".equ\t" #alias ", " #sym "\n\t" \
|
".equ\t" #alias ", " #sym "\n\t" \
|
||||||
".type\t" #alias ",@notype")
|
".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 \
|
#define __funline \
|
||||||
extern __inline \
|
extern __inline \
|
||||||
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
|
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
|
||||||
|
|
|
@ -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) {
|
_Microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
|
||||||
xmm_t v = {0};
|
xmm_t v = {0};
|
||||||
if (IsAsan()) __asan_verify(p, n);
|
if (IsAsan()) __asan_verify(p, n);
|
||||||
|
@ -154,7 +154,7 @@ void bzero(void *p, size_t n) {
|
||||||
b[--n] = x;
|
b[--n] = x;
|
||||||
} while (n);
|
} while (n);
|
||||||
}
|
}
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
} else if (IsTiny()) {
|
} else if (IsTiny()) {
|
||||||
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "a"(0));
|
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "a"(0));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -35,7 +35,7 @@ static inline const unsigned char *memchr_pure(const unsigned char *s,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
dontasan static inline const unsigned char *memchr_sse(const unsigned char *s,
|
dontasan static inline const unsigned char *memchr_sse(const unsigned char *s,
|
||||||
unsigned char c,
|
unsigned char c,
|
||||||
size_t n) {
|
size_t n) {
|
||||||
|
@ -71,7 +71,7 @@ dontasan static inline const unsigned char *memchr_sse(const unsigned char *s,
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
void *memchr(const void *s, int c, size_t n) {
|
void *memchr(const void *s, int c, size_t n) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
const void *r;
|
const void *r;
|
||||||
if (IsAsan()) __asan_verify(s, n);
|
if (IsAsan()) __asan_verify(s, n);
|
||||||
r = memchr_sse(s, c, n);
|
r = memchr_sse(s, c, n);
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
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,
|
static dontinline antiquity int memcmp_sse(const unsigned char *p,
|
||||||
const unsigned char *q, size_t n) {
|
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;
|
const unsigned char *p, *q;
|
||||||
if ((p = a) == (q = b) || !n) return 0;
|
if ((p = a) == (q = b) || !n) return 0;
|
||||||
if ((c = *p - *q)) return c;
|
if ((c = *p - *q)) return c;
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
if (!IsTiny()) {
|
if (!IsTiny()) {
|
||||||
if (n <= 16) {
|
if (n <= 16) {
|
||||||
if (n >= 8) {
|
if (n >= 8) {
|
||||||
|
|
|
@ -95,7 +95,7 @@ void *memmove(void *dst, const void *src, size_t n) {
|
||||||
d = dst;
|
d = dst;
|
||||||
s = src;
|
s = src;
|
||||||
|
|
||||||
#ifdef __x86__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
if (IsTiny()) {
|
if (IsTiny()) {
|
||||||
uint16_t w1, w2;
|
uint16_t w1, w2;
|
||||||
uint32_t l1, l2;
|
uint32_t l1, l2;
|
||||||
|
@ -214,7 +214,7 @@ void *memmove(void *dst, const void *src, size_t n) {
|
||||||
default:
|
default:
|
||||||
if (d == s) return d;
|
if (d == s) return d;
|
||||||
|
|
||||||
#ifdef __x86__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
if (n < kHalfCache3 || !kHalfCache3) {
|
if (n < kHalfCache3 || !kHalfCache3) {
|
||||||
if (d > s) {
|
if (d > s) {
|
||||||
if (IsAsan() || n < 900 || !X86_HAVE(ERMS)) {
|
if (IsAsan() || n < 900 || !X86_HAVE(ERMS)) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ static inline const unsigned char *memrchr_pure(const unsigned char *s,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
dontasan static inline const unsigned char *memrchr_sse(const unsigned char *s,
|
dontasan static inline const unsigned char *memrchr_sse(const unsigned char *s,
|
||||||
unsigned char c,
|
unsigned char c,
|
||||||
size_t n) {
|
size_t n) {
|
||||||
|
@ -69,7 +69,7 @@ dontasan static inline const unsigned char *memrchr_sse(const unsigned char *s,
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
void *memrchr(const void *s, int c, size_t n) {
|
void *memrchr(const void *s, int c, size_t n) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
const void *r;
|
const void *r;
|
||||||
if (IsAsan()) __asan_verify(s, n);
|
if (IsAsan()) __asan_verify(s, n);
|
||||||
r = memrchr_sse(s, c, n);
|
r = memrchr_sse(s, c, n);
|
||||||
|
|
|
@ -24,9 +24,9 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#ifndef __aarch64__
|
#ifndef __aarch64__
|
||||||
|
|
||||||
|
#ifndef __chibicc__
|
||||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||||
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
|
|
||||||
static void *memset_sse(char *p, char c, size_t n) {
|
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};
|
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);
|
if (IsAsan()) __asan_verify(p, n);
|
||||||
|
@ -44,8 +44,9 @@ static void *memset_sse(char *p, char c, size_t n) {
|
||||||
}
|
}
|
||||||
return p;
|
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) {
|
_Microarchitecture("avx") static void *memset_avx(char *p, char c, size_t n) {
|
||||||
char *t;
|
char *t;
|
||||||
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
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);
|
} while (n);
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
#ifdef __x86__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
} else if (IsTiny()) {
|
} else if (IsTiny()) {
|
||||||
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "a"(c));
|
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "a"(c));
|
||||||
return p;
|
return p;
|
||||||
|
|
|
@ -38,7 +38,7 @@ dontasan char *stpcpy(char *d, const char *s) {
|
||||||
if (IsAsan()) {
|
if (IsAsan()) {
|
||||||
__asan_verify(d, strlen(s) + 1);
|
__asan_verify(d, strlen(s) + 1);
|
||||||
}
|
}
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
for (; (uintptr_t)(s + i) & 15; ++i) {
|
for (; (uintptr_t)(s + i) & 15; ++i) {
|
||||||
if (!(d[i] = s[i])) {
|
if (!(d[i] = s[i])) {
|
||||||
return d + i;
|
return d + i;
|
||||||
|
|
|
@ -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)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
dontasan static inline const char *strchr_sse(const char *s, unsigned char c) {
|
dontasan static inline const char *strchr_sse(const char *s, unsigned char c) {
|
||||||
unsigned k;
|
unsigned k;
|
||||||
|
@ -95,7 +95,7 @@ static dontasan inline const char *strchr_x64(const char *p, uint64_t c) {
|
||||||
* @vforksafe
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
char *strchr(const char *s, int c) {
|
char *strchr(const char *s, int c) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
const char *r;
|
const char *r;
|
||||||
if (X86_HAVE(SSE)) {
|
if (X86_HAVE(SSE)) {
|
||||||
if (IsAsan()) __asan_verify(s, 1);
|
if (IsAsan()) __asan_verify(s, 1);
|
||||||
|
|
|
@ -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)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
dontasan static inline const char *strchrnul_sse(const char *s,
|
dontasan static inline const char *strchrnul_sse(const char *s,
|
||||||
unsigned char c) {
|
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
|
* NUL terminator if c is not found
|
||||||
*/
|
*/
|
||||||
char *strchrnul(const char *s, int c) {
|
char *strchrnul(const char *s, int c) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
const char *r;
|
const char *r;
|
||||||
if (X86_HAVE(SSE)) {
|
if (X86_HAVE(SSE)) {
|
||||||
if (IsAsan()) __asan_verify(s, 1);
|
if (IsAsan()) __asan_verify(s, 1);
|
||||||
|
|
|
@ -39,7 +39,7 @@ dontasan char *strcpy(char *d, const char *s) {
|
||||||
if (IsAsan()) {
|
if (IsAsan()) {
|
||||||
__asan_verify(d, strlen(s) + 1);
|
__asan_verify(d, strlen(s) + 1);
|
||||||
}
|
}
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
for (; (uintptr_t)(s + i) & 15; ++i) {
|
for (; (uintptr_t)(s + i) & 15; ++i) {
|
||||||
if (!(d[i] = s[i])) {
|
if (!(d[i] = s[i])) {
|
||||||
return d;
|
return d;
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
*/
|
*/
|
||||||
dontasan size_t strlen(const char *s) {
|
dontasan size_t strlen(const char *s) {
|
||||||
if (IsAsan()) __asan_verify_str(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)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
xmm_t z = {0};
|
xmm_t z = {0};
|
||||||
unsigned m, k = (uintptr_t)s & 15;
|
unsigned m, k = (uintptr_t)s & 15;
|
||||||
|
|
|
@ -2,11 +2,15 @@
|
||||||
#define COSMOPOLITAN_LIBC_BITS_WEAKEN_H_
|
#define COSMOPOLITAN_LIBC_BITS_WEAKEN_H_
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
|
#ifndef __chibicc__
|
||||||
#define _weaken(symbol) \
|
#define _weaken(symbol) \
|
||||||
__extension__({ \
|
__extension__({ \
|
||||||
extern __typeof__(symbol) symbol __attribute__((__weak__)); \
|
extern __typeof__(symbol) symbol __attribute__((__weak__)); \
|
||||||
&symbol; \
|
&symbol; \
|
||||||
})
|
})
|
||||||
|
#else
|
||||||
|
#define _weaken(symbol) (&(symbol))
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_BITS_WEAKEN_H_ */
|
#endif /* COSMOPOLITAN_LIBC_BITS_WEAKEN_H_ */
|
||||||
|
|
652
libc/stdckdint.h
652
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
|
#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_add(res, x, y) __builtin_add_overflow((x), (y), (res))
|
||||||
#define ckd_sub(res, x, y) __builtin_sub_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))
|
#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 <typename __T, typename __U, typename __V>
|
||||||
|
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 <typename __T, typename __U, typename __V>
|
||||||
|
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 <typename __T, typename __U, typename __V>
|
||||||
|
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_ */
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
typedef uint64_t xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
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) {
|
static int bcmp_sse(const char *p, const char *q, size_t n) {
|
||||||
xmm_t a;
|
xmm_t a;
|
||||||
while (n > 32) {
|
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);
|
*(const xmm_t *)(p + n - 16) ^ *(const xmm_t *)(q + n - 16);
|
||||||
return !!(a[0] | a[1]);
|
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,
|
_Microarchitecture("avx") static int bcmp_avx(const char *p, const char *q,
|
||||||
size_t n) {
|
size_t n) {
|
||||||
xmm_t a, b, c, d;
|
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);
|
__builtin_memcpy(&j, q + n - 4, 4);
|
||||||
return !!(i ^ j);
|
return !!(i ^ j);
|
||||||
}
|
}
|
||||||
|
#ifndef __chibicc__
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
} else if (LIKELY(X86_HAVE(AVX))) {
|
} else if (LIKELY(X86_HAVE(AVX))) {
|
||||||
return bcmp_avx(p, q, n);
|
return bcmp_avx(p, q, n);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
return bcmp_sse(p, q, n);
|
return bcmp_sse(p, q, n);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (n--) {
|
while (n--) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ void djbsort(int32_t *a, size_t n) {
|
||||||
__asan_verify(a, m);
|
__asan_verify(a, m);
|
||||||
}
|
}
|
||||||
if (n > 1) {
|
if (n > 1) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
if (X86_HAVE(AVX2)) {
|
if (X86_HAVE(AVX2)) {
|
||||||
djbsort_avx2(a, n);
|
djbsort_avx2(a, n);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -60,7 +60,7 @@ dontasan bool _isutf8(const void *data, size_t size) {
|
||||||
p = data;
|
p = data;
|
||||||
e = p + size;
|
e = p + size;
|
||||||
while (p < e) {
|
while (p < e) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
if (!((intptr_t)p & 15)) {
|
if (!((intptr_t)p & 15)) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if ((m = __builtin_ia32_pmovmskb128(*(xmm_t *)p >= (xmm_t){0}) ^
|
if ((m = __builtin_ia32_pmovmskb128(*(xmm_t *)p >= (xmm_t){0}) ^
|
||||||
|
|
|
@ -34,7 +34,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
*/
|
*/
|
||||||
dontasan void *memmem(const void *haystack, size_t haystacklen,
|
dontasan void *memmem(const void *haystack, size_t haystacklen,
|
||||||
const void *needle, size_t needlelen) {
|
const void *needle, size_t needlelen) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
char c;
|
char c;
|
||||||
xmm_t n, *v;
|
xmm_t n, *v;
|
||||||
unsigned i, k, m;
|
unsigned i, k, m;
|
||||||
|
|
|
@ -34,7 +34,7 @@ static inline const char16_t *memrchr16_pure(const char16_t *s, char16_t c,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
dontasan static inline const char16_t *memrchr16_sse(const char16_t *s,
|
dontasan static inline const char16_t *memrchr16_sse(const char16_t *s,
|
||||||
char16_t c, size_t n) {
|
char16_t c, size_t n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -67,7 +67,7 @@ dontasan static inline const char16_t *memrchr16_sse(const char16_t *s,
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
void *memrchr16(const void *s, int c, size_t n) {
|
void *memrchr16(const void *s, int c, size_t n) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
const void *r;
|
const void *r;
|
||||||
if (!IsTiny() && X86_HAVE(SSE)) {
|
if (!IsTiny() && X86_HAVE(SSE)) {
|
||||||
if (IsAsan()) __asan_verify(s, n * 2);
|
if (IsAsan()) __asan_verify(s, n * 2);
|
||||||
|
|
|
@ -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)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
dontasan static inline const char *rawmemchr_sse(const char *s,
|
dontasan static inline const char *rawmemchr_sse(const char *s,
|
||||||
unsigned char c) {
|
unsigned char c) {
|
||||||
|
@ -68,7 +68,7 @@ static inline dontasan uint64_t UncheckedAlignedRead64(unsigned char *p) {
|
||||||
* @return is pointer to first instance of c
|
* @return is pointer to first instance of c
|
||||||
*/
|
*/
|
||||||
void *rawmemchr(const void *s, int c) {
|
void *rawmemchr(const void *s, int c) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
const void *r;
|
const void *r;
|
||||||
if (X86_HAVE(SSE)) {
|
if (X86_HAVE(SSE)) {
|
||||||
if (IsAsan()) __asan_verify(s, 1);
|
if (IsAsan()) __asan_verify(s, 1);
|
||||||
|
|
|
@ -36,7 +36,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
* @see strstr()
|
* @see strstr()
|
||||||
*/
|
*/
|
||||||
dontasan char *strcasestr(const char *haystack, const char *needle) {
|
dontasan char *strcasestr(const char *haystack, const char *needle) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
char c;
|
char c;
|
||||||
xmm_t *p;
|
xmm_t *p;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
|
@ -30,7 +30,7 @@ typedef char16_t xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
dontasan size_t strlen16(const char16_t *s) {
|
dontasan size_t strlen16(const char16_t *s) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
size_t n;
|
size_t n;
|
||||||
xmm_t z = {0};
|
xmm_t z = {0};
|
||||||
unsigned m, k = (uintptr_t)s & 15;
|
unsigned m, k = (uintptr_t)s & 15;
|
||||||
|
|
|
@ -36,7 +36,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
* @see memmem()
|
* @see memmem()
|
||||||
*/
|
*/
|
||||||
dontasan char *strstr(const char *haystack, const char *needle) {
|
dontasan char *strstr(const char *haystack, const char *needle) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
xmm_t *p;
|
xmm_t *p;
|
||||||
size_t i;
|
size_t i;
|
||||||
unsigned k, m;
|
unsigned k, m;
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
#ifndef __chibicc__
|
||||||
typedef uint64_t xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
typedef uint64_t xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||||
|
|
||||||
dontasan static unsigned timingsafe_bcmp_sse(const char *p, const char *q,
|
dontasan static unsigned timingsafe_bcmp_sse(const char *p, const char *q,
|
||||||
size_t n) {
|
size_t n) {
|
||||||
uint64_t w;
|
uint64_t w;
|
||||||
|
@ -39,8 +39,9 @@ dontasan static unsigned timingsafe_bcmp_sse(const char *p, const char *q,
|
||||||
w = a[0] | a[1];
|
w = a[0] | a[1];
|
||||||
return w | w >> 32;
|
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,
|
dontasan static _Microarchitecture("avx") int timingsafe_bcmp_avx(const char *p,
|
||||||
const char *q,
|
const char *q,
|
||||||
size_t n) {
|
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(a, n);
|
||||||
__asan_verify(b, n);
|
__asan_verify(b, n);
|
||||||
}
|
}
|
||||||
|
#ifndef __chibicc__
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
if (X86_HAVE(AVX)) {
|
if (X86_HAVE(AVX)) {
|
||||||
return timingsafe_bcmp_avx(p, q, n);
|
return timingsafe_bcmp_avx(p, q, n);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return timingsafe_bcmp_sse(p, q, n);
|
return timingsafe_bcmp_sse(p, q, n);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else if (n >= 4) {
|
} else if (n >= 4) {
|
||||||
__builtin_memcpy(&u0, p, 4);
|
__builtin_memcpy(&u0, p, 4);
|
||||||
|
|
|
@ -30,7 +30,7 @@ typedef wchar_t xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
dontasan size_t wcslen(const wchar_t *s) {
|
dontasan size_t wcslen(const wchar_t *s) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
size_t n;
|
size_t n;
|
||||||
xmm_t z = {0};
|
xmm_t z = {0};
|
||||||
unsigned m, k = (uintptr_t)s & 15;
|
unsigned m, k = (uintptr_t)s & 15;
|
||||||
|
|
|
@ -30,7 +30,7 @@ extern const uint32_t kCombiningCharsBits;
|
||||||
* Returns cell width of monospace character.
|
* Returns cell width of monospace character.
|
||||||
*/
|
*/
|
||||||
int wcwidth(wchar_t c) {
|
int wcwidth(wchar_t c) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
if (LIKELY(32 <= c && c < 127)) {
|
if (LIKELY(32 <= c && c < 127)) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!c) {
|
} else if (!c) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ static inline const wchar_t *wmemrchr_pure(const wchar_t *s, wchar_t c,
|
||||||
return 0;
|
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,
|
dontasan static inline const wchar_t *wmemrchr_sse(const wchar_t *s, wchar_t c,
|
||||||
size_t n) {
|
size_t n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -68,7 +68,7 @@ dontasan static inline const wchar_t *wmemrchr_sse(const wchar_t *s, wchar_t c,
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
void *wmemrchr(const wchar_t *s, wchar_t c, size_t n) {
|
void *wmemrchr(const wchar_t *s, wchar_t c, size_t n) {
|
||||||
#ifdef __x86_64__
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
const void *r;
|
const void *r;
|
||||||
if (IsAsan()) {
|
if (IsAsan()) {
|
||||||
|
|
1
third_party/chibicc/README.cosmo
vendored
1
third_party/chibicc/README.cosmo
vendored
|
@ -12,7 +12,6 @@ local enhancements
|
||||||
- support __int128
|
- support __int128
|
||||||
- support _Static_assert
|
- support _Static_assert
|
||||||
- support __vector_size__
|
- support __vector_size__
|
||||||
- support __builtin_add_overflow, etc.
|
|
||||||
- support GCC C11 __atomic_* primitives
|
- support GCC C11 __atomic_* primitives
|
||||||
- support __builtin_memcpy, strlen, strpbrk, etc.
|
- support __builtin_memcpy, strlen, strpbrk, etc.
|
||||||
- support __builtin_constant_p, __builtin_likely, etc.
|
- support __builtin_constant_p, __builtin_likely, etc.
|
||||||
|
|
2
third_party/chibicc/chibicc.h
vendored
2
third_party/chibicc/chibicc.h
vendored
|
@ -410,8 +410,6 @@ struct Node {
|
||||||
Node *atomic_expr;
|
Node *atomic_expr;
|
||||||
// Variable
|
// Variable
|
||||||
Obj *var;
|
Obj *var;
|
||||||
// Arithmetic
|
|
||||||
Node *overflow;
|
|
||||||
// Numeric literal
|
// Numeric literal
|
||||||
int64_t val;
|
int64_t val;
|
||||||
long double fval;
|
long double fval;
|
||||||
|
|
6
third_party/chibicc/chibicc.mk
vendored
6
third_party/chibicc/chibicc.mk
vendored
|
@ -19,6 +19,10 @@ CHIBICC_FLAGS = \
|
||||||
-DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) \
|
-DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) \
|
||||||
-DMODE='"$(MODE)"'
|
-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
|
PKGS += THIRD_PARTY_CHIBICC
|
||||||
THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A
|
THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A
|
||||||
THIRD_PARTY_CHIBICC = $(THIRD_PARTY_CHIBICC_A_DEPS) $(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)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/third_party/chibicc/chibicc.o: private \
|
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_LIBS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)))
|
||||||
THIRD_PARTY_CHIBICC_SRCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_SRCS))
|
THIRD_PARTY_CHIBICC_SRCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_SRCS))
|
||||||
|
|
27
third_party/chibicc/codegen.c
vendored
27
third_party/chibicc/codegen.c
vendored
|
@ -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) {
|
static void HandleAtomicArithmetic(Node *node, const char *op) {
|
||||||
gen_expr(node->lhs);
|
gen_expr(node->lhs);
|
||||||
push();
|
push();
|
||||||
|
@ -1238,10 +1225,6 @@ void gen_expr(Node *node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ND_NEG:
|
case ND_NEG:
|
||||||
if (IsOverflowArithmetic(node)) {
|
|
||||||
gen_expr(node->overflow);
|
|
||||||
push();
|
|
||||||
}
|
|
||||||
gen_expr(node->lhs);
|
gen_expr(node->lhs);
|
||||||
switch (node->ty->kind) {
|
switch (node->ty->kind) {
|
||||||
case TY_FLOAT:
|
case TY_FLOAT:
|
||||||
|
@ -1277,9 +1260,6 @@ void gen_expr(Node *node) {
|
||||||
ax = "%eax";
|
ax = "%eax";
|
||||||
}
|
}
|
||||||
println("\tneg\t%s", ax);
|
println("\tneg\t%s", ax);
|
||||||
if (IsOverflowArithmetic(node)) {
|
|
||||||
HandleOverflow(ax);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
case ND_VAR:
|
case ND_VAR:
|
||||||
gen_addr(node);
|
gen_addr(node);
|
||||||
|
@ -1771,10 +1751,6 @@ void gen_expr(Node *node) {
|
||||||
error_tok(node->tok, "invalid expression");
|
error_tok(node->tok, "invalid expression");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (IsOverflowArithmetic(node)) {
|
|
||||||
gen_expr(node->overflow);
|
|
||||||
push();
|
|
||||||
}
|
|
||||||
if (node->lhs->ty->vector_size == 16) {
|
if (node->lhs->ty->vector_size == 16) {
|
||||||
gen_expr(node->rhs);
|
gen_expr(node->rhs);
|
||||||
pushx();
|
pushx();
|
||||||
|
@ -2210,9 +2186,6 @@ void gen_expr(Node *node) {
|
||||||
default:
|
default:
|
||||||
error_tok(node->tok, "invalid expression");
|
error_tok(node->tok, "invalid expression");
|
||||||
}
|
}
|
||||||
if (IsOverflowArithmetic(node)) {
|
|
||||||
HandleOverflow(ax);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gen_stmt(Node *node) {
|
void gen_stmt(Node *node) {
|
||||||
|
|
4
third_party/chibicc/help.txt
vendored
4
third_party/chibicc/help.txt
vendored
|
@ -198,10 +198,6 @@ BUILTIN FUNCTIONS
|
||||||
_Bool __builtin_types_compatible_p(typename, typename)
|
_Bool __builtin_types_compatible_p(typename, typename)
|
||||||
T __builtin_atomic_exchange(T *addr, T neu)
|
T __builtin_atomic_exchange(T *addr, T neu)
|
||||||
T * __builtin_assume_aligned(T *addr)
|
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_alloca(unsigned long)
|
||||||
void __builtin_trap()
|
void __builtin_trap()
|
||||||
int __builtin_clz(int)
|
int __builtin_clz(int)
|
||||||
|
|
47
third_party/chibicc/parse.c
vendored
47
third_party/chibicc/parse.c
vendored
|
@ -2631,27 +2631,6 @@ static Node *new_mul(Node *lhs, Node *rhs, Token *tok) {
|
||||||
return new_binary(ND_MUL, lhs, rhs, 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)*
|
// add = mul ("+" mul | "-" mul)*
|
||||||
static Node *add(Token **rest, Token *tok) {
|
static Node *add(Token **rest, Token *tok) {
|
||||||
Node *node = mul(&tok, tok);
|
Node *node = mul(&tok, tok);
|
||||||
|
@ -3378,32 +3357,6 @@ static Node *primary(Token **rest, Token *tok) {
|
||||||
*rest = skip(tok, ')');
|
*rest = skip(tok, ')');
|
||||||
return node;
|
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) {
|
if (kw == KW___BUILTIN_FPCLASSIFY) {
|
||||||
Node *node = new_node(ND_FPCLASSIFY, tok);
|
Node *node = new_node(ND_FPCLASSIFY, tok);
|
||||||
node->fpc = calloc(1, sizeof(FpClassify));
|
node->fpc = calloc(1, sizeof(FpClassify));
|
||||||
|
|
1
third_party/chibicc/printast.c
vendored
1
third_party/chibicc/printast.c
vendored
|
@ -189,7 +189,6 @@ static void PrintNode(FILE *f, int l, const char *s, Node *n) {
|
||||||
PrintInt(f, l + 2, "end: ", n->end);
|
PrintInt(f, l + 2, "end: ", n->end);
|
||||||
PrintMember(f, l + 2, "member: ", n->member);
|
PrintMember(f, l + 2, "member: ", n->member);
|
||||||
PrintObj(f, l + 2, "var: ", n->var);
|
PrintObj(f, l + 2, "var: ", n->var);
|
||||||
PrintNode(f, l + 2, "overflow: ", n->overflow);
|
|
||||||
PrintInt(f, l + 2, "val: ", n->val);
|
PrintInt(f, l + 2, "val: ", n->val);
|
||||||
if (n->fval) PrintLine(f, l + 2, "fval: %Lf", n->fval);
|
if (n->fval) PrintLine(f, l + 2, "fval: %Lf", n->fval);
|
||||||
PrintLine(f, l, "}");
|
PrintLine(f, l, "}");
|
||||||
|
|
102
third_party/chibicc/test/builtin_test.c
vendored
102
third_party/chibicc/test/builtin_test.c
vendored
|
@ -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) {
|
void test_inf(void) {
|
||||||
ASSERT(0, __builtin_isinf(0));
|
ASSERT(0, __builtin_isinf(0));
|
||||||
ASSERT(0, __builtin_isinf(1));
|
ASSERT(0, __builtin_isinf(1));
|
||||||
|
@ -433,10 +335,6 @@ int main() {
|
||||||
test_memcpy();
|
test_memcpy();
|
||||||
test_offsetof();
|
test_offsetof();
|
||||||
test_ignored();
|
test_ignored();
|
||||||
test_add_overflow();
|
|
||||||
test_sub_overflow();
|
|
||||||
test_mul_overflow();
|
|
||||||
test_neg_overflow();
|
|
||||||
test_strlen();
|
test_strlen();
|
||||||
test_strchr();
|
test_strchr();
|
||||||
test_strpbrk();
|
test_strpbrk();
|
||||||
|
|
Loading…
Reference in a new issue